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:%.*]] = add i32 [[NBITS:%.*]], -1 20; CHECK-NEXT: [[T1:%.*]] = zext i32 [[T0]] to i64 21; CHECK-NEXT: [[T2:%.*]] = shl i64 -1, [[T1]] 22; CHECK-NEXT: [[T3:%.*]] = xor i64 [[T2]], -1 23; CHECK-NEXT: [[T4:%.*]] = sub i32 32, [[NBITS]] 24; CHECK-NEXT: call void @use32(i32 [[T0]]) 25; CHECK-NEXT: call void @use64(i64 [[T1]]) 26; CHECK-NEXT: call void @use64(i64 [[T2]]) 27; CHECK-NEXT: call void @use64(i64 [[T3]]) 28; CHECK-NEXT: call void @use32(i32 [[T4]]) 29; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[X:%.*]] to i32 30; CHECK-NEXT: [[TMP2:%.*]] = shl i32 [[TMP1]], [[T4]] 31; CHECK-NEXT: [[T7:%.*]] = and i32 [[TMP2]], 2147483647 32; CHECK-NEXT: ret i32 [[T7]] 33; 34 %t0 = add i32 %nbits, -1 35 %t1 = zext i32 %t0 to i64 36 %t2 = shl i64 -1, %t1 ; shifting by nbits-1 37 %t3 = xor i64 %t2, -1 38 %t4 = sub i32 32, %nbits 39 40 call void @use32(i32 %t0) 41 call void @use64(i64 %t1) 42 call void @use64(i64 %t2) 43 call void @use64(i64 %t3) 44 call void @use32(i32 %t4) 45 46 %t5 = and i64 %t3, %x 47 %t6 = trunc i64 %t5 to i32 48 %t7 = shl i32 %t6, %t4 49 ret i32 %t7 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:%.*]] = add <8 x i32> [[NBITS:%.*]], <i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1> 60; CHECK-NEXT: [[T1:%.*]] = zext <8 x i32> [[T0]] to <8 x i64> 61; CHECK-NEXT: [[T2:%.*]] = shl <8 x i64> <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1>, [[T1]] 62; CHECK-NEXT: [[T3:%.*]] = xor <8 x i64> [[T2]], <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1> 63; CHECK-NEXT: [[T4:%.*]] = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32>, [[NBITS]] 64; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T0]]) 65; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T1]]) 66; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T2]]) 67; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T3]]) 68; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T4]]) 69; CHECK-NEXT: [[TMP1:%.*]] = trunc <8 x i64> [[X:%.*]] to <8 x i32> 70; CHECK-NEXT: [[TMP2:%.*]] = shl <8 x i32> [[TMP1]], [[T4]] 71; CHECK-NEXT: [[T7:%.*]] = and <8 x i32> [[TMP2]], <i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647> 72; CHECK-NEXT: ret <8 x i32> [[T7]] 73; 74 %t0 = add <8 x i32> %nbits, <i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1> 75 %t1 = zext <8 x i32> %t0 to <8 x i64> 76 %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 77 %t3 = xor <8 x i64> %t2, <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1> 78 %t4 = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32>, %nbits 79 80 call void @use8xi32(<8 x i32> %t0) 81 call void @use8xi64(<8 x i64> %t1) 82 call void @use8xi64(<8 x i64> %t2) 83 call void @use8xi64(<8 x i64> %t3) 84 call void @use8xi32(<8 x i32> %t4) 85 86 %t5 = and <8 x i64> %t3, %x 87 %t6 = trunc <8 x i64> %t5 to <8 x i32> 88 %t7 = shl <8 x i32> %t6, %t4 89 ret <8 x i32> %t7 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:%.*]] = add <8 x i32> [[NBITS:%.*]], <i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 undef, i32 -1> 95; CHECK-NEXT: [[T1:%.*]] = zext <8 x i32> [[T0]] to <8 x i64> 96; CHECK-NEXT: [[T2:%.*]] = shl <8 x i64> <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 undef, i64 -1>, [[T1]] 97; CHECK-NEXT: [[T3:%.*]] = xor <8 x i64> [[T2]], <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 undef, i64 -1> 98; CHECK-NEXT: [[T4:%.*]] = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 undef, i32 32>, [[NBITS]] 99; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T0]]) 100; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T1]]) 101; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T2]]) 102; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T3]]) 103; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T4]]) 104; CHECK-NEXT: [[TMP1:%.*]] = trunc <8 x i64> [[X:%.*]] to <8 x i32> 105; CHECK-NEXT: [[TMP2:%.*]] = shl <8 x i32> [[TMP1]], [[T4]] 106; CHECK-NEXT: [[T7:%.*]] = and <8 x i32> [[TMP2]], <i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 2147483647, i32 poison, i32 2147483647> 107; CHECK-NEXT: ret <8 x i32> [[T7]] 108; 109 %t0 = add <8 x i32> %nbits, <i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 -1, i32 undef, i32 -1> 110 %t1 = zext <8 x i32> %t0 to <8 x i64> 111 %t2 = shl <8 x i64> <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 undef, i64 -1>, %t1 ; shifting by nbits-1 112 %t3 = xor <8 x i64> %t2, <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 undef, i64 -1> 113 %t4 = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 undef, i32 32>, %nbits 114 115 call void @use8xi32(<8 x i32> %t0) 116 call void @use8xi64(<8 x i64> %t1) 117 call void @use8xi64(<8 x i64> %t2) 118 call void @use8xi64(<8 x i64> %t3) 119 call void @use8xi32(<8 x i32> %t4) 120 121 %t5 = and <8 x i64> %t3, %x 122 %t6 = trunc <8 x i64> %t5 to <8 x i32> 123 %t7 = shl <8 x i32> %t6, %t4 124 ret <8 x i32> %t7 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 -33, i32 -32, i32 -31, i32 -1, i32 0, i32 1, i32 31, i32 32> 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 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32>, [[NBITS]] 134; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T0]]) 135; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T1]]) 136; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T2]]) 137; CHECK-NEXT: call void @use8xi64(<8 x i64> [[T3]]) 138; CHECK-NEXT: call void @use8xi32(<8 x i32> [[T4]]) 139; CHECK-NEXT: [[TMP1:%.*]] = trunc <8 x i64> [[X:%.*]] to <8 x i32> 140; CHECK-NEXT: [[TMP2:%.*]] = shl <8 x i32> [[TMP1]], [[T4]] 141; CHECK-NEXT: [[T7:%.*]] = and <8 x i32> [[TMP2]], <i32 poison, i32 0, i32 1, i32 2147483647, i32 -1, i32 -1, i32 -1, i32 -1> 142; CHECK-NEXT: ret <8 x i32> [[T7]] 143; 144 %t0 = add <8 x i32> %nbits, <i32 -33, i32 -32, i32 -31, i32 -1, i32 0, i32 1, i32 31, i32 32> 145 %t1 = zext <8 x i32> %t0 to <8 x i64> 146 %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 147 %t3 = xor <8 x i64> %t2, <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1, i64 -1> 148 %t4 = sub <8 x i32> <i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32, i32 32>, %nbits 149 150 call void @use8xi32(<8 x i32> %t0) 151 call void @use8xi64(<8 x i64> %t1) 152 call void @use8xi64(<8 x i64> %t2) 153 call void @use8xi64(<8 x i64> %t3) 154 call void @use8xi32(<8 x i32> %t4) 155 156 %t5 = and <8 x i64> %t3, %x 157 %t6 = trunc <8 x i64> %t5 to <8 x i32> 158 %t7 = shl <8 x i32> %t6, %t4 159 ret <8 x i32> %t7 160} 161 162; -1 can be truncated. 163 164define i32 @t4_allones_trunc(i64 %x, i32 %nbits) { 165; CHECK-LABEL: @t4_allones_trunc( 166; CHECK-NEXT: [[T0:%.*]] = add i32 [[NBITS:%.*]], -1 167; CHECK-NEXT: [[T1:%.*]] = zext i32 [[T0]] to i64 168; CHECK-NEXT: [[T2:%.*]] = shl i64 -1, [[T1]] 169; CHECK-NEXT: [[T3:%.*]] = xor i64 [[T2]], 4294967295 170; CHECK-NEXT: [[T4:%.*]] = sub i32 32, [[NBITS]] 171; CHECK-NEXT: call void @use32(i32 [[T0]]) 172; CHECK-NEXT: call void @use64(i64 [[T1]]) 173; CHECK-NEXT: call void @use64(i64 [[T2]]) 174; CHECK-NEXT: call void @use64(i64 [[T3]]) 175; CHECK-NEXT: call void @use32(i32 [[T4]]) 176; CHECK-NEXT: [[T5:%.*]] = and i64 [[T3]], [[X:%.*]] 177; CHECK-NEXT: [[T6:%.*]] = trunc i64 [[T5]] to i32 178; CHECK-NEXT: [[T7:%.*]] = shl i32 [[T6]], [[T4]] 179; CHECK-NEXT: ret i32 [[T7]] 180; 181 %t0 = add i32 %nbits, -1 182 %t1 = zext i32 %t0 to i64 183 %t2 = shl i64 -1, %t1 ; shifting by nbits-1 184 %t3 = xor i64 %t2, 4294967295 ; we only care about low 32 bits 185 %t4 = sub i32 32, %nbits 186 187 call void @use32(i32 %t0) 188 call void @use64(i64 %t1) 189 call void @use64(i64 %t2) 190 call void @use64(i64 %t3) 191 call void @use32(i32 %t4) 192 193 %t5 = and i64 %t3, %x 194 %t6 = trunc i64 %t5 to i32 195 %t7 = shl i32 %t6, %t4 196 ret i32 %t7 197} 198 199; Extra uses 200 201define i32 @n5_extrause0(i64 %x, i32 %nbits) { 202; CHECK-LABEL: @n5_extrause0( 203; CHECK-NEXT: [[T0:%.*]] = add i32 [[NBITS:%.*]], -1 204; CHECK-NEXT: [[T1:%.*]] = zext i32 [[T0]] to i64 205; CHECK-NEXT: [[T2:%.*]] = shl i64 -1, [[T1]] 206; CHECK-NEXT: [[T3:%.*]] = xor i64 [[T2]], -1 207; CHECK-NEXT: [[T4:%.*]] = sub i32 32, [[NBITS]] 208; CHECK-NEXT: call void @use32(i32 [[T0]]) 209; CHECK-NEXT: call void @use64(i64 [[T1]]) 210; CHECK-NEXT: call void @use64(i64 [[T2]]) 211; CHECK-NEXT: call void @use64(i64 [[T3]]) 212; CHECK-NEXT: call void @use32(i32 [[T4]]) 213; CHECK-NEXT: [[T5:%.*]] = and i64 [[T3]], [[X:%.*]] 214; CHECK-NEXT: call void @use64(i64 [[T5]]) 215; CHECK-NEXT: [[T6:%.*]] = trunc i64 [[T5]] to i32 216; CHECK-NEXT: [[T7:%.*]] = shl i32 [[T6]], [[T4]] 217; CHECK-NEXT: ret i32 [[T7]] 218; 219 %t0 = add i32 %nbits, -1 220 %t1 = zext i32 %t0 to i64 221 %t2 = shl i64 -1, %t1 ; shifting by nbits-1 222 %t3 = xor i64 %t2, -1 223 %t4 = sub i32 32, %nbits 224 225 call void @use32(i32 %t0) 226 call void @use64(i64 %t1) 227 call void @use64(i64 %t2) 228 call void @use64(i64 %t3) 229 call void @use32(i32 %t4) 230 231 %t5 = and i64 %t3, %x 232 call void @use64(i64 %t5) 233 %t6 = trunc i64 %t5 to i32 234 %t7 = shl i32 %t6, %t4 235 ret i32 %t7 236} 237define i32 @n6_extrause1(i64 %x, i32 %nbits) { 238; CHECK-LABEL: @n6_extrause1( 239; CHECK-NEXT: [[T0:%.*]] = add i32 [[NBITS:%.*]], -1 240; CHECK-NEXT: [[T1:%.*]] = zext i32 [[T0]] to i64 241; CHECK-NEXT: [[T2:%.*]] = shl i64 -1, [[T1]] 242; CHECK-NEXT: [[T3:%.*]] = xor i64 [[T2]], -1 243; CHECK-NEXT: [[T4:%.*]] = sub i32 32, [[NBITS]] 244; CHECK-NEXT: call void @use32(i32 [[T0]]) 245; CHECK-NEXT: call void @use64(i64 [[T1]]) 246; CHECK-NEXT: call void @use64(i64 [[T2]]) 247; CHECK-NEXT: call void @use64(i64 [[T3]]) 248; CHECK-NEXT: call void @use32(i32 [[T4]]) 249; CHECK-NEXT: [[T5:%.*]] = and i64 [[T3]], [[X:%.*]] 250; CHECK-NEXT: [[T6:%.*]] = trunc i64 [[T5]] to i32 251; CHECK-NEXT: call void @use32(i32 [[T6]]) 252; CHECK-NEXT: [[T7:%.*]] = shl i32 [[T6]], [[T4]] 253; CHECK-NEXT: ret i32 [[T7]] 254; 255 %t0 = add i32 %nbits, -1 256 %t1 = zext i32 %t0 to i64 257 %t2 = shl i64 -1, %t1 ; shifting by nbits-1 258 %t3 = xor i64 %t2, -1 259 %t4 = sub i32 32, %nbits 260 261 call void @use32(i32 %t0) 262 call void @use64(i64 %t1) 263 call void @use64(i64 %t2) 264 call void @use64(i64 %t3) 265 call void @use32(i32 %t4) 266 267 %t5 = and i64 %t3, %x 268 %t6 = trunc i64 %t5 to i32 269 call void @use32(i32 %t6) 270 %t7 = shl i32 %t6, %t4 271 ret i32 %t7 272} 273define i32 @n7_extrause2(i64 %x, i32 %nbits) { 274; CHECK-LABEL: @n7_extrause2( 275; CHECK-NEXT: [[T0:%.*]] = add i32 [[NBITS:%.*]], -1 276; CHECK-NEXT: [[T1:%.*]] = zext i32 [[T0]] to i64 277; CHECK-NEXT: [[T2:%.*]] = shl i64 -1, [[T1]] 278; CHECK-NEXT: [[T3:%.*]] = xor i64 [[T2]], -1 279; CHECK-NEXT: [[T4:%.*]] = sub i32 32, [[NBITS]] 280; CHECK-NEXT: call void @use32(i32 [[T0]]) 281; CHECK-NEXT: call void @use64(i64 [[T1]]) 282; CHECK-NEXT: call void @use64(i64 [[T2]]) 283; CHECK-NEXT: call void @use64(i64 [[T3]]) 284; CHECK-NEXT: call void @use32(i32 [[T4]]) 285; CHECK-NEXT: [[T5:%.*]] = and i64 [[T3]], [[X:%.*]] 286; CHECK-NEXT: call void @use64(i64 [[T5]]) 287; CHECK-NEXT: [[T6:%.*]] = trunc i64 [[T5]] to i32 288; CHECK-NEXT: call void @use32(i32 [[T6]]) 289; CHECK-NEXT: [[T7:%.*]] = shl i32 [[T6]], [[T4]] 290; CHECK-NEXT: ret i32 [[T7]] 291; 292 %t0 = add i32 %nbits, -1 293 %t1 = zext i32 %t0 to i64 294 %t2 = shl i64 -1, %t1 ; shifting by nbits-1 295 %t3 = xor i64 %t2, -1 296 %t4 = sub i32 32, %nbits 297 298 call void @use32(i32 %t0) 299 call void @use64(i64 %t1) 300 call void @use64(i64 %t2) 301 call void @use64(i64 %t3) 302 call void @use32(i32 %t4) 303 304 %t5 = and i64 %t3, %x 305 call void @use64(i64 %t5) 306 %t6 = trunc i64 %t5 to i32 307 call void @use32(i32 %t6) 308 %t7 = shl i32 %t6, %t4 309 ret i32 %t7 310} 311