lightning
[Top][All Lists]
Advanced

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

Re: [Lightning] jit_qdivr_u trashes JIT_R0 on x86_64


From: Marc Nieper-Wißkirchen
Subject: Re: [Lightning] jit_qdivr_u trashes JIT_R0 on x86_64
Date: Wed, 4 Sep 2019 16:23:30 +0200

Hi Paulo,

Am Mi., 4. Sept. 2019 um 15:04 Uhr schrieb Paulo César Pereira de
Andrade <address@hidden>:
>
> Em qua, 4 de set de 2019 às 03:37, Marc Nieper-Wißkirchen
> <address@hidden> escreveu:
>
>   Hi Marc,
>
> > >   I believe the function your code calls is to avoid inlining identical 
> > > code,
> > > if that is the case, you could use a simple block of code, to avoid the
> > > prolog/epilog cost. If it is a C function, the compiler should generate
> > > an optimized version, or you could write it in assembly.
> > >
> > >   For example, using the new 'live' wrapper (btw, in this specific
> > > example, using 'live' is not required, because it understands %r0 is
> > > live due to using it as a printf argument):
> > > """
> > > #define USE_JMPR    1
> > > .data    16
> > > fmt:
> > > .c    "%d %d %d\n"
> > > .code
> > >     jmpi main
> > > helper:
> > >     movi %v1 5
> > >     movi %v2 7
> > > #if USE_JMPR
> > >     jmpr %v0
> > > #else
> > >     jmpi label
> > > #endif
> > > main:
> > >     prolog
> > >     movi %v1 2
> > >     movi %v2 3
> > >     addr %r0 %v1 %v2
> > > #if USE_JMPR
> > >     movi %v0 label
> > > #endif
> > >     jmpi helper
> > > label:
> > > #if USE_JMPR
> > >     live %r0
> > > #endif
> > >     qdivr %v1 %v2 %v2 %v1
> > >     prepare
> > >         pushargi fmt
> > >         ellipsis
> > >         pushargr %r0
> > >         pushargr %v1
> > >         pushargr %v2
> > >     finishi @printf
> > >     ret
> > >     epilog
> > > """
> > >
> > >   Suppose 'helper' above is a common code, then, your code can
> > > just jump to the common code, and from the common code, jump
> > > back; you might also make it inside a jit function, because if the
> > > common code needs to spill/reload a temporary, it must have
> > > a stack frame, in that case, just create an block only reachable
> > > from a jump to the common code.
> > >   If the address to jump back is known, the helper code can jump
> > > back to it, allowing lightning to follow the jump and understand the
> > > live registers, otherwise, can use jmpr, passing the 'jump back'
> > > address in a register.
> > >   jmpr allows flexibility in that kind of construct, as well as different
> > > approaches for dispatch tables.
> > >   Another alternative is to use jit_tramp and jit_frame. See 
> > > check/tramp.tst
> > > or check/ctramp.c for an example, implementing a Fibonacci number
> > > calculator and tail call optimized code.
> >
> > To which extent is code like your example code guaranteed to work,
> > Paulo? For example, could we mark *all* registers live after "jmpi
> > helper"?
>
>   Lightning might run out of registers, cause an assertion and return
> JIT_NOREG. If lightning it compiled with -DNDEBUG the assertion
> will become a noop and it will generate invalid code, after several
> assertions of an invalid register.
>
> > On some ports, like x86_64, a jmpi instruction needs a scratch
> > register, and when all registers are marked live after jmpi, the only
> > way to get a scratch register is to spill one live register before the
> > jmpi and reload it afterward.
>
>   When it cannot spill/reload, it calls jit_get_reg with the
> jit_class_nospill flag, and if there are no free registers it fails as
> described above.

Thank you for this information.

Would it be enough to ensure that there is at least one non-live
register around instructions with non-local control flow so that this
assertion is never triggered? (A code generator using GNU lightning as
a backend must never cause this assertion being triggered or it would
be buggy.)

>
> > Does GNU lightning work this way?
> >
> > I have another question about your code: In the above example, the
> > callee-saved registers JIT_Vx are used to hold parameters for the
> > handler subroutine. Is it also possible to declare a caller-saved
> > register to use as an argument (in-going and/or out-going) for the
> > handler?
>
>     Not any kind of formal declaration, but it can use it in any way. It

Okay, if I understood correctly this means that in a code like the
following, the register R0 can be used to safely transfer parameters
to and, in case it jumps back, from the handler procedure.

jmpi handler
live (JIT_R0)

> is just inventing its own ABI. Using JIT_Vx for in/out arguments makes
> things simpler because they are not scratch registers, so, they are not
> clobbered in function calls. Note that the example is not a function
> call, but a jump to a common thunk only accessible with a jump. And
> as previously described, this thunk would be better inside a prolog/epilog
> pair, because if it needs to spill/reload a temporary, it will again
> cause an assertion, due to not having a stack frame.

This, I understand and this is also how I have setup my code.

Cheers,

Marc

>
> > Cheers,
> >
> > Marc
>
> Thanks,
> Paulo



reply via email to

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