Work on grzebes - #3305
Draft
MarkMcCaskey wants to merge 18 commits into
Draft
Conversation
Each declared local that is copy-propagated away still reserves a vestigial 4-byte stack home, so the trivial one-line helpers and the duplicate distance/zero locals were only widening grZebes_801DB3CC's frame. Inline them by hand, symmetrise the left/right neighbour blocks, and fold effective_dist back into dist. Code generation is unchanged.
The zero local was only a staging copy; dropping it is code-generation neutral.
Report for GALE01 (98dcaaa - 115ead2)📈 Matched code: 95.52% (+0.07%, +2628 bytes) ✅ 2 new matches
📈 1 improvement in an unmatched item
|
The b-side computed its scaled velocity through a one-line inline helper and clamped in place, while the a-side used a plain multiply and a separate clamp local. Writing both the same way keeps code generation identical and drops two more vestigial stack homes.
The retail frame is 0x58; ours was 0x78. The gap was eight locals that MWCC copy-propagates away but still gives a vestigial 4-byte home: the duplicate current_x/current_y aliases, the old_x/old_y reads the bound checks can take straight from the entry, and the one-line scale helper whose result the b-side clamped in place. Removing them lands the frame on 0x58 with the three sqrt staging slots at their retail offsets, and drops a diff row.
The grZe_BubbleState cast only existed to reach grZe_8049F170 through a struct view of three separate arrays, and its state local was an unused object slot. Every other function in the TU indexes the array directly. Code generation is unchanged.
MWCC canonicalises `x * C` with the constant in frA, but folds `x / C` into a multiply that keeps it in frC. Retail's grZebes_801DB3CC has the latter encoding throughout the bubble-collision loop, so the radii and the repulsion strength were written as divisions.
Retail loads ej->x08_x before ej->x0C_y and subtracts dx before dy. The inline subtraction helper is the lever that decides which of the pair is scheduled first, so it belongs on dy; the declarations follow suit. The emitted instruction stream now matches retail exactly, leaving only a callee-saved register permutation.
`(void) 0.0;` in grZebes_801DB3CC's update helper emitted an 8-byte double that retail's .sdata2 does not contain, shifting every constant after it. Removing it makes .sdata2 byte-identical and leaves all code untouched; the remaining .data/.sdata deltas are the usual dtk tail-alignment padding.
`last_idx` must outrank the loop locals it shares a live range with, which means it is declared last among the function's own locals and the two loop walkers are declared alongside it rather than inside their blocks. That puts the four callee-saved registers on retail's assignment; only the floating-point allocation still differs.
Byte-identical; the split initialisation was a decomp artifact.
The inner loop steps its walker before the counter, which is MWCC's strength-reduction signature: the source indexes grZe_8049F170[j] and the compiler derives the pointer. The outer loop has the opposite order, so its `ei` is a real walked pointer and stays one. Byte-identical.
Same strength-reduction signature as grZebes_801DBB60's pair loop: the walker steps before the counter, so the source indexed the array and MWCC derived the pointer. Byte-identical.
The candidate bubble's position is read into locals the same way the popped entry's already is; those two homed floats are exactly the eight bytes the PAD_STACK was reserving. Byte-identical, and the frame is unchanged at 0x98.
The dx/dy temporaries were decomp scaffolding: writing the squared distance directly gives retail's instruction stream for the whole computation and drops the artificial subtraction helper from this loop. Only the five loaded coordinates remain permuted.
The five loaded coordinates were claiming exactly the reversed set of registers. Reading the winning pair's coordinates straight out of the bubble array pools them as expression temps, and the dead reads in the loop preheader do the same for the current bubble's, which puts all five webs in the claim order retail has.
The two point-to-endpoint branches square each component into a fresh variable instead of in place, which is what puts the first square in its own register.
Testing the ground and joint pointers with an embedded assignment keeps each in its own local instead of a compiler temp, which is what breaks the fifteen-way register jam; walking the candidate bubbles through a pointer restores the stack slot the wrapper inline used to bill.
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.
No description provided.