Files
BFM-decomp/cookbook/C0420.md
T

2.0 KiB

§379 ★★★ — MEM_IN_STRUCT_P: THE SAME LOAD, WRITTEN AS A STRUCT MEMBER, SCHEDULES WHERE A CAST CANNOT (P31 S69; byte-proven main/func_80021284 220 ins and main/func_8002D904 217 ins, found INDEPENDENTLY by two agents)

The symptom. A load sits below a store to a scalar global in your output and above it in the target (or vice versa), and no statement permutation moves it. func_80021284 sat at closeness 7 across a 120-order statement-permutation plateau; the fix took it straight to 0.

The mechanism. gcc-2.7.2's alias machinery asks true_dependence/anti_dependence whether a load may cross a store. Its answer turns on MEM_IN_STRUCT_P — the /s flag expand_expr sets on a MEM. A raw *(u32 *)(arg0 + N) load is a plain MEM: it may alias the scalar global, so the scheduler will not move it across that store. The same address read through a struct pointer (p->field) is /s, declared non-aliasing against a fixed scalar store, and floats freely.

*(u32 *)(arg0 + 0x18)   /* plain MEM  — pinned below the store to D_800xxxxx */
p->attr                 /* MEM_IN_STRUCT_P — free to hoist to the block top  */

The complement, same pass, opposite direction (func_8002D904, worth 26 of its 41 residuals): assigning an indexed table address to a pointer variable first makes the resulting INDIRECT_REF non-MEM_IN_STRUCT_P — gcc sets /s whenever "the address was computed by addition", so every array/cast spelling comes out /s+varying, and the load floats to the block top. Take the address into a local pointer when you need the load to STAY.

So the dial has two ends and both are zero-byte:

you want write it as
the load to FLOAT (cross a scalar store) a struct-member access through a pointer
the load to STAY take the address into a local pointer variable first

Related store-side note at src/800.c:21942 (W16). This is the alias-analysis sibling of §41b's "global load hoisted above the RTL prologue" wall — that one is unreachable; this one is a spelling.