[AVR] Improve inline rotate/shift expansions
authorAyke van Laethem <aykevanlaethem@gmail.com>
Sun, 23 Aug 2020 12:17:29 +0000 (14:17 +0200)
committerAyke van Laethem <aykevanlaethem@gmail.com>
Sat, 31 Oct 2020 22:15:49 +0000 (23:15 +0100)
These expansions were rather inefficient and were done with more code
than necessary. This change optimizes them to use expansions more
similar to GCC. The code size is the same (when optimizing for code
size) but somehow LLVM reorders blocks in a non-optimal way. Still, this
should be an improvement with a reduction in code size of around 0.12%
(when building compiler-rt).

Differential Revision: https://reviews.llvm.org/D86418

llvm/lib/Target/AVR/AVRISelLowering.cpp
llvm/test/CodeGen/AVR/rot.ll
llvm/test/CodeGen/AVR/shift.ll

index a816c2412b08c0e12d2cce3fb33e83516638f0e5..9a464d0a52d8d6bdc3713f74f7d4c144ad8b6907 100644 (file)
@@ -1458,9 +1458,11 @@ MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr &MI,
 
   // Create loop block.
   MachineBasicBlock *LoopBB = F->CreateMachineBasicBlock(LLVM_BB);
+  MachineBasicBlock *CheckBB = F->CreateMachineBasicBlock(LLVM_BB);
   MachineBasicBlock *RemBB = F->CreateMachineBasicBlock(LLVM_BB);
 
   F->insert(I, LoopBB);
+  F->insert(I, CheckBB);
   F->insert(I, RemBB);
 
   // Update machine-CFG edges by transferring all successors of the current
@@ -1469,14 +1471,14 @@ MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr &MI,
                 BB->end());
   RemBB->transferSuccessorsAndUpdatePHIs(BB);
 
-  // Add adges BB => LoopBB => RemBB, BB => RemBB, LoopBB => LoopBB.
-  BB->addSuccessor(LoopBB);
-  BB->addSuccessor(RemBB);
-  LoopBB->addSuccessor(RemBB);
-  LoopBB->addSuccessor(LoopBB);
+  // Add edges BB => LoopBB => CheckBB => RemBB, CheckBB => LoopBB.
+  BB->addSuccessor(CheckBB);
+  LoopBB->addSuccessor(CheckBB);
+  CheckBB->addSuccessor(LoopBB);
+  CheckBB->addSuccessor(RemBB);
 
-  Register ShiftAmtReg = RI.createVirtualRegister(&AVR::LD8RegClass);
-  Register ShiftAmtReg2 = RI.createVirtualRegister(&AVR::LD8RegClass);
+  Register ShiftAmtReg = RI.createVirtualRegister(&AVR::GPR8RegClass);
+  Register ShiftAmtReg2 = RI.createVirtualRegister(&AVR::GPR8RegClass);
   Register ShiftReg = RI.createVirtualRegister(RC);
   Register ShiftReg2 = RI.createVirtualRegister(RC);
   Register ShiftAmtSrcReg = MI.getOperand(2).getReg();
@@ -1484,44 +1486,41 @@ MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr &MI,
   Register DstReg = MI.getOperand(0).getReg();
 
   // BB:
-  // cpi N, 0
-  // breq RemBB
-  BuildMI(BB, dl, TII.get(AVR::CPIRdK)).addReg(ShiftAmtSrcReg).addImm(0);
-  BuildMI(BB, dl, TII.get(AVR::BREQk)).addMBB(RemBB);
+  // rjmp CheckBB
+  BuildMI(BB, dl, TII.get(AVR::RJMPk)).addMBB(CheckBB);
 
   // LoopBB:
-  // ShiftReg = phi [%SrcReg, BB], [%ShiftReg2, LoopBB]
-  // ShiftAmt = phi [%N, BB],      [%ShiftAmt2, LoopBB]
   // ShiftReg2 = shift ShiftReg
+  auto ShiftMI = BuildMI(LoopBB, dl, TII.get(Opc), ShiftReg2).addReg(ShiftReg);
+  if (HasRepeatedOperand)
+    ShiftMI.addReg(ShiftReg);
+
+  // CheckBB:
+  // ShiftReg = phi [%SrcReg, BB], [%ShiftReg2, LoopBB]
+  // ShiftAmt = phi [%N,      BB], [%ShiftAmt2, LoopBB]
+  // DestReg  = phi [%SrcReg, BB], [%ShiftReg,  LoopBB]
   // ShiftAmt2 = ShiftAmt - 1;
-  BuildMI(LoopBB, dl, TII.get(AVR::PHI), ShiftReg)
+  // if (ShiftAmt2 >= 0) goto LoopBB;
+  BuildMI(CheckBB, dl, TII.get(AVR::PHI), ShiftReg)
       .addReg(SrcReg)
       .addMBB(BB)
       .addReg(ShiftReg2)
       .addMBB(LoopBB);
-  BuildMI(LoopBB, dl, TII.get(AVR::PHI), ShiftAmtReg)
+  BuildMI(CheckBB, dl, TII.get(AVR::PHI), ShiftAmtReg)
       .addReg(ShiftAmtSrcReg)
       .addMBB(BB)
       .addReg(ShiftAmtReg2)
       .addMBB(LoopBB);
-
-  auto ShiftMI = BuildMI(LoopBB, dl, TII.get(Opc), ShiftReg2).addReg(ShiftReg);
-  if (HasRepeatedOperand)
-    ShiftMI.addReg(ShiftReg);
-
-  BuildMI(LoopBB, dl, TII.get(AVR::SUBIRdK), ShiftAmtReg2)
-      .addReg(ShiftAmtReg)
-      .addImm(1);
-  BuildMI(LoopBB, dl, TII.get(AVR::BRNEk)).addMBB(LoopBB);
-
-  // RemBB:
-  // DestReg = phi [%SrcReg, BB], [%ShiftReg, LoopBB]
-  BuildMI(*RemBB, RemBB->begin(), dl, TII.get(AVR::PHI), DstReg)
+  BuildMI(CheckBB, dl, TII.get(AVR::PHI), DstReg)
       .addReg(SrcReg)
       .addMBB(BB)
       .addReg(ShiftReg2)
       .addMBB(LoopBB);
 
+  BuildMI(CheckBB, dl, TII.get(AVR::DECRd), ShiftAmtReg2)
+      .addReg(ShiftAmtReg);
+  BuildMI(CheckBB, dl, TII.get(AVR::BRPLk)).addMBB(LoopBB);
+
   MI.eraseFromParent(); // The pseudo instruction is gone now.
   return RemBB;
 }
index 3154234299541d7b39891c95998130210a17b733..81aa191d39934e09fc0664fe2f0389e79dd0d790 100644 (file)
@@ -6,14 +6,14 @@
 define i8 @rol8(i8 %val, i8 %amt) {
   ; CHECK:      andi r22, 7
 
-  ; CHECK-NEXT: cpi r22, 0
-  ; CHECK-NEXT: breq .LBB0_2
+  ; CHECK-NEXT: dec r22
+  ; CHECK-NEXT: brmi .LBB0_2
 
 ; CHECK-NEXT: .LBB0_1:
   ; CHECK-NEXT: lsl r24
   ; CHECK-NEXT: adc r24, r1
-  ; CHECK-NEXT: subi r22, 1
-  ; CHECK-NEXT: brne .LBB0_1
+  ; CHECK-NEXT: dec r22
+  ; CHECK-NEXT: brpl .LBB0_1
 
 ; CHECK-NEXT: .LBB0_2:
   ; CHECK-NEXT: ret
@@ -33,16 +33,16 @@ define i8 @rol8(i8 %val, i8 %amt) {
 define i8 @ror8(i8 %val, i8 %amt) {
   ; CHECK:      andi r22, 7
 
-  ; CHECK-NEXT: cpi r22, 0
-  ; CHECK-NEXT: breq .LBB1_2
+  ; CHECK-NEXT: dec r22
+  ; CHECK-NEXT: brmi .LBB1_2
 
 ; CHECK-NEXT: .LBB1_1:
   ; CHECK-NEXT: lsr r24
   ; CHECK-NEXT: ldi r0, 0
   ; CHECK-NEXT: ror r0
   ; CHECK-NEXT: or r24, r0
-  ; CHECK-NEXT: subi r22, 1
-  ; CHECK-NEXT: brne .LBB1_1
+  ; CHECK-NEXT: dec r22
+  ; CHECK-NEXT: brpl .LBB1_1
 
 ; CHECK-NEXT: .LBB1_2:
   ; CHECK-NEXT: ret
index 8d59050f0d356ad73b52006f4ee4894a1506a555..42ca766d3729de9ac631c6a82fc1c65df4a2413e 100644 (file)
@@ -1,5 +1,49 @@
 ; RUN: llc < %s -march=avr | FileCheck %s
 
+; Optimize for speed.
+; CHECK-LABEL: shift_i8_i8_speed
+define i8 @shift_i8_i8_speed(i8 %a, i8 %b) {
+  ; CHECK:        dec r22
+  ; CHECK-NEXT:   brmi .LBB0_2
+  ; CHECK-NEXT: .LBB0_1:
+  ; CHECK-NEXT:   lsl r24
+  ; CHECK-NEXT:   dec r22
+  ; CHECK-NEXT:   brpl .LBB0_1
+  ; CHECK-NEXT: .LBB0_2:
+  ; CHECK-NEXT:   ret
+  %result = shl i8 %a, %b
+  ret i8 %result
+}
+
+; Optimize for size (producing slightly smaller code).
+; CHECK-LABEL: shift_i8_i8_size
+define i8 @shift_i8_i8_size(i8 %a, i8 %b) optsize {
+  ; CHECK:      .LBB1_1:
+  ; CHECK-NEXT:   dec r22
+  ; CHECK-NEXT:   brmi .LBB1_3
+  ; CHECK:        lsl r24
+  ; CHECK-NEXT:   rjmp .LBB1_1
+  ; CHECK-NEXT: .LBB1_3:
+  ; CHECK-NEXT:   ret
+  %result = shl i8 %a, %b
+  ret i8 %result
+}
+
+; CHECK-LABEL: shift_i16_i16
+define i16 @shift_i16_i16(i16 %a, i16 %b) {
+  ; CHECK:        dec r22
+  ; CHECK-NEXT:   brmi .LBB2_2
+  ; CHECK-NEXT: .LBB2_1:
+  ; CHECK-NEXT:   lsl r24
+  ; CHECK-NEXT:   rol r25
+  ; CHECK-NEXT:   dec r22
+  ; CHECK-NEXT:   brpl .LBB2_1
+  ; CHECK-NEXT: .LBB2_2:
+  ; CHECK-NEXT:   ret
+  %result = shl i16 %a, %b
+  ret i16 %result
+}
+
 ; CHECK-LABEL: shift_i64_i64
 define i64 @shift_i64_i64(i64 %a, i64 %b) {
   ; CHECK: call    __ashldi3