@@ -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;.
4350define 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, yet it cannot be optimized into a simple
2219+ ; constant because we actually treat undef as a unique value rather than ignoring it.
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 last case explicitly returns undef, yet it cannot be optimized into a simple
2245+ ; constant because we actually treat undef as a unique value rather than ignoring it.
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