[llvm] 3d59d94 - [AVR] Mark call-clobbered registers as clobbered in interrupt handlers

Ayke van Laethem via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 19 05:22:24 PST 2022


Author: Ayke van Laethem
Date: 2022-01-19T14:22:13+01:00
New Revision: 3d59d94a206a840d780c8f34610977734095149a

URL: https://github.com/llvm/llvm-project/commit/3d59d94a206a840d780c8f34610977734095149a
DIFF: https://github.com/llvm/llvm-project/commit/3d59d94a206a840d780c8f34610977734095149a.diff

LOG: [AVR] Mark call-clobbered registers as clobbered in interrupt handlers

I have matched the RISCV backend, which only uses the interrupt save
list in getCalleeSavedRegs, _not_ in getCallPreservedMask. I don't know
the details of these two methods, but with it, the correct amount of
registers is saved and restored.

Without this patch, practically all interrupt handlers that call a
function will miscompile.

I have added a test to verify this behavior. I've also added a very
simple test to verify that more normal interrupt operations (in this
case, incrementing a global value) behave as expected.

Differential Revision: https://reviews.llvm.org/D116551

Added: 
    

Modified: 
    llvm/lib/Target/AVR/AVRCallingConv.td
    llvm/lib/Target/AVR/AVRRegisterInfo.cpp
    llvm/test/CodeGen/AVR/interrupts.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AVR/AVRCallingConv.td b/llvm/lib/Target/AVR/AVRCallingConv.td
index 87874c5c50b2..b4bc35e191c0 100644
--- a/llvm/lib/Target/AVR/AVRCallingConv.td
+++ b/llvm/lib/Target/AVR/AVRCallingConv.td
@@ -36,4 +36,4 @@ def ArgCC_AVR_Vararg : CallingConv<[
 //===----------------------------------------------------------------------===//
 
 def CSR_Normal : CalleeSavedRegs<(add R29, R28, (sequence "R%u", 17, 2))>;
-def CSR_Interrupts : CalleeSavedRegs<(add(sequence "R%u", 31, 0))>;
+def CSR_Interrupts : CalleeSavedRegs<(add(sequence "R%u", 31, 2))>;

diff  --git a/llvm/lib/Target/AVR/AVRRegisterInfo.cpp b/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
index 1886debaf492..5dd7f5c55695 100644
--- a/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
+++ b/llvm/lib/Target/AVR/AVRRegisterInfo.cpp
@@ -44,10 +44,7 @@ AVRRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
 const uint32_t *
 AVRRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
                                       CallingConv::ID CC) const {
-  const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
-
-  return AFI->isInterruptOrSignalHandler() ? CSR_Interrupts_RegMask
-                                           : CSR_Normal_RegMask;
+  return CSR_Normal_RegMask;
 }
 
 BitVector AVRRegisterInfo::getReservedRegs(const MachineFunction &MF) const {

diff  --git a/llvm/test/CodeGen/AVR/interrupts.ll b/llvm/test/CodeGen/AVR/interrupts.ll
index e112de0a0ddd..7838e352f045 100644
--- a/llvm/test/CodeGen/AVR/interrupts.ll
+++ b/llvm/test/CodeGen/AVR/interrupts.ll
@@ -1,5 +1,7 @@
 ; RUN: llc < %s -march=avr | FileCheck %s
 
+ at count = global i8 0
+
 define avr_intrcc void @interrupt_handler() {
 ; CHECK-LABEL: interrupt_handler:
 ; CHECK: sei
@@ -104,5 +106,75 @@ define avr_intrcc void @interrupt_alloca() {
   ret void
 }
 
+define void @signal_handler_with_increment() #1 {
+; CHECK-LABEL: signal_handler_with_increment:
+; CHECK:      push r0
+; CHECK-NEXT: push r1
+; CHECK-NEXT: in r0, 63
+; CHECK-NEXT: push r0
+; CHECK-NEXT: clr r0
+; CHECK-NEXT: clr r1
+; CHECK-NEXT: push r24
+; CHECK-NEXT: lds r24, count
+; CHECK-NEXT: inc r24
+; CHECK-NEXT: sts count, r24
+; CHECK-NEXT: pop r24
+; CHECK-NEXT: pop r0
+; CHECK-NEXT: out 63, r0
+; CHECK-NEXT: pop r1
+; CHECK-NEXT: pop r0
+; CHECK-NEXT: reti
+  %old = load volatile i8, i8* @count
+  %new = add i8 %old, 1
+  store volatile i8 %new, i8* @count
+  ret void
+}
+
+declare void @foo()
+
+; When a signal handler calls a function, it must push/pop all call clobbered
+; registers.
+define void @signal_handler_with_call() #1 {
+; CHECK-LABEL: signal_handler_with_call:
+; CHECK:      push r0
+; CHECK-NEXT: push r1
+; CHECK-NEXT: in r0, 63
+; CHECK-NEXT: push r0
+; CHECK-NEXT: clr r0
+; CHECK-NEXT: clr r1
+; CHECK-NEXT: push r18
+; CHECK-NEXT: push r19
+; CHECK-NEXT: push r20
+; CHECK-NEXT: push r21
+; CHECK-NEXT: push r22
+; CHECK-NEXT: push r23
+; CHECK-NEXT: push r24
+; CHECK-NEXT: push r25
+; CHECK-NEXT: push r26
+; CHECK-NEXT: push r27
+; CHECK-NEXT: push r30
+; CHECK-NEXT: push r31
+; CHECK-NEXT: call foo
+; CHECK-NEXT: pop r31
+; CHECK-NEXT: pop r30
+; CHECK-NEXT: pop r27
+; CHECK-NEXT: pop r26
+; CHECK-NEXT: pop r25
+; CHECK-NEXT: pop r24
+; CHECK-NEXT: pop r23
+; CHECK-NEXT: pop r22
+; CHECK-NEXT: pop r21
+; CHECK-NEXT: pop r20
+; CHECK-NEXT: pop r19
+; CHECK-NEXT: pop r18
+; CHECK-NEXT: pop r0
+; CHECK-NEXT: out 63, r0
+; CHECK-NEXT: pop r1
+; CHECK-NEXT: pop r0
+; CHECK-NEXT: reti
+  call void @foo()
+  ret void
+}
+
 attributes #0 = { "interrupt" }
 attributes #1 = { "signal" }


        


More information about the llvm-commits mailing list