1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -instcombine -S | FileCheck %s 3 4; Given pattern: 5; (trunc (iSrc x a>> Q) to iDst) a>> K 6; we should rewrite it as 7; (trunc (iSrc x a>> (Q+K)) to iDst) 8; iff (Q+K) is bitwidth(iSrc)-1 9; THIS FOLD DOES *NOT* REQUIRE ANY 'nuw'/`nsw` FLAGS! 10 11; Basic scalar test 12 13define i16 @t0(i32 %x, i16 %y) { 14; CHECK-LABEL: @t0( 15; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[X:%.*]], 31 16; CHECK-NEXT: [[T5:%.*]] = trunc i32 [[TMP1]] to i16 17; CHECK-NEXT: ret i16 [[T5]] 18; 19 %t0 = sub i16 32, %y 20 %t1 = zext i16 %t0 to i32 21 %t2 = ashr i32 %x, %t1 22 %t3 = trunc i32 %t2 to i16 23 %t4 = add i16 %y, -1 24 %t5 = ashr i16 %t3, %t4 25 ret i16 %t5 26} 27 28; Basic vector tests 29 30define <2 x i16> @t1_vec_splat(<2 x i32> %x, <2 x i16> %y) { 31; CHECK-LABEL: @t1_vec_splat( 32; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i32> [[X:%.*]], <i32 31, i32 31> 33; CHECK-NEXT: [[T5:%.*]] = trunc <2 x i32> [[TMP1]] to <2 x i16> 34; CHECK-NEXT: ret <2 x i16> [[T5]] 35; 36 %t0 = sub <2 x i16> <i16 32, i16 32>, %y 37 %t1 = zext <2 x i16> %t0 to <2 x i32> 38 %t2 = ashr <2 x i32> %x, %t1 39 %t3 = trunc <2 x i32> %t2 to <2 x i16> 40 %t4 = add <2 x i16> %y, <i16 -1, i16 -1> 41 %t5 = ashr <2 x i16> %t3, %t4 42 ret <2 x i16> %t5 43} 44 45define <3 x i16> @t3_vec_nonsplat_undef0(<3 x i32> %x, <3 x i16> %y) { 46; CHECK-LABEL: @t3_vec_nonsplat_undef0( 47; CHECK-NEXT: [[TMP1:%.*]] = ashr <3 x i32> [[X:%.*]], <i32 31, i32 0, i32 31> 48; CHECK-NEXT: [[T5:%.*]] = trunc <3 x i32> [[TMP1]] to <3 x i16> 49; CHECK-NEXT: ret <3 x i16> [[T5]] 50; 51 %t0 = sub <3 x i16> <i16 32, i16 undef, i16 32>, %y 52 %t1 = zext <3 x i16> %t0 to <3 x i32> 53 %t2 = ashr <3 x i32> %x, %t1 54 %t3 = trunc <3 x i32> %t2 to <3 x i16> 55 %t4 = add <3 x i16> %y, <i16 -1, i16 -1, i16 -1> 56 %t5 = ashr <3 x i16> %t3, %t4 57 ret <3 x i16> %t5 58} 59 60define <3 x i16> @t4_vec_nonsplat_undef1(<3 x i32> %x, <3 x i16> %y) { 61; CHECK-LABEL: @t4_vec_nonsplat_undef1( 62; CHECK-NEXT: [[TMP1:%.*]] = ashr <3 x i32> [[X:%.*]], <i32 31, i32 0, i32 31> 63; CHECK-NEXT: [[T5:%.*]] = trunc <3 x i32> [[TMP1]] to <3 x i16> 64; CHECK-NEXT: ret <3 x i16> [[T5]] 65; 66 %t0 = sub <3 x i16> <i16 32, i16 32, i16 32>, %y 67 %t1 = zext <3 x i16> %t0 to <3 x i32> 68 %t2 = ashr <3 x i32> %x, %t1 69 %t3 = trunc <3 x i32> %t2 to <3 x i16> 70 %t4 = add <3 x i16> %y, <i16 -1, i16 undef, i16 -1> 71 %t5 = ashr <3 x i16> %t3, %t4 72 ret <3 x i16> %t5 73} 74 75define <3 x i16> @t5_vec_nonsplat_undef1(<3 x i32> %x, <3 x i16> %y) { 76; CHECK-LABEL: @t5_vec_nonsplat_undef1( 77; CHECK-NEXT: [[TMP1:%.*]] = ashr <3 x i32> [[X:%.*]], <i32 31, i32 0, i32 31> 78; CHECK-NEXT: [[T5:%.*]] = trunc <3 x i32> [[TMP1]] to <3 x i16> 79; CHECK-NEXT: ret <3 x i16> [[T5]] 80; 81 %t0 = sub <3 x i16> <i16 32, i16 undef, i16 32>, %y 82 %t1 = zext <3 x i16> %t0 to <3 x i32> 83 %t2 = ashr <3 x i32> %x, %t1 84 %t3 = trunc <3 x i32> %t2 to <3 x i16> 85 %t4 = add <3 x i16> %y, <i16 -1, i16 undef, i16 -1> 86 %t5 = ashr <3 x i16> %t3, %t4 87 ret <3 x i16> %t5 88} 89 90; One-use tests 91 92declare void @use16(i16) 93declare void @use32(i32) 94 95define i16 @t6_extrause0(i32 %x, i16 %y) { 96; CHECK-LABEL: @t6_extrause0( 97; CHECK-NEXT: [[T0:%.*]] = sub i16 32, [[Y:%.*]] 98; CHECK-NEXT: [[T1:%.*]] = zext i16 [[T0]] to i32 99; CHECK-NEXT: [[T2:%.*]] = ashr i32 [[X:%.*]], [[T1]] 100; CHECK-NEXT: [[T3:%.*]] = trunc i32 [[T2]] to i16 101; CHECK-NEXT: call void @use16(i16 [[T3]]) 102; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[X]], 31 103; CHECK-NEXT: [[T5:%.*]] = trunc i32 [[TMP1]] to i16 104; CHECK-NEXT: ret i16 [[T5]] 105; 106 %t0 = sub i16 32, %y 107 %t1 = zext i16 %t0 to i32 108 %t2 = ashr i32 %x, %t1 109 %t3 = trunc i32 %t2 to i16 110 %t4 = add i16 %y, -1 111 call void @use16(i16 %t3) 112 %t5 = ashr i16 %t3, %t4 113 ret i16 %t5 114} 115 116define i16 @t7_extrause1(i32 %x, i16 %y) { 117; CHECK-LABEL: @t7_extrause1( 118; CHECK-NEXT: [[T4:%.*]] = add i16 [[Y:%.*]], -1 119; CHECK-NEXT: call void @use16(i16 [[T4]]) 120; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[X:%.*]], 31 121; CHECK-NEXT: [[T5:%.*]] = trunc i32 [[TMP1]] to i16 122; CHECK-NEXT: ret i16 [[T5]] 123; 124 %t0 = sub i16 32, %y 125 %t1 = zext i16 %t0 to i32 126 %t2 = ashr i32 %x, %t1 127 %t3 = trunc i32 %t2 to i16 128 %t4 = add i16 %y, -1 129 call void @use16(i16 %t4) 130 %t5 = ashr i16 %t3, %t4 131 ret i16 %t5 132} 133 134define i16 @t8_extrause2(i32 %x, i16 %y) { 135; CHECK-LABEL: @t8_extrause2( 136; CHECK-NEXT: [[T0:%.*]] = sub i16 32, [[Y:%.*]] 137; CHECK-NEXT: [[T1:%.*]] = zext i16 [[T0]] to i32 138; CHECK-NEXT: [[T2:%.*]] = ashr i32 [[X:%.*]], [[T1]] 139; CHECK-NEXT: [[T3:%.*]] = trunc i32 [[T2]] to i16 140; CHECK-NEXT: [[T4:%.*]] = add i16 [[Y]], -1 141; CHECK-NEXT: call void @use16(i16 [[T3]]) 142; CHECK-NEXT: call void @use16(i16 [[T4]]) 143; CHECK-NEXT: [[T5:%.*]] = ashr i16 [[T3]], [[T4]] 144; CHECK-NEXT: ret i16 [[T5]] 145; 146 %t0 = sub i16 32, %y 147 %t1 = zext i16 %t0 to i32 148 %t2 = ashr i32 %x, %t1 149 %t3 = trunc i32 %t2 to i16 150 %t4 = add i16 %y, -1 151 call void @use16(i16 %t3) 152 call void @use16(i16 %t4) 153 %t5 = ashr i16 %t3, %t4 154 ret i16 %t5 155} 156 157; No 'nuw'/'nsw' flags are to be propagated! 158; But we can't test that, such IR does not reach that code. 159 160; Negative tests 161 162; Can only fold if we are extracting the sign bit. 163define i16 @t9_ashr(i32 %x, i16 %y) { 164; CHECK-LABEL: @t9_ashr( 165; CHECK-NEXT: [[T0:%.*]] = sub i16 32, [[Y:%.*]] 166; CHECK-NEXT: [[T1:%.*]] = zext i16 [[T0]] to i32 167; CHECK-NEXT: [[T2:%.*]] = ashr i32 [[X:%.*]], [[T1]] 168; CHECK-NEXT: [[T3:%.*]] = trunc i32 [[T2]] to i16 169; CHECK-NEXT: [[T4:%.*]] = add i16 [[Y]], -2 170; CHECK-NEXT: [[T5:%.*]] = ashr i16 [[T3]], [[T4]] 171; CHECK-NEXT: ret i16 [[T5]] 172; 173 %t0 = sub i16 32, %y 174 %t1 = zext i16 %t0 to i32 175 %t2 = ashr i32 %x, %t1 176 %t3 = trunc i32 %t2 to i16 177 %t4 = add i16 %y, -2 178 %t5 = ashr i16 %t3, %t4 179 ret i16 %t5 180} 181 182; If we have different right-shifts, in general, we can't do anything with it. 183define i16 @n10_lshr_ashr(i32 %x, i16 %y) { 184; CHECK-LABEL: @n10_lshr_ashr( 185; CHECK-NEXT: [[T0:%.*]] = sub i16 32, [[Y:%.*]] 186; CHECK-NEXT: [[T1:%.*]] = zext i16 [[T0]] to i32 187; CHECK-NEXT: [[T2:%.*]] = lshr i32 [[X:%.*]], [[T1]] 188; CHECK-NEXT: [[T3:%.*]] = trunc i32 [[T2]] to i16 189; CHECK-NEXT: [[T4:%.*]] = add i16 [[Y]], -1 190; CHECK-NEXT: [[T5:%.*]] = ashr i16 [[T3]], [[T4]] 191; CHECK-NEXT: ret i16 [[T5]] 192; 193 %t0 = sub i16 32, %y 194 %t1 = zext i16 %t0 to i32 195 %t2 = lshr i32 %x, %t1 196 %t3 = trunc i32 %t2 to i16 197 %t4 = add i16 %y, -1 198 %t5 = ashr i16 %t3, %t4 199 ret i16 %t5 200} 201