SDCC __preserves_regs broken?

ZX80, ZX 81, ZX Spectrum, TS2068 and other clones
Post Reply
derekfountain
Member
Posts: 121
Joined: Mon Mar 26, 2018 1:49 pm

SDCC __preserves_regs broken?

Post by derekfountain »

Something seems broken in recent SDCC. Maybe. I'm not quite sure what's going on...

The testcase is this:

Code: Select all

#include <arch/zx.h>

int main(void)
{
  uint16_t x;
  uint8_t y;

  for( y=0; y<192; y++ )
  {
    for( x=0; x<256; x++ )
    {
      uint8_t *test = zx_pxy2saddr( x, y );
      *test = 255;
    }
  }

  return 0;
}

zcc +zx -vn  -clib=sdcc_iy -startup=4 main.c -o vectors -create-app --c-code-in-asm --std-c99 --list -m -s
which is a very inefficient way to fill the screen. But it doesn't work with freshly built 2.1 or nightly. The x loop iterates for the top line (i.e. when y=0 but not subsequent values). Unrolling the y loop makes it OK again, so I think it's a stack issue with repeated calls to zx_pxy2saddr().

On a hunch, I went to the header file and changed:

Code: Select all

extern unsigned char *zx_pxy2saddr(unsigned char x,unsigned char y) __preserves_regs(b,c,d,e,iyl,iyh);
extern unsigned char *zx_pxy2saddr_callee(unsigned char x,unsigned char y) __preserves_regs(b,c,d,e,iyl,iyh) __z88dk_callee;
#define zx_pxy2saddr(a,b) zx_pxy2saddr_callee(a,b)
to

Code: Select all

extern unsigned char *zx_pxy2saddr(unsigned char x,unsigned char y);
extern unsigned char *zx_pxy2saddr_callee(unsigned char x,unsigned char y) __z88dk_callee;
#define zx_pxy2saddr(a,b) zx_pxy2saddr_callee(a,b)
Then the test code works as expected.

I've built z88dk with

Code: Select all

export BUILD_SDCC=1
which shows the problem. Adding

Code: Select all

export BUILD_SDCC_HTTP=1
and ensuring SDCC is downloaded from http://nightly.z88dk.org/zsdcc/zsdcc_r12036_src.tar.gz also shows the problem. Which rather makes me doubt myself. Surely someone would have spotted this earlier if that copy of SDCC had a problem?

I'm out of my depth! Can someone else take a look?
derekfountain
Member
Posts: 121
Joined: Mon Mar 26, 2018 1:49 pm

Re: SDCC __preserves_regs broken?

Post by derekfountain »

Right, so last night I was a bit hasty blaming SDCC for this one. :rolleyes:

The underlying code is commented:

Code: Select all

asm_zx_pxy2saddr:

   ; enter :  l = x coordinate
   ;          h = valid y coordinate
   ;
   ; exit  : hl = screen address of byte containing pixel
   ;          e = x coordinate
   ;          d = y coordinate
   ;
   ; uses  : af, de, hl
so claiming to preserve DE:

Code: Select all

extern unsigned char *zx_pxy2saddr(unsigned char x,unsigned char y) __preserves_regs(b,c,d,e,iyl,iyh);
extern unsigned char *zx_pxy2saddr_callee(unsigned char x,unsigned char y) __preserves_regs(b,c,d,e,iyl,iyh) __z88dk_callee;
is wrong. Removing d,e from those register lists fixes it.

I'm still not sure why this should bite me now. That must be a fairly commonly used function.
User avatar
dom
Well known member
Posts: 2076
Joined: Sun Jul 15, 2007 10:01 pm

Re: SDCC __preserves_regs broken?

Post by dom »

Thank you, I've now corrected that one in the tree.

sdcc has undergone quite a lot of change over the past year which has changed the shape of the generated code quite a lot, this has led to both quite a few bugs in sdcc and shown up issues like the one you found: I suspect it's now keeping something in de that previously it wasn't. Given some of my experience trying to isolate test cases, I suspect that if you'd written the code slightly differently, different code would have been generated which wouldn't have been triggered by the incorrect register definition.
Post Reply