1
0
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:
Chris Lattner 2010-12-13 03:18:54 +00:00
parent 6d4df726a6
commit a21c02e807
2 changed files with 141 additions and 2 deletions

View File

@ -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,

View File

@ -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: ]
}