mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-26 13:33:34 -04:00
phase-36: T2 — the oracle and the probe: tools/delever_oracle.py (4,284 recipes via make -n -W; a candidate compiled in place to a scratch object and compared with the fleet run's; calibrated 177/177 untouched + twin 32/32 + positive control DIFFERS) and tools/delever.py (positional rewrites per lever class, rung A strip-all + rung B greedy, headers serial after the TU phase); --probe on 283 distinct bodies: A identical 53/283, sites removed 561/1,309 (42.9 %), needed 748 (launder 77 %, barrier 82 %, pins 45 % — v0/v1 + a0–a3 dominant), 0.225 s per compile — T4 priced at ~94k compiles ≈ 0.5 h, the residue ≈ 81 % of bodies ≈ 1,800 distinct exemplars; dictionary + SETUP rows; kit corpus; the 🛑 block for T3
This commit is contained in:
@@ -479,10 +479,12 @@ unsloth_compiled_cache/
|
||||
!/.run/P36/probe/*.md
|
||||
!/.run/P36/probe/*.json
|
||||
!/.run/P36/probe/*.py
|
||||
!/.run/P36/probe/*.jsonl
|
||||
!/.run/P36/delever/
|
||||
/.run/P36/delever/*
|
||||
!/.run/P36/delever/*.log
|
||||
!/.run/P36/delever/*.json
|
||||
/.run/P36/delever/recipes.json
|
||||
!/.run/P36/delever/*.jsonl
|
||||
!/.run/P36/delever/*.txt
|
||||
!/.run/P36/permuter/
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
.venv/bin/python tools/tool_census.py --all
|
||||
tool_census: 298 tool files (find == git ls-files) + 38 retired; classes {'LIVE': 238, 'ORPHAN': 30, 'REFERENCED': 30, 'RETIRED': 38}; dictionary rows 336
|
||||
tool_census: wrote docs/tool-index.md
|
||||
tool_census: wrote decomp-architect/tools/MANIFEST.md
|
||||
tool_census: corpus materialised — 365 verbatim copies, 30 pointers, INDEX.md
|
||||
kit-corpus wall=24.17 s
|
||||
@@ -229,7 +229,7 @@
|
||||
}
|
||||
},
|
||||
"coverage_ok": true,
|
||||
"elapsed_s": 35.0,
|
||||
"elapsed_s": 40.0,
|
||||
"generated": "2026-09-09",
|
||||
"headers": 3181,
|
||||
"levers_AB": {
|
||||
|
||||
@@ -25,4 +25,4 @@ lever_census: 218 binaries · 4,121 TUs + 3,181 headers · coverage OK · unclas
|
||||
src/shared/ov/func_80178004.h pins got 26 expected 26 OK
|
||||
ov_SC03_006 func_80184034 bare-name pins got 3 expected 3 OK
|
||||
engine_prelude.h asm sites (a macro definition only) got 0 expected 0 OK
|
||||
elapsed 35.0 s
|
||||
elapsed 40.0 s
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
{
|
||||
"head": "a1407bdfc",
|
||||
"stamp": "b44c5a8a3423",
|
||||
"generated": "2026-09-09 01:50",
|
||||
"aliases": [
|
||||
"main",
|
||||
"ov_SC03_014",
|
||||
"ov_SC03_015",
|
||||
"ov_SC04_011"
|
||||
],
|
||||
"objects": 177,
|
||||
"identical": 177,
|
||||
"failures": [],
|
||||
"twin_checks": 32,
|
||||
"twin_mismatch": [],
|
||||
"positive_control": {
|
||||
"obj": "build/src/800.o",
|
||||
"verdict": "DIFFERS"
|
||||
},
|
||||
"per_alias": {
|
||||
"main": {
|
||||
"objects": 85,
|
||||
"identical": 85,
|
||||
"seconds": 6.707000000000002,
|
||||
"mean_s": 0.079
|
||||
},
|
||||
"ov_SC03_014": {
|
||||
"objects": 32,
|
||||
"identical": 32,
|
||||
"seconds": 4.815,
|
||||
"mean_s": 0.15
|
||||
},
|
||||
"ov_SC03_015": {
|
||||
"objects": 32,
|
||||
"identical": 32,
|
||||
"seconds": 4.541,
|
||||
"mean_s": 0.142
|
||||
},
|
||||
"ov_SC04_011": {
|
||||
"objects": 28,
|
||||
"identical": 28,
|
||||
"seconds": 3.943,
|
||||
"mean_s": 0.141
|
||||
}
|
||||
},
|
||||
"per_object_seconds": {
|
||||
"build/src/800.o": 0.752,
|
||||
"build/src/800_b.o": 0.07,
|
||||
"build/src/800_b_2.o": 0.329,
|
||||
"build/src/800_b_o0a.o": 0.074,
|
||||
"build/src/800_c.o": 0.195,
|
||||
"build/src/800b2.o": 0.078,
|
||||
"build/src/apicard1.o": 0.061,
|
||||
"build/src/apicard2.o": 0.069,
|
||||
"build/src/apicard3.o": 0.076,
|
||||
"build/src/apicard4.o": 0.066,
|
||||
"build/src/apicard5.o": 0.086,
|
||||
"build/src/apicard6.o": 0.072,
|
||||
"build/src/apicard7.o": 0.081,
|
||||
"build/src/boot.o": 0.08,
|
||||
"build/src/gap.o": 0.071,
|
||||
"build/src/libapi1.o": 0.07,
|
||||
"build/src/libapi2.o": 0.063,
|
||||
"build/src/libc2_1.o": 0.064,
|
||||
"build/src/libc2_2.o": 0.059,
|
||||
"build/src/libcd1.o": 0.069,
|
||||
"build/src/libcd2.o": 0.065,
|
||||
"build/src/libetc.o": 0.062,
|
||||
"build/src/libgpu.o": 0.059,
|
||||
"build/src/libgpu2.o": 0.067,
|
||||
"build/src/libgs1.o": 0.057,
|
||||
"build/src/libgs2.o": 0.064,
|
||||
"build/src/libgs3.o": 0.057,
|
||||
"build/src/libgs4.o": 0.064,
|
||||
"build/src/libgs5.o": 0.057,
|
||||
"build/src/libgs6.o": 0.077,
|
||||
"build/src/libgs7.o": 0.061,
|
||||
"build/src/libgs8.o": 0.059,
|
||||
"build/src/libgte1.o": 0.055,
|
||||
"build/src/libgte10.o": 0.065,
|
||||
"build/src/libgte11.o": 0.063,
|
||||
"build/src/libgte12.o": 0.061,
|
||||
"build/src/libgte13.o": 0.056,
|
||||
"build/src/libgte14.o": 0.058,
|
||||
"build/src/libgte15.o": 0.071,
|
||||
"build/src/libgte16.o": 0.063,
|
||||
"build/src/libgte17.o": 0.063,
|
||||
"build/src/libgte18.o": 0.061,
|
||||
"build/src/libgte19.o": 0.063,
|
||||
"build/src/libgte2.o": 0.061,
|
||||
"build/src/libgte20.o": 0.066,
|
||||
"build/src/libgte21.o": 0.058,
|
||||
"build/src/libgte22.o": 0.063,
|
||||
"build/src/libgte23.o": 0.064,
|
||||
"build/src/libgte24.o": 0.057,
|
||||
"build/src/libgte25.o": 0.061,
|
||||
"build/src/libgte26.o": 0.068,
|
||||
"build/src/libgte27.o": 0.062,
|
||||
"build/src/libgte28.o": 0.06,
|
||||
"build/src/libgte29.o": 0.068,
|
||||
"build/src/libgte3.o": 0.069,
|
||||
"build/src/libgte30.o": 0.069,
|
||||
"build/src/libgte4.o": 0.065,
|
||||
"build/src/libgte5.o": 0.065,
|
||||
"build/src/libgte6.o": 0.061,
|
||||
"build/src/libgte7.o": 0.058,
|
||||
"build/src/libgte8.o": 0.059,
|
||||
"build/src/libgte9.o": 0.068,
|
||||
"build/src/libmcrd1.o": 0.082,
|
||||
"build/src/libmcrd2.o": 0.064,
|
||||
"build/src/libpad1.o": 0.068,
|
||||
"build/src/libpad2.o": 0.066,
|
||||
"build/src/sgap.o": 0.066,
|
||||
"build/src/sgap_2.o": 0.067,
|
||||
"build/src/sgap_3.o": 0.073,
|
||||
"build/src/sgap_4.o": 0.078,
|
||||
"build/src/sgap_5.o": 0.065,
|
||||
"build/src/sgap_6.o": 0.064,
|
||||
"build/src/sgap_8.o": 0.076,
|
||||
"build/src/snd1.o": 0.073,
|
||||
"build/src/snd10.o": 0.07,
|
||||
"build/src/snd11.o": 0.071,
|
||||
"build/src/snd12.o": 0.063,
|
||||
"build/src/snd2.o": 0.072,
|
||||
"build/src/snd3.o": 0.068,
|
||||
"build/src/snd4.o": 0.073,
|
||||
"build/src/snd5.o": 0.067,
|
||||
"build/src/snd6.o": 0.069,
|
||||
"build/src/snd7.o": 0.069,
|
||||
"build/src/snd8.o": 0.063,
|
||||
"build/src/snd9.o": 0.065,
|
||||
"build/src/ov_SC03_014/ov_SC03_014.o": 0.141,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_after.o": 0.509,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_8012ACE0.o": 0.394,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_80135888.o": 0.082,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_80135A4C.o": 0.08,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_80135D20.o": 0.126,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_801380E0.o": 0.169,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_8013C98C.o": 0.129,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_8013F350.o": 0.097,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_8013FFD8.o": 0.074,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_80140608.o": 0.182,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_8015444C.o": 0.086,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_80154C24.o": 0.174,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_801588CC.o": 0.102,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_80159C84.o": 0.079,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_8015A3C8.o": 0.075,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_8015AE2C.o": 0.093,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_8015C32C.o": 0.487,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_8016AB6C.o": 0.267,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_80171B4C.o": 0.102,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_801734BC.o": 0.205,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_801789AC.o": 0.064,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_80178D40.o": 0.099,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_8017A4AC.o": 0.066,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.o": 0.168,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.o": 0.193,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_80184440.o": 0.054,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_jr_801848E4.o": 0.281,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_o0b.o": 0.059,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_o0c.o": 0.06,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_o0d.o": 0.053,
|
||||
"build/src/ov_SC03_014/ov_SC03_014_o0e.o": 0.065,
|
||||
"build/src/ov_SC03_015/ov_SC03_015.o": 0.12,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_after.o": 0.526,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_8012ACE0.o": 0.382,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_80135888.o": 0.051,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_80135A4C.o": 0.051,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_80135D20.o": 0.116,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_801380E0.o": 0.148,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_8013C98C.o": 0.113,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_8013F350.o": 0.064,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_8013FFD8.o": 0.06,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_80140608.o": 0.18,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_8015444C.o": 0.07,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_80154C24.o": 0.169,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_801588CC.o": 0.085,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_80159C84.o": 0.066,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_8015A3C8.o": 0.068,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_8015AE2C.o": 0.092,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_8015C32C.o": 0.472,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_8016AB6C.o": 0.259,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_80171B4C.o": 0.101,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_801734BC.o": 0.201,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_801789AC.o": 0.058,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_80178D40.o": 0.1,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_8017A4AC.o": 0.064,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_8017AE2C.o": 0.164,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_8017EB7C.o": 0.189,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_80184440.o": 0.05,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_jr_801848E4.o": 0.278,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_o0b.o": 0.06,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_o0c.o": 0.061,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_o0d.o": 0.054,
|
||||
"build/src/ov_SC03_015/ov_SC03_015_o0e.o": 0.069,
|
||||
"build/src/ov_SC04_011/ov_SC04_011.o": 0.121,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_after.o": 0.423,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_8012ACE0.o": 0.353,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_80135888.o": 0.054,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_80135A4C.o": 0.053,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_80135D20.o": 0.12,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_801380E0.o": 0.152,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_8013C98C.o": 0.109,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_8013F350.o": 0.076,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_8013FFD8.o": 0.065,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_80140608.o": 0.172,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_8015444C.o": 0.072,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_80154C24.o": 0.169,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_801588CC.o": 0.092,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_80159C84.o": 0.066,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_8015A3C8.o": 0.073,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_8015AE2C.o": 0.093,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_8015C32C.o": 0.353,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_8016AB6C.o": 0.217,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_80171B4C.o": 0.099,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_801734BC.o": 0.164,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_801789AC.o": 0.054,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_80178D40.o": 0.085,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_8017A4AC.o": 0.063,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_8017AE2C.o": 0.093,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_jr_8017D494.o": 0.444,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_o0b.o": 0.048,
|
||||
"build/src/ov_SC04_011/ov_SC04_011_o0c.o": 0.06
|
||||
},
|
||||
"ok": true,
|
||||
"seconds": 2.3
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
01:56:54 probe: 285 bodies sampled from 19868 lever bodies (2340 distinct classes); seed 11
|
||||
01:56:54 src/md_MAIN_003/md_MAIN_003_o0e.c:func_800D0B1C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/md_MAIN_003/md_MAIN_003_o0c.c:func_800D0D6C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/boot.c:func_80011380 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/md_MAIN_011/md_MAIN_011.c:func_800CEF00 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/md_MAIN_003/md_MAIN_003_o0e.c:func_800D0268 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/boot.c:func_80011C8C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/800_b.c:func_8002B0B4 A=DIFFERS B: removed 0 needed 5 compiles 6
|
||||
01:56:54 src/md_MAIN_003/md_MAIN_003_jr_800D1E18.c:func_800D2A24 A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:56:54 src/md_MAIN_021/md_MAIN_021.c:func_800CB0C8 A=DIFFERS B: removed 0 needed 3 compiles 4
|
||||
01:56:54 src/boot.c:func_80010F80 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/md_MAIN_026/md_MAIN_026.c:func_800CB900 A=DIFFERS B: removed 1 needed 1 compiles 3
|
||||
01:56:54 src/800_c.c:func_800383A4 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:56:54 src/boot.c:func_80010A08 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/md_MAIN_009/md_MAIN_009.c:func_800CD674 A=DIFFERS B: removed 2 needed 6 compiles 10
|
||||
01:56:55 src/md_SC03_076/md_SC03_076_jr_801F218C.c:func_801F2348 A=DIFFERS B: removed 2 needed 1 compiles 4
|
||||
01:56:55 src/md_MAIN_044/md_MAIN_044.c:func_800CCD2C A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:56:55 src/md_SC03_135/md_SC03_135_jr_801E5358.c:func_801E559C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:55 src/md_SC03_075/md_SC03_075.c:func_801F02D4 A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:56:55 src/md_SC04_026/md_SC04_026.c:func_801E89D4 A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:56:55 src/md_MAIN_001/md_MAIN_001.c:func_800CF290 A=DIFFERS B: removed 9 needed 4 compiles 15
|
||||
01:56:55 src/md_MAIN_044/md_MAIN_044.c:func_800CD894 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:56:55 src/md_MAIN_003/md_MAIN_003.c:func_800CF3E8 A=DIFFERS B: removed 4 needed 8 compiles 14
|
||||
01:56:55 src/md_MAIN_043/md_MAIN_043.c:func_800CD404 A=DIFFERS B: removed 7 needed 1 compiles 10
|
||||
01:56:55 src/md_MAIN_013/md_MAIN_013.c:func_800CB138 A=DIFFERS B: removed 0 needed 13 compiles 15
|
||||
01:56:55 src/md_SC05_026/md_SC05_026_jr_801F0748.c:func_801F0C4C A=DIFFERS B: removed 4 needed 2 compiles 8
|
||||
01:56:55 src/800_c.c:func_800385C0 A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:56:55 src/ov_MAIN_012/ov_MAIN_012_jr_8013F350.c:func_801418F8 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:55 src/ov_MAIN_012/ov_MAIN_012_jr_8013C98C.c:func_8013D53C A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:56:55 src/md_SC07_003/md_SC07_003.c:func_801A293C A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:56:55 src/md_SC07_004/md_SC07_004.c:func_801AB818 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:56 src/md_MAIN_003/md_MAIN_003.c:func_800CFEB4 A=DIFFERS B: removed 7 needed 4 compiles 13
|
||||
01:56:56 src/800_b_2.c:func_8002EFF8 A=DIFFERS B: removed 1 needed 2 compiles 5
|
||||
01:56:56 src/ov_MAIN_012/ov_MAIN_012_jr_8016AE5C.c:func_8016E9EC A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:56:56 src/ov_SC01_004/ov_SC01_004_jr_8017E5B8.c:func_8017E5B8 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:56:56 src/ov_SC01_004/ov_SC01_004_jr_8017BE9C.c:func_8017DC38 A=DIFFERS B: removed 1 needed 3 compiles 6
|
||||
01:56:56 src/ov_MAIN_012/ov_MAIN_012_jr_801380E0.c:func_8013B274 A=DIFFERS B: removed 4 needed 8 compiles 13
|
||||
01:56:56 src/ov_SC01_004/ov_SC01_004_jr_8017E5B8.c:func_8017E804 A=DIFFERS B: removed 1 needed 5 compiles 8
|
||||
01:56:56 src/800.c:func_80012E6C A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:56:57 src/800_b_2.c:func_8002FF0C A=DIFFERS B: removed 0 needed 3 compiles 4
|
||||
01:56:57 src/ov_SC01_000/ov_SC01_000_jr_8017BEBC.c:func_8017E4A0 A=DIFFERS B: removed 7 needed 2 compiles 11
|
||||
01:56:57 src/md_SC07_004/md_SC07_004.c:func_801AE908 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:56:57 src/800_c.c:func_800391D4 A=DIFFERS B: removed 0 needed 10 compiles 12
|
||||
01:56:57 src/ov_SC01_008/ov_SC01_008_jr_8017BE9C.c:func_8017E050 A=DIFFERS B: removed 0 needed 4 compiles 6
|
||||
01:56:57 src/ov_SC01_084/ov_SC01_084_jr_80182A00.c:func_80183BD0 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:57 src/ov_SC01_009/ov_SC01_009_jr_8017E590.c:func_8017FFD0 A=DIFFERS B: removed 3 needed 4 compiles 9
|
||||
01:56:58 src/ov_SC01_084/ov_SC01_084_jr_80182A00.c:func_8018392C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:58 src/ov_SC01_077/ov_SC01_077_jr_8017AE2C.c:func_8017B614 A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:56:58 src/ov_SC01_084/ov_SC01_084_jr_80182A00.c:func_80183A7C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:58 src/800_b_2.c:func_80034314 A=DIFFERS B: removed 2 needed 1 compiles 5
|
||||
01:56:58 src/ov_MAIN_012/ov_MAIN_012.c:func_80130D48 A=DIFFERS B: removed 5 needed 4 compiles 11
|
||||
01:56:58 src/ov_SC02_005/ov_SC02_005_jr_8017CF90.c:func_8018118C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:58 src/ov_SC02_005/ov_SC02_005_jr_8017AE2C.c:func_8017C41C A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:56:58 src/800_c.c:func_80038958 A=DIFFERS B: removed 5 needed 2 compiles 9
|
||||
01:56:58 src/ov_SC01_080/ov_SC01_080_jr_8017AE2C.c:func_80180728 A=DIFFERS B: removed 0 needed 5 compiles 6
|
||||
01:56:58 src/ov_MAIN_012/ov_MAIN_012_jr_8015A3C8.c:func_80162438 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:56:59 src/ov_SC01_000/ov_SC01_000_jr_8013C98C.c:func_8013D9B0 A=DIFFERS B: removed 9 needed 25 compiles 36
|
||||
01:56:59 src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c:func_8017FD9C A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:56:59 src/ov_SC02_005/ov_SC02_005_jr_8018EA04.c:func_8018FEA0 A=DIFFERS B: removed 5 needed 3 compiles 10
|
||||
01:56:59 src/ov_SC02_005/ov_SC02_005_jr_80185E80.c:func_8018D270 A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:56:59 src/ov_SC02_005/ov_SC02_005_jr_8018EA04.c:func_8018FA34 A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:57:00 src/ov_SC01_077/ov_SC01_077.c:func_80140958 A=DIFFERS B: removed 7 needed 4 compiles 13
|
||||
01:57:00 src/ov_SC02_021/ov_SC02_021_jr_8017ECFC.c:func_8017F1B4 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:00 src/ov_SC02_011/ov_SC02_011_jr_80183178.c:func_80187E08 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:00 src/ov_SC02_021/ov_SC02_021_jr_8017C294.c:func_8017DC10 A=DIFFERS B: removed 1 needed 3 compiles 6
|
||||
01:57:00 src/md_SC07_004/md_SC07_004.c:func_801A2DC4 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:57:00 src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c:func_8017F67C A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:57:00 src/ov_SC02_028/ov_SC02_028_jr_801884D8.c:func_8018AB34 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:00 src/ov_SC02_028/ov_SC02_028_jr_8017D898.c:func_80181264 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:00 src/ov_SC02_011/ov_SC02_011_jr_80188E3C.c:func_8018AB20 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:01 src/ov_SC02_026/ov_SC02_026_jr_8017C180.c:func_8017F6B0 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:01 src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c:func_8017D710 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:01 src/ov_SC02_011/ov_SC02_011_jr_80183178.c:func_80186868 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:01 src/ov_SC02_035/ov_SC02_035_jr_8017BEBC.c:func_80181B00 A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:57:01 src/ov_SC02_041/ov_SC02_041_jr_8017BEBC.c:func_8018317C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:01 src/ov_MAIN_012/ov_MAIN_012.c:func_8012956C A=DIFFERS B: removed 6 needed 4 compiles 12
|
||||
01:57:02 src/ov_SC02_039/ov_SC02_039_jr_8017BEBC.c:func_8017DE00 A=DIFFERS B: removed 6 needed 4 compiles 12
|
||||
01:57:02 src/ov_SC03_001/ov_SC03_001_jr_8017AE2C.c:func_80182058 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:02 src/ov_SC03_001/ov_SC03_001_jr_80189030.c:func_801898E4 A=DIFFERS B: removed 1 needed 5 compiles 8
|
||||
01:57:02 src/ov_SC03_001/ov_SC03_001_jr_8018B8DC.c:func_8018BCD4 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:03 src/ov_SC02_026/ov_SC02_026_jr_8017C180.c:func_8017E3AC A=DIFFERS B: removed 4 needed 1 compiles 7
|
||||
01:57:03 src/ov_SC03_002/ov_SC03_002_jr_8017D604.c:func_8017EA54 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:57:03 src/800_b_2.c:func_8003388C A=DIFFERS B: removed 2 needed 15 compiles 19
|
||||
01:57:03 src/ov_SC02_011/ov_SC02_011_jr_80183178.c:func_80187CE8 A=DIFFERS B: removed 4 needed 4 compiles 10
|
||||
01:57:03 src/ov_SC03_013/ov_SC03_013_jr_8017C730.c:func_8017DD98 A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:57:04 src/ov_SC02_011/ov_SC02_011_jr_80183178.c:func_80188250 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:04 src/ov_SC03_001/ov_SC03_001_jr_8017AE2C.c:func_8017BF50 A=DIFFERS B: removed 3 needed 1 compiles 6
|
||||
01:57:04 src/800_c.c:func_80038A58 A=DIFFERS B: removed 26 needed 9 compiles 37
|
||||
01:57:04 src/ov_SC03_011/ov_SC03_011_jr_80140608.c:func_80140958 A=DIFFERS B: removed 7 needed 4 compiles 13
|
||||
01:57:04 src/ov_SC03_024/ov_SC03_024_jr_80183BF8.c:func_80185E38 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:04 src/ov_SC03_028/ov_SC03_028_jr_8017DF98.c:func_80180AC4 A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:57:05 src/ov_SC03_024/ov_SC03_024_jr_8017DF84.c:func_80182108 A=DIFFERS B: removed 1 needed 3 compiles 6
|
||||
01:57:05 src/ov_SC03_028/ov_SC03_028_jr_801887A8.c:func_80189AF4 A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:57:05 src/800.c:func_800242D0 A=DIFFERS B: removed 6 needed 5 compiles 13
|
||||
01:57:05 src/800_c.c:func_800384A8 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:05 src/md_SC07_004/md_SC07_004.c:func_801AB694 A=DIFFERS B: removed 5 needed 1 compiles 8
|
||||
01:57:06 src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c:func_80185BD4 A=DIFFERS B: removed 3 needed 2 compiles 7
|
||||
01:57:06 src/ov_SC03_030/ov_SC03_030_jr_8017AE2C.c:func_80180960 A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:57:06 src/ov_SC03_105/ov_SC03_105_jr_8017C8D0.c:func_8017E180 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:06 src/ov_SC03_029/ov_SC03_029_jr_8017FF7C.c:func_80180B84 A=DIFFERS B: removed 4 needed 1 compiles 7
|
||||
01:57:06 src/ov_SC03_105/ov_SC03_105_jr_80186DDC.c:func_80187928 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:06 src/ov_SC03_097/ov_SC03_097_jr_8017D898.c:func_80181CF4 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:06 src/ov_SC03_092/ov_SC03_092_jr_80181694.c:func_8018478C A=DIFFERS B: removed 0 needed 8 compiles 10
|
||||
01:57:06 src/ov_SC03_108/ov_SC03_108_jr_8017F83C.c:func_8017FD64 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:07 src/ov_SC03_028/ov_SC03_028_jr_80185C14.c:func_80186368 A=DIFFERS B: removed 17 needed 3 compiles 22
|
||||
01:57:07 src/ov_SC03_105/ov_SC03_105_jr_80181C84.c:func_80183A98 A=DIFFERS B: removed 0 needed 5 compiles 6
|
||||
01:57:07 src/ov_SC03_121/ov_SC03_121_jr_8017E1D0.c:func_8017F374 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:07 src/ov_SC03_112/ov_SC03_112_jr_8017C294.c:func_8017D174 A=DIFFERS B: removed 1 needed 3 compiles 5
|
||||
01:57:07 src/ov_SC03_094/ov_SC03_094_jr_8017BEBC.c:func_80181448 A=DIFFERS B: removed 2 needed 4 compiles 8
|
||||
01:57:07 src/ov_SC04_015/ov_SC04_015_jr_8017AE2C.c:func_8017DBAC A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:08 src/md_SC07_004/md_SC07_004.c:func_801A395C A=DIFFERS B: removed 1 needed 2 compiles 5
|
||||
01:57:08 src/ov_SC04_018/ov_SC04_018_jr_80188E1C.c:func_80189EA0 A=DIFFERS B: removed 1 needed 1 compiles 3
|
||||
01:57:08 src/ov_SC04_018/ov_SC04_018_jr_801878E8.c:func_80188778 A=DIFFERS B: removed 2 needed 4 compiles 8
|
||||
01:57:08 src/ov_SC02_037/ov_SC02_037_jr_8017AE2C.c:func_8017F2B4 A=DIFFERS B: removed 6 needed 17 compiles 25
|
||||
01:57:08 src/ov_SC04_020/ov_SC04_020_jr_8017D604.c:func_8018087C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:08 src/ov_SC03_113/ov_SC03_113_jr_8017C294.c:func_8017F394 A=DIFFERS B: removed 5 needed 1 compiles 8
|
||||
01:57:08 src/md_SC07_004/md_SC07_004.c:func_801A7CDC A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:08 src/ov_SC03_107/ov_SC03_107_jr_801789AC.c:func_8017BEBC A=DIFFERS B: removed 0 needed 7 compiles 8
|
||||
01:57:09 src/ov_SC01_077/ov_SC01_077.c:func_8013D9B0 A=DIFFERS B: removed 9 needed 25 compiles 36
|
||||
01:57:09 src/ov_SC05_001/ov_SC05_001_jr_8017BEBC.c:func_80182258 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:09 src/ov_SC04_016/ov_SC04_016_jr_8017BEBC.c:func_8017DA50 A=DIFFERS B: removed 2 needed 8 compiles 12
|
||||
01:57:09 src/ov_SC05_003/ov_SC05_003_jr_8017BEBC.c:func_801815A0 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:09 src/ov_SC03_113/ov_SC03_113_jr_8017C294.c:func_8017E178 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:09 src/ov_SC05_005/ov_SC05_005_jr_8017D898.c:func_801816A8 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:09 src/ov_SC04_015/ov_SC04_015_jr_8017AE2C.c:func_8017BF70 A=DIFFERS B: removed 3 needed 1 compiles 6
|
||||
01:57:09 src/ov_SC05_010/ov_SC05_010_jr_80180F84.c:func_801814AC A=DIFFERS B: removed 1 needed 1 compiles 3
|
||||
01:57:09 src/ov_SC01_077/ov_SC01_077.c:func_801418F8 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:09 src/ov_SC05_008/ov_SC05_008_jr_8017AE2C.c:func_8017E6A4 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:09 src/ov_SC05_002/ov_SC05_002_jr_8017BEBC.c:func_8017F200 A=DIFFERS B: removed 5 needed 1 compiles 8
|
||||
01:57:09 src/ov_SC05_003/ov_SC05_003_jr_8017BEBC.c:func_801812AC A=DIFFERS B: removed 1 needed 1 compiles 3
|
||||
01:57:09 src/ov_SC03_124/ov_SC03_124_jr_80188544.c:func_80188C68 A=DIFFERS B: removed 5 needed 19 compiles 26
|
||||
01:57:10 src/ov_SC06_013/ov_SC06_013_jr_8017BEBC.c:func_8017DE14 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:10 src/ov_SC06_006/ov_SC06_006_jr_8017DB90.c:func_8017E550 A=DIFFERS B: removed 0 needed 3 compiles 4
|
||||
01:57:10 src/ov_SC06_016/ov_SC06_016_jr_801816DC.c:func_80181C78 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:10 src/ov_SC06_011/ov_SC06_011_jr_8017EEEC.c:func_8017F3C8 A=DIFFERS B: removed 4 needed 1 compiles 7
|
||||
01:57:10 src/ov_SC06_008/ov_SC06_008_jr_8017C294.c:func_8017D73C A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:10 src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c:func_8018A688 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:10 src/ov_SC04_011/ov_SC04_011_jr_8017D494.c:func_801835B0 A=DIFFERS B: removed 0 needed 3 compiles 4
|
||||
01:57:10 src/ov_SC06_011/ov_SC06_011_jr_8017BEBC.c:func_8017E5D0 A=DIFFERS B: removed 4 needed 3 compiles 9
|
||||
01:57:10 src/ov_SC05_010/ov_SC05_010_jr_80181CDC.c:func_80183D5C A=DIFFERS B: removed 9 needed 1 compiles 12
|
||||
01:57:10 src/ov_SC06_016/ov_SC06_016_jr_8017C8D0.c:func_801810A4 A=DIFFERS B: removed 2 needed 3 compiles 6
|
||||
01:57:11 src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c:func_80182464 A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:57:11 src/ov_SC06_024/ov_SC06_024_jr_80186F00.c:func_8018D674 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:11 src/ov_SC03_107/ov_SC03_107_jr_801789AC.c:func_8017CF48 A=DIFFERS B: removed 2 needed 4 compiles 8
|
||||
01:57:11 src/ov_SC06_029/ov_SC06_029_jr_801898CC.c:func_8018A180 A=COMPILE-ERROR B: removed 0 needed 6 compiles 7
|
||||
01:57:11 src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c:func_801811DC A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:12 src/ov_SC06_024/ov_SC06_024_jr_8017BEBC.c:func_8017FA1C A=DIFFERS B: removed 1 needed 3 compiles 6
|
||||
01:57:12 src/ov_SC06_030/ov_SC06_030_jr_8017F65C.c:func_80180FF4 A=DIFFERS B: removed 0 needed 10 compiles 12
|
||||
01:57:12 src/ov_SC06_033/ov_SC06_033_jr_8018D98C.c:func_8018D98C A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:12 src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c:func_80185DD8 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:12 src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c:func_8018A974 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:57:12 src/ov_SC06_032/ov_SC06_032_jr_801902EC.c:func_801902EC A=DIFFERS B: removed 4 needed 9 compiles 14
|
||||
01:57:12 src/ov_SC06_033/ov_SC06_033_jr_8018C2D8.c:func_8018C2D8 A=DIFFERS B: removed 4 needed 8 compiles 13
|
||||
01:57:12 src/ov_SC06_032/ov_SC06_032_jr_801919A0.c:func_801919A0 A=REFUSED B: removed 4 needed 10 compiles 14
|
||||
01:57:13 src/ov_SC07_000/ov_SC07_000_jr_8017F8B8.c:func_80181BA8 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:13 src/ov_SC07_007/ov_SC07_007_jr_8013C98C.c:func_8013D53C A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:13 src/ov_SC06_016/ov_SC06_016_jr_8017C8D0.c:func_801813B0 A=DIFFERS B: removed 0 needed 12 compiles 13
|
||||
01:57:13 src/ov_SC07_007/ov_SC07_007_jr_8017BEBC.c:func_8018044C A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:13 src/resident/resident.c:func_800CFE60 A=DIFFERS B: removed 1 needed 2 compiles 5
|
||||
01:57:13 src/ov_SC07_002/ov_SC07_002_jr_8017C8D0.c:func_80185FB0 A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:57:13 src/ov_SC07_010/ov_SC07_010_jr_8017AE2C.c:func_80180480 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:13 src/resident/resident_jr_800D00E4.c:func_800D0488 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:13 src/resident/resident_jr_800D128C.c:func_800D1984 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:14 src/ov_SC06_032/ov_SC06_032_jr_80182890.c:func_8018BA4C A=DIFFERS B: removed 3 needed 2 compiles 7
|
||||
01:57:14 src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c:func_801835B0 A=DIFFERS B: removed 0 needed 7 compiles 8
|
||||
01:57:14 src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c:func_8017DB20 A=DIFFERS B: removed 2 needed 1 compiles 5
|
||||
01:57:14 src/resident/resident_jr_800D00E4.c:func_800D0E30 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:57:14 src/resident/resident_jr_800D128C.c:func_800D128C A=DIFFERS B: removed 0 needed 3 compiles 4
|
||||
01:57:14 src/ov_SC07_007/ov_SC07_007_jr_8017BEBC.c:func_8018122C A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:57:14 src/resident/resident_jr_800D00E4.c:func_800D0214 A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:57:14 src/resident/resident_jr_800D128C.c:func_800D1658 A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:57:14 src/resident/resident_jr_800D00E4.c:func_800D02D0 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:14 src/ov_SC04_011/ov_SC04_011_jr_8017D494.c:func_8018E428 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:14 src/resident/resident_jr_800D00E4.c:func_800D0D7C A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:14 src/resident/resident_jr_800D128C.c:func_800D2D10 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:14 src/ov_SC07_010/ov_SC07_010_jr_80140608.c:func_80140958 A=DIFFERS B: removed 7 needed 4 compiles 13
|
||||
01:57:15 src/resident/resident_jr_800D128C.c:func_800D2650 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:15 src/resident/resident_jr_800D128C.c:func_800D1B80 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:15 src/ov_SC07_006/ov_SC07_006_jr_8017BEBC.c:func_80182F3C A=DIFFERS B: removed 6 needed 6 compiles 13
|
||||
01:57:15 src/ov_SC07_006/ov_SC07_006_jr_80171B4C.c:func_80176734 A=DIFFERS B: removed 1 needed 11 compiles 14
|
||||
01:57:16 src/ov_SC04_011/ov_SC04_011_jr_8017D494.c:func_8018315C A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:57:29 src/800.c:func_800226C0 A=DIFFERS B: removed 31 needed 14 compiles 47
|
||||
01:57:30 src/800.c:func_80020DA4 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:34 src/800.c:func_8002AF70 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:57:37 src/800.c:func_800241C0 A=DIFFERS B: removed 3 needed 3 compiles 8
|
||||
01:57:38 src/800.c:func_80016A7C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:45 src/800.c:func_80023570 A=DIFFERS B: removed 9 needed 4 compiles 15
|
||||
01:57:47 src/800.c:func_8001A114 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:53 src/800.c:func_80016224 A=DIFFERS B: removed 3 needed 6 compiles 11
|
||||
01:57:54 src/800.c:func_80025A30 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:55 src/800.c:func_8001EA14 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:58:13 src/800.c:func_800215F4 A=DIFFERS B: removed 29 needed 7 compiles 38
|
||||
01:58:19 src/800.c:func_8002AC00 A=DIFFERS B: removed 4 needed 5 compiles 11
|
||||
01:58:25 src/800.c:func_8001BADC A=DIFFERS B: removed 5 needed 3 compiles 10
|
||||
01:58:26 src/800.c:func_800273F4 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:58:30 src/800.c:func_80015208 A=DIFFERS B: removed 3 needed 1 compiles 6
|
||||
01:58:35 src/800.c:func_8001BBBC A=DIFFERS B: removed 4 needed 4 compiles 10
|
||||
01:58:39 src/800.c:LoaderInitFileTable A=DIFFERS B: removed 0 needed 7 compiles 9
|
||||
01:58:40 src/shared/ov/func_8012A860.h:func_8012A860 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:58:41 src/shared/ov/func_8012C2D0.h:func_8012C2D0 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:58:44 src/shared/ov/func_8012DBD0.h:func_8012DBD0 A=DIFFERS B: removed 8 needed 4 compiles 14
|
||||
01:58:46 src/shared/ov/func_80135004__0f8f8d0b.h:func_80135004 A=DIFFERS B: removed 4 needed 4 compiles 10
|
||||
01:58:48 src/shared/ov/func_80135168__bad0a585.h:func_80135168 A=DIFFERS B: removed 0 needed 5 compiles 7
|
||||
01:58:48 src/shared/ov/func_80135A4C__e0129286.h:func_80135A4C A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:58:49 src/shared/ov/func_80135EB0__c9438c12.h:func_80135EB0 A=DIFFERS B: removed 0 needed 6 compiles 8
|
||||
01:58:50 src/shared/ov/func_80136334__6e7f4730.h:func_80136334 A=DIFFERS B: removed 4 needed 4 compiles 10
|
||||
01:58:51 src/shared/ov/func_8013B274__28562738.h:func_8013B274 A=DIFFERS B: removed 4 needed 8 compiles 13
|
||||
01:58:51 src/shared/ov/func_8013D178__421ba659.h:func_8013D178 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:58:52 src/shared/ov/func_80140608__2fb5c201.h:func_80140608 A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:58:53 src/shared/ov/func_801415C0.h:func_801415C0 A=DIFFERS B: removed 3 needed 2 compiles 7
|
||||
01:58:53 src/shared/ov/func_80141B90.h:func_80141B90 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:58:54 src/shared/ov/func_80145A2C__530ca2ff.h:func_80145A2C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:58:54 src/shared/ov/func_801497A8.h:func_801497A8 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:58:55 src/shared/ov/func_8014DD8C.h:func_8014DD8C A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:58:56 src/shared/ov/func_8014F74C.h:func_8014F74C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:58:58 src/shared/ov/func_801536DC.h:func_801536DC A=DIFFERS B: removed 2 needed 1 compiles 5
|
||||
01:59:00 src/shared/ov/func_8015B6F4.h:func_8015B6F4 A=DIFFERS B: removed 1 needed 3 compiles 6
|
||||
01:59:02 src/shared/ov/func_801612B8.h:func_801612B8 A=DIFFERS B: removed 2 needed 1 compiles 5
|
||||
01:59:05 src/shared/ov/func_80162438__e113e304.h:func_80162438 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:59:09 src/shared/ov/func_80166054.h:func_80166054 A=DIFFERS B: removed 5 needed 5 compiles 12
|
||||
01:59:11 src/shared/ov/func_80166F58__3728db8a.h:func_80166F58 A=DIFFERS B: removed 2 needed 2 compiles 6
|
||||
01:59:12 src/shared/ov/func_8016DF5C__a8a4aea4.h:func_8016DF5C A=DIFFERS B: removed 1 needed 2 compiles 5
|
||||
01:59:13 src/shared/ov/func_801759D8.h:func_801759D8 A=DIFFERS B: removed 1 needed 1 compiles 3
|
||||
01:59:16 src/shared/ov/func_80176734__261d72d2.h:func_80176734 A=DIFFERS B: removed 1 needed 11 compiles 14
|
||||
01:59:18 src/shared/ov/func_801778A8.h:func_801778A8 A=DIFFERS B: removed 3 needed 2 compiles 7
|
||||
01:59:23 src/shared/ov/func_80177B5C__879ede92.h:func_80177B5C A=DIFFERS B: removed 8 needed 15 compiles 25
|
||||
01:59:24 src/shared/ov/func_8017CF6C__4771362e.h:func_8017CF6C A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:59:24 src/shared/ov/func_8017D0BC__4f23330c.h:func_8017D0BC A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:59:24 src/shared/ov/func_8017E98C__94ae7b9b.h:func_8017E98C A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:59:25 src/shared/ov/func_80181538__27797037.h:func_80181538 A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:59:25 src/shared/ov/func_80188028.h:func_80188028 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,264 @@
|
||||
01:56:54 probe: 285 bodies sampled from 19868 lever bodies (2340 distinct classes); seed 11
|
||||
01:56:54 src/md_MAIN_003/md_MAIN_003_o0e.c:func_800D0B1C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/md_MAIN_003/md_MAIN_003_o0c.c:func_800D0D6C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/boot.c:func_80011380 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/md_MAIN_011/md_MAIN_011.c:func_800CEF00 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/md_MAIN_003/md_MAIN_003_o0e.c:func_800D0268 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/boot.c:func_80011C8C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/800_b.c:func_8002B0B4 A=DIFFERS B: removed 0 needed 5 compiles 6
|
||||
01:56:54 src/md_MAIN_003/md_MAIN_003_jr_800D1E18.c:func_800D2A24 A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:56:54 src/md_MAIN_021/md_MAIN_021.c:func_800CB0C8 A=DIFFERS B: removed 0 needed 3 compiles 4
|
||||
01:56:54 src/boot.c:func_80010F80 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/md_MAIN_026/md_MAIN_026.c:func_800CB900 A=DIFFERS B: removed 1 needed 1 compiles 3
|
||||
01:56:54 src/800_c.c:func_800383A4 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:56:54 src/boot.c:func_80010A08 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:54 src/md_MAIN_009/md_MAIN_009.c:func_800CD674 A=DIFFERS B: removed 2 needed 6 compiles 10
|
||||
01:56:55 src/md_SC03_076/md_SC03_076_jr_801F218C.c:func_801F2348 A=DIFFERS B: removed 2 needed 1 compiles 4
|
||||
01:56:55 src/md_MAIN_044/md_MAIN_044.c:func_800CCD2C A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:56:55 src/md_SC03_135/md_SC03_135_jr_801E5358.c:func_801E559C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:55 src/md_SC03_075/md_SC03_075.c:func_801F02D4 A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:56:55 src/md_SC04_026/md_SC04_026.c:func_801E89D4 A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:56:55 src/md_MAIN_001/md_MAIN_001.c:func_800CF290 A=DIFFERS B: removed 9 needed 4 compiles 15
|
||||
01:56:55 src/md_MAIN_044/md_MAIN_044.c:func_800CD894 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:56:55 src/md_MAIN_003/md_MAIN_003.c:func_800CF3E8 A=DIFFERS B: removed 4 needed 8 compiles 14
|
||||
01:56:55 src/md_MAIN_043/md_MAIN_043.c:func_800CD404 A=DIFFERS B: removed 7 needed 1 compiles 10
|
||||
01:56:55 src/md_MAIN_013/md_MAIN_013.c:func_800CB138 A=DIFFERS B: removed 0 needed 13 compiles 15
|
||||
01:56:55 src/md_SC05_026/md_SC05_026_jr_801F0748.c:func_801F0C4C A=DIFFERS B: removed 4 needed 2 compiles 8
|
||||
01:56:55 src/800_c.c:func_800385C0 A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:56:55 src/ov_MAIN_012/ov_MAIN_012_jr_8013F350.c:func_801418F8 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:55 src/ov_MAIN_012/ov_MAIN_012_jr_8013C98C.c:func_8013D53C A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:56:55 src/md_SC07_003/md_SC07_003.c:func_801A293C A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:56:55 src/md_SC07_004/md_SC07_004.c:func_801AB818 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:56 src/md_MAIN_003/md_MAIN_003.c:func_800CFEB4 A=DIFFERS B: removed 7 needed 4 compiles 13
|
||||
01:56:56 src/800_b_2.c:func_8002EFF8 A=DIFFERS B: removed 1 needed 2 compiles 5
|
||||
01:56:56 src/ov_MAIN_012/ov_MAIN_012_jr_8016AE5C.c:func_8016E9EC A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:56:56 src/ov_SC01_004/ov_SC01_004_jr_8017E5B8.c:func_8017E5B8 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:56:56 src/ov_SC01_004/ov_SC01_004_jr_8017BE9C.c:func_8017DC38 A=DIFFERS B: removed 1 needed 3 compiles 6
|
||||
01:56:56 src/ov_MAIN_012/ov_MAIN_012_jr_801380E0.c:func_8013B274 A=DIFFERS B: removed 4 needed 8 compiles 13
|
||||
01:56:56 src/ov_SC01_004/ov_SC01_004_jr_8017E5B8.c:func_8017E804 A=DIFFERS B: removed 1 needed 5 compiles 8
|
||||
01:56:56 src/800.c:func_80012E6C A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:56:57 src/800_b_2.c:func_8002FF0C A=DIFFERS B: removed 0 needed 3 compiles 4
|
||||
01:56:57 src/ov_SC01_000/ov_SC01_000_jr_8017BEBC.c:func_8017E4A0 A=DIFFERS B: removed 7 needed 2 compiles 11
|
||||
01:56:57 src/md_SC07_004/md_SC07_004.c:func_801AE908 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:56:57 src/800_c.c:func_800391D4 A=DIFFERS B: removed 0 needed 10 compiles 12
|
||||
01:56:57 src/ov_SC01_008/ov_SC01_008_jr_8017BE9C.c:func_8017E050 A=DIFFERS B: removed 0 needed 4 compiles 6
|
||||
01:56:57 src/ov_SC01_084/ov_SC01_084_jr_80182A00.c:func_80183BD0 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:57 src/ov_SC01_009/ov_SC01_009_jr_8017E590.c:func_8017FFD0 A=DIFFERS B: removed 3 needed 4 compiles 9
|
||||
01:56:58 src/ov_SC01_084/ov_SC01_084_jr_80182A00.c:func_8018392C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:58 src/ov_SC01_077/ov_SC01_077_jr_8017AE2C.c:func_8017B614 A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:56:58 src/ov_SC01_084/ov_SC01_084_jr_80182A00.c:func_80183A7C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:58 src/800_b_2.c:func_80034314 A=DIFFERS B: removed 2 needed 1 compiles 5
|
||||
01:56:58 src/ov_MAIN_012/ov_MAIN_012.c:func_80130D48 A=DIFFERS B: removed 5 needed 4 compiles 11
|
||||
01:56:58 src/ov_SC02_005/ov_SC02_005_jr_8017CF90.c:func_8018118C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:56:58 src/ov_SC02_005/ov_SC02_005_jr_8017AE2C.c:func_8017C41C A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:56:58 src/800_c.c:func_80038958 A=DIFFERS B: removed 5 needed 2 compiles 9
|
||||
01:56:58 src/ov_SC01_080/ov_SC01_080_jr_8017AE2C.c:func_80180728 A=DIFFERS B: removed 0 needed 5 compiles 6
|
||||
01:56:58 src/ov_MAIN_012/ov_MAIN_012_jr_8015A3C8.c:func_80162438 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:56:59 src/ov_SC01_000/ov_SC01_000_jr_8013C98C.c:func_8013D9B0 A=DIFFERS B: removed 9 needed 25 compiles 36
|
||||
01:56:59 src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c:func_8017FD9C A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:56:59 src/ov_SC02_005/ov_SC02_005_jr_8018EA04.c:func_8018FEA0 A=DIFFERS B: removed 5 needed 3 compiles 10
|
||||
01:56:59 src/ov_SC02_005/ov_SC02_005_jr_80185E80.c:func_8018D270 A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:56:59 src/ov_SC02_005/ov_SC02_005_jr_8018EA04.c:func_8018FA34 A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:57:00 src/ov_SC01_077/ov_SC01_077.c:func_80140958 A=DIFFERS B: removed 7 needed 4 compiles 13
|
||||
01:57:00 src/ov_SC02_021/ov_SC02_021_jr_8017ECFC.c:func_8017F1B4 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:00 src/ov_SC02_011/ov_SC02_011_jr_80183178.c:func_80187E08 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:00 src/ov_SC02_021/ov_SC02_021_jr_8017C294.c:func_8017DC10 A=DIFFERS B: removed 1 needed 3 compiles 6
|
||||
01:57:00 src/md_SC07_004/md_SC07_004.c:func_801A2DC4 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:57:00 src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c:func_8017F67C A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:57:00 src/ov_SC02_028/ov_SC02_028_jr_801884D8.c:func_8018AB34 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:00 src/ov_SC02_028/ov_SC02_028_jr_8017D898.c:func_80181264 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:00 src/ov_SC02_011/ov_SC02_011_jr_80188E3C.c:func_8018AB20 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:01 src/ov_SC02_026/ov_SC02_026_jr_8017C180.c:func_8017F6B0 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:01 src/ov_SC02_011/ov_SC02_011_jr_8017AE2C.c:func_8017D710 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:01 src/ov_SC02_011/ov_SC02_011_jr_80183178.c:func_80186868 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:01 src/ov_SC02_035/ov_SC02_035_jr_8017BEBC.c:func_80181B00 A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:57:01 src/ov_SC02_041/ov_SC02_041_jr_8017BEBC.c:func_8018317C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:01 src/ov_MAIN_012/ov_MAIN_012.c:func_8012956C A=DIFFERS B: removed 6 needed 4 compiles 12
|
||||
01:57:02 src/ov_SC02_039/ov_SC02_039_jr_8017BEBC.c:func_8017DE00 A=DIFFERS B: removed 6 needed 4 compiles 12
|
||||
01:57:02 src/ov_SC03_001/ov_SC03_001_jr_8017AE2C.c:func_80182058 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:02 src/ov_SC03_001/ov_SC03_001_jr_80189030.c:func_801898E4 A=DIFFERS B: removed 1 needed 5 compiles 8
|
||||
01:57:02 src/ov_SC03_001/ov_SC03_001_jr_8018B8DC.c:func_8018BCD4 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:03 src/ov_SC02_026/ov_SC02_026_jr_8017C180.c:func_8017E3AC A=DIFFERS B: removed 4 needed 1 compiles 7
|
||||
01:57:03 src/ov_SC03_002/ov_SC03_002_jr_8017D604.c:func_8017EA54 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:57:03 src/800_b_2.c:func_8003388C A=DIFFERS B: removed 2 needed 15 compiles 19
|
||||
01:57:03 src/ov_SC02_011/ov_SC02_011_jr_80183178.c:func_80187CE8 A=DIFFERS B: removed 4 needed 4 compiles 10
|
||||
01:57:03 src/ov_SC03_013/ov_SC03_013_jr_8017C730.c:func_8017DD98 A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:57:04 src/ov_SC02_011/ov_SC02_011_jr_80183178.c:func_80188250 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:04 src/ov_SC03_001/ov_SC03_001_jr_8017AE2C.c:func_8017BF50 A=DIFFERS B: removed 3 needed 1 compiles 6
|
||||
01:57:04 src/800_c.c:func_80038A58 A=DIFFERS B: removed 26 needed 9 compiles 37
|
||||
01:57:04 src/ov_SC03_011/ov_SC03_011_jr_80140608.c:func_80140958 A=DIFFERS B: removed 7 needed 4 compiles 13
|
||||
01:57:04 src/ov_SC03_024/ov_SC03_024_jr_80183BF8.c:func_80185E38 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:04 src/ov_SC03_028/ov_SC03_028_jr_8017DF98.c:func_80180AC4 A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:57:05 src/ov_SC03_024/ov_SC03_024_jr_8017DF84.c:func_80182108 A=DIFFERS B: removed 1 needed 3 compiles 6
|
||||
01:57:05 src/ov_SC03_028/ov_SC03_028_jr_801887A8.c:func_80189AF4 A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:57:05 src/800.c:func_800242D0 A=DIFFERS B: removed 6 needed 5 compiles 13
|
||||
01:57:05 src/800_c.c:func_800384A8 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:05 src/md_SC07_004/md_SC07_004.c:func_801AB694 A=DIFFERS B: removed 5 needed 1 compiles 8
|
||||
01:57:06 src/ov_SC03_006/ov_SC03_006_jr_8017AE2C.c:func_80185BD4 A=DIFFERS B: removed 3 needed 2 compiles 7
|
||||
01:57:06 src/ov_SC03_030/ov_SC03_030_jr_8017AE2C.c:func_80180960 A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:57:06 src/ov_SC03_105/ov_SC03_105_jr_8017C8D0.c:func_8017E180 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:06 src/ov_SC03_029/ov_SC03_029_jr_8017FF7C.c:func_80180B84 A=DIFFERS B: removed 4 needed 1 compiles 7
|
||||
01:57:06 src/ov_SC03_105/ov_SC03_105_jr_80186DDC.c:func_80187928 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:06 src/ov_SC03_097/ov_SC03_097_jr_8017D898.c:func_80181CF4 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:06 src/ov_SC03_092/ov_SC03_092_jr_80181694.c:func_8018478C A=DIFFERS B: removed 0 needed 8 compiles 10
|
||||
01:57:06 src/ov_SC03_108/ov_SC03_108_jr_8017F83C.c:func_8017FD64 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:07 src/ov_SC03_028/ov_SC03_028_jr_80185C14.c:func_80186368 A=DIFFERS B: removed 17 needed 3 compiles 22
|
||||
01:57:07 src/ov_SC03_105/ov_SC03_105_jr_80181C84.c:func_80183A98 A=DIFFERS B: removed 0 needed 5 compiles 6
|
||||
01:57:07 src/ov_SC03_121/ov_SC03_121_jr_8017E1D0.c:func_8017F374 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:07 src/ov_SC03_112/ov_SC03_112_jr_8017C294.c:func_8017D174 A=DIFFERS B: removed 1 needed 3 compiles 5
|
||||
01:57:07 src/ov_SC03_094/ov_SC03_094_jr_8017BEBC.c:func_80181448 A=DIFFERS B: removed 2 needed 4 compiles 8
|
||||
01:57:07 src/ov_SC04_015/ov_SC04_015_jr_8017AE2C.c:func_8017DBAC A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:08 src/md_SC07_004/md_SC07_004.c:func_801A395C A=DIFFERS B: removed 1 needed 2 compiles 5
|
||||
01:57:08 src/ov_SC04_018/ov_SC04_018_jr_80188E1C.c:func_80189EA0 A=DIFFERS B: removed 1 needed 1 compiles 3
|
||||
01:57:08 src/ov_SC04_018/ov_SC04_018_jr_801878E8.c:func_80188778 A=DIFFERS B: removed 2 needed 4 compiles 8
|
||||
01:57:08 src/ov_SC02_037/ov_SC02_037_jr_8017AE2C.c:func_8017F2B4 A=DIFFERS B: removed 6 needed 17 compiles 25
|
||||
01:57:08 src/ov_SC04_020/ov_SC04_020_jr_8017D604.c:func_8018087C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:08 src/ov_SC03_113/ov_SC03_113_jr_8017C294.c:func_8017F394 A=DIFFERS B: removed 5 needed 1 compiles 8
|
||||
01:57:08 src/md_SC07_004/md_SC07_004.c:func_801A7CDC A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:08 src/ov_SC03_107/ov_SC03_107_jr_801789AC.c:func_8017BEBC A=DIFFERS B: removed 0 needed 7 compiles 8
|
||||
01:57:09 src/ov_SC01_077/ov_SC01_077.c:func_8013D9B0 A=DIFFERS B: removed 9 needed 25 compiles 36
|
||||
01:57:09 src/ov_SC05_001/ov_SC05_001_jr_8017BEBC.c:func_80182258 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:09 src/ov_SC04_016/ov_SC04_016_jr_8017BEBC.c:func_8017DA50 A=DIFFERS B: removed 2 needed 8 compiles 12
|
||||
01:57:09 src/ov_SC05_003/ov_SC05_003_jr_8017BEBC.c:func_801815A0 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:09 src/ov_SC03_113/ov_SC03_113_jr_8017C294.c:func_8017E178 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:09 src/ov_SC05_005/ov_SC05_005_jr_8017D898.c:func_801816A8 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:09 src/ov_SC04_015/ov_SC04_015_jr_8017AE2C.c:func_8017BF70 A=DIFFERS B: removed 3 needed 1 compiles 6
|
||||
01:57:09 src/ov_SC05_010/ov_SC05_010_jr_80180F84.c:func_801814AC A=DIFFERS B: removed 1 needed 1 compiles 3
|
||||
01:57:09 src/ov_SC01_077/ov_SC01_077.c:func_801418F8 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:09 src/ov_SC05_008/ov_SC05_008_jr_8017AE2C.c:func_8017E6A4 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:09 src/ov_SC05_002/ov_SC05_002_jr_8017BEBC.c:func_8017F200 A=DIFFERS B: removed 5 needed 1 compiles 8
|
||||
01:57:09 src/ov_SC05_003/ov_SC05_003_jr_8017BEBC.c:func_801812AC A=DIFFERS B: removed 1 needed 1 compiles 3
|
||||
01:57:09 src/ov_SC03_124/ov_SC03_124_jr_80188544.c:func_80188C68 A=DIFFERS B: removed 5 needed 19 compiles 26
|
||||
01:57:10 src/ov_SC06_013/ov_SC06_013_jr_8017BEBC.c:func_8017DE14 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:10 src/ov_SC06_006/ov_SC06_006_jr_8017DB90.c:func_8017E550 A=DIFFERS B: removed 0 needed 3 compiles 4
|
||||
01:57:10 src/ov_SC06_016/ov_SC06_016_jr_801816DC.c:func_80181C78 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:10 src/ov_SC06_011/ov_SC06_011_jr_8017EEEC.c:func_8017F3C8 A=DIFFERS B: removed 4 needed 1 compiles 7
|
||||
01:57:10 src/ov_SC06_008/ov_SC06_008_jr_8017C294.c:func_8017D73C A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:10 src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c:func_8018A688 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:10 src/ov_SC04_011/ov_SC04_011_jr_8017D494.c:func_801835B0 A=DIFFERS B: removed 0 needed 3 compiles 4
|
||||
01:57:10 src/ov_SC06_011/ov_SC06_011_jr_8017BEBC.c:func_8017E5D0 A=DIFFERS B: removed 4 needed 3 compiles 9
|
||||
01:57:10 src/ov_SC05_010/ov_SC05_010_jr_80181CDC.c:func_80183D5C A=DIFFERS B: removed 9 needed 1 compiles 12
|
||||
01:57:10 src/ov_SC06_016/ov_SC06_016_jr_8017C8D0.c:func_801810A4 A=DIFFERS B: removed 2 needed 3 compiles 6
|
||||
01:57:11 src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c:func_80182464 A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:57:11 src/ov_SC06_024/ov_SC06_024_jr_80186F00.c:func_8018D674 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:11 src/ov_SC03_107/ov_SC03_107_jr_801789AC.c:func_8017CF48 A=DIFFERS B: removed 2 needed 4 compiles 8
|
||||
01:57:11 src/ov_SC06_029/ov_SC06_029_jr_801898CC.c:func_8018A180 A=COMPILE-ERROR B: removed 0 needed 6 compiles 7
|
||||
01:57:11 src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c:func_801811DC A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:12 src/ov_SC06_024/ov_SC06_024_jr_8017BEBC.c:func_8017FA1C A=DIFFERS B: removed 1 needed 3 compiles 6
|
||||
01:57:12 src/ov_SC06_030/ov_SC06_030_jr_8017F65C.c:func_80180FF4 A=DIFFERS B: removed 0 needed 10 compiles 12
|
||||
01:57:12 src/ov_SC06_033/ov_SC06_033_jr_8018D98C.c:func_8018D98C A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:12 src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c:func_80185DD8 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:12 src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c:func_8018A974 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:57:12 src/ov_SC06_032/ov_SC06_032_jr_801902EC.c:func_801902EC A=DIFFERS B: removed 4 needed 9 compiles 14
|
||||
01:57:12 src/ov_SC06_033/ov_SC06_033_jr_8018C2D8.c:func_8018C2D8 A=DIFFERS B: removed 4 needed 8 compiles 13
|
||||
01:57:12 src/ov_SC06_032/ov_SC06_032_jr_801919A0.c:func_801919A0 A=REFUSED B: removed 4 needed 10 compiles 14
|
||||
01:57:13 src/ov_SC07_000/ov_SC07_000_jr_8017F8B8.c:func_80181BA8 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:13 src/ov_SC07_007/ov_SC07_007_jr_8013C98C.c:func_8013D53C A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:13 src/ov_SC06_016/ov_SC06_016_jr_8017C8D0.c:func_801813B0 A=DIFFERS B: removed 0 needed 12 compiles 13
|
||||
01:57:13 src/ov_SC07_007/ov_SC07_007_jr_8017BEBC.c:func_8018044C A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:13 src/resident/resident.c:func_800CFE60 A=DIFFERS B: removed 1 needed 2 compiles 5
|
||||
01:57:13 src/ov_SC07_002/ov_SC07_002_jr_8017C8D0.c:func_80185FB0 A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:57:13 src/ov_SC07_010/ov_SC07_010_jr_8017AE2C.c:func_80180480 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:13 src/resident/resident_jr_800D00E4.c:func_800D0488 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:13 src/resident/resident_jr_800D128C.c:func_800D1984 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:14 src/ov_SC06_032/ov_SC06_032_jr_80182890.c:func_8018BA4C A=DIFFERS B: removed 3 needed 2 compiles 7
|
||||
01:57:14 src/ov_SC06_000/ov_SC06_000_jr_8017AE2C.c:func_801835B0 A=DIFFERS B: removed 0 needed 7 compiles 8
|
||||
01:57:14 src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c:func_8017DB20 A=DIFFERS B: removed 2 needed 1 compiles 5
|
||||
01:57:14 src/resident/resident_jr_800D00E4.c:func_800D0E30 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:57:14 src/resident/resident_jr_800D128C.c:func_800D128C A=DIFFERS B: removed 0 needed 3 compiles 4
|
||||
01:57:14 src/ov_SC07_007/ov_SC07_007_jr_8017BEBC.c:func_8018122C A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:57:14 src/resident/resident_jr_800D00E4.c:func_800D0214 A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:57:14 src/resident/resident_jr_800D128C.c:func_800D1658 A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:57:14 src/resident/resident_jr_800D00E4.c:func_800D02D0 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:14 src/ov_SC04_011/ov_SC04_011_jr_8017D494.c:func_8018E428 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:14 src/resident/resident_jr_800D00E4.c:func_800D0D7C A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:14 src/resident/resident_jr_800D128C.c:func_800D2D10 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:14 src/ov_SC07_010/ov_SC07_010_jr_80140608.c:func_80140958 A=DIFFERS B: removed 7 needed 4 compiles 13
|
||||
01:57:15 src/resident/resident_jr_800D128C.c:func_800D2650 A=DIFFERS B: removed 1 needed 4 compiles 7
|
||||
01:57:15 src/resident/resident_jr_800D128C.c:func_800D1B80 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:57:15 src/ov_SC07_006/ov_SC07_006_jr_8017BEBC.c:func_80182F3C A=DIFFERS B: removed 6 needed 6 compiles 13
|
||||
01:57:15 src/ov_SC07_006/ov_SC07_006_jr_80171B4C.c:func_80176734 A=DIFFERS B: removed 1 needed 11 compiles 14
|
||||
01:57:16 src/ov_SC04_011/ov_SC04_011_jr_8017D494.c:func_8018315C A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:57:29 src/800.c:func_800226C0 A=DIFFERS B: removed 31 needed 14 compiles 47
|
||||
01:57:30 src/800.c:func_80020DA4 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:34 src/800.c:func_8002AF70 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:57:37 src/800.c:func_800241C0 A=DIFFERS B: removed 3 needed 3 compiles 8
|
||||
01:57:38 src/800.c:func_80016A7C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:45 src/800.c:func_80023570 A=DIFFERS B: removed 9 needed 4 compiles 15
|
||||
01:57:47 src/800.c:func_8001A114 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:57:53 src/800.c:func_80016224 A=DIFFERS B: removed 3 needed 6 compiles 11
|
||||
01:57:54 src/800.c:func_80025A30 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:57:55 src/800.c:func_8001EA14 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:58:13 src/800.c:func_800215F4 A=DIFFERS B: removed 29 needed 7 compiles 38
|
||||
01:58:19 src/800.c:func_8002AC00 A=DIFFERS B: removed 4 needed 5 compiles 11
|
||||
01:58:25 src/800.c:func_8001BADC A=DIFFERS B: removed 5 needed 3 compiles 10
|
||||
01:58:26 src/800.c:func_800273F4 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:58:30 src/800.c:func_80015208 A=DIFFERS B: removed 3 needed 1 compiles 6
|
||||
01:58:35 src/800.c:func_8001BBBC A=DIFFERS B: removed 4 needed 4 compiles 10
|
||||
01:58:39 src/800.c:LoaderInitFileTable A=DIFFERS B: removed 0 needed 7 compiles 9
|
||||
01:58:40 src/shared/ov/func_8012A860.h:func_8012A860 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:58:41 src/shared/ov/func_8012C2D0.h:func_8012C2D0 A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:58:44 src/shared/ov/func_8012DBD0.h:func_8012DBD0 A=DIFFERS B: removed 8 needed 4 compiles 14
|
||||
01:58:46 src/shared/ov/func_80135004__0f8f8d0b.h:func_80135004 A=DIFFERS B: removed 4 needed 4 compiles 10
|
||||
01:58:48 src/shared/ov/func_80135168__bad0a585.h:func_80135168 A=DIFFERS B: removed 0 needed 5 compiles 7
|
||||
01:58:48 src/shared/ov/func_80135A4C__e0129286.h:func_80135A4C A=DIFFERS B: removed 0 needed 3 compiles 5
|
||||
01:58:49 src/shared/ov/func_80135EB0__c9438c12.h:func_80135EB0 A=DIFFERS B: removed 0 needed 6 compiles 8
|
||||
01:58:50 src/shared/ov/func_80136334__6e7f4730.h:func_80136334 A=DIFFERS B: removed 4 needed 4 compiles 10
|
||||
01:58:51 src/shared/ov/func_8013B274__28562738.h:func_8013B274 A=DIFFERS B: removed 4 needed 8 compiles 13
|
||||
01:58:51 src/shared/ov/func_8013D178__421ba659.h:func_8013D178 A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:58:52 src/shared/ov/func_80140608__2fb5c201.h:func_80140608 A=DIFFERS B: removed 1 needed 1 compiles 4
|
||||
01:58:53 src/shared/ov/func_801415C0.h:func_801415C0 A=DIFFERS B: removed 3 needed 2 compiles 7
|
||||
01:58:53 src/shared/ov/func_80141B90.h:func_80141B90 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:58:54 src/shared/ov/func_80145A2C__530ca2ff.h:func_80145A2C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:58:54 src/shared/ov/func_801497A8.h:func_801497A8 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:58:55 src/shared/ov/func_8014DD8C.h:func_8014DD8C A=DIFFERS B: removed 0 needed 2 compiles 3
|
||||
01:58:56 src/shared/ov/func_8014F74C.h:func_8014F74C A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
01:58:58 src/shared/ov/func_801536DC.h:func_801536DC A=DIFFERS B: removed 2 needed 1 compiles 5
|
||||
01:59:00 src/shared/ov/func_8015B6F4.h:func_8015B6F4 A=DIFFERS B: removed 1 needed 3 compiles 6
|
||||
01:59:02 src/shared/ov/func_801612B8.h:func_801612B8 A=DIFFERS B: removed 2 needed 1 compiles 5
|
||||
01:59:05 src/shared/ov/func_80162438__e113e304.h:func_80162438 A=DIFFERS B: removed 2 needed 3 compiles 7
|
||||
01:59:09 src/shared/ov/func_80166054.h:func_80166054 A=DIFFERS B: removed 5 needed 5 compiles 12
|
||||
01:59:11 src/shared/ov/func_80166F58__3728db8a.h:func_80166F58 A=DIFFERS B: removed 2 needed 2 compiles 6
|
||||
01:59:12 src/shared/ov/func_8016DF5C__a8a4aea4.h:func_8016DF5C A=DIFFERS B: removed 1 needed 2 compiles 5
|
||||
01:59:13 src/shared/ov/func_801759D8.h:func_801759D8 A=DIFFERS B: removed 1 needed 1 compiles 3
|
||||
01:59:16 src/shared/ov/func_80176734__261d72d2.h:func_80176734 A=DIFFERS B: removed 1 needed 11 compiles 14
|
||||
01:59:18 src/shared/ov/func_801778A8.h:func_801778A8 A=DIFFERS B: removed 3 needed 2 compiles 7
|
||||
01:59:23 src/shared/ov/func_80177B5C__879ede92.h:func_80177B5C A=DIFFERS B: removed 8 needed 15 compiles 25
|
||||
01:59:24 src/shared/ov/func_8017CF6C__4771362e.h:func_8017CF6C A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:59:24 src/shared/ov/func_8017D0BC__4f23330c.h:func_8017D0BC A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:59:24 src/shared/ov/func_8017E98C__94ae7b9b.h:func_8017E98C A=DIFFERS B: removed 0 needed 1 compiles 3
|
||||
01:59:25 src/shared/ov/func_80181538__27797037.h:func_80181538 A=DIFFERS B: removed 0 needed 2 compiles 4
|
||||
01:59:25 src/shared/ov/func_80188028.h:func_80188028 A=DIFFERS B: removed 0 needed 1 compiles 2
|
||||
# probe — 285 bodies sampled, 283 judged (seed 11, 2026-09-09 01:59, wall 151.4 s)
|
||||
|
||||
- rung A (strip-all) identical: **53 / 283** (register dropped) · 53 with `register` kept
|
||||
- lever-free after rung B: **53 / 283**
|
||||
- sites: 1309 usable · removed 561 (42.9 %) · needed 748
|
||||
- needed by kind: {'pin': 360, 'launder': 154, 'instruction': 21, 'barrier': 127, 'register': 8, 'keepalive': 36, 'cast': 26, 'decl-body': 16}
|
||||
- needed by detail (top): {'launder:': 123, 'barrier:': 82, 'pin:$2': 80, 'pin:$4': 50, 'pin:$3': 46, 'barrier:memory': 45, 'pin:$5': 37, 'keepalive:': 36, 'pin:$16': 27, 'launder:out-only': 20, 'cast:volatile s32 *': 18, 'pin:$17': 17, 'pin:$6': 15, 'instruction:addiu': 14, 'decl-body:': 14, 'pin:$0': 13, 'pin:$19': 13, 'pin:$8': 11, 'pin:$7': 10, 'pin:$9': 8, 'register:': 8, 'pin:$14': 5, 'pin:$21': 5, 'launder:LAUNDER_8018A180': 5, 'pin:$10': 4, 'pin:$12': 4, 'pin:$18': 4, 'cast:volatile s16 *': 4, 'instruction:addu': 4, 'pin:$20': 4}
|
||||
- removed by kind: {'instruction': 3, 'pin': 438, 'decl-body': 11, 'register': 4, 'launder': 45, 'barrier': 27, 'keepalive': 8, 'cast': 25}
|
||||
- refused (rewrite not applicable): {'instruction `sll` has no C spelling in the table': 1, 'instruction `addu` has no C spelling in the table': 1, 'instruction `li` has no C spelling in the table': 1, 'instruction `nop` has no C spelling in the table': 1, 'macro-carried instruction is residue': 2, 'no statement end for the macro use': 3}
|
||||
- compiles 1660 · mean 5.87 per body · 0.225 s per compile
|
||||
|
||||
| kind | bodies | A identical | A (register kept) | lever-free after B | sites | removed | needed | compiles | s/compile |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
||||
| main | 40 | 6 | 6 | 6 | 272 | 146 | 126 | 328 | 0.386 |
|
||||
| resident | 16 | 4 | 4 | 4 | 31 | 9 | 22 | 53 | 0.06 |
|
||||
| md | 29 | 2 | 2 | 2 | 121 | 56 | 65 | 161 | 0.139 |
|
||||
| shared | 40 | 7 | 7 | 7 | 164 | 65 | 99 | 216 | 0.211 |
|
||||
| ov | 158 | 34 | 34 | 34 | 721 | 285 | 436 | 902 | 0.195 |
|
||||
|
||||
| feature | bodies | lever-free |
|
||||
|---|---:|---:|
|
||||
| zero | 17 | 1 |
|
||||
| init | 32 | 7 |
|
||||
| instr | 10 | 1 |
|
||||
| cast | 22 | 1 |
|
||||
| register | 12 | 3 |
|
||||
| launder | 68 | 4 |
|
||||
| barrier | 78 | 9 |
|
||||
| keepalive | 27 | 1 |
|
||||
| volatile | 40 | 11 |
|
||||
|
||||
**Pricing (R41; population 16,064 lever bodies / 55,913 removable sites):** T4 ≈ 94,226 compiles ≈ 5.89 CPU-h ≈ 0.49 h wall at 12 workers; residue after the mechanical ladder ≈ 13,055 bodies / 31,950 sites (the sample's rates applied to the population).
|
||||
probe wall=160.86 s
|
||||
@@ -0,0 +1,188 @@
|
||||
{
|
||||
"generated": "2026-09-09 01:59",
|
||||
"seed": 11,
|
||||
"sampled": 285,
|
||||
"judged": 283,
|
||||
"not_judged": {
|
||||
"NOTHING-USABLE": 2
|
||||
},
|
||||
"rung_A_identical": 53,
|
||||
"rung_A_keep_register_identical": 53,
|
||||
"lever_free_after_B": 53,
|
||||
"sites": {
|
||||
"total": 1309,
|
||||
"removed": 561,
|
||||
"needed": 748,
|
||||
"pct_removed": 42.9
|
||||
},
|
||||
"needed_by_kind": {
|
||||
"pin": 360,
|
||||
"launder": 154,
|
||||
"instruction": 21,
|
||||
"barrier": 127,
|
||||
"register": 8,
|
||||
"keepalive": 36,
|
||||
"cast": 26,
|
||||
"decl-body": 16
|
||||
},
|
||||
"needed_by_detail": {
|
||||
"launder:": 123,
|
||||
"barrier:": 82,
|
||||
"pin:$2": 80,
|
||||
"pin:$4": 50,
|
||||
"pin:$3": 46,
|
||||
"barrier:memory": 45,
|
||||
"pin:$5": 37,
|
||||
"keepalive:": 36,
|
||||
"pin:$16": 27,
|
||||
"launder:out-only": 20,
|
||||
"cast:volatile s32 *": 18,
|
||||
"pin:$17": 17,
|
||||
"pin:$6": 15,
|
||||
"instruction:addiu": 14,
|
||||
"decl-body:": 14,
|
||||
"pin:$0": 13,
|
||||
"pin:$19": 13,
|
||||
"pin:$8": 11,
|
||||
"pin:$7": 10,
|
||||
"pin:$9": 8,
|
||||
"register:": 8,
|
||||
"pin:$14": 5,
|
||||
"pin:$21": 5,
|
||||
"launder:LAUNDER_8018A180": 5,
|
||||
"pin:$10": 4,
|
||||
"pin:$12": 4,
|
||||
"pin:$18": 4,
|
||||
"cast:volatile s16 *": 4,
|
||||
"instruction:addu": 4,
|
||||
"pin:$20": 4
|
||||
},
|
||||
"removed_by_kind": {
|
||||
"instruction": 3,
|
||||
"pin": 438,
|
||||
"decl-body": 11,
|
||||
"register": 4,
|
||||
"launder": 45,
|
||||
"barrier": 27,
|
||||
"keepalive": 8,
|
||||
"cast": 25
|
||||
},
|
||||
"refused": {
|
||||
"instruction `sll` has no C spelling in the table": 1,
|
||||
"instruction `addu` has no C spelling in the table": 1,
|
||||
"instruction `li` has no C spelling in the table": 1,
|
||||
"instruction `nop` has no C spelling in the table": 1,
|
||||
"macro-carried instruction is residue": 2,
|
||||
"no statement end for the macro use": 3
|
||||
},
|
||||
"by_kind": {
|
||||
"main": {
|
||||
"bodies": 40,
|
||||
"A_identical": 6,
|
||||
"A_keep_register_identical": 6,
|
||||
"lever_free": 6,
|
||||
"sites": 272,
|
||||
"removed": 146,
|
||||
"needed": 126,
|
||||
"compiles": 328,
|
||||
"mean_s_per_compile": 0.386
|
||||
},
|
||||
"resident": {
|
||||
"bodies": 16,
|
||||
"A_identical": 4,
|
||||
"A_keep_register_identical": 4,
|
||||
"lever_free": 4,
|
||||
"sites": 31,
|
||||
"removed": 9,
|
||||
"needed": 22,
|
||||
"compiles": 53,
|
||||
"mean_s_per_compile": 0.06
|
||||
},
|
||||
"md": {
|
||||
"bodies": 29,
|
||||
"A_identical": 2,
|
||||
"A_keep_register_identical": 2,
|
||||
"lever_free": 2,
|
||||
"sites": 121,
|
||||
"removed": 56,
|
||||
"needed": 65,
|
||||
"compiles": 161,
|
||||
"mean_s_per_compile": 0.139
|
||||
},
|
||||
"shared": {
|
||||
"bodies": 40,
|
||||
"A_identical": 7,
|
||||
"A_keep_register_identical": 7,
|
||||
"lever_free": 7,
|
||||
"sites": 164,
|
||||
"removed": 65,
|
||||
"needed": 99,
|
||||
"compiles": 216,
|
||||
"mean_s_per_compile": 0.211
|
||||
},
|
||||
"ov": {
|
||||
"bodies": 158,
|
||||
"A_identical": 34,
|
||||
"A_keep_register_identical": 34,
|
||||
"lever_free": 34,
|
||||
"sites": 721,
|
||||
"removed": 285,
|
||||
"needed": 436,
|
||||
"compiles": 902,
|
||||
"mean_s_per_compile": 0.195
|
||||
}
|
||||
},
|
||||
"flags": {
|
||||
"zero": {
|
||||
"bodies": 17,
|
||||
"lever_free": 1
|
||||
},
|
||||
"init": {
|
||||
"bodies": 32,
|
||||
"lever_free": 7
|
||||
},
|
||||
"instr": {
|
||||
"bodies": 10,
|
||||
"lever_free": 1
|
||||
},
|
||||
"cast": {
|
||||
"bodies": 22,
|
||||
"lever_free": 1
|
||||
},
|
||||
"register": {
|
||||
"bodies": 12,
|
||||
"lever_free": 3
|
||||
},
|
||||
"launder": {
|
||||
"bodies": 68,
|
||||
"lever_free": 4
|
||||
},
|
||||
"barrier": {
|
||||
"bodies": 78,
|
||||
"lever_free": 9
|
||||
},
|
||||
"keepalive": {
|
||||
"bodies": 27,
|
||||
"lever_free": 1
|
||||
},
|
||||
"volatile": {
|
||||
"bodies": 40,
|
||||
"lever_free": 11
|
||||
}
|
||||
},
|
||||
"compiles": 1660,
|
||||
"mean_compiles_per_body": 5.87,
|
||||
"mean_s_per_compile": 0.225,
|
||||
"wall_s": 151.4,
|
||||
"population": {
|
||||
"bodies": 16064,
|
||||
"sites": 55913
|
||||
},
|
||||
"pricing": {
|
||||
"T4_compiles_est": 94226,
|
||||
"T4_cpu_hours_est": 5.89,
|
||||
"T4_wall_hours_at_16_est": 0.49,
|
||||
"residue_bodies_est": 13055,
|
||||
"residue_sites_est": 31950
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
# probe — 285 bodies sampled, 283 judged (seed 11, 2026-09-09 01:59, wall 151.4 s)
|
||||
|
||||
- rung A (strip-all) identical: **53 / 283** (register dropped) · 53 with `register` kept
|
||||
- lever-free after rung B: **53 / 283**
|
||||
- sites: 1309 usable · removed 561 (42.9 %) · needed 748
|
||||
- needed by kind: {'pin': 360, 'launder': 154, 'instruction': 21, 'barrier': 127, 'register': 8, 'keepalive': 36, 'cast': 26, 'decl-body': 16}
|
||||
- needed by detail (top): {'launder:': 123, 'barrier:': 82, 'pin:$2': 80, 'pin:$4': 50, 'pin:$3': 46, 'barrier:memory': 45, 'pin:$5': 37, 'keepalive:': 36, 'pin:$16': 27, 'launder:out-only': 20, 'cast:volatile s32 *': 18, 'pin:$17': 17, 'pin:$6': 15, 'instruction:addiu': 14, 'decl-body:': 14, 'pin:$0': 13, 'pin:$19': 13, 'pin:$8': 11, 'pin:$7': 10, 'pin:$9': 8, 'register:': 8, 'pin:$14': 5, 'pin:$21': 5, 'launder:LAUNDER_8018A180': 5, 'pin:$10': 4, 'pin:$12': 4, 'pin:$18': 4, 'cast:volatile s16 *': 4, 'instruction:addu': 4, 'pin:$20': 4}
|
||||
- removed by kind: {'instruction': 3, 'pin': 438, 'decl-body': 11, 'register': 4, 'launder': 45, 'barrier': 27, 'keepalive': 8, 'cast': 25}
|
||||
- refused (rewrite not applicable): {'instruction `sll` has no C spelling in the table': 1, 'instruction `addu` has no C spelling in the table': 1, 'instruction `li` has no C spelling in the table': 1, 'instruction `nop` has no C spelling in the table': 1, 'macro-carried instruction is residue': 2, 'no statement end for the macro use': 3}
|
||||
- compiles 1660 · mean 5.87 per body · 0.225 s per compile
|
||||
|
||||
| kind | bodies | A identical | A (register kept) | lever-free after B | sites | removed | needed | compiles | s/compile |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
||||
| main | 40 | 6 | 6 | 6 | 272 | 146 | 126 | 328 | 0.386 |
|
||||
| resident | 16 | 4 | 4 | 4 | 31 | 9 | 22 | 53 | 0.06 |
|
||||
| md | 29 | 2 | 2 | 2 | 121 | 56 | 65 | 161 | 0.139 |
|
||||
| shared | 40 | 7 | 7 | 7 | 164 | 65 | 99 | 216 | 0.211 |
|
||||
| ov | 158 | 34 | 34 | 34 | 721 | 285 | 436 | 902 | 0.195 |
|
||||
|
||||
| feature | bodies | lever-free |
|
||||
|---|---:|---:|
|
||||
| zero | 17 | 1 |
|
||||
| init | 32 | 7 |
|
||||
| instr | 10 | 1 |
|
||||
| cast | 22 | 1 |
|
||||
| register | 12 | 3 |
|
||||
| launder | 68 | 4 |
|
||||
| barrier | 78 | 9 |
|
||||
| keepalive | 27 | 1 |
|
||||
| volatile | 40 | 11 |
|
||||
|
||||
**Pricing (R41; population 16,064 lever bodies / 55,913 removable sites):** T4 ≈ 94,226 compiles ≈ 5.89 CPU-h ≈ 0.49 h wall at 12 workers; residue after the mechanical ladder ≈ 13,055 bodies / 31,950 sites (the sample's rates applied to the population).
|
||||
@@ -69,6 +69,8 @@ tools/decompme_replica.sh P4 ADAPT reproduce an external reference toolchain loc
|
||||
tools/dedup_extend.py P6 ADAPT extend an existing code-share registry to newly onboarded binaries Extends the existing share registry to newly onboarded binaries repo config/src layout SUPERSEDED tools/share_body.py
|
||||
tools/dedup_integrate.py P6 ADAPT validate a code-share registry byte-honestly, failing closed on signature drift Byte-honesty validator for the code-share registry; fails closed on signature drift repo config registry path LIVE
|
||||
tools/dedup_propagate.py P6 ADAPT lift one matched body into a shared macro and instantiate it everywhere Lifts one matched body into a shared macro and instantiates it at every duplicate site repo shared-header/src layout SUPERSEDED tools/share_body.py
|
||||
tools/delever.py P10 ADAPT take register pins, asm statements, volatile and register levers out of matched C, byte-gated per site The Phase-36 de-lever engine: positional rewrites per lever class (pin -> plain declaration, barrier/launder/keep-alive deleted, a hand-placed instruction -> its C, the zero-register variable -> 0, volatile/register dropped), rung A strip-all and rung B greedy per body through delever_oracle, headers serialized after the TU phase; --probe runs a stratified sample of distinct bodies and prices the campaign with denominators the census site records, the oracle LIVE
|
||||
tools/delever_oracle.py P10 ADAPT judge one translation-unit edit by the bytes of its object in under a second The Phase-36 fast byte oracle: every object's exact build command captured once via make -n -W (the Makefile's own recipe, pad stage and -O0 overrides included), a candidate compiled in place with -o/-MF redirected to scratch and compared with the fleet run's object; --calibrate proves 100 % equality untouched, twin == primary and a positive control before any verdict is trusted the Makefile's object rules, the twin rule LIVE
|
||||
tools/demacroize.py P6 ADAPT escape a shared-header declaration conflict locally by unmacroizing one body Per-binary local escape from a shared-header declaration conflict by unmacroizing one body repo shared-header layout FROZEN tools/share_body.py
|
||||
tools/diff_autopsy.sh P7 ADAPT find which words diverge when the whole-binary gate says different but not where Reproduces exactly what the gate saw, then decodes the diverging words and restores the tree repo src/build paths STILL-NEEDED find WHICH words diverge when the whole-binary gate says DIFF but not where
|
||||
tools/diff_regions.py P7 ADAPT classify where a remapped sibling's compiled bytes diverge from its target Classifies where a remapped member's compiled bytes diverge from its target repo build paths STILL-NEEDED classify where a mechanically remapped sibling's compiled bytes diverge from its target
|
||||
|
||||
|
@@ -1,7 +1,9 @@
|
||||
# Gen3 handoff — where Gen2 ends, what comes next, and the levers already in hand
|
||||
|
||||
> **Written at the Gen2 exit (Phase 33, 2026-09-07).** Gen2's contract is met and published: 218 binaries rebuild
|
||||
> byte-identical from C ([`docs/verification.md`](verification.md)), every game-code function in every binary is C, the
|
||||
> byte-identical from C ([`docs/verification.md`](verification.md)), every game-code function in every binary is C (*corrected
|
||||
> 2026-09-09, Phase 36 T1b: fourteen were whole-body assembly inside C shells, invisible to the file-scope detector — listed
|
||||
> DECOMPILE-NOW / UNCERTAIN in the manifest*), the
|
||||
> repository is public with its full rewritten history. This page is the seed for Gen3's first plan — it names the
|
||||
> owner's stated next intent, gives the starter census derived from the tree (with the commands, so the next session
|
||||
> re-derives rather than trusts), states the one invariant that must survive every Gen3 edit, and inventories the
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
> its platform SDK need the marked adaptation. The last table lists the tools that are project-only in code (their *shape* is a task;
|
||||
> their code does not transfer). *TODO(platform): the MIPS and PlayStation SDK hard-codes are the ones another platform replaces first.*
|
||||
>
|
||||
> **Coverage:** 296 tool files in scope (submodules, vendored and downloaded code excluded), of which 296 live rows
|
||||
> below; per phase: P1 2 · P2 26 · P3 17 · P4 9 · P5 26 · P6 51 · P7 20 · P8 86 · P9 27 · P10 16 · PROJECT-ONLY 16. Superseded tools appear only as pointers to their successor (30 pointer rows); one-offs are omitted. Table rows in all: 326 (the installer checks its copy against this figure).
|
||||
> **Coverage:** 298 tool files in scope (submodules, vendored and downloaded code excluded), of which 298 live rows
|
||||
> below; per phase: P1 2 · P2 26 · P3 17 · P4 9 · P5 26 · P6 51 · P7 20 · P8 86 · P9 27 · P10 18 · PROJECT-ONLY 16. Superseded tools appear only as pointers to their successor (30 pointer rows); one-offs are omitted. Table rows in all: 328 (the installer checks its copy against this figure).
|
||||
|
||||
## P1 — extraction + manifest
|
||||
|
||||
@@ -333,12 +333,14 @@
|
||||
| `lint_symbol_refs.py` | flag address-named references whose address now has a curated name | Flags address-named references in committed sources whose address now has a curated name | repo symbol/src paths |
|
||||
| `uniquify_type.py` | give each conflicting camp of a same-named type its own name | Gives each conflicting camp of a same-named type its own name so every camp becomes liftable | repo src layout |
|
||||
| `verbatim_check.py` | guard that every inline-assembly body still reproduces its target bytes | Regression guard that every inline-assembly body still reproduces its target bytes | repo src layout |
|
||||
| `delever_oracle.py` | judge one translation-unit edit by the bytes of its object in under a second | The Phase-36 fast byte oracle: every object's exact build command captured once via make -n -W (the Makefile's own recipe, pad stage and -O0 overrides included), a candidate compiled in place with -o/-MF redirected to scratch and compared with the fleet run's object; --calibrate proves 100 % equality untouched, twin == primary and a positive control before any verdict is trusted | the Makefile's object rules, the twin rule |
|
||||
| `share_census.py` | measure duplicate function bodies across the fleet and assert one source per unique function | The census of byte-identical function classes across every binary with their source forms and verdicts, plus the S1 invariant check with its exception ledger and a fixture self-test | repo paths, the registry and signature schemas |
|
||||
| `ghidra_apply_symbols.sh` | mirror the curated symbol file into the analysis database with a real save | Mirrors the curated symbol file into the analysis program headlessly, with a real save | repo symbol path, project name |
|
||||
| `frozen.py` | refuse, from one place, the command line of a tool the project has frozen | The one refusal a FROZEN tool prints from its main(): the tool, the successor and why; imports never exit (libraries stay usable) | nothing |
|
||||
| `verbatim_target_s.py` | regenerate a splitter-format target disassembly for a function no longer stubbed | Regenerates a splitter-format target disassembly for a function that is no longer a stub; --gas emits the assemblable gas-syntax form ($-registers, .L labels, noreorder) that a web diff service accepts as a pasted target | repo build/asm layout |
|
||||
| `share_body_cycle.sh` | run the share-body batch cycle unattended: batch, verify by exit code, log, commit, periodic clean fleet check | The Phase-35 T5 driver for bucket new: per batch share_body --apply --bucket new --batches 1 --label new<k>, the gated N/N line read, the phase log entry appended, the bank committed the moment it is green, the clean fleet run every N batches — stops on the first red | repo paths, the phase-log format, the fleet count from config/check.*.sha |
|
||||
| `share_body.py` | share one byte-identical function class across its binaries through an include-at-site header, gated per binary | The Phase-35 successor of dedup_propagate + dedup_extend for the include-at-site form: exemplar by majority text, the header written once, every private copy replaced by the include at its position, per-binary byte gate with object comparison, bisect on red, the registry appended or extended by text, the exception ledger on refusal; --plan / --apply --bucket extend|new | repo paths, the registry and signature schemas |
|
||||
| `delever.py` | take register pins, asm statements, volatile and register levers out of matched C, byte-gated per site | The Phase-36 de-lever engine: positional rewrites per lever class (pin -> plain declaration, barrier/launder/keep-alive deleted, a hand-placed instruction -> its C, the zero-register variable -> 0, volatile/register dropped), rung A strip-all and rung B greedy per body through delever_oracle, headers serialized after the TU phase; --probe runs a stratified sample of distinct bodies and prices the campaign with denominators | the census site records, the oracle |
|
||||
| `verbatim_to_stub.py` | turn an inline-assembly body back into a stub the toolchain can reach | Turns an inline-assembly body back into an include-assembly stub | repo src/asm layout |
|
||||
|
||||
## PROJECT-ONLY — project-only in code (the shape is a task; the code does not transfer)
|
||||
|
||||
@@ -0,0 +1,608 @@
|
||||
#!/usr/bin/env python3
|
||||
"""delever.py — take the compiler-forcing constructs ("levers") out of matched C, byte-gated per translation unit
|
||||
(Phase 36; the probe engine at T2, the campaign tool at T3).
|
||||
|
||||
tools/delever.py --probe --sample 150 [--seed 1] [-j 12] # T2: rung A + rung B on a stratified sample of DISTINCT bodies
|
||||
# -> .run/P36/probe/{probe_results.jsonl,probe_summary.json,probe_table.md}
|
||||
|
||||
THE LADDER PER BODY (deterministic, zero tokens):
|
||||
rung A strip-all — every removable site of the body rewritten at once (pin -> plain declaration; barrier/launder/keep-alive ->
|
||||
deleted; a hand-placed instruction -> its C; `$0` pin -> its variable's uses replaced by 0; volatile -> dropped; register ->
|
||||
dropped), one compile, the object compared with the fleet run's (tools/delever_oracle.py). Measured twice: with the `register`
|
||||
keyword dropped from the pin (the target form) and with it kept (A').
|
||||
rung B greedy — if A differs: from the untouched text, the sites are re-applied one at a time (asm statements first, then pins,
|
||||
volatile, register); a site whose removal keeps the object identical is REMOVED, one that changes it is NEEDED.
|
||||
The verdict of a body = the set of NEEDED sites; a body with none is lever-free. Never touched: GTE ops, the manifest's verbatim
|
||||
bodies, an asm-body (a whole routine — the manifest's DECOMPILE rows are another task's work), file-scope declarations.
|
||||
|
||||
EVERY EDIT IS POSITIONAL on the raw text (line/col from the census), the file is written in place for the compile and restored
|
||||
from the in-memory snapshot right after (never `git checkout`, R102); a site whose raw token does not match the census is REFUSED
|
||||
(R43), never guessed.
|
||||
"""
|
||||
import argparse
|
||||
import collections
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import random
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
REPO = pathlib.Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "tools"))
|
||||
import delever_oracle as oracle # noqa: E402
|
||||
import lever_census as lc # noqa: E402
|
||||
import share_census as sc # noqa: E402
|
||||
|
||||
SITES = REPO / ".run" / "P36" / "census" / "lever_sites.jsonl"
|
||||
PROBE = REPO / ".run" / "P36" / "probe"
|
||||
REMOVABLE = {("A", "pin"), ("B", "barrier"), ("B", "launder"), ("B", "keepalive"), ("B", "instruction"),
|
||||
("C", "cast"), ("C", "decl-body"), ("D", "register")}
|
||||
ORDER = {"barrier": 0, "launder": 1, "keepalive": 2, "instruction": 3, "pin": 4, "cast": 5, "decl-body": 6, "register": 7}
|
||||
STRLIT = lc.STRLIT
|
||||
|
||||
|
||||
class Refuse(Exception):
|
||||
pass
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# text helpers (positions on the RAW text; comments masked to equal-length spaces so a ';' in a comment never ends a statement)
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def same_len_mask(raw):
|
||||
return sc._TOK.sub(lambda m: re.sub(r"[^\n]", " ", m.group(0)) if m.group(0)[:2] in ("/*", "//") else m.group(0), raw)
|
||||
|
||||
|
||||
def line_starts(text):
|
||||
ls = [0]
|
||||
for ln in text.split("\n"):
|
||||
ls.append(ls[-1] + len(ln) + 1)
|
||||
return ls
|
||||
|
||||
|
||||
def stmt_end(m, pos):
|
||||
"""index just past the ';' that ends the statement starting at pos (paren depth 0, string literals skipped); -1 if none."""
|
||||
depth, i, n = 0, pos, len(m)
|
||||
while i < n:
|
||||
c = m[i]
|
||||
if c == '"':
|
||||
mm = STRLIT.match(m, i)
|
||||
i = mm.end() if mm else i + 1
|
||||
continue
|
||||
if c == "(":
|
||||
depth += 1
|
||||
elif c == ")":
|
||||
depth -= 1
|
||||
elif c == ";" and depth <= 0:
|
||||
return i + 1
|
||||
elif c == "}" and depth == 0:
|
||||
return -1
|
||||
i += 1
|
||||
return -1
|
||||
|
||||
|
||||
def ws_after(m, pos):
|
||||
i = pos
|
||||
while i < len(m) and m[i] in " \t":
|
||||
i += 1
|
||||
return i
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# the rewrite of one site -> [(start, end, replacement)] on the raw text
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
ASM_HEAD = re.compile(r"(?:__asm__|__asm|asm)\s*(?:__volatile__|volatile)?\s*\(")
|
||||
PIN_CLAUSE = re.compile(r"\s*(?:__asm__|__asm|asm)\s*\(\s*\"[^\"]*\"\s*\)")
|
||||
INSTR_TABLE = {
|
||||
# mnemonic -> (arity, C template) using OUT / IN1 / IN2 / IMM; the operands come from the asm's "=r"(..) / "r"(..) lists
|
||||
"addu": ("OUT = IN1;", "zero"), "move": ("OUT = IN1;", None), "addiu": ("OUT = IN1 + IMM;", None), "sll": ("OUT = IN1 << IMM;", None),
|
||||
"srl": ("OUT = (u32)IN1 >> IMM;", None), "and": ("OUT = IN1 & IN2;", None), "andi": ("OUT = IN1 & IMM;", None),
|
||||
"lui": ("OUT = IMM << 16;", None), "li": ("OUT = IMM;", None), "lw": ("OUT = *(s32 *)((s32)IN1 + IMM);", None),
|
||||
"lh": ("OUT = *(s16 *)((s32)IN1 + IMM);", None), "la": ("OUT = (s32)&SYM;", None),
|
||||
}
|
||||
|
||||
|
||||
def parse_asm_operands(inner):
|
||||
"""(template, outputs, inputs) — outputs/inputs as [(constraint, expr)]; the asm's own parser rules (lever_census)."""
|
||||
s = inner.strip()
|
||||
parts, i, n = [], 0, len(s)
|
||||
while i < n:
|
||||
if s[i] in " \t\r\n":
|
||||
i += 1
|
||||
continue
|
||||
mm = STRLIT.match(s, i)
|
||||
if not mm:
|
||||
break
|
||||
parts.append(mm.group(0)[1:-1])
|
||||
i = mm.end()
|
||||
rest = s[i:].strip()
|
||||
secs = lc._split_sections(rest[1:]) if rest.startswith(":") else []
|
||||
def ops(sec):
|
||||
out = []
|
||||
for mm in re.finditer(r'"([^"]*)"\s*\(', sec):
|
||||
c = lc._paren_span(sec, mm.end() - 1)
|
||||
out.append((mm.group(1), sec[mm.end():c].strip()))
|
||||
return out
|
||||
outs = ops(secs[0]) if len(secs) > 0 else []
|
||||
ins = ops(secs[1]) if len(secs) > 1 else []
|
||||
return "".join(parts), outs, ins
|
||||
|
||||
|
||||
def instruction_to_c(inner, indent):
|
||||
"""The C statement for a hand-placed single-instruction asm, or None (residue)."""
|
||||
tmpl, outs, ins = parse_asm_operands(inner)
|
||||
t = re.sub(r"\\[nt]", " ", tmpl).strip()
|
||||
if len(outs) != 1:
|
||||
return None
|
||||
out_expr = outs[0][1]
|
||||
allops = [e for _, e in outs] + [e for _, e in ins]
|
||||
def resolve(tok):
|
||||
mm = re.fullmatch(r"%(\d+)", tok)
|
||||
if mm:
|
||||
k = int(mm.group(1))
|
||||
return allops[k] if k < len(allops) else None
|
||||
return None
|
||||
IMM = r"-?(?:0x[0-9A-Fa-f]+|\d+)"
|
||||
# two-instruction address / constant materializations (one C expression each)
|
||||
mm = re.fullmatch(r"lui\s+%0\s*,\s*%%hi\((\w+)\)\s*;?\s*addiu\s+%0\s*,\s*%0\s*,\s*%%lo\(\1\)", t)
|
||||
if mm:
|
||||
return f"{indent}{out_expr} = (s32)&{mm.group(1)};"
|
||||
mm = re.fullmatch(r"lui\s+%0\s*,\s*(" + IMM + r")\s*;?\s*ori\s+%0\s*,\s*%0\s*,\s*(" + IMM + r")", t)
|
||||
if mm:
|
||||
return f"{indent}{out_expr} = ({mm.group(1)} << 16) | {mm.group(2)};"
|
||||
if ";" in t or "\n" in t:
|
||||
return None # other multi-instruction templates are residue
|
||||
toks = [x for x in re.split(r"[\s,]+", t) if x]
|
||||
if not toks:
|
||||
return None
|
||||
mnem = toks[0].lower()
|
||||
if mnem not in INSTR_TABLE:
|
||||
return None
|
||||
templ, note = INSTR_TABLE[mnem]
|
||||
refs = [x for x in toks[1:]]
|
||||
if mnem == "addu":
|
||||
if len(refs) != 3:
|
||||
return None
|
||||
if refs[2] in ("$zero", "$0"):
|
||||
in1 = resolve(refs[1])
|
||||
return None if in1 is None else f"{indent}{out_expr} = {in1};"
|
||||
in1, in2 = resolve(refs[1]), resolve(refs[2])
|
||||
return None if in1 is None or in2 is None else f"{indent}{out_expr} = (s32){in1} + (s32){in2};"
|
||||
if mnem == "addiu" and len(refs) == 3 and refs[1] in ("$zero", "$0") and re.fullmatch(IMM, refs[2]):
|
||||
return f"{indent}{out_expr} = {refs[2]};"
|
||||
if mnem == "move":
|
||||
if len(refs) != 2:
|
||||
return None
|
||||
in1 = resolve(refs[1])
|
||||
return None if in1 is None else f"{indent}{out_expr} = {in1};"
|
||||
if mnem == "la":
|
||||
if len(refs) != 2 or not re.fullmatch(r"[A-Za-z_]\w*", refs[1]):
|
||||
return None
|
||||
return f"{indent}{out_expr} = (s32)&{refs[1]};"
|
||||
if mnem in ("lw", "lh"):
|
||||
mm = re.fullmatch(r"(-?\w+)\((%\d+)\)", refs[1]) if len(refs) == 2 else None
|
||||
if not mm:
|
||||
return None
|
||||
base = resolve(mm.group(2))
|
||||
return None if base is None else templ.replace("OUT", out_expr).replace("IN1", base).replace("IMM", mm.group(1)) and f"{indent}{templ.replace('OUT', out_expr).replace('IN1', base).replace('IMM', mm.group(1))}"
|
||||
if mnem in ("addiu", "sll", "srl", "andi"):
|
||||
if len(refs) != 3:
|
||||
return None
|
||||
in1 = resolve(refs[1])
|
||||
if in1 is None or not re.fullmatch(IMM, refs[2]):
|
||||
return None
|
||||
return f"{indent}{templ.replace('OUT', out_expr).replace('IN1', '(s32)' + in1).replace('IMM', refs[2])}"
|
||||
if mnem == "and":
|
||||
if len(refs) != 3:
|
||||
return None
|
||||
in1, in2 = resolve(refs[1]), resolve(refs[2])
|
||||
return None if in1 is None or in2 is None else f"{indent}{out_expr} = (s32){in1} & (s32){in2};"
|
||||
if mnem in ("lui", "li"):
|
||||
if len(refs) != 2 or not re.fullmatch(r"-?(?:0x[0-9A-Fa-f]+|\d+)", refs[1]):
|
||||
return None
|
||||
return f"{indent}{templ.replace('OUT', out_expr).replace('IMM', refs[1])}"
|
||||
return None
|
||||
|
||||
|
||||
def site_edits(raw, m, ls, site, keep_register=False):
|
||||
"""[(start, end, replacement)] for one site, or raise Refuse. `m` = same_len_mask(raw)."""
|
||||
pos = ls[site["line"] - 1] + site["col"] - 1
|
||||
cls, kind = site["cls"], site["kind"]
|
||||
indent_start = m.rfind("\n", 0, pos) + 1
|
||||
indent = re.match(r"[ \t]*", raw[indent_start:pos]).group(0)
|
||||
if cls == "A":
|
||||
if not m.startswith("register", pos):
|
||||
raise Refuse(f"token mismatch at {site['tu']}:{site['line']}: expected `register`")
|
||||
e = stmt_end(m, pos)
|
||||
if e < 0:
|
||||
raise Refuse(f"no statement end for the pin at {site['tu']}:{site['line']}")
|
||||
stmt = raw[pos:e]
|
||||
if site.get("zero"):
|
||||
# the zero-register variable: delete the declaration, replace every use in the body by 0
|
||||
mm = re.search(r"([A-Za-z_]\w*)\s*(?:__asm__|__asm|asm)\s*\(", stmt)
|
||||
if not mm:
|
||||
raise Refuse("zero pin without a name")
|
||||
name = mm.group(1)
|
||||
edits = [(indent_start if raw[indent_start:pos].strip() == "" else pos, e + (1 if raw[e:e + 1] == "\n" and raw[indent_start:pos].strip() == "" else 0), "")]
|
||||
b0, b1 = ls[site["fn_line"] - 1], ls[site["fn_end"]] - 1
|
||||
for um in re.finditer(r"\b%s\b" % re.escape(name), m[b0:b1]):
|
||||
s = b0 + um.start()
|
||||
if s < pos or s >= e:
|
||||
edits.append((s, s + len(name), "0"))
|
||||
return edits
|
||||
new = stmt if keep_register else re.sub(r"\bregister\b[ \t]*", "", stmt, count=1)
|
||||
new = PIN_CLAUSE.sub("", new)
|
||||
return [(pos, e, new)]
|
||||
if cls == "B" and site.get("via"):
|
||||
name = site["via"]
|
||||
if not m.startswith(name, pos):
|
||||
raise Refuse(f"token mismatch at {site['tu']}:{site['line']}: expected `{name}(`")
|
||||
if kind not in ("barrier", "launder", "keepalive"):
|
||||
raise Refuse(f"macro-carried {kind} is residue")
|
||||
e = stmt_end(m, pos)
|
||||
if e < 0:
|
||||
raise Refuse("no statement end for the macro use")
|
||||
whole_line = raw[indent_start:pos].strip() == "" and raw[e:ws_after(m, e)].strip() == "" and raw[ws_after(m, e):ws_after(m, e) + 1] == "\n"
|
||||
return [(indent_start, ws_after(m, e) + 1, "")] if whole_line else [(pos, e, "")]
|
||||
if cls == "B":
|
||||
if not ASM_HEAD.match(m, pos):
|
||||
raise Refuse(f"token mismatch at {site['tu']}:{site['line']}: expected an asm statement")
|
||||
o = m.find("(", pos)
|
||||
c = lc._paren_span(m, o)
|
||||
e = stmt_end(m, pos)
|
||||
if c < 0 or e < 0:
|
||||
raise Refuse("unterminated asm statement")
|
||||
if kind in ("barrier", "launder", "keepalive"):
|
||||
new = ""
|
||||
elif kind == "instruction":
|
||||
new = instruction_to_c(m[o + 1:c] if '"' in m[o + 1:c] else raw[o + 1:c], "")
|
||||
if new is None:
|
||||
raise Refuse(f"instruction `{site['detail']}` has no C spelling in the table")
|
||||
new = new.strip()
|
||||
else:
|
||||
raise Refuse(f"asm kind {kind} is not removable")
|
||||
whole_line = raw[indent_start:pos].strip() == "" and raw[e:ws_after(m, e)].strip() == "" and raw[ws_after(m, e):ws_after(m, e) + 1] == "\n"
|
||||
if new == "" and whole_line:
|
||||
return [(indent_start, ws_after(m, e) + 1, "")]
|
||||
return [(pos, e, new)]
|
||||
if cls == "C":
|
||||
if not m.startswith("volatile", pos):
|
||||
raise Refuse(f"token mismatch at {site['tu']}:{site['line']}: expected `volatile`")
|
||||
return [(pos, ws_after(m, pos + len("volatile")), "")]
|
||||
if cls == "D":
|
||||
if not m.startswith("register", pos):
|
||||
raise Refuse(f"token mismatch at {site['tu']}:{site['line']}: expected `register`")
|
||||
return [(pos, ws_after(m, pos + len("register")), "")]
|
||||
raise Refuse(f"class {cls}/{kind} is not removable")
|
||||
|
||||
|
||||
def apply_edits(raw, edits):
|
||||
"""Splice non-overlapping edits (bottom-up). Overlap -> Refuse."""
|
||||
es = sorted(edits, key=lambda x: (x[0], x[1]))
|
||||
for a, b in zip(es, es[1:]):
|
||||
if b[0] < a[1]:
|
||||
raise Refuse(f"overlapping edits at {a[0]}..{a[1]} / {b[0]}..{b[1]}")
|
||||
out = raw
|
||||
for s, e, r in sorted(es, key=lambda x: -x[0]):
|
||||
out = out[:s] + r + out[e:]
|
||||
return out
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# the population
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def load_sites():
|
||||
return [json.loads(l) for l in SITES.read_text().splitlines() if l.strip()]
|
||||
|
||||
|
||||
def bodies_from_sites(sites):
|
||||
bodies = {}
|
||||
for s in sites:
|
||||
if not s.get("fn"):
|
||||
continue
|
||||
b = bodies.setdefault((s["tu"], s["fn"]), dict(tu=s["tu"], fn=s["fn"], fn_line=s["fn_line"], fn_end=s["fn_end"], nhash=s.get("nhash"),
|
||||
aliases=s["aliases"], header=s.get("header", False), sites=[], frozen=[]))
|
||||
if (s["cls"], s["kind"]) in REMOVABLE:
|
||||
b["sites"].append(s)
|
||||
else:
|
||||
b["frozen"].append(s)
|
||||
return bodies
|
||||
|
||||
|
||||
def kind_of(tu):
|
||||
return "shared" if tu.startswith("src/shared/") else "ov" if tu.startswith("src/ov_") else "md" if tu.startswith("src/md_") \
|
||||
else "resident" if tu.startswith("src/resident/") else "main"
|
||||
|
||||
|
||||
def includers():
|
||||
"""header rel -> [TU rel] from the #include lines of every TU (the recipe to compile a header's body is an includer's)."""
|
||||
inc = collections.defaultdict(list)
|
||||
for p in sorted((REPO / "src").rglob("*.c")):
|
||||
rel = p.relative_to(REPO).as_posix()
|
||||
text = p.read_text(errors="surrogateescape")
|
||||
for mm in sc.INCLUDE_LINE.finditer(sc.mask_text(text)):
|
||||
inc[os.path.normpath(os.path.join(os.path.dirname(rel), mm.group(1)))].append(rel)
|
||||
return inc
|
||||
|
||||
|
||||
def features(b):
|
||||
ks = collections.Counter(s["kind"] for s in b["sites"])
|
||||
n = len(b["sites"])
|
||||
mix = "pins-only" if set(ks) <= {"pin"} else "asm-only" if not (set(ks) & {"pin", "cast", "decl-body", "register"}) else "mixed"
|
||||
return dict(kind=kind_of(b["tu"]), n=n, bucket=("1" if n == 1 else "2-4" if n <= 4 else "5-9" if n <= 9 else "10+"), mix=mix,
|
||||
zero=any(s.get("zero") for s in b["sites"]), init=any(s.get("init") for s in b["sites"] if s["kind"] == "pin"),
|
||||
instr=any(s["kind"] == "instruction" for s in b["sites"]), cast=any(s["kind"] == "cast" for s in b["sites"]),
|
||||
register=any(s["kind"] == "register" for s in b["sites"]), volatile=any(s["cls"] == "C" for s in b["sites"]),
|
||||
launder=any(s["kind"] == "launder" for s in b["sites"]), barrier=any(s["kind"] == "barrier" for s in b["sites"]),
|
||||
keepalive=any(s["kind"] == "keepalive" for s in b["sites"]))
|
||||
|
||||
|
||||
def stratified_sample(bodies, n, seed):
|
||||
rnd = random.Random(seed)
|
||||
# one exemplar per normalized class
|
||||
by_class = {}
|
||||
for key, b in bodies.items():
|
||||
if not b["sites"]:
|
||||
continue
|
||||
h = b["nhash"] or key
|
||||
cur = by_class.get(h)
|
||||
pref = {"main": 0, "resident": 1, "md": 2, "shared": 3, "ov": 4}[kind_of(b["tu"])]
|
||||
if cur is None or pref < cur[0]:
|
||||
by_class[h] = (pref, key)
|
||||
pool = [bodies[k] for _, k in by_class.values()]
|
||||
rnd.shuffle(pool)
|
||||
# quotas scale with --sample (the shape of the population: main/resident/md are few but distinct, overlays are many)
|
||||
base = {"main": 20, "resident": 16, "md": 15, "shared": 20, "ov": 79}
|
||||
scale = n / sum(base.values())
|
||||
quota = {k: max(3, int(round(v * scale))) for k, v in base.items()}
|
||||
picked, seen = [], set()
|
||||
for kind, q in quota.items():
|
||||
cands = [b for b in pool if kind_of(b["tu"]) == kind]
|
||||
# round-robin over (bucket, mix)
|
||||
groups = collections.defaultdict(list)
|
||||
for b in cands:
|
||||
f = features(b)
|
||||
groups[(f["bucket"], f["mix"])].append(b)
|
||||
keys = sorted(groups)
|
||||
i = 0
|
||||
while len([b for b in picked if kind_of(b["tu"]) == kind]) < q and any(groups[k] for k in keys):
|
||||
k = keys[i % len(keys)]
|
||||
i += 1
|
||||
if groups[k]:
|
||||
b = groups[k].pop()
|
||||
if (b["tu"], b["fn"]) not in seen:
|
||||
picked.append(b)
|
||||
seen.add((b["tu"], b["fn"]))
|
||||
# the special features, topped up from the pool
|
||||
for flag, want in (("zero", 10), ("init", 10), ("instr", 12), ("cast", 8), ("register", 5), ("launder", 8), ("keepalive", 6)):
|
||||
have = sum(1 for b in picked if features(b)[flag])
|
||||
for b in pool:
|
||||
if have >= want:
|
||||
break
|
||||
if (b["tu"], b["fn"]) not in seen and features(b)[flag]:
|
||||
picked.append(b)
|
||||
seen.add((b["tu"], b["fn"]))
|
||||
have += 1
|
||||
return picked
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# the ladder on one body
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def run_body(b, recipe, write_path, raw, m, ls, log):
|
||||
"""Returns the per-body result dict; the caller restores the file."""
|
||||
sites = sorted(b["sites"], key=lambda s: (ORDER.get(s["kind"], 9), s["line"], s["col"]))
|
||||
res = dict(tu=b["tu"], fn=b["fn"], nhash=b["nhash"], kind=kind_of(b["tu"]), aliases=b["aliases"], header=b["header"],
|
||||
obj=recipe["obj"], n_sites=len(sites), sites=[dict(kind=s["kind"], cls=s["cls"], detail=s["detail"], line=s["line"]) for s in sites],
|
||||
refused=[], compiles=0, seconds=0.0, features=features(b))
|
||||
per_site, edits_all, edits_keep = {}, [], []
|
||||
usable = []
|
||||
for s in sites:
|
||||
try:
|
||||
ed = site_edits(raw, m, ls, s)
|
||||
edk = site_edits(raw, m, ls, s, keep_register=True) if s["kind"] == "pin" else ed
|
||||
per_site[id(s)] = (ed, edk)
|
||||
usable.append(s)
|
||||
edits_all += ed
|
||||
edits_keep += edk
|
||||
except Refuse as ex:
|
||||
res["refused"].append(dict(kind=s["kind"], line=s["line"], why=str(ex)))
|
||||
res["n_usable"] = len(usable)
|
||||
if not usable:
|
||||
res["verdict"] = "NOTHING-USABLE"
|
||||
return res
|
||||
|
||||
def judge(edits, tag):
|
||||
try:
|
||||
cand = apply_edits(raw, edits)
|
||||
except Refuse as ex:
|
||||
return "REFUSED", str(ex)
|
||||
if cand == raw:
|
||||
return "REFUSED", "no-op edit (the candidate equals the original — an identical object would prove nothing, R37)"
|
||||
v, dt, err = oracle.judge(recipe, cand, tag=tag, write_path=write_path)
|
||||
res["compiles"] += 1
|
||||
res["seconds"] += dt
|
||||
return v, err
|
||||
# rung A (register dropped) and A' (register kept)
|
||||
vA, errA = judge(edits_all, "A")
|
||||
res["rung_A"] = vA
|
||||
res["rung_A_err"] = errA[:200] if vA == "COMPILE-ERROR" else ""
|
||||
if any(s["kind"] == "pin" for s in usable):
|
||||
vK, _ = judge(edits_keep, "Ak")
|
||||
res["rung_A_keep_register"] = vK
|
||||
else:
|
||||
res["rung_A_keep_register"] = vA
|
||||
if vA == "IDENTICAL":
|
||||
res["removed"] = [dict(kind=s["kind"], detail=s["detail"], line=s["line"]) for s in usable]
|
||||
res["needed"] = []
|
||||
res["verdict"] = "LEVER-FREE"
|
||||
return res
|
||||
# rung B greedy
|
||||
accepted, needed, removed = [], [], []
|
||||
for s in usable:
|
||||
ed, _ = per_site[id(s)]
|
||||
v, err = judge(accepted + ed, "B")
|
||||
if v == "IDENTICAL":
|
||||
accepted += ed
|
||||
removed.append(dict(kind=s["kind"], detail=s["detail"], line=s["line"]))
|
||||
else:
|
||||
needed.append(dict(kind=s["kind"], detail=s["detail"], line=s["line"], verdict=v, err=(err[:120] if v == "COMPILE-ERROR" else "")))
|
||||
res["removed"], res["needed"] = removed, needed
|
||||
res["verdict"] = "LEVER-FREE" if not needed else "RESIDUE"
|
||||
log(f" {b['tu']}:{b['fn']} A={vA} B: removed {len(removed)} needed {len(needed)} compiles {res['compiles']}")
|
||||
return res
|
||||
|
||||
|
||||
def probe(sample_n, seed, jobs):
|
||||
PROBE.mkdir(parents=True, exist_ok=True)
|
||||
ok, why = oracle.calibration_current()
|
||||
if not ok:
|
||||
sys.exit(f"delever: the oracle's calibration is not current ({why}) — run tools/delever_oracle.py --calibrate first (R56)")
|
||||
recipes = oracle.load_recipes()["recipes"]
|
||||
sites = load_sites()
|
||||
bodies = bodies_from_sites(sites)
|
||||
inc = includers()
|
||||
sample = stratified_sample(bodies, sample_n, seed)
|
||||
log_f = open(PROBE / "probe_log.txt", "a")
|
||||
|
||||
def log(msg):
|
||||
line = f"{time.strftime('%H:%M:%S')} {msg}"
|
||||
print(line, flush=True)
|
||||
log_f.write(line + "\n")
|
||||
log_f.flush()
|
||||
log(f"probe: {len(sample)} bodies sampled from {len(bodies)} lever bodies ({len({b['nhash'] for b in bodies.values() if b['sites']})} distinct classes); seed {seed}")
|
||||
# group by the FILE that gets written (a TU, or a header) — one worker per file
|
||||
by_file = collections.defaultdict(list)
|
||||
for b in sample:
|
||||
by_file[b["tu"]].append(b)
|
||||
|
||||
def work(tu):
|
||||
out = []
|
||||
if tu.endswith(".h"):
|
||||
tus = [t for t in inc.get(tu, []) if ("build/" + t[:-2] + ".o") in recipes]
|
||||
if not tus:
|
||||
return [dict(tu=tu, fn=b["fn"], verdict="NO-INCLUDER-RECIPE") for b in by_file[tu]]
|
||||
recipe = recipes["build/" + tus[0][:-2] + ".o"]
|
||||
write_path = tu
|
||||
else:
|
||||
obj = "build/" + tu[:-2] + ".o"
|
||||
if obj not in recipes:
|
||||
return [dict(tu=tu, fn=b["fn"], verdict="NO-RECIPE") for b in by_file[tu]]
|
||||
recipe = recipes[obj]
|
||||
write_path = None
|
||||
path = REPO / tu
|
||||
raw = path.read_text(errors="surrogateescape")
|
||||
m = same_len_mask(raw)
|
||||
ls = line_starts(raw)
|
||||
try:
|
||||
for b in by_file[tu]:
|
||||
out.append(run_body(b, recipe, write_path, raw, m, ls, log))
|
||||
finally:
|
||||
path.write_text(raw, errors="surrogateescape")
|
||||
return out
|
||||
results = []
|
||||
t0 = time.time()
|
||||
# phase 1: translation units, one worker per TU (no two candidates of one file at once, and no header is being edited);
|
||||
# phase 2: shared headers, SERIAL — a header's edit reaches every includer, so nothing else may compile meanwhile
|
||||
# (the dry run's three "compile errors" were two workers' candidates crossing inside one includer)
|
||||
tu_files = sorted(f for f in by_file if not f.endswith(".h"))
|
||||
hdr_files = sorted(f for f in by_file if f.endswith(".h"))
|
||||
with ThreadPoolExecutor(max_workers=jobs) as ex:
|
||||
for r in ex.map(work, tu_files):
|
||||
results.extend(r)
|
||||
for f in hdr_files:
|
||||
results.extend(work(f))
|
||||
wall = time.time() - t0
|
||||
with open(PROBE / "probe_results.jsonl", "w") as f:
|
||||
for r in results:
|
||||
f.write(json.dumps(r) + "\n")
|
||||
summary = summarize(results, bodies, wall, seed)
|
||||
(PROBE / "probe_summary.json").write_text(json.dumps(summary, indent=1) + "\n")
|
||||
(PROBE / "probe_table.md").write_text(render(summary) + "\n")
|
||||
print(render(summary))
|
||||
return summary
|
||||
|
||||
|
||||
def summarize(results, bodies, wall, seed):
|
||||
judged = [r for r in results if r.get("verdict") in ("LEVER-FREE", "RESIDUE")]
|
||||
def pct(a, b):
|
||||
return round(100.0 * a / b, 1) if b else None
|
||||
by_kind = {}
|
||||
for k in ("main", "resident", "md", "shared", "ov"):
|
||||
rs = [r for r in judged if r["kind"] == k]
|
||||
if not rs:
|
||||
continue
|
||||
by_kind[k] = dict(bodies=len(rs), A_identical=sum(1 for r in rs if r["rung_A"] == "IDENTICAL"),
|
||||
A_keep_register_identical=sum(1 for r in rs if r.get("rung_A_keep_register") == "IDENTICAL"),
|
||||
lever_free=sum(1 for r in rs if r["verdict"] == "LEVER-FREE"),
|
||||
sites=sum(r["n_usable"] for r in rs), removed=sum(len(r["removed"]) for r in rs), needed=sum(len(r["needed"]) for r in rs),
|
||||
compiles=sum(r["compiles"] for r in rs), mean_s_per_compile=round(sum(r["seconds"] for r in rs) / max(sum(r["compiles"] for r in rs), 1), 3))
|
||||
needed_kinds = collections.Counter(n["kind"] for r in judged for n in r["needed"])
|
||||
needed_detail = collections.Counter(f"{n['kind']}:{n['detail']}" for r in judged for n in r["needed"])
|
||||
removed_kinds = collections.Counter(x["kind"] for r in judged for x in r["removed"])
|
||||
refused = collections.Counter(x["why"].split(":")[0][:60] for r in results for x in r.get("refused", []))
|
||||
sites_total = sum(r["n_usable"] for r in judged)
|
||||
sites_needed = sum(len(r["needed"]) for r in judged)
|
||||
flags = {}
|
||||
for flag in ("zero", "init", "instr", "cast", "register", "launder", "barrier", "keepalive", "volatile"):
|
||||
rs = [r for r in judged if r["features"].get(flag)]
|
||||
flags[flag] = dict(bodies=len(rs), lever_free=sum(1 for r in rs if r["verdict"] == "LEVER-FREE"))
|
||||
pop_bodies = sum(1 for b in bodies.values() if b["sites"])
|
||||
pop_sites = sum(len(b["sites"]) for b in bodies.values())
|
||||
mean_compiles = sum(r["compiles"] for r in judged) / max(len(judged), 1)
|
||||
mean_s = sum(r["seconds"] for r in judged) / max(sum(r["compiles"] for r in judged), 1)
|
||||
return dict(generated=time.strftime("%Y-%m-%d %H:%M"), seed=seed, sampled=len(results), judged=len(judged),
|
||||
not_judged=collections.Counter(r.get("verdict") for r in results if r not in judged),
|
||||
rung_A_identical=sum(1 for r in judged if r["rung_A"] == "IDENTICAL"),
|
||||
rung_A_keep_register_identical=sum(1 for r in judged if r.get("rung_A_keep_register") == "IDENTICAL"),
|
||||
lever_free_after_B=sum(1 for r in judged if r["verdict"] == "LEVER-FREE"),
|
||||
sites=dict(total=sites_total, removed=sites_total - sites_needed, needed=sites_needed, pct_removed=pct(sites_total - sites_needed, sites_total)),
|
||||
needed_by_kind=dict(needed_kinds), needed_by_detail=dict(needed_detail.most_common(30)), removed_by_kind=dict(removed_kinds),
|
||||
refused=dict(refused), by_kind=by_kind, flags=flags,
|
||||
compiles=sum(r["compiles"] for r in judged), mean_compiles_per_body=round(mean_compiles, 2), mean_s_per_compile=round(mean_s, 3),
|
||||
wall_s=round(wall, 1),
|
||||
population=dict(bodies=pop_bodies, sites=pop_sites),
|
||||
pricing=dict(T4_compiles_est=int(pop_bodies * mean_compiles), T4_cpu_hours_est=round(pop_bodies * mean_compiles * mean_s / 3600, 2),
|
||||
T4_wall_hours_at_16_est=round(pop_bodies * mean_compiles * mean_s / 3600 / 12, 2),
|
||||
residue_bodies_est=int(pop_bodies * (1 - (sum(1 for r in judged if r["verdict"] == "LEVER-FREE") / max(len(judged), 1)))),
|
||||
residue_sites_est=int(pop_sites * (sites_needed / max(sites_total, 1)))))
|
||||
|
||||
|
||||
def render(s):
|
||||
L = [f"# probe — {s['sampled']} bodies sampled, {s['judged']} judged (seed {s['seed']}, {s['generated']}, wall {s['wall_s']} s)", "",
|
||||
f"- rung A (strip-all) identical: **{s['rung_A_identical']} / {s['judged']}** (register dropped) · {s['rung_A_keep_register_identical']} with `register` kept",
|
||||
f"- lever-free after rung B: **{s['lever_free_after_B']} / {s['judged']}**",
|
||||
f"- sites: {s['sites']['total']} usable · removed {s['sites']['removed']} ({s['sites']['pct_removed']} %) · needed {s['sites']['needed']}",
|
||||
f"- needed by kind: {s['needed_by_kind']}", f"- needed by detail (top): {s['needed_by_detail']}",
|
||||
f"- removed by kind: {s['removed_by_kind']}", f"- refused (rewrite not applicable): {s['refused']}",
|
||||
f"- compiles {s['compiles']} · mean {s['mean_compiles_per_body']} per body · {s['mean_s_per_compile']} s per compile", "",
|
||||
"| kind | bodies | A identical | A (register kept) | lever-free after B | sites | removed | needed | compiles | s/compile |", "|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|"]
|
||||
for k, v in s["by_kind"].items():
|
||||
L.append(f"| {k} | {v['bodies']} | {v['A_identical']} | {v['A_keep_register_identical']} | {v['lever_free']} | {v['sites']} | {v['removed']} | {v['needed']} | {v['compiles']} | {v['mean_s_per_compile']} |")
|
||||
L += ["", "| feature | bodies | lever-free |", "|---|---:|---:|"]
|
||||
for k, v in s["flags"].items():
|
||||
L.append(f"| {k} | {v['bodies']} | {v['lever_free']} |")
|
||||
p = s["pricing"]
|
||||
L += ["", f"**Pricing (R41; population {s['population']['bodies']:,} lever bodies / {s['population']['sites']:,} removable sites):** "
|
||||
f"T4 ≈ {p['T4_compiles_est']:,} compiles ≈ {p['T4_cpu_hours_est']} CPU-h ≈ {p['T4_wall_hours_at_16_est']} h wall at 12 workers; "
|
||||
f"residue after the mechanical ladder ≈ {p['residue_bodies_est']:,} bodies / {p['residue_sites_est']:,} sites (the sample's rates applied to the population)."]
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
|
||||
ap.add_argument("--probe", action="store_true")
|
||||
ap.add_argument("--sample", type=int, default=150)
|
||||
ap.add_argument("--seed", type=int, default=1)
|
||||
ap.add_argument("-j", "--jobs", type=int, default=12)
|
||||
a = ap.parse_args()
|
||||
if a.probe:
|
||||
probe(a.sample, a.seed, a.jobs)
|
||||
return
|
||||
ap.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,303 @@
|
||||
#!/usr/bin/env python3
|
||||
"""delever_oracle.py — the fast byte oracle for a single-translation-unit source edit (Phase 36 T2, 2026-09-09).
|
||||
|
||||
tools/delever_oracle.py --recipes [-j N] # capture every object's exact build command via `make -n -W` -> .run/P36/delever/recipes.json
|
||||
tools/delever_oracle.py --calibrate ov_SC04_011 main # compile every TU of the named binaries UNTOUCHED: 100 % object equality with build/,
|
||||
# twin == primary, then the POSITIVE control (a nop injected -> DIFFERS); exit 1 otherwise
|
||||
tools/delever_oracle.py --status # is the calibration current for this HEAD / Makefile?
|
||||
|
||||
THE QUESTION IT ANSWERS: "does this candidate text for TU X still produce the byte-identical object?" — and only that. The whole-binary
|
||||
gate (`make check BINARY=…`, and the clean fleet run, R22) remains the arbiter of every batch; this oracle is the inner loop that
|
||||
decides one lever site at a time in ~0.3–5 s instead of ~90 s.
|
||||
|
||||
HOW (the design settled at gate 1 + the plan agent's review, R57: the instrument's own path is part of the instrument):
|
||||
* the recipe of every object is the Makefile's OWN command, printed by `make -n -W <src> <obj> BINARY=<alias>` (0.04–0.15 s each;
|
||||
captured once per Makefile/config state, ~4,300 objects at -j16 in ~30 s). It carries the per-object -O0 overrides, the
|
||||
jtbl_rodata_pads stage of main/module objects, the reorder island, the twin rule (the primary's source into the twin's object).
|
||||
tools/compile_only.py's re-typed pipeline omits the pad stage and is NOT used.
|
||||
* a candidate compiles IN PLACE at the real path (objects embed the source path as an STT_FILE symbol) with `-o` and `-MF`
|
||||
redirected to scratch — build/ is never written, so the baseline object of the fleet run stays the reference; the TU's text is
|
||||
restored from the caller's in-memory snapshot (never `git checkout`, R102). Workers own whole TUs: no two candidates of one TU at once.
|
||||
* verdict = whole-object byte equality with build/<obj> (R56: build/ must come from a clean fleet run of THIS tree — --calibrate proves it).
|
||||
* CALIBRATION (R39/R57): every sampled TU compiled untouched reproduces its object byte for byte; a twin's object equals its primary's;
|
||||
a deliberately altered body reports DIFFERS. `.run/P36/delever/calibration.json` records HEAD, the Makefile/config mtimes and the
|
||||
per-object seconds (the scheduler's cost model); an --apply of the de-lever tool refuses without a current calibration.
|
||||
"""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
REPO = pathlib.Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "tools"))
|
||||
|
||||
RUN = REPO / ".run" / "P36" / "delever"
|
||||
RECIPES = RUN / "recipes.json"
|
||||
CALIB = RUN / "calibration.json"
|
||||
SCRATCH = RUN / "obj"
|
||||
RECIPE_RE = re.compile(r"^set -o pipefail; (.*) -o (build/\S+\.o)$")
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# enumeration: (alias, src, obj) for every object of every binary — derived from the Makefile's own rules (R33)
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def src_dirs():
|
||||
import corpus
|
||||
return dict(corpus.src_dirs())
|
||||
|
||||
|
||||
def twin_of_map():
|
||||
import share_census
|
||||
return share_census.twin_of_map()
|
||||
|
||||
|
||||
def objects(aliases=None):
|
||||
"""[(alias, src_rel, obj_rel)] — the pattern rule build/src/%.o: src/%.c, and for a twin the primary's sources renamed into the
|
||||
twin's own object names (Makefile twin block)."""
|
||||
import compile_only
|
||||
dirs = src_dirs()
|
||||
twins = twin_of_map()
|
||||
out = []
|
||||
for a in sorted(dirs):
|
||||
if aliases and a not in aliases:
|
||||
continue
|
||||
prim = twins.get(a)
|
||||
for p in compile_only.tus_of(a, dirs):
|
||||
src = p.relative_to(REPO).as_posix()
|
||||
if prim:
|
||||
# src/<prim>/<prim><suffix>.c -> build/src/<twin>/<twin><suffix>.o
|
||||
stem = p.name[:-2]
|
||||
if not stem.startswith(prim):
|
||||
continue
|
||||
obj = f"build/src/{a}/{a}{stem[len(prim):]}.o"
|
||||
else:
|
||||
obj = "build/" + src[:-2] + ".o"
|
||||
out.append((a, src, obj))
|
||||
return out
|
||||
|
||||
|
||||
def config_stamp():
|
||||
files = [REPO / "Makefile"] + sorted((REPO / "config").glob("*.mk"))
|
||||
h = hashlib.sha1()
|
||||
for f in files:
|
||||
st = f.stat()
|
||||
h.update(f"{f.name}|{int(st.st_mtime)}|{st.st_size}\n".encode())
|
||||
return h.hexdigest()[:12]
|
||||
|
||||
|
||||
def head():
|
||||
return subprocess.run(["git", "rev-parse", "--short", "HEAD"], cwd=REPO, capture_output=True, text=True).stdout.strip()
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# recipes
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def capture_recipe(alias, src, obj):
|
||||
r = subprocess.run(["make", "-n", "-W", src, obj, f"BINARY={alias}"], cwd=REPO, capture_output=True, text=True)
|
||||
if r.returncode != 0:
|
||||
return None, f"make -n rc={r.returncode}: {r.stderr.strip()[:200]}"
|
||||
lines = [ln for ln in r.stdout.splitlines() if ln.startswith("set -o pipefail;")]
|
||||
if len(lines) != 1:
|
||||
return None, f"expected ONE pipeline line, got {len(lines)}"
|
||||
m = RECIPE_RE.match(lines[0])
|
||||
if not m or m.group(2) != obj:
|
||||
return None, f"unparsed recipe: {lines[0][:160]}"
|
||||
return dict(alias=alias, src=src, obj=obj, pipeline=m.group(1)), None
|
||||
|
||||
|
||||
def build_recipes(jobs, aliases=None):
|
||||
objs = objects(aliases)
|
||||
recipes, errors = {}, []
|
||||
t0 = time.time()
|
||||
with ThreadPoolExecutor(max_workers=jobs) as ex:
|
||||
for (a, src, obj), (rec, err) in zip(objs, ex.map(lambda t: capture_recipe(*t), objs)):
|
||||
if rec:
|
||||
recipes[obj] = rec
|
||||
else:
|
||||
errors.append(f"{a} {src} {obj}: {err}")
|
||||
return dict(stamp=config_stamp(), head=head(), generated=time.strftime("%Y-%m-%d %H:%M"), n=len(recipes),
|
||||
seconds=round(time.time() - t0, 1), recipes=recipes, errors=errors)
|
||||
|
||||
|
||||
def load_recipes(refresh=False, jobs=16):
|
||||
if RECIPES.exists() and not refresh:
|
||||
d = json.loads(RECIPES.read_text())
|
||||
if d.get("stamp") == config_stamp():
|
||||
return d
|
||||
d = build_recipes(jobs)
|
||||
RUN.mkdir(parents=True, exist_ok=True)
|
||||
RECIPES.write_text(json.dumps(d, indent=1) + "\n")
|
||||
return d
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# compile + compare
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def compile_obj(recipe, text=None, tag="x", write_path=None):
|
||||
"""Compile the recipe's source (with `text` written IN PLACE first — to `write_path` when the edited file is a header the
|
||||
source includes, else to the source itself; the CALLER restores it) to a scratch object. Returns (bytes | None, seconds, errors)."""
|
||||
src = REPO / (write_path or recipe["src"])
|
||||
obj = recipe["obj"]
|
||||
out = SCRATCH / (obj[len("build/"):].replace("/", "__")[:-2] + f".{tag}.o")
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
dep = str(out)[:-2] + ".d"
|
||||
pipeline = recipe["pipeline"]
|
||||
pipeline = re.sub(r"-MF \S+", f"-MF {dep}", pipeline, count=1)
|
||||
cmd = f"set -o pipefail; {pipeline} -o {out}"
|
||||
if text is not None:
|
||||
src.write_text(text, errors="surrogateescape")
|
||||
t0 = time.time()
|
||||
r = subprocess.run(["bash", "-c", cmd], cwd=REPO, capture_output=True, text=True)
|
||||
dt = time.time() - t0
|
||||
if r.returncode != 0 or not out.exists():
|
||||
# gcc 2.7.2 prints errors without the word "error" and the assembler floods stderr with `$at` warnings: keep every
|
||||
# non-warning line (R103), then the tail
|
||||
errs = [ln for ln in r.stderr.splitlines()
|
||||
if ln.strip() and not re.search(r"\bwarning:", ln, re.I) and not ln.startswith(("In file included", " " * 16))
|
||||
and ": In function" not in ln]
|
||||
return None, dt, ("\n".join(errs[:8]) or r.stderr[-400:])
|
||||
data = out.read_bytes()
|
||||
try:
|
||||
out.unlink()
|
||||
pathlib.Path(dep).unlink(missing_ok=True)
|
||||
except OSError:
|
||||
pass
|
||||
return data, dt, ""
|
||||
|
||||
|
||||
def baseline_bytes(obj):
|
||||
p = REPO / obj
|
||||
return p.read_bytes() if p.exists() else None
|
||||
|
||||
|
||||
def judge(recipe, text, tag="x", write_path=None):
|
||||
"""(verdict, seconds, err): verdict in IDENTICAL | DIFFERS | COMPILE-ERROR | NO-BASELINE."""
|
||||
base = baseline_bytes(recipe["obj"])
|
||||
if base is None:
|
||||
return "NO-BASELINE", 0.0, ""
|
||||
data, dt, err = compile_obj(recipe, text, tag, write_path)
|
||||
if data is None:
|
||||
return "COMPILE-ERROR", dt, err
|
||||
return ("IDENTICAL" if data == base else "DIFFERS"), dt, ""
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# calibration
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def calibrate(aliases, jobs, recipes):
|
||||
"""Every object of the named binaries compiled UNTOUCHED -> must equal build/; twin == primary; then the positive control."""
|
||||
recs = [r for r in recipes["recipes"].values() if r["alias"] in aliases]
|
||||
if not recs:
|
||||
sys.exit(f"delever_oracle: no recipes for {aliases} (R43)")
|
||||
twins = twin_of_map()
|
||||
results = []
|
||||
|
||||
def one(r):
|
||||
v, dt, err = judge(r, None, tag="cal")
|
||||
return dict(alias=r["alias"], obj=r["obj"], verdict=v, seconds=round(dt, 3), err=err[-200:])
|
||||
with ThreadPoolExecutor(max_workers=jobs) as ex:
|
||||
results = list(ex.map(one, recs))
|
||||
ok = sum(1 for x in results if x["verdict"] == "IDENTICAL")
|
||||
bad = [x for x in results if x["verdict"] != "IDENTICAL"]
|
||||
# twin == primary on the objects both build
|
||||
twin_checks = []
|
||||
for a in aliases:
|
||||
prim = twins.get(a)
|
||||
if not prim:
|
||||
continue
|
||||
for r in recipes["recipes"].values():
|
||||
if r["alias"] == a:
|
||||
pobj = r["obj"].replace(f"build/src/{a}/{a}", f"build/src/{prim}/{prim}")
|
||||
same = baseline_bytes(r["obj"]) == baseline_bytes(pobj)
|
||||
twin_checks.append(dict(twin=r["obj"], primary=pobj, equal=same))
|
||||
twin_bad = [t for t in twin_checks if not t["equal"]]
|
||||
# the positive control: a nop injected into a REAL function body (the first definition the shared scanner finds in the
|
||||
# first recipe's source with a body of >= 3 lines) must DIFFER — a verifier that cannot fail is no verifier (R39/R53)
|
||||
import share_census as sc
|
||||
ctl = recs[0]
|
||||
src = REPO / ctl["src"]
|
||||
orig = src.read_text(errors="surrogateescape")
|
||||
pos_verdict = "SKIPPED"
|
||||
defs = [r for r in sc.scan_text(orig, ctl["src"], shared_defs=None) if r["form"] == "def" and r.get("nlines", 0) >= 3 and not r.get("empty")]
|
||||
if defs:
|
||||
d = defs[0]
|
||||
line_starts = [0]
|
||||
for ln in orig.split("\n"):
|
||||
line_starts.append(line_starts[-1] + len(ln) + 1)
|
||||
# at the END of the body (C89: a statement before the declarations is a parse error)
|
||||
o = orig.rfind("}", line_starts[d["end"] - 1], line_starts[d["end"]])
|
||||
if o >= 0:
|
||||
cand = orig[:o] + ' __asm__("nop");\n' + orig[o:]
|
||||
try:
|
||||
pos_verdict, _, err = judge(ctl, cand, tag="ctl")
|
||||
pos_verdict = pos_verdict if pos_verdict != "COMPILE-ERROR" else f"COMPILE-ERROR ({err[-100:]})"
|
||||
finally:
|
||||
src.write_text(orig, errors="surrogateescape")
|
||||
by_alias = {}
|
||||
for x in results:
|
||||
d = by_alias.setdefault(x["alias"], dict(objects=0, identical=0, seconds=0.0))
|
||||
d["objects"] += 1
|
||||
d["identical"] += x["verdict"] == "IDENTICAL"
|
||||
d["seconds"] += x["seconds"]
|
||||
return dict(head=head(), stamp=config_stamp(), generated=time.strftime("%Y-%m-%d %H:%M"), aliases=sorted(aliases),
|
||||
objects=len(results), identical=ok, failures=bad[:20], twin_checks=len(twin_checks), twin_mismatch=twin_bad[:10],
|
||||
positive_control=dict(obj=ctl["obj"], verdict=pos_verdict),
|
||||
per_alias={a: dict(v, mean_s=round(v["seconds"] / max(v["objects"], 1), 3)) for a, v in by_alias.items()},
|
||||
per_object_seconds={x["obj"]: x["seconds"] for x in results},
|
||||
ok=(not bad and not twin_bad and pos_verdict == "DIFFERS"))
|
||||
|
||||
|
||||
def calibration_current():
|
||||
if not CALIB.exists():
|
||||
return False, "no calibration"
|
||||
d = json.loads(CALIB.read_text())
|
||||
if d.get("head") != head():
|
||||
return False, f"calibrated at {d.get('head')}, HEAD is {head()}"
|
||||
if d.get("stamp") != config_stamp():
|
||||
return False, "the Makefile/config changed since the calibration"
|
||||
return bool(d.get("ok")), ("ok" if d.get("ok") else "the calibration FAILED")
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
|
||||
ap.add_argument("--recipes", action="store_true", help="(re)capture every object's recipe")
|
||||
ap.add_argument("--calibrate", nargs="*", help="binaries to calibrate on (e.g. ov_SC04_011 ov_SC03_015 main)")
|
||||
ap.add_argument("--status", action="store_true")
|
||||
ap.add_argument("-j", "--jobs", type=int, default=16)
|
||||
a = ap.parse_args()
|
||||
RUN.mkdir(parents=True, exist_ok=True)
|
||||
if a.status:
|
||||
ok, why = calibration_current()
|
||||
print(f"delever_oracle: calibration {'CURRENT' if ok else 'STALE/MISSING'} — {why}")
|
||||
sys.exit(0 if ok else 1)
|
||||
if a.recipes:
|
||||
d = load_recipes(refresh=True, jobs=a.jobs)
|
||||
print(f"delever_oracle: {d['n']} recipes captured in {d['seconds']} s at -j{a.jobs}; errors {len(d['errors'])}")
|
||||
for e in d["errors"][:10]:
|
||||
print(" ", e)
|
||||
sys.exit(1 if d["errors"] else 0)
|
||||
if a.calibrate is not None:
|
||||
recipes = load_recipes(jobs=a.jobs)
|
||||
t0 = time.time()
|
||||
d = calibrate(a.calibrate, a.jobs, recipes)
|
||||
d["seconds"] = round(time.time() - t0, 1)
|
||||
CALIB.write_text(json.dumps(d, indent=1) + "\n")
|
||||
print(f"delever_oracle --calibrate {' '.join(d['aliases'])}: {d['identical']}/{d['objects']} objects byte-identical untouched; "
|
||||
f"twin checks {d['twin_checks']} ({len(d['twin_mismatch'])} mismatch); positive control {d['positive_control']['verdict']} "
|
||||
f"on {d['positive_control']['obj']}; {d['seconds']} s — {'OK' if d['ok'] else 'FAIL'}")
|
||||
for a_, v in d["per_alias"].items():
|
||||
print(f" {a_:14s} {v['identical']}/{v['objects']} identical, mean {v['mean_s']} s per object")
|
||||
for f in d["failures"][:10]:
|
||||
print(" FAIL", f["alias"], f["obj"], f["verdict"], f["err"][-120:])
|
||||
sys.exit(0 if d["ok"] else 1)
|
||||
ap.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -405,7 +405,8 @@ def walk_file(raw, rel, is_header):
|
||||
d = span_of_line.get(ln)
|
||||
flat = re.sub(r"\s+", " ", text).strip()
|
||||
# a file-scope asm block keeps its whole template: the manifest match reads its `.globl`/`.ent` name
|
||||
sites.append(dict(tu=rel, fn=(d["name"] if d else None), fn_line=(d["line"] if d else None), line=ln,
|
||||
sites.append(dict(tu=rel, fn=(d["name"] if d else None), fn_line=(d["line"] if d else None), fn_end=(d["end"] if d else None),
|
||||
nhash=(d["nhash"] if d else None), line=ln,
|
||||
col=pos - masked.rfind("\n", 0, pos), cls=cls, kind=kind, detail=detail,
|
||||
text=(flat if (cls == "B" and d is None) else flat[:200]), marked=marked(ln), scope=("body" if d else "file"), **kw))
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
> its platform SDK need the marked adaptation. The last table lists the tools that are project-only in code (their *shape* is a task;
|
||||
> their code does not transfer). *TODO(platform): the MIPS and PlayStation SDK hard-codes are the ones another platform replaces first.*
|
||||
>
|
||||
> **Coverage:** 296 tool files in scope (submodules, vendored and downloaded code excluded), of which 296 live rows
|
||||
> below; per phase: P1 2 · P2 26 · P3 17 · P4 9 · P5 26 · P6 51 · P7 20 · P8 86 · P9 27 · P10 16 · PROJECT-ONLY 16. Superseded tools appear only as pointers to their successor (30 pointer rows); one-offs are omitted. Table rows in all: 326 (the installer checks its copy against this figure).
|
||||
> **Coverage:** 298 tool files in scope (submodules, vendored and downloaded code excluded), of which 298 live rows
|
||||
> below; per phase: P1 2 · P2 26 · P3 17 · P4 9 · P5 26 · P6 51 · P7 20 · P8 86 · P9 27 · P10 18 · PROJECT-ONLY 16. Superseded tools appear only as pointers to their successor (30 pointer rows); one-offs are omitted. Table rows in all: 328 (the installer checks its copy against this figure).
|
||||
|
||||
## P1 — extraction + manifest
|
||||
|
||||
@@ -333,12 +333,14 @@
|
||||
| `lint_symbol_refs.py` | flag address-named references whose address now has a curated name | Flags address-named references in committed sources whose address now has a curated name | repo symbol/src paths |
|
||||
| `uniquify_type.py` | give each conflicting camp of a same-named type its own name | Gives each conflicting camp of a same-named type its own name so every camp becomes liftable | repo src layout |
|
||||
| `verbatim_check.py` | guard that every inline-assembly body still reproduces its target bytes | Regression guard that every inline-assembly body still reproduces its target bytes | repo src layout |
|
||||
| `delever_oracle.py` | judge one translation-unit edit by the bytes of its object in under a second | The Phase-36 fast byte oracle: every object's exact build command captured once via make -n -W (the Makefile's own recipe, pad stage and -O0 overrides included), a candidate compiled in place with -o/-MF redirected to scratch and compared with the fleet run's object; --calibrate proves 100 % equality untouched, twin == primary and a positive control before any verdict is trusted | the Makefile's object rules, the twin rule |
|
||||
| `share_census.py` | measure duplicate function bodies across the fleet and assert one source per unique function | The census of byte-identical function classes across every binary with their source forms and verdicts, plus the S1 invariant check with its exception ledger and a fixture self-test | repo paths, the registry and signature schemas |
|
||||
| `ghidra_apply_symbols.sh` | mirror the curated symbol file into the analysis database with a real save | Mirrors the curated symbol file into the analysis program headlessly, with a real save | repo symbol path, project name |
|
||||
| `frozen.py` | refuse, from one place, the command line of a tool the project has frozen | The one refusal a FROZEN tool prints from its main(): the tool, the successor and why; imports never exit (libraries stay usable) | nothing |
|
||||
| `verbatim_target_s.py` | regenerate a splitter-format target disassembly for a function no longer stubbed | Regenerates a splitter-format target disassembly for a function that is no longer a stub; --gas emits the assemblable gas-syntax form ($-registers, .L labels, noreorder) that a web diff service accepts as a pasted target | repo build/asm layout |
|
||||
| `share_body_cycle.sh` | run the share-body batch cycle unattended: batch, verify by exit code, log, commit, periodic clean fleet check | The Phase-35 T5 driver for bucket new: per batch share_body --apply --bucket new --batches 1 --label new<k>, the gated N/N line read, the phase log entry appended, the bank committed the moment it is green, the clean fleet run every N batches — stops on the first red | repo paths, the phase-log format, the fleet count from config/check.*.sha |
|
||||
| `share_body.py` | share one byte-identical function class across its binaries through an include-at-site header, gated per binary | The Phase-35 successor of dedup_propagate + dedup_extend for the include-at-site form: exemplar by majority text, the header written once, every private copy replaced by the include at its position, per-binary byte gate with object comparison, bisect on red, the registry appended or extended by text, the exception ledger on refusal; --plan / --apply --bucket extend|new | repo paths, the registry and signature schemas |
|
||||
| `delever.py` | take register pins, asm statements, volatile and register levers out of matched C, byte-gated per site | The Phase-36 de-lever engine: positional rewrites per lever class (pin -> plain declaration, barrier/launder/keep-alive deleted, a hand-placed instruction -> its C, the zero-register variable -> 0, volatile/register dropped), rung A strip-all and rung B greedy per body through delever_oracle, headers serialized after the TU phase; --probe runs a stratified sample of distinct bodies and prices the campaign with denominators | the census site records, the oracle |
|
||||
| `verbatim_to_stub.py` | turn an inline-assembly body back into a stub the toolchain can reach | Turns an inline-assembly body back into an include-assembly stub | repo src/asm layout |
|
||||
|
||||
## PROJECT-ONLY — project-only in code (the shape is a task; the code does not transfer)
|
||||
|
||||
@@ -783,6 +783,8 @@ Every script under `tools/` (plus the two report make-targets), grouped by purpo
|
||||
| | `tools/tool_census.py [--check | --manifest | --corpus | --all | --consumers FILE]` | **(P33.5 task 13.5)** The tools audit as a derived instrument: two independent enumerations of every tool file under `tools/` (`find` vs `git ls-files`, submodules/vendored/downloaded excluded — they must agree, R34); per tool the docstring line, its SETUP row, its CONSUMERS (Makefile/`.mk` targets, CI, the wave playbook, other tools by import or by name) and hence its class (LIVE · REFERENCED · ORPHAN); the AUTHORED facts live in `config/tool_dictionary.tsv` (phase · portability · the NEED the tool answers · what · what it hard-codes · the retirement verdict with its successor or product) with coverage asserted BOTH ways (R32 — a new tool without a row fails `--check`). Generates `docs/tool-index.md` (the need-keyed dictionary; KEEP-GEN), the kit's `tools/MANIFEST.md` (`--manifest`) and the three verbatim corpora `decomp-architect/corpus/tools/<phase>/` + `corpus/cookbook/` + `corpus/record/` (the how-to, the decision log, the accelerators, the retrospective, the story, the playbook, the effort map, the gen3 docs, the digest, every PhaseEnd — task 14.5) (`--corpus`; superseded tools as pointer files; sha1-equal to their sources). `--check` in `tools-health`; `make kit-corpus` = `--all`. `--consumers FILE` is the referrer census before any `git mv` of a tool. |
|
||||
| | `tools/share_census.py` | **(P35 T1)** The fleet-wide census of byte-identical function classes and the S1 "one source per unique function" checker (`--check`, `--selftest`, `--scope`, `--strict-macros`, `--strict-text`); its ledger is `config/dedup_exceptions.tsv`; details in the P35 T1 section below. |
|
||||
| | `tools/lever_census.py` | **(P36 T1)** The census of every compiler-forcing construct ("lever") in the fleet's C — register pins, asm statements by kind (barrier / launder / keepalive / instruction / GTE / verbatim-body), volatile levers, bare `register`, plus the deferred asm-label aliases, builtins and attributes — derived from `share_census`'s scanner with a per-token coverage assertion against the raw text, four known-true controls, the `// !FAKE:` marker split, `--check` (0 unmarked pins/asm) and `--check --strict` (0 pins, 0 asm outside the GTE header) gates, `--sites` (every site to `.run/P36/census/lever_sites.jsonl`, the delever ledger's input), `--selftest`. Evidence: `.run/P36/census/lever_census.{json,txt}`; `progress.py` publishes the `levers` block and a README sentence from it. |
|
||||
| | `tools/delever_oracle.py` | **(P36 T2)** The fast byte oracle for a single-translation-unit edit: `--recipes` captures every object's exact build command through `make -n -W <src> <obj> BINARY=<alias>` (the Makefile's own pipeline — the jump-table pad stage, the per-object `-O0` overrides, the twin rule — into `.run/P36/delever/recipes.json`, regenerable in ~15 s); a candidate is compiled IN PLACE with `-o`/`-MF` redirected to scratch and its bytes compared with `build/`'s object from the fleet run (build/ is never written); `--calibrate <aliases>` proves 100 % equality untouched + twin == primary + a positive control (a nop injected at the end of a real body → DIFFERS) and writes `calibration.json` (HEAD, config stamp, per-object seconds); `--status`. Measured at T2: main 0.08–0.77 s per object, overlays ~0.14 s. |
|
||||
| | `tools/delever.py` | **(P36 T2/T3)** The de-lever engine. Rewrites per lever class on the raw text at the census's positions (a token mismatch REFUSES, never guesses): pin → plain declaration (type/qualifiers/initializer kept; the `$0` zero-register variable's uses → 0), barrier / launder / keep-alive → deleted (via-macro `SHB(x)` too), a hand-placed instruction → its C (addu-$zero/move/la/lh/addiu/sll/srl/and/andi/lui/li/lw and the lui+addiu / lui+ori pairs), volatile / register → dropped; rung A strip-all then rung B greedy through `delever_oracle`, the file restored from the in-memory snapshot after every compile; TUs in parallel (one worker per file), shared headers SERIAL after the TU phase (a header edit reaches every includer). `--probe --sample N --seed S` runs the ladder on a stratified sample of DISTINCT bodies → `.run/P36/probe/{probe_results.jsonl,probe_summary.json,probe_table.md}` with the pricing (R41). |
|
||||
| | `tools/kit_coverage.py` | **(P33.5 task 14.5)** The kit's DISTILLATION coverage: derives the rule population (every `- **R<n>` of DIGEST §3, asserted contiguous) and the hindsight population (every `## ` heading of `docs/accelerators.md` at numbered-item granularity — 58 at S92) and asserts each is cited by a `provenance:` line of the registry seed / the kernels OR dispositioned in `config/kit_coverage_map.tsv` (`G<id>` / `DK-<n>` / `FOLDED:G<id>` / `ENV` / `PA` / `SEED:<file>` / `KIT:<path>` / `RECORD` / `COOKBOOK` / `NOT-PORTABLE`; unknown ids refused, R43); counts with denominators (R41); rc 1 on any gap. In `tools-health` after `tool_census --check`. Its first run found 26 uncited rules and 21 uncited entries → three new kernels (DK-66–DK-68) and 41 authored dispositions. |
|
||||
| | `decomp-architect/` (the day-one decomp kit) | **(P33.5 tasks 9–14)** The package a new matching-decomp project installs as Phase 0.5 on ProjectArchitect 2.0: `README.md` (the three steps), `intake.decomp.md` (ProjectArchitect's twelve items pre-answered + the phase ladder + the six readability inversions), `SETUP.md` (the installer, Step 0 contract … Step 10 verify + hard stop; `answers: <path>` for unattended runs), `decomp-architect.md` (the methodology), `templates/` (the firewall pack — `gitignore.decomp`, `firewall.txt`, `audit_public.template.py`, the planted fixture, `no-rom.template.yml` —, the READMEs, `pa-overlays.md`, `registry-E.decomp.md` G1–G67, the skeletons, `PLACEHOLDERS.md`, `layout-contract.md`), `corpus/decomp-kernels.md` (DK-1 … DK-80), the three dictionaries `corpus/tools/<phase>/` + `corpus/cookbook/` + `corpus/record/` (generated by `make kit-corpus`), `memory-seed/` (18), `tools/MANIFEST.md` (generated). **How it is checked:** `tools/kit_lint.py` (de-specialisation, placeholders, syntax, the gitignore-template diff) + `tools/tool_census.py --check` (the corpora equal their sources) + `tools/gitignore_template_check.py`, all in `tools-health`; the dry-run harness under `.run/P33.5/kit-dryrun/` (`answers.md`, `expected-manifest.txt`, `judge.py`, the install logs and verdicts of runs 1–5 — a kit change is re-verified by a resume on the last throwaway `repo/`, a fresh full run only when SETUP's steps change; the judge compares the real tree's dirty PATH SETS before/after). Wiki page: `docs/wiki/Start-a-new-decomp-project.md`. Split into its own repository after the flip. |
|
||||
| **Verification** | `tools/verify_contract.sh` | **(P33 A5/C8) THE recorded contract run**: 00 tree · 01 check-env · 02 family_hseq · 03 `make clean && extract-all && check-all` · 04 sdk-dual (or a recorded SKIP) · 05 tools-health (zero `[warn]`) · 06 audit-frontier · 07 audit-disc · 08 report; one log per step ending `EXIT=<rc>`, abort on the first red (R53), every step asserted by its contract line (R49), `SUMMARY.md` generated → `.run/P33/verify/` (tracked evidence, quoted by `docs/verification.md` §2); step 00 ignores its own output dir. ≈14 min on 32 CPUs. |
|
||||
|
||||
+7
-5
@@ -5,7 +5,7 @@ freshness). The derived columns come from the tree on every run; the authored on
|
||||
dictionary, whose coverage is asserted both ways. Read it by NEED: find the phrase that matches what you are trying to do, then the tool,
|
||||
then what proved it. The same data generates the day-one kit's manifest and its verbatim tool corpus.*
|
||||
|
||||
**Coverage:** 296 tool files in scope (submodules, vendored and downloaded code excluded; `find` and `git ls-files` agree) + 38 retired under `tools/sunset/`. Classes: LIVE 237 (a runtime consumer), REFERENCED 29 (a SETUP row only), ORPHAN 30 (neither) — of 296. Portability: PORTABLE 23, ADAPT 256, PROJECT-ONLY 17.
|
||||
**Coverage:** 298 tool files in scope (submodules, vendored and downloaded code excluded; `find` and `git ls-files` agree) + 38 retired under `tools/sunset/`. Classes: LIVE 238 (a runtime consumer), REFERENCED 30 (a SETUP row only), ORPHAN 30 (neither) — of 298. Portability: PORTABLE 23, ADAPT 258, PROJECT-ONLY 17.
|
||||
|
||||
## P1 — extraction + manifest
|
||||
|
||||
@@ -85,7 +85,7 @@ then what proved it. The same data generates the day-one kit's manifest and its
|
||||
|
||||
| When you need to… | Tool | What it does | Proven by | Adapt | Class |
|
||||
|---|---|---|---|---|---|
|
||||
| answer from one derived model whether each function is open, matched or shared | `corpus.py` | The single derived model of the source tree: open, matched or shared, per function | Makefile, api_agent.py, aprop_autodraft.py, aprop_symfix.py (+66) | repo src/config layout | LIVE |
|
||||
| answer from one derived model whether each function is open, matched or shared | `corpus.py` | The single derived model of the source tree: open, matched or shared, per function | Makefile, api_agent.py, aprop_autodraft.py, aprop_symfix.py (+67) | repo src/config layout | LIVE |
|
||||
| assert every consumer knows about each newly onboarded binary | `audit_binaries.py` | Gate asserting every consumer knows about each newly onboarded binary | Makefile | repo config/registry paths | LIVE |
|
||||
| assert every tracked source is plain text so text searches never skip it | `audit_text_sources.py` | Every tracked C source must be plain text, or text searches silently skip it | .github/workflows/no-rom.yml, Makefile | repo src paths | LIVE |
|
||||
| check that the independent what-remains views agree with the corpus oracle | `audit_frontier.py` | Checks that the independent "what remains" views agree with the corpus oracle | Makefile | repo paths | LIVE |
|
||||
@@ -294,7 +294,7 @@ then what proved it. The same data generates the day-one kit's manifest and its
|
||||
| assert that the distilled kit cites or dispositions every rule and every hindsight entry of the source project (no silent gap in the distillation) | `kit_coverage.py` | Derives the rule and accelerator populations from the digest and the ledger, matches them against the kit's provenance lines, refuses an uncovered entry unless config/kit_coverage_map.tsv dispositions it | Makefile | repo digest/ledger/kit paths + the provenance citation forms | LIVE |
|
||||
| build a progress timeline from the repository's own committed digests | `timeline.py` | Builds a progress timeline from the repository's own committed digests, with a self-check | Makefile | repo doc paths | LIVE |
|
||||
| check that every relative link in the public docs resolves | `doc_links.py` | Checks that every relative link in the public docs resolves and the link policy holds | Makefile, wiki_render.py, wiki_sync.sh | repo doc paths | LIVE |
|
||||
| compile every eligible translation unit with the pinned toolchain, using no derived bytes | `compile_only.py` | Compiles every eligible translation unit with the pinned toolchain, without any game bytes | .github/workflows/no-rom.yml, lever_census.py, macro_to_header.py, share_census.py | compiler triple, repo makefile parsing | LIVE |
|
||||
| compile every eligible translation unit with the pinned toolchain, using no derived bytes | `compile_only.py` | Compiles every eligible translation unit with the pinned toolchain, without any game bytes | .github/workflows/no-rom.yml, delever_oracle.py, lever_census.py, macro_to_header.py (+1) | compiler triple, repo makefile parsing | LIVE |
|
||||
| compute and publish progress metrics as report, machine data and per-binary breakdowns | `progress.py` | Computes and publishes the progress metrics as report, JSON and per-binary breakdowns | Makefile, docs/wave-playbook.md, api_agent.py, atlas.py (+33) | repo src/config layout | LIVE |
|
||||
| convert progress metrics into an external progress-report schema | `objdiff_report.py` | Converts the progress JSON into the external progress-report schema | .github/workflows/progress.yml | external report schema | LIVE |
|
||||
| emit the public ordinal-to-hash map and the private old-to-new map | `public_rewrite/build_commit_map.py` | Emits the public ordinal-to-new-hash map and the private old-to-new map | probe_github.sh, resolve_tokens.py | repo doc/scratch paths | LIVE |
|
||||
@@ -322,19 +322,21 @@ then what proved it. The same data generates the day-one kit's manifest and its
|
||||
|---|---|---|---|---|---|
|
||||
| add per-site function-pointer casts so a draft can call a differently typed callee | `cast_call_sites.py` | Adds per-site function-pointer casts so a draft can call a differently typed callee | canon_sig_reconcile.py, cast_self_callers.py, family_sweep.py, gate_stage.py (+4) | repo src layout | LIVE |
|
||||
| apply curated names and signatures inside the analysis tool and save | `ghidra_scripts/ApplySymbols.java` | The in-tool half of that mirror: apply curated names and signatures, save on exit | ghidra_apply_symbols.sh, ghidra_export_annotations.sh, ghidra_rebuild.sh, ExportAnnotations.java (+1) | none | LIVE |
|
||||
| census every compiler-forcing construct in the C and gate the levers-off phase | `lever_census.py` | The Phase-36 census of lever sites (register pins, asm statements by kind, volatile levers, bare register, asm-label aliases, builtins, attributes; the whole-body hand-asm routines and the GTE ops set apart) derived from the shared-body scanner with a per-token coverage assertion against the raw text, four known-true controls, the !FAKE marker split, --check (0 unmarked pins/asm) and --strict (0 pins, 0 asm) gates, --sites for the delever ledger, a fixture self-test | progress.py, verbatim_check.py | repo paths, the shared-body scanner | LIVE |
|
||||
| census every compiler-forcing construct in the C and gate the levers-off phase | `lever_census.py` | The Phase-36 census of lever sites (register pins, asm statements by kind, volatile levers, bare register, asm-label aliases, builtins, attributes; the whole-body hand-asm routines and the GTE ops set apart) derived from the shared-body scanner with a per-token coverage assertion against the raw text, four known-true controls, the !FAKE marker split, --check (0 unmarked pins/asm) and --strict (0 pins, 0 asm) gates, --sites for the delever ledger, a fixture self-test | delever.py, progress.py, verbatim_check.py | repo paths, the shared-body scanner | LIVE |
|
||||
| convert a shared-body macro header into per-function plain-C headers included at each site | `macro_to_header.py` | The Phase-35 converter: every DEFINE_ macro body becomes a plain-C header under src/shared/<space>/ included at its site, the legacy name-parameterized headers converted, the registry text-edited, the macro header deleted; --plan / --apply / --finalize / --verify | share_body.py, tool_census.py | the macro form is this project's; a kit-born project shares headers from its first bank | LIVE |
|
||||
| emit a function's target assembly as an inline-assembly body | `asm_verbatim.py` | Emits the file-scope inline-assembly body form from a disassembly file | docs/wave-playbook.md, draft_prechecks.py, gate_main.py, recover_route.py | repo asm layout | LIVE |
|
||||
| extract inline-defined types and typedefs from a source file into a shared header | `build_engine_types.py` | Extracts inline-defined named types and typedefs from a source file into a shared header | inject_capped_externs.py, lift_types.py, uniquify_type.py | repo shared-header path | LIVE |
|
||||
| flag address-named references whose address now has a curated name | `lint_symbol_refs.py` | Flags address-named references in committed sources whose address now has a curated name | .github/workflows/no-rom.yml, Makefile | repo symbol/src paths | LIVE |
|
||||
| give each conflicting camp of a same-named type its own name | `uniquify_type.py` | Gives each conflicting camp of a same-named type its own name so every camp becomes liftable | — | repo src layout | REFERENCED |
|
||||
| guard that every inline-assembly body still reproduces its target bytes | `verbatim_check.py` | Regression guard that every inline-assembly body still reproduces its target bytes | .github/workflows/no-rom.yml, lever_census.py, progress.py, verbatim_target_s.py (+1) | repo src layout | LIVE |
|
||||
| measure duplicate function bodies across the fleet and assert one source per unique function | `share_census.py` | The census of byte-identical function classes across every binary with their source forms and verdicts, plus the S1 invariant check with its exception ledger and a fixture self-test | Makefile, audit_binaries.py, dedup_integrate.py, gen_harvest_targets.py (+6) | repo paths, the registry and signature schemas | LIVE |
|
||||
| judge one translation-unit edit by the bytes of its object in under a second | `delever_oracle.py` | The Phase-36 fast byte oracle: every object's exact build command captured once via make -n -W (the Makefile's own recipe, pad stage and -O0 overrides included), a candidate compiled in place with -o/-MF redirected to scratch and compared with the fleet run's object; --calibrate proves 100 % equality untouched, twin == primary and a positive control before any verdict is trusted | delever.py | the Makefile's object rules, the twin rule | LIVE |
|
||||
| measure duplicate function bodies across the fleet and assert one source per unique function | `share_census.py` | The census of byte-identical function classes across every binary with their source forms and verdicts, plus the S1 invariant check with its exception ledger and a fixture self-test | Makefile, audit_binaries.py, dedup_integrate.py, delever.py (+8) | repo paths, the registry and signature schemas | LIVE |
|
||||
| mirror the curated symbol file into the analysis database with a real save | `ghidra_apply_symbols.sh` | Mirrors the curated symbol file into the analysis program headlessly, with a real save | — | repo symbol path, project name | REFERENCED |
|
||||
| refuse, from one place, the command line of a tool the project has frozen | `frozen.py` | The one refusal a FROZEN tool prints from its main(): the tool, the successor and why; imports never exit (libraries stay usable) | aprop_autodraft.py, blocker_probe.py, canon_sig_reconcile.py, conform_decls.py (+10) | nothing | LIVE |
|
||||
| regenerate a splitter-format target disassembly for a function no longer stubbed | `verbatim_target_s.py` | Regenerates a splitter-format target disassembly for a function that is no longer a stub; --gas emits the assemblable gas-syntax form ($-registers, .L labels, noreorder) that a web diff service accepts as a pasted target | decompme_replica.sh | repo build/asm layout | LIVE |
|
||||
| run the share-body batch cycle unattended: batch, verify by exit code, log, commit, periodic clean fleet check | `share_body_cycle.sh` | The Phase-35 T5 driver for bucket new: per batch share_body --apply --bucket new --batches 1 --label new<k>, the gated N/N line read, the phase log entry appended, the bank committed the moment it is green, the clean fleet run every N batches — stops on the first red | — | repo paths, the phase-log format, the fleet count from config/check.*.sha | ORPHAN |
|
||||
| share one byte-identical function class across its binaries through an include-at-site header, gated per binary | `share_body.py` | The Phase-35 successor of dedup_propagate + dedup_extend for the include-at-site form: exemplar by majority text, the header written once, every private copy replaced by the include at its position, per-binary byte gate with object comparison, bisect on red, the registry appended or extended by text, the exception ledger on refusal; --plan / --apply --bucket extend|new | aprop_autodraft.py, audit_binaries.py, auto_driver.py, blocker_probe.py (+18) | repo paths, the registry and signature schemas | LIVE |
|
||||
| take register pins, asm statements, volatile and register levers out of matched C, byte-gated per site | `delever.py` | The Phase-36 de-lever engine: positional rewrites per lever class (pin -> plain declaration, barrier/launder/keep-alive deleted, a hand-placed instruction -> its C, the zero-register variable -> 0, volatile/register dropped), rung A strip-all and rung B greedy per body through delever_oracle, headers serialized after the TU phase; --probe runs a stratified sample of distinct bodies and prices the campaign with denominators | — | the census site records, the oracle | REFERENCED |
|
||||
| turn an inline-assembly body back into a stub the toolchain can reach | `verbatim_to_stub.py` | Turns an inline-assembly body back into an include-assembly stub | — | repo src/asm layout | REFERENCED |
|
||||
|
||||
## PROJECT-ONLY — project-only in code (the shape is a task; the code does not transfer)
|
||||
|
||||
@@ -47,9 +47,11 @@
|
||||
in 15,667 bodies (2,215 distinct)** (+1: the DECOMPILE-NOW body is a lever); `progress.py` counts PERMANENT rows (27) with a dated
|
||||
`corrections` entry; README prose + wiki Home + Where-next + gen3-standards + gen3-handoff updated as dated snapshots; `progress.py
|
||||
--json --readme --check` fresh; `doc_links --strict` green.
|
||||
- ☐ **T2** (Max) — The probe: the oracle (recipes via `make -n -W`, replayed to a scratch object, `-MF` to scratch), CALIBRATED (sampled
|
||||
TUs untouched → 100 % object equality with `build/`; twin == primary; an altered body → DIFFERS), then rung A + B on ~150 stratified
|
||||
distinct bodies; the measured table prices T4–T7 (R41). Verify: the probe table in this log with its command.
|
||||
- ☑ **T2** (S97) — The probe. `tools/delever_oracle.py`: 4,284 recipes captured in 14 s; `--calibrate ov_SC04_011 ov_SC03_015 ov_SC03_014
|
||||
main`: **177/177 objects byte-identical untouched; twin checks 32 (0 mismatch); positive control DIFFERS on build/src/800.o — OK**
|
||||
(main 0.079 s per object mean, 0.77 s for `800.o`; overlays ~0.14 s). `tools/delever.py --probe --sample 300 --seed 11 -j 12`: **285
|
||||
distinct bodies sampled, 283 judged, 1,660 compiles, 151 s wall; rung A identical 53/283; lever-free after rung B 53/283; sites 1,309
|
||||
usable → removed 561 (42.9 %), needed 748 (57.1 %)**; the table is in the log entry below and in `.run/P36/probe/probe_table.md`.
|
||||
- ☐ **T3** (Max design) — `tools/delever.py` + `tools/delever_cycle.sh`: rungs A/B/C, group testing per TU with per-symbol attribution
|
||||
and the 2 % per-body control, shared headers greedy-on-one/verify-on-all (h_text on all), the in-memory snapshot + `inflight.json` as
|
||||
the only restore, the ledger keyed alias+tu+function+address, refusals, progress logs, negative controls, selftest with decoys.
|
||||
@@ -201,7 +203,49 @@ accumulate here as the phase produces them.**
|
||||
file-scope detectors); 14 game functions (8 in main) were assembly in C shells all along. The README prose is corrected in this commit;
|
||||
the decision log carries it at T9; Drew's word on the SDK/DECOMPILE/UNCERTAIN split is asked at the T1b report.
|
||||
|
||||
## 🛑 SESSION CHECKPOINT — S97 (2026-09-09): T0 ☑ T1 ☑ T1b ☑ (T1b's commit pending); NEXT = T2 (the probe: calibrate the object oracle, strip-all + greedy on ~150 distinct bodies, price T4–T7) at Max
|
||||
- **S97 — T2 the oracle and the probe (R37).** *The oracle* (`tools/delever_oracle.py`): every object's exact build command captured once
|
||||
through `make -n -W <src> <obj> BINARY=<alias>` (4,284 recipes, 14 s at -j16 — the Makefile's own pipeline with the jtbl pad stage of
|
||||
main/module objects, the per-object `-O0` overrides, the twin rule); a candidate compiled IN PLACE (objects carry the source path as an
|
||||
STT_FILE symbol) with `-o`/`-MF` redirected to scratch, the file restored from the in-memory snapshot after every compile; verdict =
|
||||
whole-object byte equality with `build/`'s object of the T0 fleet run. **Calibration:** `177/177 objects byte-identical untouched;
|
||||
twin checks 32 (0 mismatch); positive control DIFFERS on build/src/800.o; 2.3 s — OK` (`.run/P36/delever/calibration.json`; two
|
||||
instrument findings on the way: a control injected BEFORE the declarations is a C89 parse error, so it goes at the end of the body;
|
||||
gcc 2.7.2 reports errors without the word "error" and the assembler floods stderr with `$at` warnings — the error filter keeps
|
||||
every non-warning line, R103). *The engine* (`tools/delever.py`): positional rewrites per class at the census's line/col on the raw
|
||||
text (a token mismatch REFUSES); rung A strip-all (measured with `register` dropped and kept), rung B greedy; TUs in parallel (one
|
||||
worker per file), **shared headers SERIAL after the TU phase** — the dry run's three "compile errors" were two workers' candidates
|
||||
crossing inside one includer (a header edit reaches every includer: the campaign tool must never compile a TU while any header it
|
||||
includes is being edited). A no-op edit is REFUSED (an identical object would prove nothing, R37).
|
||||
**The probe (`--probe --sample 300 --seed 11 -j 12`; `.run/P36/probe/`):** 285 distinct bodies (one exemplar per normalized class,
|
||||
stratified by binary kind × site count × class mix, topped up for the `$0`/initializer/instruction/cast/register/launder/keep-alive
|
||||
features), 283 judged (2 NOTHING-USABLE), **1,660 compiles, 151 s wall, 0.225 s per compile, 5.87 compiles per body**.
|
||||
|
||||
| kind | bodies | A identical | A (register kept) | lever-free after B | sites | removed | needed | compiles | s/compile |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
||||
| main | 40 | 6 | 6 | 6 | 272 | 146 | 126 | 328 | 0.386 |
|
||||
| resident | 16 | 4 | 4 | 4 | 31 | 9 | 22 | 53 | 0.06 |
|
||||
| md | 29 | 2 | 2 | 2 | 121 | 56 | 65 | 161 | 0.139 |
|
||||
| shared | 40 | 7 | 7 | 7 | 164 | 65 | 99 | 216 | 0.211 |
|
||||
| ov | 158 | 34 | 34 | 34 | 721 | 285 | 436 | 902 | 0.195 |
|
||||
| **all** | **283** | **53** | **53** | **53** | **1,309** | **561 (42.9 %)** | **748 (57.1 %)** | **1,660** | **0.225** |
|
||||
|
||||
Needed by kind: pin 360 of 798 (45 %) · launder 154 of 199 (77 %) · barrier 127 of 154 (82 %) · keep-alive 36 of 44 · instruction 21
|
||||
of 24 · cast 26 of 51 · decl-body volatile 16 of 27 · bare register 8 of 12. **Needed pins by register class: v0/v1 126 · a0–a3 112 ·
|
||||
s0–s7 71 · t0–t9 36 · $0 13** (removed: s 147 · t 107 · v 90 · a 87). Residue bodies 230 of 283: 75 need only pins, 129 need at least
|
||||
one asm statement. Bodies with a launder 4/68 lever-free, a barrier 9/78, a `$0` pin 1/17, a cast 1/22, an initializer pin 7/32.
|
||||
`register` dropped vs kept: identical results (53 = 53) — the keyword is byte-neutral at -O2 on this sample. Instrument noise: rung A
|
||||
1 COMPILE-ERROR + 1 REFUSED; 6 of 748 needed sites judged by a compile error (0.8 %); 9 rewrites refused (multi-instruction
|
||||
templates, `mult`/`mfhi`, a bare `addu $v0,$zero,$zero` with no C operands, `RTP_SND` macro-carried instructions).
|
||||
**Pricing (R41; population 16,064 lever bodies / 55,913 removable sites, 2,633 distinct classes by body hash):** T4 (rungs A+B fleet-wide)
|
||||
≈ 94,000 compiles ≈ 5.9 CPU-h ≈ **0.5 h wall at 12 workers** — cheap, and it removes ≈ 24,000 sites (43 %) and frees ≈ 3,000 bodies
|
||||
(19 %). **The residue ≈ 13,000 bodies / 32,000 sites ≈ 81 % of bodies — by distinct classes ≈ 1,800 exemplars** whose copies replay:
|
||||
that is the campaign grind-to-zero prices (T6 recipes + permuter, then T7 waves). Where the residue sits: launders + barriers +
|
||||
keep-alives (317 of 748 needed = 42 %) — the CSE/scheduling steers; v0/v1 + a0–a3 pins (238 = 32 %) — argument/return-register copies
|
||||
(the §194-E/§17a ARGCOPY class); callee-saved pins (71 = 9 %) — the allocation-order class (R73, `alloc_table.py`); the rest casts,
|
||||
volatile declarations, `$0` variables, instructions. **Design consequences for T3:** per-body compiles at 0.2 s make group testing
|
||||
unnecessary (simplicity wins); run T4 first and publish the fall; rung R (T6) targets the three big classes in that order.
|
||||
|
||||
## 🛑 SESSION CHECKPOINT — S97 (2026-09-09): T0 ☑ T1 ☑ T1b ☑ T2 ☑ (T2's commit pending); NEXT = T3 (`tools/delever.py` the campaign tool: --plan/--apply, the ledger, exemplar/replay, batches + `delever_cycle.sh`, the `!FAKE` markers, refusals, selftest) at Max for the design
|
||||
|
||||
### 0. How to use this block
|
||||
A fresh session reads CLAUDE.md's load order, replays this block verbatim, asks Drew for `/effort max` (T2 is Max; T3's finish and T4–T6
|
||||
|
||||
@@ -0,0 +1,608 @@
|
||||
#!/usr/bin/env python3
|
||||
"""delever.py — take the compiler-forcing constructs ("levers") out of matched C, byte-gated per translation unit
|
||||
(Phase 36; the probe engine at T2, the campaign tool at T3).
|
||||
|
||||
tools/delever.py --probe --sample 150 [--seed 1] [-j 12] # T2: rung A + rung B on a stratified sample of DISTINCT bodies
|
||||
# -> .run/P36/probe/{probe_results.jsonl,probe_summary.json,probe_table.md}
|
||||
|
||||
THE LADDER PER BODY (deterministic, zero tokens):
|
||||
rung A strip-all — every removable site of the body rewritten at once (pin -> plain declaration; barrier/launder/keep-alive ->
|
||||
deleted; a hand-placed instruction -> its C; `$0` pin -> its variable's uses replaced by 0; volatile -> dropped; register ->
|
||||
dropped), one compile, the object compared with the fleet run's (tools/delever_oracle.py). Measured twice: with the `register`
|
||||
keyword dropped from the pin (the target form) and with it kept (A').
|
||||
rung B greedy — if A differs: from the untouched text, the sites are re-applied one at a time (asm statements first, then pins,
|
||||
volatile, register); a site whose removal keeps the object identical is REMOVED, one that changes it is NEEDED.
|
||||
The verdict of a body = the set of NEEDED sites; a body with none is lever-free. Never touched: GTE ops, the manifest's verbatim
|
||||
bodies, an asm-body (a whole routine — the manifest's DECOMPILE rows are another task's work), file-scope declarations.
|
||||
|
||||
EVERY EDIT IS POSITIONAL on the raw text (line/col from the census), the file is written in place for the compile and restored
|
||||
from the in-memory snapshot right after (never `git checkout`, R102); a site whose raw token does not match the census is REFUSED
|
||||
(R43), never guessed.
|
||||
"""
|
||||
import argparse
|
||||
import collections
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import random
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
REPO = pathlib.Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "tools"))
|
||||
import delever_oracle as oracle # noqa: E402
|
||||
import lever_census as lc # noqa: E402
|
||||
import share_census as sc # noqa: E402
|
||||
|
||||
SITES = REPO / ".run" / "P36" / "census" / "lever_sites.jsonl"
|
||||
PROBE = REPO / ".run" / "P36" / "probe"
|
||||
REMOVABLE = {("A", "pin"), ("B", "barrier"), ("B", "launder"), ("B", "keepalive"), ("B", "instruction"),
|
||||
("C", "cast"), ("C", "decl-body"), ("D", "register")}
|
||||
ORDER = {"barrier": 0, "launder": 1, "keepalive": 2, "instruction": 3, "pin": 4, "cast": 5, "decl-body": 6, "register": 7}
|
||||
STRLIT = lc.STRLIT
|
||||
|
||||
|
||||
class Refuse(Exception):
|
||||
pass
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# text helpers (positions on the RAW text; comments masked to equal-length spaces so a ';' in a comment never ends a statement)
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def same_len_mask(raw):
|
||||
return sc._TOK.sub(lambda m: re.sub(r"[^\n]", " ", m.group(0)) if m.group(0)[:2] in ("/*", "//") else m.group(0), raw)
|
||||
|
||||
|
||||
def line_starts(text):
|
||||
ls = [0]
|
||||
for ln in text.split("\n"):
|
||||
ls.append(ls[-1] + len(ln) + 1)
|
||||
return ls
|
||||
|
||||
|
||||
def stmt_end(m, pos):
|
||||
"""index just past the ';' that ends the statement starting at pos (paren depth 0, string literals skipped); -1 if none."""
|
||||
depth, i, n = 0, pos, len(m)
|
||||
while i < n:
|
||||
c = m[i]
|
||||
if c == '"':
|
||||
mm = STRLIT.match(m, i)
|
||||
i = mm.end() if mm else i + 1
|
||||
continue
|
||||
if c == "(":
|
||||
depth += 1
|
||||
elif c == ")":
|
||||
depth -= 1
|
||||
elif c == ";" and depth <= 0:
|
||||
return i + 1
|
||||
elif c == "}" and depth == 0:
|
||||
return -1
|
||||
i += 1
|
||||
return -1
|
||||
|
||||
|
||||
def ws_after(m, pos):
|
||||
i = pos
|
||||
while i < len(m) and m[i] in " \t":
|
||||
i += 1
|
||||
return i
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# the rewrite of one site -> [(start, end, replacement)] on the raw text
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
ASM_HEAD = re.compile(r"(?:__asm__|__asm|asm)\s*(?:__volatile__|volatile)?\s*\(")
|
||||
PIN_CLAUSE = re.compile(r"\s*(?:__asm__|__asm|asm)\s*\(\s*\"[^\"]*\"\s*\)")
|
||||
INSTR_TABLE = {
|
||||
# mnemonic -> (arity, C template) using OUT / IN1 / IN2 / IMM; the operands come from the asm's "=r"(..) / "r"(..) lists
|
||||
"addu": ("OUT = IN1;", "zero"), "move": ("OUT = IN1;", None), "addiu": ("OUT = IN1 + IMM;", None), "sll": ("OUT = IN1 << IMM;", None),
|
||||
"srl": ("OUT = (u32)IN1 >> IMM;", None), "and": ("OUT = IN1 & IN2;", None), "andi": ("OUT = IN1 & IMM;", None),
|
||||
"lui": ("OUT = IMM << 16;", None), "li": ("OUT = IMM;", None), "lw": ("OUT = *(s32 *)((s32)IN1 + IMM);", None),
|
||||
"lh": ("OUT = *(s16 *)((s32)IN1 + IMM);", None), "la": ("OUT = (s32)&SYM;", None),
|
||||
}
|
||||
|
||||
|
||||
def parse_asm_operands(inner):
|
||||
"""(template, outputs, inputs) — outputs/inputs as [(constraint, expr)]; the asm's own parser rules (lever_census)."""
|
||||
s = inner.strip()
|
||||
parts, i, n = [], 0, len(s)
|
||||
while i < n:
|
||||
if s[i] in " \t\r\n":
|
||||
i += 1
|
||||
continue
|
||||
mm = STRLIT.match(s, i)
|
||||
if not mm:
|
||||
break
|
||||
parts.append(mm.group(0)[1:-1])
|
||||
i = mm.end()
|
||||
rest = s[i:].strip()
|
||||
secs = lc._split_sections(rest[1:]) if rest.startswith(":") else []
|
||||
def ops(sec):
|
||||
out = []
|
||||
for mm in re.finditer(r'"([^"]*)"\s*\(', sec):
|
||||
c = lc._paren_span(sec, mm.end() - 1)
|
||||
out.append((mm.group(1), sec[mm.end():c].strip()))
|
||||
return out
|
||||
outs = ops(secs[0]) if len(secs) > 0 else []
|
||||
ins = ops(secs[1]) if len(secs) > 1 else []
|
||||
return "".join(parts), outs, ins
|
||||
|
||||
|
||||
def instruction_to_c(inner, indent):
|
||||
"""The C statement for a hand-placed single-instruction asm, or None (residue)."""
|
||||
tmpl, outs, ins = parse_asm_operands(inner)
|
||||
t = re.sub(r"\\[nt]", " ", tmpl).strip()
|
||||
if len(outs) != 1:
|
||||
return None
|
||||
out_expr = outs[0][1]
|
||||
allops = [e for _, e in outs] + [e for _, e in ins]
|
||||
def resolve(tok):
|
||||
mm = re.fullmatch(r"%(\d+)", tok)
|
||||
if mm:
|
||||
k = int(mm.group(1))
|
||||
return allops[k] if k < len(allops) else None
|
||||
return None
|
||||
IMM = r"-?(?:0x[0-9A-Fa-f]+|\d+)"
|
||||
# two-instruction address / constant materializations (one C expression each)
|
||||
mm = re.fullmatch(r"lui\s+%0\s*,\s*%%hi\((\w+)\)\s*;?\s*addiu\s+%0\s*,\s*%0\s*,\s*%%lo\(\1\)", t)
|
||||
if mm:
|
||||
return f"{indent}{out_expr} = (s32)&{mm.group(1)};"
|
||||
mm = re.fullmatch(r"lui\s+%0\s*,\s*(" + IMM + r")\s*;?\s*ori\s+%0\s*,\s*%0\s*,\s*(" + IMM + r")", t)
|
||||
if mm:
|
||||
return f"{indent}{out_expr} = ({mm.group(1)} << 16) | {mm.group(2)};"
|
||||
if ";" in t or "\n" in t:
|
||||
return None # other multi-instruction templates are residue
|
||||
toks = [x for x in re.split(r"[\s,]+", t) if x]
|
||||
if not toks:
|
||||
return None
|
||||
mnem = toks[0].lower()
|
||||
if mnem not in INSTR_TABLE:
|
||||
return None
|
||||
templ, note = INSTR_TABLE[mnem]
|
||||
refs = [x for x in toks[1:]]
|
||||
if mnem == "addu":
|
||||
if len(refs) != 3:
|
||||
return None
|
||||
if refs[2] in ("$zero", "$0"):
|
||||
in1 = resolve(refs[1])
|
||||
return None if in1 is None else f"{indent}{out_expr} = {in1};"
|
||||
in1, in2 = resolve(refs[1]), resolve(refs[2])
|
||||
return None if in1 is None or in2 is None else f"{indent}{out_expr} = (s32){in1} + (s32){in2};"
|
||||
if mnem == "addiu" and len(refs) == 3 and refs[1] in ("$zero", "$0") and re.fullmatch(IMM, refs[2]):
|
||||
return f"{indent}{out_expr} = {refs[2]};"
|
||||
if mnem == "move":
|
||||
if len(refs) != 2:
|
||||
return None
|
||||
in1 = resolve(refs[1])
|
||||
return None if in1 is None else f"{indent}{out_expr} = {in1};"
|
||||
if mnem == "la":
|
||||
if len(refs) != 2 or not re.fullmatch(r"[A-Za-z_]\w*", refs[1]):
|
||||
return None
|
||||
return f"{indent}{out_expr} = (s32)&{refs[1]};"
|
||||
if mnem in ("lw", "lh"):
|
||||
mm = re.fullmatch(r"(-?\w+)\((%\d+)\)", refs[1]) if len(refs) == 2 else None
|
||||
if not mm:
|
||||
return None
|
||||
base = resolve(mm.group(2))
|
||||
return None if base is None else templ.replace("OUT", out_expr).replace("IN1", base).replace("IMM", mm.group(1)) and f"{indent}{templ.replace('OUT', out_expr).replace('IN1', base).replace('IMM', mm.group(1))}"
|
||||
if mnem in ("addiu", "sll", "srl", "andi"):
|
||||
if len(refs) != 3:
|
||||
return None
|
||||
in1 = resolve(refs[1])
|
||||
if in1 is None or not re.fullmatch(IMM, refs[2]):
|
||||
return None
|
||||
return f"{indent}{templ.replace('OUT', out_expr).replace('IN1', '(s32)' + in1).replace('IMM', refs[2])}"
|
||||
if mnem == "and":
|
||||
if len(refs) != 3:
|
||||
return None
|
||||
in1, in2 = resolve(refs[1]), resolve(refs[2])
|
||||
return None if in1 is None or in2 is None else f"{indent}{out_expr} = (s32){in1} & (s32){in2};"
|
||||
if mnem in ("lui", "li"):
|
||||
if len(refs) != 2 or not re.fullmatch(r"-?(?:0x[0-9A-Fa-f]+|\d+)", refs[1]):
|
||||
return None
|
||||
return f"{indent}{templ.replace('OUT', out_expr).replace('IMM', refs[1])}"
|
||||
return None
|
||||
|
||||
|
||||
def site_edits(raw, m, ls, site, keep_register=False):
|
||||
"""[(start, end, replacement)] for one site, or raise Refuse. `m` = same_len_mask(raw)."""
|
||||
pos = ls[site["line"] - 1] + site["col"] - 1
|
||||
cls, kind = site["cls"], site["kind"]
|
||||
indent_start = m.rfind("\n", 0, pos) + 1
|
||||
indent = re.match(r"[ \t]*", raw[indent_start:pos]).group(0)
|
||||
if cls == "A":
|
||||
if not m.startswith("register", pos):
|
||||
raise Refuse(f"token mismatch at {site['tu']}:{site['line']}: expected `register`")
|
||||
e = stmt_end(m, pos)
|
||||
if e < 0:
|
||||
raise Refuse(f"no statement end for the pin at {site['tu']}:{site['line']}")
|
||||
stmt = raw[pos:e]
|
||||
if site.get("zero"):
|
||||
# the zero-register variable: delete the declaration, replace every use in the body by 0
|
||||
mm = re.search(r"([A-Za-z_]\w*)\s*(?:__asm__|__asm|asm)\s*\(", stmt)
|
||||
if not mm:
|
||||
raise Refuse("zero pin without a name")
|
||||
name = mm.group(1)
|
||||
edits = [(indent_start if raw[indent_start:pos].strip() == "" else pos, e + (1 if raw[e:e + 1] == "\n" and raw[indent_start:pos].strip() == "" else 0), "")]
|
||||
b0, b1 = ls[site["fn_line"] - 1], ls[site["fn_end"]] - 1
|
||||
for um in re.finditer(r"\b%s\b" % re.escape(name), m[b0:b1]):
|
||||
s = b0 + um.start()
|
||||
if s < pos or s >= e:
|
||||
edits.append((s, s + len(name), "0"))
|
||||
return edits
|
||||
new = stmt if keep_register else re.sub(r"\bregister\b[ \t]*", "", stmt, count=1)
|
||||
new = PIN_CLAUSE.sub("", new)
|
||||
return [(pos, e, new)]
|
||||
if cls == "B" and site.get("via"):
|
||||
name = site["via"]
|
||||
if not m.startswith(name, pos):
|
||||
raise Refuse(f"token mismatch at {site['tu']}:{site['line']}: expected `{name}(`")
|
||||
if kind not in ("barrier", "launder", "keepalive"):
|
||||
raise Refuse(f"macro-carried {kind} is residue")
|
||||
e = stmt_end(m, pos)
|
||||
if e < 0:
|
||||
raise Refuse("no statement end for the macro use")
|
||||
whole_line = raw[indent_start:pos].strip() == "" and raw[e:ws_after(m, e)].strip() == "" and raw[ws_after(m, e):ws_after(m, e) + 1] == "\n"
|
||||
return [(indent_start, ws_after(m, e) + 1, "")] if whole_line else [(pos, e, "")]
|
||||
if cls == "B":
|
||||
if not ASM_HEAD.match(m, pos):
|
||||
raise Refuse(f"token mismatch at {site['tu']}:{site['line']}: expected an asm statement")
|
||||
o = m.find("(", pos)
|
||||
c = lc._paren_span(m, o)
|
||||
e = stmt_end(m, pos)
|
||||
if c < 0 or e < 0:
|
||||
raise Refuse("unterminated asm statement")
|
||||
if kind in ("barrier", "launder", "keepalive"):
|
||||
new = ""
|
||||
elif kind == "instruction":
|
||||
new = instruction_to_c(m[o + 1:c] if '"' in m[o + 1:c] else raw[o + 1:c], "")
|
||||
if new is None:
|
||||
raise Refuse(f"instruction `{site['detail']}` has no C spelling in the table")
|
||||
new = new.strip()
|
||||
else:
|
||||
raise Refuse(f"asm kind {kind} is not removable")
|
||||
whole_line = raw[indent_start:pos].strip() == "" and raw[e:ws_after(m, e)].strip() == "" and raw[ws_after(m, e):ws_after(m, e) + 1] == "\n"
|
||||
if new == "" and whole_line:
|
||||
return [(indent_start, ws_after(m, e) + 1, "")]
|
||||
return [(pos, e, new)]
|
||||
if cls == "C":
|
||||
if not m.startswith("volatile", pos):
|
||||
raise Refuse(f"token mismatch at {site['tu']}:{site['line']}: expected `volatile`")
|
||||
return [(pos, ws_after(m, pos + len("volatile")), "")]
|
||||
if cls == "D":
|
||||
if not m.startswith("register", pos):
|
||||
raise Refuse(f"token mismatch at {site['tu']}:{site['line']}: expected `register`")
|
||||
return [(pos, ws_after(m, pos + len("register")), "")]
|
||||
raise Refuse(f"class {cls}/{kind} is not removable")
|
||||
|
||||
|
||||
def apply_edits(raw, edits):
|
||||
"""Splice non-overlapping edits (bottom-up). Overlap -> Refuse."""
|
||||
es = sorted(edits, key=lambda x: (x[0], x[1]))
|
||||
for a, b in zip(es, es[1:]):
|
||||
if b[0] < a[1]:
|
||||
raise Refuse(f"overlapping edits at {a[0]}..{a[1]} / {b[0]}..{b[1]}")
|
||||
out = raw
|
||||
for s, e, r in sorted(es, key=lambda x: -x[0]):
|
||||
out = out[:s] + r + out[e:]
|
||||
return out
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# the population
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def load_sites():
|
||||
return [json.loads(l) for l in SITES.read_text().splitlines() if l.strip()]
|
||||
|
||||
|
||||
def bodies_from_sites(sites):
|
||||
bodies = {}
|
||||
for s in sites:
|
||||
if not s.get("fn"):
|
||||
continue
|
||||
b = bodies.setdefault((s["tu"], s["fn"]), dict(tu=s["tu"], fn=s["fn"], fn_line=s["fn_line"], fn_end=s["fn_end"], nhash=s.get("nhash"),
|
||||
aliases=s["aliases"], header=s.get("header", False), sites=[], frozen=[]))
|
||||
if (s["cls"], s["kind"]) in REMOVABLE:
|
||||
b["sites"].append(s)
|
||||
else:
|
||||
b["frozen"].append(s)
|
||||
return bodies
|
||||
|
||||
|
||||
def kind_of(tu):
|
||||
return "shared" if tu.startswith("src/shared/") else "ov" if tu.startswith("src/ov_") else "md" if tu.startswith("src/md_") \
|
||||
else "resident" if tu.startswith("src/resident/") else "main"
|
||||
|
||||
|
||||
def includers():
|
||||
"""header rel -> [TU rel] from the #include lines of every TU (the recipe to compile a header's body is an includer's)."""
|
||||
inc = collections.defaultdict(list)
|
||||
for p in sorted((REPO / "src").rglob("*.c")):
|
||||
rel = p.relative_to(REPO).as_posix()
|
||||
text = p.read_text(errors="surrogateescape")
|
||||
for mm in sc.INCLUDE_LINE.finditer(sc.mask_text(text)):
|
||||
inc[os.path.normpath(os.path.join(os.path.dirname(rel), mm.group(1)))].append(rel)
|
||||
return inc
|
||||
|
||||
|
||||
def features(b):
|
||||
ks = collections.Counter(s["kind"] for s in b["sites"])
|
||||
n = len(b["sites"])
|
||||
mix = "pins-only" if set(ks) <= {"pin"} else "asm-only" if not (set(ks) & {"pin", "cast", "decl-body", "register"}) else "mixed"
|
||||
return dict(kind=kind_of(b["tu"]), n=n, bucket=("1" if n == 1 else "2-4" if n <= 4 else "5-9" if n <= 9 else "10+"), mix=mix,
|
||||
zero=any(s.get("zero") for s in b["sites"]), init=any(s.get("init") for s in b["sites"] if s["kind"] == "pin"),
|
||||
instr=any(s["kind"] == "instruction" for s in b["sites"]), cast=any(s["kind"] == "cast" for s in b["sites"]),
|
||||
register=any(s["kind"] == "register" for s in b["sites"]), volatile=any(s["cls"] == "C" for s in b["sites"]),
|
||||
launder=any(s["kind"] == "launder" for s in b["sites"]), barrier=any(s["kind"] == "barrier" for s in b["sites"]),
|
||||
keepalive=any(s["kind"] == "keepalive" for s in b["sites"]))
|
||||
|
||||
|
||||
def stratified_sample(bodies, n, seed):
|
||||
rnd = random.Random(seed)
|
||||
# one exemplar per normalized class
|
||||
by_class = {}
|
||||
for key, b in bodies.items():
|
||||
if not b["sites"]:
|
||||
continue
|
||||
h = b["nhash"] or key
|
||||
cur = by_class.get(h)
|
||||
pref = {"main": 0, "resident": 1, "md": 2, "shared": 3, "ov": 4}[kind_of(b["tu"])]
|
||||
if cur is None or pref < cur[0]:
|
||||
by_class[h] = (pref, key)
|
||||
pool = [bodies[k] for _, k in by_class.values()]
|
||||
rnd.shuffle(pool)
|
||||
# quotas scale with --sample (the shape of the population: main/resident/md are few but distinct, overlays are many)
|
||||
base = {"main": 20, "resident": 16, "md": 15, "shared": 20, "ov": 79}
|
||||
scale = n / sum(base.values())
|
||||
quota = {k: max(3, int(round(v * scale))) for k, v in base.items()}
|
||||
picked, seen = [], set()
|
||||
for kind, q in quota.items():
|
||||
cands = [b for b in pool if kind_of(b["tu"]) == kind]
|
||||
# round-robin over (bucket, mix)
|
||||
groups = collections.defaultdict(list)
|
||||
for b in cands:
|
||||
f = features(b)
|
||||
groups[(f["bucket"], f["mix"])].append(b)
|
||||
keys = sorted(groups)
|
||||
i = 0
|
||||
while len([b for b in picked if kind_of(b["tu"]) == kind]) < q and any(groups[k] for k in keys):
|
||||
k = keys[i % len(keys)]
|
||||
i += 1
|
||||
if groups[k]:
|
||||
b = groups[k].pop()
|
||||
if (b["tu"], b["fn"]) not in seen:
|
||||
picked.append(b)
|
||||
seen.add((b["tu"], b["fn"]))
|
||||
# the special features, topped up from the pool
|
||||
for flag, want in (("zero", 10), ("init", 10), ("instr", 12), ("cast", 8), ("register", 5), ("launder", 8), ("keepalive", 6)):
|
||||
have = sum(1 for b in picked if features(b)[flag])
|
||||
for b in pool:
|
||||
if have >= want:
|
||||
break
|
||||
if (b["tu"], b["fn"]) not in seen and features(b)[flag]:
|
||||
picked.append(b)
|
||||
seen.add((b["tu"], b["fn"]))
|
||||
have += 1
|
||||
return picked
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# the ladder on one body
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def run_body(b, recipe, write_path, raw, m, ls, log):
|
||||
"""Returns the per-body result dict; the caller restores the file."""
|
||||
sites = sorted(b["sites"], key=lambda s: (ORDER.get(s["kind"], 9), s["line"], s["col"]))
|
||||
res = dict(tu=b["tu"], fn=b["fn"], nhash=b["nhash"], kind=kind_of(b["tu"]), aliases=b["aliases"], header=b["header"],
|
||||
obj=recipe["obj"], n_sites=len(sites), sites=[dict(kind=s["kind"], cls=s["cls"], detail=s["detail"], line=s["line"]) for s in sites],
|
||||
refused=[], compiles=0, seconds=0.0, features=features(b))
|
||||
per_site, edits_all, edits_keep = {}, [], []
|
||||
usable = []
|
||||
for s in sites:
|
||||
try:
|
||||
ed = site_edits(raw, m, ls, s)
|
||||
edk = site_edits(raw, m, ls, s, keep_register=True) if s["kind"] == "pin" else ed
|
||||
per_site[id(s)] = (ed, edk)
|
||||
usable.append(s)
|
||||
edits_all += ed
|
||||
edits_keep += edk
|
||||
except Refuse as ex:
|
||||
res["refused"].append(dict(kind=s["kind"], line=s["line"], why=str(ex)))
|
||||
res["n_usable"] = len(usable)
|
||||
if not usable:
|
||||
res["verdict"] = "NOTHING-USABLE"
|
||||
return res
|
||||
|
||||
def judge(edits, tag):
|
||||
try:
|
||||
cand = apply_edits(raw, edits)
|
||||
except Refuse as ex:
|
||||
return "REFUSED", str(ex)
|
||||
if cand == raw:
|
||||
return "REFUSED", "no-op edit (the candidate equals the original — an identical object would prove nothing, R37)"
|
||||
v, dt, err = oracle.judge(recipe, cand, tag=tag, write_path=write_path)
|
||||
res["compiles"] += 1
|
||||
res["seconds"] += dt
|
||||
return v, err
|
||||
# rung A (register dropped) and A' (register kept)
|
||||
vA, errA = judge(edits_all, "A")
|
||||
res["rung_A"] = vA
|
||||
res["rung_A_err"] = errA[:200] if vA == "COMPILE-ERROR" else ""
|
||||
if any(s["kind"] == "pin" for s in usable):
|
||||
vK, _ = judge(edits_keep, "Ak")
|
||||
res["rung_A_keep_register"] = vK
|
||||
else:
|
||||
res["rung_A_keep_register"] = vA
|
||||
if vA == "IDENTICAL":
|
||||
res["removed"] = [dict(kind=s["kind"], detail=s["detail"], line=s["line"]) for s in usable]
|
||||
res["needed"] = []
|
||||
res["verdict"] = "LEVER-FREE"
|
||||
return res
|
||||
# rung B greedy
|
||||
accepted, needed, removed = [], [], []
|
||||
for s in usable:
|
||||
ed, _ = per_site[id(s)]
|
||||
v, err = judge(accepted + ed, "B")
|
||||
if v == "IDENTICAL":
|
||||
accepted += ed
|
||||
removed.append(dict(kind=s["kind"], detail=s["detail"], line=s["line"]))
|
||||
else:
|
||||
needed.append(dict(kind=s["kind"], detail=s["detail"], line=s["line"], verdict=v, err=(err[:120] if v == "COMPILE-ERROR" else "")))
|
||||
res["removed"], res["needed"] = removed, needed
|
||||
res["verdict"] = "LEVER-FREE" if not needed else "RESIDUE"
|
||||
log(f" {b['tu']}:{b['fn']} A={vA} B: removed {len(removed)} needed {len(needed)} compiles {res['compiles']}")
|
||||
return res
|
||||
|
||||
|
||||
def probe(sample_n, seed, jobs):
|
||||
PROBE.mkdir(parents=True, exist_ok=True)
|
||||
ok, why = oracle.calibration_current()
|
||||
if not ok:
|
||||
sys.exit(f"delever: the oracle's calibration is not current ({why}) — run tools/delever_oracle.py --calibrate first (R56)")
|
||||
recipes = oracle.load_recipes()["recipes"]
|
||||
sites = load_sites()
|
||||
bodies = bodies_from_sites(sites)
|
||||
inc = includers()
|
||||
sample = stratified_sample(bodies, sample_n, seed)
|
||||
log_f = open(PROBE / "probe_log.txt", "a")
|
||||
|
||||
def log(msg):
|
||||
line = f"{time.strftime('%H:%M:%S')} {msg}"
|
||||
print(line, flush=True)
|
||||
log_f.write(line + "\n")
|
||||
log_f.flush()
|
||||
log(f"probe: {len(sample)} bodies sampled from {len(bodies)} lever bodies ({len({b['nhash'] for b in bodies.values() if b['sites']})} distinct classes); seed {seed}")
|
||||
# group by the FILE that gets written (a TU, or a header) — one worker per file
|
||||
by_file = collections.defaultdict(list)
|
||||
for b in sample:
|
||||
by_file[b["tu"]].append(b)
|
||||
|
||||
def work(tu):
|
||||
out = []
|
||||
if tu.endswith(".h"):
|
||||
tus = [t for t in inc.get(tu, []) if ("build/" + t[:-2] + ".o") in recipes]
|
||||
if not tus:
|
||||
return [dict(tu=tu, fn=b["fn"], verdict="NO-INCLUDER-RECIPE") for b in by_file[tu]]
|
||||
recipe = recipes["build/" + tus[0][:-2] + ".o"]
|
||||
write_path = tu
|
||||
else:
|
||||
obj = "build/" + tu[:-2] + ".o"
|
||||
if obj not in recipes:
|
||||
return [dict(tu=tu, fn=b["fn"], verdict="NO-RECIPE") for b in by_file[tu]]
|
||||
recipe = recipes[obj]
|
||||
write_path = None
|
||||
path = REPO / tu
|
||||
raw = path.read_text(errors="surrogateescape")
|
||||
m = same_len_mask(raw)
|
||||
ls = line_starts(raw)
|
||||
try:
|
||||
for b in by_file[tu]:
|
||||
out.append(run_body(b, recipe, write_path, raw, m, ls, log))
|
||||
finally:
|
||||
path.write_text(raw, errors="surrogateescape")
|
||||
return out
|
||||
results = []
|
||||
t0 = time.time()
|
||||
# phase 1: translation units, one worker per TU (no two candidates of one file at once, and no header is being edited);
|
||||
# phase 2: shared headers, SERIAL — a header's edit reaches every includer, so nothing else may compile meanwhile
|
||||
# (the dry run's three "compile errors" were two workers' candidates crossing inside one includer)
|
||||
tu_files = sorted(f for f in by_file if not f.endswith(".h"))
|
||||
hdr_files = sorted(f for f in by_file if f.endswith(".h"))
|
||||
with ThreadPoolExecutor(max_workers=jobs) as ex:
|
||||
for r in ex.map(work, tu_files):
|
||||
results.extend(r)
|
||||
for f in hdr_files:
|
||||
results.extend(work(f))
|
||||
wall = time.time() - t0
|
||||
with open(PROBE / "probe_results.jsonl", "w") as f:
|
||||
for r in results:
|
||||
f.write(json.dumps(r) + "\n")
|
||||
summary = summarize(results, bodies, wall, seed)
|
||||
(PROBE / "probe_summary.json").write_text(json.dumps(summary, indent=1) + "\n")
|
||||
(PROBE / "probe_table.md").write_text(render(summary) + "\n")
|
||||
print(render(summary))
|
||||
return summary
|
||||
|
||||
|
||||
def summarize(results, bodies, wall, seed):
|
||||
judged = [r for r in results if r.get("verdict") in ("LEVER-FREE", "RESIDUE")]
|
||||
def pct(a, b):
|
||||
return round(100.0 * a / b, 1) if b else None
|
||||
by_kind = {}
|
||||
for k in ("main", "resident", "md", "shared", "ov"):
|
||||
rs = [r for r in judged if r["kind"] == k]
|
||||
if not rs:
|
||||
continue
|
||||
by_kind[k] = dict(bodies=len(rs), A_identical=sum(1 for r in rs if r["rung_A"] == "IDENTICAL"),
|
||||
A_keep_register_identical=sum(1 for r in rs if r.get("rung_A_keep_register") == "IDENTICAL"),
|
||||
lever_free=sum(1 for r in rs if r["verdict"] == "LEVER-FREE"),
|
||||
sites=sum(r["n_usable"] for r in rs), removed=sum(len(r["removed"]) for r in rs), needed=sum(len(r["needed"]) for r in rs),
|
||||
compiles=sum(r["compiles"] for r in rs), mean_s_per_compile=round(sum(r["seconds"] for r in rs) / max(sum(r["compiles"] for r in rs), 1), 3))
|
||||
needed_kinds = collections.Counter(n["kind"] for r in judged for n in r["needed"])
|
||||
needed_detail = collections.Counter(f"{n['kind']}:{n['detail']}" for r in judged for n in r["needed"])
|
||||
removed_kinds = collections.Counter(x["kind"] for r in judged for x in r["removed"])
|
||||
refused = collections.Counter(x["why"].split(":")[0][:60] for r in results for x in r.get("refused", []))
|
||||
sites_total = sum(r["n_usable"] for r in judged)
|
||||
sites_needed = sum(len(r["needed"]) for r in judged)
|
||||
flags = {}
|
||||
for flag in ("zero", "init", "instr", "cast", "register", "launder", "barrier", "keepalive", "volatile"):
|
||||
rs = [r for r in judged if r["features"].get(flag)]
|
||||
flags[flag] = dict(bodies=len(rs), lever_free=sum(1 for r in rs if r["verdict"] == "LEVER-FREE"))
|
||||
pop_bodies = sum(1 for b in bodies.values() if b["sites"])
|
||||
pop_sites = sum(len(b["sites"]) for b in bodies.values())
|
||||
mean_compiles = sum(r["compiles"] for r in judged) / max(len(judged), 1)
|
||||
mean_s = sum(r["seconds"] for r in judged) / max(sum(r["compiles"] for r in judged), 1)
|
||||
return dict(generated=time.strftime("%Y-%m-%d %H:%M"), seed=seed, sampled=len(results), judged=len(judged),
|
||||
not_judged=collections.Counter(r.get("verdict") for r in results if r not in judged),
|
||||
rung_A_identical=sum(1 for r in judged if r["rung_A"] == "IDENTICAL"),
|
||||
rung_A_keep_register_identical=sum(1 for r in judged if r.get("rung_A_keep_register") == "IDENTICAL"),
|
||||
lever_free_after_B=sum(1 for r in judged if r["verdict"] == "LEVER-FREE"),
|
||||
sites=dict(total=sites_total, removed=sites_total - sites_needed, needed=sites_needed, pct_removed=pct(sites_total - sites_needed, sites_total)),
|
||||
needed_by_kind=dict(needed_kinds), needed_by_detail=dict(needed_detail.most_common(30)), removed_by_kind=dict(removed_kinds),
|
||||
refused=dict(refused), by_kind=by_kind, flags=flags,
|
||||
compiles=sum(r["compiles"] for r in judged), mean_compiles_per_body=round(mean_compiles, 2), mean_s_per_compile=round(mean_s, 3),
|
||||
wall_s=round(wall, 1),
|
||||
population=dict(bodies=pop_bodies, sites=pop_sites),
|
||||
pricing=dict(T4_compiles_est=int(pop_bodies * mean_compiles), T4_cpu_hours_est=round(pop_bodies * mean_compiles * mean_s / 3600, 2),
|
||||
T4_wall_hours_at_16_est=round(pop_bodies * mean_compiles * mean_s / 3600 / 12, 2),
|
||||
residue_bodies_est=int(pop_bodies * (1 - (sum(1 for r in judged if r["verdict"] == "LEVER-FREE") / max(len(judged), 1)))),
|
||||
residue_sites_est=int(pop_sites * (sites_needed / max(sites_total, 1)))))
|
||||
|
||||
|
||||
def render(s):
|
||||
L = [f"# probe — {s['sampled']} bodies sampled, {s['judged']} judged (seed {s['seed']}, {s['generated']}, wall {s['wall_s']} s)", "",
|
||||
f"- rung A (strip-all) identical: **{s['rung_A_identical']} / {s['judged']}** (register dropped) · {s['rung_A_keep_register_identical']} with `register` kept",
|
||||
f"- lever-free after rung B: **{s['lever_free_after_B']} / {s['judged']}**",
|
||||
f"- sites: {s['sites']['total']} usable · removed {s['sites']['removed']} ({s['sites']['pct_removed']} %) · needed {s['sites']['needed']}",
|
||||
f"- needed by kind: {s['needed_by_kind']}", f"- needed by detail (top): {s['needed_by_detail']}",
|
||||
f"- removed by kind: {s['removed_by_kind']}", f"- refused (rewrite not applicable): {s['refused']}",
|
||||
f"- compiles {s['compiles']} · mean {s['mean_compiles_per_body']} per body · {s['mean_s_per_compile']} s per compile", "",
|
||||
"| kind | bodies | A identical | A (register kept) | lever-free after B | sites | removed | needed | compiles | s/compile |", "|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|"]
|
||||
for k, v in s["by_kind"].items():
|
||||
L.append(f"| {k} | {v['bodies']} | {v['A_identical']} | {v['A_keep_register_identical']} | {v['lever_free']} | {v['sites']} | {v['removed']} | {v['needed']} | {v['compiles']} | {v['mean_s_per_compile']} |")
|
||||
L += ["", "| feature | bodies | lever-free |", "|---|---:|---:|"]
|
||||
for k, v in s["flags"].items():
|
||||
L.append(f"| {k} | {v['bodies']} | {v['lever_free']} |")
|
||||
p = s["pricing"]
|
||||
L += ["", f"**Pricing (R41; population {s['population']['bodies']:,} lever bodies / {s['population']['sites']:,} removable sites):** "
|
||||
f"T4 ≈ {p['T4_compiles_est']:,} compiles ≈ {p['T4_cpu_hours_est']} CPU-h ≈ {p['T4_wall_hours_at_16_est']} h wall at 12 workers; "
|
||||
f"residue after the mechanical ladder ≈ {p['residue_bodies_est']:,} bodies / {p['residue_sites_est']:,} sites (the sample's rates applied to the population)."]
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
|
||||
ap.add_argument("--probe", action="store_true")
|
||||
ap.add_argument("--sample", type=int, default=150)
|
||||
ap.add_argument("--seed", type=int, default=1)
|
||||
ap.add_argument("-j", "--jobs", type=int, default=12)
|
||||
a = ap.parse_args()
|
||||
if a.probe:
|
||||
probe(a.sample, a.seed, a.jobs)
|
||||
return
|
||||
ap.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,303 @@
|
||||
#!/usr/bin/env python3
|
||||
"""delever_oracle.py — the fast byte oracle for a single-translation-unit source edit (Phase 36 T2, 2026-09-09).
|
||||
|
||||
tools/delever_oracle.py --recipes [-j N] # capture every object's exact build command via `make -n -W` -> .run/P36/delever/recipes.json
|
||||
tools/delever_oracle.py --calibrate ov_SC04_011 main # compile every TU of the named binaries UNTOUCHED: 100 % object equality with build/,
|
||||
# twin == primary, then the POSITIVE control (a nop injected -> DIFFERS); exit 1 otherwise
|
||||
tools/delever_oracle.py --status # is the calibration current for this HEAD / Makefile?
|
||||
|
||||
THE QUESTION IT ANSWERS: "does this candidate text for TU X still produce the byte-identical object?" — and only that. The whole-binary
|
||||
gate (`make check BINARY=…`, and the clean fleet run, R22) remains the arbiter of every batch; this oracle is the inner loop that
|
||||
decides one lever site at a time in ~0.3–5 s instead of ~90 s.
|
||||
|
||||
HOW (the design settled at gate 1 + the plan agent's review, R57: the instrument's own path is part of the instrument):
|
||||
* the recipe of every object is the Makefile's OWN command, printed by `make -n -W <src> <obj> BINARY=<alias>` (0.04–0.15 s each;
|
||||
captured once per Makefile/config state, ~4,300 objects at -j16 in ~30 s). It carries the per-object -O0 overrides, the
|
||||
jtbl_rodata_pads stage of main/module objects, the reorder island, the twin rule (the primary's source into the twin's object).
|
||||
tools/compile_only.py's re-typed pipeline omits the pad stage and is NOT used.
|
||||
* a candidate compiles IN PLACE at the real path (objects embed the source path as an STT_FILE symbol) with `-o` and `-MF`
|
||||
redirected to scratch — build/ is never written, so the baseline object of the fleet run stays the reference; the TU's text is
|
||||
restored from the caller's in-memory snapshot (never `git checkout`, R102). Workers own whole TUs: no two candidates of one TU at once.
|
||||
* verdict = whole-object byte equality with build/<obj> (R56: build/ must come from a clean fleet run of THIS tree — --calibrate proves it).
|
||||
* CALIBRATION (R39/R57): every sampled TU compiled untouched reproduces its object byte for byte; a twin's object equals its primary's;
|
||||
a deliberately altered body reports DIFFERS. `.run/P36/delever/calibration.json` records HEAD, the Makefile/config mtimes and the
|
||||
per-object seconds (the scheduler's cost model); an --apply of the de-lever tool refuses without a current calibration.
|
||||
"""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
REPO = pathlib.Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "tools"))
|
||||
|
||||
RUN = REPO / ".run" / "P36" / "delever"
|
||||
RECIPES = RUN / "recipes.json"
|
||||
CALIB = RUN / "calibration.json"
|
||||
SCRATCH = RUN / "obj"
|
||||
RECIPE_RE = re.compile(r"^set -o pipefail; (.*) -o (build/\S+\.o)$")
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# enumeration: (alias, src, obj) for every object of every binary — derived from the Makefile's own rules (R33)
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def src_dirs():
|
||||
import corpus
|
||||
return dict(corpus.src_dirs())
|
||||
|
||||
|
||||
def twin_of_map():
|
||||
import share_census
|
||||
return share_census.twin_of_map()
|
||||
|
||||
|
||||
def objects(aliases=None):
|
||||
"""[(alias, src_rel, obj_rel)] — the pattern rule build/src/%.o: src/%.c, and for a twin the primary's sources renamed into the
|
||||
twin's own object names (Makefile twin block)."""
|
||||
import compile_only
|
||||
dirs = src_dirs()
|
||||
twins = twin_of_map()
|
||||
out = []
|
||||
for a in sorted(dirs):
|
||||
if aliases and a not in aliases:
|
||||
continue
|
||||
prim = twins.get(a)
|
||||
for p in compile_only.tus_of(a, dirs):
|
||||
src = p.relative_to(REPO).as_posix()
|
||||
if prim:
|
||||
# src/<prim>/<prim><suffix>.c -> build/src/<twin>/<twin><suffix>.o
|
||||
stem = p.name[:-2]
|
||||
if not stem.startswith(prim):
|
||||
continue
|
||||
obj = f"build/src/{a}/{a}{stem[len(prim):]}.o"
|
||||
else:
|
||||
obj = "build/" + src[:-2] + ".o"
|
||||
out.append((a, src, obj))
|
||||
return out
|
||||
|
||||
|
||||
def config_stamp():
|
||||
files = [REPO / "Makefile"] + sorted((REPO / "config").glob("*.mk"))
|
||||
h = hashlib.sha1()
|
||||
for f in files:
|
||||
st = f.stat()
|
||||
h.update(f"{f.name}|{int(st.st_mtime)}|{st.st_size}\n".encode())
|
||||
return h.hexdigest()[:12]
|
||||
|
||||
|
||||
def head():
|
||||
return subprocess.run(["git", "rev-parse", "--short", "HEAD"], cwd=REPO, capture_output=True, text=True).stdout.strip()
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# recipes
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def capture_recipe(alias, src, obj):
|
||||
r = subprocess.run(["make", "-n", "-W", src, obj, f"BINARY={alias}"], cwd=REPO, capture_output=True, text=True)
|
||||
if r.returncode != 0:
|
||||
return None, f"make -n rc={r.returncode}: {r.stderr.strip()[:200]}"
|
||||
lines = [ln for ln in r.stdout.splitlines() if ln.startswith("set -o pipefail;")]
|
||||
if len(lines) != 1:
|
||||
return None, f"expected ONE pipeline line, got {len(lines)}"
|
||||
m = RECIPE_RE.match(lines[0])
|
||||
if not m or m.group(2) != obj:
|
||||
return None, f"unparsed recipe: {lines[0][:160]}"
|
||||
return dict(alias=alias, src=src, obj=obj, pipeline=m.group(1)), None
|
||||
|
||||
|
||||
def build_recipes(jobs, aliases=None):
|
||||
objs = objects(aliases)
|
||||
recipes, errors = {}, []
|
||||
t0 = time.time()
|
||||
with ThreadPoolExecutor(max_workers=jobs) as ex:
|
||||
for (a, src, obj), (rec, err) in zip(objs, ex.map(lambda t: capture_recipe(*t), objs)):
|
||||
if rec:
|
||||
recipes[obj] = rec
|
||||
else:
|
||||
errors.append(f"{a} {src} {obj}: {err}")
|
||||
return dict(stamp=config_stamp(), head=head(), generated=time.strftime("%Y-%m-%d %H:%M"), n=len(recipes),
|
||||
seconds=round(time.time() - t0, 1), recipes=recipes, errors=errors)
|
||||
|
||||
|
||||
def load_recipes(refresh=False, jobs=16):
|
||||
if RECIPES.exists() and not refresh:
|
||||
d = json.loads(RECIPES.read_text())
|
||||
if d.get("stamp") == config_stamp():
|
||||
return d
|
||||
d = build_recipes(jobs)
|
||||
RUN.mkdir(parents=True, exist_ok=True)
|
||||
RECIPES.write_text(json.dumps(d, indent=1) + "\n")
|
||||
return d
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# compile + compare
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def compile_obj(recipe, text=None, tag="x", write_path=None):
|
||||
"""Compile the recipe's source (with `text` written IN PLACE first — to `write_path` when the edited file is a header the
|
||||
source includes, else to the source itself; the CALLER restores it) to a scratch object. Returns (bytes | None, seconds, errors)."""
|
||||
src = REPO / (write_path or recipe["src"])
|
||||
obj = recipe["obj"]
|
||||
out = SCRATCH / (obj[len("build/"):].replace("/", "__")[:-2] + f".{tag}.o")
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
dep = str(out)[:-2] + ".d"
|
||||
pipeline = recipe["pipeline"]
|
||||
pipeline = re.sub(r"-MF \S+", f"-MF {dep}", pipeline, count=1)
|
||||
cmd = f"set -o pipefail; {pipeline} -o {out}"
|
||||
if text is not None:
|
||||
src.write_text(text, errors="surrogateescape")
|
||||
t0 = time.time()
|
||||
r = subprocess.run(["bash", "-c", cmd], cwd=REPO, capture_output=True, text=True)
|
||||
dt = time.time() - t0
|
||||
if r.returncode != 0 or not out.exists():
|
||||
# gcc 2.7.2 prints errors without the word "error" and the assembler floods stderr with `$at` warnings: keep every
|
||||
# non-warning line (R103), then the tail
|
||||
errs = [ln for ln in r.stderr.splitlines()
|
||||
if ln.strip() and not re.search(r"\bwarning:", ln, re.I) and not ln.startswith(("In file included", " " * 16))
|
||||
and ": In function" not in ln]
|
||||
return None, dt, ("\n".join(errs[:8]) or r.stderr[-400:])
|
||||
data = out.read_bytes()
|
||||
try:
|
||||
out.unlink()
|
||||
pathlib.Path(dep).unlink(missing_ok=True)
|
||||
except OSError:
|
||||
pass
|
||||
return data, dt, ""
|
||||
|
||||
|
||||
def baseline_bytes(obj):
|
||||
p = REPO / obj
|
||||
return p.read_bytes() if p.exists() else None
|
||||
|
||||
|
||||
def judge(recipe, text, tag="x", write_path=None):
|
||||
"""(verdict, seconds, err): verdict in IDENTICAL | DIFFERS | COMPILE-ERROR | NO-BASELINE."""
|
||||
base = baseline_bytes(recipe["obj"])
|
||||
if base is None:
|
||||
return "NO-BASELINE", 0.0, ""
|
||||
data, dt, err = compile_obj(recipe, text, tag, write_path)
|
||||
if data is None:
|
||||
return "COMPILE-ERROR", dt, err
|
||||
return ("IDENTICAL" if data == base else "DIFFERS"), dt, ""
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# calibration
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
def calibrate(aliases, jobs, recipes):
|
||||
"""Every object of the named binaries compiled UNTOUCHED -> must equal build/; twin == primary; then the positive control."""
|
||||
recs = [r for r in recipes["recipes"].values() if r["alias"] in aliases]
|
||||
if not recs:
|
||||
sys.exit(f"delever_oracle: no recipes for {aliases} (R43)")
|
||||
twins = twin_of_map()
|
||||
results = []
|
||||
|
||||
def one(r):
|
||||
v, dt, err = judge(r, None, tag="cal")
|
||||
return dict(alias=r["alias"], obj=r["obj"], verdict=v, seconds=round(dt, 3), err=err[-200:])
|
||||
with ThreadPoolExecutor(max_workers=jobs) as ex:
|
||||
results = list(ex.map(one, recs))
|
||||
ok = sum(1 for x in results if x["verdict"] == "IDENTICAL")
|
||||
bad = [x for x in results if x["verdict"] != "IDENTICAL"]
|
||||
# twin == primary on the objects both build
|
||||
twin_checks = []
|
||||
for a in aliases:
|
||||
prim = twins.get(a)
|
||||
if not prim:
|
||||
continue
|
||||
for r in recipes["recipes"].values():
|
||||
if r["alias"] == a:
|
||||
pobj = r["obj"].replace(f"build/src/{a}/{a}", f"build/src/{prim}/{prim}")
|
||||
same = baseline_bytes(r["obj"]) == baseline_bytes(pobj)
|
||||
twin_checks.append(dict(twin=r["obj"], primary=pobj, equal=same))
|
||||
twin_bad = [t for t in twin_checks if not t["equal"]]
|
||||
# the positive control: a nop injected into a REAL function body (the first definition the shared scanner finds in the
|
||||
# first recipe's source with a body of >= 3 lines) must DIFFER — a verifier that cannot fail is no verifier (R39/R53)
|
||||
import share_census as sc
|
||||
ctl = recs[0]
|
||||
src = REPO / ctl["src"]
|
||||
orig = src.read_text(errors="surrogateescape")
|
||||
pos_verdict = "SKIPPED"
|
||||
defs = [r for r in sc.scan_text(orig, ctl["src"], shared_defs=None) if r["form"] == "def" and r.get("nlines", 0) >= 3 and not r.get("empty")]
|
||||
if defs:
|
||||
d = defs[0]
|
||||
line_starts = [0]
|
||||
for ln in orig.split("\n"):
|
||||
line_starts.append(line_starts[-1] + len(ln) + 1)
|
||||
# at the END of the body (C89: a statement before the declarations is a parse error)
|
||||
o = orig.rfind("}", line_starts[d["end"] - 1], line_starts[d["end"]])
|
||||
if o >= 0:
|
||||
cand = orig[:o] + ' __asm__("nop");\n' + orig[o:]
|
||||
try:
|
||||
pos_verdict, _, err = judge(ctl, cand, tag="ctl")
|
||||
pos_verdict = pos_verdict if pos_verdict != "COMPILE-ERROR" else f"COMPILE-ERROR ({err[-100:]})"
|
||||
finally:
|
||||
src.write_text(orig, errors="surrogateescape")
|
||||
by_alias = {}
|
||||
for x in results:
|
||||
d = by_alias.setdefault(x["alias"], dict(objects=0, identical=0, seconds=0.0))
|
||||
d["objects"] += 1
|
||||
d["identical"] += x["verdict"] == "IDENTICAL"
|
||||
d["seconds"] += x["seconds"]
|
||||
return dict(head=head(), stamp=config_stamp(), generated=time.strftime("%Y-%m-%d %H:%M"), aliases=sorted(aliases),
|
||||
objects=len(results), identical=ok, failures=bad[:20], twin_checks=len(twin_checks), twin_mismatch=twin_bad[:10],
|
||||
positive_control=dict(obj=ctl["obj"], verdict=pos_verdict),
|
||||
per_alias={a: dict(v, mean_s=round(v["seconds"] / max(v["objects"], 1), 3)) for a, v in by_alias.items()},
|
||||
per_object_seconds={x["obj"]: x["seconds"] for x in results},
|
||||
ok=(not bad and not twin_bad and pos_verdict == "DIFFERS"))
|
||||
|
||||
|
||||
def calibration_current():
|
||||
if not CALIB.exists():
|
||||
return False, "no calibration"
|
||||
d = json.loads(CALIB.read_text())
|
||||
if d.get("head") != head():
|
||||
return False, f"calibrated at {d.get('head')}, HEAD is {head()}"
|
||||
if d.get("stamp") != config_stamp():
|
||||
return False, "the Makefile/config changed since the calibration"
|
||||
return bool(d.get("ok")), ("ok" if d.get("ok") else "the calibration FAILED")
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description=__doc__.split("\n")[0])
|
||||
ap.add_argument("--recipes", action="store_true", help="(re)capture every object's recipe")
|
||||
ap.add_argument("--calibrate", nargs="*", help="binaries to calibrate on (e.g. ov_SC04_011 ov_SC03_015 main)")
|
||||
ap.add_argument("--status", action="store_true")
|
||||
ap.add_argument("-j", "--jobs", type=int, default=16)
|
||||
a = ap.parse_args()
|
||||
RUN.mkdir(parents=True, exist_ok=True)
|
||||
if a.status:
|
||||
ok, why = calibration_current()
|
||||
print(f"delever_oracle: calibration {'CURRENT' if ok else 'STALE/MISSING'} — {why}")
|
||||
sys.exit(0 if ok else 1)
|
||||
if a.recipes:
|
||||
d = load_recipes(refresh=True, jobs=a.jobs)
|
||||
print(f"delever_oracle: {d['n']} recipes captured in {d['seconds']} s at -j{a.jobs}; errors {len(d['errors'])}")
|
||||
for e in d["errors"][:10]:
|
||||
print(" ", e)
|
||||
sys.exit(1 if d["errors"] else 0)
|
||||
if a.calibrate is not None:
|
||||
recipes = load_recipes(jobs=a.jobs)
|
||||
t0 = time.time()
|
||||
d = calibrate(a.calibrate, a.jobs, recipes)
|
||||
d["seconds"] = round(time.time() - t0, 1)
|
||||
CALIB.write_text(json.dumps(d, indent=1) + "\n")
|
||||
print(f"delever_oracle --calibrate {' '.join(d['aliases'])}: {d['identical']}/{d['objects']} objects byte-identical untouched; "
|
||||
f"twin checks {d['twin_checks']} ({len(d['twin_mismatch'])} mismatch); positive control {d['positive_control']['verdict']} "
|
||||
f"on {d['positive_control']['obj']}; {d['seconds']} s — {'OK' if d['ok'] else 'FAIL'}")
|
||||
for a_, v in d["per_alias"].items():
|
||||
print(f" {a_:14s} {v['identical']}/{v['objects']} identical, mean {v['mean_s']} s per object")
|
||||
for f in d["failures"][:10]:
|
||||
print(" FAIL", f["alias"], f["obj"], f["verdict"], f["err"][-120:])
|
||||
sys.exit(0 if d["ok"] else 1)
|
||||
ap.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -405,7 +405,8 @@ def walk_file(raw, rel, is_header):
|
||||
d = span_of_line.get(ln)
|
||||
flat = re.sub(r"\s+", " ", text).strip()
|
||||
# a file-scope asm block keeps its whole template: the manifest match reads its `.globl`/`.ent` name
|
||||
sites.append(dict(tu=rel, fn=(d["name"] if d else None), fn_line=(d["line"] if d else None), line=ln,
|
||||
sites.append(dict(tu=rel, fn=(d["name"] if d else None), fn_line=(d["line"] if d else None), fn_end=(d["end"] if d else None),
|
||||
nhash=(d["nhash"] if d else None), line=ln,
|
||||
col=pos - masked.rfind("\n", 0, pos), cls=cls, kind=kind, detail=detail,
|
||||
text=(flat if (cls == "B" and d is None) else flat[:200]), marked=marked(ln), scope=("body" if d else "file"), **kw))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user