-
Notifications
You must be signed in to change notification settings - Fork 0
Implementable Spec
I use this document as my coding-facing contract for L0.
I keep every rule deterministic and machine-checkable.
I freeze runtime intrinsic compatibility in docs/INTRINSIC_CONTRACTS.md as intrinsics.v1.
I freeze debug-map compatibility in docs/DEBUG_MAP_SCHEMA.md as debugmap.v1.
I freeze trace-schema compatibility in docs/TRACE_SCHEMA.md as traceschema.v1.
I freeze deterministic build guarantees in docs/DETERMINISTIC_BUILDS.md as detbuild.v1.
I freeze differential semantic runtime-equivalence guarantees in docs/DIFFERENTIAL_TESTING.md as diffsem.v1.
I freeze fuzz and malformed-input crash-free stress guarantees in docs/FUZZ_STRESS.md as fuzzstress.v1.
I freeze performance baseline and throughput-floor guarantees in docs/PERFORMANCE_BASELINES.md as perfbase.v1.
I freeze CLI error category/message stability guarantees in docs/ERROR_MODEL.md as errmodel.v1.
I freeze release packaging and checksum reproducibility guarantees in docs/RELEASE_PIPELINE.md as relpipe.v1.
I freeze compatibility and upgrade-policy guarantees in docs/COMPATIBILITY_POLICY.md as compat.v1.
I freeze final production-readiness closure guarantees in docs/PRODUCTION_READINESS.md as prodready.v1.
module = ver_sec types_sec consts_sec extern_sec globals_sec fns_sec ;
ver_sec = "ver" SP "1" NL ;
types_sec = "types" SP "{" types_body "}" NL ;
types_body = SP
| SP type_entry ("," SP type_entry)* SP ;
type_entry = type_id "=" type_tok ;
type_tok = "i1" | "i8" | "i16" | "i32" | "i64"
| "u8" | "u16" | "u32" | "u64"
| "p0<i8>"
| struct_tok
| array_tok
| fn_type_tok ;
struct_tok = "s{" type_id ("," type_id)* "}" ;
array_tok = "a" pos_int "<" type_id ">" ;
fn_type_tok = "fn(" fn_type_args ")->" type_id ;
fn_type_args = /* empty */ | type_id ("," type_id)* ;
pos_int = nonzero_digit digit* ;
digit = "0" | nonzero_digit ;
nonzero_digit = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
consts_sec = "consts" SP "{" sec_payload "}" NL ;
extern_sec = "extern" SP "{" sec_payload "}" NL ;
globals_sec = "globals" SP "{" sec_payload "}" NL ;
sec_payload = *(any_byte_except_unmatched_close) ;
fns_sec = "fns" SP "{" NL fn_def+ "}" NL? ;
fn_def = "fn" SP fn_id SP "(" fn_args ")->" type_id SP "{" NL block+ "}" NL ;
fn_args = /* empty */ | type_id ("," type_id)* ;
block = block_id ":" NL instr+ ;
instr = term_instr | value_instr | nonvalue_instr ;
term_instr = IND "ret"
| IND "ret" SP value_id
| IND "br" SP block_id
| IND "cbr" SP value_id SP block_id SP block_id ;
value_instr = IND value_id SP "=" SP opcode SP args SP ":" SP type_id ;
nonvalue_instr = (IND "st" SP value_id SP value_id)
| (IND "free" SP value_id)
| (IND "exit" SP value_id)
| (IND "write" SP value_id SP value_id)
| (IND "trace" SP dec_u (SP value_id)+) ;
opcode = "arg" | "const" | "call"
| "add.wrap" | "add.trap" | "sub.wrap" | "sub.trap" | "mul.wrap" | "mul.trap"
| "and" | "or" | "xor" | "shl" | "shr"
| "icmp.eq"
| "ld" | "gep" | "alloca" | "malloc" ;
args = arg_args
| const_args
| call_args
| bin_args
| icmp_eq_args
| ld_args
| gep_args
| alloca_args
| malloc_args ;
arg_args = dec_u ;
const_args = dec_s ;
call_args = fn_id (SP value_id)* ;
bin_args = value_id SP value_id ;
icmp_eq_args= value_id SP value_id ;
ld_args = value_id ;
gep_args = value_id SP dec_s ;
alloca_args = type_id "," SP dec_u ;
malloc_args = value_id ;
fn_id = "f" dec_u ;
block_id = "b" dec_u ;
value_id = "v" dec_u ;
type_id = "t" dec_u ;
IND = " " ;
SP = " " ;
NL = "\n" ;
dec_u = digit+ ;
dec_s = ["-"] digit+ ;
digit = "0".."9" ;- Section order is fixed:
ver,types,consts,extern,globals,fns. - Function ids are contiguous and ordered:
f0,f1,f2, ... - Block ids are contiguous and ordered per function:
b0,b1,b2, ... - First block is always
b0. - Every instruction line uses two-space indent.
- Every block ends in a terminator.
- I reject unknown opcodes in value form.
- I reject non-canonical text instead of rewriting it.
- Every referenced
tNmust exist in parsedtypes. - Supported
typesRHS token forms:- primitive integers (
i1,i8,i16,i32,i64,u8,u16,u32,u64) - pointer (
p0<i8>) - struct (
s{tA,tB,...}with one-or-more fields) - fixed array (
aN<tA>withN > 0) - function type (
fn(tA,...)->tR)
- primitive integers (
- In
typesRHS struct/array/function tokens, referencedtNids are validated and forward/self refs are rejected in bootstrap parser mode. -
arg N:N < fn_arg_count- result type suffix must equal declared argument
Ntype
-
ret vX:-
vXmust be defined before use - type(
vX) must equal function return type
-
-
cbr vC bT bF:-
vCmust be defined before use - type(
vC) must bei1
-
- Binary ops (
add.wrap,add.trap,sub.wrap,sub.trap,mul.wrap,mul.trap,and,or,xor,shl,shr):- args shape:
vA vB - both operands defined before use
- type(
vA) == type(vB) == explicit result type suffix
- args shape:
-
icmp.eq:- args shape:
vA vB - both operands defined before use
- type(
vA) == type(vB) - explicit result type suffix must be
i1
- args shape:
-
call:- shape:
call fN [vA ...] - target
fNmust exist - operand count must match callee arity
- result type suffix must match callee return type
- each value operand must be defined before use
- shape:
-
ld:- shape:
ld vPtr -
vPtrmust be defined before use - type(
vPtr) must bep0<i8>
- shape:
-
gep:- shape:
gep vPtr off -
offis signed decimal -
vPtrmust be defined before use and typedp0<i8> - explicit result type suffix must be
p0<i8>
- shape:
-
alloca:- shape:
alloca tElem, N -
tElemmust exist -
Nis unsigned decimal - explicit result type suffix must be
p0<i8>
- shape:
-
malloc:- shape:
malloc vSize -
vSizemust be defined before use -
vSizemust not be pointer-typed - explicit result type suffix must be
p0<i8>
- shape:
-
st(non-value):- shape:
st vPtr vVal - both operands must be defined before use
-
vPtrmust be typedp0<i8>
- shape:
-
free(non-value):- shape:
free vPtr - operand must be defined before use
-
vPtrmust be typedp0<i8>
- shape:
-
exit(non-value):- shape:
exit vCode - operand must be defined before use
-
vCodemust not be pointer-typed
- shape:
-
write(non-value):- shape:
write vPtr vLen - both operands must be defined before use
-
vPtrmust be typedp0<i8> -
vLenmust not be pointer-typed
- shape:
-
trace(non-value):- shape:
trace N vVal... -
Nis unsigned decimal - one-or-more traced values are required
- each traced value must be defined before use
- shape:
- Integer ops currently implemented in lowering are wrap semantics on 64-bit registers, except
add.trap/sub.trap/mul.trapwhich trap on signed overflow (jo->ud2, process-terminating trap in current runtime path). -
icmp.eqreturns0or1. - Pointer arithmetic and memory instruction semantics are defined at verifier level; full lowering/runtime semantics are still incremental.
- I keep behavior defined by default and avoid UB contracts.
I currently lower deterministic canonical kernels:
- Two-arg kernels (
f0(t0,t0)->t0, single block):-
add.wrap,add.trap,sub.wrap,sub.trap,mul.wrap,mul.trap,and,or,xor,shl,shr
-
- Compare kernel:
-
icmp.eqreturningi1
-
- Control-flow select kernel:
-
icmp.eq+cbrselectingret v0orret v1
-
- Two-function call kernels:
-
f0callsf1wheref1is canonicaladd.wrap/sub.wrap/mul.wrap
-
- Memory kernels:
- canonical
alloca + st + ldroundtrip - canonical
alloca + st + gep + ldroundtrip
- canonical
- Intrinsic kernels:
- canonical
mallockernel (syscall-backedmmapallocator path) - canonical
freekernel (defined no-op returning zero in current slice) - canonical
exitkernel (syscall-backed process exit path) - canonical
writekernel (syscall-backed stdout write path) - canonical
tracekernel (fixed 16-byte binary trace emission to stderr in current slice)
- canonical
- Const-return kernel:
-
const N/const -Nthenret
-
For verified modules outside these patterns, I emit fallback code payload: single-byte ret (0xC3).
All fields are little-endian u64.
Header (80 bytes):
-
qword[0]: magic (L0IM) -
qword[1]: version (1) -
qword[2]: header size (80) -
qword[3]: flags (0) -
qword[4]:src_off -
qword[5]:src_size -
qword[6]:code_off -
qword[7]:code_size -
qword[8]:debug_off -
qword[9]:debug_size
Section order in file:
- header
- canonical source bytes
- code bytes
- debug semantic index bytes
debug_size = 64 bytes (L0IX payload):
-
qword[0]: magic (L0IX) -
qword[1]: version (1) -
qword[2]: function count -
qword[3]: type count -
qword[4]: kernel kind id -
qword[5]: emitted code size -
qword[6]: trace schema version (1) -
qword[7]: trace record size (16)
Current bootstrap kernel kind id mapping:
-
0: fallbackret -
1:add.wrap -
2:add.trap -
3:sub.wrap -
4:sub.trap -
5:mul.wrap -
6:and -
7:or -
8:xor -
9:shl -
10:shr -
11:icmp.eq -
12:icmp.eq + cbrselect -
13: const-return kernel -
14: memory roundtrip kernel (alloca/st/ld) -
15:mul.trap -
16: canonical call->add two-function kernel -
17: canonical call->sub two-function kernel -
18: canonical call->mul two-function kernel -
19: canonicalgepmemory roundtrip kernel -
20: canonicalmallockernel -
21: canonicalfreeno-op kernel -
22: canonicalwritenewline kernel -
23: canonicalexitkernel -
24: canonicaltraceemit kernel
l0c run <file.l0img> [u64_a] [u64_b]:
- validates image header and code section bounds
- allocates executable memory via
mmap - copies code section
- calls code as
fn(u64,u64)->u64 - prints returned value as unsigned decimal
Optional build-side bootstrap artifacts:
-
--trace-schema <out.bin>:- 32-byte payload:
L0TS, version1, record size16, field count2
- 32-byte payload:
-
--debug-map <out.bin>:- variable-size payload:
L0DM, version2, entry countN, code size, thenNtriplets ofinst_id/start/end
- variable-size payload:
- current bootstrap parser accepts either option independently or both together, and rejects duplicate optional flags
Native bootstrap decode helpers:
tracecat <trace.bin>mapcat <debug_map.bin>schemacat <trace_schema.bin>tracejoin <trace.bin> <debug_map.bin>
To complete the M1 scope, I still need to finish:
- lowering for verified
ld/st/gep/allocamodules (not only verify) - non-kernel generalization of intrinsic/runtime surface (
write/malloc/free/exit) - extend debug-map coverage from kernel-template ranges to full per-L0-instruction lowering coverage for generalized codegen paths
- broader canonical rewrite mode (optional
--fixpath)
- How-To-Write-L0
- Language-Reference
- Instruction-Set
- CLI-and-Compiler-Spec
- Implementable-Spec
- Command-Reference
- Examples-Catalog
- LLM-Quick-Reference
- Opcode-Examples
- LLM-Doc-Index