[clang] d9eece9 - [ObjC][ARC] Teach the OptimizeSequences step of ObjCARCOpts about WinEH funclet tokens
Stefan Gränitz via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 24 06:17:46 PST 2023
Author: Stefan Gränitz
Date: 2023-01-24T15:17:18+01:00
New Revision: d9eece916a8a9b370e1f90e6461c612d12c55729
URL: https://github.com/llvm/llvm-project/commit/d9eece916a8a9b370e1f90e6461c612d12c55729
DIFF: https://github.com/llvm/llvm-project/commit/d9eece916a8a9b370e1f90e6461c612d12c55729.diff
LOG: [ObjC][ARC] Teach the OptimizeSequences step of ObjCARCOpts about WinEH funclet tokens
When optimizing retain-release-sequences we insert (and delete) ObjC runtime calls. These calls need a funclet operand bundle that refers to the enclosing funclet pad whenever they are inserted in a WinEH funclet. WinEH funclets can contain multiple basic blocks. In order to find the enclosing funclet pad, we have to calculate the funclet coloring first.
Reviewed By: ahatanak
Differential Revision: https://reviews.llvm.org/D137944
Added:
llvm/test/Transforms/ObjCARC/funclet-catchpad.ll
Modified:
clang/test/CodeGenObjCXX/arc-exceptions-seh.mm
llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
Removed:
################################################################################
diff --git a/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm b/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm
index d5da1111f55db..0b697be54855d 100644
--- a/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm
+++ b/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fobjc-arc-exceptions -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-O0
-// RUN: %clang_cc1 -O2 -triple x86_64-pc-windows-msvc -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fobjc-arc-exceptions -fobjc-runtime=gnustep-2.0 -mllvm -enable-objc-arc-opts=false -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-O2
+// RUN: %clang_cc1 -O0 -triple x86_64-pc-windows-msvc -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fobjc-arc-exceptions -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-O0
+// RUN: %clang_cc1 -O2 -triple x86_64-pc-windows-msvc -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fobjc-arc-exceptions -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-O2
// WinEH requires funclet tokens on nounwind intrinsics if they can lower to
// regular function calls in the course of IR transformations.
@@ -24,7 +24,9 @@ void try_catch_with_objc_intrinsic() {
// CHECK-LABEL: try_catch_with_objc_intrinsic
//
// CHECK: catch.dispatch:
-// CHECK-NEXT: [[CATCHSWITCH:%[0-9]+]] = catchswitch within none [label %catch] unwind label %[[CLEANUP1:.*]]
+// CHECK-NEXT: [[CATCHSWITCH:%[0-9]+]] = catchswitch within none [label %catch]
+// CHECK-O0: unwind label %[[CLEANUP1:.*]]
+// CHECK-O2: unwind to caller
//
// All calls within a catchpad must have funclet tokens that refer to it:
// CHECK: catch:
@@ -58,12 +60,12 @@ void try_catch_with_objc_intrinsic() {
// CHECK-O2: @llvm.objc.release
// CHECK: [ "funclet"(token [[CLEANUPPAD2]]) ]
// CHECK: cleanupret from [[CLEANUPPAD2]]
-// CHECK: unwind label %[[CLEANUP1]]
+// CHECK-O0: unwind label %[[CLEANUP1]]
+// CHECK-O2: unwind to caller
//
-// CHECK: [[CLEANUP1]]:
-// CHECK-NEXT: [[CLEANUPPAD1:%[0-9]+]] = cleanuppad within none
-// CHECK: call
+// CHECK-O0: [[CLEANUP1]]:
+// CHECK-O0-NEXT: [[CLEANUPPAD1:%[0-9]+]] = cleanuppad within none
+// CHECK-O0: call
// CHECK-O0: @llvm.objc.storeStrong
-// CHECK-O2: @llvm.objc.release
-// CHECK: [ "funclet"(token [[CLEANUPPAD1]]) ]
-// CHECK: cleanupret from [[CLEANUPPAD1]] unwind to caller
+// CHECK-O0: [ "funclet"(token [[CLEANUPPAD1]]) ]
+// CHECK-O0: cleanupret from [[CLEANUPPAD1]] unwind to caller
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
index 927f3898c9c49..5108598426036 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
@@ -501,6 +501,8 @@ class ObjCARCOpt {
/// is in fact used in the current function.
unsigned UsedInThisFunction;
+ DenseMap<BasicBlock *, ColorVector> BlockEHColors;
+
bool OptimizeRetainRVCall(Function &F, Instruction *RetainRV);
void OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV,
ARCInstKind &Class);
@@ -508,17 +510,16 @@ class ObjCARCOpt {
/// Optimize an individual call, optionally passing the
/// GetArgRCIdentityRoot if it has already been computed.
- void OptimizeIndividualCallImpl(
- Function &F, DenseMap<BasicBlock *, ColorVector> &BlockColors,
- Instruction *Inst, ARCInstKind Class, const Value *Arg);
+ void OptimizeIndividualCallImpl(Function &F, Instruction *Inst,
+ ARCInstKind Class, const Value *Arg);
/// Try to optimize an AutoreleaseRV with a RetainRV or UnsafeClaimRV. If the
/// optimization occurs, returns true to indicate that the caller should
/// assume the instructions are dead.
- bool OptimizeInlinedAutoreleaseRVCall(
- Function &F, DenseMap<BasicBlock *, ColorVector> &BlockColors,
- Instruction *Inst, const Value *&Arg, ARCInstKind Class,
- Instruction *AutoreleaseRV, const Value *&AutoreleaseRVArg);
+ bool OptimizeInlinedAutoreleaseRVCall(Function &F, Instruction *Inst,
+ const Value *&Arg, ARCInstKind Class,
+ Instruction *AutoreleaseRV,
+ const Value *&AutoreleaseRVArg);
void CheckForCFGHazards(const BasicBlock *BB,
DenseMap<const BasicBlock *, BBState> &BBStates,
@@ -566,12 +567,46 @@ class ObjCARCOpt {
void OptimizeReturns(Function &F);
+ Instruction *cloneCallInstForBB(CallInst &CI, BasicBlock &BB) {
+ SmallVector<OperandBundleDef, 1> OpBundles;
+ for (unsigned I = 0, E = CI.getNumOperandBundles(); I != E; ++I) {
+ auto Bundle = CI.getOperandBundleAt(I);
+ // Funclets will be reassociated in the future.
+ if (Bundle.getTagID() == LLVMContext::OB_funclet)
+ continue;
+ OpBundles.emplace_back(Bundle);
+ }
+
+ if (!BlockEHColors.empty()) {
+ const ColorVector &CV = BlockEHColors.find(&BB)->second;
+ assert(CV.size() > 0 && "non-unique color for block!");
+ Instruction *EHPad = CV.front()->getFirstNonPHI();
+ if (EHPad->isEHPad())
+ OpBundles.emplace_back("funclet", EHPad);
+ }
+
+ return CallInst::Create(&CI, OpBundles);
+ }
+
+ void addOpBundleForFunclet(BasicBlock *BB,
+ SmallVectorImpl<OperandBundleDef> &OpBundles) {
+ if (!BlockEHColors.empty()) {
+ const ColorVector &CV = BlockEHColors.find(BB)->second;
+ assert(CV.size() > 0 && "Uncolored block");
+ for (BasicBlock *EHPadBB : CV)
+ if (auto *EHPad = dyn_cast<FuncletPadInst>(EHPadBB->getFirstNonPHI())) {
+ OpBundles.emplace_back("funclet", EHPad);
+ return;
+ }
+ }
+ }
+
#ifndef NDEBUG
void GatherStatistics(Function &F, bool AfterOptimization = false);
#endif
public:
- void init(Module &M);
+ void init(Function &F);
bool run(Function &F, AAResults &AA);
bool hasCFGChanged() const { return CFGChanged; }
};
@@ -624,8 +659,7 @@ ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) {
}
bool ObjCARCOpt::OptimizeInlinedAutoreleaseRVCall(
- Function &F, DenseMap<BasicBlock *, ColorVector> &BlockColors,
- Instruction *Inst, const Value *&Arg, ARCInstKind Class,
+ Function &F, Instruction *Inst, const Value *&Arg, ARCInstKind Class,
Instruction *AutoreleaseRV, const Value *&AutoreleaseRVArg) {
if (BundledInsts->contains(Inst))
return false;
@@ -678,8 +712,7 @@ bool ObjCARCOpt::OptimizeInlinedAutoreleaseRVCall(
EraseInstruction(Inst);
// Run the normal optimizations on Release.
- OptimizeIndividualCallImpl(F, BlockColors, Release, ARCInstKind::Release,
- Arg);
+ OptimizeIndividualCallImpl(F, Release, ARCInstKind::Release, Arg);
return true;
}
@@ -732,31 +765,6 @@ void ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F,
LLVM_DEBUG(dbgs() << "New: " << *AutoreleaseRV << "\n");
}
-namespace {
-Instruction *
-CloneCallInstForBB(CallInst &CI, BasicBlock &BB,
- const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
- SmallVector<OperandBundleDef, 1> OpBundles;
- for (unsigned I = 0, E = CI.getNumOperandBundles(); I != E; ++I) {
- auto Bundle = CI.getOperandBundleAt(I);
- // Funclets will be reassociated in the future.
- if (Bundle.getTagID() == LLVMContext::OB_funclet)
- continue;
- OpBundles.emplace_back(Bundle);
- }
-
- if (!BlockColors.empty()) {
- const ColorVector &CV = BlockColors.find(&BB)->second;
- assert(CV.size() == 1 && "non-unique color for block!");
- Instruction *EHPad = CV.front()->getFirstNonPHI();
- if (EHPad->isEHPad())
- OpBundles.emplace_back("funclet", EHPad);
- }
-
- return CallInst::Create(&CI, OpBundles);
-}
-}
-
/// Visit each call, one at a time, and make simplifications without doing any
/// additional analysis.
void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
@@ -764,11 +772,6 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
// Reset all the flags in preparation for recomputing them.
UsedInThisFunction = 0;
- DenseMap<BasicBlock *, ColorVector> BlockColors;
- if (F.hasPersonalityFn() &&
- isScopedEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
- BlockColors = colorEHFunclets(F);
-
// Store any delayed AutoreleaseRV intrinsics, so they can be easily paired
// with RetainRV and UnsafeClaimRV.
Instruction *DelayedAutoreleaseRV = nullptr;
@@ -781,7 +784,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
auto optimizeDelayedAutoreleaseRV = [&]() {
if (!DelayedAutoreleaseRV)
return;
- OptimizeIndividualCallImpl(F, BlockColors, DelayedAutoreleaseRV,
+ OptimizeIndividualCallImpl(F, DelayedAutoreleaseRV,
ARCInstKind::AutoreleaseRV,
DelayedAutoreleaseRVArg);
setDelayedAutoreleaseRV(nullptr);
@@ -844,7 +847,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
case ARCInstKind::UnsafeClaimRV:
if (DelayedAutoreleaseRV) {
// We have a potential RV pair. Check if they cancel out.
- if (OptimizeInlinedAutoreleaseRVCall(F, BlockColors, Inst, Arg, Class,
+ if (OptimizeInlinedAutoreleaseRVCall(F, Inst, Arg, Class,
DelayedAutoreleaseRV,
DelayedAutoreleaseRVArg)) {
setDelayedAutoreleaseRV(nullptr);
@@ -855,7 +858,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
break;
}
- OptimizeIndividualCallImpl(F, BlockColors, Inst, Class, Arg);
+ OptimizeIndividualCallImpl(F, Inst, Class, Arg);
}
// Catch the final delayed AutoreleaseRV.
@@ -889,9 +892,9 @@ static bool isInertARCValue(Value *V, SmallPtrSet<Value *, 1> &VisitedPhis) {
return false;
}
-void ObjCARCOpt::OptimizeIndividualCallImpl(
- Function &F, DenseMap<BasicBlock *, ColorVector> &BlockColors,
- Instruction *Inst, ARCInstKind Class, const Value *Arg) {
+void ObjCARCOpt::OptimizeIndividualCallImpl(Function &F, Instruction *Inst,
+ ARCInstKind Class,
+ const Value *Arg) {
LLVM_DEBUG(dbgs() << "Visiting: Class: " << Class << "; " << *Inst << "\n");
// We can delete this call if it takes an inert value.
@@ -1149,8 +1152,8 @@ void ObjCARCOpt::OptimizeIndividualCallImpl(
continue;
Value *Op = PN->getIncomingValue(i);
Instruction *InsertPos = &PN->getIncomingBlock(i)->back();
- CallInst *Clone = cast<CallInst>(
- CloneCallInstForBB(*CInst, *InsertPos->getParent(), BlockColors));
+ CallInst *Clone =
+ cast<CallInst>(cloneCallInstForBB(*CInst, *InsertPos->getParent()));
if (Op->getType() != ParamTy)
Op = new BitCastInst(Op, ParamTy, "", InsertPos);
Clone->setArgOperand(0, Op);
@@ -1772,7 +1775,9 @@ void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove,
Value *MyArg = ArgTy == ParamTy ? Arg :
new BitCastInst(Arg, ParamTy, "", InsertPt);
Function *Decl = EP.get(ARCRuntimeEntryPointKind::Retain);
- CallInst *Call = CallInst::Create(Decl, MyArg, "", InsertPt);
+ SmallVector<OperandBundleDef, 1> BundleList;
+ addOpBundleForFunclet(InsertPt->getParent(), BundleList);
+ CallInst *Call = CallInst::Create(Decl, MyArg, BundleList, "", InsertPt);
Call->setDoesNotThrow();
Call->setTailCall();
@@ -1785,7 +1790,9 @@ void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove,
Value *MyArg = ArgTy == ParamTy ? Arg :
new BitCastInst(Arg, ParamTy, "", InsertPt);
Function *Decl = EP.get(ARCRuntimeEntryPointKind::Release);
- CallInst *Call = CallInst::Create(Decl, MyArg, "", InsertPt);
+ SmallVector<OperandBundleDef, 1> BundleList;
+ addOpBundleForFunclet(InsertPt->getParent(), BundleList);
+ CallInst *Call = CallInst::Create(Decl, MyArg, BundleList, "", InsertPt);
// Attach a clang.imprecise_release metadata tag, if appropriate.
if (MDNode *M = ReleasesToMove.ReleaseMetadata)
Call->setMetadata(MDKindCache.get(ARCMDKindID::ImpreciseRelease), M);
@@ -2401,17 +2408,22 @@ ObjCARCOpt::GatherStatistics(Function &F, bool AfterOptimization) {
}
#endif
-void ObjCARCOpt::init(Module &M) {
+void ObjCARCOpt::init(Function &F) {
if (!EnableARCOpts)
return;
// Intuitively, objc_retain and others are nocapture, however in practice
// they are not, because they return their argument value. And objc_release
// calls finalizers which can have arbitrary side effects.
- MDKindCache.init(&M);
+ MDKindCache.init(F.getParent());
// Initialize our runtime entry point cache.
- EP.init(&M);
+ EP.init(F.getParent());
+
+ // Compute which blocks are in which funclet.
+ if (F.hasPersonalityFn() &&
+ isScopedEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
+ BlockEHColors = colorEHFunclets(F);
}
bool ObjCARCOpt::run(Function &F, AAResults &AA) {
@@ -2487,7 +2499,7 @@ bool ObjCARCOpt::run(Function &F, AAResults &AA) {
PreservedAnalyses ObjCARCOptPass::run(Function &F,
FunctionAnalysisManager &AM) {
ObjCARCOpt OCAO;
- OCAO.init(*F.getParent());
+ OCAO.init(F);
bool Changed = OCAO.run(F, AM.getResult<AAManager>(F));
bool CFGChanged = OCAO.hasCFGChanged();
diff --git a/llvm/test/Transforms/ObjCARC/funclet-catchpad.ll b/llvm/test/Transforms/ObjCARC/funclet-catchpad.ll
new file mode 100644
index 0000000000000..9f047c29bc159
--- /dev/null
+++ b/llvm/test/Transforms/ObjCARC/funclet-catchpad.ll
@@ -0,0 +1,40 @@
+; RUN: opt -mtriple=x86_64-windows-msvc -passes=objc-arc -S < %s | FileCheck %s
+
+; Check that funclet tokens are preserved
+;
+; CHECK-LABEL: catch:
+; CHECK: %1 = catchpad within %0
+; CHECK: %2 = tail call ptr @llvm.objc.retain(ptr %exn) #0 [ "funclet"(token %1) ]
+; CHECK: call void @llvm.objc.release(ptr %exn) #0 [ "funclet"(token %1) ]
+; CHECK: catchret from %1 to label %eh.cont
+
+define void @try_catch_with_objc_intrinsic() personality ptr @__CxxFrameHandler3 {
+entry:
+ %exn.slot = alloca ptr, align 8
+ invoke void @may_throw(ptr null) to label %eh.cont unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %entry
+ %0 = catchswitch within none [label %catch] unwind to caller
+
+eh.cont: ; preds = %catch, %entry
+ ret void
+
+catch: ; preds = %catch.dispatch
+ %1 = catchpad within %0 [ptr null, i32 0, ptr %exn.slot]
+ br label %if.then
+
+if.then: ; preds = %catch
+ %exn = load ptr, ptr null, align 8
+ %2 = call ptr @llvm.objc.retain(ptr %exn) [ "funclet"(token %1) ]
+ call void @may_throw(ptr %exn)
+ call void @llvm.objc.release(ptr %exn) [ "funclet"(token %1) ]
+ catchret from %1 to label %eh.cont
+}
+
+declare void @may_throw(ptr)
+declare i32 @__CxxFrameHandler3(...)
+
+declare ptr @llvm.objc.retain(ptr) #0
+declare void @llvm.objc.release(ptr) #0
+
+attributes #0 = { nounwind }
More information about the cfe-commits
mailing list