diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2485,13 +2485,11 @@ A ``"clang.arc.attachedcall"`` operand bundle on a call indicates the call is implicitly followed by a marker instruction and a call to an ObjC runtime -function that uses the result of the call. The operand bundle takes either the +function that uses the result of the call. The operand bundle takes a mandatory pointer to the runtime function (``@objc_retainAutoreleasedReturnValue`` or -``@objc_unsafeClaimAutoreleasedReturnValue``) or no arguments. If the bundle -doesn't take any arguments, only the marker instruction has to be emitted after -the call; the runtime function calls don't have to be emitted since they already -have been emitted. The return value of a call with this bundle is used by a call -to ``@llvm.objc.clang.arc.noop.use`` unless the called function's return type is +``@objc_unsafeClaimAutoreleasedReturnValue``). +The return value of a call with this bundle is used by a call to +``@llvm.objc.clang.arc.noop.use`` unless the called function's return type is void, in which case the operand bundle is ignored. .. code-block:: llvm @@ -2501,11 +2499,8 @@ call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @objc_retainAutoreleasedReturnValue) ] call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @objc_unsafeClaimAutoreleasedReturnValue) ] - ; Only the marker instruction is inserted after the call to @foo. - call i8* @foo() [ "clang.arc.attachedcall"() ] - The operand bundle is needed to ensure the call is immediately followed by the -marker instruction or the ObjC runtime call in the final output. +marker instruction and the ObjC runtime call in the final output. .. _moduleasm: diff --git a/llvm/include/llvm/Analysis/ObjCARCUtil.h b/llvm/include/llvm/Analysis/ObjCARCUtil.h --- a/llvm/include/llvm/Analysis/ObjCARCUtil.h +++ b/llvm/include/llvm/Analysis/ObjCARCUtil.h @@ -42,7 +42,7 @@ /// which is the address of the ARC runtime function. inline Optional getAttachedARCFunction(const CallBase *CB) { auto B = CB->getOperandBundle(LLVMContext::OB_clang_arc_attachedcall); - if (!B.hasValue() || B->Inputs.size() == 0) + if (!B) return None; return cast(B->Inputs[0]); diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -5811,15 +5811,11 @@ "void return type", Call); - Assert((BU.Inputs.empty() || - (BU.Inputs.size() == 1 && isa(BU.Inputs.front()))), - "operand bundle \"clang.arc.attachedcall\" can take either no " - "arguments or one function as an argument", + Assert(BU.Inputs.size() == 1 && isa(BU.Inputs.front()), + "operand bundle \"clang.arc.attachedcall\" requires one function as " + "an argument", Call); - if (BU.Inputs.empty()) - return; - auto *Fn = cast(BU.Inputs.front()); Intrinsic::ID IID = Fn->getIntrinsicID(); diff --git a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp --- a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp +++ b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp @@ -709,20 +709,24 @@ bool AArch64ExpandPseudo::expandCALL_RVMARKER( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) { - // Expand CALL_RVMARKER pseudo to a branch, followed by the special `mov x29, - // x29` marker. Mark the sequence as bundle, to avoid passes moving other code - // in between. + // Expand CALL_RVMARKER pseudo to: + // - a branch to the call target, followed by + // - the special `mov x29, x29` marker, and + // - another branch, to the runtime function + // Mark the sequence as bundle, to avoid passes moving other code in between. MachineInstr &MI = *MBBI; MachineInstr *OriginalCall; - MachineOperand &CallTarget = MI.getOperand(0); + MachineOperand &RVTarget = MI.getOperand(0); + MachineOperand &CallTarget = MI.getOperand(1); assert((CallTarget.isGlobal() || CallTarget.isReg()) && "invalid operand for regular call"); + assert(RVTarget.isGlobal() && "invalid operand for attached call"); unsigned Opc = CallTarget.isGlobal() ? AArch64::BL : AArch64::BLR; OriginalCall = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc)).getInstr(); OriginalCall->addOperand(CallTarget); - unsigned RegMaskStartIdx = 1; + unsigned RegMaskStartIdx = 2; // Skip register arguments. Those are added during ISel, but are not // needed for the concrete branch. while (!MI.getOperand(RegMaskStartIdx).isRegMask()) { @@ -736,17 +740,22 @@ llvm::drop_begin(MI.operands(), RegMaskStartIdx)) OriginalCall->addOperand(MO); - auto *Marker = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ORRXrs)) + BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ORRXrs)) .addReg(AArch64::FP, RegState::Define) .addReg(AArch64::XZR) .addReg(AArch64::FP) - .addImm(0) + .addImm(0); + + auto *RVCall = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::BL)) + .add(RVTarget) .getInstr(); + if (MI.shouldUpdateCallSiteInfo()) - MBB.getParent()->moveCallSiteInfo(&MI, Marker); + MBB.getParent()->moveCallSiteInfo(&MI, OriginalCall); + MI.eraseFromParent(); finalizeBundle(MBB, OriginalCall->getIterator(), - std::next(Marker->getIterator())); + std::next(RVCall->getIterator())); return true; } diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -6475,12 +6475,18 @@ unsigned CallOpc = AArch64ISD::CALL; // Calls with operand bundle "clang.arc.attachedcall" are special. They should - // be expanded to the call, directly followed by a special marker sequence. - // Use the CALL_RVMARKER to do that. + // be expanded to the call, directly followed by a special marker sequence and + // a call to an ObjC library function. Use CALL_RVMARKER to do that. if (CLI.CB && objcarc::hasAttachedCallOpBundle(CLI.CB)) { assert(!IsTailCall && "tail calls cannot be marked with clang.arc.attachedcall"); CallOpc = AArch64ISD::CALL_RVMARKER; + + // Add a target global address for the retainRV/claimRV runtime function + // just before the call target. + Function *ARCFn = *objcarc::getAttachedARCFunction(CLI.CB); + auto GA = DAG.getTargetGlobalAddress(ARCFn, DL, PtrVT); + Ops.insert(Ops.begin() + 1, GA); } // Returns a chain and a flag for retval copy to use. diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -2324,8 +2324,8 @@ (BLRNoIP GPR64noip:$Rn)>, Requires<[SLSBLRMitigation]>; -def : Pat<(AArch64call_rvmarker GPR64:$Rn), - (BLR_RVMARKER GPR64:$Rn)>, +def : Pat<(AArch64call_rvmarker (i64 tglobaladdr:$rvfunc), GPR64:$Rn), + (BLR_RVMARKER tglobaladdr:$rvfunc, GPR64:$Rn)>, Requires<[NoSLSBLRMitigation]>; let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.h b/llvm/lib/Transforms/ObjCARC/ObjCARC.h --- a/llvm/lib/Transforms/ObjCARC/ObjCARC.h +++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.h @@ -105,8 +105,7 @@ class BundledRetainClaimRVs { public: - BundledRetainClaimRVs(bool ContractPass, bool UseMarker) - : ContractPass(ContractPass), UseMarker(UseMarker) {} + BundledRetainClaimRVs(bool ContractPass) : ContractPass(ContractPass) {} ~BundledRetainClaimRVs(); /// Insert a retainRV/claimRV call to the normal destination blocks of invokes @@ -156,9 +155,6 @@ DenseMap RVCalls; bool ContractPass; - - /// Indicates whether the target uses a special inline-asm marker. - bool UseMarker; }; } // end namespace objcarc diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp --- a/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp @@ -123,20 +123,9 @@ // can't be tail calls. if (auto *CI = dyn_cast(CB)) CI->setTailCallKind(CallInst::TCK_NoTail); - - if (UseMarker) { - // Remove the retainRV/claimRV function operand from the operand bundle - // to reflect the fact that the backend is responsible for emitting only - // the marker instruction, but not the retainRV/claimRV call. - OperandBundleDef OB("clang.arc.attachedcall", None); - auto *NewCB = CallBase::Create(CB, OB, CB); - CB->replaceAllUsesWith(NewCB); - CB->eraseFromParent(); - } } - if (!ContractPass || !UseMarker) - EraseInstruction(P.first); + EraseInstruction(P.first); } RVCalls.clear(); diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp --- a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp @@ -434,23 +434,20 @@ LLVM_FALLTHROUGH; case ARCInstKind::RetainRV: case ARCInstKind::UnsafeClaimRV: { - bool IsInstContainedInBundle = BundledInsts->contains(Inst); - - // Return now if the target doesn't need a special inline-asm marker. Return - // true if this is a bundled retainRV/claimRV call, which is going to be - // erased at the end of this pass, to avoid undoing objc-arc-expand and + // Return true if this is a bundled retainRV/claimRV call, which is always + // redundant with the attachedcall in the bundle, and is going to be erased + // at the end of this pass. This avoids undoing objc-arc-expand and // replacing uses of the retainRV/claimRV call's argument with its result. - if (!RVInstMarker) - return IsInstContainedInBundle; - - // The target needs a special inline-asm marker. + if (BundledInsts->contains(Inst)) + return true; - // We don't have to emit the marker if this is a bundled call since the - // backend is responsible for emitting it. Return false to undo - // objc-arc-expand. - if (IsInstContainedInBundle) + // If this isn't a bundled call, and the target doesn't need a special + // inline-asm marker, we're done: return now, and undo objc-arc-expand. + if (!RVInstMarker) return false; + // The target needs a special inline-asm marker. Insert it. + BasicBlock::iterator BBI = Inst->getIterator(); BasicBlock *InstParent = Inst->getParent(); @@ -548,7 +545,7 @@ AA = A; DT = D; PA.setAA(A); - BundledRetainClaimRVs BRV(true, RVInstMarker); + BundledRetainClaimRVs BRV(/*ContractPass=*/true); BundledInsts = &BRV; std::pair R = BundledInsts->insertAfterInvokes(F, DT); diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp --- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -2459,7 +2459,7 @@ return false; Changed = CFGChanged = false; - BundledRetainClaimRVs BRV(false, objcarc::getRVInstMarker(*F.getParent())); + BundledRetainClaimRVs BRV(/*ContractPass=*/false); BundledInsts = &BRV; LLVM_DEBUG(dbgs() << "<<< ObjCARCOpt: Visiting Function: " << F.getName() diff --git a/llvm/test/CodeGen/AArch64/call-rv-marker.ll b/llvm/test/CodeGen/AArch64/call-rv-marker.ll --- a/llvm/test/CodeGen/AArch64/call-rv-marker.ll +++ b/llvm/test/CodeGen/AArch64/call-rv-marker.ll @@ -25,15 +25,29 @@ @g = dso_local global i8* null, align 8 @fptr = dso_local global i8* ()* null, align 8 -define dso_local i8* @rv_marker_1() { -; CHECK-LABEL: rv_marker_1: +define dso_local i8* @rv_marker_1_retain() { +; CHECK-LABEL: rv_marker_1_retain: ; CHECK: .cfi_offset w30, -16 ; CHECK-NEXT: bl foo1 ; SELDAG-NEXT: mov x29, x29 +; SELDAG-NEXT: bl objc_retainAutoreleasedReturnValue ; GISEL-NOT: mov x29, x29 ; entry: - %call = call i8* @foo1() [ "clang.arc.attachedcall"() ] + %call = call i8* @foo1() [ "clang.arc.attachedcall"(i8* (i8*)* @objc_retainAutoreleasedReturnValue) ] + ret i8* %call +} + +define dso_local i8* @rv_marker_1_unsafeClaim() { +; CHECK-LABEL: rv_marker_1_unsafeClaim: +; CHECK: .cfi_offset w30, -16 +; CHECK-NEXT: bl foo1 +; SELDAG-NEXT: mov x29, x29 +; SELDAG-NEXT: bl objc_unsafeClaimAutoreleasedReturnValue +; GISEL-NOT: mov x29, x29 +; +entry: + %call = call i8* @foo1() [ "clang.arc.attachedcall"(i8* (i8*)* @objc_unsafeClaimAutoreleasedReturnValue) ] ret i8* %call } @@ -43,13 +57,14 @@ ; GISEL: csinc w0, w8, wzr, eq ; CHECK-NEXT: bl foo0 ; SELDAG-NEXT: mov x29, x29 +; SELDAG-NEXT: bl objc_retainAutoreleasedReturnValue ; CHECK-NEXT: ldr x30, [sp], #16 ; CHECK-NEXT: b foo2 ; entry: %tobool.not = icmp eq i32 %c, 0 %.sink = select i1 %tobool.not, i32 2, i32 1 - %call1 = call i8* @foo0(i32 %.sink) [ "clang.arc.attachedcall"() ] + %call1 = call i8* @foo0(i32 %.sink) [ "clang.arc.attachedcall"(i8* (i8*)* @objc_retainAutoreleasedReturnValue) ] tail call void @foo2(i8* %call1) ret void } @@ -59,9 +74,10 @@ ; CHECK: .cfi_offset w30, -32 ; CHECK-NEXT: bl foo1 ; SELDAG-NEXT: mov x29, x29 +; SELDAG-NEXT: bl objc_retainAutoreleasedReturnValue ; entry: - %call = call i8* @foo1() [ "clang.arc.attachedcall"() ] + %call = call i8* @foo1() [ "clang.arc.attachedcall"(i8* (i8*)* @objc_retainAutoreleasedReturnValue) ] invoke void @objc_object(i8* %call) #5 to label %invoke.cont unwind label %lpad @@ -81,13 +97,14 @@ ; CHECK: .Ltmp3: ; CHECK-NEXT: bl foo1 ; SELDAG-NEXT: mov x29, x29 +; SELDAG-NEXT: bl objc_retainAutoreleasedReturnValue ; CHECK-NEXT: .Ltmp4: ; entry: %s = alloca %struct.S, align 1 %0 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 0 call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %0) #2 - %call = invoke i8* @foo1() [ "clang.arc.attachedcall"() ] + %call = invoke i8* @foo1() [ "clang.arc.attachedcall"(i8* (i8*)* @objc_retainAutoreleasedReturnValue) ] to label %invoke.cont unwind label %lpad invoke.cont: ; preds = %entry @@ -122,12 +139,13 @@ ; CHECK-LABEL: rv_marker_5_indirect_call ; CHECK: ldr [[ADDR:x[0-9]+]], [ ; CHECK-NEXT: blr [[ADDR]] -; SLEDAG-NEXT: mov x29, x29 +; SELDAG-NEXT: mov x29, x29 +; SELDAG-NEXT: bl objc_retainAutoreleasedReturnValue ; GISEL-NOT: mov x29, x29 ; entry: %0 = load i8* ()*, i8* ()** @fptr, align 8 - %call = call i8* %0() [ "clang.arc.attachedcall"() ] + %call = call i8* %0() [ "clang.arc.attachedcall"(i8* (i8*)* @objc_retainAutoreleasedReturnValue) ] tail call void @foo2(i8* %call) ret i8* %call } @@ -141,9 +159,12 @@ ; CHECK-NEXT: mov x2, [[TMP]] ; CHECK-NEXT: bl foo ; SELDAG-NEXT: mov x29, x29 +; SELDAG-NEXT: bl objc_retainAutoreleasedReturnValue ; GISEL-NOT: mov x29, x29 - call i8* @foo(i64 %c, i64 %b, i64 %a) [ "clang.arc.attachedcall"() ] + call i8* @foo(i64 %c, i64 %b, i64 %a) [ "clang.arc.attachedcall"(i8* (i8*)* @objc_retainAutoreleasedReturnValue) ] ret void } +declare i8* @objc_retainAutoreleasedReturnValue(i8*) +declare i8* @objc_unsafeClaimAutoreleasedReturnValue(i8*) declare i32 @__gxx_personality_v0(...) diff --git a/llvm/test/CodeGen/AArch64/expand-blr-rvmarker-pseudo.mir b/llvm/test/CodeGen/AArch64/expand-blr-rvmarker-pseudo.mir --- a/llvm/test/CodeGen/AArch64/expand-blr-rvmarker-pseudo.mir +++ b/llvm/test/CodeGen/AArch64/expand-blr-rvmarker-pseudo.mir @@ -25,6 +25,7 @@ ret void } + declare i8* @attachedcall() ... --- @@ -33,6 +34,7 @@ # CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $w30, implicit-def $sp, implicit-def $wsp, implicit-def dead $x0, implicit-def $fp, implicit-def $w29, implicit $x0, implicit $sp, implicit $xzr, implicit $fp { # CHECK-NEXT: BLR $x0, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0 # CHECK-NEXT: ORRXrs $xzr, $fp, 0 +# CHECK-NEXT: BL @attachedcall, implicit-def $lr, implicit internal $sp # CHECK-NEXT: } # CHECK-NEXT: RET undef $lr, implicit killed $w0 # @@ -44,7 +46,7 @@ bb.0: liveins: $lr, $x0 - BLR_RVMARKER $x0, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0 + BLR_RVMARKER @attachedcall, $x0, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0 RET_ReallyLR implicit killed $w0 ... @@ -53,6 +55,7 @@ # CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $w30, implicit-def $sp, implicit-def $wsp, implicit-def dead $x0, implicit-def $fp, implicit-def $w29, implicit $sp, implicit $x0, implicit $xzr, implicit $fp { # CHECK-NEXT: BL @foo, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $x0, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0 # CHECK-NEXT: $fp = ORRXrs $xzr, $fp, 0 +# CHECK-NEXT: BL @attachedcall, implicit-def $lr, implicit internal $sp # CHECK-NEXT: } # CHECK-NEXT: RET undef $lr, implicit killed $w0 # @@ -61,7 +64,7 @@ bb.0: liveins: $lr, $x0 - BLR_RVMARKER @foo, $x0, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0 + BLR_RVMARKER @attachedcall, @foo, $x0, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0 RET_ReallyLR implicit killed $w0 ... @@ -70,6 +73,7 @@ # CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $w30, implicit-def $sp, implicit-def $wsp, implicit-def $x0, implicit-def $w0, implicit-def $fp, implicit-def $w29, implicit $sp, implicit $x0, implicit $x1, implicit $x2, implicit $xzr, implicit $fp { # CHECK-NEXT: BL @foo, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $x0, implicit $x1, implicit $x2, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $x0 # CHECK-NEXT: $fp = ORRXrs $xzr, $fp, 0 +# CHECK-NEXT: BL @attachedcall, implicit-def $lr, implicit internal $sp # CHECK-NEXT: } # CHECK-NEXT: RET undef $lr # @@ -78,7 +82,7 @@ bb.0: liveins: $lr, $x0, $x1, $x2 - BLR_RVMARKER @foo, $x0, $x1, $x2, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $x0 + BLR_RVMARKER @attachedcall, @foo, $x0, $x1, $x2, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $x0 RET_ReallyLR ... @@ -87,6 +91,7 @@ # CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $w30, implicit-def $sp, implicit-def $wsp, implicit-def dead $x0, implicit-def $fp, implicit-def $w29, implicit $sp, implicit $w0, implicit $w1, implicit $xzr, implicit $fp { # CHECK-NEXT: BL @foo, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0, implicit $w1, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0 # CHECK-NEXT: $fp = ORRXrs $xzr, $fp, 0 +# CHECK-NEXT: BL @attachedcall, implicit-def $lr, implicit internal $sp # CHECK-NEXT: } # CHECK-NEXT: RET undef $lr, implicit killed $w0 # @@ -95,7 +100,7 @@ bb.0: liveins: $lr, $w0, $w1 - BLR_RVMARKER @foo, $w0, $w1, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0 + BLR_RVMARKER @attachedcall, @foo, $w0, $w1, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0 RET_ReallyLR implicit killed $w0 ... @@ -105,6 +110,7 @@ # CHECK-NEXT: BUNDLE implicit-def $lr, implicit-def $w30, implicit-def $sp, implicit-def $wsp, implicit-def dead $x0, implicit-def $fp, implicit-def $w29, implicit $x8, implicit $sp, implicit $w0, implicit $w1, implicit $xzr, implicit $fp { # CHECK-NEXT: BLR $x8, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0, implicit $w1, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0 # CHECK-NEXT: $fp = ORRXrs $xzr, $fp, 0 +# CHECK-NEXT: BL @attachedcall, implicit-def $lr, implicit internal $sp # CHECK-NEXT: } # CHECK-NEXT: RET undef $lr, implicit killed $w0 # @@ -113,6 +119,6 @@ bb.0: liveins: $lr, $x8, $w0, $w1 - BLR_RVMARKER $x8, $w0, $w1, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0 + BLR_RVMARKER @attachedcall, $x8, $w0, $w1, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def dead $x0 RET_ReallyLR implicit killed $w0 ... diff --git a/llvm/test/CodeGen/AArch64/rvmarker-pseudo-expansion-and-outlining.mir b/llvm/test/CodeGen/AArch64/rvmarker-pseudo-expansion-and-outlining.mir --- a/llvm/test/CodeGen/AArch64/rvmarker-pseudo-expansion-and-outlining.mir +++ b/llvm/test/CodeGen/AArch64/rvmarker-pseudo-expansion-and-outlining.mir @@ -1,18 +1,20 @@ # RUN: llc -enable-machine-outliner -start-before=aarch64-expand-pseudo -mtriple=arm64-apple-ios -o - %s | FileCheck %s # # The calls to _cb1 & _cb2 should be followed by the marker instruction -# 'mov x29, x29'. The marker should not get outlined. +# 'mov x29, x29' and the attached call. Neither should get outlined. # # CHECK-LABEL: _fn1: # CHECK: bb.0: # CHECK: bl _cb1 # CHECK-NEXT: mov x29, x29 +# CHECK-NEXT: bl _attachedcall # CHECK: b _OUTLINED_FUNCTION_0 # # CHECK-LABEL: _fn2: # CHECK: bb.0: # CHECK: bl _cb2 # CHECK-NEXT: mov x29, x29 +# CHECK-NEXT: bl _attachedcall # CHECK: b _OUTLINED_FUNCTION_0 # # CHECK-LABEL: _OUTLINED_FUNCTION_0: @@ -38,6 +40,8 @@ declare void @cb1() declare void @cb2() + + declare i8* @attachedcall() ... --- name: fn1 @@ -48,7 +52,7 @@ bb.0: liveins: $lr - BLR_RVMARKER @cb1, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $x0 + BLR_RVMARKER @attachedcall, @cb1, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $x0 $w12 = ORRWri $wzr, 1 $w12 = ORRWri $wzr, 1 $w12 = ORRWri $wzr, 1 @@ -67,7 +71,7 @@ bb.0: liveins: $lr, $x19, $x20, $lr - BLR_RVMARKER @cb2, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $x0 + BLR_RVMARKER @attachedcall, @cb2, csr_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $x0 $w12 = ORRWri $wzr, 1 $w12 = ORRWri $wzr, 1 $w12 = ORRWri $wzr, 1 diff --git a/llvm/test/CodeGen/X86/call-rv-marker.ll b/llvm/test/CodeGen/X86/call-rv-marker.ll --- a/llvm/test/CodeGen/X86/call-rv-marker.ll +++ b/llvm/test/CodeGen/X86/call-rv-marker.ll @@ -38,8 +38,8 @@ ret i8* %call } -define i8* @rv_marker_1_claim() { -; CHECK-LABEL: rv_marker_1_claim: +define i8* @rv_marker_1_unsafeClaim() { +; CHECK-LABEL: rv_marker_1_unsafeClaim: ; CHECK: pushq %rax ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: callq _foo1 diff --git a/llvm/test/Transforms/ObjCARC/contract-marker-funclet.ll b/llvm/test/Transforms/ObjCARC/contract-marker-funclet.ll --- a/llvm/test/Transforms/ObjCARC/contract-marker-funclet.ll +++ b/llvm/test/Transforms/ObjCARC/contract-marker-funclet.ll @@ -51,12 +51,12 @@ } ; CHECK-LABEL: define dso_local void @"?test_attr_claimRV@@YAXXZ"() -; CHECK: %[[CALL4:.*]] = notail call i8* @"?noexcept_func@@YAPAUobjc_object@@XZ"() [ "clang.arc.attachedcall"() ] -; CHECK: call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %[[CALL4]]) +; CHECK: %[[CALL4:.*]] = notail call i8* @"?noexcept_func@@YAPAUobjc_object@@XZ"() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.unsafeClaimAutoreleasedReturnValue) ] +; CHECK-NEXT: ret void ; CHECK: %[[V1:.*]] = cleanuppad -; CHECK: %[[CALL:.*]] = notail call i8* @"?noexcept_func@@YAPAUobjc_object@@XZ"() [ "funclet"(token %[[V1]]), "clang.arc.attachedcall"() ] -; CHECK: call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %[[CALL]]) [ "funclet"(token %[[V1]]) ] +; CHECK: %[[CALL:.*]] = notail call i8* @"?noexcept_func@@YAPAUobjc_object@@XZ"() [ "funclet"(token %[[V1]]), "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.unsafeClaimAutoreleasedReturnValue) ] +; CHECK-NEXT: cleanupret from %[[V1]] unwind to caller define dso_local void @"?test_attr_claimRV@@YAXXZ"() local_unnamed_addr #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { entry: diff --git a/llvm/test/Transforms/ObjCARC/contract-rv-attr.ll b/llvm/test/Transforms/ObjCARC/contract-rv-attr.ll --- a/llvm/test/Transforms/ObjCARC/contract-rv-attr.ll +++ b/llvm/test/Transforms/ObjCARC/contract-rv-attr.ll @@ -2,8 +2,8 @@ ; RUN: opt -passes=objc-arc-contract -S < %s | FileCheck %s ; CHECK-LABEL: define void @test0() { -; CHECK: %[[CALL:.*]] = notail call i8* @foo() [ "clang.arc.attachedcall"() ] -; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %[[CALL]]) +; CHECK: %[[CALL:.*]] = notail call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ] +; CHECK-NOT: call i8* @llvm.objc.retainAutoreleasedReturnValue( define void @test0() { %call1 = call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ] @@ -11,8 +11,8 @@ } ; CHECK-LABEL: define void @test1() { -; CHECK: %[[CALL:.*]] = notail call i8* @foo() [ "clang.arc.attachedcall"() ] -; CHECK: call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* %[[CALL]]) +; CHECK: %[[CALL:.*]] = notail call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.unsafeClaimAutoreleasedReturnValue) ] +; CHECK-NOT: call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue( define void @test1() { %call1 = call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.unsafeClaimAutoreleasedReturnValue) ] @@ -20,15 +20,15 @@ } ; CHECK-LABEL:define i8* @test2( -; CHECK: %[[CALL1:.*]] = invoke i8* @foo() [ "clang.arc.attachedcall"() ] +; CHECK: %[[V0:.*]] = invoke i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ] -; CHECK: %[[V0:.*]] = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %[[CALL1]]) -; CHECK-NEXT: br +; CHECK-NOT: = call i8* @llvm.objc.retainAutoreleasedReturnValue( +; CHECK: br -; CHECK: %[[CALL3:.*]] = invoke i8* @foo() [ "clang.arc.attachedcall"() ] +; CHECK: %[[V2:.*]] = invoke i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ] -; CHECK: %[[V2:.*]] = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %[[CALL3]]) -; CHECK-NEXT: br +; CHECK-NOT: = call i8* @llvm.objc.retainAutoreleasedReturnValue( +; CHECK: br ; CHECK: %[[RETVAL:.*]] = phi i8* [ %[[V0]], {{.*}} ], [ %[[V2]], {{.*}} ] ; CHECK: ret i8* %[[RETVAL]] diff --git a/llvm/test/Verifier/operand-bundles.ll b/llvm/test/Verifier/operand-bundles.ll --- a/llvm/test/Verifier/operand-bundles.ll +++ b/llvm/test/Verifier/operand-bundles.ll @@ -66,15 +66,17 @@ } define void @f_clang_arc_attachedcall() { -; CHECK: Multiple "clang.arc.attachedcall" operand bundles +; CHECK: requires one function as an argument +; CHECK-NEXT: call %0* @foo0() [ "clang.arc.attachedcall"() ] +; CHECK-NEXT: Multiple "clang.arc.attachedcall" operand bundles ; CHECK-NEXT: call %0* @foo0() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue), "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ] ; CHECK-NEXT: must call a function returning a pointer ; CHECK-NEXT: call i8 @foo1() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ] ; CHECK-NEXT: or a non-returning function ; CHECK-NEXT: call void @g() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ] -; CHECK-NEXT: can take either no arguments +; CHECK-NEXT: requires one function as an argument ; CHECK-NEXT: call %0* @foo0() [ "clang.arc.attachedcall"(i8* (i8*)* null) ] -; CHECK-NEXT: can take either no arguments +; CHECK-NEXT: requires one function as an argument ; CHECK-NEXT: call %0* @foo0() [ "clang.arc.attachedcall"(i64 0) ] ; CHECK-NEXT: invalid function argument ; CHECK-NEXT: call %0* @foo0() [ "clang.arc.attachedcall"(i8 ()* @foo1) ]