Skip to content

Commit cc42863

Browse files
committed
[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.
1 parent 954d0a9 commit cc42863

File tree

5 files changed

+53
-20
lines changed

5 files changed

+53
-20
lines changed

llvm/lib/Target/AVR/AVRFrameLowering.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,11 @@ void AVRFrameLowering::emitPrologue(MachineFunction &MF,
5757
DebugLoc DL = (MBBI != MBB.end()) ? MBBI->getDebugLoc() : DebugLoc();
5858
const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>();
5959
const AVRInstrInfo &TII = *STI.getInstrInfo();
60+
const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
6061
bool HasFP = hasFP(MF);
6162

6263
// Interrupt handlers re-enable interrupts in function entry.
63-
if (CallConv == CallingConv::AVR_INTR) {
64+
if (AFI->isInterruptHandler() && CallConv != CallingConv::AVR_SIGNAL) {
6465
BuildMI(MBB, MBBI, DL, TII.get(AVR::BSETs))
6566
.addImm(0x07)
6667
.setMIFlag(MachineInstr::FrameSetup);
@@ -75,8 +76,7 @@ void AVRFrameLowering::emitPrologue(MachineFunction &MF,
7576

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

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

106105
// Skip the callee-saved push instructions.
@@ -143,13 +142,11 @@ void AVRFrameLowering::emitPrologue(MachineFunction &MF,
143142

144143
void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
145144
MachineBasicBlock &MBB) const {
146-
CallingConv::ID CallConv = MF.getFunction().getCallingConv();
147-
bool isHandler = (CallConv == CallingConv::AVR_INTR ||
148-
CallConv == CallingConv::AVR_SIGNAL);
145+
const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
149146

150147
// Early exit if the frame pointer is not needed in this function except for
151148
// signal/interrupt handlers where special code generation is required.
152-
if (!hasFP(MF) && !isHandler) {
149+
if (!hasFP(MF) && !AFI->isInterruptHandler()) {
153150
return;
154151
}
155152

@@ -159,14 +156,13 @@ void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
159156

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

167163
// Emit special epilogue code to restore R1, R0 and SREG in interrupt/signal
168164
// handlers at the very end of the function, just before reti.
169-
if (isHandler) {
165+
if (AFI->isInterruptHandler()) {
170166
BuildMI(MBB, MBBI, DL, TII.get(AVR::POPRd), AVR::R0);
171167
BuildMI(MBB, MBBI, DL, TII.get(AVR::OUTARr))
172168
.addImm(0x3f)

llvm/lib/Target/AVR/AVRISelLowering.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,10 +1415,12 @@ AVRTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
14151415
return Chain;
14161416
}
14171417

1418+
const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
1419+
14181420
unsigned RetOpc =
1419-
(CallConv == CallingConv::AVR_INTR || CallConv == CallingConv::AVR_SIGNAL)
1420-
? AVRISD::RETI_FLAG
1421-
: AVRISD::RET_FLAG;
1421+
AFI->isInterruptHandler()
1422+
? AVRISD::RETI_FLAG
1423+
: AVRISD::RET_FLAG;
14221424

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

llvm/lib/Target/AVR/AVRMachineFunctionInfo.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class AVRMachineFunctionInfo : public MachineFunctionInfo {
3131
/// used inside the function.
3232
bool HasStackArgs;
3333

34+
/// Whether or not the function is an interrupt handler.
35+
bool IsInterruptHandler;
36+
3437
/// Size of the callee-saved register portion of the
3538
/// stack frame in bytes.
3639
unsigned CalleeSavedFrameSize;
@@ -41,11 +44,19 @@ class AVRMachineFunctionInfo : public MachineFunctionInfo {
4144
public:
4245
AVRMachineFunctionInfo()
4346
: HasSpills(false), HasAllocas(false), HasStackArgs(false),
44-
CalleeSavedFrameSize(0), VarArgsFrameIndex(0) {}
47+
IsInterruptHandler(false), CalleeSavedFrameSize(0),
48+
VarArgsFrameIndex(0) {}
4549

4650
explicit AVRMachineFunctionInfo(MachineFunction &MF)
4751
: HasSpills(false), HasAllocas(false), HasStackArgs(false),
48-
CalleeSavedFrameSize(0), VarArgsFrameIndex(0) {}
52+
CalleeSavedFrameSize(0), VarArgsFrameIndex(0) {
53+
unsigned CallConv = MF.getFunction().getCallingConv();
54+
55+
this->IsInterruptHandler =
56+
CallConv == CallingConv::AVR_INTR ||
57+
CallConv == CallingConv::AVR_SIGNAL ||
58+
MF.getFunction().hasFnAttribute("interrupt");
59+
}
4960

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

70+
bool isInterruptHandler() const { return IsInterruptHandler; }
71+
5972
unsigned getCalleeSavedFrameSize() const { return CalleeSavedFrameSize; }
6073
void setCalleeSavedFrameSize(unsigned Bytes) { CalleeSavedFrameSize = Bytes; }
6174

llvm/lib/Target/AVR/AVRRegisterInfo.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include "AVR.h"
2424
#include "AVRInstrInfo.h"
25+
#include "AVRMachineFunctionInfo.h"
2526
#include "AVRTargetMachine.h"
2627
#include "MCTargetDesc/AVRMCTargetDesc.h"
2728

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

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

39-
return ((CC == CallingConv::AVR_INTR || CC == CallingConv::AVR_SIGNAL)
40+
return AFI->isInterruptHandler()
4041
? CSR_Interrupts_SaveList
41-
: CSR_Normal_SaveList);
42+
: CSR_Normal_SaveList;
4243
}
4344

4445
const uint32_t *
4546
AVRRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
4647
CallingConv::ID CC) const {
47-
return ((CC == CallingConv::AVR_INTR || CC == CallingConv::AVR_SIGNAL)
48+
const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
49+
50+
return AFI->isInterruptHandler()
4851
? CSR_Interrupts_RegMask
49-
: CSR_Normal_RegMask);
52+
: CSR_Normal_RegMask;
5053
}
5154

5255
BitVector AVRRegisterInfo::getReservedRegs(const MachineFunction &MF) const {

llvm/test/CodeGen/AVR/interrupts.ll

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,22 @@ define avr_intrcc void @interrupt_handler() {
1616
ret void
1717
}
1818

19+
define void @interrupt_handler_via_ir_attribute() #0 {
20+
; CHECK-LABEL: interrupt_handler_via_ir_attribute:
21+
; CHECK: sei
22+
; CHECK-NEXT: push r0
23+
; CHECK-NEXT: push r1
24+
; CHECK-NEXT: in r0, 63
25+
; CHECK-NEXT: push r0
26+
; CHECK: clr r0
27+
; CHECK: pop r0
28+
; CHECK-NEXT: out 63, r0
29+
; CHECK-NEXT: pop r1
30+
; CHECK-NEXT: pop r0
31+
; CHECK-NEXT: reti
32+
ret void
33+
}
34+
1935
define avr_signalcc void @signal_handler() {
2036
; CHECK-LABEL: signal_handler:
2137
; CHECK-NOT: sei
@@ -31,3 +47,6 @@ define avr_signalcc void @signal_handler() {
3147
; CHECK-NEXT: reti
3248
ret void
3349
}
50+
51+
attributes #0 = { "interrupt" }
52+
attributes #1 = { "signal" }

0 commit comments

Comments
 (0)