Menu

#3005 initialization for static local variables is generated in wrong section

open
nobody
None
other
5
2020-06-03
2020-05-24
Tony Pavlov
No

the code:

#include <gb/gb.h>
#include <stdio.h>

union long_ptr {
    long ptr;
    struct {
        void * ofs;
        int seg;
    } segofs;
};

long to_longptr(void* ptr, int bank) {
    static union long_ptr tmp = {.segofs = {ptr, bank}}; 
    return tmp.ptr;
}

long tmp;

void main() {
  tmp = to_longptr(&to_longptr, 1);
  printf("%x %x\n", (int)tmp, (int)(tmp >> 16));
}

the result:

    .area _GSINIT
;test.c:13: static union long_ptr tmp = {.segofs = {ptr, bank}}; 
    ld  de, #_to_longptr_tmp_65536_64
    ldhl    sp, #2
    ld  a, (hl)
    ld  (de), a
    inc de
    inc hl
    ld  a, (hl)
    ld  (de), a
    ld  de, #(_to_longptr_tmp_65536_64 + 0x0002)
    inc hl
    ld  a, (hl)
    ld  (de), a
    inc de
    inc hl
    ld  a, (hl)
    ld  (de), a
;--------------------------------------------------------
; Home
;--------------------------------------------------------
    .area _HOME
    .area _HOME
;--------------------------------------------------------
; code
;--------------------------------------------------------
    .area _CODE
;test.c:12: long to_longptr(void* ptr, int bank) {
;   ---------------------------------
; Function to_longptr
; ---------------------------------
_to_longptr::
    add sp, #-4
;test.c:14: return tmp.ptr;
    ld  de, #_to_longptr_tmp_65536_64 + 0
    ld  a,(de)
    ldhl    sp, #0
    ld  (hl+), a
    inc de
    ld  a, (de)
    ld  (hl+), a
    inc de
    ld  a, (de)
    ld  (hl+), a
    inc de
    ld  a, (de)
    ld  (hl), a
    pop de
    push    de
    dec hl
    ld  a, (hl+)
    ld  h, (hl)
    ld  l, a
;test.c:15: }
    add sp, #4
    ret

function code is torn into 2 pieces

commandline:

sdcc -mgbz80 --no-std-crt0 -I ..\..\gbdk\include -I ..\..\gbdk\include\asm -I src\include -c test.c -o build\test.rel

version:

SDCC : mcs51/z80/z180/r2k/r3ka/gbz80/tlcs90/ez80_z80/z80n/ds390/pic16/pic14/TININative/ds400/hc08/s08/stm8/pdk13/pdk14/pdk15 4.0.2 #11619 (MINGW64)
published under GNU General Public License (GPL)

Discussion

  • Tony Pavlov

    Tony Pavlov - 2020-05-24

    workaround is this:

    long to_longptr(void* ptr, int bank) {
    //    static union long_ptr tmp = {.segofs = {ptr, bank}};
        static union long_ptr tmp;
        tmp.segofs.ofs = ptr;
        tmp.segofs.seg = bank;
        return tmp.ptr;
    }
    

    the asm result is this:

    _to_longptr::
        add sp, #-4
    ;test.c:15: tmp.segofs.ofs = ptr;
        ld  de, #_to_longptr_tmp_65536_64
        ldhl    sp, #6
        ld  a, (hl)
        ld  (de), a
        inc de
        inc hl
        ld  a, (hl)
        ld  (de), a
    ;test.c:16: tmp.segofs.seg = bank;
        ld  de, #(_to_longptr_tmp_65536_64 + 0x0002)
        inc hl
        ld  a, (hl)
        ld  (de), a
        inc de
        inc hl
        ld  a, (hl)
        ld  (de), a
    ;test.c:17: return tmp.ptr;
        ld  de, #_to_longptr_tmp_65536_64 + 0
        ld  a,(de)
        ldhl    sp, #0
        ld  (hl+), a
        inc de
        ld  a, (de)
        ld  (hl+), a
        inc de
        ld  a, (de)
        ld  (hl+), a
        inc de
        ld  a, (de)
        ld  (hl), a
        pop de
        push    de
        dec hl
        ld  a, (hl+)
        ld  h, (hl)
        ld  l, a
    ;test.c:18: }
        add sp, #4
        ret
    

    ps: but shouldn't it return the values loaded from the static struct? why copying to local variable?

     

    Last edit: Tony Pavlov 2020-05-24
  • Tony Pavlov

    Tony Pavlov - 2020-05-31

    maybe it is not clear what is wrong here. the initialization of a local static variable in my example depends on the parameters, that are passed into the function. when the initialization of tmp is moved to _GSINIT area, there can't be parameters of a function on the stack. so this "ldhl sp, #2" is completely wrong. the initialization of tmp may be moved to _GSINIT only if the whole initialization is constant.
    ps: static is better here because faster code is generated for that on gbz80 target (compared with the stack-allocated struct).

     
  • Philipp Klaus Krause

    What is wrong here is a missing diagnostic:
    SDCC should report

    error 2: Initializer element is not a constant expression
    

    instead of trying to generate some code. Interestingly, the problem seems to be related to union / struct: For a plain int, we get the expected error.

    P.S.: From the C standard (C2X draft N2479): "All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals."

     

Log in to post a comment.

Monday.com Logo