[llvm] 8411560 - [SimplifyCFG] 'merge compatible invokes': support normal destination w/ no uses, no PHI's

Roman Lebedev via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 8 06:49:49 PST 2022


Author: Roman Lebedev
Date: 2022-02-08T17:49:38+03:00
New Revision: 8411560fd0751fc10ae03c85dabdb9d8b2b9ba6b

URL: https://github.com/llvm/llvm-project/commit/8411560fd0751fc10ae03c85dabdb9d8b2b9ba6b
DIFF: https://github.com/llvm/llvm-project/commit/8411560fd0751fc10ae03c85dabdb9d8b2b9ba6b.diff

LOG: [SimplifyCFG] 'merge compatible invokes': support normal destination w/ no uses, no PHI's

Even if the invokes have normal destination, iff it's the same block,
we can merge them. For now, require that there are no PHI nodes,
and the returned values of invokes aren't used.

Added: 
    

Modified: 
    llvm/lib/Transforms/Utils/SimplifyCFG.cpp
    llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 5d09d2ac6890d..f039f87963bcc 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -2285,13 +2285,38 @@ bool CompatibleSets::shouldBelongToSameSet(ArrayRef<InvokeInst *> Invokes) {
       return false;
   }
 
-  // Both `invoke`s must not have a normal destination.
-  // FIXME: them sharing the normal destination should be fine?
+  // Either both `invoke`s must not have a normal destination,
+  // or     both `invoke`s must     have a normal destination,
   auto HasNormalDest = [](InvokeInst *II) {
     return !isa<UnreachableInst>(II->getNormalDest()->getFirstNonPHIOrDbg());
   };
-  if (any_of(Invokes, HasNormalDest))
-    return false;
+  if (any_of(Invokes, HasNormalDest)) {
+    // Do not merge `invoke` that does not have a normal destination with one
+    // that does have a normal destination, even though doing so would be legal.
+    if (!all_of(Invokes, HasNormalDest))
+      return false;
+
+    // All normal destinations must be identical.
+    BasicBlock *NormalBB = nullptr;
+    for (InvokeInst *II : Invokes) {
+      BasicBlock *CurrNormalBB = II->getNormalDest();
+      assert(CurrNormalBB && "There is always a 'continue to' basic block.");
+      if (!NormalBB)
+        NormalBB = CurrNormalBB;
+      else if (NormalBB != CurrNormalBB)
+        return false;
+    }
+
+    // In the normal destination, there must be no PHI nodes.
+    // FIXME: just check that the incoming values are compatible?
+    if (!empty(NormalBB->phis()))
+      return false;
+
+    // For now, simply don't deal with `invoke`s that have uses.
+    auto Unused = [](InvokeInst *II) { return II->use_empty(); };
+    if (!all_of(Invokes, Unused))
+      return false;
+  }
 
 #ifndef NDEBUG
   // All unwind destinations must be identical.
@@ -2309,7 +2334,6 @@ bool CompatibleSets::shouldBelongToSameSet(ArrayRef<InvokeInst *> Invokes) {
 
   // In the unwind destination, the incoming values for these two `invoke`s
   // must be compatible .
-  // We know we don't have the normal destination, so we don't check it.
   if (!IncomingValuesAreCompatible(
           Invokes.front()->getUnwindDest(),
           {Invokes[0]->getParent(), Invokes[1]->getParent()}))
@@ -2348,9 +2372,12 @@ static void MergeCompatibleInvokesImpl(ArrayRef<InvokeInst *> Invokes,
   if (DTU)
     Updates.reserve(2 + 3 * Invokes.size());
 
+  bool HasNormalDest =
+      !isa<UnreachableInst>(Invokes[0]->getNormalDest()->getFirstNonPHIOrDbg());
+
   // Clone one of the invokes into a new basic block.
   // Since they are all compatible, it doesn't matter which invoke is cloned.
-  InvokeInst *MergedInvoke = [&Invokes]() {
+  InvokeInst *MergedInvoke = [&Invokes, HasNormalDest]() {
     InvokeInst *II0 = Invokes.front();
     BasicBlock *II0BB = II0->getParent();
     BasicBlock *InsertBeforeBlock =
@@ -2365,12 +2392,14 @@ static void MergeCompatibleInvokesImpl(ArrayRef<InvokeInst *> Invokes,
     // NOTE: all invokes have the same attributes, so no handling needed.
     MergedInvokeBB->getInstList().push_back(MergedInvoke);
 
-    // For now, we've required that the normal destination is unreachable,
-    // so just form a new block with unreachable terminator.
-    BasicBlock *MergedNormalDest = BasicBlock::Create(
-        Ctx, II0BB->getName() + ".cont", Func, InsertBeforeBlock);
-    new UnreachableInst(Ctx, MergedNormalDest);
-    MergedInvoke->setNormalDest(MergedNormalDest);
+    if (!HasNormalDest) {
+      // This set does not have a normal destination,
+      // so just form a new block with unreachable terminator.
+      BasicBlock *MergedNormalDest = BasicBlock::Create(
+          Ctx, II0BB->getName() + ".cont", Func, InsertBeforeBlock);
+      new UnreachableInst(Ctx, MergedNormalDest);
+      MergedInvoke->setNormalDest(MergedNormalDest);
+    }
 
     // The unwind destination, however, remainds identical for all invokes here.
 

diff  --git a/llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll b/llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll
index 944af32e75470..5fee3d8bb8d7c 100644
--- a/llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll
+++ b/llvm/test/Transforms/SimplifyCFG/X86/merge-compatible-invokes-of-landingpad.ll
@@ -153,10 +153,7 @@ define void @t3_shared_identical_normal_dest() personality i8* bitcast (i32 (...
 ; CHECK-LABEL: @t3_shared_identical_normal_dest(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[C0:%.*]] = call i1 @cond()
-; CHECK-NEXT:    br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE:%.*]]
-; CHECK:       if.then0:
-; CHECK-NEXT:    invoke void @maybe_throw()
-; CHECK-NEXT:    to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
+; CHECK-NEXT:    br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], label [[IF_ELSE:%.*]]
 ; CHECK:       invoke.cont:
 ; CHECK-NEXT:    call void @sideeffect()
 ; CHECK-NEXT:    unreachable
@@ -167,10 +164,10 @@ define void @t3_shared_identical_normal_dest() personality i8* bitcast (i32 (...
 ; CHECK-NEXT:    resume { i8*, i32 } [[EH]]
 ; CHECK:       if.else:
 ; CHECK-NEXT:    [[C1:%.*]] = call i1 @cond()
-; CHECK-NEXT:    br i1 [[C1]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
-; CHECK:       if.then1:
+; CHECK-NEXT:    br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_END:%.*]]
+; CHECK:       if.then1.invoke:
 ; CHECK-NEXT:    invoke void @maybe_throw()
-; CHECK-NEXT:    to label [[INVOKE_CONT]] unwind label [[LPAD]]
+; CHECK-NEXT:    to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
 ; CHECK:       if.end:
 ; CHECK-NEXT:    call void @sideeffect()
 ; CHECK-NEXT:    ret void
@@ -1642,10 +1639,7 @@ define void @t27_invoke_ret_value_is_used() personality i8* bitcast (i32 (...)*
 ; CHECK-LABEL: @t27_invoke_ret_value_is_used(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[C0:%.*]] = call i1 @cond()
-; CHECK-NEXT:    br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE:%.*]]
-; CHECK:       if.then0:
-; CHECK-NEXT:    [[V0:%.*]] = invoke i32 @returning_maybe_throw()
-; CHECK-NEXT:    to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
+; CHECK-NEXT:    br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], label [[IF_ELSE:%.*]]
 ; CHECK:       invoke.cont:
 ; CHECK-NEXT:    call void @sideeffect()
 ; CHECK-NEXT:    unreachable
@@ -1656,10 +1650,10 @@ define void @t27_invoke_ret_value_is_used() personality i8* bitcast (i32 (...)*
 ; CHECK-NEXT:    resume { i8*, i32 } [[EH]]
 ; CHECK:       if.else:
 ; CHECK-NEXT:    [[C1:%.*]] = call i1 @cond()
-; CHECK-NEXT:    br i1 [[C1]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
-; CHECK:       if.then1:
-; CHECK-NEXT:    [[V1:%.*]] = invoke i32 @returning_maybe_throw()
-; CHECK-NEXT:    to label [[INVOKE_CONT]] unwind label [[LPAD]]
+; CHECK-NEXT:    br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_END:%.*]]
+; CHECK:       if.then1.invoke:
+; CHECK-NEXT:    [[TMP0:%.*]] = invoke i32 @returning_maybe_throw()
+; CHECK-NEXT:    to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
 ; CHECK:       if.end:
 ; CHECK-NEXT:    call void @sideeffect()
 ; CHECK-NEXT:    ret void
@@ -1756,10 +1750,7 @@ define void @t29_common_normal_destination_and_unreachable_normal_destination()
 ; CHECK-LABEL: @t29_common_normal_destination_and_unreachable_normal_destination(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[C0:%.*]] = call i1 @cond()
-; CHECK-NEXT:    br i1 [[C0]], label [[IF_THEN0:%.*]], label [[IF_ELSE0:%.*]]
-; CHECK:       if.then0:
-; CHECK-NEXT:    invoke void @maybe_throw()
-; CHECK-NEXT:    to label [[INVOKE_CONT0:%.*]] unwind label [[LPAD:%.*]]
+; CHECK-NEXT:    br i1 [[C0]], label [[IF_THEN1_INVOKE:%.*]], label [[IF_ELSE0:%.*]]
 ; CHECK:       invoke.cont0:
 ; CHECK-NEXT:    call void @sideeffect()
 ; CHECK-NEXT:    unreachable
@@ -1770,10 +1761,10 @@ define void @t29_common_normal_destination_and_unreachable_normal_destination()
 ; CHECK-NEXT:    resume { i8*, i32 } [[EH]]
 ; CHECK:       if.else0:
 ; CHECK-NEXT:    [[C1:%.*]] = call i1 @cond()
-; CHECK-NEXT:    br i1 [[C1]], label [[IF_THEN1:%.*]], label [[IF_ELSE1:%.*]]
-; CHECK:       if.then1:
+; CHECK-NEXT:    br i1 [[C1]], label [[IF_THEN1_INVOKE]], label [[IF_ELSE1:%.*]]
+; CHECK:       if.then1.invoke:
 ; CHECK-NEXT:    invoke void @maybe_throw()
-; CHECK-NEXT:    to label [[INVOKE_CONT0]] unwind label [[LPAD]]
+; CHECK-NEXT:    to label [[INVOKE_CONT0:%.*]] unwind label [[LPAD:%.*]]
 ; CHECK:       if.else1:
 ; CHECK-NEXT:    [[C2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C2]], label [[IF_THEN2:%.*]], label [[IF_END:%.*]]


        


More information about the llvm-commits mailing list