8000 [AVR] Cherry-pick 17 upstream AVR backend fixes into the Rust LLVM fork by dylanmckay · Pull Request #66 · rust-lang/llvm-project · GitHub
[go: up one dir, main page]

Skip to content

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

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
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
[AVR] Respect the 'interrupt' function attribute
In the past, AVR functions were only lowered with interrupt-specific
machine code if the function was defined with the "avr-interrupt" or
"avr-signal" calling conventions.

This patch modifies the backend so that if the function does not have a
special calling convention, but does have an "interrupt" attribute,
that function is interpreted as a function with interrupts.

This also extracts the "is this function an interrupt" logic from
several disparate places in the backend into one AVRMachineFunctionInfo
attribute.

Bug found by Wilhelm Meier.
  • Loading branch information
dylanmckay committed Jun 23, 2020
commit cc4286349b4673e436fc30e1287f475fcb56104a
16 changes: 6 additions & 10 deletions llvm/lib/Target/AVR/AVRFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@ 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() && CallConv != CallingConv::AVR_SIGNAL) {
BuildMI(MBB, MBBI, DL, TII.get(AVR::BSETs))
.addImm(0x07)
.setMIFlag(MachineInstr::FrameSetup);
Expand All @@ -75,8 +76,7 @@ void AVRFrameLowering::emitPrologue(MachineFunction &MF,

// 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->isInterruptHandler()) {
BuildMI(MBB, MBBI, DL, TII.get(AVR::PUSHWRr))
.addReg(AVR::R1R0, RegState::Kill)
.setMIFlag(MachineInstr::FrameSetup);
Expand All @@ -100,7 +100,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 +142,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->isInterruptHandler()) {
return;
}

Expand All @@ -159,14 +156,13 @@ 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->isInterruptHandler()) {
BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), AVR::R0);
BuildMI(MBB, MBBI, DL, TII.get(AVR::OUTARr))
.addImm(0x3f)
Expand Down
8 changes: 5 additions & 3 deletions llvm/lib/Target/AVR/AVRISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1415,10 +1415,12 @@ AVRTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
return Chain;
}

const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();

unsigned RetOpc =
(CallConv == CallingConv::AVR_INTR || CallConv == CallingConv::AVR_SIGNAL)
? AVRISD::RETI_FLAG
: AVRISD::RET_FLAG;
AFI->isInterruptHandler()
? AVRISD::RETI_FLAG
: AVRISD::RET_FLAG;

RetOps[0] = Chain; // Update chain.

Expand Down
17 changes: 15 additions & 2 deletions llvm/lib/Target/AVR/AVRMachineFunctionInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class AVRMachineFunctionInfo : public MachineFunctionInfo {
/// used inside the function.
bool HasStackArgs;

/// Whether or not the function is an interrupt handler.
bool IsInterruptHandler;

/// Size of the callee-saved register portion of the
/// stack frame in bytes.
unsigned CalleeSavedFrameSize;
Expand All @@ -41,11 +44,19 @@ class AVRMachineFunctionInfo : public MachineFunctionInfo {
public:
AVRMachineFunctionInfo()
: HasSpills(false), HasAllocas(false), HasStackArgs(false),
CalleeSavedFrameSize(0), VarArgsFrameIndex(0) {}
IsInterruptHandler(false), CalleeSavedFrameSize(0),
VarArgsFrameIndex(0) {}

explicit AVRMachineFunctionInfo(MachineFunction &MF)
: HasSpills(false), HasAllocas(false), HasStackArgs(false),
CalleeSavedFrameSize(0), VarArgsFrameIndex(0) {}
CalleeSavedFrameSize(0), VarArgsFrameIndex(0) {
unsigned CallConv = MF.getFunction().getCallingConv();

this->IsInterruptHandler =
CallConv == CallingConv::AVR_INTR ||
CallConv == CallingConv::AVR_SIGNAL ||
MF.getFunction().hasFnAttribute("interrupt");
}

bool getHasSpills() const { return HasSpills; }
void setHasSpills(bool B) { HasSpills = B; }
Expand All @@ -56,6 +67,8 @@ class AVRMachineFunctionInfo : public MachineFunctionInfo {
bool getHasStackArgs() const { return HasStackArgs; }
void setHasStackArgs(bool B) { HasStackArgs = B; }

bool isInterruptHandler() const { return IsInterruptHandler; }

unsigned getCalleeSavedFrameSize() const { return CalleeSavedFrameSize; }
void setCalleeSavedFrameSize(unsigned Bytes) { CalleeSavedFrameSize = Bytes; }

Expand Down
13 changes: 8 additions & 5 deletions llvm/lib/Target/AVR/AVRRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "AVR.h"
#include "AVRInstrInfo.h"
#include "AVRMachineFunctionInfo.h"
#include "AVRTargetMachine.h"
#include "MCTargetDesc/AVRMCTargetDesc.h"

Expand All @@ -34,19 +35,21 @@ AVRRegisterInfo::AVRRegisterInfo() : AVRGenRegisterInfo(0) {}

const uint16_t *
AVRRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
CallingConv::ID CC = MF->getFunction().getCallingConv();
const AVRMachineFunctionInfo *AFI = MF->getInfo<AVRMachineFunctionInfo>();

return ((CC == CallingConv::AVR_INTR || CC == CallingConv::AVR_SIGNAL)
return AFI->isInterruptHandler()
? CSR_Interrupts_SaveList
: CSR_Normal_SaveList);
: CSR_Normal_SaveList;
}

const uint32_t *
AVRRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
CallingConv::ID CC) const {
return ((CC == CallingConv::AVR_INTR || CC == CallingConv::AVR_SIGNAL)
const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();

return AFI->isInterruptHandler()
? CSR_Interrupts_RegMask
: CSR_Normal_RegMask);
: CSR_Normal_RegMask;
}

BitVector AVRRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
Expand Down
19 changes: 19 additions & 0 deletions llvm/test/CodeGen/AVR/interrupts.ll
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@ define avr_intrcc void @interrupt_handler() {
ret void
}

define void @interrupt_handler_via_ir_attribute() #0 {
; CHECK-LABEL: interrupt_handler_via_ir_attribute:
; CHECK: sei
; CHECK-NEXT: push r0
; CHECK-NEXT: push r1
; CHECK-NEXT: in r0, 63
; CHECK-NEXT: push r0
; CHECK: clr r0
; CHECK: pop r0
; CHECK-NEXT: out 63, r0
; CHECK-NEXT: pop r1
; CHECK-NEXT: pop r0
; CHECK-NEXT: reti
ret void
}

define avr_signalcc void @signal_handler() {
; CHECK-LABEL: signal_handler:
; CHECK-NOT: sei
Expand All @@ -31,3 +47,6 @@ define avr_signalcc void @signal_handler() {
; CHECK-NEXT: reti
ret void
}

attributes #0 = { "interrupt" }
attributes #1 = { "signal" }
0