Skip to content

Commit

Permalink
Merge pull request #66 from dylanmckay/avr-pick-upstream-llvm-fixes
Browse files Browse the repository at this point in the history
[AVR] Cherry-pick 17 upstream AVR backend fixes into the Rust LLVM fork
  • Loading branch information
nikic authored Jun 23, 2020
2 parents 0ddefec + 12dfdd3 commit 6c040dd
Show file tree
Hide file tree
Showing 36 changed files with 1,868 additions and 419 deletions.
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

0 comments on commit 6c040dd

Please sign in to comment.