Skip to content

Commit aeed6d1

Browse files
committed
[SimplifyCFG] Lookup table test cases
1 parent f8d2704 commit aeed6d1

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(
@@ -2184,3 +2191,234 @@ return: ; preds = %sw.default, %entry,
21842191
%retval.0 = phi { i8, i8 } [ undef, %entry ], [ undef, %entry ], [ undef, %entry ], [ %1, %sw.default ]
21852192
ret { i8, i8 } %retval.0
21862193
}
2194+
2195+
; The switch has a hole which falls through to an unreachable default case, but it can still be optimized into a constant load because
2196+
; the poison value used for the hole is ignored.
2197+
define i32 @constant_hole_unreachable_default(i32 %x) {
2198+
; CHECK-LABEL: @constant_hole_unreachable_default(
2199+
; CHECK-NEXT: entry:
2200+
; CHECK-NEXT: ret i32 1
2201+
;
2202+
entry:
2203+
switch i32 %x, label %sw.default [
2204+
i32 0, label %bb0
2205+
i32 2, label %bb0
2206+
i32 3, label %bb0
2207+
i32 4, label %bb0
2208+
]
2209+
2210+
sw.default: unreachable
2211+
bb0: br label %return
2212+
2213+
return:
2214+
%res = phi i32 [ 1, %bb0 ]
2215+
ret i32 %res
2216+
}
2217+
2218+
; The switch has a hole which falls through to an unreachable default case and the first case explicitly returns undef, but it can still
2219+
; be optimized into a constant load because the undef values are ignored.
2220+
define i32 @constant_hole_unreachable_default_firstundef(i32 %x) {
2221+
; CHECK-LABEL: @constant_hole_unreachable_default_firstundef(
2222+
; 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]]
2226+
;
2227+
entry:
2228+
switch i32 %x, label %sw.default [
2229+
i32 0, label %bb.undef
2230+
i32 2, label %bb0
2231+
i32 3, label %bb0
2232+
i32 4, label %bb0
2233+
]
2234+
2235+
sw.default: unreachable
2236+
bb.undef: br label %return
2237+
bb0: br label %return
2238+
2239+
return:
2240+
%res = phi i32 [ undef, %bb.undef ], [ 1, %bb0 ]
2241+
ret i32 %res
2242+
}
2243+
2244+
; The switch has a hole which falls through to an unreachable default case and the first case explicitly returns undef, but it can still
2245+
; be optimized into a constant load because the undef values are ignored.
2246+
define i32 @constant_hole_unreachable_default_lastundef(i32 %x) {
2247+
; CHECK-LABEL: @constant_hole_unreachable_default_lastundef(
2248+
; 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]]
2252+
;
2253+
entry:
2254+
switch i32 %x, label %sw.default [
2255+
i32 0, label %bb0
2256+
i32 2, label %bb0
2257+
i32 3, label %bb0
2258+
i32 4, label %bb.undef
2259+
]
2260+
2261+
sw.default: unreachable
2262+
bb.undef: br label %return
2263+
bb0: br label %return
2264+
2265+
return:
2266+
%res = phi i32 [ undef, %bb.undef ], [ 1, %bb0 ]
2267+
ret i32 %res
2268+
}
2269+
2270+
; The switch has a hole which falls through to an unreachable default case and the first case explicitly returns poison, but it can still
2271+
; be optimized into a constant load because the poison values are ignored.
2272+
define i32 @constant_hole_unreachable_default_firstpoison(i32 %x) {
2273+
; CHECK-LABEL: @constant_hole_unreachable_default_firstpoison(
2274+
; 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]]
2278+
;
2279+
entry:
2280+
switch i32 %x, label %sw.default [
2281+
i32 0, label %bb.poison
2282+
i32 2, label %bb0
2283+
i32 3, label %bb0
2284+
i32 4, label %bb0
2285+
]
2286+
2287+
sw.default: unreachable
2288+
bb.poison: br label %return
2289+
bb0: br label %return
2290+
2291+
return:
2292+
%res = phi i32 [ poison, %bb.poison ], [ 1, %bb0 ]
2293+
ret i32 %res
2294+
}
2295+
2296+
; The switch has a hole which falls through to an unreachable default case and the first case explicitly returns poison, but it can still
2297+
; be optimized into a constant load because the poison values are ignored.
2298+
define i32 @constant_hole_unreachable_default_lastpoison(i32 %x) {
2299+
; CHECK-LABEL: @constant_hole_unreachable_default_lastpoison(
2300+
; 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]]
2304+
;
2305+
entry:
2306+
switch i32 %x, label %sw.default [
2307+
i32 0, label %bb0
2308+
i32 2, label %bb0
2309+
i32 3, label %bb0
2310+
i32 4, label %bb.poison
2311+
]
2312+
2313+
sw.default: unreachable
2314+
bb.poison: br label %return
2315+
bb0: br label %return
2316+
2317+
return:
2318+
%res = phi i32 [ poison, %bb.poison ], [ 1, %bb0 ]
2319+
ret i32 %res
2320+
}
2321+
2322+
define i32 @constant_hole_unreachable_default_undef_poison(i32 %x) {
2323+
; CHECK-LABEL: @constant_hole_unreachable_default_undef_poison(
2324+
; 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]]
2328+
;
2329+
entry:
2330+
switch i32 %x, label %sw.default [
2331+
i32 0, label %bb.undef
2332+
i32 2, label %bb.poison
2333+
i32 3, label %bb.poison
2334+
i32 4, label %bb.poison
2335+
]
2336+
2337+
sw.default: unreachable
2338+
bb.undef: br label %return
2339+
bb.poison: br label %return
2340+
2341+
return:
2342+
%res = phi i32 [ undef, %bb.undef ], [ poison, %bb.poison ]
2343+
ret i32 %res
2344+
}
2345+
2346+
define i32 @constant_hole_unreachable_default_poison_undef(i32 %x) {
2347+
; CHECK-LABEL: @constant_hole_unreachable_default_poison_undef(
2348+
; 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]]
2352+
;
2353+
entry:
2354+
switch i32 %x, label %sw.default [
2355+
i32 0, label %bb.poison
2356+
i32 2, label %bb.poison
2357+
i32 3, label %bb.poison
2358+
i32 4, label %bb.undef
2359+
]
2360+
2361+
sw.default: unreachable
2362+
bb.undef: br label %return
2363+
bb.poison: br label %return
2364+
2365+
return:
2366+
%res = phi i32 [ undef, %bb.undef ], [ poison, %bb.poison ]
2367+
ret i32 %res
2368+
}
2369+
2370+
; 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.
2371+
; TODO: We should add support for this, at least in certain cases.
2372+
define i32 @linearmap_hole_unreachable_default(i32 %x) {
2373+
; CHECK-LABEL: @linearmap_hole_unreachable_default(
2374+
; CHECK-NEXT: entry:
2375+
; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [5 x i32], ptr @switch.table.linearmap_hole_unreachable_default, i32 0, i32 [[X:%.*]]
2376+
; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i32, ptr [[SWITCH_GEP]], align 4
2377+
; CHECK-NEXT: ret i32 [[SWITCH_LOAD]]
2378+
;
2379+
entry:
2380+
switch i32 %x, label %sw.default [
2381+
i32 0, label %bb0
2382+
i32 2, label %bb2
2383+
i32 3, label %bb3
2384+
i32 4, label %bb4
2385+
]
2386+
2387+
sw.default: unreachable
2388+
bb0: br label %return
2389+
bb2: br label %return
2390+
bb3: br label %return
2391+
bb4: br label %return
2392+
2393+
return:
2394+
%res = phi i32 [ 1, %bb0 ], [ 5, %bb2 ], [ 7, %bb3 ], [ 9, %bb4 ]
2395+
ret i32 %res
2396+
}
2397+
2398+
; The switch has a hole which falls through to an unreachable default case, but it can still be optimized into a bitmask extraction because
2399+
; the poison value used for the hole is simply replaced with zero.
2400+
define i1 @bitset_hole_unreachable_default(i32 %x) {
2401+
; CHECK-LABEL: @bitset_hole_unreachable_default(
2402+
; CHECK-NEXT: entry:
2403+
; CHECK-NEXT: [[SWITCH_CAST:%.*]] = trunc i32 [[X:%.*]] to i5
2404+
; CHECK-NEXT: [[SWITCH_SHIFTAMT:%.*]] = mul nuw nsw i5 [[SWITCH_CAST]], 1
2405+
; CHECK-NEXT: [[SWITCH_DOWNSHIFT:%.*]] = lshr i5 8, [[SWITCH_SHIFTAMT]]
2406+
; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = trunc i5 [[SWITCH_DOWNSHIFT]] to i1
2407+
; CHECK-NEXT: ret i1 [[SWITCH_MASKED]]
2408+
;
2409+
entry:
2410+
switch i32 %x, label %sw.default [
2411+
i32 0, label %bb0
2412+
i32 2, label %bb0
2413+
i32 3, label %bb1
2414+
i32 4, label %bb0
2415+
]
2416+
2417+
sw.default: unreachable
2418+
bb0: br label %return
2419+
bb1: br label %return
2420+
2421+
return:
2422+
%res = phi i1 [ 0, %bb0 ], [ 1, %bb1 ]
2423+
ret i1 %res
2424+
}

0 commit comments

Comments
 (0)