mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-03-02 22:32:08 +00:00
fix a fairly serious oversight with switch formation from
or'd conditions. Previously we'd compile something like this: int crud (unsigned char c) { return c == 62 || c == 34 || c == 92; } into: switch i8 %c, label %lor.rhs [ i8 62, label %lor.end i8 34, label %lor.end ] lor.rhs: ; preds = %entry %cmp8 = icmp eq i8 %c, 92 br label %lor.end lor.end: ; preds = %entry, %entry, %lor.rhs %0 = phi i1 [ true, %entry ], [ %cmp8, %lor.rhs ], [ true, %entry ] %lor.ext = zext i1 %0 to i32 ret i32 %lor.ext which failed to merge the compare-with-92 into the switch. With this patch we simplify this all the way to: switch i8 %c, label %lor.rhs [ i8 62, label %lor.end i8 34, label %lor.end i8 92, label %lor.end ] lor.rhs: ; preds = %entry br label %lor.end lor.end: ; preds = %entry, %entry, %entry, %lor.rhs %0 = phi i1 [ true, %entry ], [ false, %lor.rhs ], [ true, %entry ], [ true, %entry ] %lor.ext = zext i1 %0 to i32 ret i32 %lor.ext which is much better for codegen's switch lowering stuff. This kicks in 33 times on 176.gcc (for example) cutting 103 instructions off the generated code. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@121671 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e991b5fdd5
commit
61c77449c7
@ -1770,6 +1770,91 @@ static bool SimplifyIndirectBrOnSelect(IndirectBrInst *IBI, SelectInst *SI) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TryToSimplifyUncondBranchWithICmpInIt - This is called when we find an icmp
|
||||||
|
/// instruction (a seteq/setne with a constant) as the only instruction in a
|
||||||
|
/// block that ends with an uncond branch. We are looking for a very specific
|
||||||
|
/// pattern that occurs when "A == 1 || A == 2 || A == 3" gets simplified. In
|
||||||
|
/// this case, we merge the first two "or's of icmp" into a switch, but then the
|
||||||
|
/// default value goes to an uncond block with a seteq in it, we get something
|
||||||
|
/// like:
|
||||||
|
///
|
||||||
|
/// switch i8 %A, label %DEFAULT [ i8 1, label %end i8 2, label %end ]
|
||||||
|
/// DEFAULT:
|
||||||
|
/// %tmp = icmp eq i8 %A, 92
|
||||||
|
/// br label %end
|
||||||
|
/// end:
|
||||||
|
/// ... = phi i1 [ true, %entry ], [ %tmp, %DEFAULT ], [ true, %entry ]
|
||||||
|
///
|
||||||
|
/// We prefer to split the edge to 'end' so that there is a true/false entry to
|
||||||
|
/// the PHI, merging the third icmp into the switch.
|
||||||
|
static bool TryToSimplifyUncondBranchWithICmpInIt(ICmpInst *ICI) {
|
||||||
|
BasicBlock *BB = ICI->getParent();
|
||||||
|
// If the block has any PHIs in it or the icmp has multiple uses, it is too
|
||||||
|
// complex.
|
||||||
|
if (isa<PHINode>(BB->begin()) || !ICI->hasOneUse()) return false;
|
||||||
|
|
||||||
|
Value *V = ICI->getOperand(0);
|
||||||
|
ConstantInt *Cst = cast<ConstantInt>(ICI->getOperand(1));
|
||||||
|
|
||||||
|
// The pattern we're looking for is where our only predecessor is a switch on
|
||||||
|
// 'V' and this block is the default case for the switch. In this case we can
|
||||||
|
// fold the compared value into the switch to simplify things.
|
||||||
|
BasicBlock *Pred = BB->getSinglePredecessor();
|
||||||
|
if (Pred == 0 || !isa<SwitchInst>(Pred->getTerminator())) return false;
|
||||||
|
|
||||||
|
SwitchInst *SI = cast<SwitchInst>(Pred->getTerminator());
|
||||||
|
if (SI->getCondition() != V)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If BB is reachable on a non-default case, then we simply know the value of
|
||||||
|
// V in this block. Substitute it and constant fold the icmp instruction
|
||||||
|
// away.
|
||||||
|
if (SI->getDefaultDest() != BB) {
|
||||||
|
ConstantInt *VVal = SI->findCaseDest(BB);
|
||||||
|
assert(VVal && "Should have a unique destination value");
|
||||||
|
ICI->setOperand(0, VVal);
|
||||||
|
|
||||||
|
if (Constant *C = ConstantFoldInstruction(ICI)) {
|
||||||
|
ICI->replaceAllUsesWith(C);
|
||||||
|
ICI->eraseFromParent();
|
||||||
|
}
|
||||||
|
// BB is now empty, so it is likely to simplify away.
|
||||||
|
return SimplifyCFG(BB) | true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The use of the icmp has to be in the 'end' block, by the only PHI node in
|
||||||
|
// the block.
|
||||||
|
BasicBlock *SuccBlock = BB->getTerminator()->getSuccessor(0);
|
||||||
|
PHINode *PHIUse = dyn_cast<PHINode>(ICI->use_back());
|
||||||
|
if (PHIUse == 0 || PHIUse != &SuccBlock->front() ||
|
||||||
|
isa<PHINode>(++BasicBlock::iterator(PHIUse)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If the icmp is a SETEQ, then the default dest gets false, the new edge gets
|
||||||
|
// true in the PHI.
|
||||||
|
Constant *DefaultCst = ConstantInt::getTrue(BB->getContext());
|
||||||
|
Constant *NewCst = ConstantInt::getFalse(BB->getContext());
|
||||||
|
|
||||||
|
if (ICI->getPredicate() == ICmpInst::ICMP_EQ)
|
||||||
|
std::swap(DefaultCst, NewCst);
|
||||||
|
|
||||||
|
// Replace ICI (which is used by the PHI for the default value) with true or
|
||||||
|
// false depending on if it is EQ or NE.
|
||||||
|
ICI->replaceAllUsesWith(DefaultCst);
|
||||||
|
ICI->eraseFromParent();
|
||||||
|
|
||||||
|
// Okay, the switch goes to this block on a default value. Add an edge from
|
||||||
|
// the switch to the merge point on the compared value.
|
||||||
|
BasicBlock *NewBB = BasicBlock::Create(BB->getContext(), "switch.edge",
|
||||||
|
BB->getParent(), BB);
|
||||||
|
SI->addCase(Cst, NewBB);
|
||||||
|
|
||||||
|
// NewBB branches to the phi block, add the uncond branch and the phi entry.
|
||||||
|
BranchInst::Create(SuccBlock, NewBB);
|
||||||
|
PHIUse->addIncoming(NewCst, NewBB);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool SimplifyCFGOpt::run(BasicBlock *BB) {
|
bool SimplifyCFGOpt::run(BasicBlock *BB) {
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
Function *Fn = BB->getParent();
|
Function *Fn = BB->getParent();
|
||||||
@ -1926,11 +2011,22 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) {
|
|||||||
} else if (BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator())) {
|
} else if (BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator())) {
|
||||||
if (BI->isUnconditional()) {
|
if (BI->isUnconditional()) {
|
||||||
// If the Terminator is the only non-phi instruction, simplify the block.
|
// If the Terminator is the only non-phi instruction, simplify the block.
|
||||||
Instruction *I = BB->getFirstNonPHIOrDbg();
|
BasicBlock::iterator I = BB->getFirstNonPHIOrDbg();
|
||||||
if (I->isTerminator() && BB != &Fn->getEntryBlock() &&
|
if (I->isTerminator() && BB != &Fn->getEntryBlock() &&
|
||||||
TryToSimplifyUncondBranchFromEmptyBlock(BB))
|
TryToSimplifyUncondBranchFromEmptyBlock(BB))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// If the only instruction in the block is a seteq/setne comparison
|
||||||
|
// against a constant, try to simplify the block.
|
||||||
|
if (ICmpInst *ICI = dyn_cast<ICmpInst>(I))
|
||||||
|
if (ICI->isEquality() && isa<ConstantInt>(ICI->getOperand(1))) {
|
||||||
|
for (++I; isa<DbgInfoIntrinsic>(I); ++I)
|
||||||
|
;
|
||||||
|
if (I->isTerminator() &&
|
||||||
|
TryToSimplifyUncondBranchWithICmpInIt(ICI))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} else { // Conditional branch
|
} else { // Conditional branch
|
||||||
if (isValueEqualityComparison(BI)) {
|
if (isValueEqualityComparison(BI)) {
|
||||||
// If we only have one predecessor, and if it is a branch on this value,
|
// If we only have one predecessor, and if it is a branch on this value,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
; RUN: opt < %s -simplifycfg -S | not grep br
|
; RUN: opt < %s -simplifycfg -S | FileCheck %s
|
||||||
|
|
||||||
declare void @foo1()
|
declare void @foo1()
|
||||||
|
|
||||||
@ -15,6 +15,11 @@ T: ; preds = %0
|
|||||||
F: ; preds = %0
|
F: ; preds = %0
|
||||||
call void @foo2( )
|
call void @foo2( )
|
||||||
ret void
|
ret void
|
||||||
|
; CHECK: @test1
|
||||||
|
; CHECK: switch i32 %V, label %F [
|
||||||
|
; CHECK: i32 17, label %T
|
||||||
|
; CHECK: i32 4, label %T
|
||||||
|
; CHECK: ]
|
||||||
}
|
}
|
||||||
|
|
||||||
define void @test2(i32 %V) {
|
define void @test2(i32 %V) {
|
||||||
@ -28,6 +33,11 @@ T: ; preds = %0
|
|||||||
F: ; preds = %0
|
F: ; preds = %0
|
||||||
call void @foo2( )
|
call void @foo2( )
|
||||||
ret void
|
ret void
|
||||||
|
; CHECK: @test2
|
||||||
|
; CHECK: switch i32 %V, label %T [
|
||||||
|
; CHECK: i32 17, label %F
|
||||||
|
; CHECK: i32 4, label %F
|
||||||
|
; CHECK: ]
|
||||||
}
|
}
|
||||||
|
|
||||||
define void @test3(i32 %V) {
|
define void @test3(i32 %V) {
|
||||||
@ -42,6 +52,39 @@ T: ; preds = %N, %0
|
|||||||
F: ; preds = %N
|
F: ; preds = %N
|
||||||
call void @foo2( )
|
call void @foo2( )
|
||||||
ret void
|
ret void
|
||||||
|
|
||||||
|
; CHECK: @test3
|
||||||
|
; CHECK: switch i32 %V, label %F [
|
||||||
|
; CHECK: i32 4, label %T
|
||||||
|
; CHECK: i32 17, label %T
|
||||||
|
; CHECK: ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
define i32 @test4(i8 zeroext %c) nounwind ssp noredzone {
|
||||||
|
entry:
|
||||||
|
%cmp = icmp eq i8 %c, 62
|
||||||
|
br i1 %cmp, label %lor.end, label %lor.lhs.false
|
||||||
|
|
||||||
|
lor.lhs.false: ; preds = %entry
|
||||||
|
%cmp4 = icmp eq i8 %c, 34
|
||||||
|
br i1 %cmp4, label %lor.end, label %lor.rhs
|
||||||
|
|
||||||
|
lor.rhs: ; preds = %lor.lhs.false
|
||||||
|
%cmp8 = icmp eq i8 %c, 92
|
||||||
|
br label %lor.end
|
||||||
|
|
||||||
|
lor.end: ; preds = %lor.rhs, %lor.lhs.false, %entry
|
||||||
|
%0 = phi i1 [ true, %lor.lhs.false ], [ true, %entry ], [ %cmp8, %lor.rhs ]
|
||||||
|
%lor.ext = zext i1 %0 to i32
|
||||||
|
ret i32 %lor.ext
|
||||||
|
|
||||||
|
; CHECK: @test4
|
||||||
|
; CHECK: switch i8 %c, label %lor.rhs [
|
||||||
|
; CHECK: i8 62, label %lor.end
|
||||||
|
; CHECK: i8 34, label %lor.end
|
||||||
|
; CHECK: i8 92, label %lor.end
|
||||||
|
; CHECK: ]
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user