[AVR] Optimize the 16-bit NEGW pseudo instruction
authorBen Shi <powerman1st@163.com>
Tue, 17 Nov 2020 09:51:58 +0000 (17:51 +0800)
committerBen Shi <powerman1st@163.com>
Tue, 17 Nov 2020 09:51:58 +0000 (17:51 +0800)
Reviewed By: dylanmckay

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

llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
llvm/lib/Target/AVR/AVRInstrInfo.td
llvm/test/CodeGen/AVR/neg.ll
llvm/test/CodeGen/AVR/pseudo/NEGWRd.mir [new file with mode: 0644]

index 8ee6920..d10f014 100644 (file)
@@ -416,6 +416,44 @@ bool AVRExpandPseudo::expand<AVR::COMWRd>(Block &MBB, BlockIt MBBI) {
 }
 
 template <>
+bool AVRExpandPseudo::expand<AVR::NEGWRd>(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);
+
+  // Do NEG on the upper byte.
+  auto MIBHI =
+      buildMI(MBB, MBBI, AVR::NEGRd)
+          .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstHiReg, getKillRegState(DstIsKill));
+  // SREG is always implicitly dead
+  MIBHI->getOperand(2).setIsDead();
+
+  // Do NEG on the lower byte.
+  buildMI(MBB, MBBI, AVR::NEGRd)
+      .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+      .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+  // Do an extra SBCI.
+  auto MISBCI =
+      buildMI(MBB, MBBI, AVR::SBCIRdK)
+          .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+          .addReg(DstHiReg, getKillRegState(DstIsKill))
+          .addImm(0);
+  if (ImpIsDead)
+    MISBCI->getOperand(3).setIsDead();
+  // SREG is always implicitly killed
+  MISBCI->getOperand(4).setIsKill();
+
+  MI.eraseFromParent();
+  return true;
+}
+
+template <>
 bool AVRExpandPseudo::expand<AVR::CPWRdRr>(Block &MBB, BlockIt MBBI) {
   MachineInstr &MI = *MBBI;
   Register SrcLoReg, SrcHiReg, DstLoReg, DstHiReg;
@@ -1616,6 +1654,7 @@ bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
     EXPAND(AVR::ORIWRdK);
     EXPAND(AVR::EORWRdRr);
     EXPAND(AVR::COMWRd);
+    EXPAND(AVR::NEGWRd);
     EXPAND(AVR::CPWRdRr);
     EXPAND(AVR::CPCWRdRr);
     EXPAND(AVR::LDIWRdK);
index f03c254..8de85f6 100644 (file)
@@ -732,13 +732,23 @@ Defs = [SREG] in
                       "comw\t$rd",
                       [(set i16:$rd, (not i16:$src)), (implicit SREG)]>;
 
-  //:TODO: optimize NEG for wider types
   def NEGRd : FRd<0b1001,
                   0b0100001,
                   (outs GPR8:$rd),
                   (ins GPR8:$src),
                   "neg\t$rd",
                   [(set i8:$rd, (ineg i8:$src)), (implicit SREG)]>;
+
+  // NEGW Rd+1:Rd
+  //
+  // Expands to:
+  // neg Rd+1
+  // neg Rd
+  // sbci Rd+1, 0
+  def NEGWRd : Pseudo<(outs DREGS:$rd),
+                      (ins DREGS:$src),
+                      "negw\t$rd",
+                      [(set i16:$rd, (ineg i16:$src)), (implicit SREG)]>;
 }
 
 // TST Rd
index edcce34..355e9ab 100644 (file)
@@ -6,3 +6,13 @@ define i8 @neg8(i8 %x) {
   %sub = sub i8 0, %x
   ret i8 %sub
 }
+
+define i16 @neg16(i16 %x) {
+; CHECK-LABEL: neg16:
+; CHECK:       neg r25
+; CHECK-next:  neg r24
+; CHECK-next:  sbci r25, 0
+; CHECK-next:  ret
+  %sub = sub i16 0, %x
+  ret i16 %sub
+}
diff --git a/llvm/test/CodeGen/AVR/pseudo/NEGWRd.mir b/llvm/test/CodeGen/AVR/pseudo/NEGWRd.mir
new file mode 100644 (file)
index 0000000..0a534ad
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: llc -O0 -run-pass=avr-expand-pseudo %s -o - | FileCheck %s
+
+# This test checks the expansion of the 16-bit NEG pseudo instruction.
+
+--- |
+  target triple = "avr--"
+  define void @test_negwrd() {
+  entry:
+    ret void
+  }
+...
+
+---
+name:            test_negwrd
+body: |
+  bb.0.entry:
+
+    ; CHECK-LABEL: test_negwrd
+
+    ; CHECK:      $r15 = NEGRd $r15, implicit-def dead $sreg
+    ; CHECK-NEXT: $r14 = NEGRd $r14
+    ; CHECK-NEXT: $r15 = SBCIRdK $r15, 0, implicit-def $sreg, implicit killed $sreg
+
+    $r15r14 = NEGWRd $r15r14, implicit-def $sreg
+...