Re: Understanding SNAP

  • From: Peter Cawley <corsix@xxxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Wed, 4 Oct 2017 23:07:47 +0100

On Wed, Oct 4, 2017 at 2:08 AM, Luke Gorrie <luke@xxxxxxxx> wrote:

Why don't side traces inherit the same register/stack assignments from the
parent trace? Couldn't the side trace accept that SLOAD#3 is in xmm3 instead
of shuffling it over to xmm7? (Wouldn't this solve the problem of aborting
traces due to excessively complex register/stack shuffling?)

In short, the problem is that LuaJIT assembles a trace in reverse
order. If it assembled in the "conventional" order, then it could
start from the register/stack assignments as of the parent exit, and
work forwards. Instead, it assembles in reverse order, and has to hope
that all of the choices it makes along the way result in a final state
which matches the parent exit. For register assignments, it does
actually make a small effort to make things line up (namely, when it
chooses a register for something, it considers the assignment in the
parent to be a hint). Stack assignments are much harder to try and
line up: if the child requires more stack space than the parent, then
"[rsp+X]" doesn't mean the same thing in the parent and the child, but
the difference in rsp between parent and child isn't known until
assembly of the child trace has finished, and references to "rsp+X"
need to be emitted _during_ assembly of the child trace.

More broadly: How come side trace code does not take the parent IR code
prefix into account during code generation? My understanding is that the
side trace only uses the parent trace to create a special SNAP#0 that
scavengers required local variables from the parent. This seems to be
discarding a bunch of information from the parent trace e.g. existing
register/stack assignments, guards that have already been checked,
computations that could feed CSE/DCE optimizations, etc.

I'm afraid that I've not given enough thought to the problem to give a
good answer.

Other related posts: