Skip to content

rustc + avr = lovelove back again #139

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

Merged
merged 2 commits into from
May 8, 2022
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
1 change: 0 additions & 1 deletion clang/docs/tools/clang-formatted-files.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5990,7 +5990,6 @@ llvm/lib/Target/AVR/AVRMCInstLower.cpp
llvm/lib/Target/AVR/AVRMCInstLower.h
llvm/lib/Target/AVR/AVRRegisterInfo.cpp
llvm/lib/Target/AVR/AVRRegisterInfo.h
llvm/lib/Target/AVR/AVRRelaxMemOperations.cpp
llvm/lib/Target/AVR/AVRSelectionDAGInfo.h
llvm/lib/Target/AVR/AVRShiftExpand.cpp
llvm/lib/Target/AVR/AVRSubtarget.cpp
Expand Down
2 changes: 0 additions & 2 deletions llvm/lib/Target/AVR/AVR.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ FunctionPass *createAVRISelDag(AVRTargetMachine &TM,
CodeGenOpt::Level OptLevel);
FunctionPass *createAVRExpandPseudoPass();
FunctionPass *createAVRFrameAnalyzerPass();
FunctionPass *createAVRRelaxMemPass();
FunctionPass *createAVRBranchSelectionPass();

void initializeAVRShiftExpandPass(PassRegistry &);
void initializeAVRExpandPseudoPass(PassRegistry &);
void initializeAVRRelaxMemPass(PassRegistry &);

/// Contains the AVR backend.
namespace AVR {
Expand Down
95 changes: 76 additions & 19 deletions llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1230,37 +1230,92 @@ bool AVRExpandPseudo::expand<AVR::STWPtrPdRr>(Block &MBB, BlockIt MBBI) {
template <>
bool AVRExpandPseudo::expand<AVR::STDWPtrQRr>(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Register SrcLoReg, SrcHiReg;

Register DstReg = MI.getOperand(0).getReg();
Register SrcReg = MI.getOperand(2).getReg();
unsigned Imm = MI.getOperand(1).getImm();
bool DstIsKill = MI.getOperand(0).isKill();
unsigned Imm = MI.getOperand(1).getImm();
Register SrcReg = MI.getOperand(2).getReg();
bool SrcIsKill = MI.getOperand(2).isKill();
unsigned OpLo = AVR::STDPtrQRr;
unsigned OpHi = AVR::STDPtrQRr;
TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);

// Since we add 1 to the Imm value for the high byte below, and 63 is the
// highest Imm value allowed for the instruction, 62 is the limit here.
assert(Imm <= 62 && "Offset is out of range");
// STD's maximum displacement is 63, so larger stores have to be split into a
// set of operations
if (Imm >= 63) {
if (!DstIsKill) {
buildMI(MBB, MBBI, AVR::PUSHWRr).addReg(DstReg);
}

auto MIBLO = buildMI(MBB, MBBI, OpLo)
.addReg(DstReg)
.addImm(Imm)
.addReg(SrcLoReg, getKillRegState(SrcIsKill));
buildMI(MBB, MBBI, AVR::SUBIWRdK)
.addReg(DstReg, RegState::Define)
.addReg(DstReg, RegState::Kill)
.addImm(-Imm);

auto MIBHI = buildMI(MBB, MBBI, OpHi)
.addReg(DstReg, getKillRegState(DstIsKill))
.addImm(Imm + 1)
.addReg(SrcHiReg, getKillRegState(SrcIsKill));
buildMI(MBB, MBBI, AVR::STWPtrRr)
.addReg(DstReg, RegState::Kill)
.addReg(SrcReg, getKillRegState(SrcIsKill));

MIBLO.setMemRefs(MI.memoperands());
MIBHI.setMemRefs(MI.memoperands());
if (!DstIsKill) {
buildMI(MBB, MBBI, AVR::POPWRd).addDef(DstReg, RegState::Define);
}
} else {
unsigned OpLo = AVR::STDPtrQRr;
unsigned OpHi = AVR::STDPtrQRr;
Register SrcLoReg, SrcHiReg;
TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);

auto MIBLO = buildMI(MBB, MBBI, OpLo)
.addReg(DstReg)
.addImm(Imm)
.addReg(SrcLoReg, getKillRegState(SrcIsKill));

auto MIBHI = buildMI(MBB, MBBI, OpHi)
.addReg(DstReg, getKillRegState(DstIsKill))
.addImm(Imm + 1)
.addReg(SrcHiReg, getKillRegState(SrcIsKill));

MIBLO.setMemRefs(MI.memoperands());
MIBHI.setMemRefs(MI.memoperands());
}

MI.eraseFromParent();
return true;
}

template <>
bool AVRExpandPseudo::expand<AVR::STDSPQRr>(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
const MachineFunction &MF = *MBB.getParent();
const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();

assert(MI.getOperand(0).getReg() == AVR::SP &&
"SP is expected as base pointer");

assert(STI.getFrameLowering()->hasReservedCallFrame(MF) &&
"unexpected STDSPQRr pseudo instruction");

MI.setDesc(TII->get(AVR::STDPtrQRr));
MI.getOperand(0).setReg(AVR::R29R28);

return true;
}

template <>
bool AVRExpandPseudo::expand<AVR::STDWSPQRr>(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
const MachineFunction &MF = *MBB.getParent();
const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();

assert(MI.getOperand(0).getReg() == AVR::SP &&
"SP is expected as base pointer");

assert(STI.getFrameLowering()->hasReservedCallFrame(MF) &&
"unexpected STDWSPQRr pseudo instruction");

MI.setDesc(TII->get(AVR::STDWPtrQRr));
MI.getOperand(0).setReg(AVR::R29R28);

return true;
}

template <>
bool AVRExpandPseudo::expand<AVR::INWRdA>(Block &MBB, BlockIt MBBI) {
MachineInstr &MI = *MBBI;
Expand Down Expand Up @@ -2346,6 +2401,8 @@ bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
EXPAND(AVR::STWPtrPiRr);
EXPAND(AVR::STWPtrPdRr);
EXPAND(AVR::STDWPtrQRr);
EXPAND(AVR::STDSPQRr);
EXPAND(AVR::STDWSPQRr);
EXPAND(AVR::INWRdA);
EXPAND(AVR::OUTWARr);
EXPAND(AVR::PUSHWRr);
Expand Down
115 changes: 56 additions & 59 deletions llvm/lib/Target/AVR/AVRFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ void AVRFrameLowering::emitEpilogue(MachineFunction &MF,

// 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);
.addReg(AVR::R29R28, RegState::Kill)
.addImm(FrameSize);
// The SREG implicit def is dead.
MI->getOperand(3).setIsDead();
}
Expand Down Expand Up @@ -299,7 +299,7 @@ bool AVRFrameLowering::restoreCalleeSavedRegisters(
/// real instructions.
static void fixStackStores(MachineBasicBlock &MBB,
MachineBasicBlock::iterator StartMI,
const TargetInstrInfo &TII, Register FP) {
const TargetInstrInfo &TII) {
// Iterate through the BB until we hit a call instruction or we reach the end.
for (MachineInstr &MI :
llvm::make_early_inc_range(llvm::make_range(StartMI, MBB.end()))) {
Expand All @@ -313,15 +313,15 @@ static void fixStackStores(MachineBasicBlock &MBB,
continue;

assert(MI.getOperand(0).getReg() == AVR::SP &&
"Invalid register, should be SP!");
"SP is expected as base pointer");

// 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(FP);
MI.getOperand(0).setReg(AVR::R31R30);
}
}

Expand All @@ -331,69 +331,66 @@ MachineBasicBlock::iterator AVRFrameLowering::eliminateCallFramePseudoInstr(
const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
const AVRInstrInfo &TII = *STI.getInstrInfo();

// There is nothing to insert when the call frame memory is allocated during
// function entry. Delete the call frame pseudo and replace all pseudo stores
// with real store instructions.
if (hasReservedCallFrame(MF)) {
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 and ADJCALLSTACKDOWN are converted to adiw/subi
// instructions to read and write the stack pointer in I/O space.
if (Amount != 0) {
assert(getStackAlign() == Align(1) && "Unsupported stack alignment");

if (Opcode == TII.getCallFrameSetupOpcode()) {
// 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);

// 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)) {
addOpcode = AVR::ADIWRdK;
} else {
addOpcode = AVR::SUBIWRdK;
Amount = -Amount;
}
if (Amount == 0) {
return MBB.erase(MI);
}

assert(getStackAlign() == Align(1) && "Unsupported stack alignment");

if (Opcode == TII.getCallFrameSetupOpcode()) {
// 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();

// Build the instruction sequence.
BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);
BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP).addReg(AVR::R31R30);

MachineInstr *New = BuildMI(MBB, MI, DL, TII.get(addOpcode), AVR::R31R30)
.addReg(AVR::R31R30, RegState::Kill)
.addImm(Amount);
New->getOperand(3).setIsDead();
// Make sure the remaining stack stores are converted to real store
// instructions.
fixStackStores(MBB, MI, TII);
} else {
assert(Opcode == TII.getCallFrameDestroyOpcode());

BuildMI(MBB, MI, DL, TII.get(AVR::SPWRITE), AVR::SP)
.addReg(AVR::R31R30, RegState::Kill);
// 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)) {
AddOpcode = AVR::ADIWRdK;
} else {
AddOpcode = AVR::SUBIWRdK;
Amount = -Amount;
}

// Build the instruction sequence.
BuildMI(MBB, MI, DL, TII.get(AVR::SPREAD), AVR::R31R30).addReg(AVR::SP);

MachineInstr *New = BuildMI(MBB, MI, DL, TII.get(AddOpcode), 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);
}

return MBB.erase(MI);
Expand All @@ -420,7 +417,7 @@ struct AVRFrameAnalyzer : public MachineFunctionPass {

bool runOnMachineFunction(MachineFunction &MF) override {
const MachineFrameInfo &MFI = MF.getFrameInfo();
AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();
AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();

// If there are no fixed frame indexes during this stage it means there
// are allocas present in the function.
Expand All @@ -431,7 +428,7 @@ struct AVRFrameAnalyzer : public MachineFunctionPass {
for (unsigned i = 0, e = MFI.getObjectIndexEnd(); i != e; ++i) {
// Variable sized objects have size 0.
if (MFI.getObjectSize(i)) {
FuncInfo->setHasAllocas(true);
AFI->setHasAllocas(true);
break;
}
}
Expand Down Expand Up @@ -460,7 +457,7 @@ struct AVRFrameAnalyzer : public MachineFunctionPass {
}

if (MFI.isFixedObjectIndex(MO.getIndex())) {
FuncInfo->setHasStackArgs(true);
AFI->setHasStackArgs(true);
return false;
}
}
Expand Down
Loading