Skip to content

Commit 95f0f20

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

File tree

3 files changed

+41
-38
lines changed

3 files changed

+41
-38
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 28 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

@@ -6322,6 +6338,9 @@ SwitchLookupTable::SwitchLookupTable(
63226338
if (!ConstVal) {
63236339
// This is an undef. We could deal with it, but undefs in lookup tables
63246340
// are very seldom. It's probably not worth the additional complexity.
6341+
// TODO: In switches with holes and an unreachable default branch, this
6342+
// will actually occur every time, as the holes will be filled
6343+
// with poison.
63256344
LinearMappingPossible = false;
63266345
break;
63276346
}
@@ -6752,16 +6771,16 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
67526771

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

67586777
// If the default destination doesn't produce a constant result but is still
67596778
// reachable, and the lookup table has holes, we need to use a mask to
67606779
// determine if the current index should load from the lookup table or jump
67616780
// to the default case.
67626781
// The mask is unnecessary if the table has holes but the default destination
67636782
// is unreachable, as in that case the holes must also be unreachable.
6764-
bool NeedMask = AllHolesAreUndefined && DefaultIsReachable;
6783+
bool NeedMask = AllHolesArePoison && DefaultIsReachable;
67656784
if (NeedMask) {
67666785
// As an extra penalty for the validity test we require more cases.
67676786
if (SI->getNumCases() < 4) // FIXME: Find best threshold value (benchmark).
@@ -6906,9 +6925,11 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
69066925
for (PHINode *PHI : PHIs) {
69076926
const ResultListTy &ResultList = ResultLists[PHI];
69086927

6928+
Type *ResultType = ResultList.begin()->second->getType();
6929+
69096930
// Use any value to fill the lookup table holes.
69106931
Constant *DV =
6911-
AllHolesAreUndefined ? ResultLists[PHI][0].second : DefaultResults[PHI];
6932+
AllHolesArePoison ? PoisonValue::get(ResultType) : DefaultResults[PHI];
69126933
StringRef FuncName = Fn->getName();
69136934
SwitchLookupTable Table(Mod, TableSize, TableIndexOffset, ResultList, DV,
69146935
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)