Skip to content

Commit e47c26e

Browse files
committed
[SimplifyCFG] Eliminate dead edges of switches according to the domain of conditions
1 parent 32d6b21 commit e47c26e

File tree

7 files changed

+113
-53
lines changed

7 files changed

+113
-53
lines changed

llvm/include/llvm/Analysis/ValueTracking.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,16 @@ findValuesAffectedByCondition(Value *Cond, bool IsAssume,
10241024
LLVM_ABI Value *stripNullTest(Value *V);
10251025
LLVM_ABI const Value *stripNullTest(const Value *V);
10261026

1027+
/// Enumerates all possible values of V and inserts them into the set \p
1028+
/// Constants. If \p AllowUndefOrPoison is false, it fails when V may contains
1029+
/// undef/poison elements. Return true if the result is complete. Otherwise, the
1030+
/// result is incomplete (more than MaxCount values).
1031+
/// NOTE: The constant values are not distinct.
1032+
LLVM_ABI bool
1033+
collectPossibleValues(const Value *V,
1034+
SmallPtrSetImpl<const Constant *> &Constants,
1035+
unsigned MaxCount, bool AllowUndefOrPoison = true);
1036+
10271037
} // end namespace llvm
10281038

10291039
#endif // LLVM_ANALYSIS_VALUETRACKING_H

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10405,3 +10405,55 @@ const Value *llvm::stripNullTest(const Value *V) {
1040510405
Value *llvm::stripNullTest(Value *V) {
1040610406
return const_cast<Value *>(stripNullTest(const_cast<const Value *>(V)));
1040710407
}
10408+
10409+
bool llvm::collectPossibleValues(const Value *V,
10410+
SmallPtrSetImpl<const Constant *> &Constants,
10411+
unsigned MaxCount, bool AllowUndefOrPoison) {
10412+
SmallPtrSet<const Instruction *, 8> Visited;
10413+
SmallVector<const Instruction *, 8> Worklist;
10414+
auto Push = [&](const Value *V) -> bool {
10415+
if (auto *C = dyn_cast<Constant>(V)) {
10416+
if (!AllowUndefOrPoison && !isGuaranteedNotToBeUndefOrPoison(C))
10417+
return false;
10418+
// Check existence first to avoid unnecessary allocations.
10419+
if (Constants.contains(C))
10420+
return true;
10421+
if (Constants.size() == MaxCount)
10422+
return false;
10423+
Constants.insert(C);
10424+
return true;
10425+
}
10426+
10427+
if (auto *Inst = dyn_cast<Instruction>(V)) {
10428+
if (Visited.insert(Inst).second)
10429+
Worklist.push_back(Inst);
10430+
return true;
10431+
}
10432+
return false;
10433+
};
10434+
if (!Push(V))
10435+
return false;
10436+
while (!Worklist.empty()) {
10437+
const Instruction *CurInst = Worklist.pop_back_val();
10438+
switch (CurInst->getOpcode()) {
10439+
case Instruction::Select:
10440+
if (!Push(CurInst->getOperand(1)))
10441+
return false;
10442+
if (!Push(CurInst->getOperand(2)))
10443+
return false;
10444+
break;
10445+
case Instruction::PHI:
10446+
for (Value *IncomingValue : cast<PHINode>(CurInst)->incoming_values()) {
10447+
// Fast path for recurrence PHI.
10448+
if (IncomingValue == CurInst)
10449+
continue;
10450+
if (!Push(IncomingValue))
10451+
return false;
10452+
}
10453+
break;
10454+
default:
10455+
return false;
10456+
}
10457+
}
10458+
return true;
10459+
}

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6020,6 +6020,8 @@ static bool eliminateDeadSwitchCases(SwitchInst *SI, DomTreeUpdater *DTU,
60206020
const DataLayout &DL) {
60216021
Value *Cond = SI->getCondition();
60226022
KnownBits Known = computeKnownBits(Cond, DL, AC, SI);
6023+
SmallPtrSet<const Constant *, 4> KnownValues;
6024+
bool IsKnownValuesValid = collectPossibleValues(Cond, KnownValues, 4);
60236025

60246026
// We can also eliminate cases by determining that their values are outside of
60256027
// the limited range of the condition based on how many significant (non-sign)
@@ -6039,15 +6041,18 @@ static bool eliminateDeadSwitchCases(SwitchInst *SI, DomTreeUpdater *DTU,
60396041
UniqueSuccessors.push_back(Successor);
60406042
++It->second;
60416043
}
6042-
const APInt &CaseVal = Case.getCaseValue()->getValue();
6044+
ConstantInt *CaseC = Case.getCaseValue();
6045+
const APInt &CaseVal = CaseC->getValue();
60436046
if (Known.Zero.intersects(CaseVal) || !Known.One.isSubsetOf(CaseVal) ||
6044-
(CaseVal.getSignificantBits() > MaxSignificantBitsInCond)) {
6045-
DeadCases.push_back(Case.getCaseValue());
6047+
(CaseVal.getSignificantBits() > MaxSignificantBitsInCond) ||
6048+
(IsKnownValuesValid && !KnownValues.contains(CaseC))) {
6049+
DeadCases.push_back(CaseC);
60466050
if (DTU)
60476051
--NumPerSuccessorCases[Successor];
60486052
LLVM_DEBUG(dbgs() << "SimplifyCFG: switch case " << CaseVal
60496053
<< " is dead.\n");
6050-
}
6054+
} else if (IsKnownValuesValid)
6055+
KnownValues.erase(CaseC);
60516056
}
60526057

60536058
// If we can prove that the cases must cover all possible values, the
@@ -6058,33 +6063,41 @@ static bool eliminateDeadSwitchCases(SwitchInst *SI, DomTreeUpdater *DTU,
60586063
const unsigned NumUnknownBits =
60596064
Known.getBitWidth() - (Known.Zero | Known.One).popcount();
60606065
assert(NumUnknownBits <= Known.getBitWidth());
6061-
if (HasDefault && DeadCases.empty() &&
6062-
NumUnknownBits < 64 /* avoid overflow */) {
6063-
uint64_t AllNumCases = 1ULL << NumUnknownBits;
6064-
if (SI->getNumCases() == AllNumCases) {
6066+
if (HasDefault && DeadCases.empty()) {
6067+
if (IsKnownValuesValid && all_of(KnownValues, IsaPred<UndefValue>)) {
60656068
createUnreachableSwitchDefault(SI, DTU);
60666069
return true;
60676070
}
6068-
// When only one case value is missing, replace default with that case.
6069-
// Eliminating the default branch will provide more opportunities for
6070-
// optimization, such as lookup tables.
6071-
if (SI->getNumCases() == AllNumCases - 1) {
6072-
assert(NumUnknownBits > 1 && "Should be canonicalized to a branch");
6073-
IntegerType *CondTy = cast<IntegerType>(Cond->getType());
6074-
if (CondTy->getIntegerBitWidth() > 64 ||
6075-
!DL.fitsInLegalInteger(CondTy->getIntegerBitWidth()))
6076-
return false;
60776071

6078-
uint64_t MissingCaseVal = 0;
6079-
for (const auto &Case : SI->cases())
6080-
MissingCaseVal ^= Case.getCaseValue()->getValue().getLimitedValue();
6081-
auto *MissingCase =
6082-
cast<ConstantInt>(ConstantInt::get(Cond->getType(), MissingCaseVal));
6083-
SwitchInstProfUpdateWrapper SIW(*SI);
6084-
SIW.addCase(MissingCase, SI->getDefaultDest(), SIW.getSuccessorWeight(0));
6085-
createUnreachableSwitchDefault(SI, DTU, /*RemoveOrigDefaultBlock*/ false);
6086-
SIW.setSuccessorWeight(0, 0);
6087-
return true;
6072+
if (NumUnknownBits < 64 /* avoid overflow */) {
6073+
uint64_t AllNumCases = 1ULL << NumUnknownBits;
6074+
if (SI->getNumCases() == AllNumCases) {
6075+
createUnreachableSwitchDefault(SI, DTU);
6076+
return true;
6077+
}
6078+
// When only one case value is missing, replace default with that case.
6079+
// Eliminating the default branch will provide more opportunities for
6080+
// optimization, such as lookup tables.
6081+
if (SI->getNumCases() == AllNumCases - 1) {
6082+
assert(NumUnknownBits > 1 && "Should be canonicalized to a branch");
6083+
IntegerType *CondTy = cast<IntegerType>(Cond->getType());
6084+
if (CondTy->getIntegerBitWidth() > 64 ||
6085+
!DL.fitsInLegalInteger(CondTy->getIntegerBitWidth()))
6086+
return false;
6087+
6088+
uint64_t MissingCaseVal = 0;
6089+
for (const auto &Case : SI->cases())
6090+
MissingCaseVal ^= Case.getCaseValue()->getValue().getLimitedValue();
6091+
auto *MissingCase = cast<ConstantInt>(
6092+
ConstantInt::get(Cond->getType(), MissingCaseVal));
6093+
SwitchInstProfUpdateWrapper SIW(*SI);
6094+
SIW.addCase(MissingCase, SI->getDefaultDest(),
6095+
SIW.getSuccessorWeight(0));
6096+
createUnreachableSwitchDefault(SI, DTU,
6097+
/*RemoveOrigDefaultBlock*/ false);
6098+
SIW.setSuccessorWeight(0, 0);
6099+
return true;
6100+
}
60886101
}
60896102
}
60906103

llvm/test/CodeGen/AArch64/arm64-ccmp.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,12 +430,12 @@ declare i32 @foo()
430430

431431
; Test case distilled from 126.gcc.
432432
; The phi in sw.bb.i.i gets multiple operands for the %entry predecessor.
433-
define void @build_modify_expr() nounwind ssp {
433+
define void @build_modify_expr(i32 %cond) nounwind ssp {
434434
; CHECK-LABEL: build_modify_expr:
435435
; CHECK: ; %bb.0: ; %entry
436436
; CHECK-NEXT: ret
437437
entry:
438-
switch i32 undef, label %sw.bb.i.i [
438+
switch i32 %cond, label %sw.bb.i.i [
439439
i32 69, label %if.end85
440440
i32 70, label %if.end85
441441
i32 71, label %if.end85

llvm/test/Transforms/SimplifyCFG/switch-on-const.ll

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -164,20 +164,9 @@ define void @pr165179(i1 %cond) {
164164
; CHECK: if.else:
165165
; CHECK-NEXT: tail call void @bees.b() #[[ATTR0]]
166166
; CHECK-NEXT: br label [[SWITCHBB]]
167-
; CHECK: switchbb:
168-
; CHECK-NEXT: [[COND1:%.*]] = phi i32 [ 1, [[IF_ELSE]] ], [ -1, [[IF_THEN]] ]
169-
; CHECK-NEXT: switch i32 [[COND1]], label [[DEFAULT:%.*]] [
170-
; CHECK-NEXT: i32 1, label [[EXIT:%.*]]
171-
; CHECK-NEXT: i32 -1, label [[EXIT]]
172-
; CHECK-NEXT: ]
173-
; CHECK: common.ret:
174-
; CHECK-NEXT: ret void
175167
; CHECK: exit:
176168
; CHECK-NEXT: tail call void @bees.a() #[[ATTR0]]
177-
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
178-
; CHECK: default:
179-
; CHECK-NEXT: tail call void @bees.b() #[[ATTR0]]
180-
; CHECK-NEXT: br label [[COMMON_RET]]
169+
; CHECK-NEXT: ret void
181170
;
182171
entry:
183172
br i1 %cond, label %if.then, label %if.else
@@ -219,10 +208,8 @@ define void @switch_remove_dead_case_phi(i1 %cond1, i1 %cond2) {
219208
; CHECK-NEXT: br label [[SWITCHBB]]
220209
; CHECK: switchbb:
221210
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[PHI]], [[IF_ELSE]] ], [ 5, [[IF_THEN]] ]
222-
; CHECK-NEXT: switch i32 [[COND]], label [[DEFAULT:%.*]] [
223-
; CHECK-NEXT: i32 1, label [[EXIT:%.*]]
224-
; CHECK-NEXT: i32 -1, label [[EXIT]]
225-
; CHECK-NEXT: ]
211+
; CHECK-NEXT: [[COND3:%.*]] = icmp eq i32 [[COND]], -1
212+
; CHECK-NEXT: br i1 [[COND3]], label [[EXIT:%.*]], label [[DEFAULT:%.*]]
226213
; CHECK: common.ret:
227214
; CHECK-NEXT: ret void
228215
; CHECK: exit:
@@ -265,10 +252,8 @@ define void @switch_remove_dead_case_select(i1 %cond1, i1 %cond2) {
265252
; CHECK-NEXT: entry:
266253
; CHECK-NEXT: [[X:%.*]] = select i1 [[COND1:%.*]], i32 -1, i32 3
267254
; CHECK-NEXT: [[Y:%.*]] = select i1 [[COND2:%.*]], i32 [[X]], i32 5
268-
; CHECK-NEXT: switch i32 [[Y]], label [[DEFAULT:%.*]] [
269-
; CHECK-NEXT: i32 1, label [[EXIT:%.*]]
270-
; CHECK-NEXT: i32 -1, label [[EXIT]]
271-
; CHECK-NEXT: ]
255+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[Y]], -1
256+
; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[DEFAULT:%.*]]
272257
; CHECK: common.ret:
273258
; CHECK-NEXT: ret void
274259
; CHECK: exit:

llvm/test/Transforms/SimplifyCFG/switch_mask.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ define i1 @pr88607() {
221221
; CHECK-NEXT: entry:
222222
; CHECK-NEXT: [[COND:%.*]] = select i1 false, i32 4, i32 1
223223
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 false, i32 2, i32 [[COND]]
224+
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i32 [[SPEC_SELECT]], 1
224225
; CHECK-NEXT: ret i1 false
225226
;
226227
entry:

llvm/test/Transforms/SimplifyCFG/switch_undef.ll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
define void @f6() #0 {
66
; CHECK-LABEL: @f6(
77
; CHECK-NEXT: entry:
8-
; CHECK-NEXT: br label [[FOR_COND_I:%.*]]
9-
; CHECK: for.cond.i:
8+
; CHECK-NEXT: br label [[F1_EXIT_I:%.*]]
9+
; CHECK: f1.exit.i:
1010
; CHECK-NEXT: [[TOBOOL7_I:%.*]] = icmp ne i16 1, 0
11-
; CHECK-NEXT: br label [[FOR_COND_I]]
11+
; CHECK-NEXT: br label [[F1_EXIT_I]]
1212
;
13-
1413
entry:
1514
br label %for.cond.i
1615

0 commit comments

Comments
 (0)