[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