[WinEH] Don't visit the same catchswitch twice
authorDavid Majnemer <david.majnemer@gmail.com>
Wed, 23 Dec 2015 03:59:04 +0000 (03:59 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Wed, 23 Dec 2015 03:59:04 +0000 (03:59 +0000)
We visited the same catchswitch twice because it was both the child of
another funclet and the predecessor of a cleanuppad.

Instead, change the numbering algorithm to only recurse if the unwind
destination of the inner funclet agrees with the unwind destination of
the catchswitch.

This fixes PR25926.

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

lib/CodeGen/WinEHPrepare.cpp
test/CodeGen/WinEH/wineh-statenumbering.ll

index 3b076b6..dc9f78f 100644 (file)
@@ -165,8 +165,7 @@ static void calculateStateNumbersForInvokes(const Function *Fn,
       continue;
 
     auto &BBColors = BlockColors[&BB];
-    assert(BBColors.size() == 1 &&
-           "multi-color BB not removed by preparation");
+    assert(BBColors.size() == 1 && "multi-color BB not removed by preparation");
     BasicBlock *FuncletEntryBB = BBColors.front();
 
     BasicBlock *FuncletUnwindDest;
@@ -249,8 +248,13 @@ static void calculateCXXStateNumbers(WinEHFuncInfo &FuncInfo,
       FuncInfo.FuncletBaseStateMap[CatchPad] = CatchLow;
       for (const User *U : CatchPad->users()) {
         const auto *UserI = cast<Instruction>(U);
-        if (UserI->isEHPad())
-          calculateCXXStateNumbers(FuncInfo, UserI, CatchLow);
+        if (auto *InnerCatchSwitch = dyn_cast<CatchSwitchInst>(UserI))
+          if (InnerCatchSwitch->getUnwindDest() == CatchSwitch->getUnwindDest())
+            calculateCXXStateNumbers(FuncInfo, UserI, CatchLow);
+        if (auto *InnerCleanupPad = dyn_cast<CleanupPadInst>(UserI))
+          if (getCleanupRetUnwindDest(InnerCleanupPad) ==
+              CatchSwitch->getUnwindDest())
+            calculateCXXStateNumbers(FuncInfo, UserI, CatchLow);
       }
     }
     int CatchHigh = FuncInfo.getLastStateNumber();
@@ -347,9 +351,13 @@ static void calculateSEHStateNumbers(WinEHFuncInfo &FuncInfo,
     // outside the __try.
     for (const User *U : CatchPad->users()) {
       const auto *UserI = cast<Instruction>(U);
-      if (UserI->isEHPad()) {
-        calculateSEHStateNumbers(FuncInfo, UserI, ParentState);
-      }
+      if (auto *InnerCatchSwitch = dyn_cast<CatchSwitchInst>(UserI))
+        if (InnerCatchSwitch->getUnwindDest() == CatchSwitch->getUnwindDest())
+          calculateSEHStateNumbers(FuncInfo, UserI, ParentState);
+      if (auto *InnerCleanupPad = dyn_cast<CleanupPadInst>(UserI))
+        if (getCleanupRetUnwindDest(InnerCleanupPad) ==
+            CatchSwitch->getUnwindDest())
+          calculateSEHStateNumbers(FuncInfo, UserI, ParentState);
     }
   } else {
     auto *CleanupPad = cast<CleanupPadInst>(FirstNonPHI);
index b7ec843..dab7fde 100644 (file)
@@ -79,8 +79,63 @@ define i32 @nopads() #0 personality i32 (...)* @__CxxFrameHandler3 {
 ; CHECK-NEXT: ret i32 0
 ; CHECK-NOT: __ehhandler$nopads
 
+; CHECK-LABEL: define void @PR25926()
+define void @PR25926() personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+  ; CHECK: entry:
+  ; CHECK:   store i32 -1
+  ; CHECK:   store i32 0
+  ; CHECK:   invoke void @_CxxThrowException(
+  invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null)
+          to label %unreachable unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %entry
+  %0 = catchswitch within none [label %catch] unwind to caller
+
+catch:                                            ; preds = %catch.dispatch
+  %1 = catchpad within %0 [i8* null, i32 64, i8* null]
+  ; CHECK: catch:
+  ; CHECK:   store i32 3
+  ; CHECK:   invoke void @_CxxThrowException(
+  invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) [ "funclet"(token %1) ]
+          to label %unreachable1 unwind label %catch.dispatch1
+
+catch.dispatch1:                                  ; preds = %catch
+  %2 = catchswitch within %1 [label %catch2] unwind label %ehcleanup
+
+catch2:                                           ; preds = %catch.dispatch1
+  %3 = catchpad within %2 [i8* null, i32 64, i8* null]
+  catchret from %3 to label %try.cont
+
+try.cont:                                         ; preds = %catch2
+  ; CHECK: try.cont:
+  ; CHECK:   store i32 1
+  ; CHECK:   call void @dtor()
+  call void @dtor() #3 [ "funclet"(token %1) ]
+  catchret from %1 to label %try.cont4
+
+try.cont4:                                        ; preds = %try.cont
+  ret void
+
+ehcleanup:                                        ; preds = %catch.dispatch1
+  %4 = cleanuppad within %1 []
+  ; CHECK: ehcleanup:
+  ; CHECK:   store i32 -1
+  ; CHECK:   call void @dtor()
+  call void @dtor() #3 [ "funclet"(token %4) ]
+  cleanupret from %4 unwind to caller
+
+unreachable:                                      ; preds = %entry
+  unreachable
+
+unreachable1:                                     ; preds = %catch
+  unreachable
+}
+
 declare void @g(i32) #0
 
+declare void @dtor()
+
 declare x86_stdcallcc void @_CxxThrowException(i8*, %eh.ThrowInfo*)
 
 declare i32 @__CxxFrameHandler3(...)