Good evening,
I am trying to implement rtrackUpdate() for Z80.
(I will probably have questions about this later...)
While testing, I came across a case of dead code being generated.
I made it so that a conditional jump not taken adds new knowledge about the CPU state. In this case, the new knowledge (bit 7 of D is set) conflicts with existing knowledge (D is zero), which I assumed indicated an error on my part, but it turns out that it indicated dead code.
...addhl,hladdhl,hlex(sp),hlldd,#0x00 ; load D with zeroldc,e;doesnotaffectDldb,d;doesnotaffectDbit7,d;testbit7ofD,whichweknowisnotsetjpZ,00103$;thereforthisjumpisalwaystakenldc,e;soldb,d;thisincbc;codeincbc;isincbc;dead00103$:srab;hereitstartsa16-bitrightshiftby2rrcsrab...
I guess that it wants to treat arg1 as a 16-bit signed int in performing arg1 / 4, since it has already decided that 4 is a 16-bit signed int, and the bit 7 test is to determine whether it is negative.
This is a bit unfortunate, since at compile time it is known that 4 is not negative, and fits in 8 bits, and the other operand of the division is unsigned 8 bit.
If I change 4 to 4u, making it explicitly unsigned, the dead part goes away:
idx = 60 * arg2 + arg1 / 4u;
...
add hl, hl
add hl, hl
ld b, #0x00
srl b
rr c
srl b
rr c
add hl, bc
...
If I cast 4 to an unsigned char, the 16-bit shift becomes an 8-bit shift:
idx = 60 * arg2 + arg1 / (unsigned char)4;
...
add hl, hl
add hl, hl
srl c
srl c
ld b, #0x00
add hl, bc
...
... this looks much nicer.
Regards,
-Job
Edit to add: I am on 13724, which is HEAD at time of writing this.
Last edit: Job Bolle 2022-09-26
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
When wondering why asm is geneated (in particular, which istruction comes from which part of the input), it is often helpful to try --no-peep, --fverbose-asm, --i-code-in-asm or a combination thereof.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
geniCodeDivision() can do a simple right shift if left is unsigned and right is a power of two, but usualBinaryConversions() makes left signed if right is signed, as it casts both operands to the result type.
The test for unsignedness of left could be done on the original left before it gets cast by usualBinaryConversions.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Good evening,
I am trying to implement rtrackUpdate() for Z80.
(I will probably have questions about this later...)
While testing, I came across a case of dead code being generated.
I made it so that a conditional jump not taken adds new knowledge about the CPU state. In this case, the new knowledge (bit 7 of D is set) conflicts with existing knowledge (D is zero), which I assumed indicated an error on my part, but it turns out that it indicated dead code.
The following C code:
Generates the following Z80 code:
I guess that it wants to treat arg1 as a 16-bit signed int in performing arg1 / 4, since it has already decided that 4 is a 16-bit signed int, and the bit 7 test is to determine whether it is negative.
This is a bit unfortunate, since at compile time it is known that 4 is not negative, and fits in 8 bits, and the other operand of the division is unsigned 8 bit.
If I change 4 to 4u, making it explicitly unsigned, the dead part goes away:
If I cast 4 to an unsigned char, the 16-bit shift becomes an 8-bit shift:
... this looks much nicer.
Regards,
-Job
Edit to add: I am on 13724, which is HEAD at time of writing this.
Last edit: Job Bolle 2022-09-26
When wondering why asm is geneated (in particular, which istruction comes from which part of the input), it is often helpful to try --no-peep, --fverbose-asm, --i-code-in-asm or a combination thereof.
geniCodeDivision()
can do a simple right shift if left is unsigned and right is a power of two, butusualBinaryConversions()
makes left signed if right is signed, as it casts both operands to the result type.The test for unsignedness of left could be done on the original left before it gets cast by usualBinaryConversions.
This gets rid of the negativity test and the conditional addition:
I'm still looking into the best and most proper way to use 8-bit instead of 16-bit arithmetic when possible.