2014-08-18 10:59 GMT-03:00 Paul Cercueil <address@hidden>:
Hi,
Hi,
I am currently developing a simple MIPS-to-everything dynamic recompiler
based on Lightning. The recompiler generates blocks of machine code that are
meant to be chained: each block jumps to the following one. This is what I
want to do (MIPS code):
# lightrec_emit_end_of_block:emitter.c:37
0x77d97060 move a0,s6
0x77d97064 lui t9,0x77d7
0x77d97068 ori t9,t9,0x2198
0x77d9706c jalr t9
0x77d97070 nop
0x77d97074 jr v0
0x77d97078 nop
This code should never crash, but you are probably having trouble
with save/reload in elsewhere.
I suggest making sure to test with lightning built with --enable-assertions,
so that it would tell when/where there is a fault.
lightning 2.x has a simple register allocator, and requires entering/leaving
the jit as a function call, so that it knows and can handle "bounds" of live
registers.
Basically, jump to a C function that will return the address of the next
block of code (optionally compile it beforehand), then jump to the address
returned.
The problem is that Lightning will segfault when generating this code, as
soon as jit_calli() is executed. Apparently, jit_prolog() and jit_epilog()
are required for jit_calli() to work.
For mips this should work if using only to JIT_Rn, and not using too much
complex constructs with too long live ranges for JIT_Rn (or it could allocate
a callee save as a temporary). It probably is crashing because some JIT_Vn
is being changed, and without a prolog/epilog it cannot save (in prolog)
and reload (in epilog) the callee save register.
However, if I add jit_prolog() and jit_epilog(), Lightning will generate
some code to save/restore registers, while I don't want that. This is
especially bad since the epilog will never be reached (as the code jumps to
another block), so the stack pointer will decrease at each prolog but never
increase.
I suggest you make some benchmarking to make sure it really is
better to not use a function call sequence. If no callee save registers
are changed, it would be basically a sub/dec of the sp register.
But would be better if you could construct the jit to avoid jumps
for every small chunk; the major point of jit is avoiding branches
and jumps, usually at the cost of some code duplication.
What I would need, are either variants of jit_prolog() and jit_epilog()
which don't save/restore the registers on the stack, or alternatively to
have jit_calli() not require jit_prolog().
Do you have suggestions on how to fix this issue?
There is a lightning 1.2 compatible mips port at
https://github.com/pcpa/lightning that probably will work for the need
you describe; main difference should be right to left argument
pushing (to match lightning 1.2 api).
Thanks,
-Paul
Paulo