mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 19:52:54 +01: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. llvm-svn: 121671
This commit is contained in:
parent
6d4df726a6
commit
a21c02e807
@ -1770,6 +1770,91 @@ static bool SimplifyIndirectBrOnSelect(IndirectBrInst *IBI, SelectInst *SI) {
|
||||
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 Changed = false;
|
||||
Function *Fn = BB->getParent();
|
||||
@ -1926,11 +2011,22 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) {
|
||||
} else if (BranchInst *BI = dyn_cast<BranchInst>(BB->getTerminator())) {
|
||||
if (BI->isUnconditional()) {
|
||||
// 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() &&
|
||||
TryToSimplifyUncondBranchFromEmptyBlock(BB))
|
||||
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
|
||||
if (isValueEqualityComparison(BI)) {
|
||||
// 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()
|
||||
|
||||
@ -15,6 +15,11 @@ T: ; preds = %0
|
||||
F: ; preds = %0
|
||||
call void @foo2( )
|
||||
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) {
|
||||
@ -28,6 +33,11 @@ T: ; preds = %0
|
||||
F: ; preds = %0
|
||||
call void @foo2( )
|
||||
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) {
|
||||
@ -42,6 +52,39 @@ T: ; preds = %N, %0
|
||||
F: ; preds = %N
|
||||
call void @foo2( )
|
||||
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…
Reference in New Issue
Block a user