diff options
author | Chris Lattner <sabre@nondot.org> | 2003-10-07 18:46:23 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2003-10-07 18:46:23 +0000 |
commit | ebbc1a5aa0c37ab29d14ae56c176b3bfd25658cb (patch) | |
tree | e9f24d853c1026d5097f42b341b2124cfa3e193e /lib/Transforms/Utils | |
parent | 7528343cbd35491d61f4d66bf3f97445173afc7e (diff) | |
download | external_llvm-ebbc1a5aa0c37ab29d14ae56c176b3bfd25658cb.zip external_llvm-ebbc1a5aa0c37ab29d14ae56c176b3bfd25658cb.tar.gz external_llvm-ebbc1a5aa0c37ab29d14ae56c176b3bfd25658cb.tar.bz2 |
Bill contributed this major rewrite of the -lowerswitch pass to make it generate
logarithmic conditional branch sequences instead of linear sequences. Thanks Bill!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@8928 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/Utils')
-rw-r--r-- | lib/Transforms/Utils/LowerSwitch.cpp | 188 |
1 files changed, 144 insertions, 44 deletions
diff --git a/lib/Transforms/Utils/LowerSwitch.cpp b/lib/Transforms/Utils/LowerSwitch.cpp index 73ce2f7..f2608d9 100644 --- a/lib/Transforms/Utils/LowerSwitch.cpp +++ b/lib/Transforms/Utils/LowerSwitch.cpp @@ -7,11 +7,13 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Scalar.h" +#include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/iTerminators.h" #include "llvm/iOperators.h" #include "llvm/iPHINode.h" #include "llvm/Pass.h" +#include "Support/Debug.h" #include "Support/Statistic.h" namespace { @@ -20,9 +22,30 @@ namespace { /// LowerSwitch Pass - Replace all SwitchInst instructions with chained branch /// instructions. Note that this cannot be a BasicBlock pass because it /// modifies the CFG! - struct LowerSwitch : public FunctionPass { + class LowerSwitch : public FunctionPass { + public: bool runOnFunction(Function &F); + typedef std::pair<Constant*, BasicBlock*> Case; + typedef std::vector<Case>::iterator CaseItr; + private: void processSwitchInst(SwitchInst *SI); + + BasicBlock* switchConvert(CaseItr Begin, CaseItr End, Value* Val, + BasicBlock* OrigBlock, BasicBlock* Default); + BasicBlock* newLeafBlock(Case& Leaf, Value* Val, + BasicBlock* OrigBlock, BasicBlock* Default); + }; + + /// The comparison function for sorting the switch case values in the vector. + struct CaseCmp { + bool operator () (const LowerSwitch::Case& C1, + const LowerSwitch::Case& C2) { + if (const ConstantUInt* U1 = dyn_cast<const ConstantUInt>(C1.first)) + return U1->getValue() < cast<const ConstantUInt>(C2.first)->getValue(); + + const ConstantSInt* S1 = dyn_cast<const ConstantSInt>(C1.first); + return S1->getValue() < cast<const ConstantSInt>(C2.first)->getValue(); + } }; RegisterOpt<LowerSwitch> @@ -49,16 +72,107 @@ bool LowerSwitch::runOnFunction(Function &F) { return Changed; } +// operator<< - Used for debugging purposes. +// +std::ostream& operator << (std::ostream& O, std::vector<LowerSwitch::Case>& C) +{ + O << "["; + + for (std::vector<LowerSwitch::Case>::iterator B = C.begin(), E = C.end(); + B != E; ) { + O << *B->first; + if (++B != E) O << ", "; + } + + return O << "]"; +} + +// switchConvert - Convert the switch statement into a binary lookup of +// the case values. The function recursively builds this tree. +// +BasicBlock* LowerSwitch::switchConvert(CaseItr Begin, CaseItr End, + Value* Val, BasicBlock* OrigBlock, + BasicBlock* Default) +{ + unsigned Size = End - Begin; + + if (Size == 1) + return newLeafBlock(*Begin, Val, OrigBlock, Default); + + unsigned Mid = Size / 2; + std::vector<Case> LHS(Begin, Begin + Mid); + DEBUG(std::cerr << "LHS: " << LHS << "\n"); + std::vector<Case> RHS(Begin + Mid, End); + DEBUG(std::cerr << "RHS: " << RHS << "\n"); + + Case& Pivot = *(Begin + Mid); + DEBUG(std::cerr << "Pivot ==> " + << cast<ConstantUInt>(Pivot.first)->getValue() << "\n"); + + BasicBlock* LBranch = switchConvert(LHS.begin(), LHS.end(), Val, + OrigBlock, Default); + BasicBlock* RBranch = switchConvert(RHS.begin(), RHS.end(), Val, + OrigBlock, Default); + + // Create a new node that checks if the value is < pivot. Go to the + // left branch if it is and right branch if not. + Function* F = OrigBlock->getParent(); + BasicBlock* NewNode = new BasicBlock("NodeBlock"); + F->getBasicBlockList().insert(OrigBlock->getNext(), NewNode); + + SetCondInst* Comp = new SetCondInst(Instruction::SetLT, Val, Pivot.first, + "Pivot"); + NewNode->getInstList().push_back(Comp); + BranchInst* Br = new BranchInst(LBranch, RBranch, Comp); + NewNode->getInstList().push_back(Br); + return NewNode; +} + +// newLeafBlock - Create a new leaf block for the binary lookup tree. It +// checks if the switch's value == the case's value. If not, then it +// jumps to the default branch. At this point in the tree, the value +// can't be another valid case value, so the jump to the "default" branch +// is warranted. +// +BasicBlock* LowerSwitch::newLeafBlock(Case& Leaf, Value* Val, + BasicBlock* OrigBlock, + BasicBlock* Default) +{ + Function* F = OrigBlock->getParent(); + BasicBlock* NewLeaf = new BasicBlock("LeafBlock"); + F->getBasicBlockList().insert(OrigBlock->getNext(), NewLeaf); + + // Make the seteq instruction... + SetCondInst* Comp = new SetCondInst(Instruction::SetEQ, Val, + Leaf.first, "SwitchLeaf"); + NewLeaf->getInstList().push_back(Comp); + + // Make the conditional branch... + BasicBlock* Succ = Leaf.second; + Instruction* Br = new BranchInst(Succ, Default, Comp); + NewLeaf->getInstList().push_back(Br); + + // If there were any PHI nodes in this successor, rewrite one entry + // from OrigBlock to come from NewLeaf. + for (BasicBlock::iterator I = Succ->begin(); + PHINode* PN = dyn_cast<PHINode>(I); ++I) { + int BlockIdx = PN->getBasicBlockIndex(OrigBlock); + assert(BlockIdx != -1 && "Switch didn't go to this successor??"); + PN->setIncomingBlock((unsigned)BlockIdx, NewLeaf); + } + + return NewLeaf; +} + // processSwitchInst - Replace the specified switch instruction with a sequence -// of chained basic blocks. Right now we just insert an incredibly stupid -// linear sequence of branches. It would be better to do a balanced binary -// search eventually. FIXME +// of chained if-then insts in a balanced binary search. // void LowerSwitch::processSwitchInst(SwitchInst *SI) { BasicBlock *CurBlock = SI->getParent(); BasicBlock *OrigBlock = CurBlock; Function *F = CurBlock->getParent(); Value *Val = SI->getOperand(0); // The value we are switching on... + BasicBlock* Default = SI->getDefaultDest(); // Unlink the switch instruction from it's block. CurBlock->getInstList().remove(SI); @@ -70,50 +184,36 @@ void LowerSwitch::processSwitchInst(SwitchInst *SI) { return; } - // Expand comparisons for all of the non-default cases... - for (unsigned i = 2, e = SI->getNumOperands(); i != e; i += 2) { - // Insert a new basic block after the current one... - BasicBlock *NextBlock; - if (i != e-2) { - NextBlock = new BasicBlock("switchblock"); - F->getBasicBlockList().insert(CurBlock->getNext(), NextBlock); - } else { // Last case, if it's not the value, go to default block. - NextBlock = cast<BasicBlock>(SI->getDefaultDest()); - } - - // Make the seteq instruction... - Instruction *Comp = new SetCondInst(Instruction::SetEQ, Val, - SI->getOperand(i), "switchcase"); - CurBlock->getInstList().push_back(Comp); - - // Make the conditional branch... - BasicBlock *Succ = cast<BasicBlock>(SI->getOperand(i+1)); - Instruction *Br = new BranchInst(Succ, NextBlock, Comp); - CurBlock->getInstList().push_back(Br); - - // If there were any PHI nodes in this successor, rewrite one entry from - // OrigBlock to come from CurBlock. - for (BasicBlock::iterator I = Succ->begin(); - PHINode *PN = dyn_cast<PHINode>(I); ++I) { - int BlockIdx = PN->getBasicBlockIndex(OrigBlock); - assert(BlockIdx != -1 && "Switch didn't go to this successor??"); - PN->setIncomingBlock((unsigned)BlockIdx, CurBlock); - } + // Create a new, empty default block so that the new hierarchy of + // if-then statements go to this and the PHI nodes are happy. + BasicBlock* NewDefault = new BasicBlock("NewDefault"); + F->getBasicBlockList().insert(Default, NewDefault); - if (i == e-2) { // Is this looking at the default destination? - // If there is an entry in any PHI nodes for the default edge, make sure - // to update them as well. - for (BasicBlock::iterator I = NextBlock->begin(); - PHINode *PN = dyn_cast<PHINode>(I); ++I) { - int BlockIdx = PN->getBasicBlockIndex(OrigBlock); - assert(BlockIdx != -1 && "Switch didn't go to this successor??"); - PN->setIncomingBlock((unsigned)BlockIdx, CurBlock); - } - } + NewDefault->getInstList().push_back(new BranchInst(Default)); - CurBlock = NextBlock; // Move on to the next condition + // If there is an entry in any PHI nodes for the default edge, make sure + // to update them as well. + for (BasicBlock::iterator I = Default->begin(); + PHINode *PN = dyn_cast<PHINode>(I); ++I) { + int BlockIdx = PN->getBasicBlockIndex(OrigBlock); + assert(BlockIdx != -1 && "Switch didn't go to this successor??"); + PN->setIncomingBlock((unsigned)BlockIdx, NewDefault); } + std::vector<Case> Cases; + + // Expand comparisons for all of the non-default cases... + for (unsigned i = 1; i < SI->getNumSuccessors(); ++i) + Cases.push_back(Case(SI->getSuccessorValue(i), SI->getSuccessor(i))); + + std::sort(Cases.begin(), Cases.end(), CaseCmp()); + DEBUG(std::cerr << "Cases: " << Cases << "\n"); + BasicBlock* SwitchBlock = switchConvert(Cases.begin(), Cases.end(), Val, + OrigBlock, NewDefault); + + // Branch to our shiny new if-then stuff... + OrigBlock->getInstList().push_back(new BranchInst(SwitchBlock)); + // We are now done with the switch instruction, delete it. delete SI; } |