Skip to content

Commit aa54b9a

Browse files
committed
Corruption can occur with passing parameters on the stack when under register pressure.
See this forum discussion for details (or the GitHub issue) https://discourse.llvm.org/t/avr-register-allocation-issue-help-advice-with-debugging/88498/11 @aykevl @benshi001
1 parent 059e213 commit aa54b9a

File tree

3 files changed

+49
-12
lines changed

3 files changed

+49
-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

0 commit comments

Comments
 (0)