Menu

#3387 SDCC generates invalid opcode "jp NZ, (hl)" for calling a function pointer

closed-fixed
gbz80 (9)
Z80
5
2022-06-15
2022-05-13
bbbbbr
No

SDCC : z80/sm83/mos6502 4.2.2 #13350 (Linux)

For the gbz80/sm83: when conditionally calling a function pointer retrieved from an array, SDCC will generate an invalid opcode: jp NZ,(hl).

This causes the linker to fail with:
?ASlink-Warning-Undefined Global 'hl' referenced by module 'main'

  • The error does not happen if the function pointer is directly retrieved with:
    void (*p_func)(void) = &some_func;

  • The error also does not happen if the variable used to store the function pointer is a global or static local.

Minimal example:

void some_func(void) {
}

void (*func_list[])(void) = {
    &some_func
};

void main(void)
{

    void (*p_func)(void) = func_list[0];
    if (p_func)
        (*p_func)();
}

Relevant ASM output

;main.c:13: void (*p_func)(void) = func_list[0];
    ld  hl, #_func_list
    ld  a, (hl+)
    ld  c, a
    ld  a, (hl)
    ld  l, c
;   spillPairReg hl
;   spillPairReg hl
    ld  h, a
;   spillPairReg hl
;   spillPairReg hl
;main.c:14: if (p_func)
    or  a, c
;main.c:15: (*p_func)();
    jp  NZ,(hl)
;main.c:17: }

Discussion

  • Philipp Klaus Krause

    Looks like z80 is affected, too.
    Workaround until the bug is fixed: --no-peep.

     

    Last edit: Philipp Klaus Krause 2022-05-14
  • Sebastian Riedel

    • assigned_to: Sebastian Riedel
     
  • Sebastian Riedel

    Peephole rules 79 - 82 are bugged. They don’t check if the second jump goes to a label.
    It only gets triggered now because jp (hl) gets generated more.

        or  a, c
        jp  Z, 00103$
        call    ___sdcc_call_hl
    00103$:
        ret
    

    became

        or  a, c
        jp  Z, 00103$
        jp  (hl)
    00103$:
        ret
    
     
  • bbbbbr

    bbbbbr - 2022-06-06

    Good to know that --no-peep is a usable workaround, though being able to have the peephole rules enabled would be nice

     
  • Maarten Brock

    Maarten Brock - 2022-06-07

    Would it not be enough to change the condition of those rules to
    } if operandsNotRelated(%2 'hl' 'ix' 'iy'), labelRefCountChange(%1 -1)

     
    • Sebastian Riedel

      Turning

      replace restart {
          jp  NC,%1
          jp  %2
      %1:
      } by {
          jp  C,%2
          ; common peephole 79 removed jp by using inverse jump logic
      %1:
      } if labelRefCountChange(%1 -1)
      

      into

      } by {
          jp  C,%2
          ; common peephole 79 removed jp by using inverse jump logic
      %1:
      } if operandsNotRelated(%2 '(hl)' '(ix)' '(iy)'), labelRefCountChange(%1 -1)
      

      might suffice, yes.

       
  • Maarten Brock

    Maarten Brock - 2022-06-15
    • status: open --> closed-fixed
    • assigned_to: Sebastian Riedel --> Maarten Brock
    • Category: GBZ80 --> Z80
     
  • Maarten Brock

    Maarten Brock - 2022-06-15

    Fixed in SDCC [r13503].

     

    Related

    Commit: [r13503]

  • Maarten Brock

    Maarten Brock - 2022-06-15

    On a related note: what is the difference between common z80 peephole rule 85a and 88?

     
    • Sebastian Riedel

      Looks like a duplicate.

       

Log in to post a comment.