1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -instcombine -S | FileCheck %s 3 4; If we have some pattern that leaves only some low bits set, and then performs 5; left-shift of those bits, we can combine those two shifts into a shift+mask. 6 7; There are many variants to this pattern: 8; b) (trunc ((x & (~(-1 << maskNbits))))) << shiftNbits 9; simplify to: 10; ((trunc(x)) << shiftNbits) & (~(-1 << (maskNbits+shiftNbits))) 11 12; Simple tests. 13 14declare void @use32(i32) 15declare void @use64(i64) 16 17define i32 @t0_basic(i64 %x, i32 %nbits) { 18; CHECK-LABEL: @t0_basic( 19; CHECK-NEXT: [[T0:%.*]] = zext i32 [[NBITS:%.*]] to i64 20; CHECK-NEXT: [[T1:%.*]] = shl i64 -1, [[T0]] 21; CHECK-NEXT: [[T2:%.*]] = xor i64 [[T1]], -1 22; CHECK-NEXT: [[T3:%.*]] = sub i32 32, [[NBITS]] 23; CHECK-NEXT: [[T4:%.*]] = and i64 [[T2]], [[X:%.*]] 24; CHECK-NEXT: call void @use32(i32 [[NBITS]]) 25; CHECK-NEXT: call void @use64(i64 [[T0]]) 26; CHECK-NEXT: call void @use64(i64 [[T1]]) 27; CHECK-NEXT: call void @use64(i64 [[T2]]) 28; CHECK-NEXT: call void @use32(i32 [[T3]]) 29; CHECK-NEXT: call void @use64(i64 [[T4]]) 30; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[X]] to i32 31; CHECK-NEXT: [[T6:%.*]] = shl i32 [[TMP1]], [[T3]] 32; CHECK-NEXT: ret i32 [[T6]] 33; 34 %t0 = zext i32 %nbits to i64 35 %t1 = shl i64 -1, %t0 36 %t2 = xor i64 %t1, -1 37 %t3 = sub i32 32, %nbits 38 %t4 = and i64 %t2, %x 39 40 call void @use32(i32 %nbits) 41 call void @use64(i64 %t0) 42 call void @use64(i64 %t1) 43 call void @use64(i64 %t2) 44 call void @use32(i32 %t3) 45 call void @use64(i64 %t4) 46 47 %t5 = trunc i64 %t4 to i32 48 %t6 = shl i32 %t5, %t3 49 ret i32 %t6 50} 51 52; Vectors 53 54declare void @use8xi32(<8 x i32>) 55declare void @use8xi64(<8 x i64>) 56 57define <8 x i32> @t1_vec_splat(<8 x i64> %x, <8 x i32> %nbits) { 58; CHECK-LABEL: @t1_vec_splat( 59; CHECK-NEXT: [[T0:%.*]] = zext <8 x i32> [[NBITS:%.*]] to <8 x i64> 60; CHECK-NEXT: [[T1:%.*]] = shl <8 x i64> <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1>, [[T0]] 61; CHECK-NEXT: [[T2:%.*]] = xor <8 x i64> [[T1]], <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1> 62; CHECK-NEXT: [[T3:%.*]] = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32>, [[NBITS]] 63; CHECK-NEXT: [[T4:%.*]] = and <8 x i64> [[T2]], [[X:%.*]] 64; CHECK-NEXT: call void @use8xi32(<8 x i32> [[NBITS]]) 65; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T0]]) 66; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T1]]) 67; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T2]]) 68; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T3]]) 69; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T4]]) 70; CHECK-NEXT: [[TMP1:%.*]] = trunc <8 x i64> [[X]] to <8 x i32> 71; CHECK-NEXT: [[T6:%.*]] = shl <8 x i32> [[TMP1]], [[T3]] 72; CHECK-NEXT: ret <8 x i32> [[T6]] 73; 74 %t0 = zext <8 x i32> %nbits to <8 x i64> 75 %t1 = shl <8 x i64> <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1>, %t0 76 %t2 = xor <8 x i64> %t1, <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1> 77 %t3 = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32>, %nbits 78 %t4 = and <8 x i64> %t2, %x 79 80 call void @use8xi32(<8 x i32> %nbits) 81 call void @use8xi64(<8 x i64> %t0) 82 call void @use8xi64(<8 x i64> %t1) 83 call void @use8xi64(<8 x i64> %t2) 84 call void @use8xi32(<8 x i32> %t3) 85 call void @use8xi64(<8 x i64> %t4) 86 87 %t5 = trunc <8 x i64> %t4 to <8 x i32> 88 %t6 = shl <8 x i32> %t5, %t3 89 ret <8 x i32> %t6 90} 91 92define <8 x i32> @t2_vec_splat_undef(<8 x i64> %x, <8 x i32> %nbits) { 93; CHECK-LABEL: @t2_vec_splat_undef( 94; CHECK-NEXT: [[T0:%.*]] = zext <8 x i32> [[NBITS:%.*]] to <8 x i64> 95; CHECK-NEXT: [[T1:%.*]] = shl <8 x i64> <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 undef, i64 -1>, [[T0]] 96; CHECK-NEXT: [[T2:%.*]] = xor <8 x i64> [[T1]], <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 undef, i64 -1> 97; CHECK-NEXT: [[T3:%.*]] = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 undef, i32 32>, [[NBITS]] 98; CHECK-NEXT: [[T4:%.*]] = and <8 x i64> [[T2]], [[X:%.*]] 99; CHECK-NEXT: call void @use8xi32(<8 x i32> [[NBITS]]) 100; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T0]]) 101; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T1]]) 102; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T2]]) 103; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T3]]) 104; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T4]]) 105; CHECK-NEXT: [[TMP1:%.*]] = trunc <8 x i64> [[X]] to <8 x i32> 106; CHECK-NEXT: [[T6:%.*]] = shl <8 x i32> [[TMP1]], [[T3]] 107; CHECK-NEXT: ret <8 x i32> [[T6]] 108; 109 %t0 = zext <8 x i32> %nbits to <8 x i64> 110 %t1 = shl <8 x i64> <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 undef, i64 -1>, %t0 111 %t2 = xor <8 x i64> %t1, <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 undef, i64 -1> 112 %t3 = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 undef, i32 32>, %nbits 113 %t4 = and <8 x i64> %t2, %x 114 115 call void @use8xi32(<8 x i32> %nbits) 116 call void @use8xi64(<8 x i64> %t0) 117 call void @use8xi64(<8 x i64> %t1) 118 call void @use8xi64(<8 x i64> %t2) 119 call void @use8xi32(<8 x i32> %t3) 120 call void @use8xi64(<8 x i64> %t4) 121 122 %t5 = trunc <8 x i64> %t4 to <8 x i32> 123 %t6 = shl <8 x i32> %t5, %t3 124 ret <8 x i32> %t6 125} 126 127define <8 x i32> @t3_vec_nonsplat(<8 x i64> %x, <8 x i32> %nbits) { 128; CHECK-LABEL: @t3_vec_nonsplat( 129; CHECK-NEXT: [[T0:%.*]] = add <8 x i32> [[NBITS:%.*]], <i32 -1, i32 0, i32 0, i32 1, i32 0, i32 0, i32 0, i32 0> 130; CHECK-NEXT: [[T1:%.*]] = zext <8 x i32> [[T0]] to <8 x i64> 131; CHECK-NEXT: [[T2:%.*]] = shl <8 x i64> <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1>, [[T1]] 132; CHECK-NEXT: [[T3:%.*]] = xor <8 x i64> [[T2]], <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1> 133; CHECK-NEXT: [[T4:%.*]] = sub <8 x i32> <i32 33, i32 32, i32 33, i32 32, i32 32, i32 32, i32 32, i32 32>, [[NBITS]] 134; CHECK-NEXT: [[T5:%.*]] = and <8 x i64> [[T3]], [[X:%.*]] 135; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T0]]) 136; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T1]]) 137; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T2]]) 138; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T3]]) 139; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T4]]) 140; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T5]]) 141; CHECK-NEXT: [[TMP1:%.*]] = trunc <8 x i64> [[X]] to <8 x i32> 142; CHECK-NEXT: [[T7:%.*]] = shl <8 x i32> [[TMP1]], [[T4]] 143; CHECK-NEXT: ret <8 x i32> [[T7]] 144; 145 %t0 = add <8 x i32> %nbits, <i32 -1, i32 0, i32 0, i32 1, i32 0, i32 0, i32 0, i32 0> 146 %t1 = zext <8 x i32> %t0 to <8 x i64> 147 %t2 = shl <8 x i64> <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1>, %t1 ; shifting by nbits-1 148 %t3 = xor <8 x i64> %t2, <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1> 149 %t4 = sub <8 x i32> <i32 33, i32 32, i32 33, i32 32, i32 32, i32 32, i32 32, i32 32>, %nbits 150 %t5 = and <8 x i64> %t3, %x 151 152 call void @use8xi32(<8 x i32> %t0) 153 call void @use8xi64(<8 x i64> %t1) 154 call void @use8xi64(<8 x i64> %t2) 155 call void @use8xi64(<8 x i64> %t3) 156 call void @use8xi32(<8 x i32> %t4) 157 call void @use8xi64(<8 x i64> %t5) 158 159 %t6 = trunc <8 x i64> %t5 to <8 x i32> 160 %t7 = shl <8 x i32> %t6, %t4 161 ret <8 x i32> %t7 162} 163 164; -1 can be truncated. 165 166define i32 @t4_allones_trunc(i64 %x, i32 %nbits) { 167; CHECK-LABEL: @t4_allones_trunc( 168; CHECK-NEXT: [[T0:%.*]] = zext i32 [[NBITS:%.*]] to i64 169; CHECK-NEXT: [[T1:%.*]] = shl i64 -1, [[T0]] 170; CHECK-NEXT: [[T2:%.*]] = xor i64 [[T1]], 4294967295 171; CHECK-NEXT: [[T3:%.*]] = sub i32 32, [[NBITS]] 172; CHECK-NEXT: [[T4:%.*]] = and i64 [[T2]], [[X:%.*]] 173; CHECK-NEXT: call void @use32(i32 [[NBITS]]) 174; CHECK-NEXT: call void @use64(i64 [[T0]]) 175; CHECK-NEXT: call void @use64(i64 [[T1]]) 176; CHECK-NEXT: call void @use64(i64 [[T2]]) 177; CHECK-NEXT: call void @use32(i32 [[T3]]) 178; CHECK-NEXT: call void @use64(i64 [[T4]]) 179; CHECK-NEXT: [[T5:%.*]] = trunc i64 [[T4]] to i32 180; CHECK-NEXT: [[T6:%.*]] = shl i32 [[T5]], [[T3]] 181; CHECK-NEXT: ret i32 [[T6]] 182; 183 %t0 = zext i32 %nbits to i64 184 %t1 = shl i64 -1, %t0 185 %t2 = xor i64 %t1, 4294967295 186 %t3 = sub i32 32, %nbits 187 %t4 = and i64 %t2, %x 188 189 call void @use32(i32 %nbits) 190 call void @use64(i64 %t0) 191 call void @use64(i64 %t1) 192 call void @use64(i64 %t2) 193 call void @use32(i32 %t3) 194 call void @use64(i64 %t4) 195 196 %t5 = trunc i64 %t4 to i32 197 %t6 = shl i32 %t5, %t3 198 ret i32 %t6 199} 200 201; Extra uses 202 203define i32 @n5_extrause(i64 %x, i32 %nbits) { 204; CHECK-LABEL: @n5_extrause( 205; CHECK-NEXT: [[T0:%.*]] = zext i32 [[NBITS:%.*]] to i64 206; CHECK-NEXT: [[T1:%.*]] = shl i64 -1, [[T0]] 207; CHECK-NEXT: [[T2:%.*]] = xor i64 [[T1]], -1 208; CHECK-NEXT: [[T3:%.*]] = sub i32 32, [[NBITS]] 209; CHECK-NEXT: [[T4:%.*]] = and i64 [[T2]], [[X:%.*]] 210; CHECK-NEXT: call void @use32(i32 [[NBITS]]) 211; CHECK-NEXT: call void @use64(i64 [[T0]]) 212; CHECK-NEXT: call void @use64(i64 [[T1]]) 213; CHECK-NEXT: call void @use64(i64 [[T2]]) 214; CHECK-NEXT: call void @use32(i32 [[T3]]) 215; CHECK-NEXT: call void @use64(i64 [[T4]]) 216; CHECK-NEXT: [[T5:%.*]] = trunc i64 [[T4]] to i32 217; CHECK-NEXT: call void @use32(i32 [[T5]]) 218; CHECK-NEXT: [[T6:%.*]] = shl i32 [[T5]], [[T3]] 219; CHECK-NEXT: ret i32 [[T6]] 220; 221 %t0 = zext i32 %nbits to i64 222 %t1 = shl i64 -1, %t0 223 %t2 = xor i64 %t1, -1 224 %t3 = sub i32 32, %nbits 225 %t4 = and i64 %t2, %x 226 227 call void @use32(i32 %nbits) 228 call void @use64(i64 %t0) 229 call void @use64(i64 %t1) 230 call void @use64(i64 %t2) 231 call void @use32(i32 %t3) 232 call void @use64(i64 %t4) 233 234 %t5 = trunc i64 %t4 to i32 235 call void @use32(i32 %t5) 236 %t6 = shl i32 %t5, %t3 237 ret i32 %t6 238} 239