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

19 KiB

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