|
From: | Paul Cercueil |
Subject: | Re: [Lightning] JIT_R11 trashed by jit_callr on MIPS32 |
Date: | Wed, 29 Oct 2014 22:49:08 +0100 |
User-agent: | Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Icedove/31.0 |
Hi, On 28/10/2014 22:30, Paulo César Pereira de Andrade wrote:
2014-10-28 16:38 GMT-02:00 Paul Cercueil <address@hidden>:Hi Paulo, thanks for the response. Comments inlined below.> I've been working for some time now on my spare time on a MIPS-to-Lightning dynamic recompiler: https://github.com/pcercuei/lightrec/ It looks very nice. On a quick look I only suggest not using JIT_RA0, as you should be aware it is not available on all ports, on ix86 parameters are passes on stack, and on ia64 the first register argument has a variable value.Thanks! But I know this very well. The problem is that I cannot use theI am afraid you will be hit by this: http://git.savannah.gnu.org/cgit/lightning.git/commit/?id=abf1b6e67811eecacc634e3f2e1a89d05c7d1884jit_pushargr/jit_pushargi macros as they make Lightning crash (with an assertion failure). This is because all my blocks of code are created without a jit_prolog/jit_epilog; if I were to use them, it would create an enormous amount of overhead as Lightning would save/restore the registers on the stack for every single block of code recompiled, while I handle that elsewhere (in the "wrapper" block).This should be what you need to make it fully portable, and remove most if not all overhead: http://git.savannah.gnu.org/cgit/lightning.git/commit/?id=839341a498b7b2077d715c2ca66d3debcddc0c30 I am delaying a bit release of lightning 2.0.6, as I hope to fix any possible issue with the GNU Smalltalk port to use it, but if you could test the current git, I would really appreciate, and jit_frame and jit_tramp may be exactly what you need.
From a quick look it looks exactly what I need, yes. Thanks a lot!But I can't build from the GIT, there's no ./configure and no m4 files to build it using autoconf, what am I missing?
Note that if you do the current approach, you are risking to have your code only working on a few (register rich) lightning backends, and will break on newer lightning, because (the undocumented) JIT_RA0 was removed, to avoid it being used, and writing non portable code :( Basically, the new interfaces are like this: jit_prolog(); jit_tramp(256); ... jit_epilog(); saves all callee save registers, creates a stack frame of 256 bytes for any arguments on stack or jit_allocai calls. And: jit_prolog(); jit_tramp(256); ... jit_epilog(); assumes the the prolog/epilog and frame. You must write code that jumps and return from there, that is, you can actually write the function body later.
I assume you meant jit_frame(256) on the former - but I get the idea.Is that stack area also used for parameter passing on x86, or just to save a snapshot of the register set?
> It abuses Lightning a little bit, in the way that it doesn't use functions - the generated code directly jumps to the next block of code, recompiling it if needed. It works fine on MIPS32 for now, except for one point: jit_callr trashes the JIT_R11 register... I am afraid this is expected :( > Here's a minimal test case: > > <paul:~/dev/gcw0/lightrec> $ cat minimal.c > #include <lightning.h> > > static void get_new_function(void) { return &end_execution; } > > int main(int argc, char **argv) > { > jit_state_t *_jit; > init_jit(argv[0]); > > _jit = jit_new_state(); > > jit_movi(JIT_R11, 54); > jit_movi(JIT_R0, &get_new_function); > jit_callr(JIT_R0); > > jit_retval(JIT_R0); > jit_addr(JIT_R0, JIT_R0, JIT_R11); > jit_jmpr(JIT_R0); > > jit_emit(); > jit_disassemble(); > jit_clear_state(); > jit_destroy_state(); > finish_jit(); > > return 0; > } > > The code basically sets the JIT_R11 register to 54, call "get_new_function", adds JIT_R11 to the value returned and jumps to that new address. > > This is what I obtain: > > opendingux:/media/data/local/home # ./minimal > 0x77295000 li t9,54 > 0x77295004 lui v0,0x40 > 0x77295008 ori v0,v0,0x9d0 > 0x7729500c move t9,v0 > 0x77295010 jalr v0 > 0x77295014 nop > 0x77295018 addu v0,v0,t9 > 0x7729501c jr v0 > 0x77295020 nop > > The LUI/ORI correspond the load of the address of get_new_function. The jalr is the jit_callr. But between those, the JIT_R11 (register $t9 here) is trashed for no good reason. > > My current workaround is to completely avoid the use of JIT_R11, but it would be great if it could be fixed :). Remember that JIT_R11 is not callee save, so, lightning is supposed to be allowed to clobber it. A backend specific comment should be added to the documentation about such special cases. t9 is the pic register. Lightning does not know if it is calling a pic C function so if the jit_callr argument is not t9, it will set it to the function pointer. A workaround in your code would be to know about that.Allright, I didn't know that. I knew about $gp (register #26) but not about $t9. Then I guess I will discard it when compiling on MIPS.It is dangerous to rely on non callee save registers not being clobbered. Even if it is calling a jit function. Alpha uses the pv (r27) register the same way, but the alpha port does not make it, register 27, a "visible" JIT_R(n). PowerPC clobbers r2 and r11, but also on ppc they are not made into a JIT_R(n). Hppa clobbers r1 and r19, again not made into a JIT_R(n). Mips was the first lightning port I made, so, maybe I should change it to not make JIT_R11 available?
Well I certainly didn't expect Lightning to use a JIT_R(n) register internally. I know that those can be trashed when calling C functions, but I assumed that they would never be trashed within the generated code.
I think that it would be better to avoid this problem, yes. JIT_R11 should be removed from the list of available registers. It's not a big deal on MIPS anyway, there are plenty of registers that can be used there.
Thanks, Paulo
Bye, Paul
[Prev in Thread] | Current Thread | [Next in Thread] |