[llvm] 1fedd90 - [AVR] fix interrupt stack pointer restoration
Dylan McKay via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 30 22:52:38 PDT 2020
Author: Andrew Dona-Couch
Date: 2020-10-01T18:52:13+13:00
New Revision: 1fedd90cc7a8deabf7d75d3e668bd56ce9b1ffcc
URL: https://github.com/llvm/llvm-project/commit/1fedd90cc7a8deabf7d75d3e668bd56ce9b1ffcc
DIFF: https://github.com/llvm/llvm-project/commit/1fedd90cc7a8deabf7d75d3e668bd56ce9b1ffcc.diff
LOG: [AVR] fix interrupt stack pointer restoration
This patch fixes a corruption of the stack pointer and several registers in any AVR interrupt with non-empty stack frame. Previously, the callee-saved registers were popped before restoring the stack pointer, causing the pointer math to use the wrong base value while also corrupting the caller's register. This change fixes the code to restore the stack pointer last before exiting the interrupt service routine.
https://bugs.llvm.org/show_bug.cgi?id=47253
Reviewed By: dylanmckay
Differential Revision: https://reviews.llvm.org/D87735
Patch by Andrew Dona-Couch.
Added:
Modified:
llvm/lib/Target/AVR/AVRFrameLowering.cpp
llvm/test/CodeGen/AVR/interrupts.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/AVR/AVRFrameLowering.cpp b/llvm/lib/Target/AVR/AVRFrameLowering.cpp
index c95a553b86ac..757b41466c3f 100644
--- a/llvm/lib/Target/AVR/AVRFrameLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRFrameLowering.cpp
@@ -131,6 +131,26 @@ void AVRFrameLowering::emitPrologue(MachineFunction &MF,
.setMIFlag(MachineInstr::FrameSetup);
}
+static void restoreStatusRegister(MachineFunction &MF, MachineBasicBlock &MBB) {
+ const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
+
+ MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
+
+ DebugLoc DL = MBBI->getDebugLoc();
+ 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 (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);
+ }
+}
+
void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
@@ -151,18 +171,9 @@ void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
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 (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);
- }
-
// Early exit if there is no need to restore the frame pointer.
if (!FrameSize) {
+ restoreStatusRegister(MF, MBB);
return;
}
@@ -198,6 +209,8 @@ void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
// Write back R29R28 to SP and temporarily disable interrupts.
BuildMI(MBB, MBBI, DL, TII.get(AVR::SPWRITE), AVR::SP)
.addReg(AVR::R29R28, RegState::Kill);
+
+ restoreStatusRegister(MF, MBB);
}
// Return true if the specified function should have a dedicated frame
diff --git a/llvm/test/CodeGen/AVR/interrupts.ll b/llvm/test/CodeGen/AVR/interrupts.ll
index b402d867e12b..c6550a0fb6ae 100644
--- a/llvm/test/CodeGen/AVR/interrupts.ll
+++ b/llvm/test/CodeGen/AVR/interrupts.ll
@@ -64,5 +64,40 @@ define void @signal_handler_via_attribute() #1 {
ret void
}
+define avr_intrcc void @interrupt_alloca() {
+; CHECK-LABEL: interrupt_alloca:
+; CHECK: sei
+; CHECK-NEXT: push r0
+; CHECK-NEXT: push r1
+; CHECK-NEXT: in r0, 63
+; CHECK-NEXT: push r0
+; CHECK: clr r0
+; CHECK: push r28
+; CHECK-NEXT: push r29
+; CHECK-NEXT: in r28, 61
+; CHECK-NEXT: in r29, 62
+; CHECK-NEXT: sbiw r28, 1
+; CHECK-NEXT: in r0, 63
+; CHECK-NEXT: cli
+; CHECK-NEXT: out 62, r29
+; CHECK-NEXT: out 63, r0
+; CHECK-NEXT: out 61, r28
+; CHECK: adiw r28, 1
+; CHECK-NEXT: in r0, 63
+; CHECK-NEXT: cli
+; CHECK-NEXT: out 62, r29
+; CHECK-NEXT: out 63, r0
+; CHECK-NEXT: out 61, r28
+; CHECK-NEXT: pop r29
+; CHECK-NEXT: pop r28
+; CHECK: pop r0
+; CHECK-NEXT: out 63, r0
+; CHECK-NEXT: pop r1
+; CHECK-NEXT: pop r0
+; CHECK-NEXT: reti
+ alloca i8
+ ret void
+}
+
attributes #0 = { "interrupt" }
attributes #1 = { "signal" }
More information about the llvm-commits
mailing list