1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=avr -mattr=movw -verify-machineinstrs | FileCheck %s 3 4define i32 @shl_i32_1(i32 %a) { 5; CHECK-LABEL: shl_i32_1: 6; CHECK: ; %bb.0: 7; CHECK-NEXT: lsl r22 8; CHECK-NEXT: rol r23 9; CHECK-NEXT: rol r24 10; CHECK-NEXT: rol r25 11; CHECK-NEXT: ret 12 %res = shl i32 %a, 1 13 ret i32 %res 14} 15 16define i32 @shl_i32_2(i32 %a) { 17; CHECK-LABEL: shl_i32_2: 18; CHECK: ; %bb.0: 19; CHECK-NEXT: lsl r22 20; CHECK-NEXT: rol r23 21; CHECK-NEXT: rol r24 22; CHECK-NEXT: rol r25 23; CHECK-NEXT: lsl r22 24; CHECK-NEXT: rol r23 25; CHECK-NEXT: rol r24 26; CHECK-NEXT: rol r25 27; CHECK-NEXT: ret 28 %res = shl i32 %a, 2 29 ret i32 %res 30} 31 32define i32 @shl_i32_4(i32 %a) { 33; CHECK-LABEL: shl_i32_4: 34; CHECK: ; %bb.0: 35; CHECK-NEXT: swap r25 36; CHECK-NEXT: andi r25, 240 37; CHECK-NEXT: swap r24 38; CHECK-NEXT: eor r25, r24 39; CHECK-NEXT: andi r24, 240 40; CHECK-NEXT: eor r25, r24 41; CHECK-NEXT: swap r23 42; CHECK-NEXT: eor r24, r23 43; CHECK-NEXT: andi r23, 240 44; CHECK-NEXT: eor r24, r23 45; CHECK-NEXT: swap r22 46; CHECK-NEXT: eor r23, r22 47; CHECK-NEXT: andi r22, 240 48; CHECK-NEXT: eor r23, r22 49; CHECK-NEXT: ret 50 %res = shl i32 %a, 4 51 ret i32 %res 52} 53 54; shift four bits and then shift one bit 55define i32 @shl_i32_5(i32 %a) { 56; CHECK-LABEL: shl_i32_5: 57; CHECK: ; %bb.0: 58; CHECK-NEXT: swap r25 59; CHECK-NEXT: andi r25, 240 60; CHECK-NEXT: swap r24 61; CHECK-NEXT: eor r25, r24 62; CHECK-NEXT: andi r24, 240 63; CHECK-NEXT: eor r25, r24 64; CHECK-NEXT: swap r23 65; CHECK-NEXT: eor r24, r23 66; CHECK-NEXT: andi r23, 240 67; CHECK-NEXT: eor r24, r23 68; CHECK-NEXT: swap r22 69; CHECK-NEXT: eor r23, r22 70; CHECK-NEXT: andi r22, 240 71; CHECK-NEXT: eor r23, r22 72; CHECK-NEXT: lsl r22 73; CHECK-NEXT: rol r23 74; CHECK-NEXT: rol r24 75; CHECK-NEXT: rol r25 76; CHECK-NEXT: ret 77 %res = shl i32 %a, 5 78 ret i32 %res 79} 80 81; shift two to the right and move the registers around 82define i32 @shl_i32_6(i32 %a) { 83; CHECK-LABEL: shl_i32_6: 84; CHECK: ; %bb.0: 85; CHECK-NEXT: lsr r25 86; CHECK-NEXT: ror r24 87; CHECK-NEXT: ror r23 88; CHECK-NEXT: ror r22 89; CHECK-NEXT: mov r18, r1 90; CHECK-NEXT: ror r18 91; CHECK-NEXT: lsr r25 92; CHECK-NEXT: ror r24 93; CHECK-NEXT: ror r23 94; CHECK-NEXT: ror r22 95; CHECK-NEXT: ror r18 96; CHECK-NEXT: mov r25, r24 97; CHECK-NEXT: mov r24, r23 98; CHECK-NEXT: mov r19, r22 99; CHECK-NEXT: movw r22, r18 100; CHECK-NEXT: ret 101 %res = shl i32 %a, 6 102 ret i32 %res 103} 104 105 106; shift one to the right and move registers around 107define i32 @shl_i32_7(i32 %a) { 108; CHECK-LABEL: shl_i32_7: 109; CHECK: ; %bb.0: 110; CHECK-NEXT: lsr r25 111; CHECK-NEXT: ror r24 112; CHECK-NEXT: ror r23 113; CHECK-NEXT: ror r22 114; CHECK-NEXT: mov r18, r1 115; CHECK-NEXT: ror r18 116; CHECK-NEXT: mov r25, r24 117; CHECK-NEXT: mov r24, r23 118; CHECK-NEXT: mov r19, r22 119; CHECK-NEXT: movw r22, r18 120; CHECK-NEXT: ret 121 %res = shl i32 %a, 7 122 ret i32 %res 123} 124 125define i32 @shl_i32_8(i32 %a) { 126; CHECK-LABEL: shl_i32_8: 127; CHECK: ; %bb.0: 128; CHECK-NEXT: mov r25, r24 129; CHECK-NEXT: mov r24, r23 130; CHECK-NEXT: mov r23, r22 131; CHECK-NEXT: mov r22, r1 132; CHECK-NEXT: ret 133 %res = shl i32 %a, 8 134 ret i32 %res 135} 136 137define i32 @shl_i32_9(i32 %a) { 138; CHECK-LABEL: shl_i32_9: 139; CHECK: ; %bb.0: 140; CHECK-NEXT: lsl r22 141; CHECK-NEXT: rol r23 142; CHECK-NEXT: rol r24 143; CHECK-NEXT: mov r25, r24 144; CHECK-NEXT: mov r24, r23 145; CHECK-NEXT: mov r23, r22 146; CHECK-NEXT: mov r22, r1 147; CHECK-NEXT: ret 148 %res = shl i32 %a, 9 149 ret i32 %res 150} 151 152; shift 3 of 4 registers and move the others around 153define i32 @shl_i32_12(i32 %a) { 154; CHECK-LABEL: shl_i32_12: 155; CHECK: ; %bb.0: 156; CHECK-NEXT: swap r24 157; CHECK-NEXT: andi r24, 240 158; CHECK-NEXT: swap r23 159; CHECK-NEXT: eor r24, r23 160; CHECK-NEXT: andi r23, 240 161; CHECK-NEXT: eor r24, r23 162; CHECK-NEXT: swap r22 163; CHECK-NEXT: eor r23, r22 164; CHECK-NEXT: andi r22, 240 165; CHECK-NEXT: eor r23, r22 166; CHECK-NEXT: mov r25, r24 167; CHECK-NEXT: mov r24, r23 168; CHECK-NEXT: mov r23, r22 169; CHECK-NEXT: mov r22, r1 170; CHECK-NEXT: ret 171 %res = shl i32 %a, 12 172 ret i32 %res 173} 174 175define i32 @shl_i32_15(i32 %a) { 176; CHECK-LABEL: shl_i32_15: 177; CHECK: ; %bb.0: 178; CHECK-NEXT: movw r18, r22 179; CHECK-NEXT: lsr r24 180; CHECK-NEXT: ror r19 181; CHECK-NEXT: ror r18 182; CHECK-NEXT: mov r23, r1 183; CHECK-NEXT: ror r23 184; CHECK-NEXT: mov r22, r1 185; CHECK-NEXT: movw r24, r18 186; CHECK-NEXT: ret 187 %res = shl i32 %a, 15 188 ret i32 %res 189} 190 191; This is a special case: this shift is performed directly inside SelectionDAG 192; instead of as a custom lowering like the other shift operations. 193define i32 @shl_i32_16(i32 %a) { 194; CHECK-LABEL: shl_i32_16: 195; CHECK: ; %bb.0: 196; CHECK-NEXT: movw r24, r22 197; CHECK-NEXT: ldi r22, 0 198; CHECK-NEXT: ldi r23, 0 199; CHECK-NEXT: ret 200 %res = shl i32 %a, 16 201 ret i32 %res 202} 203 204; Combined with the register allocator, shift instructions can sometimes be 205; optimized away entirely. The least significant registers are simply stored 206; directly instead of moving them first. 207define void @shl_i32_16_ptr(i32 %a, ptr %ptr) { 208; CHECK-LABEL: shl_i32_16_ptr: 209; CHECK: ; %bb.0: 210; CHECK-NEXT: movw r30, r20 211; CHECK-NEXT: std Z+3, r23 212; CHECK-NEXT: std Z+2, r22 213; CHECK-NEXT: ldi r24, 0 214; CHECK-NEXT: ldi r25, 0 215; CHECK-NEXT: std Z+1, r25 216; CHECK-NEXT: st Z, r24 217; CHECK-NEXT: ret 218 %res = shl i32 %a, 16 219 store i32 %res, ptr %ptr 220 ret void 221} 222 223; shift only the most significant byte and then move it 224define i32 @shl_i32_28(i32 %a) { 225; CHECK-LABEL: shl_i32_28: 226; CHECK: ; %bb.0: 227; CHECK-NEXT: swap r22 228; CHECK-NEXT: andi r22, 240 229; CHECK-NEXT: mov r25, r22 230; CHECK-NEXT: mov r24, r1 231; CHECK-NEXT: mov r23, r1 232; CHECK-NEXT: mov r22, r1 233; CHECK-NEXT: ret 234 %res = shl i32 %a, 28 235 ret i32 %res 236} 237 238; move the rightmost bit to the leftmost bit and clear the rest 239define i32 @shl_i32_31(i32 %a) { 240; CHECK-LABEL: shl_i32_31: 241; CHECK: ; %bb.0: 242; CHECK-NEXT: lsr r22 243; CHECK-NEXT: mov r25, r1 244; CHECK-NEXT: ror r25 245; CHECK-NEXT: mov r24, r1 246; CHECK-NEXT: mov r23, r1 247; CHECK-NEXT: mov r22, r1 248; CHECK-NEXT: ret 249 %res = shl i32 %a, 31 250 ret i32 %res 251} 252 253define i32 @lshr_i32_1(i32 %a) { 254; CHECK-LABEL: lshr_i32_1: 255; CHECK: ; %bb.0: 256; CHECK-NEXT: lsr r25 257; CHECK-NEXT: ror r24 258; CHECK-NEXT: ror r23 259; CHECK-NEXT: ror r22 260; CHECK-NEXT: ret 261 %res = lshr i32 %a, 1 262 ret i32 %res 263} 264 265define i32 @lshr_i32_2(i32 %a) { 266; CHECK-LABEL: lshr_i32_2: 267; CHECK: ; %bb.0: 268; CHECK-NEXT: lsr r25 269; CHECK-NEXT: ror r24 270; CHECK-NEXT: ror r23 271; CHECK-NEXT: ror r22 272; CHECK-NEXT: lsr r25 273; CHECK-NEXT: ror r24 274; CHECK-NEXT: ror r23 275; CHECK-NEXT: ror r22 276; CHECK-NEXT: ret 277 %res = lshr i32 %a, 2 278 ret i32 %res 279} 280 281define i32 @lshr_i32_4(i32 %a) { 282; CHECK-LABEL: lshr_i32_4: 283; CHECK: ; %bb.0: 284; CHECK-NEXT: swap r22 285; CHECK-NEXT: andi r22, 15 286; CHECK-NEXT: swap r23 287; CHECK-NEXT: eor r22, r23 288; CHECK-NEXT: andi r23, 15 289; CHECK-NEXT: eor r22, r23 290; CHECK-NEXT: swap r24 291; CHECK-NEXT: eor r23, r24 292; CHECK-NEXT: andi r24, 15 293; CHECK-NEXT: eor r23, r24 294; CHECK-NEXT: swap r25 295; CHECK-NEXT: eor r24, r25 296; CHECK-NEXT: andi r25, 15 297; CHECK-NEXT: eor r24, r25 298; CHECK-NEXT: ret 299 %res = lshr i32 %a, 4 300 ret i32 %res 301} 302 303define i32 @lshr_i32_6(i32 %a) { 304; CHECK-LABEL: lshr_i32_6: 305; CHECK: ; %bb.0: 306; CHECK-NEXT: lsl r22 307; CHECK-NEXT: rol r23 308; CHECK-NEXT: rol r24 309; CHECK-NEXT: rol r25 310; CHECK-NEXT: mov r19, r1 311; CHECK-NEXT: rol r19 312; CHECK-NEXT: lsl r22 313; CHECK-NEXT: rol r23 314; CHECK-NEXT: rol r24 315; CHECK-NEXT: rol r25 316; CHECK-NEXT: rol r19 317; CHECK-NEXT: mov r22, r23 318; CHECK-NEXT: mov r23, r24 319; CHECK-NEXT: mov r18, r25 320; CHECK-NEXT: movw r24, r18 321; CHECK-NEXT: ret 322 %res = lshr i32 %a, 6 323 ret i32 %res 324} 325 326define i32 @lshr_i32_7(i32 %a) { 327; CHECK-LABEL: lshr_i32_7: 328; CHECK: ; %bb.0: 329; CHECK-NEXT: lsl r22 330; CHECK-NEXT: rol r23 331; CHECK-NEXT: rol r24 332; CHECK-NEXT: rol r25 333; CHECK-NEXT: mov r19, r1 334; CHECK-NEXT: rol r19 335; CHECK-NEXT: mov r22, r23 336; CHECK-NEXT: mov r23, r24 337; CHECK-NEXT: mov r18, r25 338; CHECK-NEXT: movw r24, r18 339; CHECK-NEXT: ret 340 %res = lshr i32 %a, 7 341 ret i32 %res 342} 343 344define i32 @lshr_i32_8(i32 %a) { 345; CHECK-LABEL: lshr_i32_8: 346; CHECK: ; %bb.0: 347; CHECK-NEXT: mov r22, r23 348; CHECK-NEXT: mov r23, r24 349; CHECK-NEXT: mov r24, r25 350; CHECK-NEXT: mov r25, r1 351; CHECK-NEXT: ret 352 %res = lshr i32 %a, 8 353 ret i32 %res 354} 355 356define i32 @lshr_i32_9(i32 %a) { 357; CHECK-LABEL: lshr_i32_9: 358; CHECK: ; %bb.0: 359; CHECK-NEXT: lsr r25 360; CHECK-NEXT: ror r24 361; CHECK-NEXT: ror r23 362; CHECK-NEXT: mov r22, r23 363; CHECK-NEXT: mov r23, r24 364; CHECK-NEXT: mov r24, r25 365; CHECK-NEXT: mov r25, r1 366; CHECK-NEXT: ret 367 %res = lshr i32 %a, 9 368 ret i32 %res 369} 370 371define i32 @lshr_i32_16(i32 %a) { 372; CHECK-LABEL: lshr_i32_16: 373; CHECK: ; %bb.0: 374; CHECK-NEXT: movw r22, r24 375; CHECK-NEXT: ldi r24, 0 376; CHECK-NEXT: ldi r25, 0 377; CHECK-NEXT: ret 378 %res = lshr i32 %a, 16 379 ret i32 %res 380} 381 382define i32 @lshr_i32_24(i32 %a) { 383; CHECK-LABEL: lshr_i32_24: 384; CHECK: ; %bb.0: 385; CHECK-NEXT: mov r22, r25 386; CHECK-NEXT: mov r23, r1 387; CHECK-NEXT: mov r24, r1 388; CHECK-NEXT: mov r25, r1 389; CHECK-NEXT: ret 390 %res = lshr i32 %a, 24 391 ret i32 %res 392} 393 394define i32 @lshr_i32_31(i32 %a) { 395; CHECK-LABEL: lshr_i32_31: 396; CHECK: ; %bb.0: 397; CHECK-NEXT: lsl r25 398; CHECK-NEXT: mov r22, r1 399; CHECK-NEXT: rol r22 400; CHECK-NEXT: mov r23, r1 401; CHECK-NEXT: mov r24, r1 402; CHECK-NEXT: mov r25, r1 403; CHECK-NEXT: ret 404 %res = lshr i32 %a, 31 405 ret i32 %res 406} 407 408define i32 @ashr_i32_1(i32 %a) { 409; CHECK-LABEL: ashr_i32_1: 410; CHECK: ; %bb.0: 411; CHECK-NEXT: asr r25 412; CHECK-NEXT: ror r24 413; CHECK-NEXT: ror r23 414; CHECK-NEXT: ror r22 415; CHECK-NEXT: ret 416 %res = ashr i32 %a, 1 417 ret i32 %res 418} 419 420define i32 @ashr_i32_2(i32 %a) { 421; CHECK-LABEL: ashr_i32_2: 422; CHECK: ; %bb.0: 423; CHECK-NEXT: asr r25 424; CHECK-NEXT: ror r24 425; CHECK-NEXT: ror r23 426; CHECK-NEXT: ror r22 427; CHECK-NEXT: asr r25 428; CHECK-NEXT: ror r24 429; CHECK-NEXT: ror r23 430; CHECK-NEXT: ror r22 431; CHECK-NEXT: ret 432 %res = ashr i32 %a, 2 433 ret i32 %res 434} 435 436; can't use the swap/andi/eor trick here 437define i32 @ashr_i32_4(i32 %a) { 438; CHECK-LABEL: ashr_i32_4: 439; CHECK: ; %bb.0: 440; CHECK-NEXT: asr r25 441; CHECK-NEXT: ror r24 442; CHECK-NEXT: ror r23 443; CHECK-NEXT: ror r22 444; CHECK-NEXT: asr r25 445; CHECK-NEXT: ror r24 446; CHECK-NEXT: ror r23 447; CHECK-NEXT: ror r22 448; CHECK-NEXT: asr r25 449; CHECK-NEXT: ror r24 450; CHECK-NEXT: ror r23 451; CHECK-NEXT: ror r22 452; CHECK-NEXT: asr r25 453; CHECK-NEXT: ror r24 454; CHECK-NEXT: ror r23 455; CHECK-NEXT: ror r22 456; CHECK-NEXT: ret 457 %res = ashr i32 %a, 4 458 ret i32 %res 459} 460 461define i32 @ashr_i32_7(i32 %a) { 462; CHECK-LABEL: ashr_i32_7: 463; CHECK: ; %bb.0: 464; CHECK-NEXT: lsl r22 465; CHECK-NEXT: rol r23 466; CHECK-NEXT: rol r24 467; CHECK-NEXT: rol r25 468; CHECK-NEXT: sbc r19, r19 469; CHECK-NEXT: mov r22, r23 470; CHECK-NEXT: mov r23, r24 471; CHECK-NEXT: mov r18, r25 472; CHECK-NEXT: movw r24, r18 473; CHECK-NEXT: ret 474 %res = ashr i32 %a, 7 475 ret i32 %res 476} 477 478; TODO: this could be optimized to 4 movs, instead of 5. 479define i32 @ashr_i32_8(i32 %a) { 480; CHECK-LABEL: ashr_i32_8: 481; CHECK: ; %bb.0: 482; CHECK-NEXT: mov r19, r25 483; CHECK-NEXT: lsl r19 484; CHECK-NEXT: sbc r19, r19 485; CHECK-NEXT: mov r22, r23 486; CHECK-NEXT: mov r23, r24 487; CHECK-NEXT: mov r18, r25 488; CHECK-NEXT: movw r24, r18 489; CHECK-NEXT: ret 490 %res = ashr i32 %a, 8 491 ret i32 %res 492} 493 494define i32 @ashr_i32_16(i32 %a) { 495; CHECK-LABEL: ashr_i32_16: 496; CHECK: ; %bb.0: 497; CHECK-NEXT: movw r22, r24 498; CHECK-NEXT: lsl r25 499; CHECK-NEXT: sbc r25, r25 500; CHECK-NEXT: mov r24, r25 501; CHECK-NEXT: ret 502 %res = ashr i32 %a, 16 503 ret i32 %res 504} 505 506define i32 @ashr_i32_17(i32 %a) { 507; CHECK-LABEL: ashr_i32_17: 508; CHECK: ; %bb.0: 509; CHECK-NEXT: movw r22, r24 510; CHECK-NEXT: lsl r25 511; CHECK-NEXT: sbc r25, r25 512; CHECK-NEXT: asr r23 513; CHECK-NEXT: ror r22 514; CHECK-NEXT: mov r24, r25 515; CHECK-NEXT: ret 516 %res = ashr i32 %a, 17 517 ret i32 %res 518} 519 520define i32 @ashr_i32_22(i32 %a) { 521; CHECK-LABEL: ashr_i32_22: 522; CHECK: ; %bb.0: 523; CHECK-NEXT: lsl r24 524; CHECK-NEXT: rol r25 525; CHECK-NEXT: sbc r18, r18 526; CHECK-NEXT: lsl r24 527; CHECK-NEXT: rol r25 528; CHECK-NEXT: mov r19, r18 529; CHECK-NEXT: mov r23, r18 530; CHECK-NEXT: rol r23 531; CHECK-NEXT: mov r22, r25 532; CHECK-NEXT: movw r24, r18 533; CHECK-NEXT: ret 534 %res = ashr i32 %a, 22 535 ret i32 %res 536} 537 538define i32 @ashr_i32_23(i32 %a) { 539; CHECK-LABEL: ashr_i32_23: 540; CHECK: ; %bb.0: 541; CHECK-NEXT: lsl r24 542; CHECK-NEXT: rol r25 543; CHECK-NEXT: sbc r23, r23 544; CHECK-NEXT: mov r22, r25 545; CHECK-NEXT: mov r24, r23 546; CHECK-NEXT: mov r25, r23 547; CHECK-NEXT: ret 548 %res = ashr i32 %a, 23 549 ret i32 %res 550} 551 552define i32 @ashr_i32_30(i32 %a) { 553; CHECK-LABEL: ashr_i32_30: 554; CHECK: ; %bb.0: 555; CHECK-NEXT: lsl r25 556; CHECK-NEXT: sbc r23, r23 557; CHECK-NEXT: lsl r25 558; CHECK-NEXT: mov r22, r23 559; CHECK-NEXT: rol r22 560; CHECK-NEXT: mov r24, r23 561; CHECK-NEXT: mov r25, r23 562; CHECK-NEXT: ret 563 %res = ashr i32 %a, 30 564 ret i32 %res 565} 566 567define i32 @ashr_i32_31(i32 %a) { 568; CHECK-LABEL: ashr_i32_31: 569; CHECK: ; %bb.0: 570; CHECK-NEXT: lsl r25 571; CHECK-NEXT: sbc r22, r22 572; CHECK-NEXT: mov r23, r22 573; CHECK-NEXT: movw r24, r22 574; CHECK-NEXT: ret 575 %res = ashr i32 %a, 31 576 ret i32 %res 577} 578