Menu

[z80] code generator swaps endiannes of 16-bit quantities

alvin
2015-07-24
2015-07-25
  • alvin

    alvin - 2015-07-24

    Is there any chance that sdcc could correct endiannes when dealing with 16-bit quantities? It seems like sdcc prefers to operate in 8-bits but it's missing out on quite a few opportunities to perform tasks more quickly in 16-bits. I've had an eye on using the peepholer to correct some of these occurrences but it seems like sdcc deliberately reverses the endiannes of 16-bit numbers while generating code.

    here's an example:

        ld  h,a
        rla
        sbc a, a
        ld  l,a
        ld  a,h
        add a,#0xE0
        ld  h,a
        ld  a,l
        adc a,#0xFF
        ld  l,a
    ;;;;;;
        ld  -29 (ix),h
        ld  -28 (ix),l
        bit 7, l
        jr  Z,l_main_00136$
    

    This code snippet is taking a signed char in A, sign extending it, adding #ffe0 to it and storing the 16-bit result to a variable on the stack. It then tests the most significant bit of the 16-bit quantity to determine if it's positive.

    The bad part is sdcc is using LH, not HL, to hold the 16-bit quantity.

    I would like to replace the above code up to the semicolons with:

        ld  l,a
        rla
        sbc a, a
        ld  h,a
        ld  de,#0xFFE0
        add hl,de
    

    or similar.

    This is 4 bytes shorter and 9 cycles faster. Unfortunately in the replacement code, HL holds the 16-bit quantity while in sdcc's code it's LH. So a peephole rule will have to qualify the substitution by saying HL must be dead, which means this rule would not be applied in this case.

    To have the rule applied, I'd have to capture more context, such as the following store and the test for positive:

        ld  l,a
        rla
        sbc a, a
        ld  h,a
        ld  de,#0xFFE0
        add hl,de
    ;;;;;
        ld  -29 (ix),l
        ld  -28 (ix),h
        bit 7, h
    

    But now the rule is for a very specific circumstance where the 16-bit result is immediately stored and a branch is taken if the result is positive.

    It all comes down to sdcc reversing endianness, this happens a lot and it's not random as in sometimes it's reversed and sometimes it isn't. It's almost always reversed.

    The only reason I can see for sdcc reversing endianness (other than it's done for some big-endian target and has carried over to the little-endians) is sdcc's need to push chars onto the stack using the MSB of a 16-bit register. It then saves stack space by incrementing SP so only one byte is on the stack. (This is a bad idea on the z80 and I know this has been discussed on the dev list so this is not intended to regurgitate that discussion, only speculate as to why sdcc wants to put 8-bit quantities into the MSB of 16-bit register pairs).

    I'm just wondering if anyone has considered this as it would help to improve sdcc's output.

     
  • Maarten Brock

    Maarten Brock - 2015-07-25

    My guess is that the register allocator thinks both variants are equal and just always picks the first which happens to be LH.

     

Log in to post a comment.