diff options
author | Chris Lattner <sabre@nondot.org> | 2010-12-13 04:50:38 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2010-12-13 04:50:38 +0000 |
commit | 7312a22ed63607e4ae7b0d9326e42358fd41e245 (patch) | |
tree | 5c596e06052b978ad7a6634d4b6a97d97901e3df | |
parent | f5198e7fe32704b25fc9d8b041a1d81cde1696b6 (diff) | |
download | external_llvm-7312a22ed63607e4ae7b0d9326e42358fd41e245.zip external_llvm-7312a22ed63607e4ae7b0d9326e42358fd41e245.tar.gz external_llvm-7312a22ed63607e4ae7b0d9326e42358fd41e245.tar.bz2 |
enhance the "change or icmp's into switch" xform to handle one value in an
'or sequence' that it doesn't understand. This allows us to optimize
something insane like this:
int crud (unsigned char c, unsigned x)
{
if(((((((((( (int) c <= 32 ||
(int) c == 46) || (int) c == 44)
|| (int) c == 58) || (int) c == 59) || (int) c == 60)
|| (int) c == 62) || (int) c == 34) || (int) c == 92)
|| (int) c == 39) != 0)
foo();
}
into:
define i32 @crud(i8 zeroext %c, i32 %x) nounwind ssp noredzone {
entry:
%cmp = icmp ult i8 %c, 33
br i1 %cmp, label %if.then, label %switch.early.test
switch.early.test: ; preds = %entry
switch i8 %c, label %if.end [
i8 39, label %if.then
i8 44, label %if.then
i8 58, label %if.then
i8 59, label %if.then
i8 60, label %if.then
i8 62, label %if.then
i8 46, label %if.then
i8 92, label %if.then
i8 34, label %if.then
]
by pulling the < comparison out ahead of the newly formed switch.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@121680 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Transforms/Utils/SimplifyCFG.cpp | 48 | ||||
-rw-r--r-- | test/Transforms/SimplifyCFG/switch_create.ll | 27 |
2 files changed, 70 insertions, 5 deletions
diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index 55c6afe..23dd265 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -301,6 +301,7 @@ GatherConstantCompares(Value *V, std::vector<ConstantInt*> &Vals, Value *&Extra, Instruction *I = dyn_cast<Instruction>(V); if (I == 0) return 0; + // If this is an icmp against a constant, handle this as one of the cases. if (ICmpInst *ICI = dyn_cast<ICmpInst>(I)) { if (ICI->getPredicate() == (isEQ ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE)) if (ConstantInt *C = GetConstantInt(I->getOperand(1), TD)) { @@ -310,17 +311,43 @@ GatherConstantCompares(Value *V, std::vector<ConstantInt*> &Vals, Value *&Extra, return 0; } + // Otherwise, we can only handle an | or &, depending on isEQ. if (I->getOpcode() != (isEQ ? Instruction::Or : Instruction::And)) return 0; + unsigned NumValsBeforeLHS = Vals.size(); if (Value *LHS = GatherConstantCompares(I->getOperand(0), Vals, Extra, TD, isEQ)) { + unsigned NumVals = Vals.size(); if (Value *RHS = GatherConstantCompares(I->getOperand(1), Vals, Extra, TD, isEQ)) { if (LHS == RHS) return LHS; } + Vals.resize(NumVals); + + // The RHS of the or/and can't be folded in and we haven't used "Extra" yet, + // set it and return success. + if (Extra == 0 || Extra == I->getOperand(1)) { + Extra = I->getOperand(1); + return LHS; + } + + Vals.resize(NumValsBeforeLHS); + return 0; + } + + // If the LHS can't be folded in, but Extra is available and RHS can, try to + // use LHS as Extra. + if (Extra == 0 || Extra == I->getOperand(0)) { + Extra = I->getOperand(0); + if (Value *RHS = GatherConstantCompares(I->getOperand(1), Vals, Extra, TD, + isEQ)) + return RHS; + Vals.resize(NumValsBeforeLHS); + Extra = 0; } + return 0; } @@ -2059,7 +2086,9 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) { } } - if (CompVal) { + // We do this transformation if we'll end up creating a switch with at + // least two values if Extra is used. + if (CompVal && (!ExtraCase || Values.size() > 1)) { // There might be duplicate constants in the list, which the switch // instruction can't handle, remove them now. array_pod_sort(Values.begin(), Values.end(), ConstantIntSortPredicate); @@ -2070,6 +2099,19 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) { BasicBlock *EdgeBB = BI->getSuccessor(0); if (!TrueWhenEqual) std::swap(DefaultBB, EdgeBB); + // If there are any extra values that couldn't be folded into the switch + // then we evaluate them with an explicit branch first. Split the block + // right before the condbr to handle it. + if (ExtraCase) { + BasicBlock *NewBB = BB->splitBasicBlock(BI, "switch.early.test"); + // Remove the uncond branch added to the old block. + TerminatorInst *OldTI = BB->getTerminator(); + + BranchInst::Create(EdgeBB, NewBB, ExtraCase, OldTI); + OldTI->eraseFromParent(); + BB = NewBB; + } + // Convert pointer to int before we switch. if (CompVal->getType()->isPointerTy()) { assert(TD && "Cannot switch on pointer without TargetData"); @@ -2079,8 +2121,8 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) { } // Create the new switch instruction now. - SwitchInst *New = SwitchInst::Create(CompVal, DefaultBB, - Values.size(), BI); + SwitchInst *New = + SwitchInst::Create(CompVal, DefaultBB, Values.size(), BI); // Add all of the 'cases' to the switch instruction. for (unsigned i = 0, e = Values.size(); i != e; ++i) diff --git a/test/Transforms/SimplifyCFG/switch_create.ll b/test/Transforms/SimplifyCFG/switch_create.ll index 9edbf0f..bac457c 100644 --- a/test/Transforms/SimplifyCFG/switch_create.ll +++ b/test/Transforms/SimplifyCFG/switch_create.ll @@ -149,7 +149,30 @@ UnifiedReturnBlock: ; preds = %shortcirc_done.4, %shortcirc_next.4 ; CHECK: i32 18, label %UnifiedReturnBlock ; CHECK: i32 19, label %switch.edge ; CHECK: ] - } - +define void @test7(i8 zeroext %c, i32 %x) nounwind ssp noredzone { +entry: + %cmp = icmp ult i32 %x, 32 + %cmp4 = icmp eq i8 %c, 97 + %or.cond = or i1 %cmp, %cmp4 + %cmp9 = icmp eq i8 %c, 99 + %or.cond11 = or i1 %or.cond, %cmp9 + br i1 %or.cond11, label %if.then, label %if.end + +if.then: ; preds = %entry + tail call void @foo1() nounwind noredzone + ret void + +if.end: ; preds = %entry + ret void + +; CHECK: @test7 +; CHECK: %cmp = icmp ult i32 %x, 32 +; CHECK: br i1 %cmp, label %if.then, label %switch.early.test +; CHECK: switch.early.test: +; CHECK: switch i8 %c, label %if.end [ +; CHECK: i8 99, label %if.then +; CHECK: i8 97, label %if.then +; CHECK: ] +} |