[clang] 9a9d636 - [CGObjC] Open cleanup scope before SaveAndRestore CurrentFuncletPad and push CatchRetScope early
Stefan Gränitz via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 22 03:03:36 PST 2022
Author: Stefan Gränitz
Date: 2022-11-22T12:02:53+01:00
New Revision: 9a9d636caeea9ca9364b906364ac1aaba0869858
URL: https://github.com/llvm/llvm-project/commit/9a9d636caeea9ca9364b906364ac1aaba0869858
DIFF: https://github.com/llvm/llvm-project/commit/9a9d636caeea9ca9364b906364ac1aaba0869858.diff
LOG: [CGObjC] Open cleanup scope before SaveAndRestore CurrentFuncletPad and push CatchRetScope early
Pushing the `CatchRetScope` early causes cleanups for catch parameters to be emitted in the basic block of the catch handler instead of the `catchret.dest` block. This is important because the latter is not part of the catchpad and this caused code truncations due to ARC PreISel intrinsics in WinEHPrepare.
Reviewed By: rnk
Differential Revision: https://reviews.llvm.org/D137939
Added:
Modified:
clang/lib/CodeGen/CGObjCRuntime.cpp
clang/test/CodeGenObjCXX/arc-exceptions-seh.mm
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp
index 58078d68f7166..fbf6d21bd407d 100644
--- a/clang/lib/CodeGen/CGObjCRuntime.cpp
+++ b/clang/lib/CodeGen/CGObjCRuntime.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/CodeGen/CodeGenABITypes.h"
+#include "llvm/IR/Instruction.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -227,13 +228,18 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
CatchHandler &Handler = Handlers[I];
CGF.EmitBlock(Handler.Block);
- llvm::CatchPadInst *CPI = nullptr;
- SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(CGF.CurrentFuncletPad);
- if (useFunclets)
- if ((CPI = dyn_cast_or_null<llvm::CatchPadInst>(Handler.Block->getFirstNonPHI()))) {
+
+ CodeGenFunction::LexicalScope Cleanups(CGF, Handler.Body->getSourceRange());
+ SaveAndRestore<llvm::Instruction *> RevertAfterScope(CGF.CurrentFuncletPad);
+ if (useFunclets) {
+ llvm::Instruction *CPICandidate = Handler.Block->getFirstNonPHI();
+ if (auto *CPI = dyn_cast_or_null<llvm::CatchPadInst>(CPICandidate)) {
CGF.CurrentFuncletPad = CPI;
CPI->setOperand(2, CGF.getExceptionSlot().getPointer());
+ CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CPI);
}
+ }
+
llvm::Value *RawExn = CGF.getExceptionFromSlot();
// Enter the catch.
@@ -241,8 +247,6 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
if (beginCatchFn)
Exn = CGF.EmitNounwindRuntimeCall(beginCatchFn, RawExn, "exn.adjusted");
- CodeGenFunction::LexicalScope cleanups(CGF, Handler.Body->getSourceRange());
-
if (endCatchFn) {
// Add a cleanup to leave the catch.
bool EndCatchMightThrow = (Handler.Variable == nullptr);
@@ -260,15 +264,13 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
CGF.EmitAutoVarDecl(*CatchParam);
EmitInitOfCatchParam(CGF, CastExn, CatchParam);
}
- if (CPI)
- CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CPI);
CGF.ObjCEHValueStack.push_back(Exn);
CGF.EmitStmt(Handler.Body);
CGF.ObjCEHValueStack.pop_back();
// Leave any cleanups associated with the catch.
- cleanups.ForceCleanup();
+ Cleanups.ForceCleanup();
CGF.EmitBranchThroughCleanup(Cont);
}
diff --git a/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm b/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm
index 267fbd65cc510..b432abcda97d6 100644
--- a/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm
+++ b/clang/test/CodeGenObjCXX/arc-exceptions-seh.mm
@@ -1,29 +1,64 @@
-// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s
+// 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
// WinEH requires funclet tokens on nounwind intrinsics if they can lower to
// regular function calls in the course of IR transformations.
//
// This is the case for ObjC ARC runtime intrinsics. Test that clang emits the
-// funclet tokens for llvm.objc.retain and llvm.objc.storeStrong and that they
-// refer to their catchpad's SSA value.
+// funclet tokens for llvm.objc.* calls inside catch- and cleanup-pads and that
+// they refer to their pad's SSA value.
- at class Ety;
-void opaque(void);
-void test_catch_with_objc_intrinsic(void) {
+void do_something();
+void may_throw(id);
+
+void try_catch_with_objc_intrinsic() {
+ id ex;
@try {
- opaque();
- } @catch (Ety *ex) {
- // Destroy ex when leaving catchpad. This emits calls to intrinsic functions
- // llvm.objc.retain and llvm.objc.storeStrong
+ may_throw(ex);
+ } @catch (id ex_caught) {
+ do_something();
+ may_throw(ex_caught);
}
}
-// CHECK-LABEL: define{{.*}} void {{.*}}test_catch_with_objc_intrinsic
-// ...
-// CHECK: catch.dispatch:
-// CHECK-NEXT: [[CATCHSWITCH:%[0-9]+]] = catchswitch within none
-// ...
-// CHECK: catch:
-// CHECK-NEXT: [[CATCHPAD:%[0-9]+]] = catchpad within [[CATCHSWITCH]]
-// CHECK: {{%[0-9]+}} = call {{.*}} @llvm.objc.retain{{.*}} [ "funclet"(token [[CATCHPAD]]) ]
-// CHECK: call {{.*}} @llvm.objc.storeStrong{{.*}} [ "funclet"(token [[CATCHPAD]]) ]
+// CHECK-LABEL: try_catch_with_objc_intrinsic
+//
+// CHECK: catch.dispatch:
+// CHECK-NEXT: [[CATCHSWITCH:%[0-9]+]] = catchswitch within none [label %catch] unwind label %[[CLEANUP1:.*]]
+//
+// All calls within a catchpad must have funclet tokens that refer to it:
+// CHECK: catch:
+// CHECK-NEXT: [[CATCHPAD:%[0-9]+]] = catchpad within [[CATCHSWITCH]]
+// CHECK: call
+// CHECK: @llvm.objc.retain
+// CHECK: [ "funclet"(token [[CATCHPAD]]) ]
+// CHECK: invoke
+// CHECK: do_something
+// CHECK: [ "funclet"(token [[CATCHPAD]]) ]
+// CHECK: unwind label %[[CLEANUP2:.*]]
+// CHECK: invoke
+// CHECK: may_throw
+// CHECK: [ "funclet"(token [[CATCHPAD]]) ]
+// CHECK: unwind label %[[CLEANUP2]]
+// CHECK: call
+// CHECK: @llvm.objc.storeStrong
+// CHECK: [ "funclet"(token [[CATCHPAD]]) ]
+// CHECK: catchret from [[CATCHPAD]] to label %catchret.dest
+//
+// This block exists and it's empty:
+// CHECK: catchret.dest:
+// CHECK-NEXT: br label %eh.cont
+//
+// CHECK: [[CLEANUP2]]:
+// CHECK-NEXT: [[CLEANUPPAD2:%[0-9]+]] = cleanuppad within [[CATCHPAD]]
+// CHECK: call
+// CHECK: @llvm.objc.storeStrong
+// CHECK: [ "funclet"(token [[CLEANUPPAD2]]) ]
+// CHECK: cleanupret from [[CLEANUPPAD2]]
+// CHECK: unwind label %[[CLEANUP1]]
+//
+// CHECK: [[CLEANUP1]]:
+// CHECK-NEXT: [[CLEANUPPAD1:%[0-9]+]] = cleanuppad within none
+// CHECK: call
+// CHECK: @llvm.objc.storeStrong
+// CHECK: [ "funclet"(token [[CLEANUPPAD1]]) ]
+// CHECK: cleanupret from [[CLEANUPPAD1]] unwind to caller
More information about the cfe-commits
mailing list