Menu

#3532 address lost (register overwritten) prior to function call

closed-fixed
None
Z80
5
2023-01-21
2022-12-23
sverx
No

SDCC bug, present on the latest snapshot (4.2.10 #13772):

./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.10 #13772 (Linux)
published under GNU General Public License (GPL)

Example offending code:

typedef struct tSpriteStruct {
  char dummy;
  signed char handle;
} SpriteStruct;

SpriteStruct sprites[2];

signed char SMS_addSprite (unsigned int y, unsigned int x_tile) __naked __preserves_regs(d,e,iyh,iyl) __sdcccall(1) {
__asm
    ld a,l
    ret
__endasm;
}

void main(void) {
  sprites[0].handle = SMS_addSprite(0, 0);
  sprites[1].handle = SMS_addSprite(0, 0);
}

issue: value in DE (the variable address) gets overwritten with the parameter value (constant) - thus lost - prior to the fuction call, but it's used nevertheless like if it was already there:

_main::
;main.c:17: sprites[0].handle = SMS_addSprite(0, 0);
;   skipping iCode since result will be rematerialized
;   genPlus
;fetchLitPair   de
    ld  de, #_sprites + 1
;   genSend
;   genMove_o
;fetchLitPair   de
    ld  de, #0x0000
;   genSend
;   genMove_o
;fetchLitPair   hl
    ld  hl, #0x0000
;   genCall
    call    _SMS_addSprite
;   genMove_o
;   genAssign (pointer)
    ld  (de), a

workaround: remove D and E from __preserves_regs(d,e,iyh,iyl)

CL: sdcc -c -mz80 --fverbose-asm --no-peep main.c

Related

Wiki: NGI0-Entrust-SDCC

Discussion

  • Philipp Klaus Krause

    I see two possible solutions:
    1) The caller could realize that de is used for a parameter, and thus cannot be actually used to hold another value.
    2) Another perspective is that de is not actually unused, since it is used for passing a parameter. So SDCC should emit a diagnostic when it sees such a declaration.
    Actually, doing both would also make sense.

     
    • sverx

      sverx - 2022-12-24

      I think your point 1 is absolutely correct and it should be sufficient to address this issue.

      Regarding the point 2 instead, I tend to disagree. As far as I know, the preserves_regs attribute should indicate that a function body doesn't change the contents of those listed registers, which does include the fact that it will use the registers used to pass the parameter(s) but not update them, as in the simple example above.

      Keeping this intact would mean that two successive calls to the same function that preserves the only passed parameter should be able to turn into a single LD opcode prior to the first call if the parameter is the same, as in

      some_funct(0);
      some_funct(0);
      
       
      • Philipp Klaus Krause

        I agree. I'll fix the bug first. The reuse of the parameter could be added as an optimization later.

         
  • Philipp Klaus Krause

    • assigned_to: Philipp Klaus Krause
     
  • Philipp Klaus Krause

    • status: open --> closed-fixed
     
  • Philipp Klaus Krause

    Fixed in [r13806].

     

    Related

    Commit: [r13806]


Log in to post a comment.

MongoDB Logo MongoDB