We have e.g.:
invoke # implicitely P0 and use P1 for return # could also be a method call invoke P1 # likely a return
The implicit usage of P0 in function and method calls is a PITA for the register allocator, all this implicit usage causes special handling n code, so that P0 gets properly tracked.
Additionally, P0 and especially P1 is first created in the callers registers. This implies that the old contents of P1 has to be preserved by copying to another register, which increases pressure on the register allocator. The same is done for P2 in method calls. This scheme just reduces the usable register count by 3 in methods and by 2 in functions.
To streamline that and take advantage of the current_* pointers in the context, I'd like to adapt call/return ops slightly:
invoke PSub, PRet # replaces implicit P0, P1 handling invokecc PSub # replaces implicit invokecc [P0] callmethod Pobj, Smeth, Pret # analog, no implicit S0 callmethodcc Pobj, Smeth ret_cc # replaces invoke P1
This gets rid of all hidden register semantics of these opcodes and makes it explicit for the register allocator (and when reading the code), which registers are used. As a minor improvement it also avoids the "set P0, PSub" and such opcodes, to move the needed registers in place.
In the called subroutine P2 remains "self". But P0 and P1 (current sub and continuation) are available only on demand, currently with the interpinfo opcode. Maybe two opcodes for that are in order too:
get_sub Px # simplifies coroutines get_cc Px # simplifies call/cc
leo