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.
packages/debug-info/src/types.tsarrayLength()returns the product of a type'sDW_TAG_subrange_typedimensions, sou16 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,
LoadBGTileDatamatches only when the ROM table is declaredconst u8 gBgLayerLookup[][2][2]— the[2][2]shape is what makes agbcc fold a+1into the symbol (adds r0, r4, #1) instead of emittingldrb r0, [r0, #1]. With the dimensions flattened, asmlift emitsgBgLayerLookup[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 declaresextern u16 gBgTilemapBufs[4][0x400];, the map carries{"shape": "array", "elemSize": 2, "size": 8192}, so a single subscript is emitted and agbcc rejects it:u16[1024]assigned tou16[1024]is not an lvalue assignment. Note this only shows up in the headers world — a self-declaredextern 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[]— invariableShapeand in struct members, keepingarrayLength()as-is for callers that only want the total. Everything downstream then has what it needs to declareu16 g[4][0x400]and emit multi-subscript indexing.Related:
#memberLayoutalready 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.