Given my previous sample input of:
void Test() { int test = 12 + 5 * 4 - 100 / 50;}
I now get (Comments mine):
func Test{ mov r0, 100 div r0, 50 push r0 mov r0, 5 ; mul r0, 4 ; mov r1, r0 ; *Cough* mov r0, 12 ; add r0, r1 ; pop r1 sub r0, r1 mov test, r0}
Next stage
Next up is compile time evaluation of operators. I know that r0 contains 100 at the start there, so I can substitute r0 for 100 until it's written to. My ICodeNodeOpBinary class tells me that the div instruction writes to (and reads from) r0, so I stop substituting r0 there. My ICodeNodeOpBinary class is able to evaluate any opcode, if the two values are constant (Or it will shortly), so it evaluates it to mov r0, 2. r0 isn't read from between it's initialisation on the first opcode and it's termination on the second one, so that opcode can be dropped entirely. Going through all the code doing that should give me:
func Test{ mov r0, 2 push r0 mov r0, 32 pop r1 sub r0, r1 mov test, r0}
The bit commented in the code above should optimise away nicely, since:
; Original: mov r0, 5 mul r0, 4 mov r1, r0 mov r0, 12 add r0, r1; After first substitution (mov r0, 5): mov r0, 20 mov r1, r0 mov r0, 12 add r0, r1; After second substitution (mov r0, 20): mov r1, 20 mov r0, 12 add r0, r1; After third substitution (mov r1, 20): mov r0, 12 add r0, 20; After fourth substitution (mov r0, 12): mov r0, 32; mov r0, 32 can then be substituted elsewhere
And that should all work our automatically, since I go through the I-code nodes in order.
func Test{ mov r0, 2 push r0 mov r0, 32 pop r1 sub r0, r1 mov test, r0}
; Original: mov r0, 5 mul r0, 4 mov r1, r0 mov r0, 12 add r0, r1; After first substitution (mov r0, 5): mov r0, 20 mov r1, r0 mov r0, 12 add r0, r1; After second substitution (mov r0, 20): mov r1, 20 mov r0, 12 add r0, r1; After third substitution (mov r1, 20): mov r0, 12 add r0, 20; After fourth substitution (mov r0, 12): mov r0, 32; mov r0, 32 can then be substituted elsewhere
Later on
Once the mov's and opcodes have been evaluated, I should be able to do away with mov-push pairs. E.g:
; Original:func Test{ mov r0, 2 push r0 mov r0, 32 pop r1 sub r0, r1 mov test, r0}; Becomes:func Test{ push 2 mov r0, 32 pop r1 sub r0, r1 mov test, r0}
func Test{ mov r1, 2 mov r0, 32 sub r0, r1 mov test, r0}
Anyway, once this is all done, it should boil down to:
mov test 30
Then I need to test the living crap out of it [smile]
Todo list
- Source code annotation as comments
- Make the VM support stack offsets for variables. Maybe just a simple mov command that'll grab a stack index into a register, that should need the least modification. movstack or something I think.
- Proper control structures. There's no support for anything like if, while, for, return, whatever. They should be a piece of piss to implement though. And hopefully it won't need much optimising.
- Dead code removal. Control structures can be optimised away if the expression can be evaluated at compile time.
Anyway, back to work for now...
Jack