The following code produces the incorrect output of 3,4 instead of 1,2:
/// GPL 2.0 or later
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
typedef struct {
int x;
int y;
} maths_point;
void PlayerGridNextGet( maths_point *next ) {
next->x = 1;
next->y = 2;
}
void PlayerGridGet( maths_point *current ) {
current->x = 3;
current->y = 4;
}
int MapGet( int x, int y ) { return 0; }
int StateDoorHiddenOpenSet( int x, int y ) { printf( "%d,%d", x, y ); }
bool ObjectIsHiddenDoor( char ch ) { return true; }
void SoundDoorOpen() {}
void Action() {
maths_point next;
PlayerGridNextGet( &next );
char ch = MapGet( next.x, next.y );
maths_point current;
PlayerGridGet( ¤t );
char chCurrent = MapGet( current.x, current.y );
// Hidden door open
StateDoorHiddenOpenSet( next.x, next.y );
}
int main() {
printf("Start\n");
Action();
printf("\nEnd\n");
return 0;
}
#ifdef __SDCC
__sfr __at 0xff sif;
int putchar( int c ) {
sif = 'p';
sif = c;
return c;
}
#endif
// sdcc -mz80 --fverbose-asm ./get2.c -o get2.ihx && ucsim_z80 -I if=outputs[0xff] get2.ihx
$ sdcc -mz80 --fverbose-asm ./get2.c -o get2.ihx && ucsim_z80 -I if=outputs[0xff] get2.ihx
./get2.c:25: warning 85: in function MapGet unreferenced function argument : 'x'
./get2.c:25: warning 85: in function MapGet unreferenced function argument : 'y'
./get2.c:27: warning 59: function 'StateDoorHiddenOpenSet' must return value
./get2.c:29: warning 85: in function ObjectIsHiddenDoor unreferenced function argument : 'ch'
./get2.c:31: warning 283: function declarator with no prototype
./get2.c:33: warning 283: function declarator with no prototype
./get2.c:47: warning 283: function declarator with no prototype
uCsim 0.7.6, Copyright (C) 1997 Daniel Drotos.
0> Loading from get2.ihx
3221 words read from get2.ihx
r
Simulation started, PC=0x000000
Start
3,4
End
gcc ./get2.c && ./a.out
Start
1,2
End
Removing the empty function SoundDoorOpen seems to make the difference. In my actual code, SoundDoorOpen contains code and is compiled in a separate source file. Being called makes no difference.
With SoundDoorOpen, sdcc seems to decide to use 4 bytes for the stack instead of 8:
$ diff get2-*.asm
13d12
< .globl _SoundDoorOpen
189,201d187
< ;./get2.c:35: void SoundDoorOpen() {}
< ; genLabel
< ; genFunction
< ; ---------------------------------
< ; Function SoundDoorOpen
< ; ---------------------------------
< ; Register assignment is optimal.
< ; Stack space usage: 0 bytes.
< _SoundDoorOpen::
< ; genLabel
< ; common peephole 158 removed unused label 00101$.
< ; genEndFunction
< ret
209c195
< ; Stack space usage: 4 bytes.
---
> ; Stack space usage: 8 bytes.
214,216c200,203
< ; adjustStack by -4
< push af
< push af
---
> ; adjustStack by -8
> ld hl, #-8
> add hl, sp
> ld sp, hl
251c238
< ld hl, #0
---
> ld hl, #4
260,262c247,248
< pop hl
< pop de
< push de
---
> ld e, -2 (ix)
> ld d, -1 (ix)
266,267c252,257
< ; common peephole 50b eleminated dead push/pop pair.
< push hl
---
> ld l, -4 (ix)
> ; spillPairReg hl
> ; spillPairReg hl
> ld h, -3 (ix)
> ; spillPairReg hl
> ; spillPairReg hl
sdcc -v
SDCC : mcs51/z80/z180/r2k/r2ka/r3ka/sm83/tlcs90/ez80_z80/z80n/ds390/pic16/pic14/TININative/ds400/hc08/s08/stm8/pdk13/pdk14/pdk15/mos6502 4.2.9 #13755 (Linux)
I sometimes can reproduce this (on Debian GNU/Linux on amd64 using sdcc from current trunk). But not always; looks like it even makes a difference from which directory I call SDCC. But valgrind doesn't show reads of uninitialized memory. Maybe this is affected by [bugs:3505]?
P.S.: The difference is already visible in the conflict graph for stack allocation, as can be seen using --dump-graphs. From the code supplied by Under4Mhz I've created a regression test case for this (attached).
Last edit: Philipp Klaus Krause 2023-01-21
Fixed in [r13807].
Related
Commit: [r13807]