lightning
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Lightning] JIT_R11 trashed by jit_callr on MIPS32


From: Paulo César Pereira de Andrade
Subject: Re: [Lightning] JIT_R11 trashed by jit_callr on MIPS32
Date: Tue, 28 Oct 2014 19:30:37 -0200

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 the

  I am afraid you will be hit by this:
http://git.savannah.gnu.org/cgit/lightning.git/commit/?id=abf1b6e67811eecacc634e3f2e1a89d05c7d1884

> jit_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.

  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.

>>  > 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?

Thanks,
Paulo



reply via email to

[Prev in Thread] Current Thread [Next in Thread]