Menu

#3458 wrong value when returning in a switch using __z88dk_fastcall

closed-fixed
None
Z80
5
2022-06-28
2022-06-24
Under4Mhz
No

When returning a value from a switch case statement when calling a function with the z88dk__fastcall convention, sdcc returns the incorrect value.

/// GPL 2.0
#include <stdint.h>
#include <stdio.h>

#ifndef __SDCC
#define __z88dk_fastcall
#endif

int global = 42;
int GetValue() { return global; }
int SwitchValue( int value ) __z88dk_fastcall {

    switch( value ) {

        case 1: return GetValue();
        case 2: return GetValue();
        case 3: return GetValue();
        case 4: return GetValue();
    }

    return 0;
}

void main() {

    printf( "%d\n", SwitchValue( 2 ) );
}


#ifdef __SDCC
__sfr __at 0xff sif;
int putchar(int c)
{
  sif= 'p';
  sif= c;

  return c;
}
#endif
$ sdcc -mz80 ./fastcall.c  -o fastcall.ihx
$ ucsim_z80 -I if=outputs[0xff] fastcall.ihx
uCsim 0.7.5, Copyright (C) 1997 Daniel Drotos.
0> Loading from fastcall.ihx
3130 words read from fastcall.ihx
r
Simulation started, PC=0x000000
2
$ gcc ./fastcall.c 
$ ./a.out 
42

A summary of the assembler.

_GetValue::
    ld  de, (_global)
    ret
_SwitchValue::
;./fastcall.c:12: switch( value ) {
    ld  a, l
    dec a
    or  a, h
    jp  Z,_GetValue
...

The optimization of jumping to the next function fails to account for the caller using z88dk_fastcall calling convention.

I use z88dk_fastcall for all my single parameter functions since it provides a large speedup and program size reduction in sdcc pre-4.2 versions. I can remove it now I know it's problem, since I'm using a macro and can simply define it as empty.

Discussion

  • Under4Mhz

    Under4Mhz - 2022-06-24

    I simplified the code a bit. Turns out it can happen in any function returning a value from a function call when using z88dk_fastcall. The switch isn't necessary (I just happened to be returning a function from a switch in the function it happened in).

    /// GPL 2.0
    #include <stdint.h>
    #include <stdio.h>
    
    #ifndef __SDCC
    #define __z88dk_fastcall
    #endif
    
    int GetValue() { return 42; }
    int ReturnValue() __z88dk_fastcall {
    
        return GetValue();
    }
    
    void main() {
    
        printf( "%d\n", ReturnValue() );
    }
    
    
    #ifdef __SDCC
    __sfr __at 0xff sif;
    int putchar( int c ) {
    
        sif = 'p';
        sif = c;
    
        return c;
    }
    #endif
    
    // sdcc -mz80 ./fastcall.c  -o fastcall.ihx
    // ucsim_z80 -I if=outputs[0xff] fastcall.ihx
    
    $ 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.2 #13499 (Linux)
    

    I also take back being able to remove fastcall, I have a couple of assembler functions that rely on it, so I'll have to slowly deprecate using it when I switch fully to 4.2.

     
  • Philipp Klaus Krause

    • assigned_to: Philipp Klaus Krause
    • Category: other --> Z80
     
  • Philipp Klaus Krause

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

    Fixed in [r13537] a few days ago.

     

    Related

    Commit: [r13537]


Log in to post a comment.

MongoDB Logo MongoDB