Skip to content

Commit 4858b9c

Browse files
committed
[SimplifyCFG] Replace unreachable switch lookup table holes with poison
1 parent aeed6d1 commit 4858b9c

File tree

3 files changed

+53
-40
lines changed

3 files changed

+53
-40
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6531,8 +6531,26 @@ 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<UndefValue>(SingleValue)) {
6536+
// All of the switch cases until now have returned undef/poison.
6537+
// If this case returns a defined value, ignore the previous
6538+
// undefs/poisons and use this case's result as the single constant
6539+
// value.
6540+
bool IgnorePreviousUndef = !isa<UndefValue>(CaseRes);
6541+
6542+
// If this case returns undef, but all of the previous cases have
6543+
// returned poison, promote the single constant value from poison to
6544+
// undef.
6545+
bool PromotePoisonToUndef = isa<UndefValue>(CaseRes) &&
6546+
!isa<PoisonValue>(CaseRes) &&
6547+
isa<PoisonValue>(SingleValue);
6548+
6549+
if (IgnorePreviousUndef || PromotePoisonToUndef)
6550+
SingleValue = CaseRes;
6551+
} else if (!isa<UndefValue>(CaseRes))
6552+
SingleValue = nullptr;
6553+
}
65366554
}
65376555

65386556
// Fill in any holes in the table with the default result.
@@ -6545,7 +6563,10 @@ SwitchLookupTable::SwitchLookupTable(
65456563
TableContents[I] = DefaultValue;
65466564
}
65476565

6548-
if (DefaultValue != SingleValue)
6566+
// If the default value is undef, all the holes are undef.
6567+
bool DefaultValueIsUndef = isa<UndefValue>(DefaultValue);
6568+
6569+
if (DefaultValue != SingleValue && !DefaultValueIsUndef)
65496570
SingleValue = nullptr;
65506571
}
65516572

@@ -6569,6 +6590,16 @@ SwitchLookupTable::SwitchLookupTable(
65696590
// Check if there is the same distance between two consecutive values.
65706591
for (uint64_t I = 0; I < TableSize; ++I) {
65716592
ConstantInt *ConstVal = dyn_cast<ConstantInt>(TableContents[I]);
6593+
6594+
if (!ConstVal && TableContents[I] == DefaultValue) {
6595+
// This is an undef, but is also (probably) a lookup table hole. To
6596+
// prevent any regressions from before we switched to using poison as
6597+
// the default value, holes will fall back to using the first value.
6598+
// This can be removed once we add proper handling for undefs in lookup
6599+
// tables.
6600+
ConstVal = dyn_cast<ConstantInt>(Values[0].second);
6601+
}
6602+
65726603
if (!ConstVal) {
65736604
// This is an undef. We could deal with it, but undefs in lookup tables
65746605
// are very seldom. It's probably not worth the additional complexity.
@@ -7003,16 +7034,16 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
70037034

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

70097040
// If the default destination doesn't produce a constant result but is still
70107041
// reachable, and the lookup table has holes, we need to use a mask to
70117042
// determine if the current index should load from the lookup table or jump
70127043
// to the default case.
70137044
// The mask is unnecessary if the table has holes but the default destination
70147045
// is unreachable, as in that case the holes must also be unreachable.
7015-
bool NeedMask = AllHolesAreUndefined && DefaultIsReachable;
7046+
bool NeedMask = AllHolesArePoison && DefaultIsReachable;
70167047
if (NeedMask) {
70177048
// As an extra penalty for the validity test we require more cases.
70187049
if (SI->getNumCases() < 4) // FIXME: Find best threshold value (benchmark).
@@ -7157,9 +7188,11 @@ static bool switchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder,
71577188
for (PHINode *PHI : PHIs) {
71587189
const ResultListTy &ResultList = ResultLists[PHI];
71597190

7191+
Type *ResultType = ResultList.begin()->second->getType();
7192+
71607193
// Use any value to fill the lookup table holes.
71617194
Constant *DV =
7162-
AllHolesAreUndefined ? ResultLists[PHI][0].second : DefaultResults[PHI];
7195+
AllHolesArePoison ? PoisonValue::get(ResultType) : DefaultResults[PHI];
71637196
StringRef FuncName = Fn->getName();
71647197
SwitchLookupTable Table(Mod, TableSize, TableIndexOffset, ResultList, DV,
71657198
DL, FuncName);

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

Lines changed: 10 additions & 30 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(
@@ -331,8 +325,6 @@ define i32 @overflow(i32 %type) {
331325
; CHECK-NEXT: br label [[IF_END]]
332326
; CHECK: sw.bb3:
333327
; CHECK-NEXT: br label [[IF_END]]
334-
; CHECK: sw.default:
335-
; CHECK-NEXT: br label [[IF_END]]
336328
; CHECK: if.end:
337329
; CHECK-NEXT: [[DIRENT_TYPE_0:%.*]] = phi i32 [ 3, [[SW_DEFAULT]] ], [ 6, [[SW_BB3]] ], [ 5, [[SW_BB2]] ], [ 0, [[ENTRY:%.*]] ]
338330
; CHECK-NEXT: ret i32 [[DIRENT_TYPE_0]]
@@ -2220,9 +2212,7 @@ return:
22202212
define i32 @constant_hole_unreachable_default_firstundef(i32 %x) {
22212213
; CHECK-LABEL: @constant_hole_unreachable_default_firstundef(
22222214
; CHECK-NEXT: entry:
2223-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.constant_hole_unreachable_default_firstundef, i32 0, i32 [[X:%.*]]
2224-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2225-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2215+
; CHECK-NEXT: ret i32 1
22262216
;
22272217
entry:
22282218
switch i32 %x, label %sw.default [
@@ -2246,9 +2236,7 @@ return:
22462236
define i32 @constant_hole_unreachable_default_lastundef(i32 %x) {
22472237
; CHECK-LABEL: @constant_hole_unreachable_default_lastundef(
22482238
; CHECK-NEXT: entry:
2249-
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.constant_hole_unreachable_default_lastundef, i32 0, i32 [[X:%.*]]
2250-
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2251-
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2239+
; CHECK-NEXT: ret i32 1
22522240
;
22532241
entry:
22542242
switch i32 %x, label %sw.default [
@@ -2272,9 +2260,7 @@ return:
22722260
define i32 @constant_hole_unreachable_default_firstpoison(i32 %x) {
22732261
; CHECK-LABEL: @constant_hole_unreachable_default_firstpoison(
22742262
; 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]]
2263+
; CHECK-NEXT: ret i32 1
22782264
;
22792265
entry:
22802266
switch i32 %x, label %sw.default [
@@ -2298,9 +2284,7 @@ return:
22982284
define i32 @constant_hole_unreachable_default_lastpoison(i32 %x) {
22992285
; CHECK-LABEL: @constant_hole_unreachable_default_lastpoison(
23002286
; 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]]
2287+
; CHECK-NEXT: ret i32 1
23042288
;
23052289
entry:
23062290
switch i32 %x, label %sw.default [
@@ -2322,9 +2306,7 @@ return:
23222306
define i32 @constant_hole_unreachable_default_undef_poison(i32 %x) {
23232307
; CHECK-LABEL: @constant_hole_unreachable_default_undef_poison(
23242308
; 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]]
2309+
; CHECK-NEXT: ret i32 undef
23282310
;
23292311
entry:
23302312
switch i32 %x, label %sw.default [
@@ -2346,9 +2328,7 @@ return:
23462328
define i32 @constant_hole_unreachable_default_poison_undef(i32 %x) {
23472329
; CHECK-LABEL: @constant_hole_unreachable_default_poison_undef(
23482330
; 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]]
2331+
; CHECK-NEXT: ret i32 undef
23522332
;
23532333
entry:
23542334
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)