summaryrefslogtreecommitdiff
path: root/docs/chapter-backports.md
blob: d10dc7618b1fb42964a90ba8f8ae628fa75f8b84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# Chapter backport queue

This file tracks pending backports and deferred work. Completed work and old
validation results belong in Git history. Reusable implementation constraints
live in the [AI notes](../skills/chapter25-codex-notes.md).

## Investigate next

These are candidates, not confirmed missing correctness fixes. Establish an
earlier-chapter failure before changing compiler behavior.

### Conditional Store control

Compare conditional field writes under each destination's memory-Phi and alias
model. Chapter 24 attaches control to array stores but lets ordinary field
stores rely on memory dependencies. Chapter 25's explicit Store control input
is not by itself evidence that the earlier representation is wrong.

Keep this investigation separate from GCM's memory-Phi anti-dependency walk.
Use the existing read-before-conditional-store regression as a guard, and find
a distinct failing program before adding more control constraints.

### SCCP function revival: Chapter 24

`Opto.linkCG` uses `code.link(fidx)`, which clears a linker entry when its
function is structurally dead. Chapter 25 uses the non-cleaning `_link(fidx)`
while discovering calls, so temporarily disconnected functions can be revived.
Chapter 24 already has `_link`; the question is whether its own unlinking and
SCCP sequence can expose the same failure.

Trace a function from removal of its unknown-caller edge through discovery of
a real call. Preserve the distinction between unreachable control and a
structurally deleted node. No earlier-chapter failure is established yet.
Dependency propagation already exists in Chapter 24's SCCP; only port a
specific missing dependency with a reproducer. Keep Chapter 25's escape and
external-caller machinery out of this investigation.

## Deferred until the Chapter 25 split

### Deterministic inlining

The parse-size cutoff can reject a function whose optimized body is small.
After shrinking rewrites converge, choose one growing inline using current
body sizes and a deterministic ranking. Cache sizes per convergence round;
use stable call-site provenance to break ties, not worklist order or newly
allocated node IDs. Avoid per-node dependencies and repeated whole-body scans
while a large function gradually shrinks.

The bounded boilerplate-inlining heuristic is already in Chapters 20-24.
This item is the larger Chapter 25 redesign.

### Conversion and BOTTOM-on-error contracts

Coordinate these changes with the incomplete-type/conversion split:

- Chapter 24 Loads supply a typed result even when they report an error.
  Changing that result to BOTTOM alone breaks incomplete loop typing and can
  obscure the intended diagnostic. Chapter 25's Convert nodes provide the
  surrounding typed result. Relevant existing cases include
  `testBrainFuck`, `testWhileWithNullInside`, `testNullGuardErrors`, and
  `testLinkedList0`.
- Chapter 24 arithmetic also needs its typed fallback while forward references
  are unresolved. Returning BOTTOM confuses unresolved expressions with
  uninitialized fields (`testCoRecur`) and loses arithmetic diagnostics.

Preserve the current contracts until the parser, conversions, loop bounds,
and diagnostics can move together. Do not weaken narrowing assertions or
expected errors to make an isolated backport pass.

### Representation changes

Incomplete types, numeric modes, guards, symbolic fields, and private
constructor memory need explicit teaching boundaries and coordinated
invariants. They are not independent fixes to copy into earlier snapshots.

Serialization, global identity remapping, and module escape summaries stay
with separate compilation. Escape analysis stays in Chapter 25 pending the split.

## Work that stays in Chapter 25

Class-cycle checking and CLInit runtime lowering stay in Chapter 25. The
[chapter README](../chapter25/README.md#lazy-class-initialization) explains the
implementation; future work lives in the
[roadmap](../chapter25/ROADMAP.md#class-initialization-and-compiler-follow-ups).
Native code cannot receive classes; a native-startup/class-handoff policy is
not planned. Current data pointers remain eight bytes.

## Backport validation

Introduce an independent fix in the earliest applicable chapter and propagate
it through every affected snapshot. For correctness fixes, first reproduce the
failure in the destination compiler. Preserve each chapter's representation
and tutorial boundary.

Run focused checks and the existing full Make suites for the affected compiler
directories, for example:

```sh
make -k tests CHAPTERS="chapter20 chapter21"
```

Chapter 25's inherited tests do not validate earlier compiler implementations.
Force rebuilds when older Makefiles miss dependencies, and rebuild serialized
libraries when their compiler or object format changes. Keep execution and
register-legality checks independent of spill expectations. Preserve unrelated
edits, keep text LF-only, and run `git diff --check`.