Angel Faus wrote:

Saturday 22 February 2003 16:28, Leopold Toetsch wrote:

With your approach there are three levels of parrot "registers":

- The first N registers, which in JIT will be mapped to physical registers.

- The others 32 - N parrot registers, which will be in memory.

- The "spilled" registers, which are also on memory, but will have to be copied to a parrot register (which may be a memory location or a physical registers) before being used.


Spilling is really rare, you have to work hard, to get a test case :-) But when it comes to spilling, we should do some register renumbering (which is the case for processor registers too). The current allocation is per basic block. When we start spilling, new temp registers are created, so that the register life range is limited to the usage of the new temp register and the spill code.
This is rather expensive, as for one spilled register, the whole life analysis has to be redone.



I believe it would be smarter if we instructed IMCC to generate code that only uses N parrot registers (where N is the number of machine register available). This way we avoid the risk of having to copy twice the data.


I don't think so. When we have all 3 levels of registers, using less parrot registers would just produce more spilled registers.

Actually, I'm currently generating code that uses 32+N registers. The processor registers are numbered -1, -2 ... for the top used parrot registers 0, 1, ... But the processor registers are only fixed mirrors of the parrot registers.


This is also insteresting because it gives the register allocation algorithm all the information about the actual structure of the machine we are going to run in. I am quite confident that code generated this way would run faster.


All the normal operations boil down basically to 2 different machine instruction types e.g. for some binop <op>:

   <op>_rm or <op>_rr (i386)
   <op>_rrr (RISC arch)

These are surrounded by mov_rm / mov_mr to load/store non mapped processor registers from/to parrot registers, the reg(s) are some scratch registers then like %eax on i386 or r11/r12 for ppc.

s. e.g. jit/{i386,ppc}/core.jit

So the final goal could be, to emit these load/stores too, which then could be optimized to avoid duplicate loading/storing. Or imcc could emit a register move, if in the next instruction the parrot register is used again.
Then processor specific hints could come in, like:
shr_rr_i for i386 has to have the shift count in %ecx.


We also need tho have a better procedure for saving and restoring spilled registers. Specially in the case of JIT compilation, where it could be translated to a machine save/restore.


I don't see much here. Where should the spilled registers be stored then?


What do you think about it?


I think, when it comes to spilling, we should divide the basic block, to get shorter life ranges, which would allow register renumbering then.


-angel

leo




Reply via email to