Skip to content

Commit 4a84f10

Browse files
authored
[AVR] Fix occasional corruption in stack passed params
Corruption can occur with passing parameters on the stack when under register pressure. Fixes #163015 .
1 parent 6ed814a commit 4a84f10

File tree

4 files changed

+81
-12
lines changed

4 files changed

+81
-12
lines changed

llvm/lib/Target/AVR/AVRInstrInfo.td

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,14 +1504,26 @@ let Defs = [SREG], hasSideEffects = 0 in
15041504
def FRMIDX : Pseudo<(outs DLDREGS:$dst), (ins DLDREGS:$src, i16imm:$src2),
15051505
"frmidx\t$dst, $src, $src2", []>;
15061506

1507+
// The instructions STDSPQRr and STDWSPQRr are used to store to the stack
1508+
// frame. The most accurate implementation would be to load the SP into
1509+
// a temporary pointer variable and then STDPtrQRr. However for efficiency,
1510+
// we assume that R29R28 contains the current call frame pointer.
1511+
// However in the PEI pass we sometimes rewrite a ADJCALLSTACKDOWN pseudo,
1512+
// plus one or more STDSPQRr/STDWSPQRr pseudo instructions to use Z for a
1513+
// stack adjustment then as a base pointer. To avoid corruption, we thus
1514+
// specify special classes of registers, like GPR8 and DREGS, but with
1515+
// the Z register removed, as the source/input to these instructions.
15071516
// This pseudo is either converted to a regular store or a push which clobbers
15081517
// SP.
1509-
def STDSPQRr : StorePseudo<(outs), (ins memspi:$dst, GPR8:$src),
1518+
let Defs = [SP], Uses = [SP], hasSideEffects = 0 in
1519+
def STDSPQRr : StorePseudo<(outs), (ins memspi:$dst, GPR8NOZ:$src),
15101520
"stdstk\t$dst, $src", [(store i8:$src, addr:$dst)]>;
15111521

1522+
// See the comment on STDSPQRr.
15121523
// This pseudo is either converted to a regular store or a push which clobbers
15131524
// SP.
1514-
def STDWSPQRr : StorePseudo<(outs), (ins memspi:$dt, DREGS:$src),
1525+
let Defs = [SP], Uses = [SP], hasSideEffects = 0 in
1526+
def STDWSPQRr : StorePseudo<(outs), (ins memspi:$dt, DREGSNOZ:$src),
15151527
"stdwstk\t$dt, $src", [(store i16:$src, addr:$dt)]>;
15161528

15171529
// SP read/write pseudos.

llvm/lib/Target/AVR/AVRRegisterInfo.td

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,31 @@ def PTRDISPREGS : RegisterClass<"AVR", [i16], 8, (add R31R30, R29R28), ptr>;
211211
// model this using a register class containing only the Z register.
212212
def ZREG : RegisterClass<"AVR", [i16], 8, (add R31R30)>;
213213

214+
// general registers excluding Z register lo/hi, these are the only
215+
// registers that are always safe for STDSPQr instructions
216+
def GPR8NOZ : RegisterClass<"AVR", [i8], 8,
217+
(// Return value and argument registers.
218+
add R24, R25, R18, R19, R20, R21, R22, R23,
219+
// Scratch registers.
220+
R26, R27,
221+
// Callee saved registers.
222+
R28, R29, R17, R16, R15, R14, R13, R12, R11, R10,
223+
R9, R8, R7, R6, R5, R4, R3, R2, R0, R1)>;
224+
225+
// 16-bit pair register class excluding Z register lo/hi, these are the only
226+
// registers that are always safe for STDWSPQr instructions
227+
def DREGSNOZ : RegisterClass<"AVR", [i16], 8,
228+
(// Return value and arguments.
229+
add R25R24, R19R18, R21R20, R23R22,
230+
// Scratch registers.
231+
R27R26,
232+
// Callee saved registers.
233+
R29R28, R17R16, R15R14, R13R12, R11R10, R9R8,
234+
R7R6, R5R4, R3R2, R1R0,
235+
// Pseudo regs for unaligned 16-bits
236+
R26R25, R24R23, R22R21, R20R19, R18R17, R16R15,
237+
R14R13, R12R11, R10R9)>;
238+
214239
// Register class used for the stack read pseudo instruction.
215240
def GPRSP : RegisterClass<"AVR", [i16], 8, (add SP)>;
216241

llvm/test/CodeGen/AVR/dynalloca.ll

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,16 @@ define void @dynalloca2(i16 %x) {
6464
; CHECK-NEXT: out 63, r0
6565
; CHECK-NEXT: out 61, {{.*}}
6666
; Store values on the stack
67-
; CHECK: ldi r20, 0
68-
; CHECK: ldi r21, 0
69-
; CHECK: std Z+8, r21
70-
; CHECK: std Z+7, r20
71-
; CHECK: std Z+6, r21
72-
; CHECK: std Z+5, r20
73-
; CHECK: std Z+4, r21
74-
; CHECK: std Z+3, r20
75-
; CHECK: std Z+2, r21
76-
; CHECK: std Z+1, r20
67+
; CHECK: ldi [[REG1:r[0-9]+]], 0
68+
; CHECK: ldi [[REG2:r[0-9]+]], 0
69+
; CHECK: std Z+8, [[REG2]]
70+
; CHECK: std Z+7, [[REG1]]
71+
; CHECK: std Z+6, [[REG2]]
72+
; CHECK: std Z+5, [[REG1]]
73+
; CHECK: std Z+4, [[REG2]]
74+
; CHECK: std Z+3, [[REG1]]
75+
; CHECK: std Z+2, [[REG2]]
76+
; CHECK: std Z+1, [[REG1]]
7777
; CHECK: call
7878
; Call frame restore
7979
; CHECK-NEXT: in r30, 61
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
; RUN: llc < %s -mtriple=avr | FileCheck %s
2+
3+
@ui1 = protected local_unnamed_addr global i64 zeroinitializer, align 8
4+
@ui2 = protected local_unnamed_addr global i64 zeroinitializer, align 8
5+
@failed = private unnamed_addr addrspace(1) constant [12 x i8] c"test failed\00"
6+
@stats2 = external protected global i16, align 1
7+
8+
; CHECK-LABEL: main:
9+
define i32 @main() addrspace(1) {
10+
entry:
11+
store i64 94, ptr @ui1, align 8
12+
store i64 53, ptr @ui2, align 8
13+
tail call addrspace(1) void @foo(i16 ptrtoint (ptr addrspace(1) @failed to i16), i16 11, i8 2, i16 32, ptr @stats2)
14+
%11 = load i64, ptr @ui1, align 8
15+
%12 = load i64, ptr @ui2, align 8
16+
17+
; COM: CHECK: call __udivdi3
18+
%15 = udiv i64 %11, %12
19+
20+
; look for the buggy pattern where r30/r31 are being clobbered, corrupting the stack pointer
21+
; CHECK-NOT: std Z+{{[1-9]+}}, r30
22+
; CHECK-NOT: std Z+{{[1-9]+}}, r31
23+
24+
; CHECK: call expect
25+
tail call addrspace(1) void @expect(i64 %15, i64 1, i16 ptrtoint (ptr addrspace(1) @failed to i16), i16 11, i8 2, i16 33)
26+
27+
; CHECK: ret
28+
ret i32 0
29+
}
30+
31+
declare protected void @expect(i64, i64, i16, i16, i8, i16) local_unnamed_addr addrspace(1) #0
32+
declare protected void @foo(i16, i16, i8, i16, i16) local_unnamed_addr addrspace(1) #0

0 commit comments

Comments
 (0)