1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s 3 4; *Please* keep in sync with test/CodeGen/X86/extract-bits.ll 5 6; https://bugs.llvm.org/show_bug.cgi?id=36419 7; https://bugs.llvm.org/show_bug.cgi?id=37603 8; https://bugs.llvm.org/show_bug.cgi?id=37610 9 10; Patterns: 11; a) (x >> start) & (1 << nbits) - 1 12; b) (x >> start) & ~(-1 << nbits) 13; c) (x >> start) & (-1 >> (32 - y)) 14; d) (x >> start) << (32 - y) >> (32 - y) 15; are equivalent. 16 17; ---------------------------------------------------------------------------- ; 18; Pattern a. 32-bit 19; ---------------------------------------------------------------------------- ; 20 21define i32 @bextr32_a0(i32 %val, i32 %numskipbits, i32 %numlowbits) nounwind { 22; CHECK-LABEL: bextr32_a0: 23; CHECK: // %bb.0: 24; CHECK-NEXT: mov w9, #1 25; CHECK-NEXT: lsl w9, w9, w2 26; CHECK-NEXT: lsr w8, w0, w1 27; CHECK-NEXT: sub w9, w9, #1 // =1 28; CHECK-NEXT: and w0, w9, w8 29; CHECK-NEXT: ret 30 %shifted = lshr i32 %val, %numskipbits 31 %onebit = shl i32 1, %numlowbits 32 %mask = add nsw i32 %onebit, -1 33 %masked = and i32 %mask, %shifted 34 ret i32 %masked 35} 36 37define i32 @bextr32_a0_arithmetic(i32 %val, i32 %numskipbits, i32 %numlowbits) nounwind { 38; CHECK-LABEL: bextr32_a0_arithmetic: 39; CHECK: // %bb.0: 40; CHECK-NEXT: mov w9, #1 41; CHECK-NEXT: lsl w9, w9, w2 42; CHECK-NEXT: asr w8, w0, w1 43; CHECK-NEXT: sub w9, w9, #1 // =1 44; CHECK-NEXT: and w0, w9, w8 45; CHECK-NEXT: ret 46 %shifted = ashr i32 %val, %numskipbits 47 %onebit = shl i32 1, %numlowbits 48 %mask = add nsw i32 %onebit, -1 49 %masked = and i32 %mask, %shifted 50 ret i32 %masked 51} 52 53define i32 @bextr32_a1_indexzext(i32 %val, i8 zeroext %numskipbits, i8 zeroext %numlowbits) nounwind { 54; CHECK-LABEL: bextr32_a1_indexzext: 55; CHECK: // %bb.0: 56; CHECK-NEXT: mov w9, #1 57; CHECK-NEXT: lsl w9, w9, w2 58; CHECK-NEXT: lsr w8, w0, w1 59; CHECK-NEXT: sub w9, w9, #1 // =1 60; CHECK-NEXT: and w0, w9, w8 61; CHECK-NEXT: ret 62 %skip = zext i8 %numskipbits to i32 63 %shifted = lshr i32 %val, %skip 64 %conv = zext i8 %numlowbits to i32 65 %onebit = shl i32 1, %conv 66 %mask = add nsw i32 %onebit, -1 67 %masked = and i32 %mask, %shifted 68 ret i32 %masked 69} 70 71define i32 @bextr32_a2_load(i32* %w, i32 %numskipbits, i32 %numlowbits) nounwind { 72; CHECK-LABEL: bextr32_a2_load: 73; CHECK: // %bb.0: 74; CHECK-NEXT: ldr w8, [x0] 75; CHECK-NEXT: mov w9, #1 76; CHECK-NEXT: lsl w9, w9, w2 77; CHECK-NEXT: sub w9, w9, #1 // =1 78; CHECK-NEXT: lsr w8, w8, w1 79; CHECK-NEXT: and w0, w9, w8 80; CHECK-NEXT: ret 81 %val = load i32, i32* %w 82 %shifted = lshr i32 %val, %numskipbits 83 %onebit = shl i32 1, %numlowbits 84 %mask = add nsw i32 %onebit, -1 85 %masked = and i32 %mask, %shifted 86 ret i32 %masked 87} 88 89define i32 @bextr32_a3_load_indexzext(i32* %w, i8 zeroext %numskipbits, i8 zeroext %numlowbits) nounwind { 90; CHECK-LABEL: bextr32_a3_load_indexzext: 91; CHECK: // %bb.0: 92; CHECK-NEXT: ldr w8, [x0] 93; CHECK-NEXT: mov w9, #1 94; CHECK-NEXT: lsl w9, w9, w2 95; CHECK-NEXT: sub w9, w9, #1 // =1 96; CHECK-NEXT: lsr w8, w8, w1 97; CHECK-NEXT: and w0, w9, w8 98; CHECK-NEXT: ret 99 %val = load i32, i32* %w 100 %skip = zext i8 %numskipbits to i32 101 %shifted = lshr i32 %val, %skip 102 %conv = zext i8 %numlowbits to i32 103 %onebit = shl i32 1, %conv 104 %mask = add nsw i32 %onebit, -1 105 %masked = and i32 %mask, %shifted 106 ret i32 %masked 107} 108 109define i32 @bextr32_a4_commutative(i32 %val, i32 %numskipbits, i32 %numlowbits) nounwind { 110; CHECK-LABEL: bextr32_a4_commutative: 111; CHECK: // %bb.0: 112; CHECK-NEXT: mov w9, #1 113; CHECK-NEXT: lsl w9, w9, w2 114; CHECK-NEXT: lsr w8, w0, w1 115; CHECK-NEXT: sub w9, w9, #1 // =1 116; CHECK-NEXT: and w0, w8, w9 117; CHECK-NEXT: ret 118 %shifted = lshr i32 %val, %numskipbits 119 %onebit = shl i32 1, %numlowbits 120 %mask = add nsw i32 %onebit, -1 121 %masked = and i32 %shifted, %mask ; swapped order 122 ret i32 %masked 123} 124 125; 64-bit 126 127define i64 @bextr64_a0(i64 %val, i64 %numskipbits, i64 %numlowbits) nounwind { 128; CHECK-LABEL: bextr64_a0: 129; CHECK: // %bb.0: 130; CHECK-NEXT: mov w9, #1 131; CHECK-NEXT: lsl x9, x9, x2 132; CHECK-NEXT: lsr x8, x0, x1 133; CHECK-NEXT: sub x9, x9, #1 // =1 134; CHECK-NEXT: and x0, x9, x8 135; CHECK-NEXT: ret 136 %shifted = lshr i64 %val, %numskipbits 137 %onebit = shl i64 1, %numlowbits 138 %mask = add nsw i64 %onebit, -1 139 %masked = and i64 %mask, %shifted 140 ret i64 %masked 141} 142 143define i64 @bextr64_a0_arithmetic(i64 %val, i64 %numskipbits, i64 %numlowbits) nounwind { 144; CHECK-LABEL: bextr64_a0_arithmetic: 145; CHECK: // %bb.0: 146; CHECK-NEXT: mov w9, #1 147; CHECK-NEXT: lsl x9, x9, x2 148; CHECK-NEXT: asr x8, x0, x1 149; CHECK-NEXT: sub x9, x9, #1 // =1 150; CHECK-NEXT: and x0, x9, x8 151; CHECK-NEXT: ret 152 %shifted = ashr i64 %val, %numskipbits 153 %onebit = shl i64 1, %numlowbits 154 %mask = add nsw i64 %onebit, -1 155 %masked = and i64 %mask, %shifted 156 ret i64 %masked 157} 158 159define i64 @bextr64_a1_indexzext(i64 %val, i8 zeroext %numskipbits, i8 zeroext %numlowbits) nounwind { 160; CHECK-LABEL: bextr64_a1_indexzext: 161; CHECK: // %bb.0: 162; CHECK-NEXT: mov w9, #1 163; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 164; CHECK-NEXT: lsl x9, x9, x2 165; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 166; CHECK-NEXT: lsr x8, x0, x1 167; CHECK-NEXT: sub x9, x9, #1 // =1 168; CHECK-NEXT: and x0, x9, x8 169; CHECK-NEXT: ret 170 %skip = zext i8 %numskipbits to i64 171 %shifted = lshr i64 %val, %skip 172 %conv = zext i8 %numlowbits to i64 173 %onebit = shl i64 1, %conv 174 %mask = add nsw i64 %onebit, -1 175 %masked = and i64 %mask, %shifted 176 ret i64 %masked 177} 178 179define i64 @bextr64_a2_load(i64* %w, i64 %numskipbits, i64 %numlowbits) nounwind { 180; CHECK-LABEL: bextr64_a2_load: 181; CHECK: // %bb.0: 182; CHECK-NEXT: ldr x8, [x0] 183; CHECK-NEXT: mov w9, #1 184; CHECK-NEXT: lsl x9, x9, x2 185; CHECK-NEXT: sub x9, x9, #1 // =1 186; CHECK-NEXT: lsr x8, x8, x1 187; CHECK-NEXT: and x0, x9, x8 188; CHECK-NEXT: ret 189 %val = load i64, i64* %w 190 %shifted = lshr i64 %val, %numskipbits 191 %onebit = shl i64 1, %numlowbits 192 %mask = add nsw i64 %onebit, -1 193 %masked = and i64 %mask, %shifted 194 ret i64 %masked 195} 196 197define i64 @bextr64_a3_load_indexzext(i64* %w, i8 zeroext %numskipbits, i8 zeroext %numlowbits) nounwind { 198; CHECK-LABEL: bextr64_a3_load_indexzext: 199; CHECK: // %bb.0: 200; CHECK-NEXT: ldr x8, [x0] 201; CHECK-NEXT: mov w9, #1 202; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 203; CHECK-NEXT: lsl x9, x9, x2 204; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 205; CHECK-NEXT: sub x9, x9, #1 // =1 206; CHECK-NEXT: lsr x8, x8, x1 207; CHECK-NEXT: and x0, x9, x8 208; CHECK-NEXT: ret 209 %val = load i64, i64* %w 210 %skip = zext i8 %numskipbits to i64 211 %shifted = lshr i64 %val, %skip 212 %conv = zext i8 %numlowbits to i64 213 %onebit = shl i64 1, %conv 214 %mask = add nsw i64 %onebit, -1 215 %masked = and i64 %mask, %shifted 216 ret i64 %masked 217} 218 219define i64 @bextr64_a4_commutative(i64 %val, i64 %numskipbits, i64 %numlowbits) nounwind { 220; CHECK-LABEL: bextr64_a4_commutative: 221; CHECK: // %bb.0: 222; CHECK-NEXT: mov w9, #1 223; CHECK-NEXT: lsl x9, x9, x2 224; CHECK-NEXT: lsr x8, x0, x1 225; CHECK-NEXT: sub x9, x9, #1 // =1 226; CHECK-NEXT: and x0, x8, x9 227; CHECK-NEXT: ret 228 %shifted = lshr i64 %val, %numskipbits 229 %onebit = shl i64 1, %numlowbits 230 %mask = add nsw i64 %onebit, -1 231 %masked = and i64 %shifted, %mask ; swapped order 232 ret i64 %masked 233} 234 235; 64-bit, but with 32-bit output 236 237; Everything done in 64-bit, truncation happens last. 238define i32 @bextr64_32_a0(i64 %val, i64 %numskipbits, i64 %numlowbits) nounwind { 239; CHECK-LABEL: bextr64_32_a0: 240; CHECK: // %bb.0: 241; CHECK-NEXT: mov w9, #1 242; CHECK-NEXT: lsl x9, x9, x2 243; CHECK-NEXT: lsr x8, x0, x1 244; CHECK-NEXT: sub w9, w9, #1 // =1 245; CHECK-NEXT: and w0, w9, w8 246; CHECK-NEXT: ret 247 %shifted = lshr i64 %val, %numskipbits 248 %onebit = shl i64 1, %numlowbits 249 %mask = add nsw i64 %onebit, -1 250 %masked = and i64 %mask, %shifted 251 %res = trunc i64 %masked to i32 252 ret i32 %res 253} 254 255; Shifting happens in 64-bit, then truncation. Masking is 32-bit. 256define i32 @bextr64_32_a1(i64 %val, i64 %numskipbits, i32 %numlowbits) nounwind { 257; CHECK-LABEL: bextr64_32_a1: 258; CHECK: // %bb.0: 259; CHECK-NEXT: mov w9, #1 260; CHECK-NEXT: lsl w9, w9, w2 261; CHECK-NEXT: lsr x8, x0, x1 262; CHECK-NEXT: sub w9, w9, #1 // =1 263; CHECK-NEXT: and w0, w9, w8 264; CHECK-NEXT: ret 265 %shifted = lshr i64 %val, %numskipbits 266 %truncshifted = trunc i64 %shifted to i32 267 %onebit = shl i32 1, %numlowbits 268 %mask = add nsw i32 %onebit, -1 269 %masked = and i32 %mask, %truncshifted 270 ret i32 %masked 271} 272 273; Shifting happens in 64-bit. Mask is 32-bit, but extended to 64-bit. 274; Masking is 64-bit. Then truncation. 275define i32 @bextr64_32_a2(i64 %val, i64 %numskipbits, i32 %numlowbits) nounwind { 276; CHECK-LABEL: bextr64_32_a2: 277; CHECK: // %bb.0: 278; CHECK-NEXT: mov w9, #1 279; CHECK-NEXT: lsl w9, w9, w2 280; CHECK-NEXT: lsr x8, x0, x1 281; CHECK-NEXT: sub w9, w9, #1 // =1 282; CHECK-NEXT: and w0, w9, w8 283; CHECK-NEXT: ret 284 %shifted = lshr i64 %val, %numskipbits 285 %onebit = shl i32 1, %numlowbits 286 %mask = add nsw i32 %onebit, -1 287 %zextmask = zext i32 %mask to i64 288 %masked = and i64 %zextmask, %shifted 289 %truncmasked = trunc i64 %masked to i32 290 ret i32 %truncmasked 291} 292 293; ---------------------------------------------------------------------------- ; 294; Pattern b. 32-bit 295; ---------------------------------------------------------------------------- ; 296 297define i32 @bextr32_b0(i32 %val, i32 %numskipbits, i32 %numlowbits) nounwind { 298; CHECK-LABEL: bextr32_b0: 299; CHECK: // %bb.0: 300; CHECK-NEXT: mov w9, #-1 301; CHECK-NEXT: lsr w8, w0, w1 302; CHECK-NEXT: lsl w9, w9, w2 303; CHECK-NEXT: bic w0, w8, w9 304; CHECK-NEXT: ret 305 %shifted = lshr i32 %val, %numskipbits 306 %notmask = shl i32 -1, %numlowbits 307 %mask = xor i32 %notmask, -1 308 %masked = and i32 %mask, %shifted 309 ret i32 %masked 310} 311 312define i32 @bextr32_b1_indexzext(i32 %val, i8 zeroext %numskipbits, i8 zeroext %numlowbits) nounwind { 313; CHECK-LABEL: bextr32_b1_indexzext: 314; CHECK: // %bb.0: 315; CHECK-NEXT: mov w9, #-1 316; CHECK-NEXT: lsr w8, w0, w1 317; CHECK-NEXT: lsl w9, w9, w2 318; CHECK-NEXT: bic w0, w8, w9 319; CHECK-NEXT: ret 320 %skip = zext i8 %numskipbits to i32 321 %shifted = lshr i32 %val, %skip 322 %conv = zext i8 %numlowbits to i32 323 %notmask = shl i32 -1, %conv 324 %mask = xor i32 %notmask, -1 325 %masked = and i32 %mask, %shifted 326 ret i32 %masked 327} 328 329define i32 @bextr32_b2_load(i32* %w, i32 %numskipbits, i32 %numlowbits) nounwind { 330; CHECK-LABEL: bextr32_b2_load: 331; CHECK: // %bb.0: 332; CHECK-NEXT: ldr w8, [x0] 333; CHECK-NEXT: mov w9, #-1 334; CHECK-NEXT: lsl w9, w9, w2 335; CHECK-NEXT: lsr w8, w8, w1 336; CHECK-NEXT: bic w0, w8, w9 337; CHECK-NEXT: ret 338 %val = load i32, i32* %w 339 %shifted = lshr i32 %val, %numskipbits 340 %notmask = shl i32 -1, %numlowbits 341 %mask = xor i32 %notmask, -1 342 %masked = and i32 %mask, %shifted 343 ret i32 %masked 344} 345 346define i32 @bextr32_b3_load_indexzext(i32* %w, i8 zeroext %numskipbits, i8 zeroext %numlowbits) nounwind { 347; CHECK-LABEL: bextr32_b3_load_indexzext: 348; CHECK: // %bb.0: 349; CHECK-NEXT: ldr w8, [x0] 350; CHECK-NEXT: mov w9, #-1 351; CHECK-NEXT: lsl w9, w9, w2 352; CHECK-NEXT: lsr w8, w8, w1 353; CHECK-NEXT: bic w0, w8, w9 354; CHECK-NEXT: ret 355 %val = load i32, i32* %w 356 %skip = zext i8 %numskipbits to i32 357 %shifted = lshr i32 %val, %skip 358 %conv = zext i8 %numlowbits to i32 359 %notmask = shl i32 -1, %conv 360 %mask = xor i32 %notmask, -1 361 %masked = and i32 %mask, %shifted 362 ret i32 %masked 363} 364 365define i32 @bextr32_b4_commutative(i32 %val, i32 %numskipbits, i32 %numlowbits) nounwind { 366; CHECK-LABEL: bextr32_b4_commutative: 367; CHECK: // %bb.0: 368; CHECK-NEXT: mov w9, #-1 369; CHECK-NEXT: lsr w8, w0, w1 370; CHECK-NEXT: lsl w9, w9, w2 371; CHECK-NEXT: bic w0, w8, w9 372; CHECK-NEXT: ret 373 %shifted = lshr i32 %val, %numskipbits 374 %notmask = shl i32 -1, %numlowbits 375 %mask = xor i32 %notmask, -1 376 %masked = and i32 %shifted, %mask ; swapped order 377 ret i32 %masked 378} 379 380; 64-bit 381 382define i64 @bextr64_b0(i64 %val, i64 %numskipbits, i64 %numlowbits) nounwind { 383; CHECK-LABEL: bextr64_b0: 384; CHECK: // %bb.0: 385; CHECK-NEXT: mov x9, #-1 386; CHECK-NEXT: lsr x8, x0, x1 387; CHECK-NEXT: lsl x9, x9, x2 388; CHECK-NEXT: bic x0, x8, x9 389; CHECK-NEXT: ret 390 %shifted = lshr i64 %val, %numskipbits 391 %notmask = shl i64 -1, %numlowbits 392 %mask = xor i64 %notmask, -1 393 %masked = and i64 %mask, %shifted 394 ret i64 %masked 395} 396 397define i64 @bextr64_b1_indexzext(i64 %val, i8 zeroext %numskipbits, i8 zeroext %numlowbits) nounwind { 398; CHECK-LABEL: bextr64_b1_indexzext: 399; CHECK: // %bb.0: 400; CHECK-NEXT: mov x9, #-1 401; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 402; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 403; CHECK-NEXT: lsr x8, x0, x1 404; CHECK-NEXT: lsl x9, x9, x2 405; CHECK-NEXT: bic x0, x8, x9 406; CHECK-NEXT: ret 407 %skip = zext i8 %numskipbits to i64 408 %shifted = lshr i64 %val, %skip 409 %conv = zext i8 %numlowbits to i64 410 %notmask = shl i64 -1, %conv 411 %mask = xor i64 %notmask, -1 412 %masked = and i64 %mask, %shifted 413 ret i64 %masked 414} 415 416define i64 @bextr64_b2_load(i64* %w, i64 %numskipbits, i64 %numlowbits) nounwind { 417; CHECK-LABEL: bextr64_b2_load: 418; CHECK: // %bb.0: 419; CHECK-NEXT: ldr x8, [x0] 420; CHECK-NEXT: mov x9, #-1 421; CHECK-NEXT: lsl x9, x9, x2 422; CHECK-NEXT: lsr x8, x8, x1 423; CHECK-NEXT: bic x0, x8, x9 424; CHECK-NEXT: ret 425 %val = load i64, i64* %w 426 %shifted = lshr i64 %val, %numskipbits 427 %notmask = shl i64 -1, %numlowbits 428 %mask = xor i64 %notmask, -1 429 %masked = and i64 %mask, %shifted 430 ret i64 %masked 431} 432 433define i64 @bextr64_b3_load_indexzext(i64* %w, i8 zeroext %numskipbits, i8 zeroext %numlowbits) nounwind { 434; CHECK-LABEL: bextr64_b3_load_indexzext: 435; CHECK: // %bb.0: 436; CHECK-NEXT: ldr x8, [x0] 437; CHECK-NEXT: mov x9, #-1 438; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 439; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 440; CHECK-NEXT: lsl x9, x9, x2 441; CHECK-NEXT: lsr x8, x8, x1 442; CHECK-NEXT: bic x0, x8, x9 443; CHECK-NEXT: ret 444 %val = load i64, i64* %w 445 %skip = zext i8 %numskipbits to i64 446 %shifted = lshr i64 %val, %skip 447 %conv = zext i8 %numlowbits to i64 448 %notmask = shl i64 -1, %conv 449 %mask = xor i64 %notmask, -1 450 %masked = and i64 %mask, %shifted 451 ret i64 %masked 452} 453 454define i64 @bextr64_b4_commutative(i64 %val, i64 %numskipbits, i64 %numlowbits) nounwind { 455; CHECK-LABEL: bextr64_b4_commutative: 456; CHECK: // %bb.0: 457; CHECK-NEXT: mov x9, #-1 458; CHECK-NEXT: lsr x8, x0, x1 459; CHECK-NEXT: lsl x9, x9, x2 460; CHECK-NEXT: bic x0, x8, x9 461; CHECK-NEXT: ret 462 %shifted = lshr i64 %val, %numskipbits 463 %notmask = shl i64 -1, %numlowbits 464 %mask = xor i64 %notmask, -1 465 %masked = and i64 %shifted, %mask ; swapped order 466 ret i64 %masked 467} 468 469; 64-bit, but with 32-bit output 470 471; Everything done in 64-bit, truncation happens last. 472define i32 @bextr64_32_b0(i64 %val, i64 %numskipbits, i8 %numlowbits) nounwind { 473; CHECK-LABEL: bextr64_32_b0: 474; CHECK: // %bb.0: 475; CHECK-NEXT: mov x9, #-1 476; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 477; CHECK-NEXT: lsr x8, x0, x1 478; CHECK-NEXT: lsl x9, x9, x2 479; CHECK-NEXT: bic w0, w8, w9 480; CHECK-NEXT: ret 481 %shiftedval = lshr i64 %val, %numskipbits 482 %widenumlowbits = zext i8 %numlowbits to i64 483 %notmask = shl nsw i64 -1, %widenumlowbits 484 %mask = xor i64 %notmask, -1 485 %wideres = and i64 %shiftedval, %mask 486 %res = trunc i64 %wideres to i32 487 ret i32 %res 488} 489 490; Shifting happens in 64-bit, then truncation. Masking is 32-bit. 491define i32 @bextr64_32_b1(i64 %val, i64 %numskipbits, i8 %numlowbits) nounwind { 492; CHECK-LABEL: bextr64_32_b1: 493; CHECK: // %bb.0: 494; CHECK-NEXT: mov w9, #-1 495; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 496; CHECK-NEXT: lsr x8, x0, x1 497; CHECK-NEXT: lsl w9, w9, w2 498; CHECK-NEXT: bic w0, w8, w9 499; CHECK-NEXT: ret 500 %shiftedval = lshr i64 %val, %numskipbits 501 %truncshiftedval = trunc i64 %shiftedval to i32 502 %widenumlowbits = zext i8 %numlowbits to i32 503 %notmask = shl nsw i32 -1, %widenumlowbits 504 %mask = xor i32 %notmask, -1 505 %res = and i32 %truncshiftedval, %mask 506 ret i32 %res 507} 508 509; Shifting happens in 64-bit. Mask is 32-bit, but extended to 64-bit. 510; Masking is 64-bit. Then truncation. 511define i32 @bextr64_32_b2(i64 %val, i64 %numskipbits, i8 %numlowbits) nounwind { 512; CHECK-LABEL: bextr64_32_b2: 513; CHECK: // %bb.0: 514; CHECK-NEXT: mov w9, #-1 515; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2 516; CHECK-NEXT: lsr x8, x0, x1 517; CHECK-NEXT: lsl w9, w9, w2 518; CHECK-NEXT: bic w0, w8, w9 519; CHECK-NEXT: ret 520 %shiftedval = lshr i64 %val, %numskipbits 521 %widenumlowbits = zext i8 %numlowbits to i32 522 %notmask = shl nsw i32 -1, %widenumlowbits 523 %mask = xor i32 %notmask, -1 524 %zextmask = zext i32 %mask to i64 525 %wideres = and i64 %shiftedval, %zextmask 526 %res = trunc i64 %wideres to i32 527 ret i32 %res 528} 529 530; ---------------------------------------------------------------------------- ; 531; Pattern c. 32-bit 532; ---------------------------------------------------------------------------- ; 533 534define i32 @bextr32_c0(i32 %val, i32 %numskipbits, i32 %numlowbits) nounwind { 535; CHECK-LABEL: bextr32_c0: 536; CHECK: // %bb.0: 537; CHECK-NEXT: neg w9, w2 538; CHECK-NEXT: mov w10, #-1 539; CHECK-NEXT: lsr w8, w0, w1 540; CHECK-NEXT: lsr w9, w10, w9 541; CHECK-NEXT: and w0, w9, w8 542; CHECK-NEXT: ret 543 %shifted = lshr i32 %val, %numskipbits 544 %numhighbits = sub i32 32, %numlowbits 545 %mask = lshr i32 -1, %numhighbits 546 %masked = and i32 %mask, %shifted 547 ret i32 %masked 548} 549 550define i32 @bextr32_c1_indexzext(i32 %val, i8 %numskipbits, i8 %numlowbits) nounwind { 551; CHECK-LABEL: bextr32_c1_indexzext: 552; CHECK: // %bb.0: 553; CHECK-NEXT: mov w9, #32 554; CHECK-NEXT: sub w9, w9, w2 555; CHECK-NEXT: mov w10, #-1 556; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 557; CHECK-NEXT: lsr w8, w0, w1 558; CHECK-NEXT: lsr w9, w10, w9 559; CHECK-NEXT: and w0, w9, w8 560; CHECK-NEXT: ret 561 %skip = zext i8 %numskipbits to i32 562 %shifted = lshr i32 %val, %skip 563 %numhighbits = sub i8 32, %numlowbits 564 %sh_prom = zext i8 %numhighbits to i32 565 %mask = lshr i32 -1, %sh_prom 566 %masked = and i32 %mask, %shifted 567 ret i32 %masked 568} 569 570define i32 @bextr32_c2_load(i32* %w, i32 %numskipbits, i32 %numlowbits) nounwind { 571; CHECK-LABEL: bextr32_c2_load: 572; CHECK: // %bb.0: 573; CHECK-NEXT: ldr w8, [x0] 574; CHECK-NEXT: neg w9, w2 575; CHECK-NEXT: mov w10, #-1 576; CHECK-NEXT: lsr w9, w10, w9 577; CHECK-NEXT: lsr w8, w8, w1 578; CHECK-NEXT: and w0, w9, w8 579; CHECK-NEXT: ret 580 %val = load i32, i32* %w 581 %shifted = lshr i32 %val, %numskipbits 582 %numhighbits = sub i32 32, %numlowbits 583 %mask = lshr i32 -1, %numhighbits 584 %masked = and i32 %mask, %shifted 585 ret i32 %masked 586} 587 588define i32 @bextr32_c3_load_indexzext(i32* %w, i8 %numskipbits, i8 %numlowbits) nounwind { 589; CHECK-LABEL: bextr32_c3_load_indexzext: 590; CHECK: // %bb.0: 591; CHECK-NEXT: ldr w8, [x0] 592; CHECK-NEXT: mov w9, #32 593; CHECK-NEXT: mov w10, #-1 594; CHECK-NEXT: sub w9, w9, w2 595; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 596; CHECK-NEXT: lsr w8, w8, w1 597; CHECK-NEXT: lsr w9, w10, w9 598; CHECK-NEXT: and w0, w9, w8 599; CHECK-NEXT: ret 600 %val = load i32, i32* %w 601 %skip = zext i8 %numskipbits to i32 602 %shifted = lshr i32 %val, %skip 603 %numhighbits = sub i8 32, %numlowbits 604 %sh_prom = zext i8 %numhighbits to i32 605 %mask = lshr i32 -1, %sh_prom 606 %masked = and i32 %mask, %shifted 607 ret i32 %masked 608} 609 610define i32 @bextr32_c4_commutative(i32 %val, i32 %numskipbits, i32 %numlowbits) nounwind { 611; CHECK-LABEL: bextr32_c4_commutative: 612; CHECK: // %bb.0: 613; CHECK-NEXT: neg w9, w2 614; CHECK-NEXT: mov w10, #-1 615; CHECK-NEXT: lsr w8, w0, w1 616; CHECK-NEXT: lsr w9, w10, w9 617; CHECK-NEXT: and w0, w8, w9 618; CHECK-NEXT: ret 619 %shifted = lshr i32 %val, %numskipbits 620 %numhighbits = sub i32 32, %numlowbits 621 %mask = lshr i32 -1, %numhighbits 622 %masked = and i32 %shifted, %mask ; swapped order 623 ret i32 %masked 624} 625 626; 64-bit 627 628define i64 @bextr64_c0(i64 %val, i64 %numskipbits, i64 %numlowbits) nounwind { 629; CHECK-LABEL: bextr64_c0: 630; CHECK: // %bb.0: 631; CHECK-NEXT: neg x9, x2 632; CHECK-NEXT: mov x10, #-1 633; CHECK-NEXT: lsr x8, x0, x1 634; CHECK-NEXT: lsr x9, x10, x9 635; CHECK-NEXT: and x0, x9, x8 636; CHECK-NEXT: ret 637 %shifted = lshr i64 %val, %numskipbits 638 %numhighbits = sub i64 64, %numlowbits 639 %mask = lshr i64 -1, %numhighbits 640 %masked = and i64 %mask, %shifted 641 ret i64 %masked 642} 643 644define i64 @bextr64_c1_indexzext(i64 %val, i8 %numskipbits, i8 %numlowbits) nounwind { 645; CHECK-LABEL: bextr64_c1_indexzext: 646; CHECK: // %bb.0: 647; CHECK-NEXT: mov w9, #64 648; CHECK-NEXT: sub w9, w9, w2 649; CHECK-NEXT: mov x10, #-1 650; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 651; CHECK-NEXT: lsr x8, x0, x1 652; CHECK-NEXT: lsr x9, x10, x9 653; CHECK-NEXT: and x0, x9, x8 654; CHECK-NEXT: ret 655 %skip = zext i8 %numskipbits to i64 656 %shifted = lshr i64 %val, %skip 657 %numhighbits = sub i8 64, %numlowbits 658 %sh_prom = zext i8 %numhighbits to i64 659 %mask = lshr i64 -1, %sh_prom 660 %masked = and i64 %mask, %shifted 661 ret i64 %masked 662} 663 664define i64 @bextr64_c2_load(i64* %w, i64 %numskipbits, i64 %numlowbits) nounwind { 665; CHECK-LABEL: bextr64_c2_load: 666; CHECK: // %bb.0: 667; CHECK-NEXT: ldr x8, [x0] 668; CHECK-NEXT: neg x9, x2 669; CHECK-NEXT: mov x10, #-1 670; CHECK-NEXT: lsr x9, x10, x9 671; CHECK-NEXT: lsr x8, x8, x1 672; CHECK-NEXT: and x0, x9, x8 673; CHECK-NEXT: ret 674 %val = load i64, i64* %w 675 %shifted = lshr i64 %val, %numskipbits 676 %numhighbits = sub i64 64, %numlowbits 677 %mask = lshr i64 -1, %numhighbits 678 %masked = and i64 %mask, %shifted 679 ret i64 %masked 680} 681 682define i64 @bextr64_c3_load_indexzext(i64* %w, i8 %numskipbits, i8 %numlowbits) nounwind { 683; CHECK-LABEL: bextr64_c3_load_indexzext: 684; CHECK: // %bb.0: 685; CHECK-NEXT: ldr x8, [x0] 686; CHECK-NEXT: mov w9, #64 687; CHECK-NEXT: mov x10, #-1 688; CHECK-NEXT: sub w9, w9, w2 689; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 690; CHECK-NEXT: lsr x8, x8, x1 691; CHECK-NEXT: lsr x9, x10, x9 692; CHECK-NEXT: and x0, x9, x8 693; CHECK-NEXT: ret 694 %val = load i64, i64* %w 695 %skip = zext i8 %numskipbits to i64 696 %shifted = lshr i64 %val, %skip 697 %numhighbits = sub i8 64, %numlowbits 698 %sh_prom = zext i8 %numhighbits to i64 699 %mask = lshr i64 -1, %sh_prom 700 %masked = and i64 %mask, %shifted 701 ret i64 %masked 702} 703 704define i64 @bextr64_c4_commutative(i64 %val, i64 %numskipbits, i64 %numlowbits) nounwind { 705; CHECK-LABEL: bextr64_c4_commutative: 706; CHECK: // %bb.0: 707; CHECK-NEXT: neg x9, x2 708; CHECK-NEXT: mov x10, #-1 709; CHECK-NEXT: lsr x8, x0, x1 710; CHECK-NEXT: lsr x9, x10, x9 711; CHECK-NEXT: and x0, x8, x9 712; CHECK-NEXT: ret 713 %shifted = lshr i64 %val, %numskipbits 714 %numhighbits = sub i64 64, %numlowbits 715 %mask = lshr i64 -1, %numhighbits 716 %masked = and i64 %shifted, %mask ; swapped order 717 ret i64 %masked 718} 719 720; 64-bit, but with 32-bit output 721 722; Everything done in 64-bit, truncation happens last. 723define i32 @bextr64_32_c0(i64 %val, i64 %numskipbits, i64 %numlowbits) nounwind { 724; CHECK-LABEL: bextr64_32_c0: 725; CHECK: // %bb.0: 726; CHECK-NEXT: neg x9, x2 727; CHECK-NEXT: mov x10, #-1 728; CHECK-NEXT: lsr x8, x0, x1 729; CHECK-NEXT: lsr x9, x10, x9 730; CHECK-NEXT: and w0, w9, w8 731; CHECK-NEXT: ret 732 %shifted = lshr i64 %val, %numskipbits 733 %numhighbits = sub i64 64, %numlowbits 734 %mask = lshr i64 -1, %numhighbits 735 %masked = and i64 %mask, %shifted 736 %res = trunc i64 %masked to i32 737 ret i32 %res 738} 739 740; Shifting happens in 64-bit, then truncation. Masking is 32-bit. 741define i32 @bextr64_32_c1(i64 %val, i64 %numskipbits, i32 %numlowbits) nounwind { 742; CHECK-LABEL: bextr64_32_c1: 743; CHECK: // %bb.0: 744; CHECK-NEXT: neg w9, w2 745; CHECK-NEXT: mov w10, #-1 746; CHECK-NEXT: lsr x8, x0, x1 747; CHECK-NEXT: lsr w9, w10, w9 748; CHECK-NEXT: and w0, w9, w8 749; CHECK-NEXT: ret 750 %shifted = lshr i64 %val, %numskipbits 751 %truncshifted = trunc i64 %shifted to i32 752 %numhighbits = sub i32 32, %numlowbits 753 %mask = lshr i32 -1, %numhighbits 754 %masked = and i32 %mask, %truncshifted 755 ret i32 %masked 756} 757 758; Shifting happens in 64-bit. Mask is 32-bit, but extended to 64-bit. 759; Masking is 64-bit. Then truncation. 760define i32 @bextr64_32_c2(i64 %val, i64 %numskipbits, i32 %numlowbits) nounwind { 761; CHECK-LABEL: bextr64_32_c2: 762; CHECK: // %bb.0: 763; CHECK-NEXT: neg w9, w2 764; CHECK-NEXT: mov w10, #-1 765; CHECK-NEXT: lsr x8, x0, x1 766; CHECK-NEXT: lsr w9, w10, w9 767; CHECK-NEXT: and w0, w9, w8 768; CHECK-NEXT: ret 769 %shifted = lshr i64 %val, %numskipbits 770 %numhighbits = sub i32 32, %numlowbits 771 %mask = lshr i32 -1, %numhighbits 772 %zextmask = zext i32 %mask to i64 773 %masked = and i64 %zextmask, %shifted 774 %truncmasked = trunc i64 %masked to i32 775 ret i32 %truncmasked 776} 777 778; ---------------------------------------------------------------------------- ; 779; Pattern d. 32-bit. 780; ---------------------------------------------------------------------------- ; 781 782define i32 @bextr32_d0(i32 %val, i32 %numskipbits, i32 %numlowbits) nounwind { 783; CHECK-LABEL: bextr32_d0: 784; CHECK: // %bb.0: 785; CHECK-NEXT: lsr w8, w0, w1 786; CHECK-NEXT: neg w9, w2 787; CHECK-NEXT: lsl w8, w8, w9 788; CHECK-NEXT: lsr w0, w8, w9 789; CHECK-NEXT: ret 790 %shifted = lshr i32 %val, %numskipbits 791 %numhighbits = sub i32 32, %numlowbits 792 %highbitscleared = shl i32 %shifted, %numhighbits 793 %masked = lshr i32 %highbitscleared, %numhighbits 794 ret i32 %masked 795} 796 797define i32 @bextr32_d1_indexzext(i32 %val, i8 %numskipbits, i8 %numlowbits) nounwind { 798; CHECK-LABEL: bextr32_d1_indexzext: 799; CHECK: // %bb.0: 800; CHECK-NEXT: mov w9, #32 801; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 802; CHECK-NEXT: lsr w8, w0, w1 803; CHECK-NEXT: sub w9, w9, w2 804; CHECK-NEXT: lsl w8, w8, w9 805; CHECK-NEXT: lsr w0, w8, w9 806; CHECK-NEXT: ret 807 %skip = zext i8 %numskipbits to i32 808 %shifted = lshr i32 %val, %skip 809 %numhighbits = sub i8 32, %numlowbits 810 %sh_prom = zext i8 %numhighbits to i32 811 %highbitscleared = shl i32 %shifted, %sh_prom 812 %masked = lshr i32 %highbitscleared, %sh_prom 813 ret i32 %masked 814} 815 816define i32 @bextr32_d2_load(i32* %w, i32 %numskipbits, i32 %numlowbits) nounwind { 817; CHECK-LABEL: bextr32_d2_load: 818; CHECK: // %bb.0: 819; CHECK-NEXT: ldr w8, [x0] 820; CHECK-NEXT: neg w9, w2 821; CHECK-NEXT: lsr w8, w8, w1 822; CHECK-NEXT: lsl w8, w8, w9 823; CHECK-NEXT: lsr w0, w8, w9 824; CHECK-NEXT: ret 825 %val = load i32, i32* %w 826 %shifted = lshr i32 %val, %numskipbits 827 %numhighbits = sub i32 32, %numlowbits 828 %highbitscleared = shl i32 %shifted, %numhighbits 829 %masked = lshr i32 %highbitscleared, %numhighbits 830 ret i32 %masked 831} 832 833define i32 @bextr32_d3_load_indexzext(i32* %w, i8 %numskipbits, i8 %numlowbits) nounwind { 834; CHECK-LABEL: bextr32_d3_load_indexzext: 835; CHECK: // %bb.0: 836; CHECK-NEXT: ldr w8, [x0] 837; CHECK-NEXT: mov w9, #32 838; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 839; CHECK-NEXT: sub w9, w9, w2 840; CHECK-NEXT: lsr w8, w8, w1 841; CHECK-NEXT: lsl w8, w8, w9 842; CHECK-NEXT: lsr w0, w8, w9 843; CHECK-NEXT: ret 844 %val = load i32, i32* %w 845 %skip = zext i8 %numskipbits to i32 846 %shifted = lshr i32 %val, %skip 847 %numhighbits = sub i8 32, %numlowbits 848 %sh_prom = zext i8 %numhighbits to i32 849 %highbitscleared = shl i32 %shifted, %sh_prom 850 %masked = lshr i32 %highbitscleared, %sh_prom 851 ret i32 %masked 852} 853 854; 64-bit. 855 856define i64 @bextr64_d0(i64 %val, i64 %numskipbits, i64 %numlowbits) nounwind { 857; CHECK-LABEL: bextr64_d0: 858; CHECK: // %bb.0: 859; CHECK-NEXT: lsr x8, x0, x1 860; CHECK-NEXT: neg x9, x2 861; CHECK-NEXT: lsl x8, x8, x9 862; CHECK-NEXT: lsr x0, x8, x9 863; CHECK-NEXT: ret 864 %shifted = lshr i64 %val, %numskipbits 865 %numhighbits = sub i64 64, %numlowbits 866 %highbitscleared = shl i64 %shifted, %numhighbits 867 %masked = lshr i64 %highbitscleared, %numhighbits 868 ret i64 %masked 869} 870 871define i64 @bextr64_d1_indexzext(i64 %val, i8 %numskipbits, i8 %numlowbits) nounwind { 872; CHECK-LABEL: bextr64_d1_indexzext: 873; CHECK: // %bb.0: 874; CHECK-NEXT: mov w9, #64 875; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 876; CHECK-NEXT: lsr x8, x0, x1 877; CHECK-NEXT: sub w9, w9, w2 878; CHECK-NEXT: lsl x8, x8, x9 879; CHECK-NEXT: lsr x0, x8, x9 880; CHECK-NEXT: ret 881 %skip = zext i8 %numskipbits to i64 882 %shifted = lshr i64 %val, %skip 883 %numhighbits = sub i8 64, %numlowbits 884 %sh_prom = zext i8 %numhighbits to i64 885 %highbitscleared = shl i64 %shifted, %sh_prom 886 %masked = lshr i64 %highbitscleared, %sh_prom 887 ret i64 %masked 888} 889 890define i64 @bextr64_d2_load(i64* %w, i64 %numskipbits, i64 %numlowbits) nounwind { 891; CHECK-LABEL: bextr64_d2_load: 892; CHECK: // %bb.0: 893; CHECK-NEXT: ldr x8, [x0] 894; CHECK-NEXT: neg x9, x2 895; CHECK-NEXT: lsr x8, x8, x1 896; CHECK-NEXT: lsl x8, x8, x9 897; CHECK-NEXT: lsr x0, x8, x9 898; CHECK-NEXT: ret 899 %val = load i64, i64* %w 900 %shifted = lshr i64 %val, %numskipbits 901 %numhighbits = sub i64 64, %numlowbits 902 %highbitscleared = shl i64 %shifted, %numhighbits 903 %masked = lshr i64 %highbitscleared, %numhighbits 904 ret i64 %masked 905} 906 907define i64 @bextr64_d3_load_indexzext(i64* %w, i8 %numskipbits, i8 %numlowbits) nounwind { 908; CHECK-LABEL: bextr64_d3_load_indexzext: 909; CHECK: // %bb.0: 910; CHECK-NEXT: ldr x8, [x0] 911; CHECK-NEXT: mov w9, #64 912; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1 913; CHECK-NEXT: sub w9, w9, w2 914; CHECK-NEXT: lsr x8, x8, x1 915; CHECK-NEXT: lsl x8, x8, x9 916; CHECK-NEXT: lsr x0, x8, x9 917; CHECK-NEXT: ret 918 %val = load i64, i64* %w 919 %skip = zext i8 %numskipbits to i64 920 %shifted = lshr i64 %val, %skip 921 %numhighbits = sub i8 64, %numlowbits 922 %sh_prom = zext i8 %numhighbits to i64 923 %highbitscleared = shl i64 %shifted, %sh_prom 924 %masked = lshr i64 %highbitscleared, %sh_prom 925 ret i64 %masked 926} 927 928; 64-bit, but with 32-bit output 929 930; Everything done in 64-bit, truncation happens last. 931define i32 @bextr64_32_d0(i64 %val, i64 %numskipbits, i64 %numlowbits) nounwind { 932; CHECK-LABEL: bextr64_32_d0: 933; CHECK: // %bb.0: 934; CHECK-NEXT: lsr x8, x0, x1 935; CHECK-NEXT: neg x9, x2 936; CHECK-NEXT: lsl x8, x8, x9 937; CHECK-NEXT: lsr x0, x8, x9 938; CHECK-NEXT: // kill: def $w0 killed $w0 killed $x0 939; CHECK-NEXT: ret 940 %shifted = lshr i64 %val, %numskipbits 941 %numhighbits = sub i64 64, %numlowbits 942 %highbitscleared = shl i64 %shifted, %numhighbits 943 %masked = lshr i64 %highbitscleared, %numhighbits 944 %res = trunc i64 %masked to i32 945 ret i32 %res 946} 947 948; Shifting happens in 64-bit, then truncation. Masking is 32-bit. 949define i32 @bextr64_32_d1(i64 %val, i64 %numskipbits, i32 %numlowbits) nounwind { 950; CHECK-LABEL: bextr64_32_d1: 951; CHECK: // %bb.0: 952; CHECK-NEXT: lsr x8, x0, x1 953; CHECK-NEXT: neg w9, w2 954; CHECK-NEXT: lsl w8, w8, w9 955; CHECK-NEXT: lsr w0, w8, w9 956; CHECK-NEXT: ret 957 %shifted = lshr i64 %val, %numskipbits 958 %truncshifted = trunc i64 %shifted to i32 959 %numhighbits = sub i32 32, %numlowbits 960 %highbitscleared = shl i32 %truncshifted, %numhighbits 961 %masked = lshr i32 %highbitscleared, %numhighbits 962 ret i32 %masked 963} 964 965; ---------------------------------------------------------------------------- ; 966; Constant 967; ---------------------------------------------------------------------------- ; 968 969; https://bugs.llvm.org/show_bug.cgi?id=38938 970define void @pr38938(i32* %a0, i64* %a1) nounwind { 971; CHECK-LABEL: pr38938: 972; CHECK: // %bb.0: 973; CHECK-NEXT: ldr x8, [x1] 974; CHECK-NEXT: ubfx x8, x8, #21, #10 975; CHECK-NEXT: lsl x8, x8, #2 976; CHECK-NEXT: ldr w9, [x0, x8] 977; CHECK-NEXT: add w9, w9, #1 // =1 978; CHECK-NEXT: str w9, [x0, x8] 979; CHECK-NEXT: ret 980 %tmp = load i64, i64* %a1, align 8 981 %tmp1 = lshr i64 %tmp, 21 982 %tmp2 = and i64 %tmp1, 1023 983 %tmp3 = getelementptr inbounds i32, i32* %a0, i64 %tmp2 984 %tmp4 = load i32, i32* %tmp3, align 4 985 %tmp5 = add nsw i32 %tmp4, 1 986 store i32 %tmp5, i32* %tmp3, align 4 987 ret void 988} 989 990; The most canonical variant 991define i32 @c0_i32(i32 %arg) nounwind { 992; CHECK-LABEL: c0_i32: 993; CHECK: // %bb.0: 994; CHECK-NEXT: ubfx w0, w0, #19, #10 995; CHECK-NEXT: ret 996 %tmp0 = lshr i32 %arg, 19 997 %tmp1 = and i32 %tmp0, 1023 998 ret i32 %tmp1 999} 1000 1001; Should be still fine, but the mask is shifted 1002define i32 @c1_i32(i32 %arg) nounwind { 1003; CHECK-LABEL: c1_i32: 1004; CHECK: // %bb.0: 1005; CHECK-NEXT: lsr w8, w0, #19 1006; CHECK-NEXT: and w0, w8, #0xffc 1007; CHECK-NEXT: ret 1008 %tmp0 = lshr i32 %arg, 19 1009 %tmp1 = and i32 %tmp0, 4092 1010 ret i32 %tmp1 1011} 1012 1013; Should be still fine, but the result is shifted left afterwards 1014define i32 @c2_i32(i32 %arg) nounwind { 1015; CHECK-LABEL: c2_i32: 1016; CHECK: // %bb.0: 1017; CHECK-NEXT: ubfx w8, w0, #19, #10 1018; CHECK-NEXT: lsl w0, w8, #2 1019; CHECK-NEXT: ret 1020 %tmp0 = lshr i32 %arg, 19 1021 %tmp1 = and i32 %tmp0, 1023 1022 %tmp2 = shl i32 %tmp1, 2 1023 ret i32 %tmp2 1024} 1025 1026; The mask covers newly shifted-in bit 1027define i32 @c4_i32_bad(i32 %arg) nounwind { 1028; CHECK-LABEL: c4_i32_bad: 1029; CHECK: // %bb.0: 1030; CHECK-NEXT: lsr w8, w0, #19 1031; CHECK-NEXT: and w0, w8, #0x1ffe 1032; CHECK-NEXT: ret 1033 %tmp0 = lshr i32 %arg, 19 1034 %tmp1 = and i32 %tmp0, 16382 1035 ret i32 %tmp1 1036} 1037 1038; i64 1039 1040; The most canonical variant 1041define i64 @c0_i64(i64 %arg) nounwind { 1042; CHECK-LABEL: c0_i64: 1043; CHECK: // %bb.0: 1044; CHECK-NEXT: ubfx x0, x0, #51, #10 1045; CHECK-NEXT: ret 1046 %tmp0 = lshr i64 %arg, 51 1047 %tmp1 = and i64 %tmp0, 1023 1048 ret i64 %tmp1 1049} 1050 1051; Should be still fine, but the mask is shifted 1052define i64 @c1_i64(i64 %arg) nounwind { 1053; CHECK-LABEL: c1_i64: 1054; CHECK: // %bb.0: 1055; CHECK-NEXT: lsr x8, x0, #51 1056; CHECK-NEXT: and x0, x8, #0xffc 1057; CHECK-NEXT: ret 1058 %tmp0 = lshr i64 %arg, 51 1059 %tmp1 = and i64 %tmp0, 4092 1060 ret i64 %tmp1 1061} 1062 1063; Should be still fine, but the result is shifted left afterwards 1064define i64 @c2_i64(i64 %arg) nounwind { 1065; CHECK-LABEL: c2_i64: 1066; CHECK: // %bb.0: 1067; CHECK-NEXT: ubfx x8, x0, #51, #10 1068; CHECK-NEXT: lsl x0, x8, #2 1069; CHECK-NEXT: ret 1070 %tmp0 = lshr i64 %arg, 51 1071 %tmp1 = and i64 %tmp0, 1023 1072 %tmp2 = shl i64 %tmp1, 2 1073 ret i64 %tmp2 1074} 1075 1076; The mask covers newly shifted-in bit 1077define i64 @c4_i64_bad(i64 %arg) nounwind { 1078; CHECK-LABEL: c4_i64_bad: 1079; CHECK: // %bb.0: 1080; CHECK-NEXT: lsr x8, x0, #51 1081; CHECK-NEXT: and x0, x8, #0x1ffe 1082; CHECK-NEXT: ret 1083 %tmp0 = lshr i64 %arg, 51 1084 %tmp1 = and i64 %tmp0, 16382 1085 ret i64 %tmp1 1086} 1087 1088; ---------------------------------------------------------------------------- ; 1089; Constant, storing the result afterwards. 1090; ---------------------------------------------------------------------------- ; 1091 1092; i32 1093 1094; The most canonical variant 1095define void @c5_i32(i32 %arg, i32* %ptr) nounwind { 1096; CHECK-LABEL: c5_i32: 1097; CHECK: // %bb.0: 1098; CHECK-NEXT: ubfx w8, w0, #19, #10 1099; CHECK-NEXT: str w8, [x1] 1100; CHECK-NEXT: ret 1101 %tmp0 = lshr i32 %arg, 19 1102 %tmp1 = and i32 %tmp0, 1023 1103 store i32 %tmp1, i32* %ptr 1104 ret void 1105} 1106 1107; Should be still fine, but the mask is shifted 1108define void @c6_i32(i32 %arg, i32* %ptr) nounwind { 1109; CHECK-LABEL: c6_i32: 1110; CHECK: // %bb.0: 1111; CHECK-NEXT: ubfx w8, w0, #19, #12 1112; CHECK-NEXT: str w8, [x1] 1113; CHECK-NEXT: ret 1114 %tmp0 = lshr i32 %arg, 19 1115 %tmp1 = and i32 %tmp0, 4095 1116 store i32 %tmp1, i32* %ptr 1117 ret void 1118} 1119 1120; Should be still fine, but the result is shifted left afterwards 1121define void @c7_i32(i32 %arg, i32* %ptr) nounwind { 1122; CHECK-LABEL: c7_i32: 1123; CHECK: // %bb.0: 1124; CHECK-NEXT: ubfx w8, w0, #19, #10 1125; CHECK-NEXT: lsl w8, w8, #2 1126; CHECK-NEXT: str w8, [x1] 1127; CHECK-NEXT: ret 1128 %tmp0 = lshr i32 %arg, 19 1129 %tmp1 = and i32 %tmp0, 1023 1130 %tmp2 = shl i32 %tmp1, 2 1131 store i32 %tmp2, i32* %ptr 1132 ret void 1133} 1134 1135; i64 1136 1137; The most canonical variant 1138define void @c5_i64(i64 %arg, i64* %ptr) nounwind { 1139; CHECK-LABEL: c5_i64: 1140; CHECK: // %bb.0: 1141; CHECK-NEXT: ubfx x8, x0, #51, #10 1142; CHECK-NEXT: str x8, [x1] 1143; CHECK-NEXT: ret 1144 %tmp0 = lshr i64 %arg, 51 1145 %tmp1 = and i64 %tmp0, 1023 1146 store i64 %tmp1, i64* %ptr 1147 ret void 1148} 1149 1150; Should be still fine, but the mask is shifted 1151define void @c6_i64(i64 %arg, i64* %ptr) nounwind { 1152; CHECK-LABEL: c6_i64: 1153; CHECK: // %bb.0: 1154; CHECK-NEXT: ubfx x8, x0, #51, #12 1155; CHECK-NEXT: str x8, [x1] 1156; CHECK-NEXT: ret 1157 %tmp0 = lshr i64 %arg, 51 1158 %tmp1 = and i64 %tmp0, 4095 1159 store i64 %tmp1, i64* %ptr 1160 ret void 1161} 1162 1163; Should be still fine, but the result is shifted left afterwards 1164define void @c7_i64(i64 %arg, i64* %ptr) nounwind { 1165; CHECK-LABEL: c7_i64: 1166; CHECK: // %bb.0: 1167; CHECK-NEXT: ubfx x8, x0, #51, #10 1168; CHECK-NEXT: lsl x8, x8, #2 1169; CHECK-NEXT: str x8, [x1] 1170; CHECK-NEXT: ret 1171 %tmp0 = lshr i64 %arg, 51 1172 %tmp1 = and i64 %tmp0, 1023 1173 %tmp2 = shl i64 %tmp1, 2 1174 store i64 %tmp2, i64* %ptr 1175 ret void 1176} 1177