diff --git a/.run/P36/agents/ov_SC06_018__func_80187DD0/body.c b/.run/P36/agents/ov_SC06_018__func_80187DD0/body.c new file mode 100644 index 0000000000..bbebf2783d --- /dev/null +++ b/.run/P36/agents/ov_SC06_018__func_80187DD0/body.c @@ -0,0 +1,94 @@ +void func_80187DD0(s32 param_1) +{ + s32 t1 = *(s32 *)(param_1 + 0x64); + s32 pad[2]; + + if (*(s16 *)(t1 + 0x36) != *(s16 *)(param_1 + 0x10A)) { + func_8012C218((void *)param_1); + return; + } + { + if ((*(u32 *)(t1 + 0xE0) & 4) != 0) { + func_8012E8A8((u8 *)param_1); + return; + } + { + s32 a2 = *(s32 *)(*(s32 *)(t1 + 0x20) + 0x20); + s32 a3 = param_1 + 0xFC; + + if (a2 != 0) { + if ((a2 & 0x1000000) != 0) { + s32 a1 = a2 & 0xFEFFFFFF; + u32 v0; + u32 a0; + u32 v1; + + *(u16 *)(param_1 + 0x102) = *(u16 *)(a1 + 0x66); + + v0 = *(u32 *)(a1 + 0x60); + a0 = *(u8 *)(a1 + 0x61) | ((v0 & 0xF) << 8); + v1 = (((s32)v0 >> 16) & 0xFF) | ((v0 & 0xF0) << 4); + do { // !FAKE: do-while — flow counts the stores' refs at loop depth 2 (flow.c:1440-1449, :2711 reg_n_refs += loop_depth), which lifts a0's quantity over a1's in qty_compare_1 (local-alloc.c:1598); its LOOP notes also keep sched1 from moving the 0x104 store above v1's or (sched.c:2053-2074), so w's quantity ties the (w & 0xF) one at 13333 and wins on qty number (P36 S104 e5 minimum-lever) + *(u16 *)(param_1 + 0x104) = a0; + *(u16 *)(param_1 + 0x106) = v1; + } while (0); + + *(s16 *)(param_1 + 0xFC) = (s8)*(u8 *)(a1 + 0x63); + *(s16 *)(param_1 + 0xFE) = (s8)*(u8 *)(a1 + 0x64); + *(s16 *)(param_1 + 0x100) = (s8)*(u8 *)(a1 + 0x65); + } else { + *(UAlign12 *)(param_1 + 0xFC) = *(UAlign12 *)(a2 + 0x90); + } + *(s32 *)(*(s32 *)(param_1 + 0x20) + 0x20) = a3; + } + + if ((*(u32 *)(t1 + 0xE0) & 0x80) != 0) { + if (*(u16 *)(param_1 + 0x34) == 0) { + s16 sVar2 = *(u16 *)(param_1 + 0x108) + 0x40; + *(s16 *)(param_1 + 0x108) = sVar2; + if (sVar2 > 0x200) { + *(u16 *)(param_1 + 0x108) = 0x200; + *(s16 *)(param_1 + 0x34) = *(s16 *)(param_1 + 0x34) + 1; + } + } else { + u16 uVar3 = *(u16 *)(param_1 + 0x108) - 0x80; + *(u16 *)(param_1 + 0x108) = uVar3; + if ((s16)uVar3 < 0) { + *(u16 *)(param_1 + 0x108) = 0; + *(u16 *)(param_1 + 0x34) = 0; + *(u32 *)(t1 + 0xE0) = *(u32 *)(t1 + 0xE0) & ~0x80; + } + } + } + + *(u16 *)(a3 + 6) = *(u16 *)(a3 + 6) + *(u16 *)(param_1 + 0x108); + + *(u32 *)(param_1 + 4) = *(u32 *)(t1 + 4); + *(u32 *)(param_1 + 8) = *(u32 *)(t1 + 8); + *(u32 *)(param_1 + 0xC) = *(u32 *)(t1 + 0xC); + + *(UAlign8 *)(param_1 + 0x50) = *(UAlign8 *)(t1 + 0x50); + + { + s32 dst = *(s32 *)(param_1 + 0x20); + s32 src = *(s32 *)(t1 + 0x20); + *(UAlign8 *)(dst + 0x10) = *(UAlign8 *)(src + 0x10); + } + { + s32 dst = *(s32 *)(param_1 + 0x20); + s32 src = *(s32 *)(t1 + 0x20); + *(UAlign8 *)(dst + 0x18) = *(UAlign8 *)(src + 0x18); + } + { + s32 src = *(s32 *)(t1 + 0x20); + s32 dst = *(s32 *)(param_1 + 0x20); + *(u32 *)(dst + 4) = *(u32 *)(src + 4); + } + { + s32 src = *(s32 *)(t1 + 0x20); + s32 dst = *(s32 *)(param_1 + 0x20); + *(u16 *)(dst + 0x2C) = *(u16 *)(src + 0x2C); + } + } + } +} diff --git a/.run/P36/agents/ov_SC06_018__func_80187DD0/body_plain_best.c b/.run/P36/agents/ov_SC06_018__func_80187DD0/body_plain_best.c new file mode 100644 index 0000000000..deb5120f1e --- /dev/null +++ b/.run/P36/agents/ov_SC06_018__func_80187DD0/body_plain_best.c @@ -0,0 +1,94 @@ +void func_80187DD0(s32 param_1) +{ + s32 t1 = *(s32 *)(param_1 + 0x64); + s32 pad[2]; + + if (*(s16 *)(t1 + 0x36) != *(s16 *)(param_1 + 0x10A)) { + func_8012C218((void *)param_1); + return; + } + { + if ((*(u32 *)(t1 + 0xE0) & 4) != 0) { + func_8012E8A8((u8 *)param_1); + return; + } + { + s32 a2 = *(s32 *)(*(s32 *)(t1 + 0x20) + 0x20); + s32 a3 = param_1 + 0xFC; + + if (a2 != 0) { + if ((a2 & 0x1000000) != 0) { + s32 a1 = a2 & 0xFEFFFFFF; + u32 v0; + u32 a0; + u32 v1b; + u32 v1; + + *(u16 *)(param_1 + 0x102) = *(u16 *)(a1 + 0x66); + + v0 = *(u32 *)(a1 + 0x60); + a0 = *(u8 *)(a1 + 0x61) | ((v0 & 0xF) << 8); + v1b = ((s32)v0 >> 16) & 0xFF; + v1 = ((v0 & 0xF0) << 4) | v1b; + *(u16 *)(param_1 + 0x104) = (u16)a0; + *(u16 *)(param_1 + 0x106) = (u16)v1; + + *(s16 *)(param_1 + 0xFC) = (s8)*(u8 *)(a1 + 0x63); + *(s16 *)(param_1 + 0xFE) = (s8)*(u8 *)(a1 + 0x64); + *(s16 *)(param_1 + 0x100) = (s8)*(u8 *)(a1 + 0x65); + } else { + *(UAlign12 *)(param_1 + 0xFC) = *(UAlign12 *)(a2 + 0x90); + } + *(s32 *)(*(s32 *)(param_1 + 0x20) + 0x20) = a3; + } + + if ((*(u32 *)(t1 + 0xE0) & 0x80) != 0) { + if (*(u16 *)(param_1 + 0x34) == 0) { + s16 sVar2 = *(u16 *)(param_1 + 0x108) + 0x40; + *(s16 *)(param_1 + 0x108) = sVar2; + if (sVar2 > 0x200) { + *(u16 *)(param_1 + 0x108) = 0x200; + *(s16 *)(param_1 + 0x34) = *(s16 *)(param_1 + 0x34) + 1; + } + } else { + u16 uVar3 = *(u16 *)(param_1 + 0x108) - 0x80; + *(u16 *)(param_1 + 0x108) = uVar3; + if ((s16)uVar3 < 0) { + *(u16 *)(param_1 + 0x108) = 0; + *(u16 *)(param_1 + 0x34) = 0; + *(u32 *)(t1 + 0xE0) = *(u32 *)(t1 + 0xE0) & ~0x80; + } + } + } + + *(u16 *)(a3 + 6) = *(u16 *)(a3 + 6) + *(u16 *)(param_1 + 0x108); + + *(u32 *)(param_1 + 4) = *(u32 *)(t1 + 4); + *(u32 *)(param_1 + 8) = *(u32 *)(t1 + 8); + *(u32 *)(param_1 + 0xC) = *(u32 *)(t1 + 0xC); + + *(UAlign8 *)(param_1 + 0x50) = *(UAlign8 *)(t1 + 0x50); + + { + s32 dst = *(s32 *)(param_1 + 0x20); + s32 src = *(s32 *)(t1 + 0x20); + *(UAlign8 *)(dst + 0x10) = *(UAlign8 *)(src + 0x10); + } + { + s32 dst = *(s32 *)(param_1 + 0x20); + s32 src = *(s32 *)(t1 + 0x20); + *(UAlign8 *)(dst + 0x18) = *(UAlign8 *)(src + 0x18); + } + { + s32 src = *(s32 *)(t1 + 0x20); + s32 dst = *(s32 *)(param_1 + 0x20); + *(u32 *)(dst + 4) = *(u32 *)(src + 4); + } + { + s32 src = *(s32 *)(t1 + 0x20); + s32 dst = *(s32 *)(param_1 + 0x20); + *(u16 *)(dst + 0x2C) = *(u16 *)(src + 0x2C); + } + } + } +} diff --git a/.run/P36/agents/ov_SC06_018__func_80187DD0/mechanism.md b/.run/P36/agents/ov_SC06_018__func_80187DD0/mechanism.md new file mode 100644 index 0000000000..68cd531a25 --- /dev/null +++ b/.run/P36/agents/ov_SC06_018__func_80187DD0/mechanism.md @@ -0,0 +1,89 @@ +# func_80187DD0 (src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c), e5, P36 T7 S104: MINIMUM-LEVER at 0 + +**Final: score 0 (174/174 ins, byte-identical).** Lever count 1 → 1, but the kind changes: the `register u32 v0 __asm__("$2")` +pin becomes ONE marked `do { … } while (0);` around the two halfword stores, which is ordinary C (step 8). No pin, no asm, +no volatile. The best lever-free text scores **2** (below). The nibble-packing block now reads: + + v0 = *(u32 *)(a1 + 0x60); + a0 = *(u8 *)(a1 + 0x61) | ((v0 & 0xF) << 8); + v1 = (((s32)v0 >> 16) & 0xFF) | ((v0 & 0xF0) << 4); + do { // !FAKE: do-while — … + *(u16 *)(param_1 + 0x104) = a0; + *(u16 *)(param_1 + 0x106) = v1; + } while (0); + +**The same block closes all five other copies of the class, each `--try` at 0** (`scratch/copy_.c`, built by +`scratch/port.py`, which swaps only this block into the tree's text): func_80181F40 (ov_SC06_020), func_80185E64 (ov_SC06_022), +func_8018833C (ov_SC06_024), func_80182B74 (ov_SC06_032), func_80186858 (ov_SC06_033). That is 6 pins → 6 marked do-whiles. + +## (a) The residual +Same count, a register permutation in one block (local-alloc). The target has the loaded word `w` in v0 and the `(w&0xF)<<8` +temp in v1. The lever-free text swaps them (and the or's result with them). + +## (b) The pass and the decision (local-alloc, proved with `lsim3.py` on every candidate's `.lreg`, 0 mismatches) +Quantities in the block (numbers are local-alloc's birth/death indices, 2 per insn). The target needs this assignment: +q2 = {w, w&0xF0, <<4} → v0, q3 = {w&0xF, <<8} → v1, q5 = {>>16, &0xFF, the second or} → v1, q4 = {lbu 0x61, the first +or} → a0, q0 = {mask, a1} → a1. `qty_compare_1` (local-alloc.c:1598) ranks by `floor_log2(refs)·refs/(death−birth)`, +with ties going to the lower qty number: +- q2 (8 refs) against q3 (4 refs): **24/L2 ≥ 8/L3**. That holds only when sched1's order is `lw, andi 0xf, lbu, sll 8, or, + , sh, sh`: L2 = 18, L3 = 6, a 13333 tie that q2 wins on number. If the 0x104 store is scheduled inside q2's range + (the lever-free default: sched1 puts it right after the first or because the group-2 insns are birthing-boosted, + sched.c:2507-2545), then L2 = 20, q3 wins, and w loses v0. That is the residual. +- q4 (4 refs, L4 = 16 when the store sits after group 2) against q0 (9 refs, L0 = 50): 0.50 < 0.54, so q0 takes a0 and + the lbu gets a1. Fixing the first condition alone turns the v0/v1 residual into an a0/a1 one (score 11, + `e3/u16u16_aa.c`: u16 result variables make the ors SUBREG-destination sets that fail `birthing_insn_p`, which moves + the store late). L4 cannot drop to 14 without a barrier (the lbu→or load latency queues the lbu behind the `sll`, + sched.c:2583-2600), so q4 needs a fifth ref. +- **The do-while supplies both.** flow counts a ref at `loop_depth` (2 inside the loop; propagate_block tracks the LOOP notes, flow.c:1440-1449, and mark_used_regs adds `reg_n_refs += loop_depth`, flow.c:2711), so the store's use of a0 makes + q4 5 refs: 10/16 = 0.625 > 0.54. The LOOP notes are a full sched barrier (sched.c:2053-2074), so the stores cannot + be hoisted into q2's range: L2 = 18. `lsim3` on `scratch/dumps_b9/`: q2 13333, q3 13333, q5 11666, q4 **6250**, q0 + 5400. That is exactly the target assignment. In sched2 the barrier only keeps the stores where the target has them. + +## (c) The move +Inline the two packed values into one expression each (`a0 = lbu | ((w & 0xF) << 8)`, so the lbu's destination is set +once and stays birthing-boosted, which puts it between `andi` and `sll`) and wrap the two stores in `do { } while (0)`. +Each piece is needed. Body_free + the do-while alone scores 10, because `a0` is set twice there, the lbu is not +boosted and it is scheduled first. + +## (d) GENERATOR PROPOSAL +For a local-alloc permutation where `lsim3` shows the loser short by one ref or by 2 in live length, try (1) a +`do { } while (0)`, which doubles that ref (flow loop_depth) and pins +the store after everything above it. Also try (2) inlining a two-statement `x = load; x |= y;` into one expression so the load's +destination is set once (it becomes birthing-boosted). Score the pair, and each alone. Mark (1) as `!FAKE: do-while`. + +## (e) What did not work (all `--try`, ~1,100 candidates in `scratch/e1`..`e9`) +| family | best | why | +|---|---|---| +| inline / operand order / statement order of the 7 temps (`e1`, 160) | **2** (`u32_a1101_s01_o0.c`, in `body_plain_best.c`) | the second or's result ties to `(w&0xF0)<<4` (q2 13636 > q3), so w gets v0, but the or result lands in v0, not v1 | +| variable reuse / compound assignment (`e2`, 256) | 3 | the same tie structures | +| u16/s16 result variables (`e3`, 180) | 11 | v0/v1 right, a0/a1 swapped (q4 0.50 < q0 0.54, above) | +| extra copies to add refs (`e4`/`e5`, 330) | 3 | cse folds the copies before flow counts the refs | +| `const` reads to relax the store→load dependences (`e6`/`e7`) | 2 | RTX_UNCHANGING_P reorders everything (up to 93 worse) | +| barrier between `sll` and `lbu` (`e8`) | 9 | the allocation is exactly right, but the barrier survives into sched2, the lbu cannot fill the lw delay slot, +2 nops | + +## (f) Where the method fell short +- `lsim3.py` was decisive: every hypothesis was two numbers on its table. It needs a documented home (it lives in + another agent's scratch). It should also print each qty's registers' refs, which is how the loop-depth ref showed up. +- Nothing in the method says flow's `reg_n_refs` is **weighted by loop depth**, so a `do { } while (0)` changes + allocation priorities as well as the schedule. That is a second, independent effect of the same marked construct (d4 used only the barrier). +- A two-sided allocation constraint (q2≥q3 AND q4>q0) where every plain-C single move fixes one side and breaks the + other is a case for an exhaustive search over the priority arithmetic, not for more spellings. + +- Interpretation (not proven): two stores wrapped in `do { … } while (0)` is the shape of a C statement macro + (`#define SET_PAIR(p, a, b) do { … } while (0)`), so this may be the original text rather than a lever. The sibling + in 800.c (`local[1] = a1[3].b1 | ((w & 0xF) << 8); local[2] = …`) is lever-free because it sits inside a real + `while` loop, which again points to loop depth as the missing fact. + +## (g) Structs answer +Unlikely to remove this lever. The deciding quantities are refs and live lengths in local-alloc, plus sched1's +placement of the 0x104 store. Struct field access would make the reads and stores `MEM_IN_STRUCT_P`, and they already +are (every `*(T *)(p + K)` is a PLUS_EXPR address, expr.c:4568-4577). `true_dependence` (sched.c:817-842) disambiguates +only against a fixed address, and both sides here are register-based, so the dependences cannot change. Tested the only +aliasing channel that could move the store, `const` (RTX_UNCHANGING_P): it makes things worse. What a struct *could* +supply is the original's shape of this block, e.g. a colour struct written through a pointer inside a loop over parts. If +the original sits in a real loop, the do-while stands in for real loop depth, and that information lives in the caller's +structure, not in a type. + +Files: `body.c` (min-lever text), `body_plain_best.c` (best lever-free text, 2), `scratch/copy_.c` (5 class copies +at 0), `scratch/port.py`, `scratch/an.sh` (dump + lsim3 + sched order for one candidate), `scratch/dumps_b9/` (the close), +`scratch/dumps_u16aa/` (the a0/a1 case), `scratch/e1`..`e9` (candidate families with `eN_scores.txt`). diff --git a/.run/P36/agents/ov_SC06_018__func_8018AD74/body.c b/.run/P36/agents/ov_SC06_018__func_8018AD74/body.c new file mode 100644 index 0000000000..168b528e15 --- /dev/null +++ b/.run/P36/agents/ov_SC06_018__func_8018AD74/body.c @@ -0,0 +1,28 @@ +void func_8018AD74(s32 p1, s32 p2, s32 p3, s32 p4) +{ + /* [T51] block-scoped decls (house idiom in this TU, cf. func_8018AF88): a file-scope + decl of these symbols would constrain every LATER function in the object. */ + extern Blk20_8018AF88 D_800AE620; + extern s32 func_8012C658(s32, s32, s32); + extern void RotMatrixY(s32 a0, void *a1); + extern void func_800484EC(s32, s32, s32); + extern u8 D_801CD468[]; + + Blk20_8018AF88 local_30; /* sp+0x10 */ + Blk20_8018AF88 *m; + s32 obj; + s32 out[3]; /* sp+0x30, only [0] and [2] used */ + + local_30 = D_800AE620; + obj = func_8012C658((s16)p2, (s16)p3, p1); + do { } while (0); // !FAKE: do-while — its NOTE_INSN_LOOP_END ends cse1's extended block (cse.c:8054), so m below is not folded onto the struct copy's address pseudo (cse.c:846-862) and is set AFTER obj's copy: sched1 then ranks it last by LUID (sched.c:2428) (P36 S104 e5 minimum-lever) + m = &local_30; + if (obj != 0) { + *(u16 *)(obj + 0xA) = *(u16 *)(obj + 0xA) - 0x80; + RotMatrixY((s16)p4, m); + func_800484EC((s32)m, (s32)&D_801CD468, (s32)out); + *(s32 *)(obj + 0x10) = out[0]; + *(s32 *)(obj + 0x14) = 0xFFD80000; + *(s32 *)(obj + 0x18) = out[2]; + } +} diff --git a/.run/P36/agents/ov_SC06_018__func_8018AD74/mechanism.md b/.run/P36/agents/ov_SC06_018__func_8018AD74/mechanism.md new file mode 100644 index 0000000000..99a297c350 --- /dev/null +++ b/.run/P36/agents/ov_SC06_018__func_8018AD74/mechanism.md @@ -0,0 +1,85 @@ +# func_8018AD74 (src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c), e5, P36 T7 S104: MINIMUM-LEVER at 0 + +**Final: score 0 (60/60 ins, byte-identical).** Lever count 1 → 1, but the kind changes: the tree's `__asm__` launder +on `obj` becomes ONE marked empty `do { } while (0);`, which is ordinary C (step 8). No pin, no asm, no volatile. I found no +lever-free spelling (below). The move against `body_free.c`: + + - obj = func_8012C658((s16)p2, (s16)p3, p1); + - if (obj != 0) { + - m = &local_30; + + obj = func_8012C658((s16)p2, (s16)p3, p1); + + do { } while (0); // !FAKE: do-while — … + + m = &local_30; + + if (obj != 0) { + +The class's other copy closes with the same text: **func_80185F4C** (src/ov_SC06_032/ov_SC06_032_jr_80182890.c) scores +**0** (`scratch/copy_func_80185F4C.c`). + +## (a) The residual +Same count, one instruction in the wrong place. The target is `jal; [move s1,a3]; move s0,v0; beqz s0; [addiu s2,sp,16]`. +The free text is `move s1,a3; jal; [addiu s2,sp,16]; move s0,v0; beqz; [sll a0,s1,16]`. The `m = &local_30` address +(`addiu s2,sp,16`) sits before the call instead of between the call-result copy and the branch. + +## (b) The pass and the decision (proved on dumps, `scratch/dumps_free/`, `scratch/dumps_tree/`) +1. **cse1 hoists `m` into block 0.** `local_30 = D_800AE620` expands through `expand_block_move`, which copies the + destination address into a pseudo (`.rtl` insn 17, `reg 78 = fp+16`). `m = &local_30` in the if-body is the same + `(plus fp 16)`, so cse finds reg 78 in the table. m's own pseudo is not made the class head (it does not outlive the + extended block, `make_regs_eqv`, cse.c:846-862), so every use of m becomes reg 78 and m's set is deleted. The + struct copy's own address is folded back to `fp+16`, so reg 78 now exists only to be m. It is set at insn 17, before the call. +2. **sched1 ranks it before the call.** At T-2 (just before the branch) the ready list is {17 (reg 78), 35 (`obj = v0`)}. + Both are birthing insns, boosted to `max_priority` (`adjust_priority`, sched.c:2507-2545; `birthing_insn_p` needs + `reg_n_sets == 1`, :2469-2490). Both are class 3. The tie goes to the higher LUID (`rank_for_schedule`, sched.c:2428), + which is 35, so 35 is placed last and 17 falls before the `jal`. reorg then fills the `jal` slot with it. +3. **The tree's launder** makes obj's pseudo `reg_n_sets == 2`. 35 is then not a birthing insn (priority 1 against 17's + boost), and 17 lands between 35 and the branch (`.sched` of the tree: `T-2: 17 (7f000001) 35 (1), now 17`). + +## (c) The move (minimum lever) +Assign `m = &local_30;` in block 0 after the call, behind an empty `do { } while (0);`. The loop's `NOTE_INSN_LOOP_END` +ends cse1's extended basic block (`cse_end_of_basic_block`, cse.c:8054). m's `(plus fp 16)` is then never looked up +against reg 78. Reg 78 goes dead once the movstr address is folded, and cse deletes it, so cse2 (which ignores the note) +has nothing to merge. m keeps its own pseudo, set after 35. At T-2 both are boosted and the LUID tie now picks m's set. +It lands between `move s0,v0` and `beqz`, and reorg puts it in the branch delay slot. The note is also a sched barrier +(sched.c:2053-2074), but between 35 and m's set that is harmless. +Placement matters (all `--try`): the empty loop **between the call and `m =`** scores **0**. `do { m = &local_30; } while (0)` +scores 5, because the LOOP_END comes after m and the fold still happens. Wrapping the call scores 7: its LOOP_BEG pins +`move s1,a3` before the argument setup and flips the s1/s2 allocation. Wrapping the struct copy scores 21. + +## (d) GENERATOR PROPOSAL +When the only residual is an `addiu sK,sp,N` (a local's address) sitting in a `jal` delay slot where the target has it in +the following branch's slot, and the source takes that local's address inside the if-body after a struct copy into the +same local: hoist `p = &local;` to just before the `if`, behind an empty `do { } while (0);` (marked). The mechanical +test: `.cse` shows the address pseudo created by `expand_block_move` standing in for the pointer variable. + +## (e) What did not work (all `--try`) +| spelling | score | why | +|---|---|---| +| body_free (start) | 5 | above | +| `&local_30` direct at both calls, no `m` | 5 | same fold onto reg 78 | +| `m = &local_30;` before / instead of the struct copy (`*m = D_800AE620`) | 5 / 5 | m is set first, LUID lowest | +| `m = &local_30;` between the call and `if`, no loop | 5 | cse1 folds it onto reg 78 again | +| `if (obj == 0) return;` form | 5 | the same extended block | +| `p1 = func(…, p1)` / `p2 = func(…)` to give obj a second set | 5 / 5 | expand puts the call value in a fresh temp; cse deletes the param copy, so the temp still has `n_sets == 1` | +| the sweep's R18/R7 bests | 2 (history) | never below 2 | + +## (f) Where the method fell short +- A plausible origin for an EMPTY `do { } while (0)` in 1990s game code is a debug macro compiled out + (`#define DPRINTF(...) do { } while (0)`). That is an interpretation, not proven. It would make this text the original + rather than a lever, and it is why I prefer it to the asm. Three distinct effects of a do-while(0) are now on record: + a sched barrier (d4), a cse1 extended-block end (this one, cse.c:8054), and a loop-depth ref weight (e5's + func_80187DD0, flow.c:2711). A generator that inserts `do { } while (0);` at each statement boundary and scores all of + them would have found this in about 20 compiles. +- The method has the birthing boost (S104 d8) but no rule for **cse moving a variable's definition to another block** + by folding it onto an earlier pseudo that holds the same address. That fold is what put `m` in block 0 in the first place. + "Read `.cse` for a user variable that vanished" belongs in step 3. +- I looked for a plain-C second set of `obj` (a natural `reg_n_sets == 2`) and did not find one. Every reuse of a + parameter goes through a call-value temp. + +## (g) Structs answer +Struct typing would not remove this lever. The deciding facts are cse's value equivalence of two `(plus fp 16)` +computations and sched1's LUID tie. Neither involves memory aliasing (`expr.c:4568-4577` → `sched.c` true_dependence +is not on the path: the two contenders are register copies). `local_30` is already a struct. What would matter is the +original's **statement placement** (where `&m` is formed) or a second assignment of `obj`, which is information a +struct definition does not supply. + +Files: `body.c` (the min-lever text), `scratch/copy_func_80185F4C.c` (SC06_032 copy, 0), `scratch/d/` (do-while +placements), `scratch/dumps_free/`, `scratch/dumps_tree/`, `scratch/dumps_v2/`, `scratch/dumps_v7/`. diff --git a/.run/P36/agents/ov_SC06_018__func_8018B9D4/body.c b/.run/P36/agents/ov_SC06_018__func_8018B9D4/body.c new file mode 100644 index 0000000000..396583c8a6 --- /dev/null +++ b/.run/P36/agents/ov_SC06_018__func_8018B9D4/body.c @@ -0,0 +1,35 @@ +void func_8018B9D4(s32 param_1) +{ + struct { u16 a; u16 b; s16 c; u16 d; } t1; + struct { u16 a; u16 b; s16 c; u16 d; } t2; + + func_8018BCC4((void *)param_1, 0, (u16 *)(param_1 + 0xE8), 0x81818); + func_8018BCC4((void *)param_1, 1, (u16 *)(param_1 + 0xE8), 0x204040); + t1.b = 0; + t1.a = 0; + t1.c = -*(u16 *)(param_1 + 0xE8); + t2.b = 0; + t2.a = 0; + t2.c = -*(u16 *)(param_1 + 0xEA); + if (func_8012DEB8(param_1, &t1, &t2) != 0) { + D_80126B96 = 0x4018; + D_80126B98 = 0x96; + } + if (*(s16 *)(param_1 + 0xEA) < *(s16 *)(param_1 + 0xFE)) { + *(s16 *)(param_1 + 0xEA) += 0x40; + if (*(s16 *)(param_1 + 0xEA) >= *(s16 *)(param_1 + 0xFE)) { + *(s16 *)(param_1 + 0xEA) = *(s16 *)(param_1 + 0xFE); + func_8018BC40(param_1); + } + } else { + *(s16 *)(param_1 + 0xE8) += 0x40; + if (*(s16 *)(param_1 + 0xE8) < *(s16 *)(param_1 + 0xFE)) { + return; + } + if (*(s32 *)(param_1 + 0xCC) != 0) { + func_80016714((void *)*(s32 *)(param_1 + 0xCC), 0x38); + } + *(s32 *)(*(s32 *)(param_1 + 0x64) + 0xD0) = 0; + func_8012C218((void *)param_1); + } +} diff --git a/.run/P36/agents/ov_SC06_018__func_8018B9D4/mechanism.md b/.run/P36/agents/ov_SC06_018__func_8018B9D4/mechanism.md new file mode 100644 index 0000000000..154851a144 --- /dev/null +++ b/.run/P36/agents/ov_SC06_018__func_8018B9D4/mechanism.md @@ -0,0 +1,87 @@ +# func_8018B9D4 (src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c), e5, P36 T7 S104: CLOSED at 0, zero levers + +**Final: score 0 (81/81 ins, byte-identical, frame included), plain C.** Lever count 1 → 0 (the `$0` pin), and the +`s32 pad[2]` and `r1..r4` keepalives are gone as well. The whole change from `body_free.c`: the `var_ea/var_fe/var_a0/var_v0` +temp chain is replaced by direct field arithmetic on memory: + + if (*(s16 *)(param_1 + 0xEA) < *(s16 *)(param_1 + 0xFE)) { + *(s16 *)(param_1 + 0xEA) += 0x40; + if (*(s16 *)(param_1 + 0xEA) >= *(s16 *)(param_1 + 0xFE)) { ... } + } else { + *(s16 *)(param_1 + 0xE8) += 0x40; + if (*(s16 *)(param_1 + 0xE8) < *(s16 *)(param_1 + 0xFE)) return; + ... + +The class's other copy closes with the same text (callees renamed): **func_80186BAC** +(src/ov_SC06_032/ov_SC06_032_jr_80182890.c) scores **0** (`scratch/copy_func_80186BAC.c`). + +## (a) The residual +Same count (81/81). The target has `lh v0,234(s1); lh v1,254(s1); move a0,v0; slt v0,v0,v1; beqz; addiu v0,a0,64`. The +lever-free text has `lh v1; lh v0; nop; slt v0,v1,v0; addiu v0,v1,64`. The target keeps a **copy** of the loaded 0xEA value +(`move a0,v0`) that lives past the compare. The free text has no copy, and the compare and the add read one register. + +## (b) The pass and the decision (proved on dumps, `scratch/dumps_n2e/`, `dumps_c1/`, `dumps_c5/`) +The copy comes from **combine's narrow-load split**, `combine.c:1887-1940`: when a 3-insn combination builds +`(parallel [(set A (sign_extend (mem:HI))) (set P (mem:HI))])` because the narrow load's destination P is still +needed, combine splits it into `A = sign_extend(mem)` (= `lh`) plus `P:HI = (subreg:HI A)`, a register copy. +- P is still needed because `*(s16 *)(p+0xEA) += 0x40` re-reads the halfword, and cse1 forwards that read to the + HImode load pseudo P (`.cse` insn 104: `(plus:SI (subreg:SI (reg:HI 83)) 64)`). So P has two readers: the extension + for the compare, and the add. +- `.combine` insns 92/93: `(set (reg:SI 85) (sign_extend:SI (mem:HI …234)))` and `(set (reg:HI 83) (subreg:HI (reg:SI 85) 0))`. +- The copy's source is a **SUBREG**, so local-alloc's `optimize_reg_copy_1` does not touch it. That function rewrites a + later use of the source onto the copy so the two can be tied, and it is only called for `GET_CODE (SET_SRC) == REG` + (`local-alloc.c:1003-1007`). A85 dies at the `slt` and not at the copy, so `combine_regs` cannot tie them either → + two registers → `move a0,v0`. + +Why each temp spelling fails (bytes + dumps): +- `var_a0 = var_ea` (s32): a REG-REG copy. cse canonicalises it onto var_ea and deletes it. +- `var_a0 = (s16)var_ea` (`c1`): cse keeps the re-extension, combine reduces it to `(set 79 77)` (sign-bit copies), and then + **local-alloc's `optimize_reg_copy_1` rewrites the `slt` to read 79** (`.lreg` insn 103) and ties them. Score 5. +- `s16 var_a0; var_a0 = var_ea` (`c5`): a SUBREG copy, but cse `fold_rtx` SUBREG case (paradoxical subreg of a reg + equivalent to a lowpart subreg → the inner reg) folds the add's `(subreg:SI (reg:HI 79))` back to 77. The copy dies. Score 5. +- So the copy has to be created **after** cse by combine, and with a SUBREG source. That is the 1887 split, and only + a second READ of the same halfword creates it. A temp chain never does. + +## (c) The move +Spell the field update as the original almost certainly wrote it, `*(s16 *)(p + 0xEA) += 0x40;`, and re-read the field +in the following test instead of reusing a temp: `if (*(s16 *)(p + 0xEA) >= …)`. The else arm takes the same spelling on +0xE8 (`+= 0x40` as `s16` or `u16`, both 0). The re-read after the store is forwarded by cse (store-to-load), and +the target's `sll/sra` of the stored value is exactly that forwarded extension. The frame also came out right with no +pad: `.frame vars=32` in both. + +## (d) GENERATOR PROPOSAL +When the target keeps a `move rX,rY` right after an `lh rY` (or `lb`) and rX is used later only in an `addiu`/`sh` back +to the same field, rewrite the decompiler's temp chain `t = *(s16 *)(p+K); u = t; if (t < …) { v = u + C; *(s16 *)(p+K) = v; +if ((v << 16) >> 16 …` as `if (*(s16 *)(p+K) < …) { *(s16 *)(p+K) += C; if (*(s16 *)(p+K) …`. That is, **collapse the temps into +compound assignment on the memory lvalue and re-read the field at each test**. The tell is mechanical: a `move` whose +source was just loaded by `lh`/`lb` and which the text spells with a `+ zr` / `$0` pin or a launder. + +## (e) What did not work (all `--try`) +| spelling | score | +|---|---| +| body_free (start) | 5 | +| all 81 width combinations of var_ea/var_fe/var_a0/var_v0 ∈ {s32,s16,u16} (`scratch/w/`) | best 4 (`u16 var_a0`: copy kept but an extra `andi 0xffff`) | +| `var_a0 = (s16)var_ea` | 5 (optimize_reg_copy_1 ties it, above) | +| `var_ea` kept, `var_v0 = var_ea + 0x40`, `(s16)var_v0` test | 5 | +| `+= 0x40` text but with `pad[2]` kept | 8 (the frame is 8 bytes too big, the body is identical) | +| `+= 0x40` text, pad and `r1..r4` deleted | **0** | + +## (f) Where the method fell short +- Counting said "same count, one `nop` vs `move`": that is a copy the target keeps. Step 3's listed causes are all + about copies that **cse** deletes (R20/R21 width or distance). This one is deleted by **local-alloc + `optimize_reg_copy_1`** (`local-alloc.c:700`, caller `:1003`), a pass the method never names. Worth a line in step 3: + "a copy that survives cse and combine can still be folded by optimize_reg_copy_1 when its source is a REG that dies + later in the same block with no jump in between; a SUBREG-source copy (combine.c:1887 split) is exempt." +- The pad and the keepalives were part of the lever: the temp spelling needed a `pad[2]` to make the frame right. A + close that deletes the temps has to delete the pad too. Otherwise it scores 8 and looks worse than the start. +- No generator reaches "replace a temp chain with a compound assignment on the lvalue". R6 (inline) inlines one temp + at a time, and the first step alone does not create the second read. + +## (g) Structs answer +A struct would help the READABILITY, not the decision: `e->ea += 0x40; if (e->ea >= e->fe)` gives the same RTL as the +cast spelling (the field reads are `mem:HI` either way). The deciding facts are the second read of the same `s16` +location, the combine split and the SUBREG copy, and none of them involve aliasing. The struct is the natural way to +write the re-read, and that is likely why the original has it. Not tested separately. The cast text already closes. + +Files: `body.c` (the closed text), `scratch/copy_func_80186BAC.c` (the SC06_032 copy, 0), dumps in `scratch/dumps_n2e/` +(close), `scratch/dumps_c1/` and `scratch/dumps_c5/` (the two refuted copy spellings), `scratch/w/` (the width sweep). diff --git a/.run/P36/delever/calibration.json b/.run/P36/delever/calibration.json index 7b5359c6f8..e8b4ed7ba6 100644 --- a/.run/P36/delever/calibration.json +++ b/.run/P36/delever/calibration.json @@ -1,7 +1,7 @@ { - "head": "b591697b8", + "head": "a1a0a80e2", "stamp": "15956e4a96c4", - "generated": "2026-09-11 01:50", + "generated": "2026-09-11 01:54", "aliases": [ "main", "ov_SC03_014", @@ -21,206 +21,206 @@ "main": { "objects": 85, "identical": 85, - "seconds": 6.521999999999999, - "mean_s": 0.077 + "seconds": 6.381999999999998, + "mean_s": 0.075 }, "ov_SC03_014": { "objects": 32, "identical": 32, - "seconds": 4.517, - "mean_s": 0.141 + "seconds": 4.442, + "mean_s": 0.139 }, "ov_SC03_015": { "objects": 32, "identical": 32, - "seconds": 4.3549999999999995, - "mean_s": 0.136 + "seconds": 4.295999999999999, + "mean_s": 0.134 }, "ov_SC04_011": { "objects": 28, "identical": 28, - "seconds": 3.813, - "mean_s": 0.136 + "seconds": 3.727, + "mean_s": 0.133 } }, "per_object_seconds": { - "build/src/800.o": 0.699, - "build/src/800_b.o": 0.071, - "build/src/800_b_2.o": 0.304, - "build/src/800_b_o0a.o": 0.081, - "build/src/800_c.o": 0.183, - "build/src/800b2.o": 0.073, - "build/src/apicard1.o": 0.068, - "build/src/apicard2.o": 0.064, - "build/src/apicard3.o": 0.063, - "build/src/apicard4.o": 0.088, - "build/src/apicard5.o": 0.062, - "build/src/apicard6.o": 0.087, - "build/src/apicard7.o": 0.062, - "build/src/boot.o": 0.104, - "build/src/gap.o": 0.074, - "build/src/libapi1.o": 0.081, - "build/src/libapi2.o": 0.057, - "build/src/libc2_1.o": 0.06, - "build/src/libc2_2.o": 0.058, - "build/src/libcd1.o": 0.064, - "build/src/libcd2.o": 0.058, - "build/src/libetc.o": 0.066, - "build/src/libgpu.o": 0.059, - "build/src/libgpu2.o": 0.077, - "build/src/libgs1.o": 0.048, - "build/src/libgs2.o": 0.061, - "build/src/libgs3.o": 0.059, - "build/src/libgs4.o": 0.061, - "build/src/libgs5.o": 0.061, - "build/src/libgs6.o": 0.068, + "build/src/800.o": 0.711, + "build/src/800_b.o": 0.078, + "build/src/800_b_2.o": 0.277, + "build/src/800_b_o0a.o": 0.064, + "build/src/800_c.o": 0.189, + "build/src/800b2.o": 0.075, + "build/src/apicard1.o": 0.061, + "build/src/apicard2.o": 0.072, + "build/src/apicard3.o": 0.065, + "build/src/apicard4.o": 0.08, + "build/src/apicard5.o": 0.065, + "build/src/apicard6.o": 0.081, + "build/src/apicard7.o": 0.063, + "build/src/boot.o": 0.08, + "build/src/gap.o": 0.067, + "build/src/libapi1.o": 0.068, + "build/src/libapi2.o": 0.055, + "build/src/libc2_1.o": 0.058, + "build/src/libc2_2.o": 0.055, + "build/src/libcd1.o": 0.066, + "build/src/libcd2.o": 0.057, + "build/src/libetc.o": 0.061, + "build/src/libgpu.o": 0.057, + "build/src/libgpu2.o": 0.064, + "build/src/libgs1.o": 0.058, + "build/src/libgs2.o": 0.057, + "build/src/libgs3.o": 0.064, + "build/src/libgs4.o": 0.069, + "build/src/libgs5.o": 0.053, + "build/src/libgs6.o": 0.075, "build/src/libgs7.o": 0.061, - "build/src/libgs8.o": 0.061, - "build/src/libgte1.o": 0.063, - "build/src/libgte10.o": 0.063, + "build/src/libgs8.o": 0.057, + "build/src/libgte1.o": 0.065, + "build/src/libgte10.o": 0.062, "build/src/libgte11.o": 0.061, - "build/src/libgte12.o": 0.058, + "build/src/libgte12.o": 0.062, "build/src/libgte13.o": 0.064, - "build/src/libgte14.o": 0.069, - "build/src/libgte15.o": 0.05, - "build/src/libgte16.o": 0.057, - "build/src/libgte17.o": 0.07, - "build/src/libgte18.o": 0.061, - "build/src/libgte19.o": 0.059, - "build/src/libgte2.o": 0.064, - "build/src/libgte20.o": 0.063, - "build/src/libgte21.o": 0.061, - "build/src/libgte22.o": 0.053, - "build/src/libgte23.o": 0.057, - "build/src/libgte24.o": 0.064, - "build/src/libgte25.o": 0.059, - "build/src/libgte26.o": 0.063, - "build/src/libgte27.o": 0.067, - "build/src/libgte28.o": 0.053, - "build/src/libgte29.o": 0.06, - "build/src/libgte3.o": 0.059, - "build/src/libgte30.o": 0.06, - "build/src/libgte4.o": 0.061, - "build/src/libgte5.o": 0.063, - "build/src/libgte6.o": 0.062, - "build/src/libgte7.o": 0.069, - "build/src/libgte8.o": 0.061, - "build/src/libgte9.o": 0.069, - "build/src/libmcrd1.o": 0.071, - "build/src/libmcrd2.o": 0.064, - "build/src/libpad1.o": 0.06, - "build/src/libpad2.o": 0.075, - "build/src/sgap.o": 0.067, - "build/src/sgap_2.o": 0.062, + "build/src/libgte14.o": 0.063, + "build/src/libgte15.o": 0.062, + "build/src/libgte16.o": 0.054, + "build/src/libgte17.o": 0.061, + "build/src/libgte18.o": 0.063, + "build/src/libgte19.o": 0.058, + "build/src/libgte2.o": 0.059, + "build/src/libgte20.o": 0.068, + "build/src/libgte21.o": 0.058, + "build/src/libgte22.o": 0.063, + "build/src/libgte23.o": 0.054, + "build/src/libgte24.o": 0.077, + "build/src/libgte25.o": 0.079, + "build/src/libgte26.o": 0.055, + "build/src/libgte27.o": 0.061, + "build/src/libgte28.o": 0.052, + "build/src/libgte29.o": 0.049, + "build/src/libgte3.o": 0.063, + "build/src/libgte30.o": 0.069, + "build/src/libgte4.o": 0.055, + "build/src/libgte5.o": 0.059, + "build/src/libgte6.o": 0.064, + "build/src/libgte7.o": 0.063, + "build/src/libgte8.o": 0.06, + "build/src/libgte9.o": 0.059, + "build/src/libmcrd1.o": 0.073, + "build/src/libmcrd2.o": 0.061, + "build/src/libpad1.o": 0.065, + "build/src/libpad2.o": 0.056, + "build/src/sgap.o": 0.061, + "build/src/sgap_2.o": 0.064, "build/src/sgap_3.o": 0.064, - "build/src/sgap_4.o": 0.073, - "build/src/sgap_5.o": 0.064, - "build/src/sgap_6.o": 0.07, - "build/src/sgap_8.o": 0.072, - "build/src/snd1.o": 0.072, - "build/src/snd10.o": 0.061, - "build/src/snd11.o": 0.055, - "build/src/snd12.o": 0.067, - "build/src/snd2.o": 0.071, - "build/src/snd3.o": 0.064, - "build/src/snd4.o": 0.061, - "build/src/snd5.o": 0.072, - "build/src/snd6.o": 0.071, - "build/src/snd7.o": 0.066, - "build/src/snd8.o": 0.065, - "build/src/snd9.o": 0.069, - "build/src/ov_SC03_014/ov_SC03_014.o": 0.125, - "build/src/ov_SC03_014/ov_SC03_014_after.o": 0.5, - "build/src/ov_SC03_014/ov_SC03_014_jr_8012ACE0.o": 0.388, - "build/src/ov_SC03_014/ov_SC03_014_jr_80135888.o": 0.065, - "build/src/ov_SC03_014/ov_SC03_014_jr_80135A4C.o": 0.057, - "build/src/ov_SC03_014/ov_SC03_014_jr_80135D20.o": 0.117, - "build/src/ov_SC03_014/ov_SC03_014_jr_801380E0.o": 0.148, - "build/src/ov_SC03_014/ov_SC03_014_jr_8013C98C.o": 0.129, - "build/src/ov_SC03_014/ov_SC03_014_jr_8013F350.o": 0.075, - "build/src/ov_SC03_014/ov_SC03_014_jr_8013FFD8.o": 0.066, - "build/src/ov_SC03_014/ov_SC03_014_jr_80140608.o": 0.174, - "build/src/ov_SC03_014/ov_SC03_014_jr_8015444C.o": 0.07, - "build/src/ov_SC03_014/ov_SC03_014_jr_80154C24.o": 0.188, - "build/src/ov_SC03_014/ov_SC03_014_jr_801588CC.o": 0.097, - "build/src/ov_SC03_014/ov_SC03_014_jr_80159C84.o": 0.061, - "build/src/ov_SC03_014/ov_SC03_014_jr_8015A3C8.o": 0.075, - "build/src/ov_SC03_014/ov_SC03_014_jr_8015AE2C.o": 0.089, - "build/src/ov_SC03_014/ov_SC03_014_jr_8015C32C.o": 0.441, - "build/src/ov_SC03_014/ov_SC03_014_jr_8016AB6C.o": 0.261, - "build/src/ov_SC03_014/ov_SC03_014_jr_80171B4C.o": 0.094, - "build/src/ov_SC03_014/ov_SC03_014_jr_801734BC.o": 0.182, - "build/src/ov_SC03_014/ov_SC03_014_jr_801789AC.o": 0.054, + "build/src/sgap_4.o": 0.082, + "build/src/sgap_5.o": 0.062, + "build/src/sgap_6.o": 0.062, + "build/src/sgap_8.o": 0.07, + "build/src/snd1.o": 0.064, + "build/src/snd10.o": 0.063, + "build/src/snd11.o": 0.069, + "build/src/snd12.o": 0.059, + "build/src/snd2.o": 0.065, + "build/src/snd3.o": 0.059, + "build/src/snd4.o": 0.059, + "build/src/snd5.o": 0.068, + "build/src/snd6.o": 0.068, + "build/src/snd7.o": 0.063, + "build/src/snd8.o": 0.06, + "build/src/snd9.o": 0.06, + "build/src/ov_SC03_014/ov_SC03_014.o": 0.128, + "build/src/ov_SC03_014/ov_SC03_014_after.o": 0.499, + "build/src/ov_SC03_014/ov_SC03_014_jr_8012ACE0.o": 0.38, + "build/src/ov_SC03_014/ov_SC03_014_jr_80135888.o": 0.072, + "build/src/ov_SC03_014/ov_SC03_014_jr_80135A4C.o": 0.058, + "build/src/ov_SC03_014/ov_SC03_014_jr_80135D20.o": 0.116, + "build/src/ov_SC03_014/ov_SC03_014_jr_801380E0.o": 0.15, + "build/src/ov_SC03_014/ov_SC03_014_jr_8013C98C.o": 0.112, + "build/src/ov_SC03_014/ov_SC03_014_jr_8013F350.o": 0.077, + "build/src/ov_SC03_014/ov_SC03_014_jr_8013FFD8.o": 0.067, + "build/src/ov_SC03_014/ov_SC03_014_jr_80140608.o": 0.196, + "build/src/ov_SC03_014/ov_SC03_014_jr_8015444C.o": 0.072, + "build/src/ov_SC03_014/ov_SC03_014_jr_80154C24.o": 0.169, + "build/src/ov_SC03_014/ov_SC03_014_jr_801588CC.o": 0.093, + "build/src/ov_SC03_014/ov_SC03_014_jr_80159C84.o": 0.064, + "build/src/ov_SC03_014/ov_SC03_014_jr_8015A3C8.o": 0.073, + "build/src/ov_SC03_014/ov_SC03_014_jr_8015AE2C.o": 0.091, + "build/src/ov_SC03_014/ov_SC03_014_jr_8015C32C.o": 0.427, + "build/src/ov_SC03_014/ov_SC03_014_jr_8016AB6C.o": 0.25, + "build/src/ov_SC03_014/ov_SC03_014_jr_80171B4C.o": 0.091, + "build/src/ov_SC03_014/ov_SC03_014_jr_801734BC.o": 0.183, + "build/src/ov_SC03_014/ov_SC03_014_jr_801789AC.o": 0.053, "build/src/ov_SC03_014/ov_SC03_014_jr_80178D40.o": 0.095, - "build/src/ov_SC03_014/ov_SC03_014_jr_8017A4AC.o": 0.065, - "build/src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.o": 0.153, - "build/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.o": 0.19, - "build/src/ov_SC03_014/ov_SC03_014_jr_80184440.o": 0.048, - "build/src/ov_SC03_014/ov_SC03_014_jr_801848E4.o": 0.276, - "build/src/ov_SC03_014/ov_SC03_014_o0b.o": 0.056, + "build/src/ov_SC03_014/ov_SC03_014_jr_8017A4AC.o": 0.061, + "build/src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.o": 0.15, + "build/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.o": 0.184, + "build/src/ov_SC03_014/ov_SC03_014_jr_80184440.o": 0.044, + "build/src/ov_SC03_014/ov_SC03_014_jr_801848E4.o": 0.266, + "build/src/ov_SC03_014/ov_SC03_014_o0b.o": 0.05, "build/src/ov_SC03_014/ov_SC03_014_o0c.o": 0.057, - "build/src/ov_SC03_014/ov_SC03_014_o0d.o": 0.057, - "build/src/ov_SC03_014/ov_SC03_014_o0e.o": 0.064, - "build/src/ov_SC03_015/ov_SC03_015.o": 0.118, - "build/src/ov_SC03_015/ov_SC03_015_after.o": 0.518, - "build/src/ov_SC03_015/ov_SC03_015_jr_8012ACE0.o": 0.369, - "build/src/ov_SC03_015/ov_SC03_015_jr_80135888.o": 0.051, - "build/src/ov_SC03_015/ov_SC03_015_jr_80135A4C.o": 0.051, - "build/src/ov_SC03_015/ov_SC03_015_jr_80135D20.o": 0.122, - "build/src/ov_SC03_015/ov_SC03_015_jr_801380E0.o": 0.143, - "build/src/ov_SC03_015/ov_SC03_015_jr_8013C98C.o": 0.112, - "build/src/ov_SC03_015/ov_SC03_015_jr_8013F350.o": 0.076, - "build/src/ov_SC03_015/ov_SC03_015_jr_8013FFD8.o": 0.063, - "build/src/ov_SC03_015/ov_SC03_015_jr_80140608.o": 0.166, - "build/src/ov_SC03_015/ov_SC03_015_jr_8015444C.o": 0.068, - "build/src/ov_SC03_015/ov_SC03_015_jr_80154C24.o": 0.163, - "build/src/ov_SC03_015/ov_SC03_015_jr_801588CC.o": 0.084, - "build/src/ov_SC03_015/ov_SC03_015_jr_80159C84.o": 0.067, - "build/src/ov_SC03_015/ov_SC03_015_jr_8015A3C8.o": 0.07, - "build/src/ov_SC03_015/ov_SC03_015_jr_8015AE2C.o": 0.094, - "build/src/ov_SC03_015/ov_SC03_015_jr_8015C32C.o": 0.421, - "build/src/ov_SC03_015/ov_SC03_015_jr_8016AB6C.o": 0.254, - "build/src/ov_SC03_015/ov_SC03_015_jr_80171B4C.o": 0.094, - "build/src/ov_SC03_015/ov_SC03_015_jr_801734BC.o": 0.181, - "build/src/ov_SC03_015/ov_SC03_015_jr_801789AC.o": 0.056, - "build/src/ov_SC03_015/ov_SC03_015_jr_80178D40.o": 0.099, - "build/src/ov_SC03_015/ov_SC03_015_jr_8017A4AC.o": 0.056, - "build/src/ov_SC03_015/ov_SC03_015_jr_8017AE2C.o": 0.156, - "build/src/ov_SC03_015/ov_SC03_015_jr_8017EB7C.o": 0.165, - "build/src/ov_SC03_015/ov_SC03_015_jr_80184440.o": 0.05, - "build/src/ov_SC03_015/ov_SC03_015_jr_801848E4.o": 0.257, - "build/src/ov_SC03_015/ov_SC03_015_o0b.o": 0.05, - "build/src/ov_SC03_015/ov_SC03_015_o0c.o": 0.059, - "build/src/ov_SC03_015/ov_SC03_015_o0d.o": 0.055, - "build/src/ov_SC03_015/ov_SC03_015_o0e.o": 0.067, - "build/src/ov_SC04_011/ov_SC04_011.o": 0.123, - "build/src/ov_SC04_011/ov_SC04_011_after.o": 0.415, - "build/src/ov_SC04_011/ov_SC04_011_jr_8012ACE0.o": 0.332, - "build/src/ov_SC04_011/ov_SC04_011_jr_80135888.o": 0.055, - "build/src/ov_SC04_011/ov_SC04_011_jr_80135A4C.o": 0.048, - "build/src/ov_SC04_011/ov_SC04_011_jr_80135D20.o": 0.105, - "build/src/ov_SC04_011/ov_SC04_011_jr_801380E0.o": 0.153, - "build/src/ov_SC04_011/ov_SC04_011_jr_8013C98C.o": 0.104, - "build/src/ov_SC04_011/ov_SC04_011_jr_8013F350.o": 0.072, - "build/src/ov_SC04_011/ov_SC04_011_jr_8013FFD8.o": 0.059, - "build/src/ov_SC04_011/ov_SC04_011_jr_80140608.o": 0.168, - "build/src/ov_SC04_011/ov_SC04_011_jr_8015444C.o": 0.074, + "build/src/ov_SC03_014/ov_SC03_014_o0d.o": 0.048, + "build/src/ov_SC03_014/ov_SC03_014_o0e.o": 0.066, + "build/src/ov_SC03_015/ov_SC03_015.o": 0.119, + "build/src/ov_SC03_015/ov_SC03_015_after.o": 0.472, + "build/src/ov_SC03_015/ov_SC03_015_jr_8012ACE0.o": 0.345, + "build/src/ov_SC03_015/ov_SC03_015_jr_80135888.o": 0.045, + "build/src/ov_SC03_015/ov_SC03_015_jr_80135A4C.o": 0.054, + "build/src/ov_SC03_015/ov_SC03_015_jr_80135D20.o": 0.121, + "build/src/ov_SC03_015/ov_SC03_015_jr_801380E0.o": 0.134, + "build/src/ov_SC03_015/ov_SC03_015_jr_8013C98C.o": 0.103, + "build/src/ov_SC03_015/ov_SC03_015_jr_8013F350.o": 0.063, + "build/src/ov_SC03_015/ov_SC03_015_jr_8013FFD8.o": 0.059, + "build/src/ov_SC03_015/ov_SC03_015_jr_80140608.o": 0.151, + "build/src/ov_SC03_015/ov_SC03_015_jr_8015444C.o": 0.063, + "build/src/ov_SC03_015/ov_SC03_015_jr_80154C24.o": 0.165, + "build/src/ov_SC03_015/ov_SC03_015_jr_801588CC.o": 0.088, + "build/src/ov_SC03_015/ov_SC03_015_jr_80159C84.o": 0.063, + "build/src/ov_SC03_015/ov_SC03_015_jr_8015A3C8.o": 0.062, + "build/src/ov_SC03_015/ov_SC03_015_jr_8015AE2C.o": 0.09, + "build/src/ov_SC03_015/ov_SC03_015_jr_8015C32C.o": 0.435, + "build/src/ov_SC03_015/ov_SC03_015_jr_8016AB6C.o": 0.253, + "build/src/ov_SC03_015/ov_SC03_015_jr_80171B4C.o": 0.1, + "build/src/ov_SC03_015/ov_SC03_015_jr_801734BC.o": 0.191, + "build/src/ov_SC03_015/ov_SC03_015_jr_801789AC.o": 0.052, + "build/src/ov_SC03_015/ov_SC03_015_jr_80178D40.o": 0.097, + "build/src/ov_SC03_015/ov_SC03_015_jr_8017A4AC.o": 0.062, + "build/src/ov_SC03_015/ov_SC03_015_jr_8017AE2C.o": 0.157, + "build/src/ov_SC03_015/ov_SC03_015_jr_8017EB7C.o": 0.191, + "build/src/ov_SC03_015/ov_SC03_015_jr_80184440.o": 0.052, + "build/src/ov_SC03_015/ov_SC03_015_jr_801848E4.o": 0.268, + "build/src/ov_SC03_015/ov_SC03_015_o0b.o": 0.06, + "build/src/ov_SC03_015/ov_SC03_015_o0c.o": 0.053, + "build/src/ov_SC03_015/ov_SC03_015_o0d.o": 0.057, + "build/src/ov_SC03_015/ov_SC03_015_o0e.o": 0.071, + "build/src/ov_SC04_011/ov_SC04_011.o": 0.127, + "build/src/ov_SC04_011/ov_SC04_011_after.o": 0.411, + "build/src/ov_SC04_011/ov_SC04_011_jr_8012ACE0.o": 0.326, + "build/src/ov_SC04_011/ov_SC04_011_jr_80135888.o": 0.046, + "build/src/ov_SC04_011/ov_SC04_011_jr_80135A4C.o": 0.053, + "build/src/ov_SC04_011/ov_SC04_011_jr_80135D20.o": 0.102, + "build/src/ov_SC04_011/ov_SC04_011_jr_801380E0.o": 0.148, + "build/src/ov_SC04_011/ov_SC04_011_jr_8013C98C.o": 0.106, + "build/src/ov_SC04_011/ov_SC04_011_jr_8013F350.o": 0.069, + "build/src/ov_SC04_011/ov_SC04_011_jr_8013FFD8.o": 0.051, + "build/src/ov_SC04_011/ov_SC04_011_jr_80140608.o": 0.165, + "build/src/ov_SC04_011/ov_SC04_011_jr_8015444C.o": 0.063, "build/src/ov_SC04_011/ov_SC04_011_jr_80154C24.o": 0.152, "build/src/ov_SC04_011/ov_SC04_011_jr_801588CC.o": 0.087, - "build/src/ov_SC04_011/ov_SC04_011_jr_80159C84.o": 0.064, - "build/src/ov_SC04_011/ov_SC04_011_jr_8015A3C8.o": 0.061, - "build/src/ov_SC04_011/ov_SC04_011_jr_8015AE2C.o": 0.093, - "build/src/ov_SC04_011/ov_SC04_011_jr_8015C32C.o": 0.377, - "build/src/ov_SC04_011/ov_SC04_011_jr_8016AB6C.o": 0.215, - "build/src/ov_SC04_011/ov_SC04_011_jr_80171B4C.o": 0.098, - "build/src/ov_SC04_011/ov_SC04_011_jr_801734BC.o": 0.156, - "build/src/ov_SC04_011/ov_SC04_011_jr_801789AC.o": 0.056, - "build/src/ov_SC04_011/ov_SC04_011_jr_80178D40.o": 0.081, - "build/src/ov_SC04_011/ov_SC04_011_jr_8017A4AC.o": 0.063, - "build/src/ov_SC04_011/ov_SC04_011_jr_8017AE2C.o": 0.093, - "build/src/ov_SC04_011/ov_SC04_011_jr_8017D494.o": 0.406, - "build/src/ov_SC04_011/ov_SC04_011_o0b.o": 0.051, - "build/src/ov_SC04_011/ov_SC04_011_o0c.o": 0.052 + "build/src/ov_SC04_011/ov_SC04_011_jr_80159C84.o": 0.065, + "build/src/ov_SC04_011/ov_SC04_011_jr_8015A3C8.o": 0.063, + "build/src/ov_SC04_011/ov_SC04_011_jr_8015AE2C.o": 0.095, + "build/src/ov_SC04_011/ov_SC04_011_jr_8015C32C.o": 0.335, + "build/src/ov_SC04_011/ov_SC04_011_jr_8016AB6C.o": 0.217, + "build/src/ov_SC04_011/ov_SC04_011_jr_80171B4C.o": 0.087, + "build/src/ov_SC04_011/ov_SC04_011_jr_801734BC.o": 0.155, + "build/src/ov_SC04_011/ov_SC04_011_jr_801789AC.o": 0.055, + "build/src/ov_SC04_011/ov_SC04_011_jr_80178D40.o": 0.086, + "build/src/ov_SC04_011/ov_SC04_011_jr_8017A4AC.o": 0.061, + "build/src/ov_SC04_011/ov_SC04_011_jr_8017AE2C.o": 0.105, + "build/src/ov_SC04_011/ov_SC04_011_jr_8017D494.o": 0.404, + "build/src/ov_SC04_011/ov_SC04_011_o0b.o": 0.044, + "build/src/ov_SC04_011/ov_SC04_011_o0c.o": 0.049 }, "ok": true, "seconds": 2.2 diff --git a/.run/P36/delever/ledger.jsonl b/.run/P36/delever/ledger.jsonl index 118c988cf3..94c2ecc9e0 100644 --- a/.run/P36/delever/ledger.jsonl +++ b/.run/P36/delever/ledger.jsonl @@ -29402,3 +29402,4 @@ {"ts": "2026-09-11 01:50:32", "label": "s104_e9", "rung": "E", "calib": {"head": "09bf5ea39", "stamp": "15956e4a96c4"}, "tu": "src/ov_SC02_017/ov_SC02_017_jr_8017DF34.c", "fn": "func_8017F768", "addr": 2149054312, "aliases": null, "header": false, "includers": 0, "nhash_before": "56acff1e69cd39c010f53734fd44bb9ae5d68f7c", "nhash_after": "2caa54014192539150ae4240e5db8f74058ca1e0", "source": ".run/P36/agents/ov_SC02_017__func_8017F768/body.c", "verdict": "LEVER-FREE", "sites": [], "compiles": 1, "seconds": 0.194, "objects": ["build/src/ov_SC02_017/ov_SC02_017_jr_8017DF34.o"], "before_text": "void func_8017F768(s32 a0) {\n s32 s0 = a0;\n /* $s1 pin: without it the distance/angle pair allocates swapped ($s1<->$s2)\n AND `s1 = 0x800` floats out of the beqz delay slot. */\n register s32 s1 __asm__(\"$17\"); // !FAKE: pin $17 \u2014 NEEDED DIFFERS (P36 rung B tus8)\n /* NOT pinned: pinning $s2 makes local_alloc suggest the dying $18 for the\n `s2 >= 0x801` compare result, emitting `slti $s2,...` instead of the\n target's `slti $v0,$s2,0x801`. */\n s32 s2;\n /* $a0 pin: the target computes `andi $a0,$v0,0xFFF` then `addu $s1,$a0,$zero`\n and reuses the live $a0 as func_801898A4's first argument (no `move $a0,$s1`\n at the call). Coalescing kills that copy unless the value is born in $a0. */\n register s32 angle __asm__(\"$4\"); // !FAKE: pin $4 \u2014 NEEDED DIFFERS (P36 rung B tus8)\n s32 ret;\n s16 pt[4];\n\n if (func_80148800((s32 *)&D_80126B58) & 3) {\n u8 t = (*(u8 *)(s0 + 5) + 1) & 1;\n *(u8 *)(s0 + 5) = t;\n *(s32 *)(s0 + 0x14) = D_8018E1E0[t];\n }\n\n pt[0] = D_80126940[0];\n pt[1] = 0;\n pt[2] = D_80126940[2];\n\n s2 = (s16)func_80013294((void *)&D_8018E1D0, (void *)pt);\n\n s1 = 0x800;\n if (s2 < 0x200) {\n *(s16 *)(s0 + 0x20) = 0x71;\n *(s16 *)(s0 + 0x22) = 0;\n *(s16 *)(s0 + 0x24) = 0;\n *(s16 *)(s0 + 0x2E) = 0;\n *(s16 *)(s0 + 0x30) = -0xC0;\n *(s16 *)(s0 + 0x32) = 0;\n } else {\n *(s16 *)(s0 + 0x22) = 0;\n\n angle = ratan2((s32)D_80126940[0] << 16, (s32)D_80126940[2] << 16) & 0xFFF;\n s1 = angle;\n\n *(s16 *)(s0 + 0x20) = 0x1C7;\n *(s16 *)(s0 + 0x30) = -0x10;\n *(s16 *)(s0 + 0x22) = 0;\n *(s16 *)(s0 + 0x24) = 0;\n *(s16 *)(s0 + 0x2E) = 0;\n /* +0x32 is stored ONCE PER ARM and, in this arm, ABOVE the inner if\n (\u00a7194-M: it lands in the bnez delay slot, so it dominates the branch\n and is NOT executed on the s2 >= 0x801 path). Writing it once after\n the outer if/else is what cross_jump then folds to 112 instructions. */\n *(s16 *)(s0 + 0x32) = 0;\n\n if (s2 >= 0x801) {\n u16 tmp[4];\n tmp[0] = 0;\n tmp[1] = D_80126942;\n tmp[2] = 0x800;\n\n func_801898A4(angle, tmp, tmp);\n\n D_80126940[0] = (s16)tmp[0] >> 3;\n D_80126942 = (s16)tmp[1] >> 3;\n D_80126940[2] = (s16)tmp[2] >> 3;\n }\n }\n\n D_801274EA = (s16)s1;\n ret = func_80012DBC((s32)D_801EF9F0, s1, 0x14, 1);\n D_801EF9F0 = (s16)ret;\n func_8017F92C(s0, (s16)ret, D_80126940);\n}\n", "after_text": "void func_8017F768(s32 a0) {\n s16 dir;\n s16 dist;\n s32 angle;\n s32 ret;\n s16 pt[4];\n\n if (func_80148800((s32 *)&D_80126B58) & 3) {\n u8 t = (*(u8 *)(a0 + 5) + 1) & 1;\n *(u8 *)(a0 + 5) = t;\n *(s32 *)(a0 + 0x14) = D_8018E1E0[t];\n }\n\n pt[0] = D_80126940[0];\n pt[1] = 0;\n pt[2] = D_80126940[2];\n\n dist = func_80013294((void *)&D_8018E1D0, (void *)pt);\n\n if (dist < 0x200) {\n dir = 0x800;\n *(s16 *)(a0 + 0x20) = 0x71;\n *(s16 *)(a0 + 0x22) = 0;\n *(s16 *)(a0 + 0x24) = 0;\n *(s16 *)(a0 + 0x2E) = 0;\n *(s16 *)(a0 + 0x30) = -0xC0;\n *(s16 *)(a0 + 0x32) = 0;\n } else {\n *(s16 *)(a0 + 0x22) = 0;\n\n angle = ratan2((s32)D_80126940[0] << 16, (s32)D_80126940[2] << 16) & 0xFFF;\n dir = angle;\n\n *(s16 *)(a0 + 0x20) = 0x1C7;\n *(s16 *)(a0 + 0x30) = -0x10;\n *(s16 *)(a0 + 0x22) = 0;\n *(s16 *)(a0 + 0x24) = 0;\n *(s16 *)(a0 + 0x2E) = 0;\n /* +0x32 is stored ONCE PER ARM and, in this arm, ABOVE the inner if\n (\u00a7194-M: it lands in the bnez delay slot, so it dominates the branch\n and is NOT executed on the dist >= 0x801 path). Writing it once after\n the outer if/else is what cross_jump then folds to 112 instructions. */\n *(s16 *)(a0 + 0x32) = 0;\n\n if (dist >= 0x801) {\n u16 tmp[4];\n tmp[0] = 0;\n tmp[1] = D_80126942;\n tmp[2] = 0x800;\n\n func_801898A4(angle, tmp, tmp);\n\n D_80126940[0] = (s16)tmp[0] >> 3;\n D_80126942 = (s16)tmp[1] >> 3;\n D_80126940[2] = (s16)tmp[2] >> 3;\n }\n }\n\n D_801274EA = dir;\n ret = func_80012DBC((s32)D_801EF9F0, dir, 0x14, 1);\n D_801EF9F0 = (s16)ret;\n func_8017F92C(a0, (s16)ret, D_80126940);\n}\n"} {"ts": "2026-09-11 01:50:49", "label": "s104_e9", "rung": "E", "calib": {"head": "31fb83027", "stamp": "15956e4a96c4"}, "tu": "src/ov_SC02_017/ov_SC02_017_jr_8017DF34.c", "fn": "func_8017FCFC", "addr": 2149055740, "aliases": null, "header": false, "includers": 0, "nhash_before": "3696cabfe6b4ed90988b40e43fd89a850f8d9c38", "nhash_after": "7498c74c7f83ebd46de7113de29be86e6f138144", "source": ".run/P36/agents/ov_SC02_017__func_8017FCFC/body.c", "verdict": "LEVER-FREE", "sites": [], "compiles": 1, "seconds": 0.193, "objects": ["build/src/ov_SC02_017/ov_SC02_017_jr_8017DF34.o"], "before_text": "void func_8017FCFC(void *a0) {\n s32 t;\n register s32 u __asm__(\"$3\"); // !FAKE: pin $3 \u2014 NEEDED DIFFERS (P36 rung B tus8)\n register s32 zr __asm__(\"$0\"); // !FAKE: pin $0 \u2014 NEEDED DIFFERS (P36 rung B tus8)\n s32 frame_pad;\n s32 k;\n s32 *p;\n\n (void)(s32 *)&frame_pad;\n t = *(s16 *)((s32)a0 + 0xFE);\n if (t != 0) {\n u = t + zr;\n t = u - 1;\n *(s16 *)((s32)a0 + 0xFE) = t;\n return;\n }\n k = *(u16 *)((s32)a0 + 0x5C);\n if ((k & 1) == 0) {\n return;\n }\n *(u16 *)((s32)a0 + 0x5C) = k & 0xFFFE;\n p = D_8018E204;\n t = func_800291B4(D_8018E204[(*(u16 *)((s32)a0 + 0x70)) & 0xF]) & 0xFF;\n if (t != 0) {\n *(u16 *)((s32)a0 + 0x5E) = 0;\n t = 8;\n *(s16 *)((s32)a0 + 0xFE) = t;\n return;\n }\n k = *(u16 *)((s32)a0 + 0x5E);\n if (k == 0xC) {\n __asm__(\"\" : \"=r\"(p) : \"0\"(p)); // !FAKE: launder \u2014 NEEDED DIFFERS (P36 rung B tus8)\n *(s32 *)((s32)a0 + 0x58) = (s32)D_8018E1F4 | 0x40000000 | 0x20000000;\n func_800291A0(p[(*(u16 *)((s32)a0 + 0x70)) & 0xF], 1);\n t = 0x8C00;\n *(u16 *)((s32)a0 + 0x5C) = t;\n } else {\n t = 8;\n *(s16 *)((s32)a0 + 0xFE) = t;\n if (k != 0x1D && *(s32 *)((s32)a0 + 0xDC) == 0) {\n *(s32 *)((s32)a0 + 0xDC) = 1;\n func_801746DC();\n ((void (*)(void))func_80178BF8)();\n *(s16 *)((s32)a0 + 0x2) = 2;\n func_8002D4C8(0x59D, 0);\n *(u16 *)((s32)a0 + 0x5E) = 0;\n return;\n }\n }\n *(u16 *)((s32)a0 + 0x5E) = 0;\n}\n", "after_text": "void func_8017FCFC(void *a0) {\n s32 k;\n\n if (*(s16 *)((s32)a0 + 0xFE) != 0) {\n *(s16 *)((s32)a0 + 0xFE) -= 1;\n return;\n }\n k = *(u16 *)((s32)a0 + 0x5C);\n if ((k & 1) == 0) {\n return;\n }\n *(u16 *)((s32)a0 + 0x5C) = k & 0xFFFE;\n if ((func_800291B4(D_8018E204[*(u16 *)((s32)a0 + 0x70) & 0xF]) & 0xFF) != 0) {\n *(u16 *)((s32)a0 + 0x5E) = 0;\n *(s16 *)((s32)a0 + 0xFE) = 8;\n return;\n }\n k = *(u16 *)((s32)a0 + 0x5E);\n if (k == 0xC) {\n *(s32 *)((s32)a0 + 0x58) = (s32)D_8018E1F4 | 0x40000000 | 0x20000000;\n func_800291A0(D_8018E204[*(u16 *)((s32)a0 + 0x70) & 0xF], 1);\n *(u16 *)((s32)a0 + 0x5C) = 0x8C00;\n } else {\n *(s16 *)((s32)a0 + 0xFE) = 8;\n if (k != 0x1D && *(s32 *)((s32)a0 + 0xDC) == 0) {\n *(s32 *)((s32)a0 + 0xDC) = 1;\n func_801746DC();\n ((void (*)(void))func_80178BF8)();\n *(s16 *)((s32)a0 + 0x2) = 2;\n func_8002D4C8(0x59D, 0);\n *(u16 *)((s32)a0 + 0x5E) = 0;\n return;\n }\n }\n *(u16 *)((s32)a0 + 0x5E) = 0;\n}\n"} {"ts": "2026-09-11 01:51:07", "label": "s104_e9", "rung": "E", "calib": {"head": "b591697b8", "stamp": "15956e4a96c4"}, "tu": "src/ov_SC02_017/ov_SC02_017_jr_8017DF34.c", "fn": "func_8018209C", "addr": 2149064860, "aliases": null, "header": false, "includers": 0, "nhash_before": "1427b5b4f01d5be2de684f2e48f07d0c4fffa587", "nhash_after": "31c71e7400f76e47f0c1ce76e2048b5bb257b0c8", "source": ".run/P36/agents/ov_SC02_017__func_8018209C/body.c", "verdict": "LEVER-FREE", "sites": [], "compiles": 1, "seconds": 0.201, "objects": ["build/src/ov_SC02_017/ov_SC02_017_jr_8017DF34.o"], "before_text": "void func_8018209C(void *arg0)\n{\n SV_8018209C vin;\n SV_8018209C w;\n RES_8018209C res;\n register s32 g __asm__(\"$7\"); // !FAKE: pin $7 \u2014 NEEDED DIFFERS (P36 rung B tus8)\n s32 rv;\n\n func_8012F214((s32)arg0, (s32)D_8018E56C, (s32)&vin);\n\n g = (s32)&D_800AF648;\n __asm__ __volatile__( // !FAKE: gte direct \u2014 clobbers beyond Sony's macro (a scheduling steer; P36 T5 t5_remark3)\n \"lw $12, 0(%0)\\n\" \"lw $13, 4(%0)\\n\"\n \"ctc2 $12, $0\\n\" \"ctc2 $13, $1\\n\"\n \"lw $12, 8(%0)\\n\" \"lw $13, 12(%0)\\n\" \"lw $14, 16(%0)\\n\"\n \"ctc2 $12, $2\\n\" \"ctc2 $13, $3\\n\" \"ctc2 $14, $4\\n\"\n : : \"r\"(g) : \"$12\", \"$13\", \"$14\", \"memory\"); // !FAKE: gte direct \u2014 clobbers ['memory'] (gte_SetRotMatrix_m) beyond Sony's (P36 T5 gte1)\n __asm__ __volatile__(\n \"lw $12, 20(%0)\\n\" \"lw $13, 24(%0)\\n\"\n \"ctc2 $12, $5\\n\" \"lw $14, 28(%0)\\n\"\n \"ctc2 $13, $6\\n\" \"ctc2 $14, $7\\n\"\n : : \"r\"(g) : \"$12\", \"$13\", \"$14\", \"memory\");\n\n gte_ldv0(&vin);\n gte_rtps();\n gte_stsxy(&res.x);\n gte_stflg(&res.flag);\n\n if ((res.flag & -0x1001) != 0) { rv = 0; goto out; }\n if ((res.x < 0 ? -res.x : res.x) >= 0xAB)\n goto L2;\n if ((res.y < 0 ? -res.y : res.y) >= 0x83)\n goto L2;\n goto tail;\n\nL2:\n w.vx = *(u16 *)((s32)arg0 + 6);\n w.vy = *(u16 *)((s32)arg0 + 0xA);\n w.vz = *(u16 *)((s32)arg0 + 0xE);\n gte_ldv0(&w);\n gte_rtps();\n gte_stsxy(&res.x);\n gte_stflg(&res.flag);\n\n if ((res.flag & -0x1001) != 0) { rv = 0; goto out; }\n if ((res.x < 0 ? -res.x : res.x) >= 0x105) { rv = 0; goto out; }\n if ((res.y < 0 ? -res.y : res.y) >= 0x8D) { rv = 0; goto out; }\ntail:\n if (func_80013478((s32)&D_80126B5C, (s32)&vin) <= 0x41010)\n func_8002D4C8(0xB67, 0);\n rv = 1;\nout:\n __asm__ __volatile__(\"\" : : \"r\"(rv)); // !FAKE: keepalive \u2014 NEEDED DIFFERS (P36 rung B tus8)\n}\n", "after_text": "s32 func_8018209C_impl(void *arg0) __asm__(\"func_8018209C\");\n\ns32 func_8018209C_impl(void *arg0)\n{\n SV_8018209C vin;\n SV_8018209C w;\n RES_8018209C res;\n s32 t;\n\n func_8012F214((s32)arg0, (s32)D_8018E56C, (s32)&vin);\n gte_SetRotMatrix(&D_800AF648);\n gte_SetTransMatrix(&D_800AF648);\n gte_ldv0(&vin);\n gte_rtps();\n gte_stsxy(&res.x);\n gte_stflg(&res.flag);\n if (res.flag & 0xFFFFEFFF) {\n return 0;\n }\n t = res.x;\n if (t < 0) {\n t = -t;\n }\n if (t >= 0xAB || (res.y >= 0 ? res.y >= 0x83 : -res.y >= 0x83)) {\n w.vx = *(u16 *)((s32)arg0 + 6);\n w.vy = *(u16 *)((s32)arg0 + 0xA);\n w.vz = *(u16 *)((s32)arg0 + 0xE);\n gte_ldv0(&w);\n gte_rtps();\n gte_stsxy(&res.x);\n gte_stflg(&res.flag);\n if (res.flag & 0xFFFFEFFF) {\n return 0;\n }\n t = res.x;\n if (t < 0) {\n t = -t;\n }\n if (t >= 0x105 || (res.y >= 0 ? res.y >= 0x8D : -res.y >= 0x8D)) {\n return 0;\n }\n }\n if (func_80013478((s32)&D_80126B5C, (s32)&vin) <= 0x41010) {\n func_8002D4C8(0xB67, 0);\n }\n return 1;\n}\n"} +{"ts": "2026-09-11 01:54:48", "label": "s104_e5", "rung": "E", "calib": {"head": "a1a0a80e2", "stamp": "15956e4a96c4"}, "tu": "src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c", "fn": "func_8018AD74", "addr": 2149100916, "aliases": null, "header": false, "includers": 0, "nhash_before": "5cf426b9638201838f4f6f8c83154714c1922fde", "nhash_after": "8d4a5656fffc75dcc5fa2d3c72854b7c88197dae", "source": ".run/P36/agents/ov_SC06_018__func_8018AD74/body.c", "verdict": "LEVER-FREE", "sites": [], "compiles": 1, "seconds": 0.189, "objects": ["build/src/ov_SC06_018/ov_SC06_018_jr_80187AEC.o"], "before_text": "void func_8018AD74(s32 p1, s32 p2, s32 p3, s32 p4)\n{\n /* [T51] block-scoped decls (house idiom in this TU, cf. func_8018AF88): a file-scope\n decl of these symbols would constrain every LATER function in the object. */\n extern Blk20_8018AF88 D_800AE620;\n extern s32 func_8012C658(s32, s32, s32);\n extern void RotMatrixY(s32 a0, void *a1);\n extern void func_800484EC(s32, s32, s32);\n extern u8 D_801CD468[];\n\n Blk20_8018AF88 local_30; /* sp+0x10 */\n Blk20_8018AF88 *m;\n s32 obj;\n s32 out[3]; /* sp+0x30, only [0] and [2] used */\n\n local_30 = D_800AE620;\n obj = func_8012C658((s16)p2, (s16)p3, p1);\n if (obj != 0) {\n __asm__(\"\" : \"=r\"(obj) : \"0\"(obj)); /* \u00a7350 birthing-boost kill; 0 bytes */ // !FAKE: launder \u2014 NEEDED DIFFERS (P36 rung B tus9)\n m = &local_30;\n *(u16 *)(obj + 0xA) = *(u16 *)(obj + 0xA) - 0x80;\n RotMatrixY((s16)p4, m);\n func_800484EC((s32)m, (s32)&D_801CD468, (s32)out);\n *(s32 *)(obj + 0x10) = out[0];\n *(s32 *)(obj + 0x14) = 0xFFD80000;\n *(s32 *)(obj + 0x18) = out[2];\n }\n}\n", "after_text": "void func_8018AD74(s32 p1, s32 p2, s32 p3, s32 p4)\n{\n /* [T51] block-scoped decls (house idiom in this TU, cf. func_8018AF88): a file-scope\n decl of these symbols would constrain every LATER function in the object. */\n extern Blk20_8018AF88 D_800AE620;\n extern s32 func_8012C658(s32, s32, s32);\n extern void RotMatrixY(s32 a0, void *a1);\n extern void func_800484EC(s32, s32, s32);\n extern u8 D_801CD468[];\n\n Blk20_8018AF88 local_30; /* sp+0x10 */\n Blk20_8018AF88 *m;\n s32 obj;\n s32 out[3]; /* sp+0x30, only [0] and [2] used */\n\n local_30 = D_800AE620;\n obj = func_8012C658((s16)p2, (s16)p3, p1);\n do { } while (0); // !FAKE: do-while \u2014 its NOTE_INSN_LOOP_END ends cse1's extended block (cse.c:8054), so m below is not folded onto the struct copy's address pseudo (cse.c:846-862) and is set AFTER obj's copy: sched1 then ranks it last by LUID (sched.c:2428) (P36 S104 e5 minimum-lever)\n m = &local_30;\n if (obj != 0) {\n *(u16 *)(obj + 0xA) = *(u16 *)(obj + 0xA) - 0x80;\n RotMatrixY((s16)p4, m);\n func_800484EC((s32)m, (s32)&D_801CD468, (s32)out);\n *(s32 *)(obj + 0x10) = out[0];\n *(s32 *)(obj + 0x14) = 0xFFD80000;\n *(s32 *)(obj + 0x18) = out[2];\n }\n}\n"} diff --git a/src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c b/src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c index f7f02d5e28..751af35dc6 100644 --- a/src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c +++ b/src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c @@ -5386,9 +5386,9 @@ void func_8018AD74(s32 p1, s32 p2, s32 p3, s32 p4) local_30 = D_800AE620; obj = func_8012C658((s16)p2, (s16)p3, p1); + do { } while (0); // !FAKE: do-while — its NOTE_INSN_LOOP_END ends cse1's extended block (cse.c:8054), so m below is not folded onto the struct copy's address pseudo (cse.c:846-862) and is set AFTER obj's copy: sched1 then ranks it last by LUID (sched.c:2428) (P36 S104 e5 minimum-lever) + m = &local_30; if (obj != 0) { - __asm__("" : "=r"(obj) : "0"(obj)); /* §350 birthing-boost kill; 0 bytes */ // !FAKE: launder — NEEDED DIFFERS (P36 rung B tus9) - m = &local_30; *(u16 *)(obj + 0xA) = *(u16 *)(obj + 0xA) - 0x80; RotMatrixY((s16)p4, m); func_800484EC((s32)m, (s32)&D_801CD468, (s32)out);