[WinEH] Fix cleanup state numbering
authorJoseph Tremoulet <jotrem@microsoft.com>
Fri, 9 Oct 2015 00:46:08 +0000 (00:46 +0000)
committerJoseph Tremoulet <jotrem@microsoft.com>
Fri, 9 Oct 2015 00:46:08 +0000 (00:46 +0000)
Summary:
 - Recurse from cleanupendpads to their cleanuppads, to make sure the
   cleanuppad is visited if it has a cleanupendpad but no cleanupret.
 - Check for and avoid double-processing cleanuppads, to allow for them to
   have multiple cleanuprets (plus cleanupendpads).
 - Update Cxx state numbering to visit toplevel cleanupendpads and to
   recurse from cleanupendpads to their preds, to ensure we number any
   funclets in inlined cleanups.  SEH state numbering already did this.

Reviewers: rnk

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D13374

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@249792 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/WinEHPrepare.cpp
test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll [new file with mode: 0644]

index 5141df6cc85821b8dad9202e6e420721432354d3..1cb50514f681a2fe02d520a833c427a2d18f7cc5 100644 (file)
@@ -2715,6 +2715,9 @@ static void calculateExplicitCXXStateNumbers(WinEHFuncInfo &FuncInfo,
     DEBUG(dbgs() << "CatchHigh[" << FirstTryPad->getName() << "]: " << CatchHigh
                  << '\n');
   } else if (isa<CleanupPadInst>(FirstNonPHI)) {
+    // A cleanup can have multiple exits; don't re-process after the first.
+    if (FuncInfo.EHPadStateMap.count(FirstNonPHI))
+      return;
     int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, &BB);
     FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState;
     DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB "
@@ -2722,6 +2725,15 @@ static void calculateExplicitCXXStateNumbers(WinEHFuncInfo &FuncInfo,
     for (const BasicBlock *PredBlock : predecessors(&BB))
       if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
         calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, CleanupState);
+  } else if (auto *CEPI = dyn_cast<CleanupEndPadInst>(FirstNonPHI)) {
+    // Propagate ParentState to the cleanuppad in case it doesn't have
+    // any cleanuprets.
+    BasicBlock *CleanupBlock = CEPI->getCleanupPad()->getParent();
+    calculateExplicitCXXStateNumbers(FuncInfo, *CleanupBlock, ParentState);
+    // Anything unwinding through CleanupEndPadInst is in ParentState.
+    for (const BasicBlock *PredBlock : predecessors(&BB))
+      if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
+        calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, ParentState);
   } else if (isa<TerminatePadInst>(FirstNonPHI)) {
     report_fatal_error("Not yet implemented!");
   } else {
@@ -2794,6 +2806,9 @@ static void calculateExplicitSEHStateNumbers(WinEHFuncInfo &FuncInfo,
       if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
         calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState);
   } else if (isa<CleanupPadInst>(FirstNonPHI)) {
+    // A cleanup can have multiple exits; don't re-process after the first.
+    if (FuncInfo.EHPadStateMap.count(FirstNonPHI))
+      return;
     int CleanupState = addSEHFinally(FuncInfo, ParentState, &BB);
     FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState;
     DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB "
@@ -2801,7 +2816,11 @@ static void calculateExplicitSEHStateNumbers(WinEHFuncInfo &FuncInfo,
     for (const BasicBlock *PredBlock : predecessors(&BB))
       if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
         calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, CleanupState);
-  } else if (isa<CleanupEndPadInst>(FirstNonPHI)) {
+  } else if (auto *CEPI = dyn_cast<CleanupEndPadInst>(FirstNonPHI)) {
+    // Propagate ParentState to the cleanuppad in case it doesn't have
+    // any cleanuprets.
+    BasicBlock *CleanupBlock = CEPI->getCleanupPad()->getParent();
+    calculateExplicitSEHStateNumbers(FuncInfo, *CleanupBlock, ParentState);
     // Anything unwinding through CleanupEndPadInst is in ParentState.
     FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState;
     DEBUG(dbgs() << "Assigning state #" << ParentState << " to BB "
@@ -2859,9 +2878,6 @@ void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
     if (BB.isLandingPad())
       report_fatal_error("MSVC C++ EH cannot use landingpads");
     const Instruction *FirstNonPHI = BB.getFirstNonPHI();
-    // Skip cleanupendpads; they are exits, not entries.
-    if (isa<CleanupEndPadInst>(FirstNonPHI))
-      continue;
     if (!doesEHPadUnwindToCaller(FirstNonPHI))
       continue;
     calculateExplicitCXXStateNumbers(FuncInfo, BB, -1);
diff --git a/test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll b/test/CodeGen/WinEH/wineh-statenumbering-cleanups.ll
new file mode 100644 (file)
index 0000000..bd1f232
--- /dev/null
@@ -0,0 +1,100 @@
+; RUN: sed -e s/.Cxx:// %s | opt -mtriple=x86-pc-windows-msvc -S -x86-winehstate | FileCheck %s
+; RUN: sed -e s/.SEH:// %s | opt -mtriple=x86-pc-windows-msvc -S -x86-winehstate | FileCheck %s
+
+declare i32 @__CxxFrameHandler3(...)
+declare i32 @_except_handler3(...)
+declare void @dummy_filter()
+
+declare void @f(i32)
+
+; CHECK-LABEL: define void @test1(
+;Cxx: define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
+;SEH: define void @test1() personality i32 (...)* @_except_handler3 {
+entry:
+  ; CHECK: entry:
+  ; CHECK:  store i32 0
+  ; CHECK:  invoke void @f(i32 0)
+  invoke void @f(i32 0)
+    to label %exit unwind label %cleanup.pad
+cleanup.pad:
+  ; CHECK: cleanup.pad:
+  ; CHECK:   store i32 1
+  ; CHECK:   invoke void @f(i32 1)
+  %cleanup = cleanuppad []
+  invoke void @f(i32 1)
+    to label %cleanup.ret unwind label %catch.pad
+catch.pad:
+;Cxx: %catch = catchpad [i8* null, i32 u0x40, i8* null]
+;SEH: %catch = catchpad [void ()* @dummy_filter]
+        to label %catch.body unwind label %catch.end
+catch.body:
+  catchret %catch to label %cleanup.ret
+catch.end:
+  catchendpad unwind label %cleanup.end
+cleanup.ret:
+  cleanupret %cleanup unwind to caller
+cleanup.end:
+  cleanupendpad %cleanup unwind to caller
+exit:
+  ret void
+}
+
+; CHECK-LABEL: define void @test2(
+;Cxx: define void @test2(i1 %b) personality i32 (...)* @__CxxFrameHandler3 {
+;SEH: define void @test2(i1 %b) personality i32 (...)* @_except_handler3 {
+entry:
+  ; CHECK: entry:
+  ; CHECK:   store i32 1
+  ; CHECK:   invoke void @f(i32 1)
+  invoke void @f(i32 1)
+    to label %exit unwind label %cleanup.pad
+cleanup.pad:
+  %cleanup = cleanuppad []
+  br i1 %b, label %left, label %right
+left:
+  cleanupret %cleanup unwind label %catch.pad
+right:
+  cleanupret %cleanup unwind label %catch.pad
+catch.pad:
+;Cxx: %catch = catchpad [i8* null, i32 u0x40, i8* null]
+;SEH: %catch = catchpad [void ()* @dummy_filter]
+        to label %catch.body unwind label %catch.end
+catch.body:
+  catchret %catch to label %exit
+catch.end:
+  catchendpad unwind to caller
+exit:
+  ret void
+}
+
+; CHECK-LABEL: define void @test3(
+;Cxx: define void @test3() personality i32 (...)* @__CxxFrameHandler3 {
+;SEH: define void @test3() personality i32 (...)* @_except_handler3 {
+entry:
+  ; CHECK: entry:
+  ; CHECK:   store i32 1
+  ; CHECK:   invoke void @f(i32 1)
+  invoke void @f(i32 1)
+    to label %exit unwind label %cleanup.pad
+cleanup.pad:
+  ; CHECK: cleanup.pad:
+  ; CHECK:   store i32 0
+  ; CHECK:   invoke void @f(i32 0)
+  %cleanup = cleanuppad []
+  invoke void @f(i32 0)
+    to label %unreachable unwind label %cleanup.end
+unreachable:
+  unreachable
+cleanup.end:
+  cleanupendpad %cleanup unwind label %catch.pad
+catch.pad:
+;Cxx: %catch = catchpad [i8* null, i32 u0x40, i8* null]
+;SEH: %catch = catchpad [void ()* @dummy_filter]
+        to label %catch.body unwind label %catch.end
+catch.body:
+  catchret %catch to label %exit
+catch.end:
+  catchendpad unwind to caller
+exit:
+  ret void
+}