Skip to main content

Module optimize

Module optimize 

Source
Expand description

A cheap cleanup round for freshly lifted code.

SLEIGH expresses an instruction’s semantics through unique (temporary) space: an intermediate result is stored to a temporary and immediately loaded back. Lifting add eax, ebx produces around forty QCode operations, roughly half of which are this round trip:

i32 %tmpe  = %eax_3 ^ %ebx_3;
store($temp1:4, 0 <- %tmpe);
i32 %tmp10 = load($temp1:4, 0);   // reloads what was just stored

Plain dead-code elimination cannot touch this — the store has a user, and the load has users — so the interpreter re-executes the whole round trip on every pass over the block. Forwarding the stored value to the load removes both.

This is deliberately the limited version of store-to-load forwarding, not mem2reg: it is block-local, needs no alias analysis, and is linear in the size of the block, so it can run on every lifted block without reintroducing the quadratic cost that a whole-function pass would.

§Why this is sound

Only temporary spaces are forwarded. A SLEIGH unique is scratch private to one instruction’s semantics: it is written before it is read and does not outlive the block, so no other block, and no guest-visible memory access, can observe it. Registers and RAM are left alone, since a call, a fault handler, or another block legitimately observes those.

Two further restrictions keep it honest:

  • A load is forwarded only when it matches the last store to that space and has the same width. A narrower or wider access is left alone rather than guessed at.
  • A store through a non-constant pointer clears what is known about that space, since it may land anywhere in it.

Structs§

Cleanup
What one cleanup round changed.

Functions§

forward_temp_stores
Forwards temporary-space stores to the loads that read them back, in block_id only.