diff --git a/code/duffle/gte.atom.c b/code/duffle/gte.atom.c index 438c0ad..1754025 100644 --- a/code/duffle/gte.atom.c +++ b/code/duffle/gte.atom.c @@ -275,7 +275,7 @@ typedef Struct_(RegUse_build_normalize_v3s4) { Reg scratch; /* scratchpad base; loaded via load_word_imm below. */ Reg src_ptr; Reg dst_ptr; - Reg recip_est; /* |v|² sum + shift-input + sqrtbl[index] */ + Reg recip_est; /* |v|² sum + shift-input + sqrtbl[index] */ Reg norm; Reg shift; Reg src_x; union { Reg mac1_scratch, dst_offset; } t3; @@ -372,7 +372,7 @@ atom_info(atom_bind(Binds_gte_cross_v3s4)) MipsAtom_Proc_(aa, { load_word(r.y.src_a, R_TapePtr, O_(Binds_gte_cross_v3s4,src_a)), load_word(r.z.src_b, R_TapePtr, O_(Binds_gte_cross_v3s4,src_b)), load_word(r.x.out, R_TapePtr, O_(Binds_gte_cross_v3s4,out)), - LdSlot_ add_ui_self(R_TapePtr, S_(Binds_gte_cross_v3s4)), + LdSlot_ add_ui_self( R_TapePtr, S_(Binds_gte_cross_v3s4)), mac_load_v3s4(r.a, r.y.src_a, 0), LdSlot_ mac_load_v3s4(r.b, r.z.src_b, 0), LdSlot_ diff --git a/code/duffle/lottes_tape.h b/code/duffle/lottes_tape.h index 1572047..9c219d3 100644 --- a/code/duffle/lottes_tape.h +++ b/code/duffle/lottes_tape.h @@ -97,8 +97,8 @@ enum { R_Atom5 = R_T5, R_Atom6 = R_T6, R_Atom7 = R_T7, - R_Atom8 = R_T8, - R_Atom9 = R_T9, + R_Atom8 = R_T8, + R_Atom9 = R_T9, R_Atom10 = R_V0, // Tend to be used with gte DMAs R_Atom11 = R_V1, // Tend to be used with gte DMAs R_Atom12 = R_A0, @@ -383,8 +383,8 @@ FI_ Reg regfile__alloc_helper(A2_U2 file, Reg r_id) { * any of them while R0, R1, R26-R31 remain reserved. */ I_ Reg regfile_alloc(RegFile_R rf) { Reg allocated = 0; - for index_iter(U4, idx, 0, <, Array_len(regfile_alloc_order)) { - allocated = regfile__alloc_helper(rf->GPR, idx); + for index_iter(U4, r_id, R_V0, <, R_T9) { + allocated = regfile__alloc_helper(rf->GPR, r_id); Jmp_nZero_(allocated,resolved); } assert(allocated != 0); diff --git a/code/hello_camera/hello_camera.atom.c b/code/hello_camera/hello_camera.atom.c index ac1d4d1..67b2941 100644 --- a/code/hello_camera/hello_camera.atom.c +++ b/code/hello_camera/hello_camera.atom.c @@ -111,66 +111,59 @@ typedef AtomBundle_(resolve_look_at) { MipsAtom *pop_mv_trans; }; -enum { - // TODO(Ed): We can resolve scratch at anytime its fixed to a specific address. - R_ResolveScratch = R_T4 atom_reg atom_type(U4*), -#define R_ResolveScratch_Code R_T4_Code +typedef Struct_(ResolveLookAtScratch) { + V3_S4 fwd; + V3_S4 uz; + V3_S4 right; + V3_S4 ux; + V3_S4 up; + V3_S4 uy; + P3_S4 eye; + P3_S4 target; + V3_S4 up_in; }; + +/* Binds_ResolveLookAtSub — what the C side pushes onto the tape before input_and_sub. + * The scratchpad base is no longer pushed because R_ScratchBase (= R_SP) is a tape carrier + * preserved across atoms; the atom body reads 0x1F800000 directly from R_SP. */ typedef Struct_(Binds_ResolveLookAt) { MT3_S2S4* look_at; P3_S4* eye; P3_S4* target; V3_S4* up_in; }; - -/* ─── ResolveLookAtScratch — offset schema for the resolve_look_at bundle's */ -typedef Struct_(ResolveLookAtScratch) { - V3_S4 fwd; /* offset +0 (16 bytes — 4 S4 fields incl. internal pad) */ - V3_S4 uz; /* offset +16 (16 bytes) */ - V3_S4 right; /* offset +32 (16 bytes) */ - V3_S4 ux; /* offset +48 (16 bytes) */ - V3_S4 up; /* offset +64 (16 bytes) */ - V3_S4 uy; /* offset +80 (16 bytes) */ - P3_S4 eye; /* offset +96 (16 bytes; storage alias of V3_S4) */ - P3_S4 target; /* offset +112 (16 bytes; storage alias of V3_S4) */ - V3_S4 up_in; /* offset +128 (16 bytes) */ -}; - typedef Struct_(Binds_ResolveLookAtSub) { P3_S4* target; - P3_S4* eye; + P3_S4* eye; V3_S4* up_in; - ResolveLookAtScratch* scratchpad; }; typedef Struct_(RegUse_resolve_look_at_input_and_sub) { - Reg scratch; Reg target; Reg eye; Reg up_in; Reg t0; Reg t1; Reg t2; Reg t3; Reg t4; }; /* Atom 0 in the bundle: input_and_sub. Stages C-side inputs into the scratchpad and computes fwd = target - eye. */ -internal MipsAtom* AtomBundleEntry_(resolve_look_at,input_and_sub)(AtomArena_R aa, RegUse_resolve_look_at_input_and_sub r) +internal MipsAtom* AtomBundleEntry_(resolve_look_at,input_and_sub)(AtomArena_R aa, RegUse_resolve_look_at_input_and_sub r) atom_info(atom_bind(Binds_ResolveLookAtSub)) MipsAtom_Proc_(aa, { - load_word(r.target, R_TapePtr, O_(Binds_ResolveLookAtSub,target)), - load_word(r.eye, R_TapePtr, O_(Binds_ResolveLookAtSub,eye)), - load_word(r.up_in, R_TapePtr, O_(Binds_ResolveLookAtSub,up_in)), - load_word(r.scratch, R_TapePtr, O_(Binds_ResolveLookAtSub,scratchpad)), - LdSlot_ add_ui_self( R_TapePtr, S_(Binds_ResolveLookAtSub)), + load_word(r.target, R_TapePtr, O_(Binds_ResolveLookAtSub,target)), + load_word(r.eye, R_TapePtr, O_(Binds_ResolveLookAtSub,eye)), + load_word(r.up_in, R_TapePtr, O_(Binds_ResolveLookAtSub,up_in)), + LdSlot_ add_ui_self(R_TapePtr, S_(Binds_ResolveLookAtSub)), - /* Stage up_in.x/y/z into the scratchpad. */ + /* Stage up_in.x/y/z into the scratchpad. R_ScratchBase = R_SP = 0x1F800000. */ mac_load_word_v3( r.t0, r.t1, r.t2, r.up_in, 0), LdSlot_ - mac_store_word_v3(r.t0, r.t1, r.t2, r.scratch, O_(ResolveLookAtScratch,up_in)), + mac_store_word_v3(r.t0, r.t1, r.t2, R_ScratchBase, O_(ResolveLookAtScratch,up_in)), // Stage eye.x/y/z into the scratchpad (atom 6 reads these for the translation column). mac_load_word_v3( r.t0, r.t1, r.t2, r.eye, 0), LdSlot_ - mac_store_word_v3(r.t0, r.t1, r.t2, r.scratch, O_(ResolveLookAtScratch,eye)), + mac_store_word_v3(r.t0, r.t1, r.t2, R_ScratchBase, O_(ResolveLookAtScratch,eye)), /* Compute fwd = target - eye. */ // mac_load_p3s4(t3, R_AT, t4, r.eye, 0), - mac_load_word_v3(r.t3, R_AT, r.t4, r.target, 0), LdSlot_ + mac_load_word_v3(r.t3, R_AT, r.t4, r.target, 0), LdSlot_ mac_sub_s_v3_self( r.t3, R_AT, r.t4, r.t0, r.t1, r.t2), - mac_store_word_v3(r.t3, R_AT, r.t4, r.scratch, O_(ResolveLookAtScratch,fwd)), + mac_store_word_v3(r.t3, R_AT, r.t4, R_ScratchBase, O_(ResolveLookAtScratch,fwd)), mac_yield() }) @@ -180,8 +173,6 @@ typedef Struct_(Binds_ResolveLookAtPopMvTrans) { U4 look_at; /* MT3_S2S4* — destination matrix address */ }; typedef Struct_(RegUse_resolve_look_at__pop_mv_trans) { - Reg scratch; /* loaded via load_word_imm below — can't rely on - * R_T4 surviving across the tape_run boundary */ Reg look_at; Reg_(V3_S4) row; /* populate phase: load ux/uy/uz */ union { Reg ux, v_x; } t6; /* populate addr (canonical) → matrix_vector v_x */ @@ -236,17 +227,13 @@ internal MipsAtom* resolve_look_at__pop_mv_trans(AtomArena_R aa, load_word(r.look_at, R_TapePtr, O_(Binds_ResolveLookAtPopMvTrans,look_at)), LdSlot_ add_ui_self(R_TapePtr, S_(Binds_ResolveLookAtPopMvTrans)), - /* Load scratch base via immediate (Scratchpad_Loc = 0x1F800000). We can't rely on - * R_T4 (= R_ResolveScratch) surviving across the tape_run boundary — the compiler - * treats it as clobberable per the tape_run asm_clobber list. Baking the scratch - * address via load_word_imm is robust. */ - mac_load_word_imm(r.scratch, Scratchpad_Loc), - - /* --- Scratch addresses for ux/uy/uz/eye (populate phase; t6/t7/t8 alias ux/uy/uz) --- */ - add_si(r.t6.ux, r.scratch, O_(ResolveLookAtScratch, ux)), LdSlot_ - add_si(r.t7.uy, r.scratch, O_(ResolveLookAtScratch, uy)), - add_si(r.t8.uz, r.scratch, O_(ResolveLookAtScratch, uz)), - add_si(r.eye, r.scratch, O_(ResolveLookAtScratch, eye)), + /* --- Scratch addresses for ux/uy/uz/eye (populate phase; t6/t7/t8 alias ux/uy/uz). + * R_ScratchBase (= R_SP) holds 0x1F800000; no per-atom bake is required because + * R_SP is a tape carrier preserved across atoms. --- */ + add_si(r.t6.ux, R_ScratchBase, O_(ResolveLookAtScratch, ux)), LdSlot_ + add_si(r.t7.uy, R_ScratchBase, O_(ResolveLookAtScratch, uy)), + add_si(r.t8.uz, R_ScratchBase, O_(ResolveLookAtScratch, uz)), + add_si(r.eye, R_ScratchBase, O_(ResolveLookAtScratch, eye)), /* --- POPULATE phase: write look_at->m[][] from ux/uy/uz as packed S2 --- */ mac_load_v3s4(r.row, r.t6.ux, 0), LdSlot_ mac_store_v3s2(r.row, r.look_at, O_(MT3_S2S4, m[0])), diff --git a/code/hello_camera/hello_camera.c b/code/hello_camera/hello_camera.c index 94d0cd1..96631c1 100644 --- a/code/hello_camera/hello_camera.c +++ b/code/hello_camera/hello_camera.c @@ -151,16 +151,17 @@ internal void compile_init_atoms(void) { smem.normalize_v3s4 = build_normalize_v3s4(& ab, RegUse_(build_normalize_v3s4) { - .scratch = ralloc(), - .src_ptr = ralloc(), - .dst_ptr = ralloc(), - .recip_est = ralloc(), - .norm = ralloc(), - .shift = ralloc(), - .src_x = ralloc(), - .t3 = ralloc(), - .t4 = ralloc(), - .t5 = ralloc(), + .scratch = ralloc(), + .src_ptr = ralloc(), + .dst_ptr = ralloc(), + .recip_est = ralloc(), + .norm = ralloc(), + .shift = ralloc(), + .src_x = ralloc(), + // .shift_count = ralloc(), /* dedicated slot for stage-3 → stage-4 shift count */ + .t3 = ralloc(), + .t4 = ralloc(), + .t5 = ralloc(), }); regfile_reset(& rf); @@ -173,14 +174,14 @@ internal void compile_resolve_look_at(void) { AtomArena ab = atomarena_make(slice_ut_arr(smem.resolve_look_at_mem)); AtomBundle_resolve_look_at_R bundle = C_(void*, smem.resolve_look_at_bundle); - U4 pin_mask = regfile_abi_mask | (1 << R_ResolveScratch); - RegFile rf = regfile(pin_mask); + /* R_ScratchBase (= R_SP) is a tape carrier preserved across atoms; no carrier + * pin is needed in the regfile. The standard 24-register pool is sufficient. */ + RegFile rf = regfile(regfile_abi_mask); #define ralloc() regfile_alloc(& rf) #define ralloc_v3() { ralloc(), ralloc(), ralloc() } bundle->input_and_sub = AtomBundleEntry_(resolve_look_at, input_and_sub)(& ab, RegUse_(resolve_look_at_input_and_sub) { - .scratch = R_ResolveScratch, .target = ralloc(), .eye = ralloc(), .up_in = ralloc(), @@ -190,7 +191,7 @@ internal void compile_resolve_look_at(void) { .t3 = ralloc(), .t4 = ralloc(), }); - regfile_reset_to_mask(& rf, pin_mask); + regfile_reset(& rf); bundle->normalize_fwd_uz = smem.normalize_v3s4; bundle->cross_to_right = smem.gte_cross_v3s4; @@ -200,7 +201,6 @@ internal void compile_resolve_look_at(void) { bundle->pop_mv_trans = resolve_look_at__pop_mv_trans(& ab, RegUse_(resolve_look_at__pop_mv_trans){ - .scratch = R_ResolveScratch, .look_at = ralloc(), .eye = ralloc(), .row = ralloc_v3(), @@ -229,7 +229,6 @@ I_ void resolve_look_at(TapeBuilder_R tb tb_data(tb, u4_(target)); tb_data(tb, u4_(eye)); tb_data(tb, u4_(up_in)); - tb_data(tb, u4_(smem.scratchpad)); } tb_emit(tb, bundle->normalize_fwd_uz); { tb_data(tb, u4_(O_(ResolveLookAtScratch, fwd) | (O_(ResolveLookAtScratch, uz) << 16))); diff --git a/scripts/passes/components.lua b/scripts/passes/components.lua index 5711edc..007363c 100644 --- a/scripts/passes/components.lua +++ b/scripts/passes/components.lua @@ -130,6 +130,60 @@ local function extract_arg_names(args_str) for _, tok in ipairs(tokens) do local trimmed = duffle.trim(tok) if trimmed ~= "" then + -- Strip trailing block comment (/* ... */) from the token, if present. + -- split_top_level_commas only skips block comments at TOP LEVEL (between commas), + -- not block comments embedded WITHIN a token between a parameter and a trailing comma. + -- Without this strip, the identifier-walk below stops at the `/` of `*/` and returns + -- the wrong name (or nothing). See `test_extract_arg_names_handles_trailing_block_comments`. + local trimmed_end = #trimmed + if trimmed_end >= 2 and trimmed:sub(trimmed_end - 1, trimmed_end) == "*/" then + -- Find the matching `/*` that opens the trailing comment. + -- Walk back from the `*/` looking for `/*` (whitespace + `/*`). + local close_pos = trimmed_end - 1 -- position of the second-to-last char + -- Walk back: skip trailing whitespace, then look for the `/*` opener. + while close_pos > 1 do + local ch = trimmed:sub(close_pos, close_pos) + if ch == " " or ch == "\t" or ch == "\n" or ch == "\r" then + close_pos = close_pos - 1 + else + break + end + end + -- Now scan back from close_pos for the `/*` opener (slashes are at close_pos-1 and close_pos-2). + local opener_pos = nil + local scan = close_pos - 3 + while scan >= 1 do + if trimmed:sub(scan, scan + 1) == "/*" then + opener_pos = scan + break + end + scan = scan - 1 + end + if opener_pos then + -- Truncate everything from opener_pos onwards. + trimmed = duffle.trim(trimmed:sub(1, opener_pos - 1)) + end + end + if trimmed == "" then goto continue end + -- Strip trailing array suffix `[N]` if present. + -- Example: `Reg r_data[4]` → identifier is `r_data`, not `4`. + trimmed_end = #trimmed + if trimmed_end >= 4 and trimmed:sub(trimmed_end, trimmed_end) == "]" then + -- Walk back: skip digits, expect `[`. + local bracket_pos = trimmed_end - 1 + while bracket_pos > 1 do + local ch = trimmed:sub(bracket_pos, bracket_pos) + if ch >= "0" and ch <= "9" then + bracket_pos = bracket_pos - 1 + else + break + end + end + if bracket_pos >= 1 and trimmed:sub(bracket_pos, bracket_pos) == "[" then + trimmed = duffle.trim(trimmed:sub(1, bracket_pos - 1)) + end + end + if trimmed == "" then goto continue end -- Find the identifier at the end: walk back over trailers (whitespace + `*` + `[]`), -- then walk back over the identifier chars (alnum + `_`). local ident_end = #trimmed @@ -153,6 +207,7 @@ local function extract_arg_names(args_str) ident_start = ident_start + 1 local name = trimmed:sub(ident_start, ident_end) if name ~= "" then names[#names + 1] = name end + ::continue:: end end if #names == 0 then return nil end