Skip to content

arrayLength() destroys per-dimension shape, which blocks multi-dimensional array recovery downstream #8

Description

@macabeus

packages/debug-info/src/types.ts arrayLength() returns the product of a type's DW_TAG_subrange_type dimensions, so u16 g[4][0x400] reaches a consumer as a flat count of 4096 with the dimensions gone.

That is fine for sizing, but it is lossy in a way consumers cannot recover, and it is currently the top blocker for asmlift's biggest matching gap.

Where it bites

In a real decomp. On Klonoa: Empire of Dreams, LoadBGTileData matches only when the ROM table is declared const u8 gBgLayerLookup[][2][2] — the [2][2] shape is what makes agbcc fold a +1 into the symbol (adds r0, r4, #1) instead of emitting ldrb r0, [r0, #1]. With the dimensions flattened, asmlift emits gBgLayerLookup[0][0][(a1<<1)+(a0<<2)] or abandons the array entirely for *(u8 *)(… + ((u32)&g + 1)). That output scores 24; the correctly-shaped declaration scores 0.

In asmlift's benchmark, it is the sole cause of both of its noncompile rows (kleod:CopyBGScrollTiles, kleod:UpdateHUDCounterDisplay). The project header declares extern u16 gBgTilemapBufs[4][0x400];, the map carries {"shape": "array", "elemSize": 2, "size": 8192}, so a single subscript is emitted and agbcc rejects it:

in.i:1081: incompatible types in assignment      # gBgTilemapBufs[594] = gBgTilemapBufs[659];

u16[1024] assigned to u16[1024] is not an lvalue assignment. Note this only shows up in the headers world — a self-declared extern u16 g[]; is 1-D and consistent with 1-D indexing, which is exactly why it went unnoticed.

What would fix it

Report the dimensions alongside the flat length — e.g. dims: number[] — in variableShape and in struct members, keeping arrayLength() as-is for callers that only want the total. Everything downstream then has what it needs to declare u16 g[4][0x400] and emit multi-subscript indexing.

Related: #memberLayout already returns {offset, size, bitOffset, bitWidth} with both DWARF 2/3 bit-numbering conventions normalised, so the precedent for reporting structural facts rather than a collapsed scalar is already there.

Found while dogfooding gba-kit, asmlift and Transmuter together on a decomp round.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions