Skip to content

Commit f9d54a5

Browse files
committed
[SimplifyCFG] Replace unreachable switch lookup table holes with poison
1 parent ac23a90 commit f9d54a5

File tree

3 files changed

+44
-32
lines changed

3 files changed

+44
-32
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6531,8 +6531,17 @@ SwitchLookupTable::SwitchLookupTable(
65316531
uint64_t Idx = (CaseVal->getValue() - Offset->getValue()).getLimitedValue();
65326532
TableContents[Idx] = CaseRes;
65336533

6534-
if (CaseRes != SingleValue)
6535-
SingleValue = nullptr;
6534+
if (SingleValue && CaseRes != SingleValue) {
6535+
if (isa<PoisonValue>(SingleValue)) {
6536+
// All of the switch cases until now have returned poison.
6537+
// If this case returns a non-poison value, ignore the previous
6538+
// poisons and use this case's result as the single constant
6539+
// value.
6540+
if (!isa<PoisonValue>(CaseRes))
6541+
SingleValue = CaseRes;
6542+
} else if (!isa<PoisonValue>(CaseRes))
6543+
SingleValue = nullptr;
6544+
}
65366545
}
65376546

65386547
// Fill in any holes in the table with the default result.
@@ -6545,7 +6554,10 @@ SwitchLookupTable::SwitchLookupTable(
65456554
TableContents[I] = DefaultValue;
65466555
}
65476556

6548-
if (DefaultValue != SingleValue)
6557+
// If the default value is poison, all the holes are poison.
6558+
bool DefaultValueIsPoison = isa<PoisonValue>(DefaultValue);
6559+
6560+
if (DefaultValue != SingleValue && !DefaultValueIsPoison)
65496561
SingleValue = nullptr;
65506562
}
65516563

@@ -6569,6 +6581,16 @@ SwitchLookupTable::SwitchLookupTable(
65696581
// Check if there is the same distance between two consecutive values.
65706582
for (uint64_t I = 0; I < TableSize; ++I) {
65716583
ConstantInt *ConstVal = dyn_cast<ConstantInt>(TableContents[I]);
6584+
6585+
if (!ConstVal && isa<PoisonValue>(TableContents[I])) {
6586+
// This is an poison, so it's (probably) a lookup table hole.
6587+
// To prevent any regressions from before we switched to using poison as
6588+
// the default value, holes will fall back to using the first value.
6589+
// This can be removed once we add proper handling for poisons in lookup
6590+
// tables.
6591+
ConstVal = dyn_cast<ConstantInt>(Values[0].second);
6592+
}
6593+
65726594
if (!ConstVal) {
65736595
// This is an undef. We could deal with it, but undefs in lookup tables
65746596
// are very seldom. It's probably not worth the additional complexity.
@@ -7003,16 +7025,16 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
70037025

70047026
// If the table has holes but the default destination doesn't produce any
70057027
// constant results, the lookup table entries corresponding to the holes will
7006-
// contain undefined values.
7007-
bool AllHolesAreUndefined = TableHasHoles && !HasDefaultResults;
7028+
// contain poison.
7029+
bool AllHolesArePoison = TableHasHoles && !HasDefaultResults;
70087030

70097031
// If the default destination doesn't produce a constant result but is still
70107032
// reachable, and the lookup table has holes, we need to use a mask to
70117033
// determine if the current index should load from the lookup table or jump
70127034
// to the default case.
70137035
// The mask is unnecessary if the table has holes but the default destination
70147036
// is unreachable, as in that case the holes must also be unreachable.
7015-
bool NeedMask = AllHolesAreUndefined && DefaultIsReachable;
7037+
bool NeedMask = AllHolesArePoison && DefaultIsReachable;
70167038
if (NeedMask) {
70177039
// As an extra penalty for the validity test we require more cases.
70187040
if (SI->getNumCases() < 4) // FIXME: Find best threshold value (benchmark).
@@ -7157,9 +7179,11 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
71577179
for (PHINode *PHI : PHIs) {
71587180
const ResultListTy &ResultList = ResultLists[PHI];
71597181

7182+
Type *ResultType = ResultList.begin()->second->getType();
7183+
71607184
// Use any value to fill the lookup table holes.
71617185
Constant *DV =
7162-
AllHolesAreUndefined ? ResultLists[PHI][0].second : DefaultResults[PHI];
7186+
AllHolesArePoison ? PoisonValue::get(ResultType) : DefaultResults[PHI];
71637187
StringRef FuncName = Fn->getName();
71647188
SwitchLookupTable Table(Mod, TableSize, TableIndexOffset, ResultList, DV,
71657189
DL, FuncName);

llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table.ll

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,14 @@ target triple = "x86_64-unknown-linux-gnu"
3434
; CHECK: @switch.table.unreachable_case = private unnamed_addr constant [9 x i32] [i32 0, i32 0, i32 0, i32 2, i32 -1, i32 1, i32 1, i32 1, i32 1], align 4
3535
; CHECK: @switch.table.unreachable_default = private unnamed_addr constant [4 x i32] [i32 42, i32 52, i32 1, i32 2], align 4
3636
; CHECK: @switch.table.nodefaultnoholes = private unnamed_addr constant [4 x i32] [i32 55, i32 123, i32 0, i32 -1], align 4
37-
; CHECK: @switch.table.nodefaultwithholes = private unnamed_addr constant [6 x i32] [i32 55, i32 123, i32 0, i32 -1, i32 55, i32 -1], align 4
37+
; CHECK: @switch.table.nodefaultwithholes = private unnamed_addr constant [6 x i32] [i32 55, i32 123, i32 0, i32 -1, i32 poison, i32 -1], align 4
3838
; CHECK: @switch.table.threecases = private unnamed_addr constant [3 x i32] [i32 10, i32 7, i32 5], align 4
39-
; CHECK: @switch.table.covered_switch_with_bit_tests = private unnamed_addr constant [8 x i32] [i32 2, i32 2, i32 2, i32 2, i32 2, i32 2, i32 1, i32 1], align 4
39+
; CHECK: @switch.table.covered_switch_with_bit_tests = private unnamed_addr constant [8 x i32] [i32 2, i32 2, i32 poison, i32 poison, i32 poison, i32 poison, i32 1, i32 1], align 4
4040
; CHECK: @switch.table.signed_overflow1 = private unnamed_addr constant [4 x i32] [i32 3333, i32 4444, i32 1111, i32 2222], align 4
41-
; CHECK: @switch.table.signed_overflow2 = private unnamed_addr constant [4 x i32] [i32 3333, i32 4444, i32 2222, i32 2222], align 4
42-
; CHECK: @switch.table.constant_hole_unreachable_default_firstundef = private unnamed_addr constant [5 x i32] [i32 undef, i32 undef, i32 1, i32 1, i32 1], align 4
43-
; CHECK: @switch.table.constant_hole_unreachable_default_lastundef = private unnamed_addr constant [5 x i32] [i32 1, i32 1, i32 1, i32 1, i32 undef], align 4
44-
; CHECK: @switch.table.constant_hole_unreachable_default_firstpoison = private unnamed_addr constant [5 x i32] [i32 poison, i32 poison, i32 1, i32 1, i32 1], align 4
45-
; CHECK: @switch.table.constant_hole_unreachable_default_lastpoison = private unnamed_addr constant [5 x i32] [i32 1, i32 1, i32 1, i32 1, i32 poison], align 4
46-
; CHECK: @switch.table.constant_hole_unreachable_default_undef_poison = private unnamed_addr constant [5 x i32] [i32 undef, i32 undef, i32 poison, i32 poison, i32 poison], align 4
47-
; CHECK: @switch.table.constant_hole_unreachable_default_poison_undef = private unnamed_addr constant [5 x i32] [i32 poison, i32 poison, i32 poison, i32 poison, i32 undef], align 4
48-
; CHECK: @switch.table.linearmap_hole_unreachable_default = private unnamed_addr constant [5 x i32] [i32 1, i32 1, i32 5, i32 7, i32 9], align 4
41+
; CHECK: @switch.table.signed_overflow2 = private unnamed_addr constant [4 x i32] [i32 3333, i32 4444, i32 poison, i32 2222], align 4
42+
; CHECK: @switch.table.constant_hole_unreachable_default_firstundef = private unnamed_addr constant [5 x i32] [i32 undef, i32 poison, i32 1, i32 1, i32 1], align 4
43+
; CHECK: @switch.table.constant_hole_unreachable_default_lastundef = private unnamed_addr constant [5 x i32] [i32 1, i32 poison, i32 1, i32 1, i32 undef], align 4
44+
; CHECK: @switch.table.linearmap_hole_unreachable_default = private unnamed_addr constant [5 x i32] [i32 1, i32 poison, i32 5, i32 7, i32 9], align 4
4945
;.
5046
define i32 @f(i32 %c) {
5147
; CHECK-LABEL: @f(
@@ -2272,9 +2268,7 @@ return:
22722268
define i32 @constant_hole_unreachable_default_firstpoison(i32 %x) {
22732269
; CHECK-LABEL: @constant_hole_unreachable_default_firstpoison(
22742270
; CHECK-NEXT: entry:
2275-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.constant_hole_unreachable_default_firstpoison, i32 0, i32 [[X:%.*]]
2276-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2277-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2271+
; CHECK-NEXT: ret i32 1
22782272
;
22792273
entry:
22802274
switch i32 %x, label %sw.default [
@@ -2298,9 +2292,7 @@ return:
22982292
define i32 @constant_hole_unreachable_default_lastpoison(i32 %x) {
22992293
; CHECK-LABEL: @constant_hole_unreachable_default_lastpoison(
23002294
; CHECK-NEXT: entry:
2301-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.constant_hole_unreachable_default_lastpoison, i32 0, i32 [[X:%.*]]
2302-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2303-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2295+
; CHECK-NEXT: ret i32 1
23042296
;
23052297
entry:
23062298
switch i32 %x, label %sw.default [
@@ -2322,9 +2314,7 @@ return:
23222314
define i32 @constant_hole_unreachable_default_undef_poison(i32 %x) {
23232315
; CHECK-LABEL: @constant_hole_unreachable_default_undef_poison(
23242316
; CHECK-NEXT: entry:
2325-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.constant_hole_unreachable_default_undef_poison, i32 0, i32 [[X:%.*]]
2326-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2327-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2317+
; CHECK-NEXT: ret i32 undef
23282318
;
23292319
entry:
23302320
switch i32 %x, label %sw.default [
@@ -2346,9 +2336,7 @@ return:
23462336
define i32 @constant_hole_unreachable_default_poison_undef(i32 %x) {
23472337
; CHECK-LABEL: @constant_hole_unreachable_default_poison_undef(
23482338
; CHECK-NEXT: entry:
2349-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.constant_hole_unreachable_default_poison_undef, i32 0, i32 [[X:%.*]]
2350-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2351-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2339+
; CHECK-NEXT: ret i32 undef
23522340
;
23532341
entry:
23542342
switch i32 %x, label %sw.default [

llvm/test/Transforms/SimplifyCFG/X86/switch_to_lookup_table_big.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ target triple = "i386-pc-linux-gnu"
77
;.
88
; CHECK: @switch.table.reachable_default_dense_0to31 = private unnamed_addr constant [32 x i32] [i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1], align 4
99
; CHECK: @switch.table.unreachable_default_dense_0to31 = private unnamed_addr constant [32 x i32] [i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1], align 4
10-
; CHECK: @switch.table.reachable_default_holes_0to31 = private unnamed_addr constant [32 x i32] [i32 0, i32 7, i32 6, i32 0, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 0, i32 2, i32 1, i32 0, i32 7, i32 0, i32 5, i32 4, i32 3, i32 2, i32 0, i32 0, i32 7, i32 6, i32 5, i32 0, i32 3, i32 2, i32 1], align 4
11-
; CHECK: @switch.table.unreachable_default_holes_0to31 = private unnamed_addr constant [32 x i32] [i32 0, i32 7, i32 6, i32 0, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 0, i32 2, i32 1, i32 0, i32 7, i32 0, i32 5, i32 4, i32 3, i32 2, i32 0, i32 0, i32 7, i32 6, i32 5, i32 0, i32 3, i32 2, i32 1], align 4
10+
; CHECK: @switch.table.reachable_default_holes_0to31 = private unnamed_addr constant [32 x i32] [i32 0, i32 7, i32 6, i32 poison, i32 4, i32 3, i32 2, i32 1, i32 poison, i32 7, i32 6, i32 5, i32 4, i32 poison, i32 2, i32 1, i32 0, i32 7, i32 poison, i32 5, i32 4, i32 3, i32 2, i32 poison, i32 0, i32 7, i32 6, i32 5, i32 poison, i32 3, i32 2, i32 1], align 4
11+
; CHECK: @switch.table.unreachable_default_holes_0to31 = private unnamed_addr constant [32 x i32] [i32 0, i32 7, i32 6, i32 poison, i32 4, i32 3, i32 2, i32 1, i32 poison, i32 7, i32 6, i32 5, i32 4, i32 poison, i32 2, i32 1, i32 0, i32 7, i32 poison, i32 5, i32 4, i32 3, i32 2, i32 poison, i32 0, i32 7, i32 6, i32 5, i32 poison, i32 3, i32 2, i32 1], align 4
1212
; CHECK: @switch.table.reachable_default_dense_0to32 = private unnamed_addr constant [33 x i32] [i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0], align 4
1313
; CHECK: @switch.table.unreachable_default_dense_0to32 = private unnamed_addr constant [33 x i32] [i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 3, i32 2, i32 1, i32 0], align 4
14-
; CHECK: @switch.table.unreachable_default_holes_0to32 = private unnamed_addr constant [33 x i32] [i32 0, i32 7, i32 6, i32 0, i32 4, i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4, i32 0, i32 2, i32 1, i32 0, i32 7, i32 0, i32 5, i32 4, i32 3, i32 2, i32 0, i32 0, i32 7, i32 6, i32 5, i32 0, i32 3, i32 2, i32 1, i32 0], align 4
14+
; CHECK: @switch.table.unreachable_default_holes_0to32 = private unnamed_addr constant [33 x i32] [i32 0, i32 7, i32 6, i32 poison, i32 4, i32 3, i32 2, i32 1, i32 poison, i32 7, i32 6, i32 5, i32 4, i32 poison, i32 2, i32 1, i32 0, i32 7, i32 poison, i32 5, i32 4, i32 3, i32 2, i32 poison, i32 0, i32 7, i32 6, i32 5, i32 poison, i32 3, i32 2, i32 1, i32 0], align 4
1515
;.
1616
define i32 @reachable_default_dense_0to31(i32 %x, i32 %y) {
1717
; CHECK-LABEL: @reachable_default_dense_0to31(

0 commit comments

Comments
 (0)