aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/AVR
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/AVR')
-rw-r--r--llvm/lib/Target/AVR/AVR.h48
-rw-r--r--llvm/lib/Target/AVR/AVRCallingConv.td2
-rw-r--r--llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp181
-rw-r--r--llvm/lib/Target/AVR/AVRFrameLowering.cpp96
-rw-r--r--llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp88
-rw-r--r--llvm/lib/Target/AVR/AVRISelLowering.cpp43
-rw-r--r--llvm/lib/Target/AVR/AVRISelLowering.h5
-rw-r--r--llvm/lib/Target/AVR/AVRInstrInfo.cpp4
-rw-r--r--llvm/lib/Target/AVR/AVRInstrInfo.td55
-rw-r--r--llvm/lib/Target/AVR/AVRRegisterInfo.cpp5
-rw-r--r--llvm/lib/Target/AVR/AVRRegisterInfo.h4
-rw-r--r--llvm/lib/Target/AVR/AVRRegisterInfo.td20
-rw-r--r--llvm/lib/Target/AVR/AVRSubtarget.cpp3
-rw-r--r--llvm/lib/Target/AVR/AVRSubtarget.h3
-rw-r--r--llvm/lib/Target/AVR/AVRTargetMachine.cpp6
-rw-r--r--llvm/lib/Target/AVR/AVRTargetObjectFile.cpp53
-rw-r--r--llvm/lib/Target/AVR/AVRTargetObjectFile.h5
-rw-r--r--llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp10
-rw-r--r--llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp4
19 files changed, 455 insertions, 180 deletions
diff --git a/llvm/lib/Target/AVR/AVR.h b/llvm/lib/Target/AVR/AVR.h
index 143c339c0664..0b512172ba10 100644
--- a/llvm/lib/Target/AVR/AVR.h
+++ b/llvm/lib/Target/AVR/AVR.h
@@ -28,7 +28,6 @@ FunctionPass *createAVRISelDag(AVRTargetMachine &TM,
FunctionPass *createAVRExpandPseudoPass();
FunctionPass *createAVRFrameAnalyzerPass();
FunctionPass *createAVRRelaxMemPass();
-FunctionPass *createAVRDynAllocaSRPass();
FunctionPass *createAVRBranchSelectionPass();
void initializeAVRShiftExpandPass(PassRegistry &);
@@ -39,17 +38,56 @@ void initializeAVRRelaxMemPass(PassRegistry &);
namespace AVR {
/// An integer that identifies all of the supported AVR address spaces.
-enum AddressSpace { DataMemory, ProgramMemory };
+enum AddressSpace {
+ DataMemory,
+ ProgramMemory,
+ ProgramMemory1,
+ ProgramMemory2,
+ ProgramMemory3,
+ ProgramMemory4,
+ ProgramMemory5,
+ NumAddrSpaces,
+};
/// Checks if a given type is a pointer to program memory.
template <typename T> bool isProgramMemoryAddress(T *V) {
- return cast<PointerType>(V->getType())->getAddressSpace() == ProgramMemory;
+ auto *PT = cast<PointerType>(V->getType());
+ assert(PT != nullptr && "unexpected MemSDNode");
+ return PT->getAddressSpace() == ProgramMemory ||
+ PT->getAddressSpace() == ProgramMemory1 ||
+ PT->getAddressSpace() == ProgramMemory2 ||
+ PT->getAddressSpace() == ProgramMemory3 ||
+ PT->getAddressSpace() == ProgramMemory4 ||
+ PT->getAddressSpace() == ProgramMemory5;
+}
+
+template <typename T> AddressSpace getAddressSpace(T *V) {
+ auto *PT = cast<PointerType>(V->getType());
+ assert(PT != nullptr && "unexpected MemSDNode");
+ unsigned AS = PT->getAddressSpace();
+ if (AS < NumAddrSpaces)
+ return static_cast<AddressSpace>(AS);
+ return NumAddrSpaces;
}
inline bool isProgramMemoryAccess(MemSDNode const *N) {
- auto V = N->getMemOperand()->getValue();
+ auto *V = N->getMemOperand()->getValue();
+ if (V != nullptr && isProgramMemoryAddress(V))
+ return true;
+ return false;
+}
- return (V != nullptr) ? isProgramMemoryAddress(V) : false;
+// Get the index of the program memory bank.
+// -1: not program memory
+// 0: ordinary program memory
+// 1~5: extended program memory
+inline int getProgramMemoryBank(MemSDNode const *N) {
+ auto *V = N->getMemOperand()->getValue();
+ if (V == nullptr || !isProgramMemoryAddress(V))
+ return -1;
+ AddressSpace AS = getAddressSpace(V);
+ assert(ProgramMemory <= AS && AS <= ProgramMemory5);
+ return static_cast<int>(AS - ProgramMemory);
}
} // end of namespace AVR
diff --git a/llvm/lib/Target/AVR/AVRCallingConv.td b/llvm/lib/Target/AVR/AVRCallingConv.td
index 87874c5c50b2..b4bc35e191c0 100644
--- a/llvm/lib/Target/AVR/AVRCallingConv.td
+++ b/llvm/lib/Target/AVR/AVRCallingConv.td
@@ -36,4 +36,4 @@ def ArgCC_AVR_Vararg : CallingConv<[
//===----------------------------------------------------------------------===//
def CSR_Normal : CalleeSavedRegs<(add R29, R28, (sequence "R%u", 17, 2))>;
-def CSR_Interrupts : CalleeSavedRegs<(add(sequence "R%u", 31, 0))>;
+def CSR_Interrupts : CalleeSavedRegs<(add(sequence "R%u", 31, 2))>;
diff --git a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
index cb85d73772c5..144ae2b320f9 100644
--- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
@@ -92,6 +92,7 @@ private:
/// Specific shift implementation.
bool expandLSLB7Rd(Block &MBB, BlockIt MBBI);
bool expandLSRB7Rd(Block &MBB, BlockIt MBBI);
+ bool expandASRB6Rd(Block &MBB, BlockIt MBBI);
bool expandASRB7Rd(Block &MBB, BlockIt MBBI);
bool expandLSLW4Rd(Block &MBB, BlockIt MBBI);
bool expandLSRW4Rd(Block &MBB, BlockIt MBBI);
@@ -101,6 +102,9 @@ private:
bool expandLSLW12Rd(Block &MBB, BlockIt MBBI);
bool expandLSRW12Rd(Block &MBB, BlockIt MBBI);
+ // Common implementation of LPMWRdZ and ELPMWRdZ.
+ bool expandLPMWELPMW(Block &MBB, BlockIt MBBI, bool IsExt);
+
/// Scavenges a free GPR8 register for use.
Register scavengeGPR8(MachineInstr &MI);
};
@@ -808,18 +812,25 @@ bool AVRExpandPseudo::expand<AVR::LDDWRdPtrQ>(Block &MBB, BlockIt MBBI) {
return true;
}
-template <>
-bool AVRExpandPseudo::expand<AVR::LPMWRdZ>(Block &MBB, BlockIt MBBI) {
+bool AVRExpandPseudo::expandLPMWELPMW(Block &MBB, BlockIt MBBI, bool IsExt) {
MachineInstr &MI = *MBBI;
Register DstLoReg, DstHiReg;
Register DstReg = MI.getOperand(0).getReg();
Register TmpReg = 0; // 0 for no temporary register
Register SrcReg = MI.getOperand(1).getReg();
bool SrcIsKill = MI.getOperand(1).isKill();
- unsigned OpLo = AVR::LPMRdZPi;
- unsigned OpHi = AVR::LPMRdZ;
+ unsigned OpLo = IsExt ? AVR::ELPMRdZPi : AVR::LPMRdZPi;
+ unsigned OpHi = IsExt ? AVR::ELPMRdZ : AVR::LPMRdZ;
TRI->splitReg(DstReg, DstLoReg, DstHiReg);
+ // Set the I/O register RAMPZ for ELPM.
+ if (IsExt) {
+ const AVRSubtarget &STI = MBB.getParent()->getSubtarget<AVRSubtarget>();
+ Register Bank = MI.getOperand(2).getReg();
+ // out RAMPZ, rtmp
+ buildMI(MBB, MBBI, AVR::OUTARr).addImm(STI.getIORegRAMPZ()).addReg(Bank);
+ }
+
// Use a temporary register if src and dst registers are the same.
if (DstReg == SrcReg)
TmpReg = scavengeGPR8(MI);
@@ -857,8 +868,51 @@ bool AVRExpandPseudo::expand<AVR::LPMWRdZ>(Block &MBB, BlockIt MBBI) {
}
template <>
+bool AVRExpandPseudo::expand<AVR::LPMWRdZ>(Block &MBB, BlockIt MBBI) {
+ return expandLPMWELPMW(MBB, MBBI, false);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ELPMWRdZ>(Block &MBB, BlockIt MBBI) {
+ return expandLPMWELPMW(MBB, MBBI, true);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ELPMBRdZ>(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ Register DstReg = MI.getOperand(0).getReg();
+ Register SrcReg = MI.getOperand(1).getReg();
+ Register BankReg = MI.getOperand(2).getReg();
+ bool SrcIsKill = MI.getOperand(1).isKill();
+ const AVRSubtarget &STI = MBB.getParent()->getSubtarget<AVRSubtarget>();
+
+ // Set the I/O register RAMPZ for ELPM (out RAMPZ, rtmp).
+ buildMI(MBB, MBBI, AVR::OUTARr).addImm(STI.getIORegRAMPZ()).addReg(BankReg);
+
+ // Load byte.
+ auto MILB = buildMI(MBB, MBBI, AVR::ELPMRdZ)
+ .addReg(DstReg, RegState::Define)
+ .addReg(SrcReg, getKillRegState(SrcIsKill));
+
+ MILB.setMemRefs(MI.memoperands());
+
+ MI.eraseFromParent();
+ return true;
+}
+
+template <>
bool AVRExpandPseudo::expand<AVR::LPMWRdZPi>(Block &MBB, BlockIt MBBI) {
- llvm_unreachable("wide LPMPi is unimplemented");
+ llvm_unreachable("16-bit LPMPi is unimplemented");
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ELPMBRdZPi>(Block &MBB, BlockIt MBBI) {
+ llvm_unreachable("byte ELPMPi is unimplemented");
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::ELPMWRdZPi>(Block &MBB, BlockIt MBBI) {
+ llvm_unreachable("16-bit ELPMPi is unimplemented");
}
template <typename Func>
@@ -1411,6 +1465,30 @@ bool AVRExpandPseudo::expand<AVR::LSLWRd>(Block &MBB, BlockIt MBBI) {
return true;
}
+template <>
+bool AVRExpandPseudo::expand<AVR::LSLWHiRd>(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);
+
+ // add hireg, hireg <==> lsl hireg
+ auto MILSL =
+ buildMI(MBB, MBBI, AVR::ADDRdRr)
+ .addReg(DstHiReg, RegState::Define, getDeadRegState(DstIsDead))
+ .addReg(DstHiReg, getKillRegState(DstIsKill))
+ .addReg(DstHiReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MILSL->getOperand(3).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
bool AVRExpandPseudo::expandLSLW4Rd(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register DstLoReg, DstHiReg;
@@ -1586,6 +1664,29 @@ bool AVRExpandPseudo::expand<AVR::LSRWRd>(Block &MBB, BlockIt MBBI) {
return true;
}
+template <>
+bool AVRExpandPseudo::expand<AVR::LSRWLoRd>(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);
+
+ // lsr loreg
+ auto MILSR =
+ buildMI(MBB, MBBI, AVR::LSRRd)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MILSR->getOperand(2).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
bool AVRExpandPseudo::expandLSRW4Rd(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register DstLoReg, DstHiReg;
@@ -1773,6 +1874,29 @@ bool AVRExpandPseudo::expand<AVR::ASRWRd>(Block &MBB, BlockIt MBBI) {
return true;
}
+template <>
+bool AVRExpandPseudo::expand<AVR::ASRWLoRd>(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);
+
+ // asr loreg
+ auto MIASR =
+ buildMI(MBB, MBBI, AVR::ASRRd)
+ .addReg(DstLoReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstLoReg, getKillRegState(DstIsKill));
+
+ if (ImpIsDead)
+ MIASR->getOperand(2).setIsDead();
+
+ MI.eraseFromParent();
+ return true;
+}
+
bool AVRExpandPseudo::expandASRW8Rd(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register DstLoReg, DstHiReg;
@@ -1921,6 +2045,44 @@ bool AVRExpandPseudo::expand<AVR::LSRBNRd>(Block &MBB, BlockIt MBBI) {
}
}
+bool AVRExpandPseudo::expandASRB6Rd(Block &MBB, BlockIt MBBI) {
+ MachineInstr &MI = *MBBI;
+ Register DstReg = MI.getOperand(0).getReg();
+ bool DstIsDead = MI.getOperand(0).isDead();
+ bool DstIsKill = MI.getOperand(1).isKill();
+
+ // bst r24, 6
+ // lsl r24
+ // sbc r24, r24
+ // bld r24, 0
+
+ buildMI(MBB, MBBI, AVR::BST)
+ .addReg(DstReg)
+ .addImm(6)
+ ->getOperand(2)
+ .setIsUndef(true);
+
+ buildMI(MBB, MBBI, AVR::ADDRdRr) // LSL Rd <==> ADD Rd, Rd
+ .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstReg, getKillRegState(DstIsKill))
+ .addReg(DstReg, getKillRegState(DstIsKill));
+
+ buildMI(MBB, MBBI, AVR::SBCRdRr)
+ .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstReg, getKillRegState(DstIsKill))
+ .addReg(DstReg, getKillRegState(DstIsKill));
+
+ buildMI(MBB, MBBI, AVR::BLD)
+ .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
+ .addReg(DstReg, getKillRegState(DstIsKill))
+ .addImm(0)
+ ->getOperand(3)
+ .setIsKill();
+
+ MI.eraseFromParent();
+ return true;
+}
+
bool AVRExpandPseudo::expandASRB7Rd(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register DstReg = MI.getOperand(0).getReg();
@@ -1957,6 +2119,8 @@ bool AVRExpandPseudo::expand<AVR::ASRBNRd>(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
unsigned Imm = MI.getOperand(2).getImm();
switch (Imm) {
+ case 6:
+ return expandASRB6Rd(MBB, MBBI);
case 7:
return expandASRB7Rd(MBB, MBBI);
default:
@@ -2158,6 +2322,10 @@ bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
EXPAND(AVR::LDDWRdPtrQ);
EXPAND(AVR::LPMWRdZ);
EXPAND(AVR::LPMWRdZPi);
+ EXPAND(AVR::ELPMBRdZ);
+ EXPAND(AVR::ELPMWRdZ);
+ EXPAND(AVR::ELPMBRdZPi);
+ EXPAND(AVR::ELPMWRdZPi);
EXPAND(AVR::AtomicLoad8);
EXPAND(AVR::AtomicLoad16);
EXPAND(AVR::AtomicStore8);
@@ -2189,6 +2357,9 @@ bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
EXPAND(AVR::RORWRd);
EXPAND(AVR::ROLWRd);
EXPAND(AVR::ASRWRd);
+ EXPAND(AVR::LSLWHiRd);
+ EXPAND(AVR::LSRWLoRd);
+ EXPAND(AVR::ASRWLoRd);
EXPAND(AVR::LSLWNRd);
EXPAND(AVR::LSRWNRd);
EXPAND(AVR::ASRWNRd);
diff --git a/llvm/lib/Target/AVR/AVRFrameLowering.cpp b/llvm/lib/Target/AVR/AVRFrameLowering.cpp
index 543d94875037..b3bc9ede205e 100644
--- a/llvm/lib/Target/AVR/AVRFrameLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRFrameLowering.cpp
@@ -79,11 +79,6 @@ void AVRFrameLowering::emitPrologue(MachineFunction &MF,
.addReg(AVR::R0, RegState::Kill)
.setMIFlag(MachineInstr::FrameSetup);
BuildMI(MBB, MBBI, DL, TII.get(AVR::EORRdRr))
- .addReg(AVR::R0, RegState::Define)
- .addReg(AVR::R0, RegState::Kill)
- .addReg(AVR::R0, 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)
@@ -176,7 +171,7 @@ void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
const AVRInstrInfo &TII = *STI.getInstrInfo();
// Early exit if there is no need to restore the frame pointer.
- if (!FrameSize) {
+ if (!FrameSize && !MF.getFrameInfo().hasVarSizedObjects()) {
restoreStatusRegister(MF, MBB);
return;
}
@@ -193,22 +188,24 @@ void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
--MBBI;
}
- unsigned Opcode;
+ if (FrameSize) {
+ unsigned Opcode;
- // Select the optimal opcode depending on how big it is.
- if (isUInt<6>(FrameSize)) {
- Opcode = AVR::ADIWRdK;
- } else {
- Opcode = AVR::SUBIWRdK;
- FrameSize = -FrameSize;
- }
+ // Select the optimal opcode depending on how big it is.
+ if (isUInt<6>(FrameSize)) {
+ Opcode = AVR::ADIWRdK;
+ } else {
+ Opcode = AVR::SUBIWRdK;
+ FrameSize = -FrameSize;
+ }
- // Restore the frame pointer by doing FP += <size>.
- MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)
- .addReg(AVR::R29R28, RegState::Kill)
- .addImm(FrameSize);
- // The SREG implicit def is dead.
- MI->getOperand(3).setIsDead();
+ // Restore the frame pointer by doing FP += <size>.
+ MachineInstr *MI = BuildMI(MBB, MBBI, DL, TII.get(Opcode), AVR::R29R28)
+ .addReg(AVR::R29R28, RegState::Kill)
+ .addImm(FrameSize);
+ // The SREG implicit def is dead.
+ MI->getOperand(3).setIsDead();
+ }
// Write back R29R28 to SP and temporarily disable interrupts.
BuildMI(MBB, MBBI, DL, TII.get(AVR::SPWRITE), AVR::SP)
@@ -230,7 +227,8 @@ bool AVRFrameLowering::hasFP(const MachineFunction &MF) const {
const AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();
return (FuncInfo->getHasSpills() || FuncInfo->getHasAllocas() ||
- FuncInfo->getHasStackArgs());
+ FuncInfo->getHasStackArgs() ||
+ MF.getFrameInfo().hasVarSizedObjects());
}
bool AVRFrameLowering::spillCalleeSavedRegisters(
@@ -248,7 +246,7 @@ bool AVRFrameLowering::spillCalleeSavedRegisters(
AVRMachineFunctionInfo *AVRFI = MF.getInfo<AVRMachineFunctionInfo>();
for (const CalleeSavedInfo &I : llvm::reverse(CSI)) {
- unsigned Reg = I.getReg();
+ Register Reg = I.getReg();
bool IsNotLiveIn = !MBB.isLiveIn(Reg);
assert(TRI->getRegSizeInBits(*TRI->getMinimalPhysRegClass(Reg)) == 8 &&
@@ -286,7 +284,7 @@ bool AVRFrameLowering::restoreCalleeSavedRegisters(
const TargetInstrInfo &TII = *STI.getInstrInfo();
for (const CalleeSavedInfo &CCSI : CSI) {
- unsigned Reg = CCSI.getReg();
+ Register Reg = CCSI.getReg();
assert(TRI->getRegSizeInBits(*TRI->getMinimalPhysRegClass(Reg)) == 8 &&
"Invalid register size");
@@ -480,56 +478,4 @@ char AVRFrameAnalyzer::ID = 0;
/// Creates instance of the frame analyzer pass.
FunctionPass *createAVRFrameAnalyzerPass() { return new AVRFrameAnalyzer(); }
-/// Create the Dynalloca Stack Pointer Save/Restore pass.
-/// Insert a copy of SP before allocating the dynamic stack memory and restore
-/// it in function exit to restore the original SP state. This avoids the need
-/// of reserving a register pair for a frame pointer.
-struct AVRDynAllocaSR : public MachineFunctionPass {
- static char ID;
- AVRDynAllocaSR() : MachineFunctionPass(ID) {}
-
- bool runOnMachineFunction(MachineFunction &MF) override {
- // Early exit when there are no variable sized objects in the function.
- if (!MF.getFrameInfo().hasVarSizedObjects()) {
- return false;
- }
-
- const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
- const TargetInstrInfo &TII = *STI.getInstrInfo();
- MachineBasicBlock &EntryMBB = MF.front();
- MachineBasicBlock::iterator MBBI = EntryMBB.begin();
- DebugLoc DL = EntryMBB.findDebugLoc(MBBI);
-
- Register SPCopy =
- MF.getRegInfo().createVirtualRegister(&AVR::DREGSRegClass);
-
- // Create a copy of SP in function entry before any dynallocas are
- // inserted.
- BuildMI(EntryMBB, MBBI, DL, TII.get(AVR::COPY), SPCopy).addReg(AVR::SP);
-
- // Restore SP in all exit basic blocks.
- for (MachineBasicBlock &MBB : MF) {
- // If last instruction is a return instruction, add a restore copy.
- if (!MBB.empty() && MBB.back().isReturn()) {
- MBBI = MBB.getLastNonDebugInstr();
- DL = MBBI->getDebugLoc();
- BuildMI(MBB, MBBI, DL, TII.get(AVR::COPY), AVR::SP)
- .addReg(SPCopy, RegState::Kill);
- }
- }
-
- return true;
- }
-
- StringRef getPassName() const override {
- return "AVR dynalloca stack pointer save/restore";
- }
-};
-
-char AVRDynAllocaSR::ID = 0;
-
-/// createAVRDynAllocaSRPass - returns an instance of the dynalloca stack
-/// pointer save/restore pass.
-FunctionPass *createAVRDynAllocaSRPass() { return new AVRDynAllocaSR(); }
-
} // end of namespace llvm
diff --git a/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp b/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
index 7ec2629ab45d..df364cae671c 100644
--- a/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
@@ -38,7 +38,7 @@ public:
bool SelectAddr(SDNode *Op, SDValue N, SDValue &Base, SDValue &Disp);
bool selectIndexedLoad(SDNode *N);
- unsigned selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT);
+ unsigned selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT, int Bank);
bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode,
std::vector<SDValue> &OutOps) override;
@@ -165,35 +165,31 @@ bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *N) {
return true;
}
-unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(const LoadSDNode *LD,
- MVT VT) {
- ISD::MemIndexedMode AM = LD->getAddressingMode();
-
+unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT,
+ int Bank) {
// Progmem indexed loads only work in POSTINC mode.
- if (LD->getExtensionType() != ISD::NON_EXTLOAD || AM != ISD::POST_INC) {
+ if (LD->getExtensionType() != ISD::NON_EXTLOAD ||
+ LD->getAddressingMode() != ISD::POST_INC)
return 0;
- }
+
+ // Feature ELPM is needed for loading from extended program memory.
+ assert((Bank == 0 || Subtarget->hasELPM()) &&
+ "cannot load from extended program memory on this mcu");
unsigned Opcode = 0;
int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue();
switch (VT.SimpleTy) {
- case MVT::i8: {
- if (Offs != 1) {
- return 0;
- }
- Opcode = AVR::LPMRdZPi;
+ case MVT::i8:
+ if (Offs == 1)
+ Opcode = Bank > 0 ? AVR::ELPMBRdZPi : AVR::LPMRdZPi;
break;
- }
- case MVT::i16: {
- if (Offs != 2) {
- return 0;
- }
- Opcode = AVR::LPMWRdZPi;
+ case MVT::i16:
+ if (Offs == 2)
+ Opcode = Bank > 0 ? AVR::ELPMWRdZPi : AVR::LPMWRdZPi;
break;
- }
default:
- return 0;
+ break;
}
return Opcode;
@@ -360,7 +356,12 @@ template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) {
return selectIndexedLoad(N);
}
- assert(Subtarget->hasLPM() && "cannot load from program memory on this mcu");
+ if (!Subtarget->hasLPM())
+ report_fatal_error("cannot load from program memory on this mcu");
+
+ int ProgMemBank = AVR::getProgramMemoryBank(LD);
+ if (ProgMemBank < 0 || ProgMemBank > 5)
+ report_fatal_error("unexpected program memory bank");
// This is a flash memory load, move the pointer into R31R30 and emit
// the lpm instruction.
@@ -374,25 +375,48 @@ template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) {
Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16,
Chain.getValue(1));
- SDValue RegZ = CurDAG->getRegister(AVR::R31R30, MVT::i16);
-
// Check if the opcode can be converted into an indexed load.
- if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT)) {
+ if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT, ProgMemBank)) {
// It is legal to fold the load into an indexed load.
- ResNode =
- CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr, RegZ);
- ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
+ if (ProgMemBank == 0) {
+ ResNode =
+ CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr);
+ } else {
+ // Do not combine the LDI instruction into the ELPM pseudo instruction,
+ // since it may be reused by other ELPM pseudo instructions.
+ SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);
+ auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
+ ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other,
+ Ptr, SDValue(NP, 0));
+ }
} else {
// Selecting an indexed load is not legal, fallback to a normal load.
switch (VT.SimpleTy) {
case MVT::i8:
- ResNode = CurDAG->getMachineNode(AVR::LPMRdZ, DL, MVT::i8, MVT::Other,
- Ptr, RegZ);
+ if (ProgMemBank == 0) {
+ ResNode =
+ CurDAG->getMachineNode(AVR::LPMRdZ, DL, MVT::i8, MVT::Other, Ptr);
+ } else {
+ // Do not combine the LDI instruction into the ELPM pseudo instruction,
+ // since it may be reused by other ELPM pseudo instructions.
+ SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);
+ auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
+ ResNode = CurDAG->getMachineNode(AVR::ELPMBRdZ, DL, MVT::i8, MVT::Other,
+ Ptr, SDValue(NP, 0));
+ }
break;
case MVT::i16:
- ResNode = CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16, MVT::Other,
- Ptr, RegZ);
- ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
+ if (ProgMemBank == 0) {
+ ResNode =
+ CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16, MVT::Other, Ptr);
+ } else {
+ // Do not combine the LDI instruction into the ELPM pseudo instruction,
+ // since LDI requires the destination register in range R16~R31.
+ SDValue NC = CurDAG->getTargetConstant(ProgMemBank, DL, MVT::i8);
+ auto *NP = CurDAG->getMachineNode(AVR::LDIRdK, DL, MVT::i8, NC);
+ ResNode = CurDAG->getMachineNode(AVR::ELPMWRdZ, DL, MVT::i16,
+ MVT::Other, Ptr, SDValue(NP, 0));
+ }
break;
default:
llvm_unreachable("Unsupported VT!");
diff --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp
index a6f2afb87102..a58fedf6cd36 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp
@@ -359,6 +359,11 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
Victim = DAG.getNode(AVRISD::LSRBN, dl, VT, Victim,
DAG.getConstant(7, dl, VT));
ShiftAmount = 0;
+ } else if (Op.getOpcode() == ISD::SRA && ShiftAmount == 6) {
+ // Optimize ASR when ShiftAmount == 6.
+ Victim = DAG.getNode(AVRISD::ASRBN, dl, VT, Victim,
+ DAG.getConstant(6, dl, VT));
+ ShiftAmount = 0;
} else if (Op.getOpcode() == ISD::SRA && ShiftAmount == 7) {
// Optimize ASR when ShiftAmount == 7.
Victim = DAG.getNode(AVRISD::ASRBN, dl, VT, Victim,
@@ -387,16 +392,22 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
Victim = DAG.getNode(AVRISD::LSLWN, dl, VT, Victim,
DAG.getConstant(8, dl, VT));
ShiftAmount -= 8;
+ // Only operate on the higher byte for remaining shift bits.
+ Opc8 = AVRISD::LSLHI;
break;
case ISD::SRL:
Victim = DAG.getNode(AVRISD::LSRWN, dl, VT, Victim,
DAG.getConstant(8, dl, VT));
ShiftAmount -= 8;
+ // Only operate on the lower byte for remaining shift bits.
+ Opc8 = AVRISD::LSRLO;
break;
case ISD::SRA:
Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim,
DAG.getConstant(8, dl, VT));
ShiftAmount -= 8;
+ // Only operate on the lower byte for remaining shift bits.
+ Opc8 = AVRISD::ASRLO;
break;
default:
break;
@@ -407,11 +418,22 @@ SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const {
Victim = DAG.getNode(AVRISD::LSLWN, dl, VT, Victim,
DAG.getConstant(12, dl, VT));
ShiftAmount -= 12;
+ // Only operate on the higher byte for remaining shift bits.
+ Opc8 = AVRISD::LSLHI;
break;
case ISD::SRL:
Victim = DAG.getNode(AVRISD::LSRWN, dl, VT, Victim,
DAG.getConstant(12, dl, VT));
ShiftAmount -= 12;
+ // Only operate on the lower byte for remaining shift bits.
+ Opc8 = AVRISD::LSRLO;
+ break;
+ case ISD::SRA:
+ Victim = DAG.getNode(AVRISD::ASRWN, dl, VT, Victim,
+ DAG.getConstant(8, dl, VT));
+ ShiftAmount -= 8;
+ // Only operate on the lower byte for remaining shift bits.
+ Opc8 = AVRISD::ASRLO;
break;
default:
break;
@@ -874,7 +896,8 @@ bool AVRTargetLowering::isLegalAddressingMode(const DataLayout &DL,
// Allow reg+<6bit> offset.
if (Offs < 0)
Offs = -Offs;
- if (AM.BaseGV == 0 && AM.HasBaseReg && AM.Scale == 0 && isUInt<6>(Offs)) {
+ if (AM.BaseGV == nullptr && AM.HasBaseReg && AM.Scale == 0 &&
+ isUInt<6>(Offs)) {
return true;
}
@@ -1169,7 +1192,7 @@ SDValue AVRTargetLowering::LowerFormalArguments(
llvm_unreachable("Unknown argument type!");
}
- unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC);
+ Register Reg = MF.addLiveIn(VA.getLocReg(), RC);
ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT);
// :NOTE: Clang should not promote any i8 into i16 but for safety the
@@ -1672,6 +1695,18 @@ MachineBasicBlock *AVRTargetLowering::insertMul(MachineInstr &MI,
return BB;
}
+// Insert a read from R1, which almost always contains the value 0.
+MachineBasicBlock *
+AVRTargetLowering::insertCopyR1(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);
+ MI.eraseFromParent();
+ return BB;
+}
+
MachineBasicBlock *
AVRTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *MBB) const {
@@ -1694,6 +1729,8 @@ AVRTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case AVR::MULRdRr:
case AVR::MULSRdRr:
return insertMul(MI, MBB);
+ case AVR::CopyR1:
+ return insertCopyR1(MI, MBB);
}
assert((Opc == AVR::Select16 || Opc == AVR::Select8) &&
@@ -2012,7 +2049,7 @@ void AVRTargetLowering::LowerAsmOperandForConstraint(SDValue Op,
std::string &Constraint,
std::vector<SDValue> &Ops,
SelectionDAG &DAG) const {
- SDValue Result(0, 0);
+ SDValue Result;
SDLoc DL(Op);
EVT Ty = Op.getValueType();
diff --git a/llvm/lib/Target/AVR/AVRISelLowering.h b/llvm/lib/Target/AVR/AVRISelLowering.h
index 3ae036b66bcb..116417b61566 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.h
+++ b/llvm/lib/Target/AVR/AVRISelLowering.h
@@ -38,12 +38,15 @@ enum NodeType {
LSL, ///< Logical shift left.
LSLBN, ///< Byte logical shift left N bits.
LSLWN, ///< Word logical shift left N bits.
+ LSLHI, ///< Higher 8-bit of word logical shift left.
LSR, ///< Logical shift right.
LSRBN, ///< Byte logical shift right N bits.
LSRWN, ///< Word logical shift right N bits.
+ LSRLO, ///< Lower 8-bit of word logical shift right.
ASR, ///< Arithmetic shift right.
ASRBN, ///< Byte arithmetic shift right N bits.
ASRWN, ///< Word arithmetic shift right N bits.
+ ASRLO, ///< Lower 8-bit of word arithmetic shift right.
ROR, ///< Bit rotate right.
ROL, ///< Bit rotate left.
LSLLOOP, ///< A loop of single logical shift left instructions.
@@ -184,6 +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;
};
} // end namespace llvm
diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.cpp b/llvm/lib/Target/AVR/AVRInstrInfo.cpp
index 51060018a5ca..ac52c47f93d5 100644
--- a/llvm/lib/Target/AVR/AVRInstrInfo.cpp
+++ b/llvm/lib/Target/AVR/AVRInstrInfo.cpp
@@ -304,11 +304,11 @@ bool AVRInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
}
Cond.clear();
- FBB = 0;
+ FBB = nullptr;
// Delete the JMP if it's equivalent to a fall-through.
if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) {
- TBB = 0;
+ TBB = nullptr;
I->eraseFromParent();
I = MBB.end();
UnCondBrIter = MBB.end();
diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td
index c7f423292da0..2b96dc0b833a 100644
--- a/llvm/lib/Target/AVR/AVRInstrInfo.td
+++ b/llvm/lib/Target/AVR/AVRInstrInfo.td
@@ -60,6 +60,9 @@ def AVRlsr : SDNode<"AVRISD::LSR", SDTIntUnaryOp>;
def AVRrol : SDNode<"AVRISD::ROL", SDTIntUnaryOp>;
def AVRror : SDNode<"AVRISD::ROR", SDTIntUnaryOp>;
def AVRasr : SDNode<"AVRISD::ASR", SDTIntUnaryOp>;
+def AVRlslhi : SDNode<"AVRISD::LSLHI", SDTIntUnaryOp>;
+def AVRlsrlo : SDNode<"AVRISD::LSRLO", SDTIntUnaryOp>;
+def AVRasrlo : SDNode<"AVRISD::ASRLO", SDTIntUnaryOp>;
def AVRlslbn : SDNode<"AVRISD::LSLBN", SDTIntBinOp>;
def AVRlsrbn : SDNode<"AVRISD::LSRBN", SDTIntBinOp>;
def AVRasrbn : SDNode<"AVRISD::ASRBN", SDTIntBinOp>;
@@ -1391,7 +1394,7 @@ let canFoldAsLoad = 1, isReMaterializable = 1 in {
// ldd Rd, P+q
// ldd Rd+1, P+q+1
let Constraints = "@earlyclobber $dst" in def LDDWRdPtrQ
- : Pseudo<(outs DREGS_WITHOUT_YZ_WORKAROUND
+ : Pseudo<(outs DREGS
: $dst),
(ins memri
: $memri),
@@ -1699,21 +1702,34 @@ let mayLoad = 1, hasSideEffects = 0 in {
: F16<0b1001010111011000, (outs), (ins), "elpm", []>,
Requires<[HasELPM]>;
- def ELPMRdZ : FLPMX<1, 0,
- (outs GPR8
- : $dst),
- (ins ZREG
- : $z),
+ def ELPMRdZ : FLPMX<1, 0, (outs GPR8:$dst), (ins ZREG:$z),
"elpm\t$dst, $z", []>,
Requires<[HasELPMX]>;
- let Defs = [R31R30] in def ELPMRdZPi : FLPMX<1, 1,
- (outs GPR8
- : $dst),
- (ins ZREG
- : $z),
- "elpm\t$dst, $z+", []>,
- Requires<[HasELPMX]>;
+ let Defs = [R31R30] in {
+ def ELPMRdZPi : FLPMX<1, 1, (outs GPR8:$dst), (ins ZREG:$z),
+ "elpm\t$dst, $z+", []>,
+ Requires<[HasELPMX]>;
+ }
+
+ // These pseudos are combination of the OUT and ELPM instructions.
+ let Defs = [R31R30], hasSideEffects = 1 in {
+ def ELPMBRdZ : Pseudo<(outs GPR8:$dst), (ins ZREG:$z, LD8:$p),
+ "elpmb\t$dst, $z, $p", []>,
+ Requires<[HasELPMX]>;
+
+ def ELPMWRdZ : Pseudo<(outs DREGS:$dst), (ins ZREG:$z, LD8:$p),
+ "elpmw\t$dst, $z, $p", []>,
+ Requires<[HasELPMX]>;
+
+ def ELPMBRdZPi : Pseudo<(outs GPR8:$dst), (ins ZREG:$z, LD8:$p),
+ "elpmb\t$dst, $z+, $p", []>,
+ Requires<[HasELPMX]>;
+
+ def ELPMWRdZPi : Pseudo<(outs DREGS:$dst), (ins ZREG:$z, LD8:$p),
+ "elpmw\t$dst, $z+, $p", []>,
+ Requires<[HasELPMX]>;
+ }
}
// Store program memory operations.
@@ -1848,6 +1864,9 @@ let Constraints = "$src = $rd", Defs = [SREG] in {
: $src)),
(implicit SREG)]>;
+ def LSLWHiRd : Pseudo<(outs DREGS:$rd), (ins DREGS:$src), "lslwhi\t$rd",
+ [(set i16:$rd, (AVRlslhi i16:$src)), (implicit SREG)]>;
+
def LSLWNRd : Pseudo<(outs DLDREGS
: $rd),
(ins DREGS
@@ -1895,6 +1914,9 @@ let Constraints = "$src = $rd", Defs = [SREG] in {
: $src)),
(implicit SREG)]>;
+ def LSRWLoRd : Pseudo<(outs DREGS:$rd), (ins DREGS:$src), "lsrwlo\t$rd",
+ [(set i16:$rd, (AVRlsrlo i16:$src)), (implicit SREG)]>;
+
def LSRWNRd : Pseudo<(outs DLDREGS
: $rd),
(ins DREGS
@@ -1968,6 +1990,9 @@ let Constraints = "$src = $rd", Defs = [SREG] in {
: $src)),
(implicit SREG)]>;
+ def ASRWLoRd : Pseudo<(outs DREGS:$rd), (ins DREGS:$src), "asrwlo\t$rd",
+ [(set i16:$rd, (AVRasrlo i16:$src)), (implicit SREG)]>;
+
def ROLBRd : Pseudo<(outs GPR8
: $rd),
(ins GPR8
@@ -2365,6 +2390,10 @@ def Asr16 : ShiftPseudo<(outs DREGS
: $src, i8
: $cnt))]>;
+// lowered to a copy from R1, which contains the value zero.
+let usesCustomInserter=1 in
+def CopyR1 : Pseudo<(outs GPR8:$rd), (ins), "clrz\t$rd", [(set i8:$rd, 0)]>;
+
//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AVR/AVRRegisterInfo.cpp b/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
index 1886debaf492..5dd7f5c55695 100644
--- a/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
+++ b/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
@@ -44,10 +44,7 @@ AVRRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
const uint32_t *
AVRRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const {
- const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
-
- return AFI->isInterruptOrSignalHandler() ? CSR_Interrupts_RegMask
- : CSR_Normal_RegMask;
+ return CSR_Normal_RegMask;
}
BitVector AVRRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
diff --git a/llvm/lib/Target/AVR/AVRRegisterInfo.h b/llvm/lib/Target/AVR/AVRRegisterInfo.h
index fa27d9283209..2c5647b52c1c 100644
--- a/llvm/lib/Target/AVR/AVRRegisterInfo.h
+++ b/llvm/lib/Target/AVR/AVRRegisterInfo.h
@@ -27,7 +27,7 @@ public:
public:
const uint16_t *
- getCalleeSavedRegs(const MachineFunction *MF = 0) const override;
+ getCalleeSavedRegs(const MachineFunction *MF = nullptr) const override;
const uint32_t *getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const override;
BitVector getReservedRegs(const MachineFunction &MF) const override;
@@ -39,7 +39,7 @@ public:
/// Stack Frame Processing Methods
void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj,
unsigned FIOperandNum,
- RegScavenger *RS = NULL) const override;
+ RegScavenger *RS = nullptr) const override;
Register getFrameRegister(const MachineFunction &MF) const override;
diff --git a/llvm/lib/Target/AVR/AVRRegisterInfo.td b/llvm/lib/Target/AVR/AVRRegisterInfo.td
index bb4e86ca0536..c5fda788fe4d 100644
--- a/llvm/lib/Target/AVR/AVRRegisterInfo.td
+++ b/llvm/lib/Target/AVR/AVRRegisterInfo.td
@@ -178,26 +178,6 @@ def DREGSMOVW : RegisterClass<"AVR", [i16], 8,
R29R28, R17R16, R15R14, R13R12, R11R10, R9R8,
R7R6, R5R4, R3R2, R1R0)>;
-// The 16-bit DREGS register class, excluding the Z pointer register.
-//
-// This is used by instructions which cause high pointer register
-// contention which leads to an assertion in the register allocator.
-//
-// There is no technical reason why instructions that use this class
-// cannot use Z; it's simply a workaround a regalloc bug.
-//
-// More information can be found in PR39553.
-def DREGS_WITHOUT_YZ_WORKAROUND
- : RegisterClass<"AVR", [i16], 8,
- (
- // Return value and arguments.
- add R25R24, R19R18, R21R20, R23R22,
- // Scratch registers.
- R27R26,
- // Callee saved registers.
- R17R16, R15R14, R13R12, R11R10, R9R8, R7R6, R5R4, R3R2,
- R1R0)>;
-
// 16-bit register class for immediate instructions.
def DLDREGS : RegisterClass<"AVR", [i16], 8,
(
diff --git a/llvm/lib/Target/AVR/AVRSubtarget.cpp b/llvm/lib/Target/AVR/AVRSubtarget.cpp
index 990e1c57e63f..8a5481423e9f 100644
--- a/llvm/lib/Target/AVR/AVRSubtarget.cpp
+++ b/llvm/lib/Target/AVR/AVRSubtarget.cpp
@@ -40,8 +40,7 @@ AVRSubtarget::AVRSubtarget(const Triple &TT, const std::string &CPU,
m_hasTinyEncoding(false), m_hasMemMappedGPR(false),
m_FeatureSetDummy(false),
- InstrInfo(), FrameLowering(),
- TLInfo(TM, initializeSubtargetDependencies(CPU, FS, TM)), TSInfo() {
+ TLInfo(TM, initializeSubtargetDependencies(CPU, FS, TM)) {
// Parse features string.
ParseSubtargetFeatures(CPU, /*TuneCPU*/ CPU, FS);
}
diff --git a/llvm/lib/Target/AVR/AVRSubtarget.h b/llvm/lib/Target/AVR/AVRSubtarget.h
index 90b9cd4da7c1..f8ca191b1868 100644
--- a/llvm/lib/Target/AVR/AVRSubtarget.h
+++ b/llvm/lib/Target/AVR/AVRSubtarget.h
@@ -91,6 +91,9 @@ public:
return ELFArch;
}
+ /// Get I/O register address.
+ int getIORegRAMPZ(void) const { return 0x3b; }
+
private:
/// The ELF e_flags architecture.
unsigned ELFArch;
diff --git a/llvm/lib/Target/AVR/AVRTargetMachine.cpp b/llvm/lib/Target/AVR/AVRTargetMachine.cpp
index 65740f7c2306..22b9ba3ece07 100644
--- a/llvm/lib/Target/AVR/AVRTargetMachine.cpp
+++ b/llvm/lib/Target/AVR/AVRTargetMachine.cpp
@@ -70,7 +70,6 @@ public:
bool addInstSelector() override;
void addPreSched2() override;
void addPreEmitPass() override;
- void addPreRegAlloc() override;
};
} // namespace
@@ -118,11 +117,6 @@ bool AVRPassConfig::addInstSelector() {
return false;
}
-void AVRPassConfig::addPreRegAlloc() {
- // Create the dynalloc SP save/restore pass to handle variable sized allocas.
- addPass(createAVRDynAllocaSRPass());
-}
-
void AVRPassConfig::addPreSched2() {
addPass(createAVRRelaxMemPass());
addPass(createAVRExpandPseudoPass());
diff --git a/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp b/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp
index c7715ca1f51b..fe8e863be1a3 100644
--- a/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp
+++ b/llvm/lib/Target/AVR/AVRTargetObjectFile.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "AVRTargetObjectFile.h"
+#include "AVRTargetMachine.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/IR/DerivedTypes.h"
@@ -22,14 +23,60 @@ void AVRTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM) {
Base::Initialize(Ctx, TM);
ProgmemDataSection =
Ctx.getELFSection(".progmem.data", ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
+ Progmem1DataSection =
+ Ctx.getELFSection(".progmem1.data", ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
+ Progmem2DataSection =
+ Ctx.getELFSection(".progmem2.data", ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
+ Progmem3DataSection =
+ Ctx.getELFSection(".progmem3.data", ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
+ Progmem4DataSection =
+ Ctx.getELFSection(".progmem4.data", ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
+ Progmem5DataSection =
+ Ctx.getELFSection(".progmem5.data", ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
}
MCSection *AVRTargetObjectFile::SelectSectionForGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
- // Global values in flash memory are placed in the progmem.data section
+ // Global values in flash memory are placed in the progmem*.data section
// unless they already have a user assigned section.
- if (AVR::isProgramMemoryAddress(GO) && !GO->hasSection() && Kind.isReadOnly())
- return ProgmemDataSection;
+ const auto &AVRTM = static_cast<const AVRTargetMachine &>(TM);
+ if (AVR::isProgramMemoryAddress(GO) && !GO->hasSection() &&
+ Kind.isReadOnly()) {
+ // The AVR subtarget should support LPM to access section '.progmem*.data'.
+ if (!AVRTM.getSubtargetImpl()->hasLPM()) {
+ // TODO: Get the global object's location in source file.
+ getContext().reportError(
+ SMLoc(),
+ "Current AVR subtarget does not support accessing program memory");
+ return Base::SelectSectionForGlobal(GO, Kind, TM);
+ }
+ // The AVR subtarget should support ELPM to access section
+ // '.progmem[1|2|3|4|5].data'.
+ if (!AVRTM.getSubtargetImpl()->hasELPM() &&
+ AVR::getAddressSpace(GO) != AVR::ProgramMemory) {
+ // TODO: Get the global object's location in source file.
+ getContext().reportError(SMLoc(),
+ "Current AVR subtarget does not support "
+ "accessing extended program memory");
+ return ProgmemDataSection;
+ }
+ switch (AVR::getAddressSpace(GO)) {
+ case AVR::ProgramMemory: // address space 1
+ return ProgmemDataSection;
+ case AVR::ProgramMemory1: // address space 2
+ return Progmem1DataSection;
+ case AVR::ProgramMemory2: // address space 3
+ return Progmem2DataSection;
+ case AVR::ProgramMemory3: // address space 4
+ return Progmem3DataSection;
+ case AVR::ProgramMemory4: // address space 5
+ return Progmem4DataSection;
+ case AVR::ProgramMemory5: // address space 6
+ return Progmem5DataSection;
+ default:
+ llvm_unreachable("unexpected program memory index");
+ }
+ }
// Otherwise, we work the same way as ELF.
return Base::SelectSectionForGlobal(GO, Kind, TM);
diff --git a/llvm/lib/Target/AVR/AVRTargetObjectFile.h b/llvm/lib/Target/AVR/AVRTargetObjectFile.h
index 53d8510d9a21..609849b44029 100644
--- a/llvm/lib/Target/AVR/AVRTargetObjectFile.h
+++ b/llvm/lib/Target/AVR/AVRTargetObjectFile.h
@@ -25,6 +25,11 @@ public:
private:
MCSection *ProgmemDataSection;
+ MCSection *Progmem1DataSection;
+ MCSection *Progmem2DataSection;
+ MCSection *Progmem3DataSection;
+ MCSection *Progmem4DataSection;
+ MCSection *Progmem5DataSection;
};
} // end namespace llvm
diff --git a/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp b/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp
index 95ecd28200ba..f19e7840eb31 100644
--- a/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp
+++ b/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp
@@ -107,13 +107,13 @@ class AVROperand : public MCParsedAsmOperand {
public:
AVROperand(StringRef Tok, SMLoc const &S)
- : Base(), Kind(k_Token), Tok(Tok), Start(S), End(S) {}
+ : Kind(k_Token), Tok(Tok), Start(S), End(S) {}
AVROperand(unsigned Reg, SMLoc const &S, SMLoc const &E)
- : Base(), Kind(k_Register), RegImm({Reg, nullptr}), Start(S), End(E) {}
+ : Kind(k_Register), RegImm({Reg, nullptr}), Start(S), End(E) {}
AVROperand(MCExpr const *Imm, SMLoc const &S, SMLoc const &E)
- : Base(), Kind(k_Immediate), RegImm({0, Imm}), Start(S), End(E) {}
+ : Kind(k_Immediate), RegImm({0, Imm}), Start(S), End(E) {}
AVROperand(unsigned Reg, MCExpr const *Imm, SMLoc const &S, SMLoc const &E)
- : Base(), Kind(k_Memri), RegImm({Reg, Imm}), Start(S), End(E) {}
+ : Kind(k_Memri), RegImm({Reg, Imm}), Start(S), End(E) {}
struct RegisterImmediate {
unsigned Reg;
@@ -281,7 +281,7 @@ bool AVRAsmParser::invalidOperand(SMLoc const &Loc,
OperandVector const &Operands,
uint64_t const &ErrorInfo) {
SMLoc ErrorLoc = Loc;
- char const *Diag = 0;
+ char const *Diag = nullptr;
if (ErrorInfo != ~0U) {
if (ErrorInfo >= Operands.size()) {
diff --git a/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp b/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp
index a3a4d63932c0..3624ade854c0 100644
--- a/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp
+++ b/llvm/lib/Target/AVR/MCTargetDesc/AVRAsmBackend.cpp
@@ -47,7 +47,7 @@ static void signed_width(unsigned Width, uint64_t Value,
" to " + std::to_string(Max) + ")";
if (Ctx) {
- Ctx->reportFatalError(Fixup.getLoc(), Diagnostic);
+ Ctx->reportError(Fixup.getLoc(), Diagnostic);
} else {
llvm_unreachable(Diagnostic.c_str());
}
@@ -66,7 +66,7 @@ static void unsigned_width(unsigned Width, uint64_t Value,
" (expected an integer in the range 0 to " + std::to_string(Max) + ")";
if (Ctx) {
- Ctx->reportFatalError(Fixup.getLoc(), Diagnostic);
+ Ctx->reportError(Fixup.getLoc(), Diagnostic);
} else {
llvm_unreachable(Diagnostic.c_str());
}