[AVR] Do not use R0/R1 on avrtiny
authorAyke van Laethem <aykevanlaethem@gmail.com>
Wed, 23 Nov 2022 16:24:44 +0000 (17:24 +0100)
committerAyke van Laethem <aykevanlaethem@gmail.com>
Mon, 28 Nov 2022 17:05:55 +0000 (18:05 +0100)
This patch makes sure the compiler uses R16/R17 on avrtiny (attiny10
etc) instead of R0/R1.

Some notes:

  * For the NEGW and ROLB instructions, it adds an explicit zero
    register. This is necessary because the zero register is different
    on avrtiny (and InstrInfo Uses lines need a fixed register).
  * Not entirely sure about putting all tests in features/avr-tiny.ll,
    but it doesn't seem like the "target-cpu"="attiny10" attribute
    works.

Updates: https://github.com/llvm/llvm-project/issues/53459

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

llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
llvm/lib/Target/AVR/AVRFrameLowering.cpp
llvm/lib/Target/AVR/AVRISelLowering.cpp
llvm/lib/Target/AVR/AVRISelLowering.h
llvm/lib/Target/AVR/AVRInstrInfo.td
llvm/lib/Target/AVR/AVRRegisterInfo.cpp
llvm/lib/Target/AVR/AVRSubtarget.h
llvm/test/CodeGen/AVR/features/avr-tiny.ll
llvm/test/CodeGen/AVR/pseudo/NEGWRd.mir
llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir
llvm/test/CodeGen/AVR/return.ll

index db793cc..b474f06 100644 (file)
@@ -49,11 +49,6 @@ private:
   const AVRRegisterInfo *TRI;
   const TargetInstrInfo *TII;
 
-  /// The register to be used for temporary storage.
-  const Register SCRATCH_REGISTER = AVR::R0;
-  /// The register that will always contain zero.
-  const Register ZERO_REGISTER = AVR::R1;
-
   bool expandMBB(Block &MBB);
   bool expandMI(Block &MBB, BlockIt MBBI);
   template <unsigned OP> bool expand(Block &MBB, BlockIt MBBI);
@@ -438,6 +433,7 @@ bool AVRExpandPseudo::expand<AVR::NEGWRd>(Block &MBB, BlockIt MBBI) {
   MachineInstr &MI = *MBBI;
   Register DstLoReg, DstHiReg;
   Register DstReg = MI.getOperand(0).getReg();
+  Register ZeroReg = MI.getOperand(2).getReg();
   bool DstIsDead = MI.getOperand(0).isDead();
   bool DstIsKill = MI.getOperand(1).isKill();
   bool ImpIsDead = MI.getOperand(2).isDead();
@@ -461,7 +457,7 @@ bool AVRExpandPseudo::expand<AVR::NEGWRd>(Block &MBB, BlockIt MBBI) {
       buildMI(MBB, MBBI, AVR::SBCRdRr)
           .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
           .addReg(DstHiReg, getKillRegState(DstIsKill))
-          .addReg(ZERO_REGISTER);
+          .addReg(ZeroReg);
   if (ImpIsDead)
     MISBCI->getOperand(3).setIsDead();
   // SREG is always implicitly killed
@@ -865,7 +861,7 @@ bool AVRExpandPseudo::expandAtomic(Block &MBB, BlockIt MBBI, Func f) {
 
   // Store the SREG.
   buildMI(MBB, MBBI, AVR::INRdA)
-      .addReg(SCRATCH_REGISTER, RegState::Define)
+      .addReg(STI.getTmpRegister(), RegState::Define)
       .addImm(STI.getIORegSREG());
 
   // Disable exceptions.
@@ -876,7 +872,7 @@ bool AVRExpandPseudo::expandAtomic(Block &MBB, BlockIt MBBI, Func f) {
   // Restore the status reg.
   buildMI(MBB, MBBI, AVR::OUTARr)
       .addImm(STI.getIORegSREG())
-      .addReg(SCRATCH_REGISTER);
+      .addReg(STI.getTmpRegister());
 
   MI.eraseFromParent();
   return true;
@@ -1279,6 +1275,7 @@ bool AVRExpandPseudo::expand<AVR::ROLBRd>(Block &MBB, BlockIt MBBI) {
   MachineInstr &MI = *MBBI;
   unsigned OpShift, OpCarry;
   Register DstReg = MI.getOperand(0).getReg();
+  Register ZeroReg = MI.getOperand(2).getReg();
   bool DstIsDead = MI.getOperand(0).isDead();
   bool DstIsKill = MI.getOperand(1).isKill();
   OpShift = AVR::ADDRdRr;
@@ -1297,7 +1294,7 @@ bool AVRExpandPseudo::expand<AVR::ROLBRd>(Block &MBB, BlockIt MBBI) {
   auto MIB = buildMI(MBB, MBBI, OpCarry)
                  .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
                  .addReg(DstReg, getKillRegState(DstIsKill))
-                 .addReg(ZERO_REGISTER);
+                 .addReg(ZeroReg);
 
   MIB->getOperand(3).setIsDead(); // SREG is always dead
   MIB->getOperand(4).setIsKill(); // SREG is always implicitly killed
@@ -2311,7 +2308,7 @@ bool AVRExpandPseudo::expand<AVR::SPWRITE>(Block &MBB, BlockIt MBBI) {
   TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
 
   buildMI(MBB, MBBI, AVR::INRdA)
-      .addReg(AVR::R0, RegState::Define)
+      .addReg(STI.getTmpRegister(), RegState::Define)
       .addImm(STI.getIORegSREG())
       .setMIFlags(Flags);
 
@@ -2324,7 +2321,7 @@ bool AVRExpandPseudo::expand<AVR::SPWRITE>(Block &MBB, BlockIt MBBI) {
 
   buildMI(MBB, MBBI, AVR::OUTARr)
       .addImm(STI.getIORegSREG())
-      .addReg(AVR::R0, RegState::Kill)
+      .addReg(STI.getTmpRegister(), RegState::Kill)
       .setMIFlags(Flags);
 
   buildMI(MBB, MBBI, AVR::OUTARr)
index d7683b7..3cbe691 100644 (file)
@@ -70,23 +70,23 @@ void AVRFrameLowering::emitPrologue(MachineFunction &MF,
   // handlers before saving any other registers.
   if (AFI->isInterruptOrSignalHandler()) {
     BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHRr))
-        .addReg(AVR::R0, RegState::Kill)
+        .addReg(STI.getTmpRegister(), RegState::Kill)
         .setMIFlag(MachineInstr::FrameSetup);
 
-    BuildMI(MBB, MBBI, DL, TII.get(AVR::INRdA), AVR::R0)
+    BuildMI(MBB, MBBI, DL, TII.get(AVR::INRdA), STI.getTmpRegister())
         .addImm(STI.getIORegSREG())
         .setMIFlag(MachineInstr::FrameSetup);
     BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHRr))
-        .addReg(AVR::R0, RegState::Kill)
+        .addReg(STI.getTmpRegister(), RegState::Kill)
         .setMIFlag(MachineInstr::FrameSetup);
-    if (!MRI.reg_empty(AVR::R1)) {
+    if (!MRI.reg_empty(STI.getZeroRegister())) {
       BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHRr))
-          .addReg(AVR::R1, RegState::Kill)
+          .addReg(STI.getZeroRegister(), RegState::Kill)
           .setMIFlag(MachineInstr::FrameSetup);
       BuildMI(MBB, MBBI, DL, TII.get(AVR::EORRdRr))
-          .addReg(AVR::R1, RegState::Define)
-          .addReg(AVR::R1, RegState::Kill)
-          .addReg(AVR::R1, RegState::Kill)
+          .addReg(STI.getZeroRegister(), RegState::Define)
+          .addReg(STI.getZeroRegister(), RegState::Kill)
+          .addReg(STI.getZeroRegister(), RegState::Kill)
           .setMIFlag(MachineInstr::FrameSetup);
     }
   }
@@ -149,14 +149,14 @@ static void restoreStatusRegister(MachineFunction &MF, MachineBasicBlock &MBB) {
   // Emit special epilogue code to restore R1, R0 and SREG in interrupt/signal
   // handlers at the very end of the function, just before reti.
   if (AFI->isInterruptOrSignalHandler()) {
-    if (!MRI.reg_empty(AVR::R1)) {
-      BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), AVR::R1);
+    if (!MRI.reg_empty(STI.getZeroRegister())) {
+      BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), STI.getZeroRegister());
     }
-    BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), AVR::R0);
+    BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), STI.getTmpRegister());
     BuildMI(MBB, MBBI, DL, TII.get(AVR::OUTARr))
         .addImm(STI.getIORegSREG())
-        .addReg(AVR::R0, RegState::Kill);
-    BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), AVR::R0);
+        .addReg(STI.getTmpRegister(), RegState::Kill);
+    BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), STI.getTmpRegister());
   }
 }
 
index 7b46116..35b4a38 100644 (file)
@@ -838,12 +838,12 @@ SDValue AVRTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const {
                       MachinePointerInfo(SV));
 }
 
-// Modify the existing ISD::INLINEASM node to add the implicit register r1.
+// Modify the existing ISD::INLINEASM node to add the implicit zero register.
 SDValue AVRTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
-  SDValue R1Reg = DAG.getRegister(AVR::R1, MVT::i8);
-  if (Op.getOperand(Op.getNumOperands() - 1) == R1Reg ||
-      Op.getOperand(Op.getNumOperands() - 2) == R1Reg) {
-    // R1 has already been added. Don't add it again.
+  SDValue ZeroReg = DAG.getRegister(Subtarget.getZeroRegister(), MVT::i8);
+  if (Op.getOperand(Op.getNumOperands() - 1) == ZeroReg ||
+      Op.getOperand(Op.getNumOperands() - 2) == ZeroReg) {
+    // Zero register has already been added. Don't add it again.
     // If this isn't handled, we get called over and over again.
     return Op;
   }
@@ -852,8 +852,8 @@ SDValue AVRTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
   // with some edits.
   // Add the following operands at the end (but before the glue node, if it's
   // there):
-  //  - The flags of the implicit R1 register operand.
-  //  - The implicit R1 register operand itself.
+  //  - The flags of the implicit zero register operand.
+  //  - The implicit zero register operand itself.
   SDLoc dl(Op);
   SmallVector<SDValue, 8> Ops;
   SDNode *N = Op.getNode();
@@ -870,13 +870,13 @@ SDValue AVRTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
   }
   unsigned Flags = InlineAsm::getFlagWord(InlineAsm::Kind_RegUse, 1);
   Ops.push_back(DAG.getTargetConstant(Flags, dl, MVT::i32));
-  Ops.push_back(R1Reg);
+  Ops.push_back(ZeroReg);
   if (Glue) {
     Ops.push_back(Glue);
   }
 
-  // Replace the current INLINEASM node with a new one that has R1 as implicit
-  // parameter.
+  // Replace the current INLINEASM node with a new one that has the zero
+  // register as implicit parameter.
   SDValue New = DAG.getNode(N->getOpcode(), dl, N->getVTList(), Ops);
   DAG.ReplaceAllUsesOfValueWith(Op, New);
   DAG.ReplaceAllUsesOfValueWith(Op.getValue(1), New.getValue(1));
@@ -1505,9 +1505,9 @@ SDValue AVRTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
     Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType()));
   }
 
-  // The R1 register must be passed as an implicit register so that R1 is
-  // correctly zeroed in interrupts.
-  Ops.push_back(DAG.getRegister(AVR::R1, MVT::i8));
+  // The zero register (usually R1) must be passed as an implicit register so
+  // that this register is correctly zeroed in interrupts.
+  Ops.push_back(DAG.getRegister(Subtarget.getZeroRegister(), MVT::i8));
 
   // Add a register mask operand representing the call-preserved registers.
   const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
@@ -1630,11 +1630,11 @@ AVRTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
   const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
 
   if (!AFI->isInterruptOrSignalHandler()) {
-    // The return instruction has an implicit R1 operand: it must contain zero
-    // on return.
-    // This is not needed in interrupts however, where R1 is handled specially
-    // (only pushed/popped when needed).
-    RetOps.push_back(DAG.getRegister(AVR::R1, MVT::i8));
+    // The return instruction has an implicit zero register operand: it must
+    // contain zero on return.
+    // This is not needed in interrupts however, where the zero register is
+    // handled specially (only pushed/popped when needed).
+    RetOps.push_back(DAG.getRegister(Subtarget.getZeroRegister(), MVT::i8));
   }
 
   unsigned RetOpc =
@@ -1658,6 +1658,7 @@ MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr &MI,
   unsigned Opc;
   const TargetRegisterClass *RC;
   bool HasRepeatedOperand = false;
+  bool HasZeroOperand = false;
   MachineFunction *F = BB->getParent();
   MachineRegisterInfo &RI = F->getRegInfo();
   const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
@@ -1694,6 +1695,7 @@ MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr &MI,
   case AVR::Rol8:
     Opc = AVR::ROLBRd;
     RC = &AVR::GPR8RegClass;
+    HasZeroOperand = true;
     break;
   case AVR::Rol16:
     Opc = AVR::ROLWRd;
@@ -1755,6 +1757,8 @@ MachineBasicBlock *AVRTargetLowering::insertShift(MachineInstr &MI,
   auto ShiftMI = BuildMI(LoopBB, dl, TII.get(Opc), ShiftReg2).addReg(ShiftReg);
   if (HasRepeatedOperand)
     ShiftMI.addReg(ShiftReg);
+  if (HasZeroOperand)
+    ShiftMI.addReg(Subtarget.getZeroRegister());
 
   // CheckBB:
   // ShiftReg = phi [%SrcReg, BB], [%ShiftReg2, LoopBB]
@@ -1812,14 +1816,15 @@ MachineBasicBlock *AVRTargetLowering::insertMul(MachineInstr &MI,
   return BB;
 }
 
-// Insert a read from R1, which almost always contains the value 0.
+// Insert a read from the zero register.
 MachineBasicBlock *
-AVRTargetLowering::insertCopyR1(MachineInstr &MI, MachineBasicBlock *BB) const {
+AVRTargetLowering::insertCopyZero(MachineInstr &MI,
+                                  MachineBasicBlock *BB) const {
   const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
   MachineBasicBlock::iterator I(MI);
   BuildMI(*BB, I, MI.getDebugLoc(), TII.get(AVR::COPY))
       .add(MI.getOperand(0))
-      .addReg(AVR::R1);
+      .addReg(Subtarget.getZeroRegister());
   MI.eraseFromParent();
   return BB;
 }
@@ -1831,7 +1836,6 @@ MachineBasicBlock *AVRTargetLowering::insertAtomicArithmeticOp(
   MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
   const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
   MachineBasicBlock::iterator I(MI);
-  const Register SCRATCH_REGISTER = AVR::R0;
   DebugLoc dl = MI.getDebugLoc();
 
   // Example instruction sequence, for an atomic 8-bit add:
@@ -1849,7 +1853,7 @@ MachineBasicBlock *AVRTargetLowering::insertAtomicArithmeticOp(
   unsigned StoreOpcode = (Width == 8) ? AVR::STPtrRr : AVR::STWPtrRr;
 
   // Disable interrupts.
-  BuildMI(*BB, I, dl, TII.get(AVR::INRdA), SCRATCH_REGISTER)
+  BuildMI(*BB, I, dl, TII.get(AVR::INRdA), Subtarget.getTmpRegister())
       .addImm(Subtarget.getIORegSREG());
   BuildMI(*BB, I, dl, TII.get(AVR::BCLRs)).addImm(7);
 
@@ -1871,7 +1875,7 @@ MachineBasicBlock *AVRTargetLowering::insertAtomicArithmeticOp(
   // Restore interrupts.
   BuildMI(*BB, I, dl, TII.get(AVR::OUTARr))
       .addImm(Subtarget.getIORegSREG())
-      .addReg(SCRATCH_REGISTER);
+      .addReg(Subtarget.getTmpRegister());
 
   // Remove the pseudo instruction.
   MI.eraseFromParent();
@@ -1900,8 +1904,8 @@ AVRTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
   case AVR::MULRdRr:
   case AVR::MULSRdRr:
     return insertMul(MI, MBB);
-  case AVR::CopyR1:
-    return insertCopyR1(MI, MBB);
+  case AVR::CopyZero:
+    return insertCopyZero(MI, MBB);
   case AVR::AtomicLoadAdd8:
     return insertAtomicArithmeticOp(MI, MBB, AVR::ADDRdRr, 8);
   case AVR::AtomicLoadAdd16:
@@ -2206,7 +2210,8 @@ AVRTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
       break;
     case 't': // Temporary register: r0.
       if (VT == MVT::i8)
-        return std::make_pair(unsigned(AVR::R0), &AVR::GPR8RegClass);
+        return std::make_pair(unsigned(Subtarget.getTmpRegister()),
+                              &AVR::GPR8RegClass);
       break;
     case 'w': // Special upper register pairs: r24, r26, r28, r30.
       if (VT == MVT::i8 || VT == MVT::i16)
index c5c937c..8d91c1b 100644 (file)
@@ -187,8 +187,8 @@ protected:
 private:
   MachineBasicBlock *insertShift(MachineInstr &MI, MachineBasicBlock *BB) const;
   MachineBasicBlock *insertMul(MachineInstr &MI, MachineBasicBlock *BB) const;
-  MachineBasicBlock *insertCopyR1(MachineInstr &MI,
-                                  MachineBasicBlock *BB) const;
+  MachineBasicBlock *insertCopyZero(MachineInstr &MI,
+                                    MachineBasicBlock *BB) const;
   MachineBasicBlock *insertAtomicArithmeticOp(MachineInstr &MI,
                                               MachineBasicBlock *BB,
                                               unsigned Opcode, int Width) const;
index 47dce53..4d79ce7 100644 (file)
@@ -915,16 +915,11 @@ let Constraints = "$src = $rd", Defs = [SREG] in {
   // neg Rd+1
   // neg Rd
   // sbc Rd+1, r1
-  let Uses = [R1] in
-  def NEGWRd : Pseudo<(outs DREGS
-                       : $rd),
-                      (ins DREGS
-                       : $src),
+  let hasSideEffects=0 in
+  def NEGWRd : Pseudo<(outs DREGS:$rd),
+                      (ins DREGS:$src, GPR8:$zero),
                       "negw\t$rd",
-                      [(set i16
-                        : $rd, (ineg i16
-                                : $src)),
-                       (implicit SREG)]>;
+                      []>;
 }
 
 // TST Rd
@@ -1989,16 +1984,12 @@ let Constraints = "$src = $rd", Defs = [SREG] in {
   def ASRWLoRd : Pseudo<(outs DREGS:$rd), (ins DREGS:$src), "asrwlo\t$rd",
                         [(set i16:$rd, (AVRasrlo i16:$src)), (implicit SREG)]>;
 
-  let Uses = [R1] in
+  let hasSideEffects=0 in
   def ROLBRd : Pseudo<(outs GPR8
                        : $rd),
-                      (ins GPR8
-                       : $src),
+                      (ins GPR8:$src, GPR8:$zero),
                       "rolb\t$rd",
-                      [(set i8
-                        : $rd, (AVRrol i8
-                                : $src)),
-                       (implicit SREG)]>;
+                      []>;
 
   def RORBRd : Pseudo<(outs GPR8
                        : $rd),
@@ -2389,9 +2380,9 @@ def Asr16 : ShiftPseudo<(outs DREGS
                                                      : $src, i8
                                                      : $cnt))]>;
 
-// lowered to a copy from R1, which contains the value zero.
+// lowered to a copy from the zero register.
 let usesCustomInserter=1 in
-def CopyR1 : Pseudo<(outs GPR8:$rd), (ins), "clrz\t$rd", [(set i8:$rd, 0)]>;
+def CopyZero : Pseudo<(outs GPR8:$rd), (ins), "clrz\t$rd", [(set i8:$rd, 0)]>;
 
 //===----------------------------------------------------------------------===//
 // Non-Instruction Patterns
@@ -2455,6 +2446,10 @@ def : Pat<(adde i8
            : $src1, (imm8_neg_XFORM imm
                      : $src2))>;
 
+// Emit NEGWRd with an extra zero register operand.
+def : Pat<(ineg i16:$src),
+          (NEGWRd i16:$src, (CopyZero))>;
+
 // Calls.
 let Predicates = [HasJMPCALL] in {
   def : Pat<(AVRcall(i16 tglobaladdr:$dst)), (CALLk tglobaladdr:$dst)>;
index 3f8bb7e..327f406 100644 (file)
@@ -236,7 +236,7 @@ bool AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
     // a compare and branch, invalidating the contents of SREG set by the
     // compare instruction because of the add/sub pairs. Conservatively save and
     // restore SREG before and after each add/sub pair.
-    BuildMI(MBB, II, dl, TII.get(AVR::INRdA), AVR::R0)
+    BuildMI(MBB, II, dl, TII.get(AVR::INRdA), STI.getTmpRegister())
         .addImm(STI.getIORegSREG());
 
     MachineInstr *New = BuildMI(MBB, II, dl, TII.get(AddOpc), AVR::R29R28)
@@ -247,7 +247,7 @@ bool AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
     // Restore SREG.
     BuildMI(MBB, std::next(II), dl, TII.get(AVR::OUTARr))
         .addImm(STI.getIORegSREG())
-        .addReg(AVR::R0, RegState::Kill);
+        .addReg(STI.getTmpRegister(), RegState::Kill);
 
     // No need to set SREG as dead here otherwise if the next instruction is a
     // cond branch it will be using a dead register.
index 3dd7124..ee16ed4 100644 (file)
@@ -21,6 +21,7 @@
 #include "AVRISelLowering.h"
 #include "AVRInstrInfo.h"
 #include "AVRSelectionDAGInfo.h"
+#include "MCTargetDesc/AVRMCTargetDesc.h"
 
 #define GET_SUBTARGETINFO_HEADER
 #include "AVRGenSubtargetInfo.inc"
@@ -102,6 +103,13 @@ public:
   int getRegTmpIndex() const { return hasTinyEncoding() ? 16 : 0; }
   int getRegZeroIndex() const { return hasTinyEncoding() ? 17 : 1; }
 
+  Register getTmpRegister() const {
+    return hasTinyEncoding() ? AVR::R16 : AVR::R0;
+  }
+  Register getZeroRegister() const {
+    return hasTinyEncoding() ? AVR::R17 : AVR::R1;
+  }
+
 private:
   /// The ELF e_flags architecture.
   unsigned ELFArch;
index e497efa..a99e2ec 100644 (file)
@@ -1,9 +1,173 @@
-; RUN: llc -mattr=avrtiny -O0 < %s -march=avr | FileCheck %s
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mcpu=atmega328p -O0 < %s -mtriple=avr | FileCheck --check-prefix=CHECK-MEGA %s
+; RUN: llc -mattr=avrtiny -O0 < %s -mtriple=avr | FileCheck %s
 
 define i16 @reg_copy16(i16, i16 %a) {
-; CHECK-LABEL: reg_copy16
-; CHECK: mov r24, r22
-; CHECK: mov r25, r23
-
+; CHECK-MEGA-LABEL: reg_copy16:
+; CHECK-MEGA:       ; %bb.0:
+; CHECK-MEGA-NEXT:    movw r24, r22
+; CHECK-MEGA-NEXT:    ret
+;
+; CHECK-LABEL: reg_copy16:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov r24, r22
+; CHECK-NEXT:    mov r25, r23
+; CHECK-NEXT:    ret
   ret i16 %a
 }
+
+define i8 @return_zero() {
+; CHECK-MEGA-LABEL: return_zero:
+; CHECK-MEGA:       ; %bb.0:
+; CHECK-MEGA-NEXT:    mov r24, r1
+; CHECK-MEGA-NEXT:    ret
+;
+; CHECK-LABEL: return_zero:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov r24, r17
+; CHECK-NEXT:    ret
+  ret i8 0
+}
+
+define i8 @atomic_load8(i8* %foo) {
+; CHECK-MEGA-LABEL: atomic_load8:
+; CHECK-MEGA:       ; %bb.0:
+; CHECK-MEGA-NEXT:    movw r26, r24
+; CHECK-MEGA-NEXT:    in r0, 63
+; CHECK-MEGA-NEXT:    cli
+; CHECK-MEGA-NEXT:    ld r24, X
+; CHECK-MEGA-NEXT:    out 63, r0
+; CHECK-MEGA-NEXT:    ret
+;
+; CHECK-LABEL: atomic_load8:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov r26, r24
+; CHECK-NEXT:    mov r27, r25
+; CHECK-NEXT:    in r16, 63
+; CHECK-NEXT:    cli
+; CHECK-NEXT:    ld r24, X
+; CHECK-NEXT:    out 63, r16
+; CHECK-NEXT:    ret
+  %val = load atomic i8, i8* %foo unordered, align 1
+  ret i8 %val
+}
+
+define avr_signalcc void @signal_handler_with_asm() {
+; CHECK-MEGA-LABEL: signal_handler_with_asm:
+; CHECK-MEGA:       ; %bb.0:
+; CHECK-MEGA-NEXT:    push r0
+; CHECK-MEGA-NEXT:    in r0, 63
+; CHECK-MEGA-NEXT:    push r0
+; CHECK-MEGA-NEXT:    push r1
+; CHECK-MEGA-NEXT:    clr r1
+; CHECK-MEGA-NEXT:    push r24
+; CHECK-MEGA-NEXT:    ldi r24, 3
+; CHECK-MEGA-NEXT:    ;APP
+; CHECK-MEGA-NEXT:    mov r24, r24
+; CHECK-MEGA-NEXT:    ;NO_APP
+; CHECK-MEGA-NEXT:    pop r24
+; CHECK-MEGA-NEXT:    pop r1
+; CHECK-MEGA-NEXT:    pop r0
+; CHECK-MEGA-NEXT:    out 63, r0
+; CHECK-MEGA-NEXT:    pop r0
+; CHECK-MEGA-NEXT:    reti
+;
+; CHECK-LABEL: signal_handler_with_asm:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    push r16
+; CHECK-NEXT:    in r16, 63
+; CHECK-NEXT:    push r16
+; CHECK-NEXT:    push r17
+; CHECK-NEXT:    clr r17
+; CHECK-NEXT:    push r24
+; CHECK-NEXT:    ldi r24, 3
+; CHECK-NEXT:    ;APP
+; CHECK-NEXT:    mov r24, r24
+; CHECK-NEXT:    ;NO_APP
+; CHECK-NEXT:    pop r24
+; CHECK-NEXT:    pop r17
+; CHECK-NEXT:    pop r16
+; CHECK-NEXT:    out 63, r16
+; CHECK-NEXT:    pop r16
+; CHECK-NEXT:    reti
+  call i8 asm sideeffect "mov $0, $1", "=r,r"(i8 3) nounwind
+  ret void
+}
+
+declare void @foo()
+
+define avr_signalcc void @signal_handler_with_call() {
+; CHECK-MEGA-LABEL: signal_handler_with_call:
+; CHECK-MEGA:       ; %bb.0:
+; CHECK-MEGA-NEXT:    push r0
+; CHECK-MEGA-NEXT:    in r0, 63
+; CHECK-MEGA-NEXT:    push r0
+; CHECK-MEGA-NEXT:    push r1
+; CHECK-MEGA-NEXT:    clr r1
+; CHECK-MEGA-NEXT:    push r18
+; CHECK-MEGA-NEXT:    push r19
+; CHECK-MEGA-NEXT:    push r20
+; CHECK-MEGA-NEXT:    push r21
+; CHECK-MEGA-NEXT:    push r22
+; CHECK-MEGA-NEXT:    push r23
+; CHECK-MEGA-NEXT:    push r24
+; CHECK-MEGA-NEXT:    push r25
+; CHECK-MEGA-NEXT:    push r26
+; CHECK-MEGA-NEXT:    push r27
+; CHECK-MEGA-NEXT:    push r30
+; CHECK-MEGA-NEXT:    push r31
+; CHECK-MEGA-NEXT:    call foo
+; CHECK-MEGA-NEXT:    pop r31
+; CHECK-MEGA-NEXT:    pop r30
+; CHECK-MEGA-NEXT:    pop r27
+; CHECK-MEGA-NEXT:    pop r26
+; CHECK-MEGA-NEXT:    pop r25
+; CHECK-MEGA-NEXT:    pop r24
+; CHECK-MEGA-NEXT:    pop r23
+; CHECK-MEGA-NEXT:    pop r22
+; CHECK-MEGA-NEXT:    pop r21
+; CHECK-MEGA-NEXT:    pop r20
+; CHECK-MEGA-NEXT:    pop r19
+; CHECK-MEGA-NEXT:    pop r18
+; CHECK-MEGA-NEXT:    pop r1
+; CHECK-MEGA-NEXT:    pop r0
+; CHECK-MEGA-NEXT:    out 63, r0
+; CHECK-MEGA-NEXT:    pop r0
+; CHECK-MEGA-NEXT:    reti
+;
+; CHECK-LABEL: signal_handler_with_call:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    push r16
+; CHECK-NEXT:    in r16, 63
+; CHECK-NEXT:    push r16
+; CHECK-NEXT:    push r17
+; CHECK-NEXT:    clr r17
+; CHECK-NEXT:    push r20
+; CHECK-NEXT:    push r21
+; CHECK-NEXT:    push r22
+; CHECK-NEXT:    push r23
+; CHECK-NEXT:    push r24
+; CHECK-NEXT:    push r25
+; CHECK-NEXT:    push r26
+; CHECK-NEXT:    push r27
+; CHECK-NEXT:    push r30
+; CHECK-NEXT:    push r31
+; CHECK-NEXT:    rcall foo
+; CHECK-NEXT:    pop r31
+; CHECK-NEXT:    pop r30
+; CHECK-NEXT:    pop r27
+; CHECK-NEXT:    pop r26
+; CHECK-NEXT:    pop r25
+; CHECK-NEXT:    pop r24
+; CHECK-NEXT:    pop r23
+; CHECK-NEXT:    pop r22
+; CHECK-NEXT:    pop r21
+; CHECK-NEXT:    pop r20
+; CHECK-NEXT:    pop r17
+; CHECK-NEXT:    pop r16
+; CHECK-NEXT:    out 63, r16
+; CHECK-NEXT:    pop r16
+; CHECK-NEXT:    reti
+  call void @foo()
+  ret void
+}
index 3f30fc0..38f8029 100644 (file)
@@ -21,6 +21,11 @@ body: |
     ; CHECK:      $r15 = NEGRd killed $r15, implicit-def dead $sreg
     ; CHECK-NEXT: $r14 = NEGRd $r14
     ; CHECK-NEXT: $r15 = SBCRdRr $r15, $r1, implicit-def $sreg, implicit killed $sreg
+    $r15r14 = NEGWRd $r15r14, $r1, implicit-def $sreg
 
-    $r15r14 = NEGWRd $r15r14, implicit-def $sreg, implicit $r1
+    ; avrtiny variant
+    ; CHECK:      $r15 = NEGRd killed $r15, implicit-def dead $sreg
+    ; CHECK-NEXT: $r14 = NEGRd $r14
+    ; CHECK-NEXT: $r15 = SBCRdRr $r15, $r17, implicit-def $sreg, implicit killed $sreg
+    $r15r14 = NEGWRd $r15r14, $r17, implicit-def $sreg
 ...
index a47d66f..bd3b5b7 100644 (file)
@@ -20,6 +20,10 @@ body: |
 
     ; CHECK:      $r14 = ADDRdRr killed $r14, killed $r14, implicit-def $sreg
     ; CHECK-NEXT: $r14 = ADCRdRr $r14, $r1, implicit-def dead $sreg, implicit killed $sreg
+    $r14 = ROLBRd $r14, $r1, implicit-def $sreg
 
-    $r14 = ROLBRd $r14, implicit-def $sreg, implicit $r1
+    ; avrtiny variant
+    ; CHECK:      $r14 = ADDRdRr killed $r14, killed $r14, implicit-def $sreg
+    ; CHECK-NEXT: $r14 = ADCRdRr $r14, $r17, implicit-def dead $sreg, implicit killed $sreg
+    $r14 = ROLBRd $r14, $r17, implicit-def $sreg
 ...
index 770e40b..afe3580 100644 (file)
@@ -314,12 +314,12 @@ define avr_intrcc void @interrupt_handler() {
 ; TINY-LABEL: interrupt_handler:
 ; TINY:       ; %bb.0:
 ; TINY-NEXT:    sei
-; TINY-NEXT:    push r0
-; TINY-NEXT:    in r0, 63
-; TINY-NEXT:    push r0
-; TINY-NEXT:    pop r0
-; TINY-NEXT:    out 63, r0
-; TINY-NEXT:    pop r0
+; TINY-NEXT:    push r16
+; TINY-NEXT:    in r16, 63
+; TINY-NEXT:    push r16
+; TINY-NEXT:    pop r16
+; TINY-NEXT:    out 63, r16
+; TINY-NEXT:    pop r16
 ; TINY-NEXT:    reti
   ret void
 }
@@ -337,12 +337,12 @@ define avr_signalcc void @signal_handler() {
 ;
 ; TINY-LABEL: signal_handler:
 ; TINY:       ; %bb.0:
-; TINY-NEXT:    push r0
-; TINY-NEXT:    in r0, 63
-; TINY-NEXT:    push r0
-; TINY-NEXT:    pop r0
-; TINY-NEXT:    out 63, r0
-; TINY-NEXT:    pop r0
+; TINY-NEXT:    push r16
+; TINY-NEXT:    in r16, 63
+; TINY-NEXT:    push r16
+; TINY-NEXT:    pop r16
+; TINY-NEXT:    out 63, r16
+; TINY-NEXT:    pop r16
 ; TINY-NEXT:    reti
   ret void
 }