Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 110 additions & 22 deletions llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,9 @@ class SimplifyCFGOpt {

bool tryToSimplifyUncondBranchWithICmpInIt(ICmpInst *ICI,
IRBuilder<> &Builder);

bool tryToSimplifyUncondBranchWithICmpSelectInIt(ICmpInst *ICI,
SelectInst *Select,
IRBuilder<> &Builder);
bool hoistCommonCodeFromSuccessors(Instruction *TI, bool AllInstsEqOnly);
bool hoistSuccIdenticalTerminatorToSwitchOrIf(
Instruction *TI, Instruction *I1,
Expand Down Expand Up @@ -5011,25 +5013,101 @@ bool SimplifyCFGOpt::simplifyIndirectBrOnSelect(IndirectBrInst *IBI,
/// the PHI, merging the third icmp into the switch.
bool SimplifyCFGOpt::tryToSimplifyUncondBranchWithICmpInIt(
ICmpInst *ICI, IRBuilder<> &Builder) {
// Select == nullptr means we assume that there is a hidden no-op select
// instruction of _ = `select %icmp, true, false` just after `%icmp = ...`
return tryToSimplifyUncondBranchWithICmpSelectInIt(ICI, nullptr, Builder);
}

/// Similar to tryToSimplifyUncondBranchWithICmpInIt, but handle a more generic
/// case. This is called when we find an icmp instruction (a seteq/setne with a
/// constant) and its following select instruction as the only TWO instruction
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// constant) and its following select instruction as the only TWO instruction
/// constant) and its following select instruction as the only TWO instructions

/// in a block that ends with an uncond branch. We are looking for a very
/// specific pattern that occurs when "
/// if (A == 1) return C1;
/// if (A == 2) return C2;
/// if (A < 3) return C3;
/// return C4;
/// " gets simplified. In this case, we merge the first two "branches of icmp"
/// into a switch, but then the default value goes to an uncond block with a lt
/// icmp and select in it, as InstCombine can not simplify "A < 3" as "A == 2".
/// After SimplifyCFG and other subsequent optimizations (e.g., SCCP), we might
/// get something like:
///
/// case1:
/// switch i8 %A, label %DEFAULT [ i8 0, label %end i8 1, label %case2 ]
/// case2:
/// br label %end
/// DEFAULT:
/// %tmp = icmp eq i8 %A, 2
/// %val = select i1 %tmp, i8 C3, i8 C4
/// br label %end
/// end:
/// _ = phi i8 [ C1, %case1 ], [ C2, %case2 ], [ %val, %DEFAULT ]
///
/// We prefer to split the edge to 'end' so that there are TWO entries of V3/V4
/// to the PHI, merging the icmp & select into the switch, as follows:
///
/// case1:
/// switch i8 %A, label %DEFAULT [
/// i8 0, label %end
/// i8 1, label %case2
/// i8 2, label %case3
/// ]
/// case2:
/// br label %end
/// case3:
/// br label %end
/// DEFAULT:
/// br label %end
/// end:
/// _ = phi i8 [ C1, %case1 ], [ C2, %case2 ], [ C3, %case2 ], [ C4, %DEFAULT]
bool SimplifyCFGOpt::tryToSimplifyUncondBranchWithICmpSelectInIt(
ICmpInst *ICI, SelectInst *Select, IRBuilder<> &Builder) {
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())
// If the block has any PHIs in it or the icmp/select has multiple uses, it is
// too complex.
if (isa<PHINode>(BB->begin()) || !ICI->hasOneUse() ||
(Select && !Select->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 || !isa<SwitchInst>(Pred->getTerminator()))
return false;

Value *IcmpCond;
ConstantInt *NewCaseVal;
CmpPredicate Predicate;

// Match icmp X, C
if (!match(ICI,
m_ICmp(Predicate, m_Value(IcmpCond), m_ConstantInt(NewCaseVal))))
return false;

Value *SelectCond, *SelectTrueVal, *SelectFalseVal;
Instruction *User;
if (!Select) {
// If Select == nullptr, we can assume that there is a hidden no-op select
// just after icmp
SelectCond = ICI;
SelectTrueVal = Builder.getTrue();
SelectFalseVal = Builder.getFalse();
User = ICI->user_back();
} else {
SelectCond = Select->getCondition();
// Check if the select condition is the same as the icmp condition.
if (SelectCond != ICI)
return false;
SelectTrueVal = Select->getTrueValue();
SelectFalseVal = Select->getFalseValue();
User = Select->user_back();
}

SwitchInst *SI = cast<SwitchInst>(Pred->getTerminator());
if (SI->getCondition() != V)
if (SI->getCondition() != IcmpCond)
return false;

// If BB is reachable on a non-default case, then we simply know the value of
Expand All @@ -5051,9 +5129,9 @@ bool SimplifyCFGOpt::tryToSimplifyUncondBranchWithICmpInIt(
// Ok, the block is reachable from the default dest. If the constant we're
// comparing exists in one of the other edges, then we can constant fold ICI
// and zap it.
if (SI->findCaseValue(Cst) != SI->case_default()) {
if (SI->findCaseValue(NewCaseVal) != SI->case_default()) {
Value *V;
if (ICI->getPredicate() == ICmpInst::ICMP_EQ)
if (Predicate == ICmpInst::ICMP_EQ)
V = ConstantInt::getFalse(BB->getContext());
else
V = ConstantInt::getTrue(BB->getContext());
Expand All @@ -5064,25 +5142,30 @@ bool SimplifyCFGOpt::tryToSimplifyUncondBranchWithICmpInIt(
return requestResimplify();
}

// The use of the icmp has to be in the 'end' block, by the only PHI node in
// The use of the select 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->user_back());
PHINode *PHIUse = dyn_cast<PHINode>(User);
if (PHIUse == nullptr || 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 the icmp is a SETEQ, then the default dest gets SelectFalseVal, the new
// edge gets SelectTrueVal in the PHI.
Value *DefaultCst = SelectFalseVal;
Value *NewCst = SelectTrueVal;

if (ICI->getPredicate() == ICmpInst::ICMP_EQ)
if (ICI->getPredicate() == ICmpInst::ICMP_NE)
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);
// Replace Select (which is used by the PHI for the default value) with
// SelectFalseVal or SelectTrueVal depending on if ICI is EQ or NE.
if (Select) {
Select->replaceAllUsesWith(DefaultCst);
Select->eraseFromParent();
} else {
ICI->replaceAllUsesWith(DefaultCst);
}
ICI->eraseFromParent();

SmallVector<DominatorTree::UpdateType, 2> Updates;
Expand All @@ -5099,7 +5182,7 @@ bool SimplifyCFGOpt::tryToSimplifyUncondBranchWithICmpInIt(
NewW = ((uint64_t(*W0) + 1) >> 1);
SIW.setSuccessorWeight(0, *NewW);
}
SIW.addCase(Cst, NewBB, NewW);
SIW.addCase(NewCaseVal, NewBB, NewW);
if (DTU)
Updates.push_back({DominatorTree::Insert, Pred, NewBB});
}
Expand Down Expand Up @@ -8167,13 +8250,18 @@ bool SimplifyCFGOpt::simplifyUncondBranch(BranchInst *BI,

// 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 (ICmpInst *ICI = dyn_cast<ICmpInst>(I)) {
if (ICI->isEquality() && isa<ConstantInt>(ICI->getOperand(1))) {
++I;
if (I->isTerminator() &&
tryToSimplifyUncondBranchWithICmpInIt(ICI, Builder))
return true;
if (isa<SelectInst>(I) && I->getNextNode()->isTerminator() &&
tryToSimplifyUncondBranchWithICmpSelectInIt(ICI, cast<SelectInst>(I),
Builder))
return true;
}
}

// See if we can merge an empty landing pad block with another which is
// equivalent.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
; DISABLE-NOT: @{{.*}} = private unnamed_addr constant [3 x ptr] [ptr @c1, ptr @c2, ptr @c3]
; ENABLE: @{{.*}} = private unnamed_addr constant [3 x ptr] [ptr @g1, ptr @g2, ptr @g3]
; DISABLE-NOT: @{{.*}} = private unnamed_addr constant [3 x ptr] [ptr @g1, ptr @g2, ptr @g3]
; ENABLE: @{{.*}} = private unnamed_addr constant [3 x ptr] [ptr @f1, ptr @f2, ptr @f3]
; DISABLE-NOT: @{{.*}} = private unnamed_addr constant [3 x ptr] [ptr @f1, ptr @f2, ptr @f3]
; ENABLE: @{{.*}} = private unnamed_addr constant [4 x ptr] [ptr @f1, ptr @f2, ptr @f3, ptr @f4]
; DISABLE-NOT: @{{.*}} = private unnamed_addr constant [4 x ptr] [ptr @f1, ptr @f2, ptr @f3, ptr @f4]

target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "armv7a--none-eabi"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,13 +410,12 @@ define i1 @single_value_with_mask(i32 %x) {
; OPTNOLUT-NEXT: i32 21, label %[[END]]
; OPTNOLUT-NEXT: i32 48, label %[[END]]
; OPTNOLUT-NEXT: i32 16, label %[[END]]
; OPTNOLUT-NEXT: i32 80, label %[[END]]
; OPTNOLUT-NEXT: ]
; OPTNOLUT: [[DEFAULT]]:
; OPTNOLUT-NEXT: [[CMP:%.*]] = icmp eq i32 [[X]], 80
; OPTNOLUT-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i1 false, i1 true
; OPTNOLUT-NEXT: br label %[[END]]
; OPTNOLUT: [[END]]:
; OPTNOLUT-NEXT: [[RES:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ false, %[[ENTRY]] ], [ false, %[[ENTRY]] ], [ false, %[[ENTRY]] ], [ [[SEL]], %[[DEFAULT]] ]
; OPTNOLUT-NEXT: [[RES:%.*]] = phi i1 [ false, %[[ENTRY]] ], [ false, %[[ENTRY]] ], [ false, %[[ENTRY]] ], [ false, %[[ENTRY]] ], [ true, %[[DEFAULT]] ], [ false, %[[ENTRY]] ]
; OPTNOLUT-NEXT: ret i1 [[RES]]
;
; TTINOLUT-LABEL: define i1 @single_value_with_mask(
Expand Down