Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AVR] Cherry-pick 17 upstream AVR backend fixes into the Rust LLVM fork #66

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 1 addition & 17 deletions llvm/lib/Target/AVR/AVRCallingConv.td
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,13 @@
//
//===----------------------------------------------------------------------===//
// This describes the calling conventions for AVR architecture.
// Normal functions use a special calling convention, solved in code.
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// AVR Return Value Calling Convention
//===----------------------------------------------------------------------===//

def RetCC_AVR : CallingConv
<[
// i8 is returned in R24.
CCIfType<[i8], CCAssignToReg<[R24]>>,

// i16 are returned in R25:R24, R23:R22, R21:R20 and R19:R18.
CCIfType<[i16], CCAssignToReg<[R25R24, R23R22, R21R20, R19R18]>>
]>;

// Special return value calling convention for runtime functions.
def RetCC_AVR_BUILTIN : CallingConv
<[
Expand All @@ -41,14 +33,6 @@ def ArgCC_AVR_Vararg : CallingConv
CCAssignToStack<2, 1>
]>;

// Special argument calling convention for
// division runtime functions.
def ArgCC_AVR_BUILTIN_DIV : CallingConv
<[
CCIfType<[i8], CCAssignToReg<[R24,R22]>>,
CCIfType<[i16], CCAssignToReg<[R25R24, R23R22]>>
]>;

//===----------------------------------------------------------------------===//
// Callee-saved register lists.
//===----------------------------------------------------------------------===//
Expand Down
18 changes: 13 additions & 5 deletions llvm/lib/Target/AVR/AVRDevices.td
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ def FeatureTinyEncoding : SubtargetFeature<"tinyencoding",
"The device has Tiny core specific "
"instruction encodings">;

// The device has CPU registers mapped in data address space
def FeatureMMR : SubtargetFeature<"memmappedregs", "m_hasMemMappedGPR",
"true", "The device has CPU registers "
"mapped in data address space">;

class ELFArch<string name> : SubtargetFeature<"", "ELFArch",
!strconcat("ELF::",name), "">;

Expand Down Expand Up @@ -152,7 +157,7 @@ def ELFArchXMEGA7 : ELFArch<"EF_AVR_ARCH_XMEGA7">;
// device should have.
def FamilyAVR0 : Family<"avr0", []>;

def FamilyAVR1 : Family<"avr1", [FamilyAVR0, FeatureLPM]>;
def FamilyAVR1 : Family<"avr1", [FamilyAVR0, FeatureLPM, FeatureMMR]>;

def FamilyAVR2 : Family<"avr2",
[FamilyAVR1, FeatureIJMPCALL, FeatureADDSUBIW,
Expand Down Expand Up @@ -190,11 +195,14 @@ def FamilyAVR6 : Family<"avr6",

def FamilyTiny : Family<"avrtiny",
[FamilyAVR0, FeatureBREAK, FeatureSRAM,
FeatureTinyEncoding]>;
FeatureTinyEncoding, FeatureMMR]>;

def FamilyXMEGA : Family<"xmega",
[FamilyAVR51, FeatureEIJMPCALL, FeatureSPMX,
FeatureDES]>;
[FamilyAVR0, FeatureLPM, FeatureIJMPCALL, FeatureADDSUBIW,
FeatureSRAM, FeatureJMPCALL, FeatureMultiplication,
FeatureMOVW, FeatureLPMX, FeatureSPM,
FeatureBREAK, FeatureEIJMPCALL, FeatureSPMX,
FeatureDES, FeatureELPM, FeatureELPMX]>;

def FamilyXMEGAU : Family<"xmegau",
[FamilyXMEGA, FeatureRMW]>;
Expand All @@ -208,7 +216,7 @@ def FeatureSetSpecial : FeatureSet<"special",
FeatureLPM, FeatureLPMX, FeatureELPM,
FeatureELPMX, FeatureSPM, FeatureSPMX,
FeatureDES, FeatureRMW,
FeatureMultiplication, FeatureBREAK]>;
FeatureMultiplication, FeatureBREAK, FeatureMMR]>;

//===---------------------------------------------------------------------===//
// AVR microcontrollers supported.
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,8 +597,8 @@ bool AVRExpandPseudo::expand<AVR::LDWRdPtr>(Block &MBB, BlockIt MBBI) {

// Load low byte.
auto MIBLO = buildMI(MBB, MBBI, OpLo)
.addReg(CurDstLoReg, RegState::Define)
.addReg(SrcReg, RegState::Define);
.addReg(CurDstLoReg, RegState::Define)
.addReg(SrcReg);

// Push low byte onto stack if necessary.
if (TmpReg)
Expand Down
97 changes: 38 additions & 59 deletions llvm/lib/Target/AVR/AVRFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,19 @@ void AVRFrameLowering::emitPrologue(MachineFunction &MF,
DebugLoc DL = (MBBI != MBB.end()) ? MBBI->getDebugLoc() : DebugLoc();
const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
const AVRInstrInfo &TII = *STI.getInstrInfo();
const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
bool HasFP = hasFP(MF);

// Interrupt handlers re-enable interrupts in function entry.
if (CallConv == CallingConv::AVR_INTR) {
if (AFI->isInterruptHandler()) {
BuildMI(MBB, MBBI, DL, TII.get(AVR::BSETs))
.addImm(0x07)
.setMIFlag(MachineInstr::FrameSetup);
}

// Save the frame pointer if we have one.
if (HasFP) {
BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHWRr))
.addReg(AVR::R29R28, RegState::Kill)
.setMIFlag(MachineInstr::FrameSetup);
}

// Emit special prologue code to save R1, R0 and SREG in interrupt/signal
// handlers before saving any other registers.
if (CallConv == CallingConv::AVR_INTR ||
CallConv == CallingConv::AVR_SIGNAL) {
if (AFI->isInterruptOrSignalHandler()) {
BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHWRr))
.addReg(AVR::R1R0, RegState::Kill)
.setMIFlag(MachineInstr::FrameSetup);
Expand All @@ -100,7 +93,6 @@ void AVRFrameLowering::emitPrologue(MachineFunction &MF,
}

const MachineFrameInfo &MFI = MF.getFrameInfo();
const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
unsigned FrameSize = MFI.getStackSize() - AFI->getCalleeSavedFrameSize();

// Skip the callee-saved push instructions.
Expand Down Expand Up @@ -143,13 +135,11 @@ void AVRFrameLowering::emitPrologue(MachineFunction &MF,

void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
CallingConv::ID CallConv = MF.getFunction().getCallingConv();
bool isHandler = (CallConv == CallingConv::AVR_INTR ||
CallConv == CallingConv::AVR_SIGNAL);
const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();

// Early exit if the frame pointer is not needed in this function except for
// signal/interrupt handlers where special code generation is required.
if (!hasFP(MF) && !isHandler) {
if (!hasFP(MF) && !AFI->isInterruptOrSignalHandler()) {
return;
}

Expand All @@ -159,24 +149,20 @@ void AVRFrameLowering::emitEpilogue(MachineFunction &MF,

DebugLoc DL = MBBI->getDebugLoc();
const MachineFrameInfo &MFI = MF.getFrameInfo();
const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
unsigned FrameSize = MFI.getStackSize() - AFI->getCalleeSavedFrameSize();
const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
const AVRInstrInfo &TII = *STI.getInstrInfo();

// 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 (isHandler) {
if (AFI->isInterruptOrSignalHandler()) {
BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), AVR::R0);
BuildMI(MBB, MBBI, DL, TII.get(AVR::OUTARr))
.addImm(0x3f)
.addReg(AVR::R0, RegState::Kill);
BuildMI(MBB, MBBI, DL, TII.get(AVR::POPWRd), AVR::R1R0);
}

if (hasFP(MF))
BuildMI(MBB, MBBI, DL, TII.get(AVR::POPWRd), AVR::R29R28);

// Early exit if there is no need to restore the frame pointer.
if (!FrameSize) {
return;
Expand Down Expand Up @@ -299,15 +285,10 @@ bool AVRFrameLowering::restoreCalleeSavedRegisters(
}

/// Replace pseudo store instructions that pass arguments through the stack with
/// real instructions. If insertPushes is true then all instructions are
/// replaced with push instructions, otherwise regular std instructions are
/// inserted.
/// real instructions.
static void fixStackStores(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const TargetInstrInfo &TII, bool insertPushes) {
const AVRSubtarget &STI = MBB.getParent()->getSubtarget<AVRSubtarget>();
const TargetRegisterInfo &TRI = *STI.getRegisterInfo();

const TargetInstrInfo &TII, Register FP) {
// Iterate through the BB until we hit a call instruction or we reach the end.
for (auto I = MI, E = MBB.end(); I != E && !I->isCall();) {
MachineBasicBlock::iterator NextMI = std::next(I);
Expand All @@ -322,37 +303,14 @@ static void fixStackStores(MachineBasicBlock &MBB,

assert(MI.getOperand(0).getReg() == AVR::SP &&
"Invalid register, should be SP!");
if (insertPushes) {
// Replace this instruction with a push.
Register SrcReg = MI.getOperand(2).getReg();
bool SrcIsKill = MI.getOperand(2).isKill();

// We can't use PUSHWRr here because when expanded the order of the new
// instructions are reversed from what we need. Perform the expansion now.
if (Opcode == AVR::STDWSPQRr) {
BuildMI(MBB, I, MI.getDebugLoc(), TII.get(AVR::PUSHRr))
.addReg(TRI.getSubReg(SrcReg, AVR::sub_hi),
getKillRegState(SrcIsKill));
BuildMI(MBB, I, MI.getDebugLoc(), TII.get(AVR::PUSHRr))
.addReg(TRI.getSubReg(SrcReg, AVR::sub_lo),
getKillRegState(SrcIsKill));
} else {
BuildMI(MBB, I, MI.getDebugLoc(), TII.get(AVR::PUSHRr))
.addReg(SrcReg, getKillRegState(SrcIsKill));
}

MI.eraseFromParent();
I = NextMI;
continue;
}

// Replace this instruction with a regular store. Use Y as the base
// pointer since it is guaranteed to contain a copy of SP.
unsigned STOpc =
(Opcode == AVR::STDWSPQRr) ? AVR::STDWPtrQRr : AVR::STDPtrQRr;

MI.setDesc(TII.get(STOpc));
MI.getOperand(0).setReg(AVR::R29R28);
MI.getOperand(0).setReg(FP);

I = NextMI;
}
Expand All @@ -368,26 +326,45 @@ MachineBasicBlock::iterator AVRFrameLowering::eliminateCallFramePseudoInstr(
// function entry. Delete the call frame pseudo and replace all pseudo stores
// with real store instructions.
if (hasReservedCallFrame(MF)) {
fixStackStores(MBB, MI, TII, false);
fixStackStores(MBB, MI, TII, AVR::R29R28);
return MBB.erase(MI);
}

DebugLoc DL = MI->getDebugLoc();
unsigned int Opcode = MI->getOpcode();
int Amount = TII.getFrameSize(*MI);

// Adjcallstackup does not need to allocate stack space for the call, instead
// we insert push instructions that will allocate the necessary stack.
// For adjcallstackdown we convert it into an 'adiw reg, <amt>' handling
// the read and write of SP in I/O space.
// ADJCALLSTACKUP and ADJCALLSTACKDOWN are converted to adiw/subi
// instructions to read and write the stack pointer in I/O space.
if (Amount != 0) {
assert(getStackAlignment() == 1 && "Unsupported stack alignment");

if (Opcode == TII.getCallFrameSetupOpcode()) {
fixStackStores(MBB, MI, TII, true);
// Update the stack pointer.
// In many cases this can be done far more efficiently by pushing the
// relevant values directly to the stack. However, doing that correctly
// (in the right order, possibly skipping some empty space for undef
// values, etc) is tricky and thus left to be optimized in the future.
BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);

MachineInstr *New = BuildMI(MBB, MI, DL, TII.get(AVR::SUBIWRdK), AVR::R31R30)
.addReg(AVR::R31R30, RegState::Kill)
.addImm(Amount);
New->getOperand(3).setIsDead();

BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP)
.addReg(AVR::R31R30, RegState::Kill);

// Make sure the remaining stack stores are converted to real store
// instructions.
fixStackStores(MBB, MI, TII, AVR::R31R30);
} else {
assert(Opcode == TII.getCallFrameDestroyOpcode());

// Note that small stack changes could be implemented more efficiently
// with a few pop instructions instead of the 8-9 instructions now
// required.

// Select the best opcode to adjust SP based on the offset size.
unsigned addOpcode;
if (isUInt<6>(Amount)) {
Expand Down Expand Up @@ -419,8 +396,10 @@ void AVRFrameLowering::determineCalleeSaves(MachineFunction &MF,
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS);

// If we have a frame pointer, the Y register needs to be saved as well.
// We don't do that here however - the prologue and epilogue generation
// code will handle it specially.
if (hasFP(MF)) {
SavedRegs.set(AVR::R29);
SavedRegs.set(AVR::R28);
}
}
/// The frame analyzer pass.
///
Expand Down
Loading