Files
Cesarus85--mjolnir-vr/docs/object_matching_logs/texture_page_obj.md
T

470 lines
19 KiB
Markdown

# `texture_page.obj` exact-match ledger
## Scope and invariant
- Translation unit: `source/memory/texture_page.c`
- Target: January 2002 `build/split/source/memory/texture_page.obj`
- Closeout base: `c53047fb`
- Compiler: XDK 3911 CL 13.00.9254.1
- Flags: `/O2 /Oy- /DDEBUG /Dxbox`
- Acceptance: every function and every target-owned data section must pass the
hardened COFF comparator. No inline assembly, volatile codegen coercion,
undefined behavior, byte patches, or compiler-flag changes.
This object is already behaviorally reconstructed. Nine of thirteen functions
are strict-exact, and all target-owned data is strict-exact. The four remaining
functions have equal target/candidate padded sizes and relocation counts.
## Baseline residuals
| Function | Size T/B | Relocations T/B | Target SHA-256 | Candidate SHA-256 |
| --- | ---: | ---: | --- | --- |
| `code_0010f730` | 96/96 | 6/6 | `4ea8aca9a5fe88693bb7cb72005f6a504b410ad15fd073c0725b08e4ec189953` | `1549ee0ee677c135307b88208026d6b19fe86540328a518949a03c778b8b5520` |
| `code_0010f790` | 736/736 | 21/21 | `451c78bcbdd4d6db18dbfe91ce5e1c6da0bffc6946409f4e62f7657763ec3dca` | `e318ef56a0771d9c007ca8e236d03c945b93c4175e5c5c670dda2dc548e640a0` |
| `texture_page_texture_new` | 240/240 | 9/9 | `d75574be99cf9a26ae8fc060f5d7d51bdf5005cb6699660f647adc2db545e513` | `1d5abf71760148ec35dca4d32316dc7b661e09a915023f3d1d3e4fe590802e28` |
| `texture_page_textures_end` | 112/112 | 6/6 | `6c74519b0d25aba59784237633ae13cb02dccffd26fe8cebc8f018a87b0a5702` | `3c9dc6840e0ada4946f9f409b77e9b2a6c11341672cb72082844d5bfe94911e5` |
The production blocker classifier returns `UNKNOWN` for all four. It confirms
that `code_0010f790` and `texture_page_textures_end` already have exact
relocation addresses as well as identities. The other two have identical
relocation identities but shifted addresses, so their source topology must be
corrected before register/scheduler tuning.
## Recovered foundation
- `af7e2340` / `66bf7aa7`: exact lifecycle, accessors, and allocation
foundation.
- `fab81db6` / `1ee7b15d` / `afffe8a7`: reconstructed packing algorithm and
data structures.
- The committed implementation recovers the 512-entry channel stack, 32768
texture-index stack, height comparator, power-of-two spacing, sorted packing,
cancel/end transactions, and immediate-allocation rollback.
## Experiment log
Record every one-factor source experiment here before rebuilding. Each result
must include all four residual sizes, relocation counts/addresses, normalized
hashes or first divergence, and the nine exact sibling functions' regression
status.
### E01 — defer pixel-count multiplication until dimensions fit
Changed `texture_page_texture_new` so `width*height` is evaluated only after
the width and height bounds pass, matching January's instruction order.
- Result: **STRICT EXACT**
- Size: 240/240
- Relocations: 9/9, addresses and identities exact
- Normalized SHA-256:
`d75574be99cf9a26ae8fc060f5d7d51bdf5005cb6699660f647adc2db545e513`
- Object state: 10/13 strict-exact
- Regression sweep: all nine previously exact siblings retained
### E02 — express comparator through two exact accessor calls
Replaced the manually expanded verify/get pairs with two
`texture_page_texture_get` calls.
- Result: rejected, still 96/96 and 6/6
- Improvement: reproduced January's three-callee-saved-register prologue and
epilogue exactly
- Regression: interleaved each validation with its lookup, while January
validates both pages before either lookup
- Siblings: unchanged; object remained 10/13
- Do not repeat this direct two-accessor form
### E03 — `register` second page in original comparator topology
Restored the original validate/validate/get/get order and marked the second page
pointer `register`.
- Result: no code-generation change from baseline
- The compiler ignored the hint under `/O2`
- Siblings: unchanged; object remained 10/13
- Do not repeat `register` hints for this helper
### E04 — function-scope `textures` alias in `texture_page_textures_end`
Cached `texture_page->textures` in an explicit `register` pointer while leaving
the loop variables at function scope.
- Result: no code-generation change from baseline
- The compiler continued to use EDX/EAX/ECX and emitted no inner-block EDI
lifetime
- Siblings: unchanged; object remained 10/13
- Do not repeat `register` hints for this loop
### E05 — confine the end-loop locals to the successful-resort block
Moved `absolute_index`, `textures`, and `texture` into the
`if (code_0010f790(texture_page))` block. January first saves EDI only after
that call succeeds, so the shorter source lifetime is directly suggested by
the machine code.
- Result: no code-generation change from baseline
- Size/relocations remained 112/112 and 6/6 with exact relocation addresses
- Normalized SHA remained
`3c9dc6840e0ada4946f9f409b77e9b2a6c11341672cb72082844d5bfe94911e5`
- All ten exact siblings retained
- Declaration scope alone does not control this register allocation
### E06 — split `masked_dimension` assignment from its condition
Separated each `masked_dimension &= spacing_mask` statement from the following
zero test. This tested whether the combined assignment-in-condition caused
VC7 to commute the `and` operands.
- Result: no code-generation change
- `code_0010f790` stayed 736/736, 21/21 with exact relocation addresses and
candidate SHA
`e318ef56a0771d9c007ca8e236d03c945b93c4175e5c5c670dda2dc548e640a0`
- All ten exact siblings retained
- Do not repeat simple expression splitting for these masks
### E07 — use the page global directly at all four helper sites
Removed the two page-pointer locals and referenced `bss_00456628` directly for
both validation calls and both datum lookups.
- Result: rejected
- Size stayed 96/96 but relocations regressed from 6 to 8 because the compiler
reloaded the global for both datum lookups
- All ten exact siblings retained
- The target proves that two loaded page values are preserved; direct repeated
global expressions are not the original topology
### E08 — statement-initialize both page-pointer locals
Kept the validate/validate/get/get order but changed the first page pointer from
a declaration initializer to a normal assignment, giving both page locals the
same source form.
- Result: no code-generation change
- `code_0010f730` remained 96/96 and 6/6 with candidate SHA
`1549ee0ee677c135307b88208026d6b19fe86540328a518949a03c778b8b5520`
- All ten exact siblings retained
### E09 — loop-local register hints in `texture_page_textures_end`
Applied `register` to the loop counter and texture pointer.
- Result: no code-generation change
- The candidate retained EDX/EAX/ECX rather than January's EDI/ECX/EDX
- Do not repeat register hints in this loop
### E10 — no-op barrier positions in `texture_page_textures_end`
Tested `_ReadWriteBarrier()` after the successful packing call, after loading
the texture pointer, and at the loop back edge.
- After the call: no code-generation change
- At the back edge: no code-generation change
- After the pointer load: rejected; candidate SHA changed to
`d620617f...` by adding an unwanted reload
- All ten exact siblings retained
- The barrier family does not reproduce the target register assignment
### E11 — success-block declaration initializer for the texture pointer
Declared and initialized the texture pointer inside the successful packing
block rather than assigning it after declaration.
- Result: no code-generation change
- Size/relocations stayed 112/112 and 6/6 with exact relocation addresses
- All ten exact siblings retained
### E12 — indexed texture access instead of pointer induction
Replaced the pointer-increment loop with
`textures->data + absolute_index`.
- Result: rejected structural regression
- Candidate grew from 112 to 128 bytes; relocations remained 6/6
- Candidate SHA became
`e92a1c645b9e824dbb94342d209040295f5acbc05c1d31b1e6bfc290c0504fa8`
- All ten exact siblings retained
- January proves pointer induction; do not repeat indexed access
### E13 — declaration-initialize the data-array and texture pointers
Inside the successful packing block, declare
`textures = texture_page->textures` and `texture = textures->data`, while
retaining January's pointer-increment loop. This directly tests whether the
initializer topology assigns the data-array lifetime to EDI and the element
pointer to ECX as in the target.
- Result: no code-generation change
- Size/relocations remained 112/112 and 6/6
- Candidate SHA remained
`3c9dc6840e0ada4946f9f409b77e9b2a6c11341672cb72082844d5bfe94911e5`
Result: no code-generation change. The named boolean was optimized away before
register allocation; the function remained at the baseline SHA.
### E15 — reverse the loop-local declaration order
Declare the texture pointer before the short absolute index while restoring the
direct branch on `code_0010f790`. This is the only untested declaration-order
permutation of the two real loop locals.
- Result: no code-generation change
- VC7 assigned the same stackless SSA values regardless of source declaration
order
Result: no code-generation change. The compiler folded both aliases back into
the same EDX/EAX/ECX allocation, leaving 112/112, 6/6 and SHA
`3c9dc6840e0ada4946f9f409b77e9b2a6c11341672cb72082844d5bfe94911e5`.
### E14 — explicit packing-result local
Declare `boolean resort_succeeded`, assign the `code_0010f790` return to it,
and branch on the named value. The exact sibling
`texture_page_textures_cancel` uses this source topology, making it a
target-authored allocator lead rather than a generic perturbation.
- Result: no code-generation change
- The named boolean was optimized away before register allocation
### E16 — nested lifetime for the comparator's second page
Declare `texture_page_b` in a block beginning after the first validation and
ending after the first `datum_get`. This mirrors the measured target lifetime:
the first page survives both validation calls while the second page is loaded
only after the first call and dies after the first lookup.
- Result: no code-generation change
- The compiler coalesced the nested lifetime to the same SSA value
### E17 — make the packing mask temporary unsigned
Change only `masked_dimension` from signed `short` to unsigned `word`. The value
is used exclusively as a bitmask and zero predicate, so this is
behavior-preserving. It tests whether January's `mov width, EDX; and mask, EDX`
operand choice came from an unsigned mask temporary.
- Result: no code-generation change
- Signedness does not control the commutative `and` operand choice
### E18 — widen the mask temporary's source lifetime
Move `masked_dimension` from the sorted-texture loop block to function scope
while restoring its signed-short type. This tests whether January's schedule
came from the mask temporary being live in the function's main local set.
- Result: no code-generation change
- Source scope does not affect the optimized mask SSA value
### E19 — named true value for the end-loop store
Declare `boolean sorted = TRUE` and store that named value instead of the
literal. An exact January donor (`objects_information_get`) gains a late EDI
lifetime from an additional live byte value in an otherwise similar no-call
data-array loop, so this tests the corresponding topology without adding
observable operations.
- Result: no code-generation change
- Constant propagation removed the named boolean before it could influence the
loop allocation
### E20 — initialize both loop variables in the `for` initializer
Move the texture-pointer initialization into the comma-separated `for`
initializer beside `absolute_index = 0`. This preserves January's preheader
instructions but changes the source/IR origin of both induction variables as a
single loop initialization expression.
- Result: no code-generation change
- VC7 canonicalized the comma initializer to the baseline preheader
### E21 — explicit precheck plus `do/while`
Express the already-measured CFG directly: initialize the pointer and counter,
precheck the count, then execute a bottom-tested `do/while`. The January
machine code has exactly this control-flow topology even though a `for` can
also lower to it.
- Result: no code-generation change
- VC7 reconstructed the same preheader and bottom-tested loop emitted by the
concise `for` form
### E22 - alternate locally available optimizer backends
Compile the unchanged best source using the two additional backend DLLs found
in the workspace's prior compiler-variant research (`SP4` and `SP5`). This
tests the patch-level optimizer hypothesis before spending more source shapes.
- Result: rejected before code generation
- Both backends report C1007 for the VC7 front end's `-Ob2` intermediate flag
- These are incompatible older optimizer DLLs, not usable XDK 3911 QFEs
- The valid 13.00.9210 and 13.00.9254.1 toolchains remain the only compatible
locally available variants; both emit the same three residuals
### E23-E24 - remaining declaration-order permutations in the packer
Tested `texture_width` before `texture_height`, then `masked_dimension` before
`channel_index`.
- Result: no code-generation change in either case
- VC7 assigned the same stack slots and SSA values
### E25-E26 - direct mask-value expressions
Tested a separate `dimension & mask` assignment followed by a zero test, then
removed `masked_dimension` and tested the expression directly.
- Separate assignment: no code-generation change
- Direct predicate: rejected; relocation addresses changed and the candidate
SHA became `83d76628a4a3f6987ba11fa00c24eaf8d633ce2f1b3a8c3500d0d3494a84f3d6`
### E27 - comparator page declaration order
Declared the second page before the first while retaining the
validate/validate/get/get sequence.
- Result: no code-generation change
### E28 - inline verified-page identity helper
Wrapped validation in an inline helper returning the same page. With the first
page initialized before calling the helper, this restored January's
three-callee-saved-register body and made the function byte-identical from
offset `0x0e` onward.
- Result: improvement, but not exact
- Candidate SHA:
`9600d22f437e4458aebcd785ea57fd1ced3fbb9b5c0b9d23242a03a20cf2c792`
- Sole remaining region was the first page's prologue materialization
### E29 - assignment inside each validation call
Assigned each global page pointer in the argument expression to
`code_0010f570`.
- Result: canonicalized back to the original two-register baseline
### E30 - direct global input to the inline verified-page helper
Leave both page locals uninitialized, then assign each from
`texture_page_verify_and_return(bss_00456628)`.
- Result: **STRICT EXACT**
- Size: 96/96
- Relocations: 6/6, addresses and identities exact
- Normalized SHA-256:
`4ea8aca9a5fe88693bb7cb72005f6a504b410ad15fd073c0725b08e4ec189953`
- Object state: 11/13 strict-exact
### E31-E34 - inline provenance follow-ups
Applied the successful inline-provenance idea to the two residual functions:
- Cached data-array accessor in `textures_end`: rejected; it removed January's
required per-iteration alias reload and produced SHA
`4fff2764d551c362047ff666f28e68815b4cb82f60a3e18df0d8ba9e596a1725`
- Inline mask helper in the packer: no code-generation change
- Inline first-texture accessor in `textures_end`: no code-generation change
- Repeated uncached inline data-array accessor at both load sites: no
code-generation change
### E35 - bounded packer-barrier supersearch
Compiled 127 combinations of zero-byte `_ReadWriteBarrier()` placements around
the remaining packing-mask scheduling window.
- Result: no exact candidate
- Best result still had 26 differing normalized bytes
- The barrier family can move the mask operation, but cannot reproduce all
five January operand/order pairs together
### E36 - cross the barrier lead with the prior source-shape atlas
Crossed the best packer-barrier placement with 101 previously measured,
semantically valid source shapes.
- Result: no exact candidate
- The cross-product did not improve upon the 26-byte barrier residual
- This closes the barrier-plus-expression family rather than repeating it
manually
### E37 - recover the packing-mask width
Changed `spacing_mask` from `long` to `word`. January consistently performs
low-word masks and zero-extends this value; `spacing` is also a `word`, so this
is type recovery rather than a code-generation hint.
- Result: **STRICT EXACT**
- Size: 736/736
- Relocations: 21/21, addresses and identities exact
- Normalized SHA-256:
`451c78bcbdd4d6db18dbfe91ce5e1c6da0bffc6946409f4e62f7657763ec3dca`
- Object state: 12/13 strict-exact
### E38 - preserve the packing result through `textures_end`
Stored the packing result in a `boolean` and used `result ^ TRUE` for the final
page flag. This reproduced January's EDI/ECX/EDX loop allocation and reduced
the residual from 28 to 9 bytes.
- Result: rejected
- The expression is not equivalent for noncanonical nonzero boolean values
- This experiment proved that January keeps the packing result live across the
loop, but it was not eligible production C
### E39 - bounded end-loop barrier supersearch
Crossed the nine-byte live-result candidate with 127 zero-byte barrier
placements around the call, loop, and final store.
- Result: no exact candidate
- Every best candidate retained the same nine-byte tail
- The barrier family cannot convert the dynamic result store into January's
literal zero store
### E40 - translation-unit order and linkage audit
Tested January's function order, static/external helper linkage, and
`__forceinline` variants.
- January function order did not change `textures_end`
- Externalizing the private helpers regressed their private register
conventions and multiple callers
- `__forceinline` retained the exact comparator body but still emitted the
unreferenced 16-byte helper COMDAT
### E41 - recover the `textures_end` return type
January leaves the packing result in `AL` across the entire successful loop and
returns without replacing it. Changing the function from `void` to `boolean`,
returning the named packing result, explains that lifetime naturally.
- Result: **STRICT EXACT**
- Size: 112/112
- Relocations: 6/6, addresses and identities exact
- Normalized SHA-256:
`6c74519b0d25aba59784237633ae13cb02dccffd26fe8cebc8f018a87b0a5702`
- Object state: 13/13 strict-exact
### E42 - inline-helper ownership audit
The exact comparator uses a small inline identity helper to retain January's
private-ABI provenance. The compiler emits an unreferenced 16-byte COMDAT copy
in addition to inlining both calls.
- Six macro/explicit-parameter replacements removed the extra COMDAT but
regressed the exact comparator register allocation
- The emitted helper is COMDAT `Selection: Any`, has no incoming relocation,
and is discarded by the normal reference-eliminating link
- It does not change any target-owned code or data section; ordinary progress
reports 100% code, 100% data, and all 13 functions exact
## Final strict result
- Target functions: 13/13 strict-exact
- Target code: 1922/1922 meaningful bytes
- Target data: 460/460 bytes
- Hardened relocation identities: exact for every function
- Ordinary object report: 100% code, 100% data, 100% functions
- Full project rebuild: successful
- House-style audit: passed; the recovered boolean function has one explicit
return, and all parameters remain one-per-line