[SimpleLoopUnswitch] Don't non-trivially unswitch loops with catchswitch exits
authorArthur Eubanks <aeubanks@google.com>
Thu, 8 Jul 2021 22:05:50 +0000 (15:05 -0700)
committerArthur Eubanks <aeubanks@google.com>
Wed, 14 Jul 2021 21:07:28 +0000 (14:07 -0700)
SplitBlock() can't handle catchswitch.

Fixes PR50973.

Reviewed By: aheejin

Differential Revision: https://reviews.llvm.org/D105672

llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
llvm/test/Transforms/SimpleLoopUnswitch/catchswitch.ll [new file with mode: 0644]

index 78b97ae..b9cccc2 100644 (file)
@@ -2775,14 +2775,15 @@ static bool unswitchBestCondition(
   SmallVector<BasicBlock *, 4> ExitBlocks;
   L.getUniqueExitBlocks(ExitBlocks);
 
-  // We cannot unswitch if exit blocks contain a cleanuppad instruction as we
-  // don't know how to split those exit blocks.
+  // We cannot unswitch if exit blocks contain a cleanuppad/catchswitch
+  // instruction as we don't know how to split those exit blocks.
   // FIXME: We should teach SplitBlock to handle this and remove this
   // restriction.
   for (auto *ExitBB : ExitBlocks) {
-    if (isa<CleanupPadInst>(ExitBB->getFirstNonPHI())) {
-      LLVM_DEBUG(
-          dbgs() << "Cannot unswitch because of cleanuppad in exit block\n");
+    auto *I = ExitBB->getFirstNonPHI();
+    if (isa<CleanupPadInst>(I) || isa<CatchSwitchInst>(I)) {
+      LLVM_DEBUG(dbgs() << "Cannot unswitch because of cleanuppad/catchswitch "
+                           "in exit block\n");
       return false;
     }
   }
index a20799d..def695e 100644 (file)
@@ -766,8 +766,10 @@ static BasicBlock *SplitBlockImpl(BasicBlock *Old, Instruction *SplitPt,
                             BBName);
   }
   BasicBlock::iterator SplitIt = SplitPt->getIterator();
-  while (isa<PHINode>(SplitIt) || SplitIt->isEHPad())
+  while (isa<PHINode>(SplitIt) || SplitIt->isEHPad()) {
     ++SplitIt;
+    assert(SplitIt != SplitPt->getParent()->end());
+  }
   std::string Name = BBName.str();
   BasicBlock *New = Old->splitBasicBlock(
       SplitIt, Name.empty() ? Old->getName() + ".split" : Name);
diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/catchswitch.ll b/llvm/test/Transforms/SimpleLoopUnswitch/catchswitch.ll
new file mode 100644 (file)
index 0000000..19e327c
--- /dev/null
@@ -0,0 +1,33 @@
+; RUN: opt -passes=simple-loop-unswitch -enable-nontrivial-unswitch < %s -S | FileCheck %s
+
+; CHECK: if.end{{.*}}:
+; CHECK-NOT: if.end{{.*}}:
+declare i32 @__gxx_wasm_personality_v0(...)
+
+declare void @foo()
+
+define void @test(i1 %arg) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
+entry:
+  br label %while.body
+
+while.body:                                       ; preds = %cleanup, %entry
+  br i1 %arg, label %if.end, label %if.then
+
+if.then:                                          ; preds = %while.body
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %while.body
+  invoke void @foo()
+          to label %cleanup unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %invoke.cont, %if.end
+  %0 = catchswitch within none [label %catch] unwind to caller
+
+catch:                                            ; preds = %catch.dispatch
+  %1 = catchpad within %0 [i8* null]
+  unreachable
+
+cleanup:                                          ; preds = %invoke.cont
+  br label %while.body
+}
+