1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=instsimplify -S -data-layout="E" | FileCheck %s --check-prefixes=CHECK,BIGENDIAN 3; RUN: opt < %s -passes=instsimplify -S -data-layout="e" | FileCheck %s --check-prefixes=CHECK,LITTLEENDIAN 4 5; If any bits of the shift amount are known to make it exceed or equal 6; the number of bits in the type, the shift causes undefined behavior. 7 8define i32 @shl_amount_is_known_bogus(i32 %a, i32 %b) { 9; CHECK-LABEL: @shl_amount_is_known_bogus( 10; CHECK-NEXT: ret i32 poison 11; 12 %or = or i32 %b, 32 13 %shl = shl i32 %a, %or 14 ret i32 %shl 15} 16 17define i32 @shl_amount_is_known_bogus_range_attr(i32 %a, i32 range(i32 32, 64) %b) { 18; CHECK-LABEL: @shl_amount_is_known_bogus_range_attr( 19; CHECK-NEXT: ret i32 poison 20; 21 %shl = shl i32 %a, %b 22 ret i32 %shl 23} 24 25define i32 @neg_shl_amount_is_known_bogus_range_attr(i32 %a, i32 range(i32 0, 32) %b) { 26; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_attr( 27; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B:%.*]] 28; CHECK-NEXT: ret i32 [[SHL]] 29; 30 %shl = shl i32 %a, %b 31 ret i32 %shl 32} 33 34declare range(i32 32, 64) i32 @returns_out_of_range_helper() 35declare range(i32 0, 32) i32 @returns_in_range_helper() 36 37define i32 @shl_amount_is_known_bogus_range_return(i32 %a) { 38; CHECK-LABEL: @shl_amount_is_known_bogus_range_return( 39; CHECK-NEXT: [[B:%.*]] = call i32 @returns_out_of_range_helper() 40; CHECK-NEXT: ret i32 poison 41; 42 %b = call i32 @returns_out_of_range_helper() 43 %shl = shl i32 %a, %b 44 ret i32 %shl 45} 46 47define i32 @neg_shl_amount_is_known_bogus_range_return(i32 %a) { 48; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_return( 49; CHECK-NEXT: [[B:%.*]] = call i32 @returns_in_range_helper() 50; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]] 51; CHECK-NEXT: ret i32 [[SHL]] 52; 53 %b = call i32 @returns_in_range_helper() 54 %shl = shl i32 %a, %b 55 ret i32 %shl 56} 57 58declare i32 @returns_i32_helper() 59 60define i32 @shl_amount_is_known_bogus_range_call(i32 %a) { 61; CHECK-LABEL: @shl_amount_is_known_bogus_range_call( 62; CHECK-NEXT: [[B:%.*]] = call range(i32 32, 64) i32 @returns_i32_helper() 63; CHECK-NEXT: ret i32 poison 64; 65 %b = call range(i32 32, 64) i32 @returns_i32_helper() 66 %shl = shl i32 %a, %b 67 ret i32 %shl 68} 69 70define i32 @neg_shl_amount_is_known_bogus_range_call(i32 %a) { 71; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_call( 72; CHECK-NEXT: [[B:%.*]] = call range(i32 0, 32) i32 @returns_i32_helper() 73; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]] 74; CHECK-NEXT: ret i32 [[SHL]] 75; 76 %b = call range(i32 0, 32) i32 @returns_i32_helper() 77 %shl = shl i32 %a, %b 78 ret i32 %shl 79} 80 81define <2 x i32> @shl_amount_is_known_bogus_range_attr_vec(<2 x i32> %a, <2 x i32> range(i32 32, 64) %b) { 82; CHECK-LABEL: @shl_amount_is_known_bogus_range_attr_vec( 83; CHECK-NEXT: ret <2 x i32> poison 84; 85 %shl = shl <2 x i32> %a, %b 86 ret <2 x i32> %shl 87} 88 89define <2 x i32> @neg_shl_amount_is_known_bogus_range_attr_vec(<2 x i32> %a, <2 x i32> range(i32 0, 32) %b) { 90; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_attr_vec( 91; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B:%.*]] 92; CHECK-NEXT: ret <2 x i32> [[SHL]] 93; 94 %shl = shl <2 x i32> %a, %b 95 ret <2 x i32> %shl 96} 97 98declare range(i32 32, 64) <2 x i32> @returns_out_of_range_helper_vec() 99declare range(i32 0, 32) <2 x i32> @returns_in_range_helper_vec() 100 101define <2 x i32> @shl_amount_is_known_bogus_range_return_vec(<2 x i32> %a) { 102; CHECK-LABEL: @shl_amount_is_known_bogus_range_return_vec( 103; CHECK-NEXT: [[B:%.*]] = call <2 x i32> @returns_out_of_range_helper_vec() 104; CHECK-NEXT: ret <2 x i32> poison 105; 106 %b = call <2 x i32> @returns_out_of_range_helper_vec() 107 %shl = shl <2 x i32> %a, %b 108 ret <2 x i32> %shl 109} 110 111define <2 x i32> @neg_shl_amount_is_known_bogus_range_return_vec(<2 x i32> %a) { 112; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_return_vec( 113; CHECK-NEXT: [[B:%.*]] = call <2 x i32> @returns_in_range_helper_vec() 114; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]] 115; CHECK-NEXT: ret <2 x i32> [[SHL]] 116; 117 %b = call <2 x i32> @returns_in_range_helper_vec() 118 %shl = shl <2 x i32> %a, %b 119 ret <2 x i32> %shl 120} 121 122declare <2 x i32> @returns_i32_helper_vec() 123 124define <2 x i32> @shl_amount_is_known_bogus_range_call_vec(<2 x i32> %a) { 125; CHECK-LABEL: @shl_amount_is_known_bogus_range_call_vec( 126; CHECK-NEXT: [[B:%.*]] = call range(i32 32, 64) <2 x i32> @returns_i32_helper_vec() 127; CHECK-NEXT: ret <2 x i32> poison 128; 129 %b = call range(i32 32, 64) <2 x i32> @returns_i32_helper_vec() 130 %shl = shl <2 x i32> %a, %b 131 ret <2 x i32> %shl 132} 133 134define <2 x i32> @neg_shl_amount_is_known_bogus_range_call_vec(<2 x i32> %a) { 135; CHECK-LABEL: @neg_shl_amount_is_known_bogus_range_call_vec( 136; CHECK-NEXT: [[B:%.*]] = call range(i32 0, 32) <2 x i32> @returns_i32_helper_vec() 137; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[B]] 138; CHECK-NEXT: ret <2 x i32> [[SHL]] 139; 140 %b = call range(i32 0, 32) <2 x i32> @returns_i32_helper_vec() 141 %shl = shl <2 x i32> %a, %b 142 ret <2 x i32> %shl 143} 144 145define i32 @shl_amount_is_not_known_bogus_range_call_and_range_metadata(i32 %a) { 146; CHECK-LABEL: @shl_amount_is_not_known_bogus_range_call_and_range_metadata( 147; CHECK-NEXT: [[B:%.*]] = call range(i32 0, 32) i32 @returns_i32_helper(), !range [[RNG0:![0-9]+]] 148; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[B]] 149; CHECK-NEXT: ret i32 [[SHL]] 150; 151 %b = call range(i32 0, 32) i32 @returns_i32_helper(), !range !{ i32 32, i32 64 } 152 %shl = shl i32 %a, %b 153 ret i32 %shl 154} 155 156; Check some weird types and the other shift ops. 157 158define i31 @lshr_amount_is_known_bogus(i31 %a, i31 %b) { 159; CHECK-LABEL: @lshr_amount_is_known_bogus( 160; CHECK-NEXT: ret i31 poison 161; 162 %or = or i31 %b, 31 163 %shr = lshr i31 %a, %or 164 ret i31 %shr 165} 166 167define i33 @ashr_amount_is_known_bogus(i33 %a, i33 %b) { 168; CHECK-LABEL: @ashr_amount_is_known_bogus( 169; CHECK-NEXT: ret i33 poison 170; 171 %or = or i33 %b, 33 172 %shr = ashr i33 %a, %or 173 ret i33 %shr 174} 175 176 177; If all valid bits of the shift amount are known 0, there's no shift. 178; It doesn't matter if high bits are set because that would be undefined. 179; Therefore, the only possible valid result of these shifts is %a. 180 181define i16 @ashr_amount_is_zero(i16 %a, i16 %b) { 182; CHECK-LABEL: @ashr_amount_is_zero( 183; CHECK-NEXT: ret i16 [[A:%.*]] 184; 185 %and = and i16 %b, 65520 ; 0xfff0 186 %shr = ashr i16 %a, %and 187 ret i16 %shr 188} 189 190define i300 @lshr_amount_is_zero(i300 %a, i300 %b) { 191; CHECK-LABEL: @lshr_amount_is_zero( 192; CHECK-NEXT: ret i300 [[A:%.*]] 193; 194 %and = and i300 %b, 2048 195 %shr = lshr i300 %a, %and 196 ret i300 %shr 197} 198 199define i9 @shl_amount_is_zero(i9 %a, i9 %b) { 200; CHECK-LABEL: @shl_amount_is_zero( 201; CHECK-NEXT: ret i9 [[A:%.*]] 202; 203 %and = and i9 %b, 496 ; 0x1f0 204 %shl = shl i9 %a, %and 205 ret i9 %shl 206} 207 208 209; Verify that we've calculated the log2 boundary of valid bits correctly for a weird type. 210 211define i9 @shl_amount_is_not_known_zero(i9 %a, i9 %b) { 212; CHECK-LABEL: @shl_amount_is_not_known_zero( 213; CHECK-NEXT: [[AND:%.*]] = and i9 [[B:%.*]], -8 214; CHECK-NEXT: [[SHL:%.*]] = shl i9 [[A:%.*]], [[AND]] 215; CHECK-NEXT: ret i9 [[SHL]] 216; 217 %and = and i9 %b, 504 ; 0x1f8 218 %shl = shl i9 %a, %and 219 ret i9 %shl 220} 221 222 223; For vectors, we need all scalar elements to meet the requirements to optimize. 224 225define <2 x i32> @ashr_vector_bogus(<2 x i32> %a, <2 x i32> %b) { 226; CHECK-LABEL: @ashr_vector_bogus( 227; CHECK-NEXT: ret <2 x i32> poison 228; 229 %or = or <2 x i32> %b, <i32 32, i32 32> 230 %shr = ashr <2 x i32> %a, %or 231 ret <2 x i32> %shr 232} 233 234; FIXME: This is undef, but computeKnownBits doesn't handle the union. 235define <2 x i32> @shl_vector_bogus(<2 x i32> %a, <2 x i32> %b) { 236; CHECK-LABEL: @shl_vector_bogus( 237; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[B:%.*]], <i32 32, i32 64> 238; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[OR]] 239; CHECK-NEXT: ret <2 x i32> [[SHL]] 240; 241 %or = or <2 x i32> %b, <i32 32, i32 64> 242 %shl = shl <2 x i32> %a, %or 243 ret <2 x i32> %shl 244} 245 246define <2 x i32> @lshr_vector_zero(<2 x i32> %a, <2 x i32> %b) { 247; CHECK-LABEL: @lshr_vector_zero( 248; CHECK-NEXT: ret <2 x i32> [[A:%.*]] 249; 250 %and = and <2 x i32> %b, <i32 64, i32 256> 251 %shr = lshr <2 x i32> %a, %and 252 ret <2 x i32> %shr 253} 254 255; Make sure that weird vector types work too. 256define <2 x i15> @shl_vector_zero(<2 x i15> %a, <2 x i15> %b) { 257; CHECK-LABEL: @shl_vector_zero( 258; CHECK-NEXT: ret <2 x i15> [[A:%.*]] 259; 260 %and = and <2 x i15> %b, <i15 1024, i15 1024> 261 %shl = shl <2 x i15> %a, %and 262 ret <2 x i15> %shl 263} 264 265define <2 x i32> @shl_vector_for_real(<2 x i32> %a, <2 x i32> %b) { 266; CHECK-LABEL: @shl_vector_for_real( 267; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[B:%.*]], splat (i32 3) 268; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[A:%.*]], [[AND]] 269; CHECK-NEXT: ret <2 x i32> [[SHL]] 270; 271 %and = and <2 x i32> %b, <i32 3, i32 3> ; a necessary mask op 272 %shl = shl <2 x i32> %a, %and 273 ret <2 x i32> %shl 274} 275 276 277; We calculate the valid bits of the shift using log2, and log2 of 1 (the type width) is 0. 278; That should be ok. Either the shift amount is 0 or invalid (1), so we can always return %a. 279 280define i1 @shl_i1(i1 %a, i1 %b) { 281; CHECK-LABEL: @shl_i1( 282; CHECK-NEXT: ret i1 [[A:%.*]] 283; 284 %shl = shl i1 %a, %b 285 ret i1 %shl 286} 287 288; The following cases only get folded by InstCombine, 289; see InstCombine/lshr.ll. 290 291declare i32 @llvm.cttz.i32(i32, i1) nounwind readnone 292declare i32 @llvm.ctlz.i32(i32, i1) nounwind readnone 293declare <2 x i8> @llvm.cttz.v2i8(<2 x i8>, i1) nounwind readnone 294declare <2 x i8> @llvm.ctlz.v2i8(<2 x i8>, i1) nounwind readnone 295 296define i32 @lshr_ctlz_zero_is_undef(i32 %x) { 297; CHECK-LABEL: @lshr_ctlz_zero_is_undef( 298; CHECK-NEXT: [[CT:%.*]] = call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 true) 299; CHECK-NEXT: [[SH:%.*]] = lshr i32 [[CT]], 5 300; CHECK-NEXT: ret i32 [[SH]] 301; 302 %ct = call i32 @llvm.ctlz.i32(i32 %x, i1 true) 303 %sh = lshr i32 %ct, 5 304 ret i32 %sh 305} 306 307define i32 @lshr_cttz_zero_is_undef(i32 %x) { 308; CHECK-LABEL: @lshr_cttz_zero_is_undef( 309; CHECK-NEXT: [[CT:%.*]] = call i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true) 310; CHECK-NEXT: [[SH:%.*]] = lshr i32 [[CT]], 5 311; CHECK-NEXT: ret i32 [[SH]] 312; 313 %ct = call i32 @llvm.cttz.i32(i32 %x, i1 true) 314 %sh = lshr i32 %ct, 5 315 ret i32 %sh 316} 317 318define <2 x i8> @lshr_ctlz_zero_is_undef_splat_vec(<2 x i8> %x) { 319; CHECK-LABEL: @lshr_ctlz_zero_is_undef_splat_vec( 320; CHECK-NEXT: [[CT:%.*]] = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> [[X:%.*]], i1 true) 321; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i8> [[CT]], splat (i8 3) 322; CHECK-NEXT: ret <2 x i8> [[SH]] 323; 324 %ct = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> %x, i1 true) 325 %sh = lshr <2 x i8> %ct, <i8 3, i8 3> 326 ret <2 x i8> %sh 327} 328 329define i8 @lshr_ctlz_zero_is_undef_vec(<2 x i8> %x) { 330; CHECK-LABEL: @lshr_ctlz_zero_is_undef_vec( 331; CHECK-NEXT: [[CT:%.*]] = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> [[X:%.*]], i1 true) 332; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i8> [[CT]], <i8 3, i8 0> 333; CHECK-NEXT: [[EX:%.*]] = extractelement <2 x i8> [[SH]], i32 0 334; CHECK-NEXT: ret i8 [[EX]] 335; 336 %ct = call <2 x i8> @llvm.ctlz.v2i8(<2 x i8> %x, i1 true) 337 %sh = lshr <2 x i8> %ct, <i8 3, i8 0> 338 %ex = extractelement <2 x i8> %sh, i32 0 339 ret i8 %ex 340} 341 342define <2 x i8> @lshr_cttz_zero_is_undef_splat_vec(<2 x i8> %x) { 343; CHECK-LABEL: @lshr_cttz_zero_is_undef_splat_vec( 344; CHECK-NEXT: [[CT:%.*]] = call <2 x i8> @llvm.cttz.v2i8(<2 x i8> [[X:%.*]], i1 true) 345; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i8> [[CT]], splat (i8 3) 346; CHECK-NEXT: ret <2 x i8> [[SH]] 347; 348 %ct = call <2 x i8> @llvm.cttz.v2i8(<2 x i8> %x, i1 true) 349 %sh = lshr <2 x i8> %ct, <i8 3, i8 3> 350 ret <2 x i8> %sh 351} 352 353define i8 @lshr_cttz_zero_is_undef_vec(<2 x i8> %x) { 354; CHECK-LABEL: @lshr_cttz_zero_is_undef_vec( 355; CHECK-NEXT: [[CT:%.*]] = call <2 x i8> @llvm.cttz.v2i8(<2 x i8> [[X:%.*]], i1 true) 356; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i8> [[CT]], <i8 3, i8 0> 357; CHECK-NEXT: [[EX:%.*]] = extractelement <2 x i8> [[SH]], i32 0 358; CHECK-NEXT: ret i8 [[EX]] 359; 360 %ct = call <2 x i8> @llvm.cttz.v2i8(<2 x i8> %x, i1 true) 361 %sh = lshr <2 x i8> %ct, <i8 3, i8 0> 362 %ex = extractelement <2 x i8> %sh, i32 0 363 ret i8 %ex 364} 365 366; The shift amount is 0 on either of high/low bytes. The middle byte doesn't matter. 367 368define i24 @bitcast_noshift_scalar(<3 x i8> %v1, i24 %v2) { 369; CHECK-LABEL: @bitcast_noshift_scalar( 370; CHECK-NEXT: ret i24 [[V2:%.*]] 371; 372 %c = insertelement <3 x i8> poison, i8 0, i64 0 373 %s = shufflevector <3 x i8> %v1, <3 x i8> %c, <3 x i32> <i32 3, i32 1, i32 3> 374 %b = bitcast <3 x i8> %s to i24 375 %r = shl i24 %v2, %b 376 ret i24 %r 377} 378 379; The shift amount is 0 on low byte of big-endian and unknown on little-endian. 380 381define i24 @bitcast_noshift_scalar_bigend(<3 x i8> %v1, i24 %v2) { 382; BIGENDIAN-LABEL: @bitcast_noshift_scalar_bigend( 383; BIGENDIAN-NEXT: ret i24 [[V2:%.*]] 384; 385; LITTLEENDIAN-LABEL: @bitcast_noshift_scalar_bigend( 386; LITTLEENDIAN-NEXT: [[S:%.*]] = shufflevector <3 x i8> [[V1:%.*]], <3 x i8> <i8 0, i8 poison, i8 poison>, <3 x i32> <i32 0, i32 1, i32 3> 387; LITTLEENDIAN-NEXT: [[B:%.*]] = bitcast <3 x i8> [[S]] to i24 388; LITTLEENDIAN-NEXT: [[R:%.*]] = shl i24 [[V2:%.*]], [[B]] 389; LITTLEENDIAN-NEXT: ret i24 [[R]] 390; 391 %c = insertelement <3 x i8> poison, i8 0, i64 0 392 %s = shufflevector <3 x i8> %v1, <3 x i8> %c, <3 x i32> <i32 0, i32 1, i32 3> 393 %b = bitcast <3 x i8> %s to i24 394 %r = shl i24 %v2, %b 395 ret i24 %r 396} 397 398; The shift amount is 0 on low byte of little-endian and unknown on big-endian. 399 400define i24 @bitcast_noshift_scalar_littleend(<3 x i8> %v1, i24 %v2) { 401; BIGENDIAN-LABEL: @bitcast_noshift_scalar_littleend( 402; BIGENDIAN-NEXT: [[S:%.*]] = shufflevector <3 x i8> [[V1:%.*]], <3 x i8> <i8 0, i8 poison, i8 poison>, <3 x i32> <i32 3, i32 1, i32 2> 403; BIGENDIAN-NEXT: [[B:%.*]] = bitcast <3 x i8> [[S]] to i24 404; BIGENDIAN-NEXT: [[R:%.*]] = shl i24 [[V2:%.*]], [[B]] 405; BIGENDIAN-NEXT: ret i24 [[R]] 406; 407; LITTLEENDIAN-LABEL: @bitcast_noshift_scalar_littleend( 408; LITTLEENDIAN-NEXT: ret i24 [[V2:%.*]] 409; 410 %c = insertelement <3 x i8> poison, i8 0, i64 0 411 %s = shufflevector <3 x i8> %v1, <3 x i8> %c, <3 x i32> <i32 3, i32 1, i32 2> 412 %b = bitcast <3 x i8> %s to i24 413 %r = shl i24 %v2, %b 414 ret i24 %r 415} 416 417; The shift amount is known 24 on little-endian and known 24<<16 on big-endian 418; across all vector elements, so it's an overshift either way. 419 420define <3 x i24> @bitcast_overshift_vector(<9 x i8> %v1, <3 x i24> %v2) { 421; CHECK-LABEL: @bitcast_overshift_vector( 422; CHECK-NEXT: ret <3 x i24> poison 423; 424 %c = insertelement <9 x i8> poison, i8 24, i64 0 425 %s = shufflevector <9 x i8> %v1, <9 x i8> %c, <9 x i32> <i32 9, i32 1, i32 2, i32 9, i32 4, i32 5, i32 9, i32 7, i32 8> 426 %b = bitcast <9 x i8> %s to <3 x i24> 427 %r = shl <3 x i24> %v2, %b 428 ret <3 x i24> %r 429} 430 431; The shift amount is known 23 on little-endian and known 23<<16 on big-endian 432; across all vector elements, so it's an overshift for big-endian. 433 434define <3 x i24> @bitcast_overshift_vector_bigend(<9 x i8> %v1, <3 x i24> %v2) { 435; BIGENDIAN-LABEL: @bitcast_overshift_vector_bigend( 436; BIGENDIAN-NEXT: ret <3 x i24> poison 437; 438; LITTLEENDIAN-LABEL: @bitcast_overshift_vector_bigend( 439; LITTLEENDIAN-NEXT: [[S:%.*]] = shufflevector <9 x i8> [[V1:%.*]], <9 x i8> <i8 23, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison>, <9 x i32> <i32 9, i32 1, i32 2, i32 9, i32 4, i32 5, i32 9, i32 7, i32 8> 440; LITTLEENDIAN-NEXT: [[B:%.*]] = bitcast <9 x i8> [[S]] to <3 x i24> 441; LITTLEENDIAN-NEXT: [[R:%.*]] = shl <3 x i24> [[V2:%.*]], [[B]] 442; LITTLEENDIAN-NEXT: ret <3 x i24> [[R]] 443; 444 %c = insertelement <9 x i8> poison, i8 23, i64 0 445 %s = shufflevector <9 x i8> %v1, <9 x i8> %c, <9 x i32> <i32 9, i32 1, i32 2, i32 9, i32 4, i32 5, i32 9, i32 7, i32 8> 446 %b = bitcast <9 x i8> %s to <3 x i24> 447 %r = shl <3 x i24> %v2, %b 448 ret <3 x i24> %r 449} 450 451; The shift amount is known 23 on big-endian and known 23<<16 on little-endian 452; across all vector elements, so it's an overshift for little-endian. 453 454define <3 x i24> @bitcast_overshift_vector_littleend(<9 x i8> %v1, <3 x i24> %v2) { 455; BIGENDIAN-LABEL: @bitcast_overshift_vector_littleend( 456; BIGENDIAN-NEXT: [[S:%.*]] = shufflevector <9 x i8> [[V1:%.*]], <9 x i8> <i8 23, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison>, <9 x i32> <i32 0, i32 1, i32 9, i32 3, i32 4, i32 9, i32 6, i32 7, i32 9> 457; BIGENDIAN-NEXT: [[B:%.*]] = bitcast <9 x i8> [[S]] to <3 x i24> 458; BIGENDIAN-NEXT: [[R:%.*]] = shl <3 x i24> [[V2:%.*]], [[B]] 459; BIGENDIAN-NEXT: ret <3 x i24> [[R]] 460; 461; LITTLEENDIAN-LABEL: @bitcast_overshift_vector_littleend( 462; LITTLEENDIAN-NEXT: ret <3 x i24> poison 463; 464 %c = insertelement <9 x i8> poison, i8 23, i64 0 465 %s = shufflevector <9 x i8> %v1, <9 x i8> %c, <9 x i32> <i32 0, i32 1, i32 9, i32 3, i32 4, i32 9, i32 6, i32 7, i32 9> 466 %b = bitcast <9 x i8> %s to <3 x i24> 467 %r = shl <3 x i24> %v2, %b 468 ret <3 x i24> %r 469} 470 471; Negative test - the shift amount is known 24 or 24<<16 on only 2 out of 3 elements. 472 473define <3 x i24> @bitcast_partial_overshift_vector(<9 x i8> %v1, <3 x i24> %v2) { 474; CHECK-LABEL: @bitcast_partial_overshift_vector( 475; CHECK-NEXT: [[S:%.*]] = shufflevector <9 x i8> [[V1:%.*]], <9 x i8> <i8 24, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison, i8 poison>, <9 x i32> <i32 9, i32 1, i32 2, i32 9, i32 4, i32 5, i32 6, i32 7, i32 8> 476; CHECK-NEXT: [[B:%.*]] = bitcast <9 x i8> [[S]] to <3 x i24> 477; CHECK-NEXT: [[R:%.*]] = shl <3 x i24> [[V2:%.*]], [[B]] 478; CHECK-NEXT: ret <3 x i24> [[R]] 479; 480 %c = insertelement <9 x i8> poison, i8 24, i64 0 481 %s = shufflevector <9 x i8> %v1, <9 x i8> %c, <9 x i32> <i32 9, i32 1, i32 2, i32 9, i32 4, i32 5, i32 6, i32 7, i32 8> 482 %b = bitcast <9 x i8> %s to <3 x i24> 483 %r = shl <3 x i24> %v2, %b 484 ret <3 x i24> %r 485} 486 487; Negative test - don't know how to look through a cast with non-integer type (but we could handle this...). 488 489define <1 x i64> @bitcast_noshift_vector_wrong_type(<2 x float> %v1, <1 x i64> %v2) { 490; CHECK-LABEL: @bitcast_noshift_vector_wrong_type( 491; CHECK-NEXT: [[S:%.*]] = shufflevector <2 x float> [[V1:%.*]], <2 x float> <float 0.000000e+00, float poison>, <2 x i32> <i32 2, i32 1> 492; CHECK-NEXT: [[B:%.*]] = bitcast <2 x float> [[S]] to <1 x i64> 493; CHECK-NEXT: [[R:%.*]] = shl <1 x i64> [[V2:%.*]], [[B]] 494; CHECK-NEXT: ret <1 x i64> [[R]] 495; 496 %c = insertelement <2 x float> poison, float 0.0, i64 0 497 %s = shufflevector <2 x float> %v1, <2 x float> %c, <2 x i32> <i32 2, i32 1> 498 %b = bitcast <2 x float> %s to <1 x i64> 499 %r = shl <1 x i64> %v2, %b 500 ret <1 x i64> %r 501} 502