Files
BFM-decomp/.run/giants/bf14_regmap.py
T
Drew T f5f8dec5ee docs(phase-29): the cold-start experiment — func_8017BF14 to 45/4763; §79; full R22 discharged
- COLD-START RESULT (verified independently): 4763/4763 ins, 45 mismatched = 99.06% byte /
  99.94% structural, exact frame, exact opcode histogram. NOT a match; nothing banked (45 != 0,
  the byte-gate is the sole arbiter). The residual is 3 register-grant ties, 0 structural
  divergence. Named next move: variable REUSE across c0..c3/a0v..a3v, the one §76 lever class
  the pass never reached.
- MY BRIEF'S PREMISE WAS WRONG BY CONSTRUCTION -> §79. I chose this target partly because §71's
  callee-set fingerprint returned 0.00 against every matched giant = "a genuine cold start". But
  the function makes ZERO jal calls, so its callee fingerprint is EMPTY and §71 CANNOT FIRE:
  0.00 meant "cannot answer", not "no relative". Grepping the target's DATA symbol D_800A5E60
  found the matched func_8017BEBC at once -- func_8017BF14 is the 4-light-box member of the same
  renderer family whose 3-box sibling func_8017D960 was matched hours earlier. RULE: when §71
  returns an empty/zero-overlap callee set, fall back to DATA-symbol fingerprinting; an empty
  fingerprint must never become a cold-start brief.
- NEW LEVER (§79): THE FRAME LAYOUT IS A DECLARATION-ORDER ORACLE. gcc-2.7.2 assigns stack slots
  to spilled pseudos in pseudo-number order, and pseudo numbers follow first use ~ declaration
  order -- so the target's frame map reads back its source's declaration order. Moving ONE line
  took 73% -> 84% structural and brought all 127 slots into exact correspondence.
- §76 CONFIRMED AT SCALE: the entire -62 length residual was ONE allocno-class decision (c0..c3
  declared inside the cull blocks -> 1-death local allocnos -> global.c:668-671 removes those
  regs from the global pool -> r1lo spills), 52% -> 93%. An __asm__ ref-dial reached the same
  spill and scored WORSE -- declaration scope beat the ref dial again.
- PIN NUANCE: pins are safe on a 0-jal function (§74's hazard cannot arise), 4 pins took
  94% -> 99%; but §72 held -- pins 5 and 6 made it worse.
- EFFORT ANSWER, HONEST: xHigh from a genuine cold start on a 4,763-ins giant bought the decode,
  the exact length, the exact frame and 99.06%, and did NOT close. Budget a SECOND pass at this
  size: the first buys structure, the last ~1% is register grants.
- FULL R22 DISCHARGED: make clean + extract-all + check-all -> 140 passed, 0 failed of 140 (run
  after the agent finished, per the deferral recorded in the pool commit). tools-health OK.
2026-07-25 17:08:02 -06:00

44 lines
1.8 KiB
Python

"""Register-correspondence census over index-aligned instructions (same length only)."""
import sys,os,collections
sys.path.insert(0,'/home/musashi/bfm-decomp/tools')
import masked_diff, re, subprocess, shutil
OBJ=sys.argv[1]
TGT='/home/musashi/bfm-decomp/asm/ov_SC03_116/nonmatchings/ov_SC03_116_jr_8017AE2C/func_8017BF14.s'
mine=masked_diff.insns_from_object(OBJ,'func_8017BF14')
tgt=masked_diff.insns_from_s(TGT)
R=['zero','at','v0','v1','a0','a1','a2','a3','t0','t1','t2','t3','t4','t5','t6','t7',
's0','s1','s2','s3','s4','s5','s6','s7','t8','t9','k0','k1','gp','sp','s8','ra']
pairs=collections.Counter()
for i,(a,b) in enumerate(zip(mine,tgt)):
aw = a if isinstance(a,int) else None
# use raw words
for i,(a,b) in enumerate(zip(mine,tgt)):
pass
# simpler: raw words via objdump/target parse
def words_t():
w=[]
for l in open(TGT):
m=re.match(r'\s*/\* \w+ [0-9A-F]{8} ([0-9A-F]{8}) \*/',l)
if m: w.append(int.from_bytes(bytes.fromhex(m.group(1)),'little'))
return w
OD=[c for c in ["mips-linux-gnu-objdump","mipsel-linux-gnu-objdump"] if shutil.which(c)][0]
out=subprocess.run([OD,"-drz",OBJ],capture_output=True,text=True).stdout
def words_m():
w=[];inside=False
for l in out.splitlines():
if re.match(r'^[0-9a-f]+ <func_8017BF14>:',l): inside=True;continue
if inside:
if re.match(r'^[0-9a-f]+ <',l) and w: break
m=re.match(r'\s*[0-9a-f]+:\s+([0-9a-f]{8})\s',l)
if m: w.append(int(m.group(1),16))
return w
T,M=words_t(),words_m()
print('len',len(M),len(T))
for a,b in zip(M,T):
if a==b: continue
if (a>>26)!=(b>>26): continue
for sh in (21,16,11):
ra=(a>>sh)&0x1F; rb=(b>>sh)&0x1F
if ra!=rb: pairs[(R[ra],R[rb])]+=1
for (a,b),n in pairs.most_common(20): print(' mine $%-4s -> target $%-4s x%d'%(a,b,n))