From 0d56008f53587531718ec36af82cc24576580b36 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Tue, 24 Feb 2004 05:38:11 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@11792 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Utils/SimplifyCFG.cpp | 147 +++++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 7 deletions(-) diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index b0fc6bca742..a268b47505c 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -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 #include 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 @@ static bool DominatesMergePoint(Value *V, BasicBlock *BB) { 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 &Values) { + if (Instruction *Inst = dyn_cast(V)) + if (Inst->getOpcode() == Instruction::SetEQ) { + if (Constant *C = dyn_cast(Inst->getOperand(1))) { + Values.push_back(C); + return Inst->getOperand(0); + } else if (Constant *C = dyn_cast(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 &Values) { + if (Instruction *Inst = dyn_cast(V)) + if (Inst->getOpcode() == Instruction::SetNE) { + if (Constant *C = dyn_cast(Inst->getOperand(1))) { + Values.push_back(C); + return Inst->getOperand(0); + } else if (Constant *C = dyn_cast(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 &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 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(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 @@ bool llvm::SimplifyCFG(BasicBlock *BB) { } } - // 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. @@ -452,6 +537,54 @@ bool llvm::SimplifyCFG(BasicBlock *BB) { return true; } + for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) + if (BranchInst *BI = dyn_cast((*PI)->getTerminator())) + // Change br (X == 0 | X == 1), T, F into a switch instruction. + if (BI->isConditional() && isa(BI->getCondition())) { + Instruction *Cond = cast(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 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(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. if (PHINode *PN = dyn_cast(BB->begin())) -- 2.34.1