View Issue Details

IDProjectCategoryView StatusLast Update
0037708FPCCompilerpublic2020-09-14 21:41
ReporterChristo Crause Assigned ToFlorian  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
Product Version3.3.1 
Fixed in Version3.3.1 
Summary0037708: Xtensa incorrect stack based parameter passing
DescriptionCalling a procedure with more than 6 parameters (thus forcing parameter passing via stack) results in errors for both windowed and call0 ABIs. The reason appears to be that the caller stores the stack parameters starting at the caller SP (which is correct according to the ISA). The callee loads the stack based parameter relative to the start of its stack/frame pointer. In steps to reproduce please find a simple test program. The disassembled code from this test program is shown in additional information.

Note the following:
In main the address of variable gg is stored at the current (caller) SP:
# [13] test(aa, bb, cc, dd, ee, ff, gg);
    l32r a2,.Lj5
    s32i a2,a1,0

On the callee side parameter f is loaded relative the callee SP:
# Var g located at a15+24, size=OS_32

    addi a2,a15,24
    l32i a3,a15,0
    s32i a3,a2,0

The ISA has the following to say: "If there are more than six words of arguments, the additional arguments are stored on
the stack beginning at the caller’s stack pointer and at increasingly positive offsets from
the stack pointer. That is, the caller stores the seventh argument word (after the first six
words in registers) at [sp + 0], the eighth word at [sp + 4], and so on. The callee can ac-
cess these arguments in memory beginning at [sp + FRAMESIZE], where FRAMESIZE
is the size of the callee’s stack frame."

From the generated assembler it is clear that the FRAMESIZE offset is missing, hence the stack based parameters are loaded from the wrong memory locations.
Steps To Reproduceprogram testparams;

procedure test(var a, b, c, d, e, f, g: uint32);
begin
  g := 13;
end;

var
  aa, bb, cc, dd, ee, ff, gg: uint32;

begin
  gg := 0;
  test(aa, bb, cc, dd, ee, ff, gg);
  if gg = 13 then
    halt(0)
  else
    halt(13);
end.
Additional Information.section .text.n_p$testparams_$$_test$longword$longword$longword$longword$longword$longword$longword,"ax"
    .balign 4
.globl P$TESTPARAMS_$$_TEST$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD
P$TESTPARAMS_$$_TEST$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD:
.Ll1:
# [testparams.pp]
# [4] begin
    addi a1,a1,-32
    s32i a15,a1,28
    mov a15,a1
# Var a located at a15+0, size=OS_32
# Var b located at a15+4, size=OS_32
# Var c located at a15+8, size=OS_32
# Var d located at a15+12, size=OS_32
# Var e located at a15+16, size=OS_32
# Var f located at a15+20, size=OS_32
# Var g located at a15+24, size=OS_32
    s32i a2,a15,0
    s32i a3,a15,4
    s32i a4,a15,8
    s32i a5,a15,12
    s32i a6,a15,16
    s32i a7,a15,20
    addi a2,a15,24
    l32i a3,a15,0
    s32i a3,a2,0
.Ll2:
# [5] g := 13;
    l32i a2,a15,24
    movi a3,13
    s32i a3,a2,0
.Ll3:
# [6] end;
    l32i a15,a1,28
    addi a1,a1,32
    ret
.Lt2:
.Le0:
    .size P$TESTPARAMS_$$_TEST$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD, .Le0 - P$TESTPARAMS_$$_TEST$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD
.Ll4:

.section .text.n_main,"ax"
    .balign 4
.Lj5:
    .long U_$P$TESTPARAMS_$$_GG
.Lj6:
    .long U_$P$TESTPARAMS_$$_FF
.Lj7:
    .long U_$P$TESTPARAMS_$$_EE
.Lj8:
    .long U_$P$TESTPARAMS_$$_DD
.Lj9:
    .long U_$P$TESTPARAMS_$$_CC
.Lj10:
    .long U_$P$TESTPARAMS_$$_BB
.Lj11:
    .long U_$P$TESTPARAMS_$$_AA
    .balign 4
.globl main
main:
.globl PASCALMAIN
PASCALMAIN:
.Ll5:
# [11] begin
    addi a1,a1,-48
    s32i a15,a1,44
    mov a15,a1
    s32i a0,a1,40
    call0 FPC_INIT_FUNC_TABLE
.Ll6:
# [12] gg := 0;
    movi a2,0
    l32r a3,.Lj5
    s32i a2,a3,0
.Ll7:
# [13] test(aa, bb, cc, dd, ee, ff, gg);
    l32r a2,.Lj5
    s32i a2,a1,0
    l32r a7,.Lj6
    l32r a6,.Lj7
    l32r a5,.Lj8
    l32r a4,.Lj9
    l32r a3,.Lj10
    l32r a2,.Lj11
    call0 P$TESTPARAMS_$$_TEST$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD
.Ll8:
# [14] if gg = 13 then
    l32r a2,.Lj5
    l32i a2,a2,0
    movi a3,13
    beq a2,a3,.Lj12
    j .Lj13
.Lj12:
.Ll9:
# [15] halt(0)
    movi a2,0
    call0 SYSTEM_$$_HALT$LONGINT
    j .Lj14
.Lj13:
.Ll10:
# [17] halt(1);
    movi a2,1
    call0 SYSTEM_$$_HALT$LONGINT
.Lj14:
.Ll11:
# [18] end.
    call0 fpc_do_exit
    l32i a15,a1,44
    l32i a0,a1,40
    addi a1,a1,48
    ret
TagsNo tags attached.
Fixed in Revision
FPCOldBugId
FPCTarget-
Attached Files

Activities

Florian

2020-09-13 15:54

administrator   ~0125526

It is fixed by one of my commits of the last days.

Christo Crause

2020-09-13 21:51

reporter   ~0125530

This issue is fixed for call0 but not windowed ABI. For ESP32 the instructions generated for procedure test is shown below. After saving the register parameters on the stack (a2..a7) there are 3 junk instruction starting with addi a3,a1,24. The address of parameter g is stored at a1 + 32, so the load instruction after g : =13; should be l32i a2,a1,32.

P$TESTPARAMS_$$_TEST$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD:
.Ll1:
# [testparams.pp]
# [4] begin
    entry a1,32
# Var a located at a1+0, size=OS_32
# Var b located at a1+4, size=OS_32
# Var c located at a1+8, size=OS_32
# Var d located at a1+12, size=OS_32
# Var e located at a1+16, size=OS_32
# Var f located at a1+20, size=OS_32
# Var g located at a1+24, size=OS_32
    s32i a2,a1,0
    s32i a3,a1,4
    s32i a4,a1,8
    s32i a5,a1,12
    s32i a6,a1,16
    s32i a7,a1,20
    addi a3,a1,24
    l32i a2,a7,0
    s32i a2,a3,0
.Ll2:
# [5] g := 13;
    l32i a2,a1,24
    movi a3,13
    s32i a3,a2,0
.Ll3:
# [6] end;
    retw

Florian

2020-09-13 23:07

administrator   ~0125532

Are you sure, you recompiled everything? E.g. with -O1 I get

.globl P$TESTPARAMS_$$_TEST$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD
P$TESTPARAMS_$$_TEST$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD$LONGWORD:
# Stackframe size was estimated before code generation due to stack parameters
# Calculated stackframe size: 48
# Max. outgoing parameter size: 0
# End of last temporary location: 24
# Max. window rotation in bytes: 32
# Required size after code generation: 48
# [tw37708.pp]
# [4] begin
    entry a1,48
# Var a located at a1+0, size=OS_32
# Var b located at a1+4, size=OS_32
# Var c located at a1+8, size=OS_32
# Var d located at a1+12, size=OS_32
# Var e located at a1+16, size=OS_32
# Var f located at a1+20, size=OS_32
# Var g located at a1+48, size=OS_32
    s32i a2,a1,0
    s32i a3,a1,4
    s32i a4,a1,8
    s32i a5,a1,12
    s32i a6,a1,16
    s32i a7,a1,20
# [5] g := 13;
    l32i a2,a1,48
    movi a3,13
    s32i a3,a2,0
# [6] end;
    retw

In particular I wonder that no stack statistics is printed for you?

Christo Crause

2020-09-14 08:51

reporter   ~0125535

You are correct Florian, I accidentally used an older compiler version for my EPS32 test. I confirm this issue is fixed for both windowed and call0 ABI's.

Christo Crause

2020-09-14 21:41

reporter   ~0125543

Thanks Florian.

Issue History

Date Modified Username Field Change
2020-09-05 20:09 Christo Crause New Issue
2020-09-13 15:54 Florian Assigned To => Florian
2020-09-13 15:54 Florian Status new => resolved
2020-09-13 15:54 Florian Resolution open => fixed
2020-09-13 15:54 Florian Fixed in Version => 3.3.1
2020-09-13 15:54 Florian FPCTarget => -
2020-09-13 15:54 Florian Note Added: 0125526
2020-09-13 21:51 Christo Crause Status resolved => feedback
2020-09-13 21:51 Christo Crause Resolution fixed => open
2020-09-13 21:51 Christo Crause Note Added: 0125530
2020-09-13 23:07 Florian Note Added: 0125532
2020-09-14 08:51 Christo Crause Note Added: 0125535
2020-09-14 08:51 Christo Crause Status feedback => assigned
2020-09-14 21:32 Florian Status assigned => resolved
2020-09-14 21:32 Florian Resolution open => fixed
2020-09-14 21:41 Christo Crause Status resolved => closed
2020-09-14 21:41 Christo Crause Note Added: 0125543