1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=aarch64 | FileCheck %s 3; RUN: llc < %s -mtriple=aarch64 -global-isel -global-isel-abort=1 | FileCheck %s --check-prefix=GISEL 4 5; Convert mul x, pow2 to shift. 6; Convert mul x, pow2 +/- 1 to shift + add/sub. 7; Convert mul x, (pow2 + 1) * pow2 to shift + add + shift. 8; Lowering other positive constants are not supported yet. 9 10define i32 @test2(i32 %x) { 11; CHECK-LABEL: test2: 12; CHECK: // %bb.0: 13; CHECK-NEXT: lsl w0, w0, #1 14; CHECK-NEXT: ret 15; 16; GISEL-LABEL: test2: 17; GISEL: // %bb.0: 18; GISEL-NEXT: lsl w0, w0, #1 19; GISEL-NEXT: ret 20 21 %mul = shl nsw i32 %x, 1 22 ret i32 %mul 23} 24 25define i32 @test3(i32 %x) { 26; CHECK-LABEL: test3: 27; CHECK: // %bb.0: 28; CHECK-NEXT: add w0, w0, w0, lsl #1 29; CHECK-NEXT: ret 30; 31; GISEL-LABEL: test3: 32; GISEL: // %bb.0: 33; GISEL-NEXT: add w0, w0, w0, lsl #1 34; GISEL-NEXT: ret 35 36 %mul = mul nsw i32 %x, 3 37 ret i32 %mul 38} 39 40define i32 @test4(i32 %x) { 41; CHECK-LABEL: test4: 42; CHECK: // %bb.0: 43; CHECK-NEXT: lsl w0, w0, #2 44; CHECK-NEXT: ret 45; 46; GISEL-LABEL: test4: 47; GISEL: // %bb.0: 48; GISEL-NEXT: lsl w0, w0, #2 49; GISEL-NEXT: ret 50 51 %mul = shl nsw i32 %x, 2 52 ret i32 %mul 53} 54 55define i32 @test5(i32 %x) { 56; CHECK-LABEL: test5: 57; CHECK: // %bb.0: 58; CHECK-NEXT: add w0, w0, w0, lsl #2 59; CHECK-NEXT: ret 60; 61; GISEL-LABEL: test5: 62; GISEL: // %bb.0: 63; GISEL-NEXT: add w0, w0, w0, lsl #2 64; GISEL-NEXT: ret 65 66 67 %mul = mul nsw i32 %x, 5 68 ret i32 %mul 69} 70 71define i32 @test6_32b(i32 %x) { 72; CHECK-LABEL: test6_32b: 73; CHECK: // %bb.0: 74; CHECK-NEXT: add w8, w0, w0, lsl #1 75; CHECK-NEXT: lsl w0, w8, #1 76; CHECK-NEXT: ret 77; 78; GISEL-LABEL: test6_32b: 79; GISEL: // %bb.0: 80; GISEL-NEXT: add w8, w0, w0, lsl #1 81; GISEL-NEXT: lsl w0, w8, #1 82; GISEL-NEXT: ret 83 84 %mul = mul nsw i32 %x, 6 85 ret i32 %mul 86} 87 88define i64 @test6_64b(i64 %x) { 89; CHECK-LABEL: test6_64b: 90; CHECK: // %bb.0: 91; CHECK-NEXT: add x8, x0, x0, lsl #1 92; CHECK-NEXT: lsl x0, x8, #1 93; CHECK-NEXT: ret 94; 95; GISEL-LABEL: test6_64b: 96; GISEL: // %bb.0: 97; GISEL-NEXT: add x8, x0, x0, lsl #1 98; GISEL-NEXT: lsl x0, x8, #1 99; GISEL-NEXT: ret 100 101 %mul = mul nsw i64 %x, 6 102 ret i64 %mul 103} 104 105; mul that appears together with add, sub, s(z)ext is not supported to be 106; converted to the combination of lsl, add/sub yet. 107define i64 @test6_umull(i32 %x) { 108; CHECK-LABEL: test6_umull: 109; CHECK: // %bb.0: 110; CHECK-NEXT: mov w8, #6 // =0x6 111; CHECK-NEXT: umull x0, w0, w8 112; CHECK-NEXT: ret 113; 114; GISEL-LABEL: test6_umull: 115; GISEL: // %bb.0: 116; GISEL-NEXT: mov w8, #6 // =0x6 117; GISEL-NEXT: umull x0, w0, w8 118; GISEL-NEXT: ret 119 120 %ext = zext i32 %x to i64 121 %mul = mul nsw i64 %ext, 6 122 ret i64 %mul 123} 124 125define i64 @test6_smull(i32 %x) { 126; CHECK-LABEL: test6_smull: 127; CHECK: // %bb.0: 128; CHECK-NEXT: mov w8, #6 // =0x6 129; CHECK-NEXT: smull x0, w0, w8 130; CHECK-NEXT: ret 131; 132; GISEL-LABEL: test6_smull: 133; GISEL: // %bb.0: 134; GISEL-NEXT: mov w8, #6 // =0x6 135; GISEL-NEXT: smull x0, w0, w8 136; GISEL-NEXT: ret 137 138 %ext = sext i32 %x to i64 139 %mul = mul nsw i64 %ext, 6 140 ret i64 %mul 141} 142 143define i32 @test6_madd(i32 %x, i32 %y) { 144; CHECK-LABEL: test6_madd: 145; CHECK: // %bb.0: 146; CHECK-NEXT: mov w8, #6 // =0x6 147; CHECK-NEXT: madd w0, w0, w8, w1 148; CHECK-NEXT: ret 149; 150; GISEL-LABEL: test6_madd: 151; GISEL: // %bb.0: 152; GISEL-NEXT: mov w8, #6 // =0x6 153; GISEL-NEXT: madd w0, w0, w8, w1 154; GISEL-NEXT: ret 155 156 %mul = mul nsw i32 %x, 6 157 %add = add i32 %mul, %y 158 ret i32 %add 159} 160 161define i32 @test6_msub(i32 %x, i32 %y) { 162; CHECK-LABEL: test6_msub: 163; CHECK: // %bb.0: 164; CHECK-NEXT: mov w8, #6 // =0x6 165; CHECK-NEXT: msub w0, w0, w8, w1 166; CHECK-NEXT: ret 167; 168; GISEL-LABEL: test6_msub: 169; GISEL: // %bb.0: 170; GISEL-NEXT: mov w8, #6 // =0x6 171; GISEL-NEXT: msub w0, w0, w8, w1 172; GISEL-NEXT: ret 173 174 %mul = mul nsw i32 %x, 6 175 %sub = sub i32 %y, %mul 176 ret i32 %sub 177} 178 179define i64 @test6_umaddl(i32 %x, i64 %y) { 180; CHECK-LABEL: test6_umaddl: 181; CHECK: // %bb.0: 182; CHECK-NEXT: mov w8, #6 // =0x6 183; CHECK-NEXT: umaddl x0, w0, w8, x1 184; CHECK-NEXT: ret 185; 186; GISEL-LABEL: test6_umaddl: 187; GISEL: // %bb.0: 188; GISEL-NEXT: mov w8, #6 // =0x6 189; GISEL-NEXT: umaddl x0, w0, w8, x1 190; GISEL-NEXT: ret 191 192 %ext = zext i32 %x to i64 193 %mul = mul nsw i64 %ext, 6 194 %add = add i64 %mul, %y 195 ret i64 %add 196} 197 198define i64 @test6_smaddl(i32 %x, i64 %y) { 199; CHECK-LABEL: test6_smaddl: 200; CHECK: // %bb.0: 201; CHECK-NEXT: mov w8, #6 // =0x6 202; CHECK-NEXT: smaddl x0, w0, w8, x1 203; CHECK-NEXT: ret 204; 205; GISEL-LABEL: test6_smaddl: 206; GISEL: // %bb.0: 207; GISEL-NEXT: mov w8, #6 // =0x6 208; GISEL-NEXT: smaddl x0, w0, w8, x1 209; GISEL-NEXT: ret 210 211 %ext = sext i32 %x to i64 212 %mul = mul nsw i64 %ext, 6 213 %add = add i64 %mul, %y 214 ret i64 %add 215} 216 217define i64 @test6_umsubl(i32 %x, i64 %y) { 218; CHECK-LABEL: test6_umsubl: 219; CHECK: // %bb.0: 220; CHECK-NEXT: mov w8, #6 // =0x6 221; CHECK-NEXT: umsubl x0, w0, w8, x1 222; CHECK-NEXT: ret 223; 224; GISEL-LABEL: test6_umsubl: 225; GISEL: // %bb.0: 226; GISEL-NEXT: mov w8, #6 // =0x6 227; GISEL-NEXT: umsubl x0, w0, w8, x1 228; GISEL-NEXT: ret 229 230 %ext = zext i32 %x to i64 231 %mul = mul nsw i64 %ext, 6 232 %sub = sub i64 %y, %mul 233 ret i64 %sub 234} 235 236define i64 @test6_smsubl(i32 %x, i64 %y) { 237; CHECK-LABEL: test6_smsubl: 238; CHECK: // %bb.0: 239; CHECK-NEXT: mov w8, #6 // =0x6 240; CHECK-NEXT: smsubl x0, w0, w8, x1 241; CHECK-NEXT: ret 242; 243; GISEL-LABEL: test6_smsubl: 244; GISEL: // %bb.0: 245; GISEL-NEXT: mov w8, #6 // =0x6 246; GISEL-NEXT: smsubl x0, w0, w8, x1 247; GISEL-NEXT: ret 248 249 %ext = sext i32 %x to i64 250 %mul = mul nsw i64 %ext, 6 251 %sub = sub i64 %y, %mul 252 ret i64 %sub 253} 254 255define i64 @test6_umnegl(i32 %x) { 256; CHECK-LABEL: test6_umnegl: 257; CHECK: // %bb.0: 258; CHECK-NEXT: mov w8, #6 // =0x6 259; CHECK-NEXT: umnegl x0, w0, w8 260; CHECK-NEXT: ret 261; 262; GISEL-LABEL: test6_umnegl: 263; GISEL: // %bb.0: 264; GISEL-NEXT: mov w8, #6 // =0x6 265; GISEL-NEXT: umnegl x0, w0, w8 266; GISEL-NEXT: ret 267 268 %ext = zext i32 %x to i64 269 %mul = mul nsw i64 %ext, 6 270 %sub = sub i64 0, %mul 271 ret i64 %sub 272} 273 274define i64 @test6_smnegl(i32 %x) { 275; CHECK-LABEL: test6_smnegl: 276; CHECK: // %bb.0: 277; CHECK-NEXT: mov w8, #6 // =0x6 278; CHECK-NEXT: smnegl x0, w0, w8 279; CHECK-NEXT: ret 280; 281; GISEL-LABEL: test6_smnegl: 282; GISEL: // %bb.0: 283; GISEL-NEXT: mov w8, #6 // =0x6 284; GISEL-NEXT: smnegl x0, w0, w8 285; GISEL-NEXT: ret 286 287 %ext = sext i32 %x to i64 288 %mul = mul nsw i64 %ext, 6 289 %sub = sub i64 0, %mul 290 ret i64 %sub 291} 292 293; We may hoist the "mov" instructions out of a loop 294define i32 @mull6_sub(i32 %x) { 295; CHECK-LABEL: mull6_sub: 296; CHECK: // %bb.0: 297; CHECK-NEXT: mov w8, #6 // =0x6 298; CHECK-NEXT: mov w9, #-1 // =0xffffffff 299; CHECK-NEXT: madd w0, w0, w8, w9 300; CHECK-NEXT: ret 301; 302; GISEL-LABEL: mull6_sub: 303; GISEL: // %bb.0: 304; GISEL-NEXT: mov w8, #6 // =0x6 305; GISEL-NEXT: mov w9, #-1 // =0xffffffff 306; GISEL-NEXT: madd w0, w0, w8, w9 307; GISEL-NEXT: ret 308 %mul = mul nsw i32 %x, 6 309 %sub = add nsw i32 %mul, -1 310 ret i32 %sub 311} 312 313define i64 @mull6_sub_orr(i64 %x) { 314; CHECK-LABEL: mull6_sub_orr: 315; CHECK: // %bb.0: 316; CHECK-NEXT: mov w8, #6 // =0x6 317; CHECK-NEXT: mov x9, #16773120 // =0xfff000 318; CHECK-NEXT: madd x0, x0, x8, x9 319; CHECK-NEXT: ret 320; 321; GISEL-LABEL: mull6_sub_orr: 322; GISEL: // %bb.0: 323; GISEL-NEXT: mov w8, #6 // =0x6 324; GISEL-NEXT: mov x9, #16773120 // =0xfff000 325; GISEL-NEXT: madd x0, x0, x8, x9 326; GISEL-NEXT: ret 327 %mul = mul nsw i64 %x, 6 328 %sub = add nsw i64 %mul, 16773120 329 ret i64 %sub 330} 331 332define i32 @test7(i32 %x) { 333; CHECK-LABEL: test7: 334; CHECK: // %bb.0: 335; CHECK-NEXT: lsl w8, w0, #3 336; CHECK-NEXT: sub w0, w8, w0 337; CHECK-NEXT: ret 338; 339; GISEL-LABEL: test7: 340; GISEL: // %bb.0: 341; GISEL-NEXT: lsl w8, w0, #3 342; GISEL-NEXT: sub w0, w8, w0 343; GISEL-NEXT: ret 344 345 %mul = mul nsw i32 %x, 7 346 ret i32 %mul 347} 348 349define i32 @test8(i32 %x) { 350; CHECK-LABEL: test8: 351; CHECK: // %bb.0: 352; CHECK-NEXT: lsl w0, w0, #3 353; CHECK-NEXT: ret 354; 355; GISEL-LABEL: test8: 356; GISEL: // %bb.0: 357; GISEL-NEXT: lsl w0, w0, #3 358; GISEL-NEXT: ret 359 360 %mul = shl nsw i32 %x, 3 361 ret i32 %mul 362} 363 364define i32 @test9(i32 %x) { 365; CHECK-LABEL: test9: 366; CHECK: // %bb.0: 367; CHECK-NEXT: add w0, w0, w0, lsl #3 368; CHECK-NEXT: ret 369; 370; GISEL-LABEL: test9: 371; GISEL: // %bb.0: 372; GISEL-NEXT: add w0, w0, w0, lsl #3 373; GISEL-NEXT: ret 374 375 %mul = mul nsw i32 %x, 9 376 ret i32 %mul 377} 378 379define i32 @test10(i32 %x) { 380; CHECK-LABEL: test10: 381; CHECK: // %bb.0: 382; CHECK-NEXT: add w8, w0, w0, lsl #2 383; CHECK-NEXT: lsl w0, w8, #1 384; CHECK-NEXT: ret 385; 386; GISEL-LABEL: test10: 387; GISEL: // %bb.0: 388; GISEL-NEXT: add w8, w0, w0, lsl #2 389; GISEL-NEXT: lsl w0, w8, #1 390; GISEL-NEXT: ret 391 392 %mul = mul nsw i32 %x, 10 393 ret i32 %mul 394} 395 396define i32 @test11(i32 %x) { 397; CHECK-LABEL: test11: 398; CHECK: // %bb.0: 399; CHECK-NEXT: mov w8, #11 // =0xb 400; CHECK-NEXT: mul w0, w0, w8 401; CHECK-NEXT: ret 402; 403; GISEL-LABEL: test11: 404; GISEL: // %bb.0: 405; GISEL-NEXT: mov w8, #11 // =0xb 406; GISEL-NEXT: mul w0, w0, w8 407; GISEL-NEXT: ret 408 409 %mul = mul nsw i32 %x, 11 410 ret i32 %mul 411} 412 413define i32 @test11_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" { 414; CHECK-LABEL: test11_fast_shift: 415; CHECK: // %bb.0: 416; CHECK-NEXT: add w8, w0, w0, lsl #2 417; CHECK-NEXT: add w0, w0, w8, lsl #1 418; CHECK-NEXT: ret 419; 420; GISEL-LABEL: test11_fast_shift: 421; GISEL: // %bb.0: 422; GISEL-NEXT: mov w8, #11 // =0xb 423; GISEL-NEXT: mul w0, w0, w8 424; GISEL-NEXT: ret 425 426 %mul = mul nsw i32 %x, 11 ; 11 = (((1<<2) + 1) << 1) + 1 427 ret i32 %mul 428} 429 430define i32 @test12(i32 %x) { 431; CHECK-LABEL: test12: 432; CHECK: // %bb.0: 433; CHECK-NEXT: add w8, w0, w0, lsl #1 434; CHECK-NEXT: lsl w0, w8, #2 435; CHECK-NEXT: ret 436; 437; GISEL-LABEL: test12: 438; GISEL: // %bb.0: 439; GISEL-NEXT: add w8, w0, w0, lsl #1 440; GISEL-NEXT: lsl w0, w8, #2 441; GISEL-NEXT: ret 442 443 %mul = mul nsw i32 %x, 12 444 ret i32 %mul 445} 446 447define i32 @test13(i32 %x) { 448; CHECK-LABEL: test13: 449; CHECK: // %bb.0: 450; CHECK-NEXT: mov w8, #13 // =0xd 451; CHECK-NEXT: mul w0, w0, w8 452; CHECK-NEXT: ret 453; 454; GISEL-LABEL: test13: 455; GISEL: // %bb.0: 456; GISEL-NEXT: mov w8, #13 // =0xd 457; GISEL-NEXT: mul w0, w0, w8 458; GISEL-NEXT: ret 459 460 %mul = mul nsw i32 %x, 13 461 ret i32 %mul 462} 463 464define i32 @test14(i32 %x) { 465; CHECK-LABEL: test14: 466; CHECK: // %bb.0: 467; CHECK-NEXT: lsl w8, w0, #4 468; CHECK-NEXT: sub w0, w8, w0, lsl #1 469; CHECK-NEXT: ret 470; 471; GISEL-LABEL: test14: 472; GISEL: // %bb.0: 473; GISEL-NEXT: mov w8, #14 // =0xe 474; GISEL-NEXT: mul w0, w0, w8 475; GISEL-NEXT: ret 476 477 %mul = mul nsw i32 %x, 14 478 ret i32 %mul 479} 480 481define i32 @test15(i32 %x) { 482; CHECK-LABEL: test15: 483; CHECK: // %bb.0: 484; CHECK-NEXT: lsl w8, w0, #4 485; CHECK-NEXT: sub w0, w8, w0 486; CHECK-NEXT: ret 487; 488; GISEL-LABEL: test15: 489; GISEL: // %bb.0: 490; GISEL-NEXT: lsl w8, w0, #4 491; GISEL-NEXT: sub w0, w8, w0 492; GISEL-NEXT: ret 493 494 %mul = mul nsw i32 %x, 15 495 ret i32 %mul 496} 497 498define i32 @test16(i32 %x) { 499; CHECK-LABEL: test16: 500; CHECK: // %bb.0: 501; CHECK-NEXT: lsl w0, w0, #4 502; CHECK-NEXT: ret 503; 504; GISEL-LABEL: test16: 505; GISEL: // %bb.0: 506; GISEL-NEXT: lsl w0, w0, #4 507; GISEL-NEXT: ret 508 509 %mul = mul nsw i32 %x, 16 510 ret i32 %mul 511} 512 513define i32 @test25_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" { 514; CHECK-LABEL: test25_fast_shift: 515; CHECK: // %bb.0: 516; CHECK-NEXT: add w8, w0, w0, lsl #2 517; CHECK-NEXT: add w0, w8, w8, lsl #2 518; CHECK-NEXT: ret 519; 520; GISEL-LABEL: test25_fast_shift: 521; GISEL: // %bb.0: 522; GISEL-NEXT: mov w8, #25 // =0x19 523; GISEL-NEXT: mul w0, w0, w8 524; GISEL-NEXT: ret 525 526 %mul = mul nsw i32 %x, 25 ; 25 = (1+4)*(1+4) 527 ret i32 %mul 528} 529 530define i32 @test29_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" { 531; CHECK-LABEL: test29_fast_shift: 532; CHECK: // %bb.0: 533; CHECK-NEXT: sub w8, w0, w0, lsl #3 534; CHECK-NEXT: sub w0, w0, w8, lsl #2 535; CHECK-NEXT: ret 536; 537; GISEL-LABEL: test29_fast_shift: 538; GISEL: // %bb.0: 539; GISEL-NEXT: mov w8, #29 // =0x1d 540; GISEL-NEXT: mul w0, w0, w8 541; GISEL-NEXT: ret 542 543 %mul = mul nsw i32 %x, 29 ; 29 = 1 - (1-8) * 4 544 ret i32 %mul 545} 546 547define i32 @test45_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" { 548; CHECK-LABEL: test45_fast_shift: 549; CHECK: // %bb.0: 550; CHECK-NEXT: add w8, w0, w0, lsl #2 551; CHECK-NEXT: add w0, w8, w8, lsl #3 552; CHECK-NEXT: ret 553; 554; GISEL-LABEL: test45_fast_shift: 555; GISEL: // %bb.0: 556; GISEL-NEXT: mov w8, #45 // =0x2d 557; GISEL-NEXT: mul w0, w0, w8 558; GISEL-NEXT: ret 559 560 %mul = mul nsw i32 %x, 45 ; 45 = (1+4)*(1+8) 561 ret i32 %mul 562} 563 564; Negative test: Keep MUL as don't have the feature LSLFast 565define i32 @test45(i32 %x) { 566; CHECK-LABEL: test45: 567; CHECK: // %bb.0: 568; CHECK-NEXT: mov w8, #45 // =0x2d 569; CHECK-NEXT: mul w0, w0, w8 570; CHECK-NEXT: ret 571; 572; GISEL-LABEL: test45: 573; GISEL: // %bb.0: 574; GISEL-NEXT: mov w8, #45 // =0x2d 575; GISEL-NEXT: mul w0, w0, w8 576; GISEL-NEXT: ret 577 578 %mul = mul nsw i32 %x, 45 ; 45 = (1+4)*(1+8) 579 ret i32 %mul 580} 581 582; Negative test: The shift number 5 is out of bound 583define i32 @test67_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" { 584; CHECK-LABEL: test67_fast_shift: 585; CHECK: // %bb.0: 586; CHECK-NEXT: mov w8, #67 // =0x43 587; CHECK-NEXT: mul w0, w0, w8 588; CHECK-NEXT: ret 589; 590; GISEL-LABEL: test67_fast_shift: 591; GISEL: // %bb.0: 592; GISEL-NEXT: mov w8, #67 // =0x43 593; GISEL-NEXT: mul w0, w0, w8 594; GISEL-NEXT: ret 595 596 %mul = mul nsw i32 %x, 67 ; 67 = (((1<<5) + 1) << 1) + 1 597 ret i32 %mul 598} 599 600define i32 @test85_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" { 601; CHECK-LABEL: test85_fast_shift: 602; CHECK: // %bb.0: 603; CHECK-NEXT: add w8, w0, w0, lsl #2 604; CHECK-NEXT: add w0, w8, w8, lsl #4 605; CHECK-NEXT: ret 606; 607; GISEL-LABEL: test85_fast_shift: 608; GISEL: // %bb.0: 609; GISEL-NEXT: mov w8, #85 // =0x55 610; GISEL-NEXT: mul w0, w0, w8 611; GISEL-NEXT: ret 612 613 %mul = mul nsw i32 %x, 85 ; 85 = (1+4)*(1+16) 614 ret i32 %mul 615} 616 617; Negative test: The shift number 5 is out of bound 618define i32 @test97_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" { 619; CHECK-LABEL: test97_fast_shift: 620; CHECK: // %bb.0: 621; CHECK-NEXT: mov w8, #97 // =0x61 622; CHECK-NEXT: mul w0, w0, w8 623; CHECK-NEXT: ret 624; 625; GISEL-LABEL: test97_fast_shift: 626; GISEL: // %bb.0: 627; GISEL-NEXT: mov w8, #97 // =0x61 628; GISEL-NEXT: mul w0, w0, w8 629; GISEL-NEXT: ret 630 631 %mul = mul nsw i32 %x, 97 ; 97 = ((2 + 1) << 5) + 1 632 ret i32 %mul 633} 634 635; Negative test: The shift number 5 is out of bound 636define i32 @test125_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" { 637; CHECK-LABEL: test125_fast_shift: 638; CHECK: // %bb.0: 639; CHECK-NEXT: mov w8, #125 // =0x7d 640; CHECK-NEXT: mul w0, w0, w8 641; CHECK-NEXT: ret 642; 643; GISEL-LABEL: test125_fast_shift: 644; GISEL: // %bb.0: 645; GISEL-NEXT: mov w8, #125 // =0x7d 646; GISEL-NEXT: mul w0, w0, w8 647; GISEL-NEXT: ret 648 649 %mul = mul nsw i32 %x, 125 ; 125 = 1 - ((1-32) << 2) 650 ret i32 %mul 651} 652 653; TODO: (1 - 2^M) * (1 - 2^N) 654define i32 @test225_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" { 655; CHECK-LABEL: test225_fast_shift: 656; CHECK: // %bb.0: 657; CHECK-NEXT: mov w8, #225 // =0xe1 658; CHECK-NEXT: mul w0, w0, w8 659; CHECK-NEXT: ret 660; 661; GISEL-LABEL: test225_fast_shift: 662; GISEL: // %bb.0: 663; GISEL-NEXT: mov w8, #225 // =0xe1 664; GISEL-NEXT: mul w0, w0, w8 665; GISEL-NEXT: ret 666 667 %mul = mul nsw i32 %x, 225 ; 225 = (1-16)*(1-16) 668 ret i32 %mul 669} 670 671; Negative test: The shift amount 5 larger than 4 672define i32 @test297_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" { 673; CHECK-LABEL: test297_fast_shift: 674; CHECK: // %bb.0: 675; CHECK-NEXT: mov w8, #297 // =0x129 676; CHECK-NEXT: mul w0, w0, w8 677; CHECK-NEXT: ret 678; 679; GISEL-LABEL: test297_fast_shift: 680; GISEL: // %bb.0: 681; GISEL-NEXT: mov w8, #297 // =0x129 682; GISEL-NEXT: mul w0, w0, w8 683; GISEL-NEXT: ret 684 685 %mul = mul nsw i32 %x, 297 ; 297 = (1+8)*(1+32) 686 ret i32 %mul 687} 688 689; Negative test: The shift number 5 is out of bound 690define i32 @test481_fast_shift(i32 %x) "target-features"="+alu-lsl-fast" { 691; CHECK-LABEL: test481_fast_shift: 692; CHECK: // %bb.0: 693; CHECK-NEXT: mov w8, #481 // =0x1e1 694; CHECK-NEXT: mul w0, w0, w8 695; CHECK-NEXT: ret 696; 697; GISEL-LABEL: test481_fast_shift: 698; GISEL: // %bb.0: 699; GISEL-NEXT: mov w8, #481 // =0x1e1 700; GISEL-NEXT: mul w0, w0, w8 701; GISEL-NEXT: ret 702 703 %mul = mul nsw i32 %x, 481 ; 481 = 1 - ((1-16) << 5) 704 ret i32 %mul 705} 706 707; Convert mul x, -pow2 to shift. 708; Convert mul x, -(pow2 +/- 1) to shift + add/sub. 709; Lowering other negative constants are not supported yet. 710 711define i32 @ntest2(i32 %x) { 712; CHECK-LABEL: ntest2: 713; CHECK: // %bb.0: 714; CHECK-NEXT: neg w0, w0, lsl #1 715; CHECK-NEXT: ret 716; 717; GISEL-LABEL: ntest2: 718; GISEL: // %bb.0: 719; GISEL-NEXT: mov w8, #-2 // =0xfffffffe 720; GISEL-NEXT: mul w0, w0, w8 721; GISEL-NEXT: ret 722 723 %mul = mul nsw i32 %x, -2 724 ret i32 %mul 725} 726 727define i32 @ntest3(i32 %x) { 728; CHECK-LABEL: ntest3: 729; CHECK: // %bb.0: 730; CHECK-NEXT: sub w0, w0, w0, lsl #2 731; CHECK-NEXT: ret 732; 733; GISEL-LABEL: ntest3: 734; GISEL: // %bb.0: 735; GISEL-NEXT: sub w0, w0, w0, lsl #2 736; GISEL-NEXT: ret 737 738 %mul = mul nsw i32 %x, -3 739 ret i32 %mul 740} 741 742define i32 @ntest4(i32 %x) { 743; CHECK-LABEL: ntest4: 744; CHECK: // %bb.0: 745; CHECK-NEXT: neg w0, w0, lsl #2 746; CHECK-NEXT: ret 747; 748; GISEL-LABEL: ntest4: 749; GISEL: // %bb.0: 750; GISEL-NEXT: mov w8, #-4 // =0xfffffffc 751; GISEL-NEXT: mul w0, w0, w8 752; GISEL-NEXT: ret 753 754 %mul = mul nsw i32 %x, -4 755 ret i32 %mul 756} 757 758define i32 @ntest5(i32 %x) { 759; CHECK-LABEL: ntest5: 760; CHECK: // %bb.0: 761; CHECK-NEXT: add w8, w0, w0, lsl #2 762; CHECK-NEXT: neg w0, w8 763; CHECK-NEXT: ret 764; 765; GISEL-LABEL: ntest5: 766; GISEL: // %bb.0: 767; GISEL-NEXT: add w8, w0, w0, lsl #2 768; GISEL-NEXT: neg w0, w8 769; GISEL-NEXT: ret 770 %mul = mul nsw i32 %x, -5 771 ret i32 %mul 772} 773 774define i32 @ntest6(i32 %x) { 775; CHECK-LABEL: ntest6: 776; CHECK: // %bb.0: 777; CHECK-NEXT: lsl w8, w0, #1 778; CHECK-NEXT: sub w0, w8, w0, lsl #3 779; CHECK-NEXT: ret 780; 781; GISEL-LABEL: ntest6: 782; GISEL: // %bb.0: 783; GISEL-NEXT: mov w8, #-6 // =0xfffffffa 784; GISEL-NEXT: mul w0, w0, w8 785; GISEL-NEXT: ret 786 787 %mul = mul nsw i32 %x, -6 788 ret i32 %mul 789} 790 791define i32 @ntest7(i32 %x) { 792; CHECK-LABEL: ntest7: 793; CHECK: // %bb.0: 794; CHECK-NEXT: sub w0, w0, w0, lsl #3 795; CHECK-NEXT: ret 796; 797; GISEL-LABEL: ntest7: 798; GISEL: // %bb.0: 799; GISEL-NEXT: sub w0, w0, w0, lsl #3 800; GISEL-NEXT: ret 801 802 %mul = mul nsw i32 %x, -7 803 ret i32 %mul 804} 805 806define i32 @ntest8(i32 %x) { 807; CHECK-LABEL: ntest8: 808; CHECK: // %bb.0: 809; CHECK-NEXT: neg w0, w0, lsl #3 810; CHECK-NEXT: ret 811; 812; GISEL-LABEL: ntest8: 813; GISEL: // %bb.0: 814; GISEL-NEXT: mov w8, #-8 // =0xfffffff8 815; GISEL-NEXT: mul w0, w0, w8 816; GISEL-NEXT: ret 817 818 %mul = mul nsw i32 %x, -8 819 ret i32 %mul 820} 821 822define i32 @ntest9(i32 %x) { 823; CHECK-LABEL: ntest9: 824; CHECK: // %bb.0: 825; CHECK-NEXT: add w8, w0, w0, lsl #3 826; CHECK-NEXT: neg w0, w8 827; CHECK-NEXT: ret 828; 829; GISEL-LABEL: ntest9: 830; GISEL: // %bb.0: 831; GISEL-NEXT: add w8, w0, w0, lsl #3 832; GISEL-NEXT: neg w0, w8 833; GISEL-NEXT: ret 834 835 %mul = mul nsw i32 %x, -9 836 ret i32 %mul 837} 838 839define i32 @ntest10(i32 %x) { 840; CHECK-LABEL: ntest10: 841; CHECK: // %bb.0: 842; CHECK-NEXT: mov w8, #-10 // =0xfffffff6 843; CHECK-NEXT: mul w0, w0, w8 844; CHECK-NEXT: ret 845; 846; GISEL-LABEL: ntest10: 847; GISEL: // %bb.0: 848; GISEL-NEXT: mov w8, #-10 // =0xfffffff6 849; GISEL-NEXT: mul w0, w0, w8 850; GISEL-NEXT: ret 851 852 %mul = mul nsw i32 %x, -10 853 ret i32 %mul 854} 855 856define i32 @ntest11(i32 %x) { 857; CHECK-LABEL: ntest11: 858; CHECK: // %bb.0: 859; CHECK-NEXT: mov w8, #-11 // =0xfffffff5 860; CHECK-NEXT: mul w0, w0, w8 861; CHECK-NEXT: ret 862; 863; GISEL-LABEL: ntest11: 864; GISEL: // %bb.0: 865; GISEL-NEXT: mov w8, #-11 // =0xfffffff5 866; GISEL-NEXT: mul w0, w0, w8 867; GISEL-NEXT: ret 868 869 %mul = mul nsw i32 %x, -11 870 ret i32 %mul 871} 872 873define i32 @ntest12(i32 %x) { 874; CHECK-LABEL: ntest12: 875; CHECK: // %bb.0: 876; CHECK-NEXT: lsl w8, w0, #2 877; CHECK-NEXT: sub w0, w8, w0, lsl #4 878; CHECK-NEXT: ret 879; 880; GISEL-LABEL: ntest12: 881; GISEL: // %bb.0: 882; GISEL-NEXT: mov w8, #-12 // =0xfffffff4 883; GISEL-NEXT: mul w0, w0, w8 884; GISEL-NEXT: ret 885 886 %mul = mul nsw i32 %x, -12 887 ret i32 %mul 888} 889 890define i32 @ntest13(i32 %x) { 891; CHECK-LABEL: ntest13: 892; CHECK: // %bb.0: 893; CHECK-NEXT: mov w8, #-13 // =0xfffffff3 894; CHECK-NEXT: mul w0, w0, w8 895; CHECK-NEXT: ret 896; 897; GISEL-LABEL: ntest13: 898; GISEL: // %bb.0: 899; GISEL-NEXT: mov w8, #-13 // =0xfffffff3 900; GISEL-NEXT: mul w0, w0, w8 901; GISEL-NEXT: ret 902 %mul = mul nsw i32 %x, -13 903 ret i32 %mul 904} 905 906define i32 @ntest14(i32 %x) { 907; CHECK-LABEL: ntest14: 908; CHECK: // %bb.0: 909; CHECK-NEXT: lsl w8, w0, #1 910; CHECK-NEXT: sub w0, w8, w0, lsl #4 911; CHECK-NEXT: ret 912; 913; GISEL-LABEL: ntest14: 914; GISEL: // %bb.0: 915; GISEL-NEXT: mov w8, #-14 // =0xfffffff2 916; GISEL-NEXT: mul w0, w0, w8 917; GISEL-NEXT: ret 918 919 %mul = mul nsw i32 %x, -14 920 ret i32 %mul 921} 922 923define i32 @ntest15(i32 %x) { 924; CHECK-LABEL: ntest15: 925; CHECK: // %bb.0: 926; CHECK-NEXT: sub w0, w0, w0, lsl #4 927; CHECK-NEXT: ret 928; 929; GISEL-LABEL: ntest15: 930; GISEL: // %bb.0: 931; GISEL-NEXT: sub w0, w0, w0, lsl #4 932; GISEL-NEXT: ret 933 934 %mul = mul nsw i32 %x, -15 935 ret i32 %mul 936} 937 938define i32 @ntest16(i32 %x) { 939; CHECK-LABEL: ntest16: 940; CHECK: // %bb.0: 941; CHECK-NEXT: neg w0, w0, lsl #4 942; CHECK-NEXT: ret 943; 944; GISEL-LABEL: ntest16: 945; GISEL: // %bb.0: 946; GISEL-NEXT: mov w8, #-16 // =0xfffffff0 947; GISEL-NEXT: mul w0, w0, w8 948; GISEL-NEXT: ret 949 950 %mul = mul nsw i32 %x, -16 951 ret i32 %mul 952} 953 954define i32 @muladd_demand(i32 %x, i32 %y) { 955; CHECK-LABEL: muladd_demand: 956; CHECK: // %bb.0: 957; CHECK-NEXT: sub w8, w1, w0, lsl #6 958; CHECK-NEXT: and w0, w8, #0x1ffc0 959; CHECK-NEXT: ret 960; 961; GISEL-LABEL: muladd_demand: 962; GISEL: // %bb.0: 963; GISEL-NEXT: mov w8, #131008 // =0x1ffc0 964; GISEL-NEXT: madd w8, w0, w8, w1 965; GISEL-NEXT: and w0, w8, #0x1ffc0 966; GISEL-NEXT: ret 967 %m = mul i32 %x, 131008 ; 0x0001ffc0 968 %a = add i32 %y, %m 969 %r = and i32 %a, 131008 970 ret i32 %r 971} 972 973define <4 x i32> @muladd_demand_commute(<4 x i32> %x, <4 x i32> %y) { 974; CHECK-LABEL: muladd_demand_commute: 975; CHECK: // %bb.0: 976; CHECK-NEXT: shl v0.4s, v0.4s, #6 977; CHECK-NEXT: movi v2.4s, #1, msl #16 978; CHECK-NEXT: sub v0.4s, v1.4s, v0.4s 979; CHECK-NEXT: and v0.16b, v0.16b, v2.16b 980; CHECK-NEXT: ret 981; 982; GISEL-LABEL: muladd_demand_commute: 983; GISEL: // %bb.0: 984; GISEL-NEXT: adrp x8, .LCPI56_0 985; GISEL-NEXT: movi v3.4s, #1, msl #16 986; GISEL-NEXT: ldr q2, [x8, :lo12:.LCPI56_0] 987; GISEL-NEXT: mla v1.4s, v0.4s, v2.4s 988; GISEL-NEXT: and v0.16b, v1.16b, v3.16b 989; GISEL-NEXT: ret 990 %m = mul <4 x i32> %x, <i32 131008, i32 131008, i32 131008, i32 131008> 991 %a = add <4 x i32> %m, %y 992 %r = and <4 x i32> %a, <i32 131071, i32 131071, i32 131071, i32 131071> 993 ret <4 x i32> %r 994} 995 996; Transforming `(mul x, -(2^(N-M) - 1) * 2^M)` to `(sub (shl x, M), (shl x, N))` 997; will cause overflow when N is 32 and M is 31. 998define i32 @shift_overflow(i32 %x) { 999; CHECK-LABEL: shift_overflow: 1000; CHECK: // %bb.0: 1001; CHECK-NEXT: mov w8, #-2147483648 // =0x80000000 1002; CHECK-NEXT: mul w0, w0, w8 1003; CHECK-NEXT: ret 1004; 1005; GISEL-LABEL: shift_overflow: 1006; GISEL: // %bb.0: 1007; GISEL-NEXT: mov w8, #-2147483648 // =0x80000000 1008; GISEL-NEXT: mul w0, w0, w8 1009; GISEL-NEXT: ret 1010 %const = bitcast i32 2147483648 to i32 1011 %r = mul i32 %x, %const 1012 ret i32 %r 1013} 1014 1015; Transforming `(mul x, -(2^(N-M) - 1) * 2^M)` to `(sub (shl x, M), (shl x, N))` 1016; will not cause overflow when N is 31 and M is 30. 1017define i32 @shift_no_overflow(i32 %x) { 1018; CHECK-LABEL: shift_no_overflow: 1019; CHECK: // %bb.0: 1020; CHECK-NEXT: lsl w8, w0, #31 1021; CHECK-NEXT: sub w0, w8, w0, lsl #30 1022; CHECK-NEXT: ret 1023; 1024; GISEL-LABEL: shift_no_overflow: 1025; GISEL: // %bb.0: 1026; GISEL-NEXT: mov w8, #1073741824 // =0x40000000 1027; GISEL-NEXT: mul w0, w0, w8 1028; GISEL-NEXT: ret 1029 %const = bitcast i32 1073741824 to i32 1030 %r = mul i32 %x, %const 1031 ret i32 %r 1032} 1033