diff --git a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp --- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp +++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp @@ -49,11 +49,6 @@ 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 bool expand(Block &MBB, BlockIt MBBI); @@ -438,6 +433,7 @@ 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 @@ 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 @@ // 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 @@ // 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 @@ 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 @@ 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 @@ 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 @@ 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) diff --git a/llvm/lib/Target/AVR/AVRFrameLowering.cpp b/llvm/lib/Target/AVR/AVRFrameLowering.cpp --- a/llvm/lib/Target/AVR/AVRFrameLowering.cpp +++ b/llvm/lib/Target/AVR/AVRFrameLowering.cpp @@ -70,23 +70,23 @@ // 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 @@ // 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()); } } diff --git a/llvm/lib/Target/AVR/AVRISelLowering.h b/llvm/lib/Target/AVR/AVRISelLowering.h --- a/llvm/lib/Target/AVR/AVRISelLowering.h +++ b/llvm/lib/Target/AVR/AVRISelLowering.h @@ -187,8 +187,8 @@ 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; diff --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp --- a/llvm/lib/Target/AVR/AVRISelLowering.cpp +++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp @@ -838,12 +838,12 @@ 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 @@ // 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 Ops; SDNode *N = Op.getNode(); @@ -870,13 +870,13 @@ } 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 @@ 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 @@ const AVRMachineFunctionInfo *AFI = MF.getInfo(); 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 @@ 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 @@ case AVR::Rol8: Opc = AVR::ROLBRd; RC = &AVR::GPR8RegClass; + HasZeroOperand = true; break; case AVR::Rol16: Opc = AVR::ROLWRd; @@ -1755,6 +1757,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ // 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 @@ 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 @@ 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) diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td --- a/llvm/lib/Target/AVR/AVRInstrInfo.td +++ b/llvm/lib/Target/AVR/AVRInstrInfo.td @@ -915,16 +915,11 @@ // 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 @@ 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 @@ : $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 @@ : $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)>; diff --git a/llvm/lib/Target/AVR/AVRRegisterInfo.cpp b/llvm/lib/Target/AVR/AVRRegisterInfo.cpp --- a/llvm/lib/Target/AVR/AVRRegisterInfo.cpp +++ b/llvm/lib/Target/AVR/AVRRegisterInfo.cpp @@ -236,7 +236,7 @@ // 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 @@ // 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. diff --git a/llvm/lib/Target/AVR/AVRSubtarget.h b/llvm/lib/Target/AVR/AVRSubtarget.h --- a/llvm/lib/Target/AVR/AVRSubtarget.h +++ b/llvm/lib/Target/AVR/AVRSubtarget.h @@ -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 @@ 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; diff --git a/llvm/test/CodeGen/AVR/features/avr-tiny.ll b/llvm/test/CodeGen/AVR/features/avr-tiny.ll --- a/llvm/test/CodeGen/AVR/features/avr-tiny.ll +++ b/llvm/test/CodeGen/AVR/features/avr-tiny.ll @@ -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 +} diff --git a/llvm/test/CodeGen/AVR/pseudo/NEGWRd.mir b/llvm/test/CodeGen/AVR/pseudo/NEGWRd.mir --- a/llvm/test/CodeGen/AVR/pseudo/NEGWRd.mir +++ b/llvm/test/CodeGen/AVR/pseudo/NEGWRd.mir @@ -21,6 +21,11 @@ ; 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 ... diff --git a/llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir b/llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir --- a/llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir +++ b/llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir @@ -20,6 +20,10 @@ ; 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 ... diff --git a/llvm/test/CodeGen/AVR/return.ll b/llvm/test/CodeGen/AVR/return.ll --- a/llvm/test/CodeGen/AVR/return.ll +++ b/llvm/test/CodeGen/AVR/return.ll @@ -314,12 +314,12 @@ ; 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 @@ ; ; 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 }