Skip to content

Commit d6098d6

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

File tree

3 files changed

+53
-38
lines changed

3 files changed

+53
-38
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6281,8 +6281,26 @@ 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+
bool IgnorePreviousUndef = !isa<UndefValue>(CaseRes);
6291+
6292+
// If this case returns undef, but all of the previous cases have
6293+
// returned poison, promote the single constant value from poison to
6294+
// undef.
6295+
bool PromotePoisonToUndef = isa<UndefValue>(CaseRes) &&
6296+
!isa<PoisonValue>(CaseRes) &&
6297+
isa<PoisonValue>(SingleValue);
6298+
6299+
if (IgnorePreviousUndef || PromotePoisonToUndef)
6300+
SingleValue = CaseRes;
6301+
} else if (!isa<UndefValue>(CaseRes))
6302+
SingleValue = nullptr;
6303+
}
62866304
}
62876305

62886306
// Fill in any holes in the table with the default result.
@@ -6295,7 +6313,10 @@ SwitchLookupTable::SwitchLookupTable(
62956313
TableContents[I] = DefaultValue;
62966314
}
62976315

6298-
if (DefaultValue != SingleValue)
6316+
// If the default value is undef, all the holes are undef.
6317+
bool DefaultValueIsUndef = isa<UndefValue>(DefaultValue);
6318+
6319+
if (DefaultValue != SingleValue && !DefaultValueIsUndef)
62996320
SingleValue = nullptr;
63006321
}
63016322

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

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

67586789
// If the default destination doesn't produce a constant result but is still
67596790
// reachable, and the lookup table has holes, we need to use a mask to
67606791
// determine if the current index should load from the lookup table or jump
67616792
// to the default case.
67626793
// The mask is unnecessary if the table has holes but the default destination
67636794
// is unreachable, as in that case the holes must also be unreachable.
6764-
bool NeedMask = AllHolesAreUndefined && DefaultIsReachable;
6795+
bool NeedMask = AllHolesArePoison && DefaultIsReachable;
67656796
if (NeedMask) {
67666797
// As an extra penalty for the validity test we require more cases.
67676798
if (SI->getNumCases() < 4) // FIXME: Find best threshold value (benchmark).
@@ -6906,9 +6937,11 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
69066937
for (PHINode *PHI : PHIs) {
69076938
const ResultListTy &ResultList = ResultLists[PHI];
69086939

6940+
Type *ResultType = ResultList.begin()->second->getType();
6941+
69096942
// Use any value to fill the lookup table holes.
69106943
Constant *DV =
6911-
AllHolesAreUndefined ? ResultLists[PHI][0].second : DefaultResults[PHI];
6944+
AllHolesArePoison ? PoisonValue::get(ResultType) : DefaultResults[PHI];
69126945
StringRef FuncName = Fn->getName();
69136946
SwitchLookupTable Table(Mod, TableSize, TableIndexOffset, ResultList, DV,
69146947
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 undef
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 undef
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)