[PATCH] D127962: [WinEHPrepare] Propagate funclet tokens when inlining into EH funclets

Stefan Gränitz via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 16 06:38:13 PDT 2022


sgraenitz created this revision.
sgraenitz added reviewers: theraven, rnk, DHowett-MSFT.
Herald added a subscriber: hiraditya.
Herald added a project: All.
sgraenitz requested review of this revision.
Herald added a project: LLVM.

WinEH requires funclet tokens for (nounwind) ObjC++ ARC intrinsics, because they are subject to pre-ISel lowering. That's because they appear as regular function calls for subsequent passes (like WinEHPrepare). Without funclet token they would be consider them implausible instrucitons and marked as unreachable. Affected EH funclets would get truncated silently, which causes unpredictable crashes at runtime.

Thus, when we target WinEH and generate calls to pre-ISel intrinsics from EH funclets, we emit funclet tokens explicitly. My previous patch D124762 <https://reviews.llvm.org/D124762> implements that.

Now, the inliner has to propagate funclet tokens to such intrinsics, if they get inlined into EH funclets. That's what this patch implements.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D127962

Files:
  llvm/lib/Transforms/Utils/InlineFunction.cpp
  llvm/test/Feature/OperandBundles/inliner-funclet-wineh.ll


Index: llvm/test/Feature/OperandBundles/inliner-funclet-wineh.ll
===================================================================
--- /dev/null
+++ llvm/test/Feature/OperandBundles/inliner-funclet-wineh.ll
@@ -0,0 +1,55 @@
+; RUN: opt -S -always-inline -mtriple=x86_64-windows-msvc < %s | FileCheck %s
+
+; WinEH doesn't require funclet tokens on nounwind intrinsics per se. ObjC++ ARC
+; intrinsics are a special case, because they are subject to pre-ISel lowering.
+; They appear as regular function calls for subsequent passes, like WinEHPrepare
+; which would consider them implausible instrucitons and mark them unreachable.
+; Affected EH funclets would get truncated silently, which causes unpredictable
+; crashes at runtime.
+;
+; Thus, when we target WinEH and generate calls to pre-ISel intrinsics from EH
+; funclets, we emit funclet tokens explicitly.
+;
+; The inliner has to propagate funclet tokens to such intrinsics, if they get
+; inlined into EH funclets.
+
+define void @inlined_fn(ptr %ex) #1 {
+entry:
+  call void @llvm.objc.storeStrong(ptr %ex, ptr null)
+  ret void
+}
+
+define void @test_catch_with_inline() personality ptr @__CxxFrameHandler3 {
+entry:
+  %exn.slot = alloca ptr, align 8
+  %ex = alloca ptr, align 8
+  invoke void @opaque() to label %invoke.cont unwind label %catch.dispatch
+
+catch.dispatch:
+  %0 = catchswitch within none [label %catch] unwind to caller
+
+invoke.cont:
+  unreachable
+
+catch:
+  %1 = catchpad within %0 [ptr null, i32 64, ptr %exn.slot]
+  call void @inlined_fn(ptr %ex) [ "funclet"(token %1) ]
+  catchret from %1 to label %catchret.dest
+
+catchret.dest:
+  ret void
+}
+
+declare void @opaque()
+declare void @llvm.objc.storeStrong(ptr, ptr) #0
+declare i32 @__CxxFrameHandler3(...)
+
+attributes #0 = { nounwind }
+attributes #1 = { alwaysinline }
+
+; CHECK-LABEL:  define void @test_catch_with_inline()
+;                 ...
+; CHECK:        catch:
+; CHECK-NEXT:     %1 = catchpad within %0 [ptr null, i32 64, ptr %exn.slot]
+; CHECK-NEXT:     call void @llvm.objc.storeStrong(ptr %ex, ptr null) [ "funclet"(token %1) ]
+; CHECK-NEXT:     catchret from %1 to label %catchret.dest
Index: llvm/lib/Transforms/Utils/InlineFunction.cpp
===================================================================
--- llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -1833,8 +1833,9 @@
   // We need to figure out which funclet the callsite was in so that we may
   // properly nest the callee.
   Instruction *CallSiteEHPad = nullptr;
+  EHPersonality Personality = EHPersonality::Unknown;
   if (CallerPersonality) {
-    EHPersonality Personality = classifyEHPersonality(CallerPersonality);
+    Personality = classifyEHPersonality(CallerPersonality);
     if (isScopedEHPersonality(Personality)) {
       Optional<OperandBundleUse> ParentFunclet =
           CB.getOperandBundle(LLVMContext::OB_funclet);
@@ -2305,11 +2306,16 @@
         if (!I)
           continue;
 
-        // Skip call sites which are nounwind intrinsics.
-        auto *CalledFn =
-            dyn_cast<Function>(I->getCalledOperand()->stripPointerCasts());
-        if (CalledFn && CalledFn->isIntrinsic() && I->doesNotThrow())
-          continue;
+        // In general, skip call sites which are nounwind intrinsics. When
+        // targeting WinEH, we must propagate funclet tokens to pre-ISel
+        // intrinsics, if they get inlined into EH funclets. Otherwise,
+        // WinEHPrepare would mark them unreachable and cause truncations.
+        if (Personality != EHPersonality::MSVC_CXX) {
+          auto *CalledFn =
+              dyn_cast<Function>(I->getCalledOperand()->stripPointerCasts());
+          if (CalledFn && CalledFn->isIntrinsic() && I->doesNotThrow())
+            continue;
+        }
 
         // Skip call sites which already have a "funclet" bundle.
         if (I->getOperandBundle(LLVMContext::OB_funclet))


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D127962.437525.patch
Type: text/x-patch
Size: 3938 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20220616/dd4d6f3d/attachment.bin>


More information about the llvm-commits mailing list