Skip to content

Commit 4e6e6d4

Browse files
committed
[SimplifyCFG] Lookup table test cases
1 parent fe1301b commit 4e6e6d4

File tree

1 file changed

+238
-0
lines changed

1 file changed

+238
-0
lines changed

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

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ target triple = "x86_64-unknown-linux-gnu"
3939
; 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
4040
; CHECK: @switch.table.signed_overflow1 = private unnamed_addr constant [4 x i32] [i32 3333, i32 4444, i32 1111, i32 2222], align 4
4141
; 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
4249
;.
4350
define i32 @f(i32 %c) {
4451
; CHECK-LABEL: @f(
@@ -2151,3 +2158,234 @@ return: ; preds = %sw.default, %entry,
21512158
%retval.0 = phi { i8, i8 } [ undef, %entry ], [ undef, %entry ], [ undef, %entry ], [ %1, %sw.default ]
21522159
ret { i8, i8 } %retval.0
21532160
}
2161+
2162+
; The switch has a hole which falls through to an unreachable default case, but it can still be optimized into a constant load because
2163+
; the poison value used for the hole is ignored.
2164+
define i32 @constant_hole_unreachable_default(i32 %x) {
2165+
; CHECK-LABEL: @constant_hole_unreachable_default(
2166+
; CHECK-NEXT: entry:
2167+
; CHECK-NEXT: ret i32 1
2168+
;
2169+
entry:
2170+
switch i32 %x, label %sw.default [
2171+
i32 0, label %bb0
2172+
i32 2, label %bb0
2173+
i32 3, label %bb0
2174+
i32 4, label %bb0
2175+
]
2176+
2177+
sw.default: unreachable
2178+
bb0: br label %return
2179+
2180+
return:
2181+
%res = phi i32 [ 1, %bb0 ]
2182+
ret i32 %res
2183+
}
2184+
2185+
; The switch has a hole which falls through to an unreachable default case and the first case explicitly returns undef, but it can still
2186+
; be optimized into a constant load because the undef values are ignored.
2187+
define i32 @constant_hole_unreachable_default_firstundef(i32 %x) {
2188+
; CHECK-LABEL: @constant_hole_unreachable_default_firstundef(
2189+
; 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]]
2193+
;
2194+
entry:
2195+
switch i32 %x, label %sw.default [
2196+
i32 0, label %bb.undef
2197+
i32 2, label %bb0
2198+
i32 3, label %bb0
2199+
i32 4, label %bb0
2200+
]
2201+
2202+
sw.default: unreachable
2203+
bb.undef: br label %return
2204+
bb0: br label %return
2205+
2206+
return:
2207+
%res = phi i32 [ undef, %bb.undef ], [ 1, %bb0 ]
2208+
ret i32 %res
2209+
}
2210+
2211+
; The switch has a hole which falls through to an unreachable default case and the first case explicitly returns undef, but it can still
2212+
; be optimized into a constant load because the undef values are ignored.
2213+
define i32 @constant_hole_unreachable_default_lastundef(i32 %x) {
2214+
; CHECK-LABEL: @constant_hole_unreachable_default_lastundef(
2215+
; 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]]
2219+
;
2220+
entry:
2221+
switch i32 %x, label %sw.default [
2222+
i32 0, label %bb0
2223+
i32 2, label %bb0
2224+
i32 3, label %bb0
2225+
i32 4, label %bb.undef
2226+
]
2227+
2228+
sw.default: unreachable
2229+
bb.undef: br label %return
2230+
bb0: br label %return
2231+
2232+
return:
2233+
%res = phi i32 [ undef, %bb.undef ], [ 1, %bb0 ]
2234+
ret i32 %res
2235+
}
2236+
2237+
; The switch has a hole which falls through to an unreachable default case and the first case explicitly returns poison, but it can still
2238+
; be optimized into a constant load because the poison values are ignored.
2239+
define i32 @constant_hole_unreachable_default_firstpoison(i32 %x) {
2240+
; CHECK-LABEL: @constant_hole_unreachable_default_firstpoison(
2241+
; 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]]
2245+
;
2246+
entry:
2247+
switch i32 %x, label %sw.default [
2248+
i32 0, label %bb.poison
2249+
i32 2, label %bb0
2250+
i32 3, label %bb0
2251+
i32 4, label %bb0
2252+
]
2253+
2254+
sw.default: unreachable
2255+
bb.poison: br label %return
2256+
bb0: br label %return
2257+
2258+
return:
2259+
%res = phi i32 [ poison, %bb.poison ], [ 1, %bb0 ]
2260+
ret i32 %res
2261+
}
2262+
2263+
; The switch has a hole which falls through to an unreachable default case and the first case explicitly returns poison, but it can still
2264+
; be optimized into a constant load because the poison values are ignored.
2265+
define i32 @constant_hole_unreachable_default_lastpoison(i32 %x) {
2266+
; CHECK-LABEL: @constant_hole_unreachable_default_lastpoison(
2267+
; 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]]
2271+
;
2272+
entry:
2273+
switch i32 %x, label %sw.default [
2274+
i32 0, label %bb0
2275+
i32 2, label %bb0
2276+
i32 3, label %bb0
2277+
i32 4, label %bb.poison
2278+
]
2279+
2280+
sw.default: unreachable
2281+
bb.poison: br label %return
2282+
bb0: br label %return
2283+
2284+
return:
2285+
%res = phi i32 [ poison, %bb.poison ], [ 1, %bb0 ]
2286+
ret i32 %res
2287+
}
2288+
2289+
define i32 @constant_hole_unreachable_default_undef_poison(i32 %x) {
2290+
; CHECK-LABEL: @constant_hole_unreachable_default_undef_poison(
2291+
; 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]]
2295+
;
2296+
entry:
2297+
switch i32 %x, label %sw.default [
2298+
i32 0, label %bb.undef
2299+
i32 2, label %bb.poison
2300+
i32 3, label %bb.poison
2301+
i32 4, label %bb.poison
2302+
]
2303+
2304+
sw.default: unreachable
2305+
bb.undef: br label %return
2306+
bb.poison: br label %return
2307+
2308+
return:
2309+
%res = phi i32 [ undef, %bb.undef ], [ poison, %bb.poison ]
2310+
ret i32 %res
2311+
}
2312+
2313+
define i32 @constant_hole_unreachable_default_poison_undef(i32 %x) {
2314+
; CHECK-LABEL: @constant_hole_unreachable_default_poison_undef(
2315+
; 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]]
2319+
;
2320+
entry:
2321+
switch i32 %x, label %sw.default [
2322+
i32 0, label %bb.poison
2323+
i32 2, label %bb.poison
2324+
i32 3, label %bb.poison
2325+
i32 4, label %bb.undef
2326+
]
2327+
2328+
sw.default: unreachable
2329+
bb.undef: br label %return
2330+
bb.poison: br label %return
2331+
2332+
return:
2333+
%res = phi i32 [ undef, %bb.undef ], [ poison, %bb.poison ]
2334+
ret i32 %res
2335+
}
2336+
2337+
; The switch has a hole which falls through to an unreachable default case, which prevents it from being optimized into a linear mapping 2*x+1.
2338+
; TODO: We should add support for this, at least in certain cases.
2339+
define i32 @linearmap_hole_unreachable_default(i32 %x) {
2340+
; CHECK-LABEL: @linearmap_hole_unreachable_default(
2341+
; CHECK-NEXT: entry:
2342+
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.linearmap_hole_unreachable_default, i32 0, i32 [[X:%.*]]
2343+
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2344+
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2345+
;
2346+
entry:
2347+
switch i32 %x, label %sw.default [
2348+
i32 0, label %bb0
2349+
i32 2, label %bb2
2350+
i32 3, label %bb3
2351+
i32 4, label %bb4
2352+
]
2353+
2354+
sw.default: unreachable
2355+
bb0: br label %return
2356+
bb2: br label %return
2357+
bb3: br label %return
2358+
bb4: br label %return
2359+
2360+
return:
2361+
%res = phi i32 [ 1, %bb0 ], [ 5, %bb2 ], [ 7, %bb3 ], [ 9, %bb4 ]
2362+
ret i32 %res
2363+
}
2364+
2365+
; The switch has a hole which falls through to an unreachable default case, but it can still be optimized into a bitmask extraction because
2366+
; the poison value used for the hole is simply replaced with zero.
2367+
define i1 @bitset_hole_unreachable_default(i32 %x) {
2368+
; CHECK-LABEL: @bitset_hole_unreachable_default(
2369+
; CHECK-NEXT: entry:
2370+
; CHECK-NEXT: [[SWITCH_CAST:%.*]] = trunc i32 [[X:%.*]] to i5
2371+
; CHECK-NEXT: [[SWITCH_SHIFTAMT:%.*]] = mul nuw nsw i5 [[SWITCH_CAST]], 1
2372+
; CHECK-NEXT: [[SWITCH_DOWNSHIFT:%.*]] = lshr i5 8, [[SWITCH_SHIFTAMT]]
2373+
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = trunc i5 [[SWITCH_DOWNSHIFT]] to i1
2374+
; CHECK-NEXT: ret i1 [[SWITCH_MASKED]]
2375+
;
2376+
entry:
2377+
switch i32 %x, label %sw.default [
2378+
i32 0, label %bb0
2379+
i32 2, label %bb0
2380+
i32 3, label %bb1
2381+
i32 4, label %bb0
2382+
]
2383+
2384+
sw.default: unreachable
2385+
bb0: br label %return
2386+
bb1: br label %return
2387+
2388+
return:
2389+
%res = phi i1 [ 0, %bb0 ], [ 1, %bb1 ]
2390+
ret i1 %res
2391+
}

0 commit comments

Comments
 (0)