[llvm] 5527b21 - [AVR] Do not use R0/R1 on avrtiny
Ayke van Laethem via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 28 09:06:15 PST 2022
Author: Ayke van Laethem
Date: 2022-11-28T18:05:55+01:00
New Revision: 5527b215160cf202431881df3be59ed5c8dabb25
URL: https://github.com/llvm/llvm-project/commit/5527b215160cf202431881df3be59ed5c8dabb25
DIFF: https://github.com/llvm/llvm-project/commit/5527b215160cf202431881df3be59ed5c8dabb25.diff
LOG: [AVR] Do not use R0/R1 on avrtiny
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
Added:
Modified:
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
Removed:
################################################################################
diff --git a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
index db793cccaeafa..b474f065924b9 100644
--- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
@@ -49,11 +49,6 @@ class AVRExpandPseudo : public MachineFunctionPass {
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)
diff --git a/llvm/lib/Target/AVR/AVRFrameLowering.cpp b/llvm/lib/Target/AVR/AVRFrameLowering.cpp
index d7683b745e0a4..3cbe691282f42 100644
--- a/llvm/lib/Target/AVR/AVRFrameLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRFrameLowering.cpp
@@ -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());
}
}
diff --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp
index 7b461160c2a9c..35b4a38ed79eb 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp
@@ -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)
diff --git a/llvm/lib/Target/AVR/AVRISelLowering.h b/llvm/lib/Target/AVR/AVRISelLowering.h
index c5c937c983ed4..8d91c1bb996a1 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.h
+++ b/llvm/lib/Target/AVR/AVRISelLowering.h
@@ -187,8 +187,8 @@ class AVRTargetLowering : public TargetLowering {
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/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td
index 47dce5357a9fc..4d79ce755c9c8 100644
--- a/llvm/lib/Target/AVR/AVRInstrInfo.td
+++ b/llvm/lib/Target/AVR/AVRInstrInfo.td
@@ -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)>;
diff --git a/llvm/lib/Target/AVR/AVRRegisterInfo.cpp b/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
index 3f8bb7e67db80..327f406718a55 100644
--- a/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
+++ b/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
@@ -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.
diff --git a/llvm/lib/Target/AVR/AVRSubtarget.h b/llvm/lib/Target/AVR/AVRSubtarget.h
index 3dd71243387b5..ee16ed4062c46 100644
--- 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 @@ class AVRSubtarget : public AVRGenSubtargetInfo {
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
index e497efa59095d..a99e2ecc074ef 100644
--- 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
index 3f30fc0ecaf1f..38f8029a6c943 100644
--- a/llvm/test/CodeGen/AVR/pseudo/NEGWRd.mir
+++ b/llvm/test/CodeGen/AVR/pseudo/NEGWRd.mir
@@ -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
...
diff --git a/llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir b/llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir
index a47d66fd60486..bd3b5b74114f1 100644
--- a/llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir
+++ b/llvm/test/CodeGen/AVR/pseudo/ROLBrd.mir
@@ -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
...
diff --git a/llvm/test/CodeGen/AVR/return.ll b/llvm/test/CodeGen/AVR/return.ll
index 770e40b6fdc0b..afe358026b96a 100644
--- a/llvm/test/CodeGen/AVR/return.ll
+++ b/llvm/test/CodeGen/AVR/return.ll
@@ -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
}
More information about the llvm-commits
mailing list