kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 651ae85e2d4b2a378ed9567ec16f77c29761e5fb
parent dba8886b09e7bd057a9bcdc43c9588d458cbcf02
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed, 13 May 2026 09:11:57 -0700

toy-todo.md plan

Diffstat:
Adoc/toy-todo.md | 623+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 623 insertions(+), 0 deletions(-)

diff --git a/doc/toy-todo.md b/doc/toy-todo.md @@ -0,0 +1,623 @@ +# Toy CG Coverage TODO + +Toy should become the primary way to exercise the public CG API in +`include/cfree/cg.h`. This file tracks the gaps between what the current toy +language can express and the full CG surface. + +Baseline: `lang/toy/toy.c` currently has core integer functions, locals, +globals, direct calls, tail calls, pointers to `int`, variadic helpers, inline +asm helpers, atomics, memory helpers, a hard-coded record field test, and a +hard-coded type-query test. + +## Language Extension Plan + +This section is a decision log for source-language extensions that make toy +able to express the full CG API surface. Items move from `Proposed` to +`Accepted` or `Rejected` as decisions are made. + +### Group 1: Types And Literals + +Status: Accepted + +Goal: make toy able to name every CG type shape and produce scalar constants +for those types. Later work on calls, atomics, globals, records, and memory +operations should build on these type forms instead of adding one-off builtins. + +Proposal: + +- Builtin scalar type names: `void`, `bool`, `i8`, `u8`, `i16`, `u16`, `i32`, + `u32`, `i64`, `u64`, `isize`, `usize`, `f32`, `f64`, and `va_list`. +- Keep `int` as a compatibility alias for `isize` for existing toy tests. +- Pointer types remain prefix: `*T`. +- Arrays use prefix count syntax: `[N]T`, for example `[4]i32`. +- Function pointer types use `fn(T, U): R` as a type form. Variadic function + types use `fn(T, ...): R`. +- Qualified types use prefix qualifiers: `const T`, `volatile T`, and + `restrict T`. Multiple qualifiers are allowed as repeated prefixes. +- Boolean literals are `true` and `false`. +- Numeric literals keep their current unsuffixed form and are context-typed by + the target declaration, parameter, return, or cast. Add decimal float literals + for `f32`/`f64`. +- Add explicit casts as `expr as T` so tests can force conversion edges without + needing C-like cast ambiguity in the grammar. +- Add type query expressions: `sizeof<T>()`, `alignof<T>()`, and + `offsetof<T>(field)`. + +Decisions: + +- Use `true`/`false` for boolean literals. +- Use `[N]T` for arrays. +- Use `expr as T` for casts. +- Include `offsetof<T>(field)` with the type-query expressions. + +### Group 2: Declarations, Linkage, And Attributes + +Status: Accepted + +Goal: expose function/data declaration modes and symbol attributes without +turning toy into C. Declarations should stay regular enough that coverage cases +are easy to read and failures point at CG behavior rather than parser trivia. + +Proposal: + +- Function and data definitions are static/private by default. +- Exported definitions use `pub`: + `pub fn name(args): ret { ... }`, `pub let x: T = init;`, and + `pub var x: T = init;`. +- Imported function declarations use explicit `extern`: + `extern fn name(args): ret;` + This emits `cfree_cg_func_decl` without `cfree_cg_func_begin`. +- Function definitions keep the current non-exported shape: + `fn name(args): ret { ... }`. +- Global definitions keep `let`/`var`: + `let x: T = init;`, `var x: T = init;`, and zero-init `var x: T;`. +- Imported data declarations use `extern`: + `extern let name: T;`, `extern var name: T;`. + These emit `cfree_cg_data_decl` without a definition. +- Attributes use a prefix bracket list before `pub`, `extern`, `fn`, `let`, or + `var`: + `#[bind(local), visibility(hidden), section(".foo"), align(16), used]` +- Supported attributes: + `bind(global|local|weak)`, `visibility(default|hidden|protected)`, + `section("name")`, `align(N)`, `readonly`, `tls`, `tls_model(default|local_exec|initial_exec|local_dynamic|general_dynamic|tlvp)`, + `common`, `used`, and `noreturn`. +- `pub` maps to global binding unless an explicit `bind(...)` attribute + overrides it for an error-case test. Non-`pub` definitions map to local + binding by default. +- `let` implies readonly for defined data; `readonly` remains accepted on `var` + to exercise the declaration flag directly. + +Decisions: + +- Use `#[...]` attributes. +- Default definitions are static/private. +- Use `pub` to mark exported definitions. +- Use explicit `extern` for outside functions and data. + +### Group 3: Composite Types And Initializers + +Status: Accepted + +Goal: let toy source define records, enums, aliases, arrays, and aggregate +initializers directly, so CG type construction, layout, data emission, field +access, and ABI aggregate behavior are all covered without hard-coded helper +types. + +Proposal: + +- Type aliases: + `type Word = u64;` +- Record declarations: + `record Pair { a: i32; b: i32; }` +- Anonymous record fields use `_`: + `record Tuple2 { _: i32; _: i32; }` +- Field alignment uses field attributes: + `record Padded { #[align(16)] x: i32; y: i32; }` +- Packed records use a record attribute: + `#[packed] record Header { tag: u8; len: u32; }` +- Enum declarations: + `enum Color: i32 { red = 1; green = 2; blue = 3; }` + The base type is required so enum layout is explicit. +- Record literals use named fields: + `Pair { a: 1, b: 2 }` +- Array literals use bracket values: + `[1, 2, 3, 4]` + The expected type supplies the element type and count. +- Zero aggregate literal: + `zero<T>()` + This gives tests a concise way to produce zeroed arrays/records/globals. +- Global initializers may use scalar literals, bool/float literals, string/byte + literals, array literals, record literals, `zero<T>()`, and symbol addresses. +- String literals have type `*[N]u8` or `*u8` only through decay contexts; exact + behavior can be narrowed during implementation. +- Symbol address initializers use `&name` initially; symbol addends and + non-`ADDR` reference kinds are handled in a later symbol-reference group. + +Decisions: + +- Use `record`; do not add `struct` as an alias initially. +- Support `Color.red` and `.red` enum value references. `.red` requires an + expected enum type from context. +- Use `zero<T>()` for zero values and zero aggregate initializers. + +### Group 4: Lvalues, Field Access, Indexing, And Memory + +Status: Accepted + +Goal: make normal toy expressions produce the lvalue shapes CG needs for +`addr`, `indirect`, `load`, `store`, `index`, `field`, `memcpy`, and `memset`. +The language should express memory operations through ordinary source forms +first, with explicit builtins kept for exact CG knob coverage. + +Proposal: + +- Field access: + `expr.field` + If `expr` has record type, this selects the field directly. If `expr` has + pointer-to-record type, field access implicitly dereferences before selecting + the field. There is no `->` operator. +- Array and pointer indexing: + `expr[index]` + This lowers through `cfree_cg_index`; arrays use array lvalues, pointers use + pointer rvalues converted to element lvalues. +- Address-of accepts any lvalue: + `&x`, `&*p`, `&arr[i]`, `&rec.field`, and `&ptr.field`. +- Assignment accepts any assignable lvalue: + `x = value;`, `*p = value;`, `arr[i] = value;`, `rec.field = value;`, + `ptr.field = value;`. +- Aggregate copy is expressed by assignment when source and destination have + the same array or record type. +- Explicit memory builtins remain for exact size/alignment coverage: + `memcpy(dst, src, size, align)`, `memset(dst, value, size, align)`. + They return `void`. + +Decisions: + +- Do not add `->`; use `.` and let type checking decide whether the base is + direct or indirect. +- Allow aggregate assignment for both records and arrays. +- `memcpy` and `memset` return `void`. +- Do not add explicit offset indexing syntax or a helper for now. +- Do not add compound assignment or inc/dec syntax for now. + +### Group 5: Operators, Casts, And Control Values + +Status: Accepted + +Goal: exercise every scalar binop, cmp, unop, and conversion path while keeping +the expression grammar close to the CG stack model. + +Proposal: + +- Arithmetic operators are type-directed: + signed integer types use signed division/remainder and signed comparisons; + unsigned integer types use unsigned division/remainder and unsigned + comparisons; floats use float arithmetic/comparisons when supported by CG. +- Shift operators: + `<<` always maps to `CFREE_CG_SHL`; `>>` maps to signed or unsigned shift + based on the left operand type. +- Bitwise operators apply to integer types: `&`, `|`, `^`, and unary `~`. +- Logical operators apply to `bool`: `!`, `&&`, `||`. +- Comparisons produce `bool`, not `int`. +- Conditions and logical operators accept integer values using C-style truth: + zero is false, any non-zero value is true. The operation result is `bool`. +- Casts use the accepted spelling `expr as T`. +- Enum values cast explicitly to/from their base integer type through `as`. +- Pointer casts are allowed through `as *T` for CG conversion coverage. +- Pointer comparisons are allowed for `==`, `!=`, `<`, `<=`, `>`, and `>=`. + Ordered pointer comparisons are address-order comparisons using the target + pointer representation. +- Add bit helpers as explicit builtins instead of syntax: + `bitget(value, lo, width)` and `bitset(dst, src, lo, width)`. + These map to the inline CG composites and require integer operands. +- Keep no compound assignment and no inc/dec syntax. + +Decisions: + +- Integer truth uses zero for false and any non-zero value for true. +- Add `bitget` and `bitset` builtins. +- Allow all pointer comparisons, including ordered address comparisons. + +### Group 6: Control Flow And Expression Scopes + +Status: Accepted + +Goal: expose the structured scope operations, labels/branches through normal +control flow, and unreachable paths without turning toy into an assembly-like +language. + +Proposal: + +- Keep statement control flow: + `if cond { ... } else { ... }`, `while cond { ... }`, `break;`, + `continue;`, and `return`. +- Add expression `if`: + `if cond { expr } else { expr }` + This produces a value and exercises expression-valued scopes. +- Add result-typed `while`: + `while<T> cond { ... }` + The loop body may use `break expr;` to exit with a value of `T`. This maps to + `cfree_cg_scope_begin` with a non-`NONE` result type. +- Conditional break/continue stays source-level structured: + `if cond { break; }` and `if cond { continue; }` + The compiler may lower these through the conditional CG helpers where useful, + but toy does not add `break if` or `continue if` syntax. +- Add `unreachable();` and `trap();` as intrinsics in the intrinsic group, but + control-flow tests should also use them to cover dead-end blocks. +- Do not add source-level labels/goto initially. Short-circuiting, `if`, and + loops should cover labels and branches at the CG API level. + +Decisions: + +- Expression `if` uses braces. +- Use `while<T> cond { ... }` for value-producing loops. +- Keep source as `if cond { break; }` and `if cond { continue; }`; do not add + conditional break/continue syntax. + +### Group 7: Calls, Function Pointers, ABI, And Variadics + +Status: Accepted + +Goal: make toy able to exercise direct calls, indirect calls, tail calls, +scalar and aggregate ABI paths, and variadic argument handling using ordinary +typed source. + +Proposal: + +- Direct calls keep the existing spelling: + `callee(arg0, arg1)`. +- Function values are addressable with `&name` and have type `*fn(...): R`. +- Bare function names are also allowed in value position and produce function + values, so `let fp: *fn(i32): i32 = f;` is valid. +- Indirect calls use normal call syntax when the callee expression has function + or pointer-to-function type: + `fp(arg0, arg1)`. +- Tail calls keep explicit source spelling: + `return tail callee(args);` + The callee may be direct or indirect. Variadic tail calls remain rejected. +- Function parameters and returns may use every scalar type, pointers, enums, + aliases, records, and arrays where CG supports the shape. +- Records can be passed and returned by value. Tests should include small + records, large records, mixed integer/float records, and homogeneous float + aggregates on targets where the ABI distinguishes them. +- Arrays act like records: they are first-class values and pass by value. There + is no implicit array-to-pointer decay. +- `&arr` is equivalent to `&arr[0]`, producing a pointer to the first element + rather than a pointer to the whole array. +- Variadic functions keep `...` in the parameter list: + `fn sum(count: i32, ...): i32 { ... }` +- `va_start`, `va_arg<T>`, `va_copy`, and `va_end` become typed builtins: + `va_start(ap);`, `va_arg<T>(ap)`, `va_copy(dst, src);`, `va_end(ap);` +- Variadic call sites accept any expression type. Default argument promotion + is explicit through `as` instead of hidden C-like promotion. +- Function type queries from Group 1 should be used in tests to validate + function pointer and variadic type shapes. + +Decisions: + +- Allow bare function names in value position. +- Arrays are first-class by-value aggregates, like records. +- Do not add implicit array decay. +- `&arr` is the same as `&arr[0]`. +- Variadic call-site promotions are explicit through `as`. + +### Group 8: Intrinsics And Atomics + +Status: Accepted + +Goal: expose the CG intrinsic and atomic APIs with typed, explicit source forms +that make memory order, result shape, and multi-result behavior visible in toy +tests. + +Proposal: + +- Intrinsics use named builtin functions: + `trap()`, `unreachable()`, `clz(x)`, `ctz(x)`, `popcount(x)`, `bswap(x)`, + `prefetch(ptr)`, `expect(value, expected)`, and + `assume_aligned(ptr, align)`. +- `setjmp`/`longjmp` use typed builtins: + `setjmp(buf)` returns `i32`; `longjmp(buf, value)` returns `void` and is + noreturn in control-flow analysis. +- Overflow intrinsics return a small record shape: + `add_overflow(a, b)`, `sub_overflow(a, b)`, and `mul_overflow(a, b)`. + The result is an anonymous record with fields `{ value: T; ok: bool; }`. +- Atomic memory order names are enum-like builtin constants: + `.relaxed`, `.consume`, `.acquire`, `.release`, `.acq_rel`, `.seq_cst`. +- Atomic builtins take memory order explicitly: + `atomic_load<T>(ptr, order)`, `atomic_store<T>(ptr, value, order)`, + `atomic_rmw<T>(op, ptr, value, order)`, + `atomic_cmpxchg<T>(ptr, expected, desired, success_order, failure_order)`, + and `atomic_fence(order)`. +- Atomic RMW op names are enum-like constants: + `.xchg`, `.add`, `.sub`, `.and`, `.or`, `.xor`, `.nand`. +- `atomic_cmpxchg<T>` returns a builtin record: + an anonymous record with fields `{ prior: T; ok: bool; }` + so tests can inspect both CG results. +- The parser/type checker should reject invalid compare-exchange order pairs + when it can do so locally. +- Keep compatibility aliases for the current simple builtins only during test + migration if needed: `atomic_add`, `atomic_sub`, `atomic_cas_ok`, and + `fence`. + +Decisions: + +- Overflow and compare-exchange builtins return anonymous records. +- Use dot constants for memory orders and RMW ops. +- Remove compatibility aliases after test migration. + +### Group 9: Symbol References, Relocations, And TLS + +Status: Accepted + +Goal: support thread-local storage and normal imported/exported symbol access +as language features. Do not add a use-site relocation escape hatch unless the +CG API grows a clear language-level semantic for it. + +Proposal: + +- Keep ordinary symbol address syntax: + `&name` + The declaration attributes on `name`, plus target and code-model context, + select the ordinary reference kind. For example, TLS attributes select the + default TLS access path, and imported functions/data can use the platform's + normal PLT/GOT behavior where appropriate. +- Global data symbol initializers also use ordinary address syntax: + `let p: *i32 = &name;` + This maps to a normal `cfree_cg_data_symbol` emission selected from the same + declaration/context information. +- TLS variables are declared with Group 2 attributes: + `#[tls, tls_model(local_exec)] var tls_counter: i32;` +- TLS imports use `extern` plus the same attributes: + `#[tls, tls_model(initial_exec)] extern var errno: i32;` +- Normal TLS variable access and `&tls_counter` use the declaration's TLS + attributes and model. This is the language-level path for exercising TLS + codegen. +- Supported source TLS models are: + `default`, `local_exec`, `initial_exec`, `local_dynamic`, + `general_dynamic`, and `tlvp`. +- Target-incompatible TLS models should produce diagnostics rather than silently + falling back. +- For non-TLS imports, ordinary calls, bare function values, variable loads, and + `&name` should choose direct, PLT, GOT, or PC-relative references according + to declaration binding, visibility, target, and output mode. + +Rationale: + +- Thread-local storage is a real source-language feature. It belongs in toy + because normal loads, stores, address-taking, imports, and TLS models all + exercise meaningful codegen behavior. +- Use-site relocation forms such as explicit GOT/PLT/PCREL selection are not + currently accepted as toy language extensions. If the only way to exercise a + `CfreeCgSymbolRefKind` is an artificial escape hatch, that is evidence that + the CG API may need narrowing or re-shaping around declaration attributes, + target mode, and semantic operations instead. +- Low-level relocation record tests can remain in object/linker-specific + harnesses until there is a clear language-level operation that needs them. + +Follow-up CG API questions: + +- Should the public CG API keep `CfreeCgSymbolRefKind` on `push_symbol` and + `data_symbol`, or should reference kind be inferred from declaration attrs + and compile/output mode? +- For source TLS models, should `default` always choose the platform default, + or should toy require an explicit model in tests that assert a specific + relocation sequence? + +Decisions: + +- Support TLS as a normal source-language feature through declaration + attributes and normal variable/address access. +- Do not add explicit use-site relocation syntax to toy for now. + +### Group 10: Inline Assembly + +Status: Accepted + +Goal: expose `cfree_cg_inline_asm` through a source form that is explicit +enough for CG tests but still reads like a language feature rather than a C API +dump. + +Proposal: + +- Use an expression form: + `asm<T>(template, outputs, inputs, clobbers, flags)` + It returns `T`, or `void` for statement-only asm. +- Template is a string literal or existing `arch(...)` selector. +- Inputs are typed expressions with constraints: + `in("r", expr)`, `in("m", lvalue)`, `in("i", const_expr)`. +- Outputs declare constraints and result names: + `out("=r", name: T)`, `out("=&r", name: T)`. +- Inout operands consume and produce one value: + `inout("+r", expr)`. +- Multiple outputs return an anonymous record with fields named from the output + operands. A single output returns the output value directly. +- Named operands use the output/input names when provided, giving tests a path + to symbolic operand names. +- Clobbers are string literals: + `clobbers("memory", "cc")`. +- Flags are dot constants: + `.volatile` + Omitted flags mean non-volatile asm. +- Example: + `asm<i32>("add %0, %1, %2", out("=r", value: i32), inputs(in("r", a), in("r", b)), clobbers(), .volatile)` + +Decisions: + +- Use a single `asm<T>(...)` form for statement and expression asm. +- Use wrapper groups such as `inputs(...)` and `clobbers(...)`. +- Multi-output asm returns an anonymous record. + +## Type System + +- Add syntax for all builtin scalar types, not just `int`/`isize`, implicit + `void` returns, and `va_list`: `bool`, `i8`, `u8`, `i16`, `u16`, `i32`, + `u32`, `i64`, `u64`, `usize`, `f32`, and `f64`. +- Add float literals and operations so toy exercises `cfree_cg_push_float`, + floating arithmetic, floating calls/returns, and float ABI paths. +- Add array type syntax and declaration support. `typecheck()` currently + constructs one array type internally, but toy programs cannot declare array + locals, globals, parameters, or return values. +- Add named alias syntax. `typecheck()` constructs an alias, but aliases cannot + be introduced or used by toy source. +- Add qualified type syntax for `const`, `volatile`, and `restrict`. + `typecheck()` only constructs a `const int` and does not exercise qualified + values in declarations or memory operations. +- Add record/struct declarations with arbitrary field names, field counts, + field types, anonymous fields, packed alignment, and explicit field alignment. + Toy currently has only one internal `Pair { int a; int b; }`. +- Add enum declarations and enum constants as source-level values. The current + enum coverage is only an internal constructor call inside `typecheck()`. +- Add function pointer type syntax. Toy can form direct function types for + declared functions, but source cannot declare function pointer variables, + parameters, globals, or indirect calls. +- Exercise `cfree_cg_type_record_field`. The current type-query builtin checks + record-ness and field count, but does not query field metadata. +- Exercise type layout through source constructs, not only hard-coded helper + calls: `sizeof(type)`, `alignof(type)`, and possibly `offsetof(record, field)`. + +## Declarations And Linkage + +- Add function declarations without definitions, including external functions. + Toy calls `cfree_cg_func_decl`, but only immediately before defining the same + function. +- Add global data declarations without definitions to exercise + `cfree_cg_data_decl`. +- Add declaration attributes: non-default binding, hidden/protected visibility, + custom sections, explicit alignment, readonly, TLS, common, used, and noreturn. +- Add TLS globals and source-level selection of TLS models. +- Add support for undefined external data/function references so link-time + symbol handling is exercised from toy. + +## Global Data Initializers + +- Add byte/string data initializers. Toy has a hard-coded `byteconst()` helper + for `cfree_cg_push_bytes`, but no source-level string or byte literal data. +- Add aggregate initializers for arrays and records. +- Add explicit zero-fill ranges inside aggregate initializers, not only whole + object zero initialization. +- Add symbol initializer addends and non-pointer-width symbol records. +- Add source coverage for non-`ADDR` data symbol reference kinds: `PCREL`, + `GOT`, `PLT`, `TLS_LE`, `TLS_IE`, `TLS_LD`, `TLS_GD`, and `TLVP`. + +## Symbol References + +- Add source-level control over `cfree_cg_push_symbol` reference kind and addend. + Current code references use `CFREE_CG_SYMREF_ADDR` with addend `0`. +- Add GOT/PLT and PC-relative code reference tests. +- Add TLS code reference tests for all TLS symbol reference kinds. +- Add TLVP coverage for Mach-O-style thread-local references. + +## Values And Lvalues + +- Add string literals as expression values. +- Generalize address-of beyond identifiers. Source cannot write `&*p`, + `&index(p, i)`, or `&record.field`. +- Generalize assignment targets beyond variables and unary `*p`. Source cannot + assign through indexed or field lvalues directly. +- Add first-class array and record values so `load`, `store`, `addr`, + `indirect`, `field`, `index`, `memcpy`, and ABI aggregate paths can interact + naturally. +- Add pre/post increment and decrement to exercise `cfree_cg_inc_dec`. + +## Operators And Conversions + +- Add unsigned arithmetic and comparisons. Missing source coverage includes + `CFREE_CG_UDIV`, `CFREE_CG_UREM`, `CFREE_CG_SHR_U`, `CFREE_CG_LT_U`, + `CFREE_CG_LE_U`, `CFREE_CG_GT_U`, and `CFREE_CG_GE_U`. +- Add explicit casts to exercise `cfree_cg_convert` across integer widths, + signedness, pointers, booleans, and floats. Current conversion coverage is + essentially comparison `i1 -> int`. +- Add a real `bool` type instead of representing truth values as `int`. +- Add bitfield-like extraction/insertion helpers or syntax to exercise + `cfree_cg_bitget` and `cfree_cg_bitset`. +- Check whether toy should allow chained comparisons or keep one comparison per + expression; the current parser accepts only one comparison operator at that + precedence level. + +## Stack Operations + +- Keep direct stack manipulation out of normal toy syntax if possible, but add + small targeted builtins when needed to exercise stack-sensitive CG behavior. +- `cfree_cg_dup`, `cfree_cg_swap`, `cfree_cg_drop`, and `cfree_cg_rot3` are used + incidentally today. Add explicit regression cases for stack order if bugs + appear around multi-result operations, inc/dec, atomics, or inline asm. + +## Control Flow + +- Add expression-valued scopes so `cfree_cg_scope_begin` with a non-`NONE` + result type, `cfree_cg_break`, `cfree_cg_break_true`, `cfree_cg_break_false`, + and `cfree_cg_scope_end` are exercised with carried values. +- Add conditional loop continuation syntax or builtins for + `cfree_cg_continue_true` and `cfree_cg_continue_false`. +- Add direct tests for `cfree_cg_break_true`; current loops use + `cfree_cg_break_false` for while conditions. +- Keep label/jump/branch coverage through short-circuiting and `if`, but add + targeted cases for awkward CFG shapes: empty blocks, nested conditionals, + early returns inside loops, and branches after unreachable paths. + +## Calls And ABI Coverage + +- Add indirect calls through function pointers. +- Add calls and returns for every scalar builtin type. +- Add by-value record parameters and record returns, including large records and + ABI-specific aggregate classifications. +- Add HFA/HVA-style float aggregate coverage where the target ABI supports it. +- Add variadic arguments beyond integer values: pointers, floats, and records. +- Decide whether to support variadic tail calls or document that toy should + reject them permanently. + +## Intrinsics + +- Add source forms for `trap()` and `unreachable()`. +- Add `setjmp`/`longjmp` coverage, including buffer storage. +- Add overflow intrinsics: `add_overflow`, `sub_overflow`, and `mul_overflow`. + These require a way to consume the two-value `(result, ok)` CG result. +- Add `prefetch(addr)`. +- Add `assume_aligned(ptr, align)` or an equivalent helper. +- Add result-type checks for existing intrinsics across more than `int` once + more scalar types exist. + +## Atomics + +- Add source-level memory order selection for relaxed, consume, acquire, + release, acquire-release, and sequentially consistent operations. +- Add remaining RMW operations: exchange, and, or, xor, and nand. +- Add atomic operations over widths other than toy `int`. +- Add compare-exchange forms that expose both returned values: the prior value + and the success flag. `atomic_cas_ok` currently drops the prior value. +- Add invalid-order diagnostics for compare-exchange success/failure pairs. + +## Inline Assembly + +- Add symbolic operand names. +- Add multiple outputs and multiple inout operands. +- Add asm operands for non-`int` types once those types exist. +- Add non-volatile asm support. Current helpers always set + `CFREE_CG_ASM_VOLATILE`. +- Add richer clobber lists instead of only `memory` or one arch-selected string. +- Add target-specific tests for unsupported constraints and diagnostics. + +## Memory Operations + +- Add configurable alignment operands for `memcpy` and `memset`; current toy + always emits alignment `1`. +- Add configurable `index` offset; current toy always passes offset `0`. +- Add direct field access syntax for arbitrary records. `fieldtest()` only + stores and loads field index `1` of the internal `Pair`. +- Add array indexing over array lvalues, not just pointer indexing. +- Add record and array copies that lower through normal source constructs. + +## Debug Location Coverage + +- Add tests that verify `cfree_cg_set_loc` flows through functions, scopes, + locals, params, instructions, and data definitions. +- Add multi-line expressions and initializers so sticky source locations are + exercised across nested parse/codegen calls. + +## Test Harness Work + +- Keep each new feature paired with a small toy corpus case under + `test/toy/cases`. +- Prefer one feature family per case so CG regressions point at a small surface. +- Run targeted toy cases across representative architectures when the feature + touches ABI, relocation, TLS, or inline asm behavior.