Skip to content

Commit e30a331

Browse files
committed
[SimplifyCFG] Replace unreachable switch lookup table holes with poison
1 parent 4e6e6d4 commit e30a331

File tree

3 files changed

+48
-38
lines changed

3 files changed

+48
-38
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6281,8 +6281,21 @@ SwitchLookupTable::SwitchLookupTable(
62816281
uint64_t Idx = (CaseVal->getValue() - Offset->getValue()).getLimitedValue();
62826282
TableContents[Idx] = CaseRes;
62836283

6284-
if (CaseRes != SingleValue)
6285-
SingleValue = nullptr;
6284+
if (SingleValue && CaseRes != SingleValue) {
6285+
if (isa<UndefValue>(SingleValue)) {
6286+
// All of the switch cases until now have returned undef/poison.
6287+
// If this case returns a defined value, ignore the previous
6288+
// undefs/poisons and use this case's result as the single constant
6289+
// value.
6290+
// If this case returns poison, but all of the previous cases have
6291+
// returned undef, promote the single constant value from undef to
6292+
// poison.
6293+
if (!isa<UndefValue>(CaseRes) ||
6294+
(isa<PoisonValue>(CaseRes) && !isa<PoisonValue>(SingleValue)))
6295+
SingleValue = CaseRes;
6296+
} else if (!isa<UndefValue>(CaseRes))
6297+
SingleValue = nullptr;
6298+
}
62866299
}
62876300

62886301
// Fill in any holes in the table with the default result.
@@ -6295,7 +6308,10 @@ SwitchLookupTable::SwitchLookupTable(
62956308
TableContents[I] = DefaultValue;
62966309
}
62976310

6298-
if (DefaultValue != SingleValue)
6311+
// If the default value is undef, all the holes are undef.
6312+
bool DefaultValueIsUndef = isa<UndefValue>(DefaultValue);
6313+
6314+
if (DefaultValue != SingleValue && !DefaultValueIsUndef)
62996315
SingleValue = nullptr;
63006316
}
63016317

@@ -6319,6 +6335,16 @@ SwitchLookupTable::SwitchLookupTable(
63196335
// Check if there is the same distance between two consecutive values.
63206336
for (uint64_t I = 0; I < TableSize; ++I) {
63216337
ConstantInt *ConstVal = dyn_cast<ConstantInt>(TableContents[I]);
6338+
6339+
if (!ConstVal && TableContents[I] == DefaultValue) {
6340+
// This is an undef, but is also (probably) a lookup table hole. To
6341+
// prevent any regressions from before we switched to using poison as
6342+
// the default value, holes will fall back to using the first value.
6343+
// This can be removed once we add proper handling for undefs in lookup
6344+
// tables.
6345+
ConstVal = dyn_cast<ConstantInt>(Values[0].second);
6346+
}
6347+
63226348
if (!ConstVal) {
63236349
// This is an undef. We could deal with it, but undefs in lookup tables
63246350
// are very seldom. It's probably not worth the additional complexity.
@@ -6752,16 +6778,16 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
67526778

67536779
// If the table has holes but the default destination doesn't produce any
67546780
// constant results, the lookup table entries corresponding to the holes will
6755-
// contain undefined values.
6756-
bool AllHolesAreUndefined = TableHasHoles && !HasDefaultResults;
6781+
// contain poison.
6782+
bool AllHolesArePoison = TableHasHoles && !HasDefaultResults;
67576783

67586784
// If the default destination doesn't produce a constant result but is still
67596785
// reachable, and the lookup table has holes, we need to use a mask to
67606786
// determine if the current index should load from the lookup table or jump
67616787
// to the default case.
67626788
// The mask is unnecessary if the table has holes but the default destination
67636789
// is unreachable, as in that case the holes must also be unreachable.
6764-
bool NeedMask = AllHolesAreUndefined && DefaultIsReachable;
6790+
bool NeedMask = AllHolesArePoison && DefaultIsReachable;
67656791
if (NeedMask) {
67666792
// As an extra penalty for the validity test we require more cases.
67676793
if (SI->getNumCases() < 4) // FIXME: Find best threshold value (benchmark).
@@ -6906,9 +6932,11 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
69066932
for (PHINode *PHI : PHIs) {
69076933
const ResultListTy &ResultList = ResultLists[PHI];
69086934

6935+
Type *ResultType = ResultList.begin()->second->getType();
6936+
69096937
// Use any value to fill the lookup table holes.
69106938
Constant *DV =
6911-
AllHolesAreUndefined ? ResultLists[PHI][0].second : DefaultResults[PHI];
6939+
AllHolesArePoison ? PoisonValue::get(ResultType) : DefaultResults[PHI];
69126940
StringRef FuncName = Fn->getName();
69136941
SwitchLookupTable Table(Mod, TableSize, TableIndexOffset, ResultList, DV,
69146942
DL, FuncName);

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

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,12 @@ 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.linearmap_hole_unreachable_default = private unnamed_addr constant [5 x i32] [i32 1, i32 poison, i32 5, i32 7, i32 9], align 4
4943
;.
5044
define i32 @f(i32 %c) {
5145
; CHECK-LABEL: @f(
@@ -2187,9 +2181,7 @@ return:
21872181
define i32 @constant_hole_unreachable_default_firstundef(i32 %x) {
21882182
; CHECK-LABEL: @constant_hole_unreachable_default_firstundef(
21892183
; CHECK-NEXT: entry:
2190-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.constant_hole_unreachable_default_firstundef, i32 0, i32 [[X:%.*]]
2191-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2192-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2184+
; CHECK-NEXT: ret i32 1
21932185
;
21942186
entry:
21952187
switch i32 %x, label %sw.default [
@@ -2213,9 +2205,7 @@ return:
22132205
define i32 @constant_hole_unreachable_default_lastundef(i32 %x) {
22142206
; CHECK-LABEL: @constant_hole_unreachable_default_lastundef(
22152207
; CHECK-NEXT: entry:
2216-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.constant_hole_unreachable_default_lastundef, i32 0, i32 [[X:%.*]]
2217-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2218-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2208+
; CHECK-NEXT: ret i32 1
22192209
;
22202210
entry:
22212211
switch i32 %x, label %sw.default [
@@ -2239,9 +2229,7 @@ return:
22392229
define i32 @constant_hole_unreachable_default_firstpoison(i32 %x) {
22402230
; CHECK-LABEL: @constant_hole_unreachable_default_firstpoison(
22412231
; CHECK-NEXT: entry:
2242-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.constant_hole_unreachable_default_firstpoison, i32 0, i32 [[X:%.*]]
2243-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2244-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2232+
; CHECK-NEXT: ret i32 1
22452233
;
22462234
entry:
22472235
switch i32 %x, label %sw.default [
@@ -2265,9 +2253,7 @@ return:
22652253
define i32 @constant_hole_unreachable_default_lastpoison(i32 %x) {
22662254
; CHECK-LABEL: @constant_hole_unreachable_default_lastpoison(
22672255
; CHECK-NEXT: entry:
2268-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.constant_hole_unreachable_default_lastpoison, i32 0, i32 [[X:%.*]]
2269-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2270-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2256+
; CHECK-NEXT: ret i32 1
22712257
;
22722258
entry:
22732259
switch i32 %x, label %sw.default [
@@ -2289,9 +2275,7 @@ return:
22892275
define i32 @constant_hole_unreachable_default_undef_poison(i32 %x) {
22902276
; CHECK-LABEL: @constant_hole_unreachable_default_undef_poison(
22912277
; CHECK-NEXT: entry:
2292-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.constant_hole_unreachable_default_undef_poison, i32 0, i32 [[X:%.*]]
2293-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2294-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2278+
; CHECK-NEXT: ret i32 poison
22952279
;
22962280
entry:
22972281
switch i32 %x, label %sw.default [
@@ -2313,9 +2297,7 @@ return:
23132297
define i32 @constant_hole_unreachable_default_poison_undef(i32 %x) {
23142298
; CHECK-LABEL: @constant_hole_unreachable_default_poison_undef(
23152299
; CHECK-NEXT: entry:
2316-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.constant_hole_unreachable_default_poison_undef, i32 0, i32 [[X:%.*]]
2317-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2318-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2300+
; CHECK-NEXT: ret i32 poison
23192301
;
23202302
entry:
23212303
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)