Moving definitions to use dedicated scratch register.

This commit is contained in:
ed
2026-08-18 09:26:49 -04:00
parent da007d342e
commit 86fe189b4e
5 changed files with 108 additions and 67 deletions
+1 -1
View File
@@ -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.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.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)), 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.a, r.y.src_a, 0), LdSlot_
mac_load_v3s4(r.b, r.z.src_b, 0), LdSlot_ mac_load_v3s4(r.b, r.z.src_b, 0), LdSlot_
+2 -2
View File
@@ -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. */ * any of them while R0, R1, R26-R31 remain reserved. */
I_ Reg regfile_alloc(RegFile_R rf) { I_ Reg regfile_alloc(RegFile_R rf) {
Reg allocated = 0; Reg allocated = 0;
for index_iter(U4, idx, 0, <, Array_len(regfile_alloc_order)) { for index_iter(U4, r_id, R_V0, <, R_T9) {
allocated = regfile__alloc_helper(rf->GPR, idx); allocated = regfile__alloc_helper(rf->GPR, r_id);
Jmp_nZero_(allocated,resolved); Jmp_nZero_(allocated,resolved);
} }
assert(allocated != 0); assert(allocated != 0);
+26 -39
View File
@@ -111,39 +111,33 @@ typedef AtomBundle_(resolve_look_at) { MipsAtom
*pop_mv_trans; *pop_mv_trans;
}; };
enum { typedef Struct_(ResolveLookAtScratch) {
// TODO(Ed): We can resolve scratch at anytime its fixed to a specific address. V3_S4 fwd;
R_ResolveScratch = R_T4 atom_reg atom_type(U4*), V3_S4 uz;
#define R_ResolveScratch_Code R_T4_Code 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) { typedef Struct_(Binds_ResolveLookAt) {
MT3_S2S4* look_at; MT3_S2S4* look_at;
P3_S4* eye; P3_S4* eye;
P3_S4* target; P3_S4* target;
V3_S4* up_in; 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) { typedef Struct_(Binds_ResolveLookAtSub) {
P3_S4* target; P3_S4* target;
P3_S4* eye; P3_S4* eye;
V3_S4* up_in; V3_S4* up_in;
ResolveLookAtScratch* scratchpad;
}; };
typedef Struct_(RegUse_resolve_look_at_input_and_sub) { typedef Struct_(RegUse_resolve_look_at_input_and_sub) {
Reg scratch;
Reg target; Reg eye; Reg up_in; Reg target; Reg eye; Reg up_in;
Reg t0; Reg t1; Reg t2; Reg t3; Reg t4; Reg t0; Reg t1; Reg t2; Reg t3; Reg t4;
}; };
@@ -153,16 +147,15 @@ atom_info(atom_bind(Binds_ResolveLookAtSub)) MipsAtom_Proc_(aa, {
load_word(r.target, R_TapePtr, O_(Binds_ResolveLookAtSub,target)), load_word(r.target, R_TapePtr, O_(Binds_ResolveLookAtSub,target)),
load_word(r.eye, R_TapePtr, O_(Binds_ResolveLookAtSub,eye)), 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.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)),
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_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). // 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_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. */ /* Compute fwd = target - eye. */
// mac_load_p3s4(t3, R_AT, t4, r.eye, 0), // mac_load_p3s4(t3, R_AT, t4, r.eye, 0),
@@ -170,7 +163,7 @@ atom_info(atom_bind(Binds_ResolveLookAtSub)) MipsAtom_Proc_(aa, {
mac_sub_s_v3_self( mac_sub_s_v3_self(
r.t3, R_AT, r.t4, r.t3, R_AT, r.t4,
r.t0, r.t1, r.t2), 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() mac_yield()
}) })
@@ -180,8 +173,6 @@ typedef Struct_(Binds_ResolveLookAtPopMvTrans) {
U4 look_at; /* MT3_S2S4* — destination matrix address */ U4 look_at; /* MT3_S2S4* — destination matrix address */
}; };
typedef Struct_(RegUse_resolve_look_at__pop_mv_trans) { 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 look_at;
Reg_(V3_S4) row; /* populate phase: load ux/uy/uz */ Reg_(V3_S4) row; /* populate phase: load ux/uy/uz */
union { Reg ux, v_x; } t6; /* populate addr (canonical) → matrix_vector v_x */ 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)), load_word(r.look_at, R_TapePtr, O_(Binds_ResolveLookAtPopMvTrans,look_at)),
LdSlot_ add_ui_self(R_TapePtr, S_(Binds_ResolveLookAtPopMvTrans)), LdSlot_ add_ui_self(R_TapePtr, S_(Binds_ResolveLookAtPopMvTrans)),
/* Load scratch base via immediate (Scratchpad_Loc = 0x1F800000). We can't rely on /* --- Scratch addresses for ux/uy/uz/eye (populate phase; t6/t7/t8 alias ux/uy/uz).
* R_T4 (= R_ResolveScratch) surviving across the tape_run boundary — the compiler * R_ScratchBase (= R_SP) holds 0x1F800000; no per-atom bake is required because
* treats it as clobberable per the tape_run asm_clobber list. Baking the scratch * R_SP is a tape carrier preserved across atoms. --- */
* address via load_word_imm is robust. */ add_si(r.t6.ux, R_ScratchBase, O_(ResolveLookAtScratch, ux)), LdSlot_
mac_load_word_imm(r.scratch, Scratchpad_Loc), add_si(r.t7.uy, R_ScratchBase, O_(ResolveLookAtScratch, uy)),
add_si(r.t8.uz, R_ScratchBase, O_(ResolveLookAtScratch, uz)),
/* --- Scratch addresses for ux/uy/uz/eye (populate phase; t6/t7/t8 alias ux/uy/uz) --- */ add_si(r.eye, R_ScratchBase, O_(ResolveLookAtScratch, eye)),
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)),
/* --- POPULATE phase: write look_at->m[][] from ux/uy/uz as packed S2 --- */ /* --- 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])), mac_load_v3s4(r.row, r.t6.ux, 0), LdSlot_ mac_store_v3s2(r.row, r.look_at, O_(MT3_S2S4, m[0])),
+5 -6
View File
@@ -158,6 +158,7 @@ internal void compile_init_atoms(void) {
.norm = ralloc(), .norm = ralloc(),
.shift = ralloc(), .shift = ralloc(),
.src_x = ralloc(), .src_x = ralloc(),
// .shift_count = ralloc(), /* dedicated slot for stage-3 → stage-4 shift count */
.t3 = ralloc(), .t3 = ralloc(),
.t4 = ralloc(), .t4 = ralloc(),
.t5 = ralloc(), .t5 = ralloc(),
@@ -173,14 +174,14 @@ internal void compile_resolve_look_at(void) {
AtomArena ab = atomarena_make(slice_ut_arr(smem.resolve_look_at_mem)); 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); AtomBundle_resolve_look_at_R bundle = C_(void*, smem.resolve_look_at_bundle);
U4 pin_mask = regfile_abi_mask | (1 << R_ResolveScratch); /* R_ScratchBase (= R_SP) is a tape carrier preserved across atoms; no carrier
RegFile rf = regfile(pin_mask); * 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() regfile_alloc(& rf)
#define ralloc_v3() { ralloc(), ralloc(), ralloc() } #define ralloc_v3() { ralloc(), ralloc(), ralloc() }
bundle->input_and_sub = AtomBundleEntry_(resolve_look_at, input_and_sub)(& ab, bundle->input_and_sub = AtomBundleEntry_(resolve_look_at, input_and_sub)(& ab,
RegUse_(resolve_look_at_input_and_sub) { RegUse_(resolve_look_at_input_and_sub) {
.scratch = R_ResolveScratch,
.target = ralloc(), .target = ralloc(),
.eye = ralloc(), .eye = ralloc(),
.up_in = ralloc(), .up_in = ralloc(),
@@ -190,7 +191,7 @@ internal void compile_resolve_look_at(void) {
.t3 = ralloc(), .t3 = ralloc(),
.t4 = ralloc(), .t4 = ralloc(),
}); });
regfile_reset_to_mask(& rf, pin_mask); regfile_reset(& rf);
bundle->normalize_fwd_uz = smem.normalize_v3s4; bundle->normalize_fwd_uz = smem.normalize_v3s4;
bundle->cross_to_right = smem.gte_cross_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, bundle->pop_mv_trans = resolve_look_at__pop_mv_trans(& ab,
RegUse_(resolve_look_at__pop_mv_trans){ RegUse_(resolve_look_at__pop_mv_trans){
.scratch = R_ResolveScratch,
.look_at = ralloc(), .look_at = ralloc(),
.eye = ralloc(), .eye = ralloc(),
.row = ralloc_v3(), .row = ralloc_v3(),
@@ -229,7 +229,6 @@ I_ void resolve_look_at(TapeBuilder_R tb
tb_data(tb, u4_(target)); tb_data(tb, u4_(target));
tb_data(tb, u4_(eye)); tb_data(tb, u4_(eye));
tb_data(tb, u4_(up_in)); tb_data(tb, u4_(up_in));
tb_data(tb, u4_(smem.scratchpad));
} }
tb_emit(tb, bundle->normalize_fwd_uz); { tb_emit(tb, bundle->normalize_fwd_uz); {
tb_data(tb, u4_(O_(ResolveLookAtScratch, fwd) | (O_(ResolveLookAtScratch, uz) << 16))); tb_data(tb, u4_(O_(ResolveLookAtScratch, fwd) | (O_(ResolveLookAtScratch, uz) << 16)));
+55
View File
@@ -130,6 +130,60 @@ local function extract_arg_names(args_str)
for _, tok in ipairs(tokens) do for _, tok in ipairs(tokens) do
local trimmed = duffle.trim(tok) local trimmed = duffle.trim(tok)
if trimmed ~= "" then 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 + `*` + `[]`), -- Find the identifier at the end: walk back over trailers (whitespace + `*` + `[]`),
-- then walk back over the identifier chars (alnum + `_`). -- then walk back over the identifier chars (alnum + `_`).
local ident_end = #trimmed local ident_end = #trimmed
@@ -153,6 +207,7 @@ local function extract_arg_names(args_str)
ident_start = ident_start + 1 ident_start = ident_start + 1
local name = trimmed:sub(ident_start, ident_end) local name = trimmed:sub(ident_start, ident_end)
if name ~= "" then names[#names + 1] = name end if name ~= "" then names[#names + 1] = name end
::continue::
end end
end end
if #names == 0 then return nil end if #names == 0 then return nil end