summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-08 16:52:27 -0700
committerCliff Click <cliffc@acm.org>2026-10-08 16:52:27 -0700
commit7096ba70c05eabfe96fd7e69d276b16ac1bd0bb9 (patch)
treebda5cb52577488cb61544c671afa5080297d0381 /docs
parent87a75c83b75480e65147a4d425fddd14a05df4d9 (diff)
downloadSimple-7096ba70c05eabfe96fd7e69d276b16ac1bd0bb9.tar.gz
Simple-7096ba70c05eabfe96fd7e69d276b16ac1bd0bb9.zip
Support putting static data into ELF constant poolmain
Mostly fcn inits in <clinit>
Diffstat (limited to 'docs')
-rw-r--r--docs/chapter-backports.md59
-rw-r--r--docs/regalloc-spills.md81
2 files changed, 67 insertions, 73 deletions
diff --git a/docs/chapter-backports.md b/docs/chapter-backports.md
index 49288607..c7b3706e 100644
--- a/docs/chapter-backports.md
+++ b/docs/chapter-backports.md
@@ -465,18 +465,10 @@ lines beyond the original extraction.
## Pending corrections
-- **Residual allocation comparisons (investigated 2026-10-07; no compiler fix).**
- After fixture cleanup, cohort 23 is 103 in Chapter 24 versus 104 in 25;
- cohort 24 improves 1,387 to 1,315. The small actionable case is Win64
- NewtonExport: six moves in both chapters, but Chapter 25 puts five in the loop
- rather than four (34 to 41 weighted). Inspect destructive-add operand choice,
- coalescing and Phi/return-register bias. Bubble Sort
- now executes fewer instructions on both ARM and RISC-V; its higher static
- weight does not represent more executed allocator instructions.
- Ordinary Newton's larger static score mostly counts duplicated inlined loops:
- a no-inline diagnostic nearly matches Chapter 24. The
- [remaining-differences report](regalloc-spills.md#remaining-differences-after-fixture-cleanup)
- separates these findings from the deferred inliner work below.
+Allocator tuning is good enough: the residual Win64 NewtonExport ranking issue
+is closed without a fix. Additional emulator-driver/measurement coverage is also
+closed without expansion (Cliff, 2026-10-08). The remaining active work is AOT
+class initialization below; the other items stay deferred for the chapter split.
- **Chapter 25 deterministic inlining (deferred until after the Chapter 25 split).**
As of 2026-10-07, ordinary functions reject `_approxUIDs >= 100` before checking
@@ -546,11 +538,44 @@ lines beyond the original extraction.
known-null regression is already rejected
during parsing in 10-24. Keep this separate from the constructor/memory fixes.
-## AOT class initialization: larger independent work
-
-Proposed on 2026-09-19; deferred behind the smaller queue above. This is
-a substantial, self-contained Chapter 25 change, not an entangled backport.
-Earlier chapter applicability has not been established.
+## AOT class initialization
+
+Authorized on 2026-10-08 as the final cleanup before revisiting the Chapter 25
+split. The declared-constant final-field portion is implemented in Chapter 25:
+
+- StaticData owns object placement, canonical class identity, and relocations
+ for function/object pointers in ELF and emulator data images. Imported class
+ objects reference their defining compilation unit's `Name.$class` symbol.
+- Instruction selection omits a final-field Store only when its declared type
+ already identifies exactly the stored constant. Serialized ideal IR retains
+ its memory edges; no lattice or constructor-memory contract changed.
+- Runtime stores to mutable or insufficiently precise fields remain. Constant
+ pools remain read-only and class objects remain writable. Function pointers
+ remain four bytes, data pointers eight bytes. Native linking now explicitly
+ selects low-address placement for the existing function-pointer width; ELF
+ relocation overflow is checked by the linker.
+- The full parallel Chapter 25 Make suite passes (395, 37, 9, 23, 1, 21 tests).
+ The final focused suite passes three static-data checks: native and ARM/RISC
+ function-pointer calls before `<clinit>`, plus two serialized importers
+ sharing one mutable class-object address. The third check was added after
+ that full run. All 199 historical allocations and 108 dynamic cases pass;
+ cohort membership, inputs and results remain fixed. Tables are refreshed.
+ Logs live under `build/aot-init/` and `build/{spill,dynamic}-stats/`.
+
+**Initialization semantics decided:** dynamic `<clinit>` runs once on first
+active touch, after its parent completes. Passive class references do not
+trigger execution. Reject initialization cycles across modules; there is no
+early parent-ready point. Untouched classes execute no initialization code.
+The [lazy initialization design](../chapter25/initialization.md) covers the
+proposed ClassInit metadata owned by CompUnit, CLInitNode checks with parser-flow
+and ideal simplification, a hidden `$init` field set inside `<clinit>`, static
+proofs, and serialization/composition validation. Those mechanisms are
+design work, not implemented by the constant-field lowering above.
+
+Changing data-pointer width and moving fully initialized class objects to
+read-only storage remain separate follow-ons.
+
+The original broader design below remains a proposal, not a completion claim.
The goal is to pre-allocate AOT class objects in ELF data and pre-fill their
fields, letting ordinary graph optimization remove redundant initialization.
diff --git a/docs/regalloc-spills.md b/docs/regalloc-spills.md
index 4f738fe5..8e83f3ba 100644
--- a/docs/regalloc-spills.md
+++ b/docs/regalloc-spills.md
@@ -21,12 +21,12 @@ no encoder, so its dynamic cells are unavailable. There is no cross-cohort total
<!-- spill-matrix:start -->
| Test cohort | Cases D / X | Ch 20: Ops / RA / X | Ch 21: Ops / RA / X | Ch 22: Ops / RA / X | Ch 23: Ops / RA / X | Ch 24: Ops / RA / X | Ch 25: Ops / RA / X |
|---|---:|---:|---:|---:|---:|---:|---:|
-| Ch 20 | 22 / 13 | — / — / 161 | 55,173 / 5,407 / 174 | 58,751 / 9,099 / 175 | 58,736 / 9,084 / 184 | 58,720 / 9,068 / 183 | 59,043 / 9,094 / 209 |
-| Ch 21 | 20 / 18 | | 6,207 / 261 / 461 | 6,324 / 379 / 475 | 6,326 / 381 / 475 | 6,325 / 380 / 470 | 6,233 / 219 / 533 |
-| Ch 22 | 14 / 8 | | | 198 / 60 / 7 | 194 / 56 / 7 | 194 / 56 / 7 | 332 / 136 / 11 |
-| Ch 23 | 14 / 8 | | | | 630 / 160 / 36 | 630 / 160 / 36 | 1,106 / 442 / 36 |
-| Ch 24 | 36 / 20 | | | | | 4,923 / 1,341 / 790 | 5,044 / 1,470 / 609 |
-| Ch 25 | 2 / 12 | | | | | | 20 / 0 / 1,862 |
+| Ch 20 | 22 / 13 | — / — / 161 | 55,173 / 5,407 / 174 | 58,751 / 9,099 / 175 | 58,736 / 9,084 / 184 | 58,720 / 9,068 / 183 | 58,965 / 9,076 / 208 |
+| Ch 21 | 20 / 18 | | 6,207 / 261 / 461 | 6,324 / 379 / 475 | 6,326 / 381 / 475 | 6,325 / 380 / 470 | 6,196 / 219 / 534 |
+| Ch 22 | 14 / 8 | | | 198 / 60 / 7 | 194 / 56 / 7 | 194 / 56 / 7 | 252 / 92 / 11 |
+| Ch 23 | 14 / 8 | | | | 630 / 160 / 36 | 630 / 160 / 36 | 864 / 358 / 36 |
+| Ch 24 | 36 / 20 | | | | | 4,923 / 1,341 / 790 | 4,646 / 1,335 / 609 |
+| Ch 25 | 2 / 12 | | | | | | 20 / 0 / 1,856 |
<!-- spill-matrix:end -->
Measured on Windows, 2026-10-07, using optimizer seed 123 for the historical
@@ -64,60 +64,29 @@ answers, including nested equality at arguments 0-3, finite Newton results and
Bubble Sort's complete output. The shared ISA tests and full Chapter 21-25
Make suites pass after the backend/evaluator corrections.
-## Remaining differences after fixture cleanup
+## Remaining initialization costs
-The Chapter 24-to-25 comparison, using the same inputs and cases in each row:
+Chapter 25 now places declared constant final fields directly in static data,
+including function addresses, and omits their initialization stores. The same
+fixed inputs and test cases give:
| Cohort | Ch 24 Ops | Ch 25 Ops | Change |
|---|---:|---:|---:|
-| Ch 20 | 58,720 | 59,043 | +0.6% |
-| Ch 21 | 6,325 | 6,233 | -1.5% |
-| Ch 22 | 194 | 332 | +71.1% |
-| Ch 23 | 630 | 1,106 | +75.6% |
-| Ch 24 | 4,923 | 5,044 | +2.5% |
-
-Chapter 25 retains top-level bindings in the compilation unit's class object.
-Initializing its fields generates stores, function-pointer constants and class
-addresses, even when helper calls have already inlined and folded. Chapters
-through 24 can eliminate these bindings as locals. Small programs make this
-fixed initialization cost particularly visible.
-
-For example, `Chapter23Test.testAnd` takes 12 instructions per target in 24 and
-32 in 25. The extra 20 are four field stores, four instructions materializing
-two function pointers, ten materializing the class address at five uses
-(including the hidden call argument), and two integer constants. The actual
-short-circuit expression has already folded in both chapters.
-
-Across the entire Chapter 23 cohort, executed-node attribution accounts for
-the **476** extra instructions:
-
-| Generated work | Instruction change |
-|---|---:|
-| Field stores | +126 |
-| Function-pointer materialization | +108 |
-| Pointer-address materialization | +240 |
-| Integer constants | +50 |
-| Allocator copies/spills/reloads | +2 |
-| Unconditional jumps | +2 |
-| Calls, prologues/returns, extensions and loads removed | -52 |
-
-Its RA subset rises **160 to 442**, comprising **224** extra pointer-address
-rematerialization instructions, **56** extra integer rematerializations and
-only **2** extra copies/spills/reloads. RA labels allocator-created code; it
-does not mean all 282 extra instructions are stack traffic. `testAndPtr` also
-loses a helper call per execution, so inlining has improved despite the larger
-whole-program count. Moving constant initialization to static data would
-remove much of this work; reusing class addresses could reduce the repeated
-materialization. Neither optimization is included in this measurement update.
-
-Both Bubble Sort targets improve: RISC-V **2,062 / 591 to 1,877 / 493**, and
-ARM **2,040 / 579 to 1,868 / 478** (Ops / RA). Together they save 357 instructions;
-the other Chapter 24 cases add 478, leaving a net increase of 121. Newton
-integer improves **136 / 36 to 116 / 17** across both targets. In the Chapter 20
-BrainFuck case, ARM adds 95 instructions: 88 net extra integer materializations
-plus seven initialization instructions; its executed split count stays at 33.
-These tables compare whole chapter compilers, including frontend and inlining
-changes, rather than isolating allocator rankings.
+| Ch 20 | 58,720 | 58,965 | +0.4% |
+| Ch 21 | 6,325 | 6,196 | -2.0% |
+| Ch 22 | 194 | 252 | +29.9% |
+| Ch 23 | 630 | 864 | +37.1% |
+| Ch 24 | 4,923 | 4,646 | -5.6% |
+
+Chapter 25 retains top-level bindings in its class object; earlier chapters can
+eliminate them as locals. Mutable fields and final fields whose declarations
+do not identify their exact constant still need runtime initialization. This
+fixed cost remains visible in small programs even after helper calls inline.
+
+For cohort 23, the RA subset is 160 in Chapter 24 and 358 in Chapter 25. It
+includes allocator-created constant/address rematerialization as well as copies
+and stack traffic; it must not be read as a count of spills alone. These tables
+compare whole chapter compilers, including frontend and inlining changes.
## Reproduce