[llvm] 50f1aa1 - [AVR] Optimize 16-bit int shift

Ben Shi via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 27 23:10:23 PST 2021


Author: Ben Shi
Date: 2021-01-28T15:10:11+08:00
New Revision: 50f1aa1db5c59499b40abda1f565a3db1ebd7ee4

URL: https://github.com/llvm/llvm-project/commit/50f1aa1db5c59499b40abda1f565a3db1ebd7ee4
DIFF: https://github.com/llvm/llvm-project/commit/50f1aa1db5c59499b40abda1f565a3db1ebd7ee4.diff

LOG: [AVR] Optimize 16-bit int shift

Reviewed By: dylanmckay

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

Added: 
    

Modified: 
    llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
    llvm/lib/Target/AVR/AVRISelLowering.cpp
    llvm/lib/Target/AVR/AVRISelLowering.h
    llvm/lib/Target/AVR/AVRInstrInfo.td
    llvm/test/CodeGen/AVR/shift.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
index a48d3d134bb5..2f7e017e550a 100644
--- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
@@ -1402,6 +1402,135 @@ bool AVRExpandPseudo::expand<AVR::LSLWRd>(Block &MBB, BlockIt MBBI) {
   return true;
 }
 
+template <>
+bool AVRExpandPseudo::expand<AVR::LSLW4Rd>(Block &MBB, BlockIt MBBI) {
+  MachineInstr &MI = *MBBI;
+  Register DstLoReg, DstHiReg;
+  Register DstReg = MI.getOperand(0).getReg();
+  bool DstIsDead = MI.getOperand(0).isDead();
+  bool DstIsKill = MI.getOperand(1).isKill();
+  bool ImpIsDead = MI.getOperand(2).isDead();
+  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+  // swap Rh
+  // swap Rl
+  buildMI(MBB, MBBI, AVR::SWAPRd)
+      .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstHiReg, getKillRegState(DstIsKill));
+  buildMI(MBB, MBBI, AVR::SWAPRd)
+      .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+  // andi Rh, 0xf0
+  auto MI0 =
+      buildMI(MBB, MBBI, AVR::ANDIRdK)
+          .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstHiReg, getKillRegState(DstIsKill))
+          .addImm(0xf0);
+  // SREG is implicitly dead.
+  MI0->getOperand(3).setIsDead();
+
+  // eor Rh, Rl
+  auto MI1 =
+      buildMI(MBB, MBBI, AVR::EORRdRr)
+          .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstHiReg, getKillRegState(DstIsKill))
+          .addReg(DstLoReg, getKillRegState(DstIsKill));
+  // SREG is implicitly dead.
+  MI1->getOperand(3).setIsDead();
+
+  // andi Rl, 0xf0
+  auto MI2 =
+      buildMI(MBB, MBBI, AVR::ANDIRdK)
+          .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstLoReg, getKillRegState(DstIsKill))
+          .addImm(0xf0);
+  // SREG is implicitly dead.
+  MI2->getOperand(3).setIsDead();
+
+  // eor Rh, Rl
+  auto MI3 =
+      buildMI(MBB, MBBI, AVR::EORRdRr)
+          .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstHiReg, getKillRegState(DstIsKill))
+          .addReg(DstLoReg, getKillRegState(DstIsKill));
+  if (ImpIsDead)
+    MI3->getOperand(3).setIsDead();
+
+  MI.eraseFromParent();
+  return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LSLW8Rd>(Block &MBB, BlockIt MBBI) {
+  MachineInstr &MI = *MBBI;
+  Register DstLoReg, DstHiReg;
+  Register DstReg = MI.getOperand(0).getReg();
+  bool DstIsDead = MI.getOperand(0).isDead();
+  bool DstIsKill = MI.getOperand(1).isKill();
+  bool ImpIsDead = MI.getOperand(2).isDead();
+  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+  // mov Rh, Rl
+  buildMI(MBB, MBBI, AVR::MOVRdRr)
+      .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+  // clr Rl
+  auto MIBLO =
+      buildMI(MBB, MBBI, AVR::EORRdRr)
+          .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstLoReg, getKillRegState(DstIsKill))
+          .addReg(DstLoReg, getKillRegState(DstIsKill));
+  if (ImpIsDead)
+    MIBLO->getOperand(3).setIsDead();
+
+  MI.eraseFromParent();
+  return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LSLW12Rd>(Block &MBB, BlockIt MBBI) {
+  MachineInstr &MI = *MBBI;
+  Register DstLoReg, DstHiReg;
+  Register DstReg = MI.getOperand(0).getReg();
+  bool DstIsDead = MI.getOperand(0).isDead();
+  bool DstIsKill = MI.getOperand(1).isKill();
+  bool ImpIsDead = MI.getOperand(2).isDead();
+  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+  // mov Rh, Rl
+  buildMI(MBB, MBBI, AVR::MOVRdRr)
+      .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+  // swap Rh
+  buildMI(MBB, MBBI, AVR::SWAPRd)
+      .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+  // andi Rh, 0xf0
+  auto MI0 =
+      buildMI(MBB, MBBI, AVR::ANDIRdK)
+          .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstHiReg, getKillRegState(DstIsKill))
+          .addImm(0xf0);
+  // SREG is implicitly dead.
+  MI0->getOperand(3).setIsDead();
+
+  // clr Rl
+  auto MI1 =
+      buildMI(MBB, MBBI, AVR::EORRdRr)
+          .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstLoReg, getKillRegState(DstIsKill))
+          .addReg(DstLoReg, getKillRegState(DstIsKill));
+  if (ImpIsDead)
+    MI1->getOperand(3).setIsDead();
+
+  MI.eraseFromParent();
+  return true;
+}
+
 template <>
 bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
   MachineInstr &MI = *MBBI;
@@ -1433,6 +1562,135 @@ bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
   return true;
 }
 
+template <>
+bool AVRExpandPseudo::expand<AVR::LSRW4Rd>(Block &MBB, BlockIt MBBI) {
+  MachineInstr &MI = *MBBI;
+  Register DstLoReg, DstHiReg;
+  Register DstReg = MI.getOperand(0).getReg();
+  bool DstIsDead = MI.getOperand(0).isDead();
+  bool DstIsKill = MI.getOperand(1).isKill();
+  bool ImpIsDead = MI.getOperand(2).isDead();
+  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+  // swap Rh
+  // swap Rl
+  buildMI(MBB, MBBI, AVR::SWAPRd)
+      .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstHiReg, getKillRegState(DstIsKill));
+  buildMI(MBB, MBBI, AVR::SWAPRd)
+      .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+  // andi Rl, 0xf
+  auto MI0 =
+      buildMI(MBB, MBBI, AVR::ANDIRdK)
+          .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstLoReg, getKillRegState(DstIsKill))
+          .addImm(0xf);
+  // SREG is implicitly dead.
+  MI0->getOperand(3).setIsDead();
+
+  // eor Rl, Rh
+  auto MI1 =
+      buildMI(MBB, MBBI, AVR::EORRdRr)
+          .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstLoReg, getKillRegState(DstIsKill))
+          .addReg(DstHiReg, getKillRegState(DstIsKill));
+  // SREG is implicitly dead.
+  MI1->getOperand(3).setIsDead();
+
+  // andi Rh, 0xf
+  auto MI2 =
+      buildMI(MBB, MBBI, AVR::ANDIRdK)
+          .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstHiReg, getKillRegState(DstIsKill))
+          .addImm(0xf);
+  // SREG is implicitly dead.
+  MI2->getOperand(3).setIsDead();
+
+  // eor Rl, Rh
+  auto MI3 =
+      buildMI(MBB, MBBI, AVR::EORRdRr)
+          .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstLoReg, getKillRegState(DstIsKill))
+          .addReg(DstHiReg, getKillRegState(DstIsKill));
+  if (ImpIsDead)
+    MI3->getOperand(3).setIsDead();
+
+  MI.eraseFromParent();
+  return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LSRW8Rd>(Block &MBB, BlockIt MBBI) {
+  MachineInstr &MI = *MBBI;
+  Register DstLoReg, DstHiReg;
+  Register DstReg = MI.getOperand(0).getReg();
+  bool DstIsDead = MI.getOperand(0).isDead();
+  bool DstIsKill = MI.getOperand(1).isKill();
+  bool ImpIsDead = MI.getOperand(2).isDead();
+  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+  // Move upper byte to lower byte.
+  buildMI(MBB, MBBI, AVR::MOVRdRr)
+      .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstHiReg);
+
+  // Clear upper byte.
+  auto MIBHI =
+      buildMI(MBB, MBBI, AVR::EORRdRr)
+          .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstHiReg, getKillRegState(DstIsKill))
+          .addReg(DstHiReg, getKillRegState(DstIsKill));
+  if (ImpIsDead)
+    MIBHI->getOperand(3).setIsDead();
+
+  MI.eraseFromParent();
+  return true;
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LSRW12Rd>(Block &MBB, BlockIt MBBI) {
+  MachineInstr &MI = *MBBI;
+  Register DstLoReg, DstHiReg;
+  Register DstReg = MI.getOperand(0).getReg();
+  bool DstIsDead = MI.getOperand(0).isDead();
+  bool DstIsKill = MI.getOperand(1).isKill();
+  bool ImpIsDead = MI.getOperand(2).isDead();
+  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+  // Move upper byte to lower byte.
+  buildMI(MBB, MBBI, AVR::MOVRdRr)
+      .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstHiReg);
+
+  // swap Rl
+  buildMI(MBB, MBBI, AVR::SWAPRd)
+      .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+  // andi Rl, 0xf
+  auto MI0 =
+      buildMI(MBB, MBBI, AVR::ANDIRdK)
+          .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstLoReg, getKillRegState(DstIsKill))
+          .addImm(0xf);
+  // SREG is implicitly dead.
+  MI0->getOperand(3).setIsDead();
+
+  // Clear upper byte.
+  auto MIBHI =
+      buildMI(MBB, MBBI, AVR::EORRdRr)
+          .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstHiReg, getKillRegState(DstIsKill))
+          .addReg(DstHiReg, getKillRegState(DstIsKill));
+  if (ImpIsDead)
+    MIBHI->getOperand(3).setIsDead();
+
+  MI.eraseFromParent();
+  return true;
+}
+
 template <>
 bool AVRExpandPseudo::expand<AVR::RORWRd>(Block &MBB, BlockIt MBBI) {
   llvm_unreachable("RORW unimplemented");
@@ -1476,6 +1734,39 @@ bool AVRExpandPseudo::expand<AVR::ASRWRd>(Block &MBB, BlockIt MBBI) {
   return true;
 }
 
+template <>
+bool AVRExpandPseudo::expand<AVR::ASRW8Rd>(Block &MBB, BlockIt MBBI) {
+  MachineInstr &MI = *MBBI;
+  Register DstLoReg, DstHiReg;
+  Register DstReg = MI.getOperand(0).getReg();
+  bool DstIsDead = MI.getOperand(0).isDead();
+  bool DstIsKill = MI.getOperand(1).isKill();
+  bool ImpIsDead = MI.getOperand(2).isDead();
+  TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+
+  // Move upper byte to lower byte.
+  buildMI(MBB, MBBI, AVR::MOVRdRr)
+      .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+  // Move the sign bit to the C flag.
+  buildMI(MBB, MBBI, AVR::ADDRdRr).addReg(DstHiReg)
+      .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+  // Set upper byte to 0 or -1.
+  auto MIBHI =
+      buildMI(MBB, MBBI, AVR::SBCRdRr)
+          .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstHiReg, getKillRegState(DstIsKill))
+          .addReg(DstHiReg, getKillRegState(DstIsKill));
+  if (ImpIsDead)
+    MIBHI->getOperand(3).setIsDead();
+
+  MI.eraseFromParent();
+  return true;
+}
+
 template <>
 bool AVRExpandPseudo::expand<AVR::LSLB7Rd>(Block &MBB, BlockIt MBBI) {
   MachineInstr &MI = *MBBI;
@@ -1798,10 +2089,17 @@ bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
     EXPAND(AVR::ROLBRd);
     EXPAND(AVR::RORBRd);
     EXPAND(AVR::LSLWRd);
+    EXPAND(AVR::LSLW4Rd);
+    EXPAND(AVR::LSLW8Rd);
+    EXPAND(AVR::LSLW12Rd);
     EXPAND(AVR::LSRWRd);
+    EXPAND(AVR::LSRW4Rd);
+    EXPAND(AVR::LSRW8Rd);
+    EXPAND(AVR::LSRW12Rd);
     EXPAND(AVR::RORWRd);
     EXPAND(AVR::ROLWRd);
     EXPAND(AVR::ASRWRd);
+    EXPAND(AVR::ASRW8Rd);
     EXPAND(AVR::LSLB7Rd);
     EXPAND(AVR::LSRB7Rd);
     EXPAND(AVR::ASRB7Rd);

diff  --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp
index 3e7c2984655a..944f7b681b5c 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp
@@ -334,7 +334,7 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
     llvm_unreachable("Invalid shift opcode");
   }
 
-  // Optimize int8 shifts.
+  // Optimize int8/int16 shifts.
   if (VT.getSizeInBits() == 8) {
     if (Op.getOpcode() == ISD::SHL && 4 <= ShiftAmount && ShiftAmount < 7) {
       // Optimize LSL when 4 <= ShiftAmount <= 6.
@@ -362,6 +362,50 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
       Victim = DAG.getNode(AVRISD::ASR7, dl, VT, Victim);
       ShiftAmount = 0;
     }
+  } else if (VT.getSizeInBits() == 16) {
+    if (4 <= ShiftAmount && ShiftAmount < 8)
+      switch (Op.getOpcode()) {
+      case ISD::SHL:
+        Victim = DAG.getNode(AVRISD::LSL4, dl, VT, Victim);
+        ShiftAmount -= 4;
+        break;
+      case ISD::SRL:
+        Victim = DAG.getNode(AVRISD::LSR4, dl, VT, Victim);
+        ShiftAmount -= 4;
+        break;
+      default:
+        break;
+      }
+    else if (8 <= ShiftAmount && ShiftAmount < 12)
+      switch (Op.getOpcode()) {
+      case ISD::SHL:
+        Victim = DAG.getNode(AVRISD::LSL8, dl, VT, Victim);
+        ShiftAmount -= 8;
+        break;
+      case ISD::SRL:
+        Victim = DAG.getNode(AVRISD::LSR8, dl, VT, Victim);
+        ShiftAmount -= 8;
+        break;
+      case ISD::SRA:
+        Victim = DAG.getNode(AVRISD::ASR8, dl, VT, Victim);
+        ShiftAmount -= 8;
+        break;
+      default:
+        break;
+      }
+    else if (12 <= ShiftAmount)
+      switch (Op.getOpcode()) {
+      case ISD::SHL:
+        Victim = DAG.getNode(AVRISD::LSL12, dl, VT, Victim);
+        ShiftAmount -= 12;
+        break;
+      case ISD::SRL:
+        Victim = DAG.getNode(AVRISD::LSR12, dl, VT, Victim);
+        ShiftAmount -= 12;
+        break;
+      default:
+        break;
+      }
   }
 
   while (ShiftAmount--) {

diff  --git a/llvm/lib/Target/AVR/AVRISelLowering.h b/llvm/lib/Target/AVR/AVRISelLowering.h
index 7aff4159211b..3532b09a3ba0 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.h
+++ b/llvm/lib/Target/AVR/AVRISelLowering.h
@@ -36,8 +36,15 @@ enum NodeType {
   /// TargetExternalSymbol, and TargetGlobalAddress.
   WRAPPER,
   LSL,     ///< Logical shift left.
+  LSL4,    ///< Logical shift left 4 bits.
+  LSL8,    ///< Logical shift left 8 bits.
+  LSL12,   ///< Logical shift left 12 bits.
   LSR,     ///< Logical shift right.
+  LSR4,    ///< Logical shift right 4 bits.
+  LSR8,    ///< Logical shift right 8 bits.
+  LSR12,   ///< Logical shift right 12 bits.
   ASR,     ///< Arithmetic shift right.
+  ASR8,    ///< Arithmetic shift right 8 bits.
   LSL7,    ///< Logical shift left 7 bits.
   LSR7,    ///< Logical shift right 7 bits.
   ASR7,    ///< Arithmetic shift right 7 bits.

diff  --git a/llvm/lib/Target/AVR/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td
index 9f7c16fc96d2..e967e107a1c8 100644
--- a/llvm/lib/Target/AVR/AVRInstrInfo.td
+++ b/llvm/lib/Target/AVR/AVRInstrInfo.td
@@ -55,10 +55,17 @@ def AVRselectcc: SDNode<"AVRISD::SELECT_CC", SDT_AVRSelectCC, [SDNPInGlue]>;
 
 // Shift nodes.
 def AVRlsl : SDNode<"AVRISD::LSL", SDTIntUnaryOp>;
+def AVRlsl4 : SDNode<"AVRISD::LSL4", SDTIntUnaryOp>;
+def AVRlsl8 : SDNode<"AVRISD::LSL8", SDTIntUnaryOp>;
+def AVRlsl12 : SDNode<"AVRISD::LSL12", SDTIntUnaryOp>;
 def AVRlsr : SDNode<"AVRISD::LSR", SDTIntUnaryOp>;
+def AVRlsr4 : SDNode<"AVRISD::LSR4", SDTIntUnaryOp>;
+def AVRlsr8 : SDNode<"AVRISD::LSR8", SDTIntUnaryOp>;
+def AVRlsr12 : SDNode<"AVRISD::LSR12", SDTIntUnaryOp>;
 def AVRrol : SDNode<"AVRISD::ROL", SDTIntUnaryOp>;
 def AVRror : SDNode<"AVRISD::ROR", SDTIntUnaryOp>;
 def AVRasr : SDNode<"AVRISD::ASR", SDTIntUnaryOp>;
+def AVRasr8 : SDNode<"AVRISD::ASR8", SDTIntUnaryOp>;
 def AVRlsl7 : SDNode<"AVRISD::LSL7", SDTIntUnaryOp>;
 def AVRlsr7 : SDNode<"AVRISD::LSR7", SDTIntUnaryOp>;
 def AVRasr7 : SDNode<"AVRISD::ASR7", SDTIntUnaryOp>;
@@ -1674,6 +1681,21 @@ Defs = [SREG] in
                        "lslb7\t$rd",
                        [(set i8:$rd, (AVRlsl7 i8:$src)), (implicit SREG)]>;
 
+  def LSLW4Rd : Pseudo<(outs DREGS:$rd),
+                       (ins DREGS:$src),
+                       "lslw4\t$rd",
+                       [(set i16:$rd, (AVRlsl4 i16:$src)), (implicit SREG)]>;
+
+  def LSLW8Rd : Pseudo<(outs DREGS:$rd),
+                       (ins DREGS:$src),
+                       "lslw8\t$rd",
+                       [(set i16:$rd, (AVRlsl8 i16:$src)), (implicit SREG)]>;
+
+  def LSLW12Rd : Pseudo<(outs DREGS:$rd),
+                       (ins DREGS:$src),
+                       "lslw12\t$rd",
+                       [(set i16:$rd, (AVRlsl12 i16:$src)), (implicit SREG)]>;
+
   def LSRRd : FRd<0b1001,
                   0b0100110,
                   (outs GPR8:$rd),
@@ -1691,6 +1713,21 @@ Defs = [SREG] in
                       "lsrw\t$rd",
                       [(set i16:$rd, (AVRlsr i16:$src)), (implicit SREG)]>;
 
+  def LSRW4Rd : Pseudo<(outs DREGS:$rd),
+                       (ins DREGS:$src),
+                       "lsrw4\t$rd",
+                       [(set i16:$rd, (AVRlsr4 i16:$src)), (implicit SREG)]>;
+
+  def LSRW8Rd : Pseudo<(outs DREGS:$rd),
+                       (ins DREGS:$src),
+                       "lsrw8\t$rd",
+                       [(set i16:$rd, (AVRlsr8 i16:$src)), (implicit SREG)]>;
+
+  def LSRW12Rd : Pseudo<(outs DREGS:$rd),
+                       (ins DREGS:$src),
+                       "lsrw12\t$rd",
+                       [(set i16:$rd, (AVRlsr12 i16:$src)), (implicit SREG)]>;
+
   def ASRRd : FRd<0b1001,
                   0b0100101,
                   (outs GPR8:$rd),
@@ -1708,6 +1745,11 @@ Defs = [SREG] in
                       "asrw\t$rd",
                       [(set i16:$rd, (AVRasr i16:$src)), (implicit SREG)]>;
 
+  def ASRW8Rd : Pseudo<(outs DREGS:$rd),
+                       (ins DREGS:$src),
+                       "asrw8\t$rd",
+                       [(set i16:$rd, (AVRasr8 i16:$src)), (implicit SREG)]>;
+
   // Bit rotate operations.
   let Uses = [SREG] in
   {
@@ -2123,12 +2165,7 @@ def : Pat<(store i16:$src, (i16 (AVRWrapper tglobaladdr:$dst))),
 def : Pat<(i16 (AVRWrapper tblockaddress:$dst)),
           (LDIWRdK tblockaddress:$dst)>;
 
-// hi-reg truncation : trunc(int16 >> 8)
-//:FIXME: i think it's better to emit an extract subreg node in the DAG than
-// all this mess once we get optimal shift code
-// lol... I think so, too. [@agnat]
-def : Pat<(i8 (trunc (AVRlsr (AVRlsr (AVRlsr (AVRlsr (AVRlsr (AVRlsr (AVRlsr
-                     (AVRlsr DREGS:$src)))))))))),
+def : Pat<(i8 (trunc (AVRlsr8 DREGS:$src))),
           (EXTRACT_SUBREG DREGS:$src, sub_hi)>;
 
 // :FIXME: DAGCombiner produces an shl node after legalization from these seq:

diff  --git a/llvm/test/CodeGen/AVR/shift.ll b/llvm/test/CodeGen/AVR/shift.ll
index 7a21a016e5c8..34042b3a1199 100644
--- a/llvm/test/CodeGen/AVR/shift.ll
+++ b/llvm/test/CodeGen/AVR/shift.ll
@@ -178,3 +178,93 @@ define i8 @asr_i8_7(i8 %a) {
   %result = ashr i8 %a, 7
   ret i8 %result
 }
+
+define i16 @lsl_i16_5(i16 %a) {
+; CHECK-LABEL: lsl_i16_5
+; CHECK:       swap r25
+; CHECK-NEXT:  swap r24
+; CHECK-NEXT:  andi r25, 240
+; CHECK-NEXT:  eor r25, r24
+; CHECK-NEXT:  andi r24, 240
+; CHECK-NEXT:  eor r25, r24
+; CHECK-NEXT:  lsl r24
+; CHECK-NEXT:  rol r25
+; CHECK-NEXT:  ret
+  %result = shl i16 %a, 5
+  ret i16 %result
+}
+
+define i16 @lsl_i16_9(i16 %a) {
+; CHECK-LABEL: lsl_i16_9
+; CHECK:       mov r25, r24
+; CHECK-NEXT:  clr r24
+; CHECK-NEXT:  lsl r24
+; CHECK-NEXT:  rol r25
+; CHECK-NEXT:  ret
+  %result = shl i16 %a, 9
+  ret i16 %result
+}
+
+define i16 @lsl_i16_13(i16 %a) {
+; CHECK-LABEL: lsl_i16_13
+; CHECK:       mov r25, r24
+; CHECK-NEXT:  swap r25
+; CHECK-NEXT:  andi r25, 240
+; CHECK-NEXT:  clr r24
+; CHECK-NEXT:  lsl r24
+; CHECK-NEXT:  rol r25
+; CHECK-NEXT:  ret
+  %result = shl i16 %a, 13
+  ret i16 %result
+}
+
+define i16 @lsr_i16_5(i16 %a) {
+; CHECK-LABEL: lsr_i16_5
+; CHECK:       swap r25
+; CHECK-NEXT:  swap r24
+; CHECK-NEXT:  andi r24, 15
+; CHECK-NEXT:  eor r24, r25
+; CHECK-NEXT:  andi r25, 15
+; CHECK-NEXT:  eor r24, r25
+; CHECK-NEXT:  lsr r25
+; CHECK-NEXT:  ror r24
+; CHECK-NEXT:  ret
+  %result = lshr i16 %a, 5
+  ret i16 %result
+}
+
+define i16 @lsr_i16_9(i16 %a) {
+; CHECK-LABEL: lsr_i16_9
+; CHECK:       mov r24, r25
+; CHECK-NEXT:  clr r25
+; CHECK-NEXT:  lsr r25
+; CHECK-NEXT:  ror r24
+; CHECK-NEXT:  ret
+  %result = lshr i16 %a, 9
+  ret i16 %result
+}
+
+define i16 @lsr_i16_13(i16 %a) {
+; CHECK-LABEL: lsr_i16_13
+; CHECK:       mov r24, r25
+; CHECK-NEXT:  swap r24
+; CHECK-NEXT:  andi r24, 15
+; CHECK-NEXT:  clr r25
+; CHECK-NEXT:  lsr r25
+; CHECK-NEXT:  ror r24
+; CHECK-NEXT:  ret
+  %result = lshr i16 %a, 13
+  ret i16 %result
+}
+
+define i16 @asr_i16_9(i16 %a) {
+; CHECK-LABEL: asr_i16_9
+; CHECK:       mov r24, r25
+; CHECK-NEXT:  lsl r25
+; CHECK-NEXT:  sbc r25, r25
+; CHECK-NEXT:  asr r25
+; CHECK-NEXT:  ror r24
+; CHECK-NEXT:  ret
+  %result = ashr i16 %a, 9
+  ret i16 %result
+}


        


More information about the llvm-commits mailing list