[ObjC][ARC] Handle operand bundle "clang.arc.attachedcall" on targets

that don't use the inline asm marker

This patch makes the changes to the ARC middle-end passes that are
needed to handle operand bundle "clang.arc.attachedcall" on targets that
don't use the inline asm marker for the retainRV/autoreleaseRV
handshake (e.g., x86-64).

Note that anyone who wants to use the operand bundle on their target has
to teach their backend to handle the operand bundle. The x86-64 backend
already knows about the operand bundle (see
https://reviews.llvm.org/D94597).

Differential Revision: https://reviews.llvm.org/D111334
This commit is contained in:
Akira Hatanaka 2021-11-08 17:50:08 -08:00
parent 92c9b340be
commit 8f8d9f743d
5 changed files with 57 additions and 16 deletions

View File

@ -124,14 +124,19 @@ BundledRetainClaimRVs::~BundledRetainClaimRVs() {
if (auto *CI = dyn_cast<CallInst>(CB))
CI->setTailCallKind(CallInst::TCK_NoTail);
// Remove the ARC intrinsic function operand from the operand bundle.
OperandBundleDef OB("clang.arc.attachedcall", None);
auto *NewCB = CallBase::Create(CB, OB, CB);
CB->replaceAllUsesWith(NewCB);
CB->eraseFromParent();
} else {
EraseInstruction(P.first);
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);
}
RVCalls.clear();

View File

@ -105,7 +105,8 @@ CallInst *createCallInstWithColors(
class BundledRetainClaimRVs {
public:
BundledRetainClaimRVs(bool ContractPass) : ContractPass(ContractPass) {}
BundledRetainClaimRVs(bool ContractPass, bool UseMarker)
: ContractPass(ContractPass), UseMarker(UseMarker) {}
~BundledRetainClaimRVs();
/// Insert a retainRV/claimRV call to the normal destination blocks of invokes
@ -155,6 +156,9 @@ private:
DenseMap<CallInst *, CallBase *> RVCalls;
bool ContractPass;
/// Indicates whether the target uses a special inline-asm marker.
bool UseMarker;
};
} // end namespace objcarc

View File

@ -434,13 +434,21 @@ bool ObjCARCContract::tryToPeepholeInstruction(
LLVM_FALLTHROUGH;
case ARCInstKind::RetainRV:
case ARCInstKind::ClaimRV: {
// If we're compiling for a target which needs a special inline-asm
// marker to do the return value optimization and the retainRV/claimRV call
// wasn't bundled with a call, insert the marker now.
if (!RVInstMarker)
return false;
bool IsInstContainedInBundle = BundledInsts->contains(Inst);
if (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
// replacing uses of the retainRV/claimRV call's argument with its result.
if (!RVInstMarker)
return IsInstContainedInBundle;
// The target needs a special inline-asm marker.
// 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)
return false;
BasicBlock::iterator BBI = Inst->getIterator();
@ -540,7 +548,7 @@ bool ObjCARCContract::run(Function &F, AAResults *A, DominatorTree *D) {
AA = A;
DT = D;
PA.setAA(A);
BundledRetainClaimRVs BRV(true);
BundledRetainClaimRVs BRV(true, RVInstMarker);
BundledInsts = &BRV;
std::pair<bool, bool> R = BundledInsts->insertAfterInvokes(F, DT);

View File

@ -2461,7 +2461,7 @@ bool ObjCARCOpt::run(Function &F, AAResults &AA) {
return false;
Changed = CFGChanged = false;
BundledRetainClaimRVs BRV(false);
BundledRetainClaimRVs BRV(false, objcarc::getRVInstMarker(*F.getParent()));
BundledInsts = &BRV;
LLVM_DEBUG(dbgs() << "<<< ObjCARCOpt: Visiting Function: " << F.getName()

View File

@ -0,0 +1,24 @@
; RUN: opt -objc-arc-contract -S < %s | FileCheck %s
; RUN: opt -passes=objc-arc-contract -S < %s | FileCheck %s
; CHECK-LABEL: define void @test0() {
; CHECK: %[[CALL:.*]] = notail call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ]
; CHECK-NEXT: ret void
define void @test0() {
%call1 = call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ]
ret void
}
; CHECK-LABEL: define void @test1() {
; CHECK: %[[CALL:.*]] = notail call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.unsafeClaimAutoreleasedReturnValue) ]
; CHECK-NEXT: ret void
define void @test1() {
%call1 = call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.unsafeClaimAutoreleasedReturnValue) ]
ret void
}
declare i8* @foo()
declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*)
declare i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8*)