mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-17 18:31:04 +00:00
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
This commit is contained in:
parent
f5198e7fe3
commit
7312a22ed6
@ -301,6 +301,7 @@ GatherConstantCompares(Value *V, std::vector<ConstantInt*> &Vals, Value *&Extra,
|
|||||||
Instruction *I = dyn_cast<Instruction>(V);
|
Instruction *I = dyn_cast<Instruction>(V);
|
||||||
if (I == 0) return 0;
|
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 (ICmpInst *ICI = dyn_cast<ICmpInst>(I)) {
|
||||||
if (ICI->getPredicate() == (isEQ ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE))
|
if (ICI->getPredicate() == (isEQ ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE))
|
||||||
if (ConstantInt *C = GetConstantInt(I->getOperand(1), TD)) {
|
if (ConstantInt *C = GetConstantInt(I->getOperand(1), TD)) {
|
||||||
@ -310,17 +311,43 @@ GatherConstantCompares(Value *V, std::vector<ConstantInt*> &Vals, Value *&Extra,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Otherwise, we can only handle an | or &, depending on isEQ.
|
||||||
if (I->getOpcode() != (isEQ ? Instruction::Or : Instruction::And))
|
if (I->getOpcode() != (isEQ ? Instruction::Or : Instruction::And))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
unsigned NumValsBeforeLHS = Vals.size();
|
||||||
if (Value *LHS = GatherConstantCompares(I->getOperand(0), Vals, Extra, TD,
|
if (Value *LHS = GatherConstantCompares(I->getOperand(0), Vals, Extra, TD,
|
||||||
isEQ)) {
|
isEQ)) {
|
||||||
|
unsigned NumVals = Vals.size();
|
||||||
if (Value *RHS = GatherConstantCompares(I->getOperand(1), Vals, Extra, TD,
|
if (Value *RHS = GatherConstantCompares(I->getOperand(1), Vals, Extra, TD,
|
||||||
isEQ)) {
|
isEQ)) {
|
||||||
if (LHS == RHS)
|
if (LHS == RHS)
|
||||||
return LHS;
|
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;
|
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
|
// There might be duplicate constants in the list, which the switch
|
||||||
// instruction can't handle, remove them now.
|
// instruction can't handle, remove them now.
|
||||||
array_pod_sort(Values.begin(), Values.end(), ConstantIntSortPredicate);
|
array_pod_sort(Values.begin(), Values.end(), ConstantIntSortPredicate);
|
||||||
@ -2070,6 +2099,19 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) {
|
|||||||
BasicBlock *EdgeBB = BI->getSuccessor(0);
|
BasicBlock *EdgeBB = BI->getSuccessor(0);
|
||||||
if (!TrueWhenEqual) std::swap(DefaultBB, EdgeBB);
|
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.
|
// Convert pointer to int before we switch.
|
||||||
if (CompVal->getType()->isPointerTy()) {
|
if (CompVal->getType()->isPointerTy()) {
|
||||||
assert(TD && "Cannot switch on pointer without TargetData");
|
assert(TD && "Cannot switch on pointer without TargetData");
|
||||||
@ -2079,8 +2121,8 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the new switch instruction now.
|
// Create the new switch instruction now.
|
||||||
SwitchInst *New = SwitchInst::Create(CompVal, DefaultBB,
|
SwitchInst *New =
|
||||||
Values.size(), BI);
|
SwitchInst::Create(CompVal, DefaultBB, Values.size(), BI);
|
||||||
|
|
||||||
// Add all of the 'cases' to the switch instruction.
|
// Add all of the 'cases' to the switch instruction.
|
||||||
for (unsigned i = 0, e = Values.size(); i != e; ++i)
|
for (unsigned i = 0, e = Values.size(); i != e; ++i)
|
||||||
|
@ -149,7 +149,30 @@ UnifiedReturnBlock: ; preds = %shortcirc_done.4, %shortcirc_next.4
|
|||||||
; CHECK: i32 18, label %UnifiedReturnBlock
|
; CHECK: i32 18, label %UnifiedReturnBlock
|
||||||
; CHECK: i32 19, label %switch.edge
|
; CHECK: i32 19, label %switch.edge
|
||||||
; CHECK: ]
|
; 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: ]
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user