[AVR] Optimize 8-bit logic left/right shifts
authorBen Shi <powerman1st@163.com>
Sat, 23 Jan 2021 15:54:16 +0000 (23:54 +0800)
committerBen Shi <powerman1st@163.com>
Sat, 23 Jan 2021 15:54:16 +0000 (23:54 +0800)
Reviewed By: dylanmckay

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

llvm/lib/Target/AVR/AVRISelLowering.cpp
llvm/lib/Target/AVR/AVRISelLowering.h
llvm/lib/Target/AVR/AVRInstrInfo.td
llvm/test/CodeGen/AVR/ctlz.ll
llvm/test/CodeGen/AVR/ctpop.ll
llvm/test/CodeGen/AVR/cttz.ll
llvm/test/CodeGen/AVR/shift.ll

index 9a464d0..bd5fd26 100644 (file)
@@ -334,6 +334,24 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
     llvm_unreachable("Invalid shift opcode");
   }
 
+  // Optimize int8 shifts.
+  if (VT.getSizeInBits() == 8) {
+    if (Op.getOpcode() == ISD::SHL && 4 <= ShiftAmount && ShiftAmount < 7) {
+      // Optimize LSL when 4 <= ShiftAmount <= 6.
+      Victim = DAG.getNode(AVRISD::SWAP, dl, VT, Victim);
+      Victim =
+          DAG.getNode(ISD::AND, dl, VT, Victim, DAG.getConstant(0xf0, dl, VT));
+      ShiftAmount -= 4;
+    } else if (Op.getOpcode() == ISD::SRL && 4 <= ShiftAmount &&
+               ShiftAmount < 7) {
+      // Optimize LSR when 4 <= ShiftAmount <= 6.
+      Victim = DAG.getNode(AVRISD::SWAP, dl, VT, Victim);
+      Victim =
+          DAG.getNode(ISD::AND, dl, VT, Victim, DAG.getConstant(0x0f, dl, VT));
+      ShiftAmount -= 4;
+    }
+  }
+
   while (ShiftAmount--) {
     Victim = DAG.getNode(Opc8, dl, VT, Victim);
   }
index d1eaf53..ed9aea7 100644 (file)
@@ -56,6 +56,8 @@ enum NodeType {
   CMPC,
   /// Test for zero or minus instruction.
   TST,
+  /// Swap Rd[7:4] <-> Rd[3:0].
+  SWAP,
   /// Operand 0 and operand 1 are selection variable, operand 2
   /// is condition code and operand 3 is flag operand.
   SELECT_CC
index 8de85f6..926d1f8 100644 (file)
@@ -67,6 +67,9 @@ def AVRrolLoop : SDNode<"AVRISD::ROLLOOP", SDTIntShiftOp>;
 def AVRrorLoop : SDNode<"AVRISD::RORLOOP", SDTIntShiftOp>;
 def AVRasrLoop : SDNode<"AVRISD::ASRLOOP", SDTIntShiftOp>;
 
+// SWAP node.
+def AVRSwap : SDNode<"AVRISD::SWAP", SDTIntUnaryOp>;
+
 //===----------------------------------------------------------------------===//
 // AVR Operands, Complex Patterns and Transformations Definitions.
 //===----------------------------------------------------------------------===//
@@ -1729,7 +1732,7 @@ def SWAPRd : FRd<0b1001,
                  (outs GPR8:$rd),
                  (ins GPR8:$src),
                  "swap\t$rd",
-                 [(set i8:$rd, (bswap i8:$src))]>;
+                 [(set i8:$rd, (AVRSwap i8:$src))]>;
 
 // IO register bit set/clear operations.
 //:TODO: add patterns when popcount(imm)==2 to be expanded with 2 sbi/cbi
index 8681b8a..93c2f0b 100644 (file)
@@ -10,8 +10,7 @@ declare i8 @llvm.ctlz.i8(i8)
 
 ; CHECK-LABEL: count_leading_zeros:
 ; CHECK: cpi    [[RESULT:r[0-9]+]], 0
-; CHECK: brne   .LBB0_1
-; CHECK: rjmp   .LBB0_2
+; CHECK: breq   .LBB0_2
 ; CHECK: mov    [[SCRATCH:r[0-9]+]], {{.*}}[[RESULT]]
 ; CHECK: lsr    {{.*}}[[SCRATCH]]
 ; CHECK: or     {{.*}}[[SCRATCH]], {{.*}}[[RESULT]]
@@ -20,10 +19,8 @@ declare i8 @llvm.ctlz.i8(i8)
 ; CHECK: lsr    {{.*}}[[RESULT]]
 ; CHECK: or     {{.*}}[[RESULT]], {{.*}}[[SCRATCH]]
 ; CHECK: mov    {{.*}}[[SCRATCH]], {{.*}}[[RESULT]]
-; CHECK: lsr    {{.*}}[[SCRATCH]]
-; CHECK: lsr    {{.*}}[[SCRATCH]]
-; CHECK: lsr    {{.*}}[[SCRATCH]]
-; CHECK: lsr    {{.*}}[[SCRATCH]]
+; CHECK: swap   {{.*}}[[SCRATCH]]
+; CHECK: andi   {{.*}}[[SCRATCH]], 15
 ; CHECK: or     {{.*}}[[SCRATCH]], {{.*}}[[RESULT]]
 ; CHECK: com    {{.*}}[[SCRATCH]]
 ; CHECK: mov    {{.*}}[[RESULT]], {{.*}}[[SCRATCH]]
@@ -37,10 +34,7 @@ declare i8 @llvm.ctlz.i8(i8)
 ; CHECK: andi   {{.*}}[[SCRATCH]], 51
 ; CHECK: add    {{.*}}[[SCRATCH]], {{.*}}[[RESULT]]
 ; CHECK: mov    {{.*}}[[RESULT]], {{.*}}[[SCRATCH]]
-; CHECK: lsr    {{.*}}[[RESULT]]
-; CHECK: lsr    {{.*}}[[RESULT]]
-; CHECK: lsr    {{.*}}[[RESULT]]
-; CHECK: lsr    {{.*}}[[RESULT]]
+; CHECK: swap   {{.*}}[[RESULT]]
 ; CHECK: add    {{.*}}[[RESULT]], {{.*}}[[SCRATCH]]
 ; CHECK: andi   {{.*}}[[RESULT]], 15
 ; CHECK: ret
index 3c0c71e..a2be891 100644 (file)
@@ -20,10 +20,7 @@ declare i8 @llvm.ctpop.i8(i8)
 ; CHECK: andi   {{.*}}[[RESULT]], 51
 ; CHECK: add    {{.*}}[[RESULT]], {{.*}}[[SCRATCH]]
 ; CHECK: mov    {{.*}}[[SCRATCH]], {{.*}}[[RESULT]]
-; CHECK: lsr    {{.*}}[[SCRATCH]]
-; CHECK: lsr    {{.*}}[[SCRATCH]]
-; CHECK: lsr    {{.*}}[[SCRATCH]]
-; CHECK: lsr    {{.*}}[[SCRATCH]]
+; CHECK: swap   {{.*}}[[SCRATCH]]
 ; CHECK: add    {{.*}}[[SCRATCH]], {{.*}}[[RESULT]]
 ; CHECK: andi   {{.*}}[[SCRATCH]], 15
 ; CHECK: mov    {{.*}}[[RESULT]], {{.*}}[[SCRATCH]]
index 60ba57e..b68994f 100644 (file)
@@ -26,10 +26,7 @@ declare i8 @llvm.cttz.i8(i8)
 ; CHECK: andi   {{.*}}[[RESULT]], 51
 ; CHECK: add    {{.*}}[[RESULT]], {{.*}}[[SCRATCH]]
 ; CHECK: mov    {{.*}}[[SCRATCH]], {{.*}}[[RESULT]]
-; CHECK: lsr    {{.*}}[[SCRATCH]]
-; CHECK: lsr    {{.*}}[[SCRATCH]]
-; CHECK: lsr    {{.*}}[[SCRATCH]]
-; CHECK: lsr    {{.*}}[[SCRATCH]]
+; CHECK: swap   {{.*}}[[SCRATCH]]
 ; CHECK: add    {{.*}}[[SCRATCH]], {{.*}}[[RESULT]]
 ; CHECK: andi   {{.*}}[[SCRATCH]], 15
 ; CHECK: mov    {{.*}}[[RESULT]], {{.*}}[[SCRATCH]]
index 42ca766..e5d3aee 100644 (file)
@@ -50,3 +50,105 @@ define i64 @shift_i64_i64(i64 %a, i64 %b) {
   %result = shl i64 %a, %b
   ret i64 %result
 }
+
+define i8 @lsl_i8_1(i8 %a) {
+; CHECK-LABEL: lsl_i8_1:
+; CHECK:       lsl r24
+  %res = shl i8 %a, 1
+  ret i8 %res
+}
+
+define i8 @lsl_i8_2(i8 %a) {
+; CHECK-LABEL: lsl_i8_2:
+; CHECK:       lsl r24
+; CHECK-NEXT:  lsl r24
+  %res = shl i8 %a, 2
+  ret i8 %res
+}
+
+define i8 @lsl_i8_3(i8 %a) {
+; CHECK-LABEL: lsl_i8_3:
+; CHECK:       lsl r24
+; CHECK-NEXT:  lsl r24
+; CHECK-NEXT:  lsl r24
+  %res = shl i8 %a, 3
+  ret i8 %res
+}
+
+define i8 @lsl_i8_4(i8 %a) {
+; CHECK-LABEL: lsl_i8_4:
+; CHECK:       swap r24
+; CHECK-NEXT:  andi r24, -16
+  %res = shl i8 %a, 4
+  ret i8 %res
+}
+
+define i8 @lsl_i8_5(i8 %a) {
+; CHECK-LABEL: lsl_i8_5:
+; CHECK:       swap r24
+; CHECK-NEXT:  andi r24, -16
+; CHECK-NEXT:  lsl r24
+  %res = shl i8 %a, 5
+  ret i8 %res
+}
+
+define i8 @lsl_i8_6(i8 %a) {
+; CHECK-LABEL: lsl_i8_6:
+; CHECK:       swap r24
+; CHECK-NEXT:  andi r24, -16
+; CHECK-NEXT:  lsl r24
+; CHECK-NEXT:  lsl r24
+  %res = shl i8 %a, 6
+  ret i8 %res
+}
+
+define i8 @lsr_i8_1(i8 %a) {
+; CHECK-LABEL: lsr_i8_1:
+; CHECK:       lsr r24
+  %res = lshr i8 %a, 1
+  ret i8 %res
+}
+
+define i8 @lsr_i8_2(i8 %a) {
+; CHECK-LABEL: lsr_i8_2:
+; CHECK:       lsr r24
+; CHECK-NEXT:  lsr r24
+  %res = lshr i8 %a, 2
+  ret i8 %res
+}
+
+define i8 @lsr_i8_3(i8 %a) {
+; CHECK-LABEL: lsr_i8_3:
+; CHECK:       lsr r24
+; CHECK-NEXT:  lsr r24
+; CHECK-NEXT:  lsr r24
+  %res = lshr i8 %a, 3
+  ret i8 %res
+}
+
+define i8 @lsr_i8_4(i8 %a) {
+; CHECK-LABEL: lsr_i8_4:
+; CHECK:       swap r24
+; CHECK-NEXT:  andi r24, 15
+  %res = lshr i8 %a, 4
+  ret i8 %res
+}
+
+define i8 @lsr_i8_5(i8 %a) {
+; CHECK-LABEL: lsr_i8_5:
+; CHECK:       swap r24
+; CHECK-NEXT:  andi r24, 15
+; CHECK-NEXT:  lsr r24
+  %res = lshr i8 %a, 5
+  ret i8 %res
+}
+
+define i8 @lsr_i8_6(i8 %a) {
+; CHECK-LABEL: lsr_i8_6:
+; CHECK:       swap r24
+; CHECK-NEXT:  andi r24, 15
+; CHECK-NEXT:  lsr r24
+; CHECK-NEXT:  lsr r24
+  %res = lshr i8 %a, 6
+  ret i8 %res
+}