2.7 KiB
§250 — %hi/%lo vs lw: THE EXTERN'S ARRAY-vs-SCALAR SHAPE DECIDES ADDRESS MATERIALISATION (P31 S58b)
The single most common type-level residual in this harvest, worth one instruction each time.
| target shows | the extern must be | why |
|---|---|---|
lui/addiu pair, no load |
an array (extern T D_x[];) or &scalar |
array decay is a link-time constant gcc folds straight into the pair |
lui/lw pair |
a scalar of pointer/word type | the address is materialised, then dereferenced |
lui $at + addu $at,$at,idx + %lo(...) load |
an array indexed in C | keeps the index in the addressing mode |
separate lui per adjacent byte/half |
distinct scalar objects (§216) | one array collapses them to one base |
Cards. func_8017DE00 (ov_SC07_000): extern s32 D_801D0C78[] — as a plain s32 it emitted lw $a0,0($a0) where the target wants lui/addiu. func_801826CC (ov_SC03_002): declaring a
function-pointer table as a scalar void (*D)(void) forced a load path; extern void (*D_80189CFC[])(void) folds the address directly, including under | 0x40000000. func_80185B7C:
the fleet row prints a value type while the use site takes the address — the tell is whether the
symbol feeds an addiu/lui pair or a load. func_8017FCBC, func_8017D68C, func_80186C70,
func_8018372C, func_80183C24 all repeat it.
AND THE &-vs-DECAY DISTINCTION IS REAL. func_8018269C (ov_SC05_018): (u32)&D_8018AFC0 | 0x40000000 emits an extra move (the la is forced through a pseudo); the array-decay form
(u32)D_8018AFC0 | 0x40000000 gives the target's exact lui/addiu/or chain. Nearest prior art is
§162c's constant-OR rules, which do not mention the la-vs-decay distinction.
THE INVERSE — WHEN THE ARRAY DECL IS UNUSABLE (§216 confirmed). func_8018BB44 (ov_SC04_011,
49/49): the card's authoritative D_801EFEA0 as u8[] makes gcc materialise ONE base and address all
four bytes off it — 43 ins vs the target's 49. The target does an independent lui/lbu/sb
triple per byte, which only falls out when each byte is a distinct scalar object (block-scoped
extern u8 with an explicit __asm__ name), plus a separate u8 *flag = &scalar3; to force the
entry-time $a0 materialisation. func_801AA2F8 (md_SC07_004) is the same finding: the TU's
Blk4_801A7358 D_801F88B8 decl cannot be used for the three per-byte stores without collapsing the
luis.
BOUNDARY. When a symbol's address is only ever formed (never loaded, never indexed), the object type is codegen-neutral — pick the fleet/TU spelling and move on. The dial only bites when a load, an index, or an adjacent sibling symbol is involved.