-
Notifications
You must be signed in to change notification settings - Fork 7
Description
Currently we do all arithmetic in 16-bit, even when the operands and destination are 8-bit (i.e. char types). This is a very single-pass-compiler and C thing to do (surely this is what the usual arithmetic conversions were designed for), but since uxn has native 8-bit operations and a limited stack size, it's neither efficient nor makes for particularly æsthetically-pleasing assembly. This will get worse if we start doing sign extension when promoting char to int (see #9).
So, it would be nice if (char)(some_char * 2 + 3) could be codegen'd as #02 MUL #03 ADD rather than #0002 MUL2 #0003 ADD2. As I see it there's two ways this could be done: in a “single-pass” fashion by changing the codegen step, or with some sort of later optimisation pass.
I am optimistic about the former approach. I think we could do it by propagating cast/conversion information downwards when doing codegen for expressions.
Currently the codegen behaviour is something like:
- When encountering
(char)(some_char * 2 + 3):- Recurse to generate
(some_char * 2 + 3)- Recurse to generate
some_char * 2- Recurse to generate
some_char- Output code for loading
some_char - Output code to extend to
int(something like00 SWP)
- Output code for loading
- Recurse to generate
2- Output
0002
- Output
- Output
MUL2
- Recurse to generate
- Recurse to generate
3- Output
0003
- Output
- Output
ADD2
- Recurse to generate
- Output code to truncate to
char(something likeNIP) - Output code to extend to
int(something like00 SWP)
- Recurse to generate
In the new system there would be a new flag used in expression codegen, something like truncate_to_byte. Now the behaviour would look something like:
- When encountering
(char)(some_char * 2 + 3):- Recurse to generate
(some_char * 2 + 3)withtruncate_to_byteset- Recurse to generate
some_char * 2withtruncate_to_byteset- Recurse to generate
some_charwithtruncate_to_byteset- Output code for loading
some_char Output code to extend toint(something like00 SWP)
- Output code for loading
- Recurse to generate
2withtruncate_to_byteset- Output
020002
- Output
- Output
MULMUL2
- Recurse to generate
- Recurse to generate
3withtruncate_to_byteset- Output
030003
- Output
- Output
ADDADD2
- Recurse to generate
Output code to truncate tochar(something likeNIP)- Output code to extend to
int(something like00 SWP) but only iftruncate_to_byteis not set
- Recurse to generate
A more tricky case is something like (char)((1 << 8) >> 8), where we can't use 8-bit operations all the way down. That can be handled by not propagating truncate_to_byte when dealing with such operators.
An important thing to note here is that it's strictly a codegen optimisation: the type information isn't affected. I don't think it's possible to do the same trick during type assignment instead, it would break things.