diff options
| author | Cliff Click <cliffc@acm.org> | 2026-08-10 11:11:18 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-08-10 11:11:18 -0700 |
| commit | 51f1f8f4b871e3b52eb0c5d18b03f362a2b37791 (patch) | |
| tree | 0d734f9d53fa58acfd0ad2875f6c753c78d523a1 /chapter25/src/main/smp/sys/aryi64.smp | |
| parent | ac3cfbfd58a2e7fdc61995c83a587778cb4e2919 (diff) | |
| download | Simple-51f1f8f4b871e3b52eb0c5d18b03f362a2b37791.tar.gz Simple-51f1f8f4b871e3b52eb0c5d18b03f362a2b37791.zip | |
Chapter 25: add separate compilation and simplify SSA construction
Introduce Chapter 25 with separately compiled Simple modules, serialized IR,
cross-compilation-unit linking, and native system-library integration. This
also completes a broad parser and type-system cleanup needed to make graph
construction independent of incomplete parse-time type information.
Separate compilation and linking
- Add compilation-unit Start/Stop nodes and track functions, classes, aliases,
and global indices across compilation-unit boundaries.
- Serialize canonical types and ideal graph nodes into ELF objects, including
dependency metadata, relocations, global/local bitset remapping, and dense
memory-alias information.
- Load dependent objects on demand, recursively resolve source and object
paths, relink calls and function pointers, and preserve external C symbols.
- Distinguish the post-optimization ownership hook from unknown callers so
private call graphs can remain precise while public functions remain
externally callable.
- Add command-line and build support for compiling modules and the reusable
`sys` object library.
Parser, constructors, and SSA
- Replace inline constructor expansion with a hidden default `<init>` followed
by an explicit user constructor declared as `new Type = { ... }`.
- Keep the default constructor private, pass private object memory through
constructor calls, and require user constructors to initialize non-default
fields before the object escapes.
- Track possibly-uninitialized fields in parser `Var` state and diagnose early
reads without encoding parser-only constraints in Load and Store nodes.
- Make ordinary parser memory bulk and recover precise alias slices in the
optimizer using `MemMerge`, `MemPhi`, and `BulkMemPhi` nodes.
- Remove parser-supplied type constraints from Loads and ordinary Phis, defer
integer/float arithmetic selection, and keep call shape driven by syntax
instead of provisional inferred types.
- Preserve chained field declarations as static parser information when flow
types are not yet available, including postfix field updates through calls.
Types, functions, and escape analysis
- Add `TypeScalar` as the common lattice family for integer, float, memory
pointer, and function-pointer values, with scalar TOP/BOT values for generic
Loads, Stores, parameters, and invalid intermediate expressions.
- Represent unresolved struct definitions directly with the `TypeStruct`
forward-reference flag while retaining the separate open-structure concept;
close and canonicalize recursive structures without side maps.
- Add explicit `FunPtrNode` references so constant function pointers retain a
graph edge to their Return, and keep referenced functions alive until Opto
proves the pointer dead.
- Refine public-function and class-initializer escape handling, including
public-only fallback escape sets and monotone compilation-unit summaries.
- Add guards, proof casts, read-only propagation, pointer-to-integer conversion
for non-null FFI arguments, and consistent deep mutability checks at calls.
Optimization and code generation
- Make weak and unresolved graph inputs compute conservatively and monotonically
throughout iterative peepholes and SCCP.
- Preserve independent memory slices when sharpening Stores, retain control on
conditional Stores, and freeze Store widths from their target field types.
- Extend serialization for new node kinds, scalar types, Store modes, function
pointers, and memory partitions, preserving serialize/deserialize bijection.
- Complete native selection and encoding support across x86-64, RISC-V, and
ARM, including FFI pointer conversion and missing integer operations.
- Fix x86 immediate multiply REX encoding and assorted scheduling, register
allocation, spilling, relocation, and constant-pool issues exposed by the
larger linked graphs.
System library, tests, and documentation
- Compile and link the Simple `sys` library, including libc bindings, I/O,
scanners, strings, vectors, array helpers, and executable entry points.
- Add Chapter 25 module, serialization, constructor, forward-reference,
postfix-update, system, Hello World, and Bubble Sort coverage; update golden
graphs and spill expectations for the new IR shape.
- Add module and type-system documentation, parser-simplification design notes,
grammar updates, examples, diagrams, and graph visualization assets.
The resulting compiler passes the raw Chapter 1-24 suite and the Chapter 25
system and separate-compilation tests, including a freshly rebuilt `sys.o` and
the native Bubble Sort example.
Diffstat (limited to 'chapter25/src/main/smp/sys/aryi64.smp')
| -rw-r--r-- | chapter25/src/main/smp/sys/aryi64.smp | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/chapter25/src/main/smp/sys/aryi64.smp b/chapter25/src/main/smp/sys/aryi64.smp new file mode 100644 index 00000000..499431d8 --- /dev/null +++ b/chapter25/src/main/smp/sys/aryi64.smp @@ -0,0 +1,63 @@ +// -*- mode: java; -*- + +// Ary/Vector of i64s +struct aryi64 { + u32 !len = 0; + i64[] !buf; + + new aryi64 = { i64[] b -> + buf = b; + }; + + // Grow as needed + val _grow = { int len2 -> + if( len+len2 < buf# ) return self; + int newlen = buf# * 2; + while( len+len2 >= newlen ) newlen *= 2; + i64[] !buf2 = new i64[newlen]; + for( int i=0; i<buf#; i++ ) + buf2[i] = buf[i]; + buf = buf2; + self; + }; + + // Add a i64 to aryu8 + val add = { i64 c -> + _grow(1).buf[len++] = c; + self; + }; + + // Write to aryu8 + val str = { -> + // TODO: clunky default constructor syntax + var str = new aryu8(new u8[1]).add('['); + for( int i=0; i<len; i++ ) + str.num(buf[i]).add(',').add(' '); + str.undo(2).add(']'); + }; +}; + + +// Parse a comma-separated list of numbers, wrapped with square brackets, +// with optional whitespace e.g. "[ -17, 0,99,12456789 ] ". +// parseAryI64 & aryi64.str are bijections modulo whitespace. +// Returns null if the parse failed, without giving a clue as to why. +val parseAryI64 = { u8[~] str -> + Scan !s = new Scan(str); + if( !s.match('[') ) return null; + // Array of parsed results + var nums = new aryi64(new i64[1]); + + // Parse a list of numbers + if( s.match(']') ) // Handle the empty list + return nums; + + // Parse number commas "123, " until something else + while( s.x < s.buf# ) { + nums.add(s.number()); + if( !s.match(',') ) + break; + }; + // Close the list + return s.match(']') ? nums : null; +}; |
