[llvm-commits] CVS: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Chris Lattner
lattner at cs.uiuc.edu
Mon Feb 23 23:39:01 PST 2004
Changes in directory llvm/lib/Transforms/Utils:
SimplifyCFG.cpp updated: 1.23 -> 1.24
---
Log message:
Implement: test/Regression/Transforms/SimplifyCFG/switch_create.ll
This turns code like this:
if (X == 4 | X == 7)
and
if (X != 4 & X != 7)
into switch instructions.
---
Diffs of the changes: (+140 -7)
Index: llvm/lib/Transforms/Utils/SimplifyCFG.cpp
diff -u llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.23 llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.24
--- llvm/lib/Transforms/Utils/SimplifyCFG.cpp:1.23 Mon Feb 16 00:35:48 2004
+++ llvm/lib/Transforms/Utils/SimplifyCFG.cpp Mon Feb 23 23:38:11 2004
@@ -14,17 +14,18 @@
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
+#include "llvm/Type.h"
#include "llvm/Support/CFG.h"
#include <algorithm>
#include <functional>
using namespace llvm;
-// PropagatePredecessors - This gets "Succ" ready to have the predecessors from
-// "BB". This is a little tricky because "Succ" has PHI nodes, which need to
-// have extra slots added to them to hold the merge edges from BB's
-// predecessors, and BB itself might have had PHI nodes in it. This function
-// returns true (failure) if the Succ BB already has a predecessor that is a
-// predecessor of BB and incoming PHI arguments would not be discernible.
+// PropagatePredecessorsForPHIs - This gets "Succ" ready to have the
+// predecessors from "BB". This is a little tricky because "Succ" has PHI
+// nodes, which need to have extra slots added to them to hold the merge edges
+// from BB's predecessors, and BB itself might have had PHI nodes in it. This
+// function returns true (failure) if the Succ BB already has a predecessor that
+// is a predecessor of BB and incoming PHI arguments would not be discernible.
//
// Assumption: Succ is the single successor for BB.
//
@@ -200,6 +201,91 @@
return true;
}
+// GatherConstantSetEQs - Given a potentially 'or'd together collection of seteq
+// instructions that compare a value against a constant, return the value being
+// compared, and stick the constant into the Values vector.
+static Value *GatherConstantSetEQs(Value *V, std::vector<Constant*> &Values) {
+ if (Instruction *Inst = dyn_cast<Instruction>(V))
+ if (Inst->getOpcode() == Instruction::SetEQ) {
+ if (Constant *C = dyn_cast<Constant>(Inst->getOperand(1))) {
+ Values.push_back(C);
+ return Inst->getOperand(0);
+ } else if (Constant *C = dyn_cast<Constant>(Inst->getOperand(0))) {
+ Values.push_back(C);
+ return Inst->getOperand(1);
+ }
+ } else if (Inst->getOpcode() == Instruction::Or) {
+ if (Value *LHS = GatherConstantSetEQs(Inst->getOperand(0), Values))
+ if (Value *RHS = GatherConstantSetEQs(Inst->getOperand(1), Values))
+ if (LHS == RHS)
+ return LHS;
+ }
+ return 0;
+}
+
+// GatherConstantSetNEs - Given a potentially 'and'd together collection of
+// setne instructions that compare a value against a constant, return the value
+// being compared, and stick the constant into the Values vector.
+static Value *GatherConstantSetNEs(Value *V, std::vector<Constant*> &Values) {
+ if (Instruction *Inst = dyn_cast<Instruction>(V))
+ if (Inst->getOpcode() == Instruction::SetNE) {
+ if (Constant *C = dyn_cast<Constant>(Inst->getOperand(1))) {
+ Values.push_back(C);
+ return Inst->getOperand(0);
+ } else if (Constant *C = dyn_cast<Constant>(Inst->getOperand(0))) {
+ Values.push_back(C);
+ return Inst->getOperand(1);
+ }
+ } else if (Inst->getOpcode() == Instruction::Cast) {
+ // Cast of X to bool is really a comparison against zero.
+ assert(Inst->getType() == Type::BoolTy && "Can only handle bool values!");
+ Values.push_back(Constant::getNullValue(Inst->getOperand(0)->getType()));
+ return Inst->getOperand(0);
+ } else if (Inst->getOpcode() == Instruction::And) {
+ if (Value *LHS = GatherConstantSetNEs(Inst->getOperand(0), Values))
+ if (Value *RHS = GatherConstantSetNEs(Inst->getOperand(1), Values))
+ if (LHS == RHS)
+ return LHS;
+ }
+ return 0;
+}
+
+
+
+/// GatherValueComparisons - If the specified Cond is an 'and' or 'or' of a
+/// bunch of comparisons of one value against constants, return the value and
+/// the constants being compared.
+static bool GatherValueComparisons(Instruction *Cond, Value *&CompVal,
+ std::vector<Constant*> &Values) {
+ if (Cond->getOpcode() == Instruction::Or) {
+ CompVal = GatherConstantSetEQs(Cond, Values);
+
+ // Return true to indicate that the condition is true if the CompVal is
+ // equal to one of the constants.
+ return true;
+ } else if (Cond->getOpcode() == Instruction::And) {
+ CompVal = GatherConstantSetNEs(Cond, Values);
+
+ // Return false to indicate that the condition is false if the CompVal is
+ // equal to one of the constants.
+ return false;
+ }
+ return false;
+}
+
+/// ErasePossiblyDeadInstructionTree - If the specified instruction is dead and
+/// has no side effects, nuke it. If it uses any instructions that become dead
+/// because the instruction is now gone, nuke them too.
+static void ErasePossiblyDeadInstructionTree(Instruction *I) {
+ if (isInstructionTriviallyDead(I)) {
+ std::vector<Value*> Operands(I->op_begin(), I->op_end());
+ I->getParent()->getInstList().erase(I);
+ for (unsigned i = 0, e = Operands.size(); i != e; ++i)
+ if (Instruction *OpI = dyn_cast<Instruction>(Operands[i]))
+ ErasePossiblyDeadInstructionTree(OpI);
+ }
+}
+
// SimplifyCFG - This function is used to do simplification of a CFG. For
// example, it adjusts branches to branches to eliminate the extra hop, it
// eliminates unreachable basic blocks, and does other "peephole" optimization
@@ -389,7 +475,6 @@
}
}
-
// Merge basic blocks into their predecessor if there is only one distinct
// pred, and if there is only one distinct successor of the predecessor, and
// if there are no PHI nodes.
@@ -451,6 +536,54 @@
return true;
}
+
+ for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI)
+ if (BranchInst *BI = dyn_cast<BranchInst>((*PI)->getTerminator()))
+ // Change br (X == 0 | X == 1), T, F into a switch instruction.
+ if (BI->isConditional() && isa<Instruction>(BI->getCondition())) {
+ Instruction *Cond = cast<Instruction>(BI->getCondition());
+ // If this is a bunch of seteq's or'd together, or if it's a bunch of
+ // 'setne's and'ed together, collect them.
+ Value *CompVal = 0;
+ std::vector<Constant*> Values;
+ bool TrueWhenEqual = GatherValueComparisons(Cond, CompVal, Values);
+ if (CompVal && CompVal->getType()->isInteger()) {
+ // There might be duplicate constants in the list, which the switch
+ // instruction can't handle, remove them now.
+ std::sort(Values.begin(), Values.end());
+ Values.erase(std::unique(Values.begin(), Values.end()), Values.end());
+
+ // Figure out which block is which destination.
+ BasicBlock *DefaultBB = BI->getSuccessor(1);
+ BasicBlock *EdgeBB = BI->getSuccessor(0);
+ if (!TrueWhenEqual) std::swap(DefaultBB, EdgeBB);
+
+ // Create the new switch instruction now.
+ SwitchInst *New = new SwitchInst(CompVal, DefaultBB, BI);
+
+ // Add all of the 'cases' to the switch instruction.
+ for (unsigned i = 0, e = Values.size(); i != e; ++i)
+ New->addCase(Values[i], EdgeBB);
+
+ // We added edges from PI to the EdgeBB. As such, if there were any
+ // PHI nodes in EdgeBB, they need entries to be added corresponding to
+ // the number of edges added.
+ for (BasicBlock::iterator BBI = EdgeBB->begin();
+ PHINode *PN = dyn_cast<PHINode>(BBI); ++BBI) {
+ Value *InVal = PN->getIncomingValueForBlock(*PI);
+ for (unsigned i = 0, e = Values.size()-1; i != e; ++i)
+ PN->addIncoming(InVal, *PI);
+ }
+
+ // Erase the old branch instruction.
+ (*PI)->getInstList().erase(BI);
+
+ // Erase the potentially condition tree that was used to computed the
+ // branch condition.
+ ErasePossiblyDeadInstructionTree(Cond);
+ return true;
+ }
+ }
// If there is a trivial two-entry PHI node in this basic block, and we can
// eliminate it, do so now.
More information about the llvm-commits
mailing list