@@ -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(
@@ -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