[llvm-branch-commits] [llvm] d22a47e - [SimplifyCFG] Teach mergeEmptyReturnBlocks() to preserve DomTree

Roman Lebedev via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Dec 16 14:08:32 PST 2020


Author: Roman Lebedev
Date: 2020-12-17T01:03:50+03:00
New Revision: d22a47e9fff84c0872331d871b8fe2850e56d809

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

LOG: [SimplifyCFG] Teach mergeEmptyReturnBlocks() to preserve DomTree

A first real transformation that didn't already knew how to do that,
but it's pretty tame - either change successor of all the predecessors
of a block and carefully delay deletion of the block until afterwards
the DomTree updates are appled, or add a successor to the block.

There wasn't a great test coverage for this, so i added extra, to be sure.

Added: 
    llvm/test/Transforms/SimplifyCFG/merge-empty-return-blocks.ll

Modified: 
    llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
    llvm/test/Transforms/SimplifyCFG/2005-10-02-InvokeSimplify.ll
    llvm/test/Transforms/SimplifyCFG/return-merge.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp b/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
index aecc681aad8e..35ab1e52ee2e 100644
--- a/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
+++ b/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
@@ -77,9 +77,12 @@ STATISTIC(NumSimpl, "Number of blocks simplified");
 
 /// If we have more than one empty (other than phi node) return blocks,
 /// merge them together to promote recursive block merging.
-static bool mergeEmptyReturnBlocks(Function &F) {
+static bool mergeEmptyReturnBlocks(Function &F, DomTreeUpdater *DTU) {
   bool Changed = false;
 
+  std::vector<DominatorTree::UpdateType> Updates;
+  SmallVector<BasicBlock *, 8> DeadBlocks;
+
   BasicBlock *RetBlock = nullptr;
 
   // Scan all the blocks in the function, looking for empty return blocks.
@@ -135,8 +138,15 @@ static bool mergeEmptyReturnBlocks(Function &F) {
     if (Ret->getNumOperands() == 0 ||
         Ret->getOperand(0) ==
           cast<ReturnInst>(RetBlock->getTerminator())->getOperand(0)) {
+      // All predecessors of BB should now branch to RetBlock instead.
+      if (DTU) {
+        for (auto *Predecessor : predecessors(&BB)) {
+          Updates.push_back({DominatorTree::Delete, Predecessor, &BB});
+          Updates.push_back({DominatorTree::Insert, Predecessor, RetBlock});
+        }
+      }
       BB.replaceAllUsesWith(RetBlock);
-      BB.eraseFromParent();
+      DeadBlocks.emplace_back(&BB);
       continue;
     }
 
@@ -160,6 +170,17 @@ static bool mergeEmptyReturnBlocks(Function &F) {
     RetBlockPHI->addIncoming(Ret->getOperand(0), &BB);
     BB.getTerminator()->eraseFromParent();
     BranchInst::Create(RetBlock, &BB);
+    if (DTU)
+      Updates.push_back({DominatorTree::Insert, &BB, RetBlock});
+  }
+
+  if (DTU) {
+    DTU->applyUpdatesPermissive(Updates);
+    for (auto *BB : DeadBlocks)
+      DTU->deleteBB(BB);
+  } else {
+    for (auto *BB : DeadBlocks)
+      BB->eraseFromParent();
   }
 
   return Changed;
@@ -200,7 +221,7 @@ static bool simplifyFunctionCFGImpl(Function &F, const TargetTransformInfo &TTI,
   DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
 
   bool EverChanged = removeUnreachableBlocks(F, DT ? &DTU : nullptr);
-  EverChanged |= mergeEmptyReturnBlocks(F);
+  EverChanged |= mergeEmptyReturnBlocks(F, DT ? &DTU : nullptr);
   EverChanged |= iterativelySimplifyCFG(F, TTI, DT ? &DTU : nullptr, Options);
 
   // If neither pass changed anything, we're done.

diff  --git a/llvm/test/Transforms/SimplifyCFG/2005-10-02-InvokeSimplify.ll b/llvm/test/Transforms/SimplifyCFG/2005-10-02-InvokeSimplify.ll
index c71f05bf0a35..f224b6656de1 100644
--- a/llvm/test/Transforms/SimplifyCFG/2005-10-02-InvokeSimplify.ll
+++ b/llvm/test/Transforms/SimplifyCFG/2005-10-02-InvokeSimplify.ll
@@ -1,4 +1,4 @@
-; RUN: opt < %s -simplifycfg -disable-output
+; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -disable-output
 
 define i1 @foo() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
 	%X = invoke i1 @foo( )

diff  --git a/llvm/test/Transforms/SimplifyCFG/merge-empty-return-blocks.ll b/llvm/test/Transforms/SimplifyCFG/merge-empty-return-blocks.ll
new file mode 100644
index 000000000000..24baec0e4523
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/merge-empty-return-blocks.ll
@@ -0,0 +1,48 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S < %s | FileCheck %s
+
+define void @t0(i1 %c) {
+; CHECK-LABEL: @t0(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br i1 %c, label %end0, label %end1
+
+end0:
+  ret void
+
+end1:
+  ret void
+}
+
+define i8 @t1(i1 %c, i8 %v) {
+; CHECK-LABEL: @t1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    ret i8 [[V:%.*]]
+;
+entry:
+  br i1 %c, label %end0, label %end1
+
+end0:
+  ret i8 %v
+
+end1:
+  ret i8 %v
+}
+
+define i8 @t2(i1 %c, i8 %v0, i8 %v1) {
+; CHECK-LABEL: @t2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[C:%.*]], i8 [[V0:%.*]], i8 [[V1:%.*]]
+; CHECK-NEXT:    ret i8 [[SPEC_SELECT]]
+;
+entry:
+  br i1 %c, label %end0, label %end1
+
+end0:
+  ret i8 %v0
+
+end1:
+  ret i8 %v1
+}

diff  --git a/llvm/test/Transforms/SimplifyCFG/return-merge.ll b/llvm/test/Transforms/SimplifyCFG/return-merge.ll
index 977b6dff87cb..f65cf4925e6e 100644
--- a/llvm/test/Transforms/SimplifyCFG/return-merge.ll
+++ b/llvm/test/Transforms/SimplifyCFG/return-merge.ll
@@ -1,4 +1,4 @@
-; RUN: opt < %s -simplifycfg -S | not grep br
+; RUN: opt < %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | not grep br
 
 define i32 @test1(i1 %C) {
 entry:


        


More information about the llvm-branch-commits mailing list