Match 3 functions in hsd_3A94 - #3231
Merged
Merged
Conversation
Restructure fn_803AE7F8, fn_803AF3F0, fn_803B0120, and fn_803B0E9C: hoist the repeated queue-command blocks into helpers, split the verify/write results into their own locals, and correct the stack padding. fn_803AE7F8 96.64 -> 98.34, fn_803AF3F0 92.95 -> 97.80, fn_803B0120 95.55 -> 96.48, fn_803B0E9C 97.28 -> 98.27. Co-authored-by: ford-bubba-ai <ford.lascari@gmail.com>
The target's loop exit is a bge/b pair rather than a folded conditional branch, which is how MWCC lowers an inlined early return. 98.27 -> 98.54; the remainder is register allocation.
Both CARDWrite retry blocks are identical; sharing one inline also drops the opacity cast the two copies needed. 98.54 -> 99.24.
Report for GALE01 (05d0b1d - e796c29)📈 Matched code: 91.92% (+0.20%, +7620 bytes) ✅ 3 new matches
📈 1 improvement in an unmatched item
|
The first CARDRead retry loop is an inline like the write helper, which colours its locals from the pool band; declaration order inside each helper then fixes the remaining register rotations. 99.24 -> 99.53.
99.53 -> 99.66.
The three rewind helpers address the entry through a pointer and advance the cursor before clearing, like cancelQueuedCardCommands. fn_803AE7F8 98.34 -> 99.10, fn_803AF3F0 97.80 -> 98.64, fn_803B0120 96.48 -> 97.27.
The caller keeps its own copy of the size, so the load CSEs and the copy into the caller's local shows up as the original's addi. 99.10 -> 99.22.
Mirrors fn_803AE7F8: the helper reads the file size itself and the caller keeps its own copy. 98.64 -> 98.74.
The TU already pairs First/Final block helpers; giving the last write its own inline recovers the second site's register assignment. 99.66 -> 99.80.
The offset local sits between the two command buffers in the queue-write helper, which gives the target's uniform 40-byte stride, and the done command's buffer is a function-scope object above the verify buffers. 99.22 -> 99.22, but the done buffer and block map now land on their original stack slots.
Every nine-word command buffer in the file is a CardCmd, so the queue calls read as field assignments and the state and buffer pointers stop being laundered through s32. Byte-identical everywhere.
Declaring both buffers at helper scope puts them in the original's order and lands one on its stack slot. 98.82 -> 98.83.
Block map and frame now land on the original's offsets. 98.83 -> 98.84.
Matches the family idiom in fn_803ACF30 and fn_803ACD58, which the window index picks out as 100%-matched twins of this loop, and drops the cast. Byte-identical.
calculateBlocksBefore was a byte-identical second copy of fn_803AC6B8_blocks_before. Byte-identical output; fn_803ADF90 stays matched.
The target keeps state->x270[i] in one register for both the comparison and the assignment. 98.84 -> 98.87.
The original names the induction variable: the target colours it below the scan loop's locals, which a compiler-created IV never is. 99.22 -> 99.42.
98.87 -> 98.93.
…inal The walker steps before the counter, and the open block reads the offset before the file descriptor. 99.42 -> 99.46.
The original does not name it there, so the value coalesces into its register instead of being copied. 99.46 -> 99.66.
Declaring the block offset before the command buffer puts the buffer at the lower slot, which matches the frame the original emits for both write-pass queue commands. Also spell the sequence wrap as an explicit 0xFF mask.
The repair pass builds its two commands in place, like the write pass, rather than through a shared inline: the original's frame puts all six command buffers in one contiguous run of 40-byte blocks, which only happens for block-scope buffers. With the block chunk size hoisted into the loop condition the whole frame and every branch target now agree.
…us path The queued path's success branch jumps past the x170/x270 updates, so those two stores belong to the CARDWrite branch only.
The scan loop's index and the inlined sequence comparison hold each other's registers otherwise.
The file block count comes from fn_803AC634 itself rather than a duplicate of its body, and the queue entry the completion path fills in is addressed through a pointer.
The spare-block command is the ordinary write command with a logical index of 0xFFFF, which is what makes it reject block zero.
Pull the card-open retry and the sequence-number check into helpers, name the write pass's block size, and address the completion queue entry through a pointer; every command buffer now lands at its retail slot.
The digest slice offset is the block index scaled by the digest size, not a second counter; the compiler strength-reduces it, which is why the original never spends a register on it.
The block list the check only reads is const, and drop the now-unused command wrapper.
The retail exit from the free-block reclaim loop branches straight to the write pass; ours re-tested secondary_count first. Nesting the -257 bail inside the same guard as the reclaim loop reproduces the branch target.
The verify walker is compiler-created: retail seeds it from the already materialised block_map base and steps it before the counter, both of which only the block_map[0][i] index form reproduces. With that in place the two queue sites need separate inlines, as elsewhere in this file: the first returns the command result directly, the final keeps a named result. That one extra web is what orders the walker, the counter and the data pointer, and with them file_blocks, free_count and the sequence-match flag.
Retail keeps the incremented sequence number in a scratch register and masks it into current_seq; the (u8) cast folds both into one web, the & 0xFF spelling (as in fn_803AE7F8) keeps them apart.
Same shape as the verify pair: the full-chunk site returns the command result directly, the trailing-chunk site (and the free-block site that shares its register web) keeps a named result. That fixes the write pass's walker and its remaining counter.
With the two command builders split, the write pass wants the same counter web as the other loops rather than its own; that recovers the data pointer, the sequence number and the counter itself.
Only the trailing-chunk site keeps a named block; the full-chunk site reads the map inline, which is what puts the chunk size in its retail register.
The block value has to outrank the offset helper's own pooled temps in the simplify scan; a named local puts it in the low band, where it survives the first pass and colours before the logical index.
The two block values reach their command builders as inline parameter temps, which are numbered above the offset helper's own temps and so colour after them. A one-field carrier re-ranks each into the loop temp band, which fixes the free-block command and the full-chunk write command; PAD_STACK absorbs the two carriers' frame slots.
Block-scope carriers sort below the completion command buffer and push it eight bytes up; at function scope they sort above it, so the whole frame comes back exact.
The write loop's sector load and the two block-offset sums were swapped between r3 and r4. The sector web is removed from the interference graph with degree 27 against K=29, just under the threshold, because four earlier pool temps decrement it first; it is therefore coloured after the sums instead of before. Reading remaining at the top of the loop body extends its live range across the loop head, which restores the two edges that defer the sector web to a later simplify pass.
The frame was 0x18 short of the target's 0x548; PAD_STACK(80) recovers it exactly. The verify loop left through a break and then re-tested i >= file_blocks || remaining <= 0, which emitted the loop's bottom test a second time. The target reaches the close block by fallthrough, so the early exits become a goto past it and the guard goes away. 97.2688 -> 97.7601.
Transplants the matched fn_803AF3F0 shapes: the write helper declares its main CardCmd before the offset temp so the type-1 buffer lands below the type-2 one; the secondary-block site becomes a real queue_write call, whose unreachable type-2 buffer is still allocated and produces the target's 0x50 buffer gap; state->x8 - 0x20 moves into a chunk_size helper whose local bills the 16 bytes missing below the first buffer; and the write preheader takes AF3F0's named-temp form. Six of the eight command buffers and block_map now sit at the target's offsets. 97.7601 -> 97.8169.
Two structural facts, both read off the frame rather than the score. The write helper declared its type-2 buffer before the type-1 one, so every expansion's pair was allocated in the wrong order. And the redundancy loop hand-expanded queue_write with phys = 0xFFFF, which allocated one named buffer at the top of the frame where the target has it fifth, followed by the unreachable type-2 buffer that produces the 0x50 gap. Calling the helper also removes the duplicated command block. Score is unchanged at 98.7003; the buffer order and the misplaced buffer are now right, which the score cannot see.
MarkMcCaskey
marked this pull request as ready for review
August 28, 2026 19:32
fjooord
added a commit
to fjooord/melee
that referenced
this pull request
Aug 29, 2026
…mp#3253: upstream-gospel gmresultplayer/grkongo/grgreens/hsd_3A94/tydisplay functions; keep our exact grmaterial (Matching unit) over upstream's near-match
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Need 3 functions for getting to vs mode. Seeding from #3223 and I’ll keep grinding from there