[llvm-commits] [llvm] r91890 - in /llvm/trunk: lib/Transforms/Scalar/SimplifyCFGPass.cpp test/Transforms/SimplifyCFG/basictest.ll

Chris Lattner sabre at nondot.org
Mon Dec 21 22:07:31 PST 2009


Author: lattner
Date: Tue Dec 22 00:07:30 2009
New Revision: 91890

URL: http://llvm.org/viewvc/llvm-project?rev=91890&view=rev
Log:
Implement PR5795 by merging duplicated return blocks.  This could go further
by merging all returns in a function into a single one, but simplifycfg 
currently likes to duplicate the return (an unfortunate choice!)

Modified:
    llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp
    llvm/trunk/test/Transforms/SimplifyCFG/basictest.ll

Modified: llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp?rev=91890&r1=91889&r2=91890&view=diff

==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp Tue Dec 22 00:07:30 2009
@@ -189,6 +189,77 @@
   return true;
 }
 
+/// MergeEmptyReturnBlocks - 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) {
+  bool Changed = false;
+  
+  BasicBlock *RetBlock = 0;
+  
+  // Scan all the blocks in the function, looking for empty return blocks.
+  for (Function::iterator BBI = F.begin(), E = F.end(); BBI != E; ) {
+    BasicBlock &BB = *BBI++;
+    
+    // Only look at return blocks.
+    ReturnInst *Ret = dyn_cast<ReturnInst>(BB.getTerminator());
+    if (Ret == 0) continue;
+    
+    // Only look at the block if it is empty or the only other thing in it is a
+    // single PHI node that is the operand to the return.
+    if (Ret != &BB.front()) {
+      // Check for something else in the block.
+      BasicBlock::iterator I = Ret;
+      --I;
+      if (!isa<PHINode>(I) || I != BB.begin() ||
+          Ret->getNumOperands() == 0 ||
+          Ret->getOperand(0) != I)
+        continue;
+    }
+    
+    // If this is the first returning block, remember it and keep going.
+    if (RetBlock == 0) {
+      RetBlock = &BB;
+      continue;
+    }
+    
+    // Otherwise, we found a duplicate return block.  Merge the two.
+    Changed = true;
+    
+    // Case when there is no input to the return or when the returned values
+    // agree is trivial.  Note that they can't agree if there are phis in the
+    // blocks.
+    if (Ret->getNumOperands() == 0 ||
+        Ret->getOperand(0) == 
+          cast<ReturnInst>(RetBlock->getTerminator())->getOperand(0)) {
+      BB.replaceAllUsesWith(RetBlock);
+      BB.eraseFromParent();
+      continue;
+    }
+    
+    // If the canonical return block has no PHI node, create one now.
+    PHINode *RetBlockPHI = dyn_cast<PHINode>(RetBlock->begin());
+    if (RetBlockPHI == 0) {
+      Value *InVal = cast<ReturnInst>(RetBlock->begin())->getOperand(0);
+      RetBlockPHI = PHINode::Create(Ret->getOperand(0)->getType(), "merge",
+                                    &RetBlock->front());
+      
+      for (pred_iterator PI = pred_begin(RetBlock), E = pred_end(RetBlock);
+           PI != E; ++PI)
+        RetBlockPHI->addIncoming(InVal, *PI);
+      RetBlock->getTerminator()->setOperand(0, RetBlockPHI);
+    }
+    
+    // Turn BB into a block that just unconditionally branches to the return
+    // block.  This handles the case when the two return blocks have a common
+    // predecessor but that return different things.
+    RetBlockPHI->addIncoming(Ret->getOperand(0), &BB);
+    BB.getTerminator()->eraseFromParent();
+    BranchInst::Create(RetBlock, &BB);
+  }
+  
+  return Changed;
+}
+
 /// IterativeSimplifyCFG - Call SimplifyCFG on all the blocks in the function,
 /// iterating until no more changes are made.
 static bool IterativeSimplifyCFG(Function &F) {
@@ -216,6 +287,7 @@
 //
 bool CFGSimplifyPass::runOnFunction(Function &F) {
   bool EverChanged = RemoveUnreachableBlocksFromFn(F);
+  EverChanged |= MergeEmptyReturnBlocks(F);
   EverChanged |= IterativeSimplifyCFG(F);
   
   // If neither pass changed anything, we're done.

Modified: llvm/trunk/test/Transforms/SimplifyCFG/basictest.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/basictest.ll?rev=91890&r1=91889&r2=91890&view=diff

==============================================================================
--- llvm/trunk/test/Transforms/SimplifyCFG/basictest.ll (original)
+++ llvm/trunk/test/Transforms/SimplifyCFG/basictest.ll Tue Dec 22 00:07:30 2009
@@ -38,3 +38,22 @@
 @test4g = global i8* blockaddress(@test4, %return)
 
 
+; PR5795
+define void @test5(i32 %A) {
+  switch i32 %A, label %return [
+    i32 2, label %bb
+    i32 10, label %bb1
+  ]
+
+bb:                                               ; preds = %entry
+  ret void
+
+bb1:                                              ; preds = %entry
+  ret void
+
+return:                                           ; preds = %entry
+  ret void
+; CHECK: @test5
+; CHECK-NEXT: bb:
+; CHECK-NEXT: ret void
+}





More information about the llvm-commits mailing list