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.