diff --git a/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm b/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm --- 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 @@ // 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 @@ // 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 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -546,7 +546,9 @@ void MoveCalls(Value *Arg, RRInfo &RetainsToMove, RRInfo &ReleasesToMove, BlotMapVector &Retains, DenseMap &Releases, - SmallVectorImpl &DeadInsts, Module *M); + SmallVectorImpl &DeadInsts, + const DenseMap &BlockColors, + Module *M); bool PairUpRetainsAndReleases(DenseMap &BBStates, BlotMapVector &Retains, @@ -559,7 +561,7 @@ bool PerformCodePlacement(DenseMap &BBStates, BlotMapVector &Retains, - DenseMap &Releases, Module *M); + DenseMap &Releases, Function &F); void OptimizeWeakCalls(Function &F); @@ -756,6 +758,20 @@ return CallInst::Create(&CI, OpBundles); } + +void addOpBundleForFunclet(BasicBlock *BB, + const DenseMap &BlockColors, + SmallVectorImpl &OpBundles) { + if (!BlockColors.empty()) { + const ColorVector &CV = BlockColors.find(BB)->second; + assert(CV.size() > 0 && "Uncolored block"); + for (BasicBlock *EHPadBB : CV) + if (auto *EHPad = dyn_cast(EHPadBB->getFirstNonPHI())) { + OpBundles.emplace_back("funclet", EHPad); + return; + } + } +} } /// Visit each call, one at a time, and make simplifications without doing any @@ -1757,12 +1773,12 @@ } /// Move the calls in RetainsToMove and ReleasesToMove. -void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove, - RRInfo &ReleasesToMove, - BlotMapVector &Retains, - DenseMap &Releases, - SmallVectorImpl &DeadInsts, - Module *M) { +void ObjCARCOpt::MoveCalls( + Value *Arg, RRInfo &RetainsToMove, RRInfo &ReleasesToMove, + BlotMapVector &Retains, + DenseMap &Releases, + SmallVectorImpl &DeadInsts, + const DenseMap &BlockColors, Module *M) { Type *ArgTy = Arg->getType(); Type *ParamTy = PointerType::getUnqual(Type::getInt8Ty(ArgTy->getContext())); @@ -1773,7 +1789,9 @@ Value *MyArg = ArgTy == ParamTy ? Arg : new BitCastInst(Arg, ParamTy, "", InsertPt); Function *Decl = EP.get(ARCRuntimeEntryPointKind::Retain); - CallInst *Call = CallInst::Create(Decl, MyArg, "", InsertPt); + SmallVector BundleList; + addOpBundleForFunclet(InsertPt->getParent(), BlockColors, BundleList); + CallInst *Call = CallInst::Create(Decl, MyArg, BundleList, "", InsertPt); Call->setDoesNotThrow(); Call->setTailCall(); @@ -1786,7 +1804,9 @@ Value *MyArg = ArgTy == ParamTy ? Arg : new BitCastInst(Arg, ParamTy, "", InsertPt); Function *Decl = EP.get(ARCRuntimeEntryPointKind::Release); - CallInst *Call = CallInst::Create(Decl, MyArg, "", InsertPt); + SmallVector BundleList; + addOpBundleForFunclet(InsertPt->getParent(), BlockColors, 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); @@ -2015,9 +2035,14 @@ bool ObjCARCOpt::PerformCodePlacement( DenseMap &BBStates, BlotMapVector &Retains, - DenseMap &Releases, Module *M) { + DenseMap &Releases, Function &F) { LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::PerformCodePlacement ==\n"); + DenseMap BlockColors; + if (F.hasPersonalityFn() && + isScopedEHPersonality(classifyEHPersonality(F.getPersonalityFn()))) + BlockColors = colorEHFunclets(F); + bool AnyPairsCompletelyEliminated = false; SmallVector DeadInsts; @@ -2053,15 +2078,15 @@ RRInfo RetainsToMove, ReleasesToMove; bool PerformMoveCalls = PairUpRetainsAndReleases( - BBStates, Retains, Releases, M, Retain, DeadInsts, + BBStates, Retains, Releases, F.getParent(), Retain, DeadInsts, RetainsToMove, ReleasesToMove, Arg, KnownSafe, AnyPairsCompletelyEliminated); if (PerformMoveCalls) { // Ok, everything checks out and we're all set. Let's move/delete some // code! - MoveCalls(Arg, RetainsToMove, ReleasesToMove, - Retains, Releases, DeadInsts, M); + MoveCalls(Arg, RetainsToMove, ReleasesToMove, Retains, Releases, + DeadInsts, BlockColors, F.getParent()); } } @@ -2251,9 +2276,8 @@ return false; // Transform. - bool AnyPairsCompletelyEliminated = PerformCodePlacement(BBStates, Retains, - Releases, - F.getParent()); + bool AnyPairsCompletelyEliminated = + PerformCodePlacement(BBStates, Retains, Releases, F); return AnyPairsCompletelyEliminated && NestingDetected; } diff --git a/llvm/test/Transforms/ObjCARC/funclet-catchpad.ll b/llvm/test/Transforms/ObjCARC/funclet-catchpad.ll new file mode 100644 --- /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 }