[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