commit 65fc09c8eabc994c0c5b77384b896cdbb9d5aaf2
parent ad86871713a85088c3cb1d3aa5f9f0eb383cd665
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sun, 26 Apr 2026 15:14:14 -0700
scheme1: adopt libp1pp global/array helpers; add pair + heap field macros
Replace open-coded la+ld(_,0) and li+mul+add+ld sequences with the
new ld_global / st_global / ld_array / st_array helpers. Add
scheme1-local set_car / set_cdr for tagged-pair stores and
heap_ld / heap_st for tagged-heap-pointer field access via a
constant field offset; declare BV and REC structs to back them.
Trim the now-stale file-header narrative.
Diffstat:
| M | scheme1/scheme1.P1pp | | | 2522 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
1 file changed, 1231 insertions(+), 1291 deletions(-)
diff --git a/scheme1/scheme1.P1pp b/scheme1/scheme1.P1pp
@@ -1,36 +1,11 @@
# scheme1.P1pp -- Phase 1 minimal Scheme interpreter on P1.
#
-# The full target is described in docs/LISP-C.md and docs/LISP.md. This
-# file is the spine: enough infrastructure to read a single source file,
-# parse one s-expression, and evaluate it via tag-dispatched eval/apply
-# with a single primitive (`sys-exit`). Every later piece (more
-# primitives, special forms, closures, pmatch, records, prelude, repl
-# loop) hooks onto these anchors without restructuring.
-#
-# What's wired up now:
-# - Tag layout per LISP-C.md: fixnums, pairs, symbols, headered objects,
-# immediate singletons. mkimm composes IMM constants at M1pp time.
-# - Bump heap allocator (cons + alloc_hdr) over a BSS-past-ELF_end arena.
-# - Linear-scan symbol intern table; entries store (name_ptr, name_len,
-# global_val) borrowed directly from readbuf.
-# - Reader: '(', ')', fixnums (decimal, optional leading `-`), bare
-# symbols. No strings/hex/chars/quote/dotted yet, no `;` comments.
-# - eval: tag dispatch -> self-eval / symbol lookup / pair application.
-# - apply: HDR.PRIM dispatch only; closures/specials come later.
-# - One primitive: sys-exit. Exits with the raw fixnum.
-#
-# Build chain (P1pp.P1pp = libp1pp must be in the catm sequence):
+# Build chain:
# catm P1-<arch>.M1pp P1.M1pp P1pp.P1pp scheme1/scheme1.P1pp \
# | m1pp -> M0 -> hex2 -> ELF
#
-# At run time, scripts/boot-run-scheme1.sh catm's scheme1/prelude.scm
-# in front of the user .scm and passes the combined file to the binary,
-# so the interpreter itself has no embedded prelude.
-#
-# Memory model: the ELF's ph_memsz is 8 MB (boot2 default), so all
-# zero-initialized arenas live past :ELF_end and cost zero file bytes.
-# p1_main writes their absolute addresses into pointer slots once at
-# startup; every later access goes through one extra load.
+# Run chain:
+# catm scheme1/prelude.scm prog.scm | scheme1
# =========================================================================
# Constants
@@ -43,9 +18,7 @@
# imm_val(idx) -> integer-expression for the tagged immediate at IMM index
# `idx`. Used both at %li sites (loaded into a register) and at $() emission
# sites (baked into a static word).
-%macro imm_val(idx)
-(| (<< idx 3) %TAG.IMM)
-%endm
+%macro imm_val(idx) (| (<< idx 3) %TAG.IMM) %endm
# Layout helpers. %struct stride is 8 bytes per field.
%struct PAIR { car cdr } # .SIZE = 16
@@ -53,6 +26,8 @@
%struct PRIM { hdr entry_w data } # .SIZE = 24
%struct CLOSURE { hdr params body env } # .SIZE = 32
%struct TD { hdr name nfields } # .SIZE = 24
+%struct BV { hdr data } # .SIZE = 16
+%struct REC { hdr td } # .SIZE = 16 (header)
# Records are variable width: header + td slot + N field slots.
# BSS arena offsets from :ELF_end. readbuf is 256 KiB (sized to fit
@@ -63,49 +38,29 @@
# startup loop materializes &ELF_end + OFF_X into the matching pointer
# slot. The offsets are emitted directly in bss_init_tbl via $().
-%macro SYMTAB_CAP_SLOTS()
-8192
-%endm
-
-%macro READBUF_CAP_BYTES()
-262144
-%endm
-
-%macro HEAP_CAP_BYTES()
-0x1000000
-%endm
+%macro SYMTAB_CAP_SLOTS() 8192 %endm
+%macro READBUF_CAP_BYTES() 262144 %endm
+%macro HEAP_CAP_BYTES() 0x1000000 %endm
# =========================================================================
# Tag idioms
# =========================================================================
-%macro tagof(rd, rs)
-%andi(rd, rs, 7)
-%endm
-
-%macro mkfix(rd, rs)
-%shli(rd, rs, 3)
-%endm
-
-%macro untag_fix(rd, rs)
-%sari(rd, rs, 3)
-%endm
-
-%macro untag_sym(rd, rs)
-%sari(rd, rs, 3)
-%endm
-
-%macro car(rd, rs)
-%ld(rd, rs, -1)
-%endm
-
-%macro cdr(rd, rs)
-%ld(rd, rs, 7)
-%endm
-
-%macro hdr_type(rd, rs)
-%lb(rd, rs, -3)
-%endm
+%macro tagof(rd, rs) %andi(rd, rs, 7) %endm
+%macro mkfix(rd, rs) %shli(rd, rs, 3) %endm
+%macro untag_fix(rd, rs) %sari(rd, rs, 3) %endm
+%macro untag_sym(rd, rs) %sari(rd, rs, 3) %endm
+%macro car(rd, rs) %ld(rd, rs, -1) %endm
+%macro cdr(rd, rs) %ld(rd, rs, 7) %endm
+%macro set_car(rs, pair_tagged) %st(rs, pair_tagged, -1) %endm
+%macro set_cdr(rs, pair_tagged) %st(rs, pair_tagged, 7) %endm
+%macro hdr_type(rd, rs) %lb(rd, rs, -3) %endm
+
+# Field access through a tagged HEAP pointer (tag = 3). `field` is a
+# constant byte offset from the underlying raw object (e.g. %PRIM.data,
+# %CLOSURE.env). Reader is %ld; writer is %heap_st.
+%macro heap_ld(rd, rs, field) %ld(rd, rs, (- field 3)) %endm
+%macro heap_st(rs, rt, field) %st(rs, rt, (- field 3)) %endm
# =========================================================================
# Scheme1-local helpers
@@ -115,217 +70,169 @@
# be the destination register; the macro reuses it as a scratch pointer
# during the la / ld / add chain before the final lb writes the byte.
%macro readbuf_byte(rd, off_reg)
-%la(rd, &readbuf_buf_ptr)
-%ld(rd, rd, 0)
-%add(rd, rd, off_reg)
-%lb(rd, rd, 0)
+ %ld_global(rd, &readbuf_buf_ptr)
+ %add(rd, rd, off_reg)
+ %lb(rd, rd, 0)
%endm
# Branch to `target` if `ch_reg` holds an ASCII whitespace byte (space,
# tab, LF, CR). `scratch` is clobbered.
%macro is_ws_branch(scratch, ch_reg, target)
-%addi(scratch, ch_reg, -32)
-%beqz(scratch, target)
-%addi(scratch, ch_reg, -9)
-%beqz(scratch, target)
-%addi(scratch, ch_reg, -10)
-%beqz(scratch, target)
-%addi(scratch, ch_reg, -13)
-%beqz(scratch, target)
+ %addi(scratch, ch_reg, -32)
+ %beqz(scratch, target)
+ %addi(scratch, ch_reg, -9)
+ %beqz(scratch, target)
+ %addi(scratch, ch_reg, -10)
+ %beqz(scratch, target)
+ %addi(scratch, ch_reg, -13)
+ %beqz(scratch, target)
%endm
# Compute &symtab_buf + idx_reg * SYMENT.SIZE into rd. `scratch` is
# clobbered.
%macro symtab_entry(rd, idx_reg, scratch)
-%la(rd, &symtab_buf_ptr)
-%ld(rd, rd, 0)
-%shli(scratch, idx_reg, 5)
-%add(rd, rd, scratch)
+ %ld_global(rd, &symtab_buf_ptr)
+ %shli(scratch, idx_reg, 5)
+ %add(rd, rd, scratch)
%endm
# Print msg_label and abort. Never returns. Routes through runtime_error
# so every error path lands in one place (stderr + exit 1).
%macro die(msg)
-%la(a0, & ## msg)
-%call(&runtime_error)
+ %la(a0, & ## msg)
+ %call(&runtime_error)
%endm
# Intern a special-form name and stash the tagged-symbol value in a
# labeled slot. `name` and `slot` are written as full label refs
# (`&foo`) so the macro can substitute them verbatim into %la sites.
%macro intern_form(name, len, slot)
-%la(a0, name)
-%li(a1, len)
-%call(&intern)
-%la(t0, slot)
-%st(a0, t0, 0)
+ %la(a0, name)
+ %li(a1, len)
+ %call(&intern)
+ %st_global(a0, slot, t0)
%endm
# Special-form dispatch: pointer-compare the head symbol against `slot`'s
# cached value (in t0) and branch to `target` on hit. Caller has already
# loaded head into t0.
%macro dispatch_form(slot, target)
-%la(t1, slot)
-%ld(t1, t1, 0)
-%beq(t0, t1, target)
+ %ld_global(t1, slot)
+ %beq(t0, t1, target)
%endm
# Tail-jump from a special-form dispatch label to its handler. Handlers
# uniformly take (rest=cdr(expr), env) -> value; expr lives at sp[0],
# env at sp[8] in eval's frame.
%macro tail_to_handler(handler)
-%ld(a0, sp, 0)
-%cdr(a0, a0)
-%ld(a1, sp, 8)
-%tail(handler)
+ %ld(a0, sp, 0)
+ %cdr(a0, a0)
+ %ld(a1, sp, 8)
+ %tail(handler)
%endm
# Branch to `target` if `val` holds the NIL immediate. `scratch` is
# clobbered.
%macro if_nil(scratch, val, target)
-%li(scratch, %imm_val(%IMM.NIL))
-%beq(val, scratch, target)
+ %li(scratch, %imm_val(%IMM.NIL))
+ %beq(val, scratch, target)
%endm
# Advance a list cursor parked at sp[slot] to its cdr. t0 is the implicit
# scratch register; callers must ensure it's free.
%macro advance_walk(slot)
-%ld(t0, sp, slot)
-%cdr(t0, t0)
-%st(t0, sp, slot)
+ %ld(t0, sp, slot)
+ %cdr(t0, t0)
+ %st(t0, sp, slot)
%endm
# Bind a global from registers a0 (value) and t0 (tagged sym). Untags t0,
# rearranges into the (idx, val) ABI, and calls sym_set_global. Used at
# the tail of every define-style binder.
%macro bind_global_from_t0()
-%untag_sym(t0, t0)
-%mov(a1, a0)
-%mov(a0, t0)
-%call(&sym_set_global)
+ %untag_sym(t0, t0)
+ %mov(a1, a0)
+ %mov(a0, t0)
+ %call(&sym_set_global)
%endm
# car-and-untag-fixnum: rd = car(list) >> 3.
%macro car_fix(rd, list)
-%car(rd, list)
-%sari(rd, rd, 3)
+ %car(rd, list)
+ %sari(rd, rd, 3)
%endm
# car-then-load-bytevector-data-pointer: rd = (car(list)).data_ptr.
%macro car_bvdata(rd, list)
-%car(rd, list)
-%ld(rd, rd, 5)
+ %car(rd, list)
+ %ld(rd, rd, 5)
%endm
# Positional list-arg extraction. r_n receives the nth element of `list`;
# the last destination register doubles as the in-flight rest cursor
# during extraction (its final value is the last argument).
%macro args2(r0, r1, list)
-%car(r0, list)
-%cdr(r1, list)
-%car(r1, r1)
+ %car(r0, list)
+ %cdr(r1, list)
+ %car(r1, r1)
%endm
%macro args3(r0, r1, r2, list)
-%car(r0, list)
-%cdr(r2, list)
-%car(r1, r2)
-%cdr(r2, r2)
-%car(r2, r2)
+ %car(r0, list)
+ %cdr(r2, list)
+ %car(r1, r2)
+ %cdr(r2, r2)
+ %car(r2, r2)
%endm
%macro args4(r0, r1, r2, r3, list)
-%car(r0, list)
-%cdr(r3, list)
-%car(r1, r3)
-%cdr(r3, r3)
-%car(r2, r3)
-%cdr(r3, r3)
-%car(r3, r3)
+ %car(r0, list)
+ %cdr(r3, list)
+ %car(r1, r3)
+ %cdr(r3, r3)
+ %car(r2, r3)
+ %cdr(r3, r3)
+ %car(r3, r3)
%endm
# =========================================================================
# p1_main -- runtime spine
# =========================================================================
-#
-# Frame layout (16 bytes):
-# +0 saved argv
-
-%fn(p1_main, 16, {
- %st(a1, sp, 0)
-
- # Stash argc/argv globally so the sys-argv primitive can rebuild a
- # list of bytevectors on demand without re-plumbing them through
- # every call frame.
- %la(t0, &saved_argc)
- %st(a0, t0, 0)
- %la(t0, &saved_argv)
- %st(a1, t0, 0)
+%fn(p1_main, 0, {
+ # Stash argc/argv
+ %st_global(a0, &saved_argc, t0)
+ %st_global(a1, &saved_argv, t0)
+
+ # if argc < 2 goto usage
%li(t0, 2)
%bltu(a0, t0, &::usage)
- # Initialize BSS pointer slots from ELF_end + OFF_*. Same idiom as
- # M1pp.P1: a tiny init table walked once.
- %la(t0, &ELF_end)
- %la(t1, &bss_init_tbl)
- %la(t2, &bss_init_tbl_end)
- ::bss_loop
- %beq(t1, t2, &::bss_done)
- %ld(a0, t1, 0)
- %ld(a2, t1, 8)
- %add(a2, a2, t0)
- %st(a2, a0, 0)
- %addi(t1, t1, 16)
- %b(&::bss_loop)
- ::bss_done
-
- # heap_next = &heap_buf, rounded up to 8-byte alignment. The BSS arena
- # starts at &ELF_end + OFF_heap, but &ELF_end's alignment depends on
- # the data section above it; cons assumes 8-byte-aligned heap_next so
- # every pair pointer's low 3 bits are exactly the PAIR tag.
- %la(t0, &heap_buf_ptr)
- %ld(t0, t0, 0)
- %alignup(t0, t0, 8, t1)
- %la(t1, &heap_next)
- %st(t0, t1, 0)
-
- # heap_end = heap_buf_ptr + HEAP_CAP_BYTES. cons / alloc_hdr /
- # alloc_bytes test (heap_next + bytes <= heap_end) on every
- # allocation and abort via runtime_error on overflow.
- %la(t0, &heap_buf_ptr)
- %ld(t0, t0, 0)
- %li(t1, %HEAP_CAP_BYTES)
- %add(t0, t0, t1)
- %la(t1, &heap_end)
- %st(t0, t1, 0)
-
- # Reserve special-form symbol indices, then bind built-in primitives.
- # The Scheme prelude is catm'd into argv[1] by scripts/run-scheme1.sh
- # before scheme1 starts, so there's no separate prelude eval pass.
+ # Initialize
+ %call(&bss_init)
+ %call(&heap_init)
%call(&intern_special_forms)
%call(®ister_primitives)
- # argv[1] is the source path (NUL-terminated cstr from the kernel).
- %ld(a1, sp, 0)
- %ld(a0, a1, 8)
+ # load_source(argv[1])
+ %ld_global(a0, &saved_argv)
+ %ld(a0, a0, 8)
%call(&load_source)
- # Top-level read-eval loop. Each iteration: skip ws+comments, stop
- # at EOF, otherwise parse one form and eval it under NIL.
- ::repl
- %call(&skip_ws)
- %la(t0, &readbuf_pos)
- %ld(t0, t0, 0)
- %la(t1, &readbuf_len)
- %ld(t1, t1, 0)
- %beq(t0, t1, &::done)
- %call(&parse_one)
- %li(a1, %imm_val(%IMM.NIL))
- %call(&eval)
- %b(&::repl)
-
- ::done
+ # read-eval loop
+ %loop_tag(eval, {
+ # eof = skip_ws()
+ %call(&skip_ws)
+ # if eof break
+ %bnez(a0, &eval_end)
+ # expr = parse_one()
+ %call(&parse_one)
+ # eval(expr, env=nil)
+ %li(a1, %imm_val(%IMM.NIL))
+ %call(&eval)
+ })
+
+ # return 0
%li(a0, 0)
%eret
@@ -336,218 +243,6 @@
})
# =========================================================================
-# Runtime error -- single abort entry point
-# =========================================================================
-#
-# runtime_error(msg_cstr=a0) -> never returns. Every overflow / bounds /
-# unbound / type-failure path lands here so error reporting (and the
-# eventual user-facing `error` primitive) only have to be implemented
-# once. Today we tail into libp1pp's `panic`, which writes msg + LF to
-# stderr and sys_exits 1.
-:runtime_error
- %tail(&panic)
-
-# =========================================================================
-# Source loading -- argv[1] -> readbuf, length stored in readbuf_len
-# =========================================================================
-
-%fn(load_source, 0, {
- %la(t0, &readbuf_buf_ptr)
- %ld(a1, t0, 0)
- %li(a2, %READBUF_CAP_BYTES)
- %call(&read_file)
- %bltz(a0, &::fail)
-
- # If the read filled (or would have filled) the buffer, the source
- # is at least cap bytes; refuse rather than silently truncate.
- # read_file does a single sys_read so n == cap is the only saturation
- # signal we have. We treat n >= cap as overflow defensively.
- %li(t0, %READBUF_CAP_BYTES)
- %bltu(a0, t0, &::ok)
- %die(msg_readbuf_full)
-
- ::ok
- %la(t0, &readbuf_len)
- %st(a0, t0, 0)
- %li(a0, 0)
- %la(t0, &readbuf_pos)
- %st(a0, t0, 0)
- %eret
-
- ::fail
- %die(msg_load_fail)
-})
-
-# =========================================================================
-# Heap: cons (leaf) and alloc_hdr (leaf)
-# =========================================================================
-#
-# Both are call-free leaves: bump heap_next, write fields, return tagged
-# pointer. Each allocation tests (new_next <= heap_end) and aborts via
-# runtime_error if the bump would overflow the heap arena. heap_next is
-# kept 8-byte aligned so every PAIR/HEAP tag bit is exact: cons always
-# bumps by a multiple of 8 (16); alloc_hdr / alloc_bytes round their
-# argument up via %alignup(_,_,8,_).
-
-# cons(car=a0, cdr=a1) -> tagged pair (a0). Allocates 16 bytes.
-:cons
-%scope cons
- %la(t2, &heap_next)
- %ld(t0, t2, 0)
- %addi(t1, t0, 16)
- %la(a3, &heap_end)
- %ld(a3, a3, 0)
- %bltu(a3, t1, &::oom)
- %st(a0, t0, 0)
- %st(a1, t0, 8)
- %st(t1, t2, 0)
- %addi(a0, t0, 1)
- %ret
- ::oom
- %die(msg_heap_full)
-%endscope
-
-# alloc_hdr(bytes=a0, hdr_word=a1) -> tagged heap obj (a0)
-# Rounds bytes up to a multiple of 8 and writes hdr_word at offset 0.
-:alloc_hdr
-%scope alloc_hdr
- %alignup(a0, a0, 8, t0)
- %la(t2, &heap_next)
- %ld(t0, t2, 0)
- %add(t1, t0, a0)
- %la(a3, &heap_end)
- %ld(a3, a3, 0)
- %bltu(a3, t1, &::oom)
- %st(t1, t2, 0)
- %st(a1, t0, 0)
- %addi(a0, t0, 3)
- %ret
- ::oom
- %die(msg_heap_full)
-%endscope
-
-# list_length(list=a0) -> count (a0). Linear walk; clobbers a0 (used as
-# the cursor). Callers that need the list afterward must save it first.
-:list_length
-%scope list_length
- %li(t0, 0)
- ::loop
- %if_nil(t1, a0, &::done)
- %addi(t0, t0, 1)
- %cdr(a0, a0)
- %b(&::loop)
- ::done
- %mov(a0, t0)
- %ret
-%endscope
-
-# =========================================================================
-# Symbol intern -- linear scan, append on miss
-# =========================================================================
-#
-# Frame: 32 bytes
-# +0 name_ptr (input)
-# +8 name_len (input)
-# +16 idx (loop counter / found index)
-# +24 entry_ptr (spilled across memcmp)
-
-%fn(intern, 32, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
-
- %li(t0, 0)
- %st(t0, sp, 16)
-
- ::scan
- # idx >= count? -> append
- %ld(t0, sp, 16)
- %la(t1, &symtab_count)
- %ld(t1, t1, 0)
- %bltu(t0, t1, &::probe)
- %b(&::append)
-
- ::probe
- %symtab_entry(t1, t0, t2)
- %st(t1, sp, 24)
-
- # entry.name_len == name_len ?
- %ld(t2, t1, 8)
- %ld(a2, sp, 8)
- %bne(t2, a2, &::next)
-
- # memcmp(entry.name_ptr, name_ptr, len)
- %ld(a0, t1, 0)
- %ld(a1, sp, 0)
- %ld(a2, sp, 8)
- %call(&memcmp)
- %beqz(a0, &::found)
-
- ::next
- %ld(t0, sp, 16)
- %addi(t0, t0, 1)
- %st(t0, sp, 16)
- %b(&::scan)
-
- ::append
- # Bounds check; on overflow exit 5 with a message.
- %ld(t0, sp, 16)
- %li(t1, %SYMTAB_CAP_SLOTS)
- %bltu(t0, t1, &::append_ok)
- %die(msg_symtab_full)
-
- ::append_ok
- # Copy the name into a stable heap buffer. The caller-provided ptr
- # may live in readbuf_buf (parse_atom), which gets overwritten when
- # the next source is loaded; symtab entries must outlive that.
- %ld(a0, sp, 8)
- %call(&alloc_bytes)
- %ld(a1, sp, 0)
- %ld(a2, sp, 8)
- %call(&memcpy) ; returns dst in a0 = stable copy
-
- %ld(t0, sp, 16)
- %symtab_entry(t1, t0, t2)
- %st(a0, t1, 0) ; entry.name_ptr = stable copy
- %ld(a0, sp, 8)
- %st(a0, t1, 8)
- %li(a0, %imm_val(%IMM.UNBOUND))
- %st(a0, t1, 16)
- %li(a0, 0)
- %st(a0, t1, 24)
-
- # symtab_count = idx + 1
- %addi(a0, t0, 1)
- %la(t2, &symtab_count)
- %st(a0, t2, 0)
-
- # fall through with idx in t0 = sp[16]
-
- ::found
- %ld(t0, sp, 16)
- %shli(a0, t0, 3)
- %ori(a0, a0, %TAG.SYM)
-})
-
-# Lookup by sym_idx (untagged, in a0). Returns symtab[idx].global_val in a0.
-# Leaf.
-:sym_global
- %la(t0, &symtab_buf_ptr)
- %ld(t0, t0, 0)
- %shli(t1, a0, 5)
- %add(t0, t0, t1)
- %ld(a0, t0, 16)
- %ret
-
-# sym_set_global(idx=a0, val=a1). Leaf.
-:sym_set_global
- %la(t0, &symtab_buf_ptr)
- %ld(t0, t0, 0)
- %shli(t1, a0, 5)
- %add(t0, t0, t1)
- %st(a1, t0, 16)
- %ret
-
-# =========================================================================
# Reader -- parse_one over readbuf with a single byte cursor
# =========================================================================
#
@@ -555,47 +250,47 @@
# The reader is called recursively from parse_list, so every state goes
# through frame slots, not s-registers.
-# Skip whitespace (ASCII 32, 9, 10, 13) and `;`-to-LF comments. Leaf.
+# Skip whitespace (ASCII 32, 9, 10, 13) and `;`-to-LF comments. Returns
+# a0 = 1 if readbuf_pos >= readbuf_len after skipping (caller hit EOF),
+# else 0. Leaf.
:skip_ws
%scope skip_ws
- %la(t2, &readbuf_pos)
- %ld(t0, t2, 0)
- %la(t1, &readbuf_len)
- %ld(t1, t1, 0)
+ %lda_global(t0, t2, &readbuf_pos)
+ %ld_global(t1, &readbuf_len)
::loop
- %beq(t0, t1, &::done)
- %readbuf_byte(a0, t0)
- %is_ws_branch(a1, a0, &::step)
- %addi(a1, a0, -59) ; ';'
- %beqz(a1, &::comment)
- %b(&::done)
- ::comment
- # Consume up to and including the next LF, or to EOF.
- %addi(t0, t0, 1)
- %beq(t0, t1, &::done)
- %readbuf_byte(a0, t0)
- %addi(a1, a0, -10)
- %bnez(a1, &::comment)
- %addi(t0, t0, 1)
- %b(&::loop)
- ::step
- %addi(t0, t0, 1)
- %b(&::loop)
+ %beq(t0, t1, &::done)
+ %readbuf_byte(a0, t0)
+ %is_ws_branch(a1, a0, &::step)
+ %addi(a1, a0, -59) ; ';'
+ %beqz(a1, &::comment)
+ %b(&::done)
+ ::comment
+ # Consume up to and including the next LF, or to EOF.
+ %addi(t0, t0, 1)
+ %beq(t0, t1, &::done)
+ %readbuf_byte(a0, t0)
+ %addi(a1, a0, -10)
+ %bnez(a1, &::comment)
+ %addi(t0, t0, 1)
+ %b(&::loop)
+ ::step
+ %addi(t0, t0, 1)
+ %b(&::loop)
::done
%st(t0, t2, 0)
+ %li(a0, 1)
+ %beq(t0, t1, &::ret)
+ %li(a0, 0)
+ ::ret
%ret
%endscope
# parse_one() -> tagged value in a0
%fn(parse_one, 0, {
%call(&skip_ws)
+ %bnez(a0, &::eof)
- %la(t0, &readbuf_pos)
- %ld(t0, t0, 0)
- %la(t1, &readbuf_len)
- %ld(t1, t1, 0)
- %beq(t0, t1, &::eof)
-
+ %ld_global(t0, &readbuf_pos)
%readbuf_byte(a0, t0)
%addi(a1, a0, -40)
@@ -615,8 +310,7 @@
::lparen
# Consume '(' and read items until ')'.
- %la(t0, &readbuf_pos)
- %ld(t1, t0, 0)
+ %lda_global(t1, t0, &readbuf_pos)
%addi(t1, t1, 1)
%st(t1, t0, 0)
%tail(&parse_list)
@@ -627,19 +321,16 @@
::string
# Consume opening '"' and tail to parse_string. parse_string scans
# through the matching '"' (consuming it) and returns a tagged bv.
- %la(t0, &readbuf_pos)
- %ld(t1, t0, 0)
+ %lda_global(t1, t0, &readbuf_pos)
%addi(t1, t1, 1)
%st(t1, t0, 0)
%tail(&parse_string)
::hash
# Consume '#' plus its type byte; dispatch on the type byte.
- %la(t2, &readbuf_pos)
- %ld(t0, t2, 0)
+ %lda_global(t0, t2, &readbuf_pos)
%addi(t0, t0, 1)
- %la(t1, &readbuf_len)
- %ld(t1, t1, 0)
+ %ld_global(t1, &readbuf_len)
%beq(t0, t1, &::eof)
%readbuf_byte(a0, t0)
%addi(t0, t0, 1)
@@ -671,20 +362,19 @@
# then parse_hex over the slice (with optional leading '-').
%mov(a3, t0)
::hex_scan
- %beq(t0, t1, &::hex_end)
- %readbuf_byte(a0, t0)
- %is_ws_branch(a1, a0, &::hex_end)
- %addi(a1, a0, -40)
- %beqz(a1, &::hex_end)
- %addi(a1, a0, -41)
- %beqz(a1, &::hex_end)
- %addi(t0, t0, 1)
- %b(&::hex_scan)
+ %beq(t0, t1, &::hex_end)
+ %readbuf_byte(a0, t0)
+ %is_ws_branch(a1, a0, &::hex_end)
+ %addi(a1, a0, -40)
+ %beqz(a1, &::hex_end)
+ %addi(a1, a0, -41)
+ %beqz(a1, &::hex_end)
+ %addi(t0, t0, 1)
+ %b(&::hex_scan)
::hex_end
- %la(t2, &readbuf_pos)
- %st(t0, t2, 0)
- %la(a0, &readbuf_buf_ptr)
- %ld(a0, a0, 0)
+
+ %st_global(t0, &readbuf_pos, t2)
+ %ld_global(a0, &readbuf_buf_ptr)
%add(a0, a0, a3)
%sub(a1, t0, a3)
%lb(t2, a0, 0)
@@ -705,15 +395,13 @@
::quote
# Consume the leading '\''; recurse into parse_one for the datum;
# then build (quote <datum>).
- %la(t2, &readbuf_pos)
- %ld(t0, t2, 0)
+ %lda_global(t0, t2, &readbuf_pos)
%addi(t0, t0, 1)
%st(t0, t2, 0)
%call(&parse_one)
%li(a1, %imm_val(%IMM.NIL))
%call(&cons)
- %la(t0, &sym_quote)
- %ld(t0, t0, 0)
+ %ld_global(t0, &sym_quote)
%mov(a1, a0)
%mov(a0, t0)
%tail(&cons)
@@ -725,15 +413,13 @@
# quasiquote evaluator. Outside a pmatch pattern this list reaches
# eval as an application of the (unbound) `unquote` and dies through
# the standard unbound-variable path.
- %la(t2, &readbuf_pos)
- %ld(t0, t2, 0)
+ %lda_global(t0, t2, &readbuf_pos)
%addi(t0, t0, 1)
%st(t0, t2, 0)
%call(&parse_one)
%li(a1, %imm_val(%IMM.NIL))
%call(&cons)
- %la(t0, &sym_unquote)
- %ld(t0, t0, 0)
+ %ld_global(t0, &sym_unquote)
%mov(a1, a0)
%mov(a0, t0)
%tail(&cons)
@@ -746,10 +432,8 @@
::u8_lit
# Cursor is past '#u'. Demand '8' then '('; consume both and tail to
# parse_u8_body, which reads the element list and packs it into a bv.
- %la(t2, &readbuf_pos)
- %ld(t0, t2, 0)
- %la(t1, &readbuf_len)
- %ld(t1, t1, 0)
+ %lda_global(t0, t2, &readbuf_pos)
+ %ld_global(t1, &readbuf_len)
%beq(t0, t1, &::u8_bad)
%readbuf_byte(a0, t0)
%addi(a1, a0, -56) ; '8'
@@ -776,18 +460,17 @@
# Frame: 16 bytes
# +0 head (NIL until first item)
# +8 tail (most recent cons; set-cdr! target)
-%fn(parse_list, 16, {
+%struct PARSE_LIST_LOCALS { head tail } # .SIZE = 16
+%fn(parse_list, %PARSE_LIST_LOCALS.SIZE, {
%li(t0, %imm_val(%IMM.NIL))
- %st(t0, sp, 0)
- %st(t0, sp, 8)
+ %st(t0, sp, %PARSE_LIST_LOCALS.head)
+ %st(t0, sp, %PARSE_LIST_LOCALS.tail)
::loop
%call(&skip_ws)
- %la(t0, &readbuf_pos)
- %ld(t0, t0, 0)
- %la(t1, &readbuf_len)
- %ld(t1, t1, 0)
- %beq(t0, t1, &::eof)
+ %bnez(a0, &::eof)
+ %ld_global(t0, &readbuf_pos)
+ %ld_global(t1, &readbuf_len)
%readbuf_byte(a0, t0)
%addi(a1, a0, -41)
@@ -813,52 +496,46 @@
%call(&cons)
# If head is NIL, both head and tail = new cons; else set-cdr! tail = new.
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PARSE_LIST_LOCALS.head)
%li(t1, %imm_val(%IMM.NIL))
%bne(t0, t1, &::link)
- %st(a0, sp, 0)
- %st(a0, sp, 8)
+ %st(a0, sp, %PARSE_LIST_LOCALS.head)
+ %st(a0, sp, %PARSE_LIST_LOCALS.tail)
%b(&::loop)
::link
- %ld(t0, sp, 8)
+ %ld(t0, sp, %PARSE_LIST_LOCALS.tail)
# set-cdr! tail = a0 -> store a0 at [tail + 7] (raw + 8)
- %st(a0, t0, 7)
- %st(a0, sp, 8)
+ %set_cdr(a0, t0)
+ %st(a0, sp, %PARSE_LIST_LOCALS.tail)
%b(&::loop)
::do_dot
# Consume the '.', read one datum, splice it in as the cdr of the
# tail cons. Then expect a closing ')' (with optional ws).
- %la(t1, &readbuf_pos)
- %ld(t0, t1, 0)
+ %lda_global(t0, t1, &readbuf_pos)
%addi(t0, t0, 1)
%st(t0, t1, 0)
%call(&parse_one)
- %ld(t0, sp, 8)
- %st(a0, t0, 7)
+ %ld(t0, sp, %PARSE_LIST_LOCALS.tail)
+ %set_cdr(a0, t0)
%call(&skip_ws)
- %la(t0, &readbuf_pos)
- %ld(t0, t0, 0)
- %la(t1, &readbuf_len)
- %ld(t1, t1, 0)
- %beq(t0, t1, &::eof)
+ %bnez(a0, &::eof)
+ %lda_global(t0, t1, &readbuf_pos)
%readbuf_byte(a0, t0)
%addi(a1, a0, -41)
%bnez(a1, &::eof)
%addi(t0, t0, 1)
- %la(t1, &readbuf_pos)
%st(t0, t1, 0)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %PARSE_LIST_LOCALS.head)
%eret
::close
# Consume ')' and return head.
- %la(t0, &readbuf_pos)
- %ld(t1, t0, 0)
+ %lda_global(t1, t0, &readbuf_pos)
%addi(t1, t1, 1)
%st(t1, t0, 0)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %PARSE_LIST_LOCALS.head)
%eret
::eof
@@ -873,27 +550,28 @@
# Frame: 16 bytes
# +0 list head (cursor during fill pass)
# +8 result bv
-%fn(parse_u8_body, 16, {
+%struct PARSE_U8_BODY_LOCALS { list result } # .SIZE = 16
+%fn(parse_u8_body, %PARSE_U8_BODY_LOCALS.SIZE, {
%call(&parse_list)
- %st(a0, sp, 0)
+ %st(a0, sp, %PARSE_U8_BODY_LOCALS.list)
%call(&list_length) ; clobbers a0 -> count
%call(&bv_alloc) ; a0 = bv
- %st(a0, sp, 8)
+ %st(a0, sp, %PARSE_U8_BODY_LOCALS.result)
- %ld(t0, a0, 5) ; data ptr
- %ld(a0, sp, 0) ; list cursor
+ %heap_ld(t0, a0, %BV.data)
+ %ld(a0, sp, %PARSE_U8_BODY_LOCALS.list) ; list cursor
::loop
- %if_nil(t1, a0, &::done)
- %car(t1, a0)
- %sari(t1, t1, 3) ; untag fixnum -> raw byte
- %sb(t1, t0, 0)
- %addi(t0, t0, 1)
- %cdr(a0, a0)
- %b(&::loop)
+ %if_nil(t1, a0, &::done)
+ %car(t1, a0)
+ %sari(t1, t1, 3) ; untag fixnum -> raw byte
+ %sb(t1, t0, 0)
+ %addi(t0, t0, 1)
+ %cdr(a0, a0)
+ %b(&::loop)
::done
- %ld(a0, sp, 8)
+ %ld(a0, sp, %PARSE_U8_BODY_LOCALS.result)
})
# is_ident_byte(c=a0) -> a1 (1 if c is a valid identifier byte, else 0).
@@ -963,13 +641,12 @@
# +0 start cursor (byte offset)
# +8 end cursor (byte offset)
# +16 cursor (scratch slot for the symbol-validation loop)
-%fn(parse_atom, 24, {
- %la(t0, &readbuf_pos)
- %ld(t1, t0, 0)
- %st(t1, sp, 0)
+%struct PARSE_ATOM_LOCALS { start end cursor } # .SIZE = 24
+%fn(parse_atom, %PARSE_ATOM_LOCALS.SIZE, {
+ %lda_global(t1, t0, &readbuf_pos)
+ %st(t1, sp, %PARSE_ATOM_LOCALS.start)
- %la(t2, &readbuf_len)
- %ld(t2, t2, 0)
+ %ld_global(t2, &readbuf_len)
::scan
%beq(t1, t2, &::end)
@@ -986,14 +663,12 @@
%b(&::scan)
::end
- %st(t1, sp, 8)
- %la(t0, &readbuf_pos)
+ %st(t1, sp, %PARSE_ATOM_LOCALS.end)
%st(t1, t0, 0)
# Dispatch on the first byte.
- %ld(t0, sp, 0)
- %la(a0, &readbuf_buf_ptr)
- %ld(a0, a0, 0)
+ %ld(t0, sp, %PARSE_ATOM_LOCALS.start)
+ %ld_global(a0, &readbuf_buf_ptr)
%add(a0, a0, t0)
%lb(t1, a0, 0)
@@ -1009,7 +684,7 @@
%beqz(a1, &::sign)
%b(&::is_sym)
::sign
- %ld(t2, sp, 8)
+ %ld(t2, sp, %PARSE_ATOM_LOCALS.end)
%addi(t0, t0, 1)
%beq(t0, t2, &::is_sym)
%readbuf_byte(a0, t0)
@@ -1019,38 +694,36 @@
::is_sym
# Validate every byte; abort on the first non-ident byte.
- %ld(t0, sp, 0)
- %st(t0, sp, 16)
+ %ld(t0, sp, %PARSE_ATOM_LOCALS.start)
+ %st(t0, sp, %PARSE_ATOM_LOCALS.cursor)
::sym_loop
- %ld(t0, sp, 16)
- %ld(t1, sp, 8)
+ %ld(t0, sp, %PARSE_ATOM_LOCALS.cursor)
+ %ld(t1, sp, %PARSE_ATOM_LOCALS.end)
%beq(t0, t1, &::sym_intern)
%readbuf_byte(a0, t0)
%call(&is_ident_byte)
%beqz(a1, &::sym_bad)
- %ld(t0, sp, 16)
+ %ld(t0, sp, %PARSE_ATOM_LOCALS.cursor)
%addi(t0, t0, 1)
- %st(t0, sp, 16)
+ %st(t0, sp, %PARSE_ATOM_LOCALS.cursor)
%b(&::sym_loop)
::sym_bad
%die(msg_bad_ident)
::sym_intern
- %ld(a0, sp, 0)
- %la(t0, &readbuf_buf_ptr)
- %ld(t0, t0, 0)
+ %ld(a0, sp, %PARSE_ATOM_LOCALS.start)
+ %ld_global(t0, &readbuf_buf_ptr)
%add(a0, t0, a0)
- %ld(t1, sp, 8)
- %ld(t2, sp, 0)
+ %ld(t1, sp, %PARSE_ATOM_LOCALS.end)
+ %ld(t2, sp, %PARSE_ATOM_LOCALS.start)
%sub(a1, t1, t2)
%tail(&intern)
::is_int
- %ld(t0, sp, 0) ; start_off
- %ld(t1, sp, 8) ; end_off
- %la(a0, &readbuf_buf_ptr)
- %ld(a0, a0, 0)
+ %ld(t0, sp, %PARSE_ATOM_LOCALS.start) ; start_off
+ %ld(t1, sp, %PARSE_ATOM_LOCALS.end) ; end_off
+ %ld_global(a0, &readbuf_buf_ptr)
%add(a0, a0, t0) ; ptr = base + start_off
%sub(a1, t1, t0) ; len = end_off - start_off
%call(&parse_dec) ; -> (a0=value, a1=ok)
@@ -1072,65 +745,64 @@
# +8 end cursor (closing '"' position)
# +16 bv wrapper (saved across the data fill loop)
# +24 spill slot (write ptr saved across parse_hex in \x escape)
-%fn(parse_string, 32, {
- %la(t0, &readbuf_pos)
- %ld(t1, t0, 0)
- %st(t1, sp, 0)
+%struct PARSE_STRING_LOCALS { start end bv spill } # .SIZE = 32
+%fn(parse_string, %PARSE_STRING_LOCALS.SIZE, {
+ %ld_global(t1, &readbuf_pos)
+ %st(t1, sp, %PARSE_STRING_LOCALS.start)
- %la(t2, &readbuf_len)
- %ld(t2, t2, 0)
+ %ld_global(t2, &readbuf_len)
%li(a0, 0)
::scan
- %beq(t1, t2, &::eof)
- %readbuf_byte(a3, t1)
- %addi(a1, a3, -34) ; '"'
- %beqz(a1, &::scan_done)
- %addi(a1, a3, -92) ; '\\'
- %beqz(a1, &::scan_esc)
- %addi(t1, t1, 1)
- %addi(a0, a0, 1)
- %b(&::scan)
-
- ::scan_esc
- # Backslash plus the next byte yield one decoded byte. \xHEX; runs
- # until the terminating ';' (validated in pass 2); every other escape
- # is exactly two source bytes.
- %addi(t1, t1, 1)
- %beq(t1, t2, &::eof)
- %readbuf_byte(a3, t1)
- %addi(a1, a3, -120) ; 'x'
- %beqz(a1, &::scan_hex)
- %addi(t1, t1, 1)
- %addi(a0, a0, 1)
- %b(&::scan)
-
- ::scan_hex
- # Skip past 'x' and scan to the terminating ';'. EOF before ';'
- # falls into the unterminated-string path below, matching how an
- # unterminated body is reported.
- %addi(t1, t1, 1)
- ::scan_hex_loop
- %beq(t1, t2, &::eof)
- %readbuf_byte(a3, t1)
- %addi(a1, a3, -59) ; ';'
- %beqz(a1, &::scan_hex_done)
- %addi(t1, t1, 1)
- %b(&::scan_hex_loop)
- ::scan_hex_done
- %addi(t1, t1, 1) ; consume ';'
- %addi(a0, a0, 1) ; +1 output byte
- %b(&::scan)
-
+ %beq(t1, t2, &::eof)
+ %readbuf_byte(a3, t1)
+ %addi(a1, a3, -34) ; '"'
+ %beqz(a1, &::scan_done)
+ %addi(a1, a3, -92) ; '\\'
+ %beqz(a1, &::scan_esc)
+ %addi(t1, t1, 1)
+ %addi(a0, a0, 1)
+ %b(&::scan)
+
+ ::scan_esc
+ # Backslash plus the next byte yield one decoded byte. \xHEX; runs
+ # until the terminating ';' (validated in pass 2); every other escape
+ # is exactly two source bytes.
+ %addi(t1, t1, 1)
+ %beq(t1, t2, &::eof)
+ %readbuf_byte(a3, t1)
+ %addi(a1, a3, -120) ; 'x'
+ %beqz(a1, &::scan_hex)
+ %addi(t1, t1, 1)
+ %addi(a0, a0, 1)
+ %b(&::scan)
+
+ ::scan_hex
+ # Skip past 'x' and scan to the terminating ';'. EOF before ';'
+ # falls into the unterminated-string path below, matching how an
+ # unterminated body is reported.
+ %addi(t1, t1, 1)
+ ::scan_hex_loop
+ %beq(t1, t2, &::eof)
+ %readbuf_byte(a3, t1)
+ %addi(a1, a3, -59) ; ';'
+ %beqz(a1, &::scan_hex_done)
+ %addi(t1, t1, 1)
+ %b(&::scan_hex_loop)
+ ::scan_hex_done
+ %addi(t1, t1, 1) ; consume ';'
+ %addi(a0, a0, 1) ; +1 output byte
+ %b(&::scan)
::scan_done
- %st(t1, sp, 8)
+
+ %st(t1, sp, %PARSE_STRING_LOCALS.end)
%call(&bv_alloc)
- %st(a0, sp, 16)
+ %st(a0, sp, %PARSE_STRING_LOCALS.bv)
# Pass 2: decode into the freshly allocated data buffer.
- %ld(t1, sp, 0) ; start
- %ld(t2, sp, 8) ; end
- %ld(a3, a0, 5) ; data_ptr
+ %ld(t1, sp, %PARSE_STRING_LOCALS.start) ; start
+ %ld(t2, sp, %PARSE_STRING_LOCALS.end) ; end
+ %heap_ld(a3, a0, %BV.data)
::fill
%beq(t1, t2, &::fill_done)
@@ -1179,25 +851,24 @@
# t0/t1/t2 and a2/a3, so spill the cursor (t1) and write ptr (a3)
# across the call. sp+0 is free once pass 1 finishes.
%addi(t1, t1, 1) ; t1 -> first hex digit
- %st(t1, sp, 0)
- %st(a3, sp, 24)
- %la(t0, &readbuf_buf_ptr)
- %ld(t0, t0, 0)
+ %st(t1, sp, %PARSE_STRING_LOCALS.start)
+ %st(a3, sp, %PARSE_STRING_LOCALS.spill)
+ %ld_global(t0, &readbuf_buf_ptr)
%add(a0, t0, t1) ; ptr to first hex digit
%sub(a1, t2, t1) ; max len (bytes left in body)
%call(&parse_hex) ; -> (a0=value, a1=consumed)
%beqz(a1, &::hex_bad)
%li(t0, 255)
%bltu(t0, a0, &::hex_bad)
- %ld(t1, sp, 0)
+ %ld(t1, sp, %PARSE_STRING_LOCALS.start)
%add(t1, t1, a1) ; t1 = position of expected ';'
- %ld(t2, sp, 8)
+ %ld(t2, sp, %PARSE_STRING_LOCALS.end)
%beq(t1, t2, &::hex_bad)
%readbuf_byte(t0, t1)
%addi(t0, t0, -59) ; ';'
%bnez(t0, &::hex_bad)
%addi(t1, t1, 1) ; consume ';'
- %ld(a3, sp, 24)
+ %ld(a3, sp, %PARSE_STRING_LOCALS.spill)
%sb(a0, a3, 0)
%addi(a3, a3, 1)
%b(&::fill)
@@ -1207,9 +878,8 @@
::fill_done
%addi(t1, t1, 1) ; consume closing '"'
- %la(t0, &readbuf_pos)
- %st(t1, t0, 0)
- %ld(a0, sp, 16)
+ %st_global(t1, &readbuf_pos, t0)
+ %ld(a0, sp, %PARSE_STRING_LOCALS.bv)
%eret
::eof
@@ -1225,13 +895,12 @@
# Frame: 16 bytes
# +0 start cursor
# +8 end cursor
-%fn(parse_char, 16, {
- %la(t0, &readbuf_pos)
- %ld(t1, t0, 0)
- %st(t1, sp, 0)
+%struct PARSE_CHAR_LOCALS { start end } # .SIZE = 16
+%fn(parse_char, %PARSE_CHAR_LOCALS.SIZE, {
+ %lda_global(t1, t0, &readbuf_pos)
+ %st(t1, sp, %PARSE_CHAR_LOCALS.start)
- %la(t2, &readbuf_len)
- %ld(t2, t2, 0)
+ %ld_global(t2, &readbuf_len)
%beq(t1, t2, &::short)
@@ -1251,19 +920,17 @@
%b(&::scan)
::scan_done
- %st(t1, sp, 8)
- %la(t0, &readbuf_pos)
+ %st(t1, sp, %PARSE_CHAR_LOCALS.end)
%st(t1, t0, 0)
- %ld(t0, sp, 0)
- %ld(t1, sp, 8)
+ %ld(t0, sp, %PARSE_CHAR_LOCALS.start)
+ %ld(t1, sp, %PARSE_CHAR_LOCALS.end)
%sub(a2, t1, t0) ; length
%li(a3, 1)
%beq(a2, a3, &::single)
- %la(t2, &readbuf_buf_ptr)
- %ld(t2, t2, 0)
+ %ld_global(t2, &readbuf_buf_ptr)
%add(t2, t2, t0) ; t2 = slice ptr
# Hex form: first byte is 'x'.
@@ -1285,8 +952,7 @@
%b(&::bad)
::single
- %la(t2, &readbuf_buf_ptr)
- %ld(t2, t2, 0)
+ %ld_global(t2, &readbuf_buf_ptr)
%add(t2, t2, t0)
%lb(a0, t2, 0)
%mkfix(a0, a0)
@@ -1441,9 +1107,10 @@
# +0 expr
# +8 env
# +16 fn (head value, while args are being evaluated)
-%fn(eval, 32, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EVAL_LOCALS { expr env fn pad } # .SIZE = 32
+%fn(eval, %EVAL_LOCALS.SIZE, {
+ %st(a0, sp, %EVAL_LOCALS.expr)
+ %st(a1, sp, %EVAL_LOCALS.env)
%tagof(t0, a0)
%li(t1, %TAG.PAIR)
@@ -1483,7 +1150,7 @@
# Special-form dispatch: pointer-compare head against the cached
# special-form symbol values. SYM is a distinct tag, so a head that
# isn't a symbol cannot collide with any sym_* slot.
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_LOCALS.expr)
%car(t0, t0) ; t0 = head
%dispatch_form(&sym_quote, &::do_quote)
%dispatch_form(&sym_if, &::do_if)
@@ -1501,26 +1168,26 @@
%dispatch_form(&sym_pmatch, &::do_pmatch)
# head = eval(car(expr), env)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_LOCALS.expr)
%car(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_LOCALS.env)
%call(&eval)
- %st(a0, sp, 16)
+ %st(a0, sp, %EVAL_LOCALS.fn)
# args = eval_args(cdr(expr), env)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_LOCALS.expr)
%cdr(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_LOCALS.env)
%call(&eval_args)
# apply(fn, args) -- tail call
%mov(a1, a0)
- %ld(a0, sp, 16)
+ %ld(a0, sp, %EVAL_LOCALS.fn)
%tail(&apply)
::do_quote
# (quote datum) -> car(cdr(expr))
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_LOCALS.expr)
%cdr(a0, a0)
%car(a0, a0)
%eret
@@ -1564,43 +1231,44 @@
# +8 env
# +16 head (NIL until first val is appended)
# +24 tail (most recent cell; set-cdr! target)
-%fn(eval_args, 32, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EVAL_ARGS_LOCALS { args env head tail } # .SIZE = 32
+%fn(eval_args, %EVAL_ARGS_LOCALS.SIZE, {
+ %st(a0, sp, %EVAL_ARGS_LOCALS.args)
+ %st(a1, sp, %EVAL_ARGS_LOCALS.env)
%li(t0, %imm_val(%IMM.NIL))
- %st(t0, sp, 16)
- %st(t0, sp, 24)
+ %st(t0, sp, %EVAL_ARGS_LOCALS.head)
+ %st(t0, sp, %EVAL_ARGS_LOCALS.tail)
::loop
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_ARGS_LOCALS.args)
%if_nil(t1, t0, &::done)
# val = eval(car(args), env)
%car(a0, t0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_ARGS_LOCALS.env)
%call(&eval)
# cell = cons(val, NIL); append to head/tail.
%li(a1, %imm_val(%IMM.NIL))
%call(&cons)
- %ld(t0, sp, 16)
+ %ld(t0, sp, %EVAL_ARGS_LOCALS.head)
%if_nil(t1, t0, &::first)
- %ld(t0, sp, 24)
- %st(a0, t0, 7)
- %st(a0, sp, 24)
+ %ld(t0, sp, %EVAL_ARGS_LOCALS.tail)
+ %set_cdr(a0, t0)
+ %st(a0, sp, %EVAL_ARGS_LOCALS.tail)
%b(&::advance)
::first
- %st(a0, sp, 16)
- %st(a0, sp, 24)
+ %st(a0, sp, %EVAL_ARGS_LOCALS.head)
+ %st(a0, sp, %EVAL_ARGS_LOCALS.tail)
::advance
%advance_walk(0)
%b(&::loop)
::done
- %ld(a0, sp, 16)
+ %ld(a0, sp, %EVAL_ARGS_LOCALS.head)
})
# apply(fn=a0, args=a1) -> result (a0)
@@ -1608,8 +1276,9 @@
# Frame: 16 bytes
# +0 args
# +8 body (saved across bind_params for the closure path)
-%fn(apply, 16, {
- %st(a1, sp, 0)
+%struct APPLY_LOCALS { args body } # .SIZE = 16
+%fn(apply, %APPLY_LOCALS.SIZE, {
+ %st(a1, sp, %APPLY_LOCALS.args)
# Only HEAP-tagged values can be applicable.
%tagof(t0, a0)
@@ -1637,26 +1306,26 @@
# primitive. prim_apply_entry maintains the same contract when it
# tail-calls back into apply.
%mov(a1, a0)
- %ld(t0, a0, 5)
- %ld(a0, sp, 0)
+ %heap_ld(t0, a0, %PRIM.entry_w)
+ %ld(a0, sp, %APPLY_LOCALS.args)
%tailr(t0)
::closure
# Closure layout (HEAP-tagged): [hdr][params][body][env]
# field offsets from tagged ptr: params=5, body=13, env=21.
- %ld(t1, a0, 13) ; body (must survive bind_params)
- %st(t1, sp, 8)
- %ld(t2, a0, 21) ; captured env
- %ld(t0, a0, 5) ; params
+ %heap_ld(t1, a0, %CLOSURE.body) ; must survive bind_params
+ %st(t1, sp, %APPLY_LOCALS.body)
+ %heap_ld(t2, a0, %CLOSURE.env)
+ %heap_ld(t0, a0, %CLOSURE.params)
%mov(a0, t0) ; bind_params(params, args, env)
- %ld(a1, sp, 0)
+ %ld(a1, sp, %APPLY_LOCALS.args)
%mov(a2, t2)
%call(&bind_params)
# eval_body(body, new_env) -- tail call
%mov(a1, a0)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %APPLY_LOCALS.body)
%tail(&eval_body)
})
@@ -1698,9 +1367,10 @@
# Frame: 16 bytes
# +0 rest
# +8 env
-%fn(eval_if, 16, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EVAL_IF_LOCALS { rest env } # .SIZE = 16
+%fn(eval_if, %EVAL_IF_LOCALS.SIZE, {
+ %st(a0, sp, %EVAL_IF_LOCALS.rest)
+ %st(a1, sp, %EVAL_IF_LOCALS.env)
# val = eval(car(rest), env)
%car(a0, a0)
@@ -1710,19 +1380,19 @@
%beq(a0, t0, &::else_branch)
# then-branch: tail-eval(cadr(rest), env)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_IF_LOCALS.rest)
%cdr(a0, a0)
%car(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_IF_LOCALS.env)
%tail(&eval)
::else_branch
# else-branch: tail-eval(caddr(rest), env)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_IF_LOCALS.rest)
%cdr(a0, a0)
%cdr(a0, a0)
%car(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_IF_LOCALS.env)
%tail(&eval)
})
@@ -1734,31 +1404,32 @@
# +0 rest
# +8 env
# +16 closure ptr (HEAP-tagged)
-%fn(eval_lambda, 24, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EVAL_LAMBDA_LOCALS { rest env closure } # .SIZE = 24
+%fn(eval_lambda, %EVAL_LAMBDA_LOCALS.SIZE, {
+ %st(a0, sp, %EVAL_LAMBDA_LOCALS.rest)
+ %st(a1, sp, %EVAL_LAMBDA_LOCALS.env)
%li(a0, 32)
%li(a1, %HDR.CLOSURE)
%call(&alloc_hdr)
- %st(a0, sp, 16)
+ %st(a0, sp, %EVAL_LAMBDA_LOCALS.closure)
# closure[params] = car(rest)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_LAMBDA_LOCALS.rest)
%car(t1, t0)
- %ld(t0, sp, 16)
- %st(t1, t0, 5)
+ %ld(t0, sp, %EVAL_LAMBDA_LOCALS.closure)
+ %heap_st(t1, t0, %CLOSURE.params)
# closure[body] = cdr(rest)
- %ld(t1, sp, 0)
+ %ld(t1, sp, %EVAL_LAMBDA_LOCALS.rest)
%cdr(t1, t1)
- %st(t1, t0, 13)
+ %heap_st(t1, t0, %CLOSURE.body)
# closure[env] = captured env
- %ld(t1, sp, 8)
- %st(t1, t0, 21)
+ %ld(t1, sp, %EVAL_LAMBDA_LOCALS.env)
+ %heap_st(t1, t0, %CLOSURE.env)
- %ld(a0, sp, 16)
+ %ld(a0, sp, %EVAL_LAMBDA_LOCALS.closure)
})
# eval_define(rest=a0, env=a1) -> UNSPEC (a0).
@@ -1773,9 +1444,10 @@
# Frame: 16 bytes
# +0 rest
# +8 env
-%fn(eval_define, 16, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EVAL_DEFINE_LOCALS { rest env } # .SIZE = 16
+%fn(eval_define, %EVAL_DEFINE_LOCALS.SIZE, {
+ %st(a0, sp, %EVAL_DEFINE_LOCALS.rest)
+ %st(a1, sp, %EVAL_DEFINE_LOCALS.env)
# If car(rest) is a pair, this is the lambda-sugar form.
%car(t0, a0)
@@ -1784,13 +1456,13 @@
%beq(t1, t2, &::sugar)
# Plain define: value = eval(car(cdr(rest)), env)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_DEFINE_LOCALS.rest)
%cdr(a0, t0)
%car(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_DEFINE_LOCALS.env)
%call(&eval)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_DEFINE_LOCALS.rest)
%car(t0, t0)
%bind_global_from_t0()
%li(a0, %imm_val(%IMM.UNSPEC))
@@ -1798,16 +1470,16 @@
::sugar
# rest = ((name . params) . body); build (params . body) for eval_lambda.
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_DEFINE_LOCALS.rest)
%car(t0, t0)
%cdr(a0, t0) ; params
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_DEFINE_LOCALS.rest)
%cdr(a1, t0) ; body
%call(&cons)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_DEFINE_LOCALS.env)
%call(&eval_lambda)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_DEFINE_LOCALS.rest)
%car(t0, t0)
%car(t0, t0) ; name
%bind_global_from_t0()
@@ -1826,43 +1498,44 @@
# +0 rest (sym . (value-expr . ()))
# +8 env
# +16 saved value (eval'd value-expr)
-%fn(eval_setbang, 24, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EVAL_SETBANG_LOCALS { rest env saved } # .SIZE = 24
+%fn(eval_setbang, %EVAL_SETBANG_LOCALS.SIZE, {
+ %st(a0, sp, %EVAL_SETBANG_LOCALS.rest)
+ %st(a1, sp, %EVAL_SETBANG_LOCALS.env)
# value = eval(cadr(rest), env)
%cdr(a0, a0)
%car(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_SETBANG_LOCALS.env)
%call(&eval)
- %st(a0, sp, 16)
+ %st(a0, sp, %EVAL_SETBANG_LOCALS.saved)
# Walk env looking for a binding cell whose car == target sym.
# Only t0..t2 are available: t0 scratch, t1 target sym, t2 env cursor.
- %ld(t1, sp, 0)
+ %ld(t1, sp, %EVAL_SETBANG_LOCALS.rest)
%car(t1, t1) ; target sym
::lp
- %ld(t2, sp, 8)
+ %ld(t2, sp, %EVAL_SETBANG_LOCALS.env)
%if_nil(t0, t2, &::ms)
%car(t0, t2)
%car(t0, t0) ; cell sym
%beq(t0, t1, &::ht)
%cdr(t2, t2)
- %st(t2, sp, 8)
+ %st(t2, sp, %EVAL_SETBANG_LOCALS.env)
%b(&::lp)
::ht
%car(t0, t2) ; re-fetch binding cell
- %ld(a0, sp, 16)
- %st(a0, t0, 7) ; mutate cell's cdr
+ %ld(a0, sp, %EVAL_SETBANG_LOCALS.saved)
+ %set_cdr(a0, t0) ; mutate cell's cdr
%li(a0, %imm_val(%IMM.UNSPEC))
%eret
::ms
# Miss: rebind global.
- %ld(a0, sp, 16)
- %ld(t0, sp, 0)
+ %ld(a0, sp, %EVAL_SETBANG_LOCALS.saved)
+ %ld(t0, sp, %EVAL_SETBANG_LOCALS.rest)
%car(t0, t0)
%bind_global_from_t0()
%li(a0, %imm_val(%IMM.UNSPEC))
@@ -1879,61 +1552,60 @@
# +8 env
# +16 test value (live across the => eval/cons calls)
# +24 proc (live across the => cons call)
-%fn(eval_cond, 32, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EVAL_COND_LOCALS { clauses env test proc } # .SIZE = 32
+%fn(eval_cond, %EVAL_COND_LOCALS.SIZE, {
+ %st(a0, sp, %EVAL_COND_LOCALS.clauses)
+ %st(a1, sp, %EVAL_COND_LOCALS.env)
::loop
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_COND_LOCALS.clauses)
%if_nil(t1, t0, &::nm)
%car(t1, t0) ; clause
%car(t2, t1) ; test_expr
- %la(a0, &sym_else)
- %ld(a0, a0, 0)
+ %ld_global(a0, &sym_else)
%beq(t2, a0, &::dm)
%mov(a0, t2)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_COND_LOCALS.env)
%call(&eval)
%li(t0, %imm_val(%IMM.FALSE))
%beq(a0, t0, &::nx)
# Truthy. Spill test value and inspect cdr(clause): empty -> UNSPEC,
# car == => -> arrow path, else regular body.
- %st(a0, sp, 16)
- %ld(t0, sp, 0)
+ %st(a0, sp, %EVAL_COND_LOCALS.test)
+ %ld(t0, sp, %EVAL_COND_LOCALS.clauses)
%car(t0, t0)
%cdr(t0, t0)
%if_nil(t1, t0, &::nm)
%car(t1, t0)
- %la(t2, &sym_arrow)
- %ld(t2, t2, 0)
+ %ld_global(t2, &sym_arrow)
%beq(t1, t2, &::ar)
%mov(a0, t0) ; regular body
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_COND_LOCALS.env)
%tail(&eval_body)
::ar
%cdr(t0, t0)
%car(a0, t0) ; proc-expr
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_COND_LOCALS.env)
%call(&eval)
- %st(a0, sp, 24)
- %ld(a0, sp, 16)
+ %st(a0, sp, %EVAL_COND_LOCALS.proc)
+ %ld(a0, sp, %EVAL_COND_LOCALS.test)
%li(a1, %imm_val(%IMM.NIL))
%call(&cons)
%mov(a1, a0)
- %ld(a0, sp, 24)
+ %ld(a0, sp, %EVAL_COND_LOCALS.proc)
%tail(&apply)
::dm
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_COND_LOCALS.clauses)
%car(t0, t0)
%cdr(a0, t0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_COND_LOCALS.env)
%tail(&eval_body)
::nx
@@ -1956,9 +1628,10 @@
# +8 env (original)
# +16 walk (bindings, advances)
# +24 new_env (built up)
-%fn(eval_let, 32, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EVAL_LET_LOCALS { rest env walk new_env } # .SIZE = 32
+%fn(eval_let, %EVAL_LET_LOCALS.SIZE, {
+ %st(a0, sp, %EVAL_LET_LOCALS.rest)
+ %st(a1, sp, %EVAL_LET_LOCALS.env)
# Named let?
%car(t0, a0)
@@ -1966,14 +1639,14 @@
%li(t2, %TAG.SYM)
%beq(t1, t2, &::named)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_LET_LOCALS.rest)
%car(t0, t0) ; bindings
- %st(t0, sp, 16)
- %ld(t0, sp, 8)
- %st(t0, sp, 24) ; new_env = env
+ %st(t0, sp, %EVAL_LET_LOCALS.walk)
+ %ld(t0, sp, %EVAL_LET_LOCALS.env)
+ %st(t0, sp, %EVAL_LET_LOCALS.new_env) ; new_env = env
::loop
- %ld(t0, sp, 16)
+ %ld(t0, sp, %EVAL_LET_LOCALS.walk)
%if_nil(t1, t0, &::done)
%car(t1, t0) ; pair = (name init)
@@ -1982,11 +1655,11 @@
# val = eval(init, env_orig)
%mov(a0, t2)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_LET_LOCALS.env)
%call(&eval)
# binding = cons(name, val)
- %ld(t0, sp, 16)
+ %ld(t0, sp, %EVAL_LET_LOCALS.walk)
%car(t1, t0)
%car(t2, t1)
%mov(a1, a0)
@@ -1994,22 +1667,22 @@
%call(&cons)
# new_env = cons(binding, new_env)
- %ld(a1, sp, 24)
+ %ld(a1, sp, %EVAL_LET_LOCALS.new_env)
%call(&cons)
- %st(a0, sp, 24)
+ %st(a0, sp, %EVAL_LET_LOCALS.new_env)
%advance_walk(16)
%b(&::loop)
::done
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_LET_LOCALS.rest)
%cdr(a0, a0) ; body
- %ld(a1, sp, 24)
+ %ld(a1, sp, %EVAL_LET_LOCALS.new_env)
%tail(&eval_body)
::named
- %ld(a0, sp, 0)
- %ld(a1, sp, 8)
+ %ld(a0, sp, %EVAL_LET_LOCALS.rest)
+ %ld(a1, sp, %EVAL_LET_LOCALS.env)
%tail(&eval_let_named)
})
@@ -2018,18 +1691,19 @@
# bindings of the same let* form (left-to-right shadowing).
#
# Frame: 32 bytes (same layout as eval_let)
-%fn(eval_letstar, 32, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EVAL_LETSTAR_LOCALS { rest env walk new_env } # .SIZE = 32
+%fn(eval_letstar, %EVAL_LETSTAR_LOCALS.SIZE, {
+ %st(a0, sp, %EVAL_LETSTAR_LOCALS.rest)
+ %st(a1, sp, %EVAL_LETSTAR_LOCALS.env)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_LETSTAR_LOCALS.rest)
%car(t0, t0)
- %st(t0, sp, 16)
- %ld(t0, sp, 8)
- %st(t0, sp, 24)
+ %st(t0, sp, %EVAL_LETSTAR_LOCALS.walk)
+ %ld(t0, sp, %EVAL_LETSTAR_LOCALS.env)
+ %st(t0, sp, %EVAL_LETSTAR_LOCALS.new_env)
::loop
- %ld(t0, sp, 16)
+ %ld(t0, sp, %EVAL_LETSTAR_LOCALS.walk)
%if_nil(t1, t0, &::done)
%car(t1, t0)
@@ -2038,27 +1712,27 @@
# val = eval(init, new_env)
%mov(a0, t2)
- %ld(a1, sp, 24)
+ %ld(a1, sp, %EVAL_LETSTAR_LOCALS.new_env)
%call(&eval)
- %ld(t0, sp, 16)
+ %ld(t0, sp, %EVAL_LETSTAR_LOCALS.walk)
%car(t1, t0)
%car(t2, t1)
%mov(a1, a0)
%mov(a0, t2)
%call(&cons)
- %ld(a1, sp, 24)
+ %ld(a1, sp, %EVAL_LETSTAR_LOCALS.new_env)
%call(&cons)
- %st(a0, sp, 24)
+ %st(a0, sp, %EVAL_LETSTAR_LOCALS.new_env)
%advance_walk(16)
%b(&::loop)
::done
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_LETSTAR_LOCALS.rest)
%cdr(a0, a0)
- %ld(a1, sp, 24)
+ %ld(a1, sp, %EVAL_LETSTAR_LOCALS.new_env)
%tail(&eval_body)
})
@@ -2073,18 +1747,19 @@
# +8 env_orig
# +16 walk
# +24 new_env
-%fn(eval_letrec, 32, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EVAL_LETREC_LOCALS { rest env_orig walk new_env } # .SIZE = 32
+%fn(eval_letrec, %EVAL_LETREC_LOCALS.SIZE, {
+ %st(a0, sp, %EVAL_LETREC_LOCALS.rest)
+ %st(a1, sp, %EVAL_LETREC_LOCALS.env_orig)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_LETREC_LOCALS.rest)
%car(t0, t0)
- %st(t0, sp, 16)
- %ld(t0, sp, 8)
- %st(t0, sp, 24)
+ %st(t0, sp, %EVAL_LETREC_LOCALS.walk)
+ %ld(t0, sp, %EVAL_LETREC_LOCALS.env_orig)
+ %st(t0, sp, %EVAL_LETREC_LOCALS.new_env)
::phase1
- %ld(t0, sp, 16)
+ %ld(t0, sp, %EVAL_LETREC_LOCALS.walk)
%if_nil(t1, t0, &::p1_done)
%car(t1, t0)
@@ -2092,34 +1767,34 @@
%mov(a0, t2)
%li(a1, %imm_val(%IMM.UNSPEC))
%call(&cons)
- %ld(a1, sp, 24)
+ %ld(a1, sp, %EVAL_LETREC_LOCALS.new_env)
%call(&cons)
- %st(a0, sp, 24)
+ %st(a0, sp, %EVAL_LETREC_LOCALS.new_env)
%advance_walk(16)
%b(&::phase1)
::p1_done
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_LETREC_LOCALS.rest)
%car(t0, t0)
- %st(t0, sp, 16) ; reset walk
+ %st(t0, sp, %EVAL_LETREC_LOCALS.walk) ; reset walk
::phase2
- %ld(t0, sp, 16)
+ %ld(t0, sp, %EVAL_LETREC_LOCALS.walk)
%if_nil(t1, t0, &::p2_done)
%car(t1, t0)
%cdr(t2, t1)
%car(t2, t2) ; init
%mov(a0, t2)
- %ld(a1, sp, 24)
+ %ld(a1, sp, %EVAL_LETREC_LOCALS.new_env)
%call(&eval) ; val in a0
- %ld(t0, sp, 16)
+ %ld(t0, sp, %EVAL_LETREC_LOCALS.walk)
%car(t1, t0)
%car(t2, t1) ; name (in t2)
- %ld(t1, sp, 24)
+ %ld(t1, sp, %EVAL_LETREC_LOCALS.new_env)
::scan
%car(a1, t1)
%car(a2, a1)
@@ -2129,15 +1804,15 @@
::found
%car(a1, t1)
- %st(a0, a1, 7) ; set-cdr! binding val
+ %set_cdr(a0, a1) ; set-cdr! binding val
%advance_walk(16)
%b(&::phase2)
::p2_done
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_LETREC_LOCALS.rest)
%cdr(a0, a0)
- %ld(a1, sp, 24)
+ %ld(a1, sp, %EVAL_LETREC_LOCALS.new_env)
%tail(&eval_body)
})
@@ -2149,13 +1824,14 @@
# Frame: 16 bytes
# +0 rest
# +8 env
-%fn(eval_and, 16, {
+%struct EVAL_AND_LOCALS { rest env } # .SIZE = 16
+%fn(eval_and, %EVAL_AND_LOCALS.SIZE, {
%li(t0, %imm_val(%IMM.TRUE))
%if_nil(t1, a0, &::done_imm)
::loop
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+ %st(a0, sp, %EVAL_AND_LOCALS.rest)
+ %st(a1, sp, %EVAL_AND_LOCALS.env)
# If cdr(rest) is NIL, the head is the last form -> tail-eval.
%cdr(t0, a0)
@@ -2166,15 +1842,15 @@
%call(&eval)
%li(t0, %imm_val(%IMM.FALSE))
%beq(a0, t0, &::done)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_AND_LOCALS.rest)
%cdr(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_AND_LOCALS.env)
%b(&::loop)
::last
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_AND_LOCALS.rest)
%car(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_AND_LOCALS.env)
%tail(&eval)
::done
@@ -2192,13 +1868,14 @@
# Frame: 16 bytes
# +0 rest
# +8 env
-%fn(eval_or, 16, {
+%struct EVAL_OR_LOCALS { rest env } # .SIZE = 16
+%fn(eval_or, %EVAL_OR_LOCALS.SIZE, {
%li(t0, %imm_val(%IMM.FALSE))
%if_nil(t1, a0, &::done_imm)
::loop
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+ %st(a0, sp, %EVAL_OR_LOCALS.rest)
+ %st(a1, sp, %EVAL_OR_LOCALS.env)
%cdr(t0, a0)
%if_nil(t1, t0, &::last)
@@ -2207,15 +1884,15 @@
%call(&eval)
%li(t0, %imm_val(%IMM.FALSE))
%bne(a0, t0, &::done)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_OR_LOCALS.rest)
%cdr(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_OR_LOCALS.env)
%b(&::loop)
::last
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_OR_LOCALS.rest)
%car(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_OR_LOCALS.env)
%tail(&eval)
::done
@@ -2244,40 +1921,40 @@
# +24 env_ext (env extended with the matched clause's bindings)
# +32 guard cursor (advances during the guard AND-fold)
# +40 body (saved across guard evals, tail-evaluated on success)
-%fn(eval_pmatch, 48, {
- %st(a1, sp, 8)
+%struct EVAL_PMATCH_LOCALS { subject env_outer clauses env_ext guard body } # .SIZE = 48
+%fn(eval_pmatch, %EVAL_PMATCH_LOCALS.SIZE, {
+ %st(a1, sp, %EVAL_PMATCH_LOCALS.env_outer)
# subject = eval(car(rest), env_outer); clauses = cdr(rest).
%mov(t0, a0)
%cdr(t1, t0)
- %st(t1, sp, 16)
+ %st(t1, sp, %EVAL_PMATCH_LOCALS.clauses)
%car(a0, t0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_PMATCH_LOCALS.env_outer)
%call(&eval)
- %st(a0, sp, 0)
+ %st(a0, sp, %EVAL_PMATCH_LOCALS.subject)
::loop
- %ld(t0, sp, 16)
+ %ld(t0, sp, %EVAL_PMATCH_LOCALS.clauses)
%if_nil(t1, t0, &::no_match)
%car(t1, t0) ; clause
%car(t2, t1) ; pat
- %la(a3, &sym_else)
- %ld(a3, a3, 0)
+ %ld_global(a3, &sym_else)
%beq(t2, a3, &::do_else)
# pmatch_match(pat, subject, env_outer) -> (a0=env_ext, a1=ok)
%mov(a0, t2)
- %ld(a1, sp, 0)
- %ld(a2, sp, 8)
+ %ld(a1, sp, %EVAL_PMATCH_LOCALS.subject)
+ %ld(a2, sp, %EVAL_PMATCH_LOCALS.env_outer)
%call(&pmatch_match)
%beqz(a1, &::next)
- %st(a0, sp, 24) ; env_ext
+ %st(a0, sp, %EVAL_PMATCH_LOCALS.env_ext) ; env_ext
# tail = cdr(clause)
- %ld(t0, sp, 16)
+ %ld(t0, sp, %EVAL_PMATCH_LOCALS.clauses)
%car(t0, t0)
%cdr(t0, t0) ; tail = (body...) or ((guard ...) body...)
@@ -2291,34 +1968,33 @@
%li(a0, %TAG.PAIR)
%bne(t2, a0, &::body_simple)
%car(a0, t1) ; head of first form
- %la(a1, &sym_guard)
- %ld(a1, a1, 0)
+ %ld_global(a1, &sym_guard)
%bne(a0, a1, &::body_simple)
# Guard clause. guards = cdr(car(tail)); body = cdr(tail).
%cdr(a0, t1)
- %st(a0, sp, 32)
+ %st(a0, sp, %EVAL_PMATCH_LOCALS.guard)
%cdr(t0, t0)
- %st(t0, sp, 40)
+ %st(t0, sp, %EVAL_PMATCH_LOCALS.body)
::g_loop
- %ld(t0, sp, 32)
+ %ld(t0, sp, %EVAL_PMATCH_LOCALS.guard)
%if_nil(t1, t0, &::body_run)
%car(a0, t0) ; guard expr
- %ld(a1, sp, 24) ; env_ext
+ %ld(a1, sp, %EVAL_PMATCH_LOCALS.env_ext) ; env_ext
%call(&eval)
%li(t0, %imm_val(%IMM.FALSE))
%beq(a0, t0, &::next)
- %ld(t0, sp, 32)
+ %ld(t0, sp, %EVAL_PMATCH_LOCALS.guard)
%cdr(t0, t0)
- %st(t0, sp, 32)
+ %st(t0, sp, %EVAL_PMATCH_LOCALS.guard)
%b(&::g_loop)
::body_run
- %ld(a0, sp, 40)
- %ld(a1, sp, 24)
+ %ld(a0, sp, %EVAL_PMATCH_LOCALS.body)
+ %ld(a1, sp, %EVAL_PMATCH_LOCALS.env_ext)
%tail(&eval_body)
::body_simple
@@ -2326,20 +2002,20 @@
# with the extended env; tail position of the matched clause's body
# is preserved.
%mov(a0, t0)
- %ld(a1, sp, 24)
+ %ld(a1, sp, %EVAL_PMATCH_LOCALS.env_ext)
%tail(&eval_body)
::do_else
- %ld(t0, sp, 16)
+ %ld(t0, sp, %EVAL_PMATCH_LOCALS.clauses)
%car(t0, t0)
%cdr(a0, t0) ; body
- %ld(a1, sp, 8) ; env_outer (no bindings introduced)
+ %ld(a1, sp, %EVAL_PMATCH_LOCALS.env_outer) ; env_outer (no bindings introduced)
%tail(&eval_body)
::next
- %ld(t0, sp, 16)
+ %ld(t0, sp, %EVAL_PMATCH_LOCALS.clauses)
%cdr(t0, t0)
- %st(t0, sp, 16)
+ %st(t0, sp, %EVAL_PMATCH_LOCALS.clauses)
%b(&::loop)
::no_match
@@ -2367,10 +2043,11 @@
# +0 pat
# +8 subj
# +16 env
-%fn(pmatch_match, 24, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
- %st(a2, sp, 16)
+%struct PMATCH_MATCH_LOCALS { pat subj env } # .SIZE = 24
+%fn(pmatch_match, %PMATCH_MATCH_LOCALS.SIZE, {
+ %st(a0, sp, %PMATCH_MATCH_LOCALS.pat)
+ %st(a1, sp, %PMATCH_MATCH_LOCALS.subj)
+ %st(a2, sp, %PMATCH_MATCH_LOCALS.env)
%tagof(t0, a0)
%li(t1, %TAG.PAIR)
@@ -2399,8 +2076,7 @@
::pair_pat
%car(t0, a0) ; phead
- %la(t1, &sym_unquote)
- %ld(t1, t1, 0)
+ %ld_global(t1, &sym_unquote)
%beq(t0, t1, &::binder)
# Structural pair. subj must be a pair too.
@@ -2409,25 +2085,25 @@
%bne(t0, t1, &::no)
# Recurse on the cars; on success, recurse on the cdrs as a tail call.
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PMATCH_MATCH_LOCALS.pat)
%car(a0, t0)
- %ld(t0, sp, 8)
+ %ld(t0, sp, %PMATCH_MATCH_LOCALS.subj)
%car(a1, t0)
- %ld(a2, sp, 16)
+ %ld(a2, sp, %PMATCH_MATCH_LOCALS.env)
%call(&pmatch_match)
%beqz(a1, &::no)
%mov(a2, a0) ; env_after_car
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PMATCH_MATCH_LOCALS.pat)
%cdr(a0, t0)
- %ld(t0, sp, 8)
+ %ld(t0, sp, %PMATCH_MATCH_LOCALS.subj)
%cdr(a1, t0)
%tail(&pmatch_match)
::binder
# Validate (unquote <sym>): cdr(pat) is a pair, cdr(cdr(pat)) is NIL,
# car(cdr(pat)) is a symbol.
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PMATCH_MATCH_LOCALS.pat)
%cdr(t1, t0) ; cdr(pat)
%tagof(t0, t1)
%li(t2, %TAG.PAIR)
@@ -2441,22 +2117,21 @@
%bne(t2, a3, &::bad)
# Wildcard? Compare against sym_underscore; if so, no binding.
- %la(t1, &sym_underscore)
- %ld(t1, t1, 0)
+ %ld_global(t1, &sym_underscore)
%beq(t0, t1, &::ok)
# Bind: env' = cons(cons(pident, subj), env). pident lives in t0;
# cons clobbers t0..t2, so move it into a0 right away.
%mov(a0, t0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %PMATCH_MATCH_LOCALS.subj)
%call(&cons)
- %ld(a1, sp, 16)
+ %ld(a1, sp, %PMATCH_MATCH_LOCALS.env)
%call(&cons)
%li(a1, 1)
%eret
::ok
- %ld(a0, sp, 16)
+ %ld(a0, sp, %PMATCH_MATCH_LOCALS.env)
%li(a1, 1)
%eret
@@ -2484,31 +2159,32 @@
# +40 head (current pass's list head — params, then args)
# +48 tail (current pass's list tail)
# +56 params (saved between passes)
-%fn(eval_let_named, 64, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EVAL_LET_NAMED_LOCALS { rest env_orig self_binding self_env walk head tail params } # .SIZE = 64
+%fn(eval_let_named, %EVAL_LET_NAMED_LOCALS.SIZE, {
+ %st(a0, sp, %EVAL_LET_NAMED_LOCALS.rest)
+ %st(a1, sp, %EVAL_LET_NAMED_LOCALS.env_orig)
# 1. self_binding = (name . UNSPEC); self_env = cons(self_binding, env)
%car(t0, a0)
%mov(a0, t0)
%li(a1, %imm_val(%IMM.UNSPEC))
%call(&cons)
- %st(a0, sp, 16)
- %ld(a1, sp, 8)
+ %st(a0, sp, %EVAL_LET_NAMED_LOCALS.self_binding)
+ %ld(a1, sp, %EVAL_LET_NAMED_LOCALS.env_orig)
%call(&cons)
- %st(a0, sp, 24)
+ %st(a0, sp, %EVAL_LET_NAMED_LOCALS.self_env)
# 2. Pass 1: build params list (cdr-tail trick) by walking bindings.
%li(t0, %imm_val(%IMM.NIL))
- %st(t0, sp, 40)
- %st(t0, sp, 48)
- %ld(t0, sp, 0)
+ %st(t0, sp, %EVAL_LET_NAMED_LOCALS.head)
+ %st(t0, sp, %EVAL_LET_NAMED_LOCALS.tail)
+ %ld(t0, sp, %EVAL_LET_NAMED_LOCALS.rest)
%cdr(t0, t0)
%car(t0, t0) ; bindings
- %st(t0, sp, 32)
+ %st(t0, sp, %EVAL_LET_NAMED_LOCALS.walk)
::p1_loop
- %ld(t0, sp, 32)
+ %ld(t0, sp, %EVAL_LET_NAMED_LOCALS.walk)
%if_nil(t1, t0, &::p1_done)
%car(t1, t0)
@@ -2517,58 +2193,58 @@
%li(a1, %imm_val(%IMM.NIL))
%call(&cons) ; cell = (name . NIL)
- %ld(t0, sp, 40)
+ %ld(t0, sp, %EVAL_LET_NAMED_LOCALS.head)
%if_nil(t1, t0, &::p1_first)
- %ld(t0, sp, 48)
- %st(a0, t0, 7)
- %st(a0, sp, 48)
+ %ld(t0, sp, %EVAL_LET_NAMED_LOCALS.tail)
+ %set_cdr(a0, t0)
+ %st(a0, sp, %EVAL_LET_NAMED_LOCALS.tail)
%b(&::p1_advance)
::p1_first
- %st(a0, sp, 40)
- %st(a0, sp, 48)
+ %st(a0, sp, %EVAL_LET_NAMED_LOCALS.head)
+ %st(a0, sp, %EVAL_LET_NAMED_LOCALS.tail)
::p1_advance
%advance_walk(32)
%b(&::p1_loop)
::p1_done
- %ld(t0, sp, 40)
- %st(t0, sp, 56) ; save params
+ %ld(t0, sp, %EVAL_LET_NAMED_LOCALS.head)
+ %st(t0, sp, %EVAL_LET_NAMED_LOCALS.params) ; save params
# 3. Pass 2: build args list (eval inits in env_orig).
%li(t0, %imm_val(%IMM.NIL))
- %st(t0, sp, 40)
- %st(t0, sp, 48)
- %ld(t0, sp, 0)
+ %st(t0, sp, %EVAL_LET_NAMED_LOCALS.head)
+ %st(t0, sp, %EVAL_LET_NAMED_LOCALS.tail)
+ %ld(t0, sp, %EVAL_LET_NAMED_LOCALS.rest)
%cdr(t0, t0)
%car(t0, t0)
- %st(t0, sp, 32)
+ %st(t0, sp, %EVAL_LET_NAMED_LOCALS.walk)
::p2_loop
- %ld(t0, sp, 32)
+ %ld(t0, sp, %EVAL_LET_NAMED_LOCALS.walk)
%if_nil(t1, t0, &::p2_done)
%car(t1, t0)
%cdr(t2, t1)
%car(t2, t2) ; init
%mov(a0, t2)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_LET_NAMED_LOCALS.env_orig)
%call(&eval) ; val
%li(a1, %imm_val(%IMM.NIL))
%call(&cons) ; cell = (val . NIL)
- %ld(t0, sp, 40)
+ %ld(t0, sp, %EVAL_LET_NAMED_LOCALS.head)
%if_nil(t1, t0, &::p2_first)
- %ld(t0, sp, 48)
- %st(a0, t0, 7)
- %st(a0, sp, 48)
+ %ld(t0, sp, %EVAL_LET_NAMED_LOCALS.tail)
+ %set_cdr(a0, t0)
+ %st(a0, sp, %EVAL_LET_NAMED_LOCALS.tail)
%b(&::p2_advance)
::p2_first
- %st(a0, sp, 40)
- %st(a0, sp, 48)
+ %st(a0, sp, %EVAL_LET_NAMED_LOCALS.head)
+ %st(a0, sp, %EVAL_LET_NAMED_LOCALS.tail)
::p2_advance
%advance_walk(32)
@@ -2576,20 +2252,20 @@
::p2_done
# 4. Closure: eval_lambda((params . body), self_env).
- %ld(a0, sp, 56) ; params
- %ld(t0, sp, 0)
+ %ld(a0, sp, %EVAL_LET_NAMED_LOCALS.params) ; params
+ %ld(t0, sp, %EVAL_LET_NAMED_LOCALS.rest)
%cdr(t0, t0)
%cdr(a1, t0) ; body
%call(&cons)
- %ld(a1, sp, 24)
+ %ld(a1, sp, %EVAL_LET_NAMED_LOCALS.self_env)
%call(&eval_lambda)
# 5. Patch self_binding cdr to closure.
- %ld(t0, sp, 16)
- %st(a0, t0, 7)
+ %ld(t0, sp, %EVAL_LET_NAMED_LOCALS.self_binding)
+ %set_cdr(a0, t0)
# 6. apply(closure, args).
- %ld(a1, sp, 40)
+ %ld(a1, sp, %EVAL_LET_NAMED_LOCALS.head)
%tail(&apply)
})
@@ -2602,13 +2278,14 @@
# +0 params (advanced each iteration)
# +8 args (advanced each iteration)
# +16 env (extended each iteration)
-%fn(bind_params, 24, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
- %st(a2, sp, 16)
+%struct BIND_PARAMS_LOCALS { params args env } # .SIZE = 24
+%fn(bind_params, %BIND_PARAMS_LOCALS.SIZE, {
+ %st(a0, sp, %BIND_PARAMS_LOCALS.params)
+ %st(a1, sp, %BIND_PARAMS_LOCALS.args)
+ %st(a2, sp, %BIND_PARAMS_LOCALS.env)
::loop
- %ld(t0, sp, 0)
+ %ld(t0, sp, %BIND_PARAMS_LOCALS.params)
%tagof(t1, t0)
%li(t2, %TAG.PAIR)
%beq(t1, t2, &::pair)
@@ -2618,16 +2295,16 @@
::pair
# binding = cons(car(params), car(args))
- %ld(t0, sp, 0)
+ %ld(t0, sp, %BIND_PARAMS_LOCALS.params)
%car(a0, t0)
- %ld(t0, sp, 8)
+ %ld(t0, sp, %BIND_PARAMS_LOCALS.args)
%car(a1, t0)
%call(&cons)
# env = cons(binding, env)
- %ld(a1, sp, 16)
+ %ld(a1, sp, %BIND_PARAMS_LOCALS.env)
%call(&cons)
- %st(a0, sp, 16)
+ %st(a0, sp, %BIND_PARAMS_LOCALS.env)
# advance params and args
%advance_walk(0)
@@ -2636,15 +2313,15 @@
::rest_bind
# binding = cons(params_sym, args_list); env = cons(binding, env)
- %ld(a0, sp, 0)
- %ld(a1, sp, 8)
+ %ld(a0, sp, %BIND_PARAMS_LOCALS.params)
+ %ld(a1, sp, %BIND_PARAMS_LOCALS.args)
%call(&cons)
- %ld(a1, sp, 16)
+ %ld(a1, sp, %BIND_PARAMS_LOCALS.env)
%call(&cons)
- %st(a0, sp, 16)
+ %st(a0, sp, %BIND_PARAMS_LOCALS.env)
::done
- %ld(a0, sp, 16)
+ %ld(a0, sp, %BIND_PARAMS_LOCALS.env)
})
# eval_body(body=a0, env=a1) -> value of last form (a0).
@@ -2659,10 +2336,11 @@
# Frame: 16 bytes
# +0 body
# +8 env
-%fn(eval_body, 16, {
+%struct EVAL_BODY_LOCALS { body env } # .SIZE = 16
+%fn(eval_body, %EVAL_BODY_LOCALS.SIZE, {
::loop
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+ %st(a0, sp, %EVAL_BODY_LOCALS.body)
+ %st(a1, sp, %EVAL_BODY_LOCALS.env)
# Reject internal `define`. Detect (define ...) at the head of any
# form before dispatching it to eval.
@@ -2671,29 +2349,28 @@
%li(t2, %TAG.PAIR)
%bne(t1, t2, &::not_define)
%car(t1, t0) ; head sym
- %la(t2, &sym_define)
- %ld(t2, t2, 0)
+ %ld_global(t2, &sym_define)
%beq(t1, t2, &::internal_define)
::not_define
# If cdr(body) is NIL, body's car is the last form.
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_BODY_LOCALS.body)
%cdr(t0, a0)
%if_nil(t1, t0, &::last)
# Non-last form: eval and discard, advance.
%car(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_BODY_LOCALS.env)
%call(&eval)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_BODY_LOCALS.body)
%cdr(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_BODY_LOCALS.env)
%b(&::loop)
::last
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_BODY_LOCALS.body)
%car(a0, a0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %EVAL_BODY_LOCALS.env)
%tail(&eval)
::internal_define
@@ -2701,6 +2378,203 @@
})
# =========================================================================
+# Runtime error -- single abort entry point
+# =========================================================================
+#
+# runtime_error(msg_cstr=a0) -> never returns. Every overflow / bounds /
+# unbound / type-failure path lands here so error reporting (and the
+# eventual user-facing `error` primitive) only have to be implemented
+# once. Today we tail into libp1pp's `panic`, which writes msg + LF to
+# stderr and sys_exits 1.
+:runtime_error
+ %tail(&panic)
+
+# =========================================================================
+# Source loading -- argv[1] -> readbuf, length stored in readbuf_len
+# =========================================================================
+
+%fn(load_source, 0, {
+ %ld_global(a1, &readbuf_buf_ptr)
+ %li(a2, %READBUF_CAP_BYTES)
+ %call(&read_file)
+ %bltz(a0, &::fail)
+
+ # If the read filled (or would have filled) the buffer, the source
+ # is at least cap bytes; refuse rather than silently truncate.
+ # read_file does a single sys_read so n == cap is the only saturation
+ # signal we have. We treat n >= cap as overflow defensively.
+ %li(t0, %READBUF_CAP_BYTES)
+ %bltu(a0, t0, &::ok)
+ %die(msg_readbuf_full)
+
+ ::ok
+ %st_global(a0, &readbuf_len, t0)
+ %li(a0, 0)
+ %st_global(a0, &readbuf_pos, t0)
+ %eret
+
+ ::fail
+ %die(msg_load_fail)
+})
+
+# =========================================================================
+# Heap: cons (leaf) and alloc_hdr (leaf)
+# =========================================================================
+#
+# Both are call-free leaves: bump heap_next, write fields, return tagged
+# pointer. Each allocation tests (new_next <= heap_end) and aborts via
+# runtime_error if the bump would overflow the heap arena. heap_next is
+# kept 8-byte aligned so every PAIR/HEAP tag bit is exact: cons always
+# bumps by a multiple of 8 (16); alloc_hdr / alloc_bytes round their
+# argument up via %alignup(_,_,8,_).
+
+# cons(car=a0, cdr=a1) -> tagged pair (a0). Allocates 16 bytes.
+:cons
+%scope cons
+ %lda_global(t0, t2, &heap_next)
+ %addi(t1, t0, %PAIR.SIZE)
+ %ld_global(a3, &heap_end)
+ %bltu(a3, t1, &::oom)
+ %st(a0, t0, %PAIR.car)
+ %st(a1, t0, %PAIR.cdr)
+ %st(t1, t2, 0)
+ %addi(a0, t0, %TAG.PAIR)
+ %ret
+ ::oom
+ %die(msg_heap_full)
+%endscope
+
+# alloc_hdr(bytes=a0, hdr_word=a1) -> tagged heap obj (a0)
+# Rounds bytes up to a multiple of 8 and writes hdr_word at offset 0.
+:alloc_hdr
+%scope alloc_hdr
+ %alignup(a0, a0, 8, t0)
+ %lda_global(t0, t2, &heap_next)
+ %add(t1, t0, a0)
+ %ld_global(a3, &heap_end)
+ %bltu(a3, t1, &::oom)
+ %st(t1, t2, 0)
+ %st(a1, t0, 0)
+ %addi(a0, t0, 3)
+ %ret
+ ::oom
+ %die(msg_heap_full)
+%endscope
+
+# list_length(list=a0) -> count (a0). Linear walk; clobbers a0 (used as
+# the cursor). Callers that need the list afterward must save it first.
+:list_length
+%scope list_length
+ %li(t0, 0)
+ ::loop
+ %if_nil(t1, a0, &::done)
+ %addi(t0, t0, 1)
+ %cdr(a0, a0)
+ %b(&::loop)
+ ::done
+ %mov(a0, t0)
+ %ret
+%endscope
+
+# =========================================================================
+# Symbol intern -- linear scan, append on miss
+# =========================================================================
+#
+# Frame: 32 bytes
+# +0 name_ptr (input)
+# +8 name_len (input)
+# +16 idx (loop counter / found index)
+# +24 entry_ptr (spilled across memcmp)
+%struct INTERN_LOCALS { name_ptr name_len idx entry_ptr } # .SIZE = 32
+%fn(intern, %INTERN_LOCALS.SIZE, {
+ %st(a0, sp, %INTERN_LOCALS.name_ptr)
+ %st(a1, sp, %INTERN_LOCALS.name_len)
+
+ %li(t0, 0)
+ %st(t0, sp, %INTERN_LOCALS.idx)
+
+ ::scan
+ # idx >= count? -> append
+ %ld(t0, sp, %INTERN_LOCALS.idx)
+ %ld_global(t1, &symtab_count)
+ %bltu(t0, t1, &::probe)
+ %b(&::append)
+
+ ::probe
+ %symtab_entry(t1, t0, t2)
+ %st(t1, sp, %INTERN_LOCALS.entry_ptr)
+
+ # entry.name_len == name_len ?
+ %ld(t2, t1, %SYMENT.name_len)
+ %ld(a2, sp, %INTERN_LOCALS.name_len)
+ %bne(t2, a2, &::next)
+
+ # memcmp(entry.name_ptr, name_ptr, len)
+ %ld(a0, t1, %SYMENT.name_ptr)
+ %ld(a1, sp, %INTERN_LOCALS.name_ptr)
+ %ld(a2, sp, %INTERN_LOCALS.name_len)
+ %call(&memcmp)
+ %beqz(a0, &::found)
+
+ ::next
+ %ld(t0, sp, %INTERN_LOCALS.idx)
+ %addi(t0, t0, 1)
+ %st(t0, sp, %INTERN_LOCALS.idx)
+ %b(&::scan)
+
+ ::append
+ # Bounds check; on overflow exit 5 with a message.
+ %ld(t0, sp, %INTERN_LOCALS.idx)
+ %li(t1, %SYMTAB_CAP_SLOTS)
+ %bltu(t0, t1, &::append_ok)
+ %die(msg_symtab_full)
+
+ ::append_ok
+ # Copy the name into a stable heap buffer. The caller-provided ptr
+ # may live in readbuf_buf (parse_atom), which gets overwritten when
+ # the next source is loaded; symtab entries must outlive that.
+ %ld(a0, sp, %INTERN_LOCALS.name_len)
+ %call(&alloc_bytes)
+ %ld(a1, sp, %INTERN_LOCALS.name_ptr)
+ %ld(a2, sp, %INTERN_LOCALS.name_len)
+ %call(&memcpy) ; returns dst in a0 = stable copy
+
+ %ld(t0, sp, %INTERN_LOCALS.idx)
+ %symtab_entry(t1, t0, t2)
+ %st(a0, t1, %SYMENT.name_ptr) ; stable copy
+ %ld(a0, sp, %INTERN_LOCALS.name_len)
+ %st(a0, t1, %SYMENT.name_len)
+ %li(a0, %imm_val(%IMM.UNBOUND))
+ %st(a0, t1, %SYMENT.global_val)
+ %li(a0, 0)
+ %st(a0, t1, %SYMENT.pad)
+
+ # symtab_count = idx + 1
+ %addi(a0, t0, 1)
+ %st_global(a0, &symtab_count, t2)
+
+ # fall through with idx in t0 = sp[16]
+
+ ::found
+ %ld(t0, sp, %INTERN_LOCALS.idx)
+ %shli(a0, t0, 3)
+ %ori(a0, a0, %TAG.SYM)
+})
+
+# Lookup by sym_idx (untagged, in a0). Returns symtab[idx].global_val in a0.
+# Leaf.
+:sym_global
+ %ld_global(t0, &symtab_buf_ptr)
+ %ld_array(a0, t0, %SYMENT.SIZE, a0, %SYMENT.global_val, t1)
+ %ret
+
+# sym_set_global(idx=a0, val=a1). Leaf.
+:sym_set_global
+ %ld_global(t0, &symtab_buf_ptr)
+ %st_array(a1, t0, %SYMENT.SIZE, a0, %SYMENT.global_val, t1)
+ %ret
+
+# =========================================================================
# Primitives
# =========================================================================
#
@@ -2722,15 +2596,16 @@
# +8 walk (current table cursor)
# +16 end (table_end)
-%fn(register_primitives, 24, {
+%struct REGISTER_PRIMITIVES_LOCALS { prim walk end } # .SIZE = 24
+%fn(register_primitives, %REGISTER_PRIMITIVES_LOCALS.SIZE, {
%la(t0, &prim_table)
- %st(t0, sp, 8)
+ %st(t0, sp, %REGISTER_PRIMITIVES_LOCALS.walk)
%la(t0, &prim_table_end)
- %st(t0, sp, 16)
+ %st(t0, sp, %REGISTER_PRIMITIVES_LOCALS.end)
::loop
- %ld(t0, sp, 8)
- %ld(t1, sp, 16)
+ %ld(t0, sp, %REGISTER_PRIMITIVES_LOCALS.walk)
+ %ld(t1, sp, %REGISTER_PRIMITIVES_LOCALS.end)
%beq(t0, t1, &::done)
# alloc_hdr(24, HDR.PRIM) -> HEAP-tagged a0. The third slot (offset 13
@@ -2740,26 +2615,26 @@
%li(a0, 24)
%li(a1, %HDR.PRIM)
%call(&alloc_hdr)
- %st(a0, sp, 0)
+ %st(a0, sp, %REGISTER_PRIMITIVES_LOCALS.prim)
- # Write entry-label into prim's entry slot (raw+8 == tagged+5).
- %ld(t0, sp, 8)
+ # Write entry-label into prim's entry slot.
+ %ld(t0, sp, %REGISTER_PRIMITIVES_LOCALS.walk)
%ld(t1, t0, 16)
- %ld(t2, sp, 0)
- %st(t1, t2, 5)
+ %ld(t2, sp, %REGISTER_PRIMITIVES_LOCALS.prim)
+ %heap_st(t1, t2, %PRIM.entry_w)
# Intern surface name; bind global to prim ptr.
- %ld(t0, sp, 8)
+ %ld(t0, sp, %REGISTER_PRIMITIVES_LOCALS.walk)
%ld(a0, t0, 0)
%ld(a1, t0, 8)
%call(&intern)
%untag_sym(a0, a0)
- %ld(a1, sp, 0)
+ %ld(a1, sp, %REGISTER_PRIMITIVES_LOCALS.prim)
%call(&sym_set_global)
- %ld(t0, sp, 8)
+ %ld(t0, sp, %REGISTER_PRIMITIVES_LOCALS.walk)
%addi(t0, t0, 24)
- %st(t0, sp, 8)
+ %st(t0, sp, %REGISTER_PRIMITIVES_LOCALS.walk)
%b(&::loop)
::done
@@ -2847,13 +2722,13 @@
# No type check (matches car/cdr's lax stance); both return UNSPEC.
:prim_set_car_entry
%args2(t0, t1, a0)
- %st(t1, t0, -1)
+ %set_car(t1, t0)
%li(a0, %imm_val(%IMM.UNSPEC))
%ret
:prim_set_cdr_entry
%args2(t0, t1, a0)
- %st(t1, t0, 7)
+ %set_cdr(t1, t0)
%li(a0, %imm_val(%IMM.UNSPEC))
%ret
@@ -2898,53 +2773,54 @@
# +8 total length (raw)
# +16 result bv
# +24 write offset (raw, into result.data)
-%fn(prim_bv_append_entry, 32, {
- %st(a0, sp, 0)
+%struct PRIM_BV_APPEND_ENTRY_LOCALS { args total result write } # .SIZE = 32
+%fn(prim_bv_append_entry, %PRIM_BV_APPEND_ENTRY_LOCALS.SIZE, {
+ %st(a0, sp, %PRIM_BV_APPEND_ENTRY_LOCALS.args)
%li(t0, 0)
%mov(t1, a0)
::sum_loop
%if_nil(t2, t1, &::sum_done)
%car(t2, t1)
- %ld(a0, t2, -3)
+ %heap_ld(a0, t2, %BV.hdr)
%shri(a0, a0, 8)
%add(t0, t0, a0)
%cdr(t1, t1)
%b(&::sum_loop)
::sum_done
- %st(t0, sp, 8)
+ %st(t0, sp, %PRIM_BV_APPEND_ENTRY_LOCALS.total)
%mov(a0, t0)
%call(&bv_alloc)
- %st(a0, sp, 16)
+ %st(a0, sp, %PRIM_BV_APPEND_ENTRY_LOCALS.result)
%li(t0, 0)
- %st(t0, sp, 24)
+ %st(t0, sp, %PRIM_BV_APPEND_ENTRY_LOCALS.write)
::copy_loop
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PRIM_BV_APPEND_ENTRY_LOCALS.args)
%if_nil(t1, t0, &::copy_done)
%car(t1, t0) ; src bv
- %ld(t2, t1, -3)
+ %heap_ld(t2, t1, %BV.hdr)
%shri(t2, t2, 8) ; src length
- %ld(a0, sp, 16)
- %ld(a0, a0, 5) ; result.data
- %ld(a3, sp, 24)
+ %ld(a0, sp, %PRIM_BV_APPEND_ENTRY_LOCALS.result)
+ %heap_ld(a0, a0, %BV.data) ; result.data
+ %ld(a3, sp, %PRIM_BV_APPEND_ENTRY_LOCALS.write)
%add(a0, a0, a3) ; dst = result.data + offset
- %ld(a1, t1, 5) ; src.data
+ %heap_ld(a1, t1, %BV.data) ; src.data
%mov(a2, t2) ; count
%add(a3, a3, t2)
- %st(a3, sp, 24)
+ %st(a3, sp, %PRIM_BV_APPEND_ENTRY_LOCALS.write)
%cdr(t0, t0)
- %st(t0, sp, 0)
+ %st(t0, sp, %PRIM_BV_APPEND_ENTRY_LOCALS.args)
%call(&memcpy)
%b(&::copy_loop)
::copy_done
- %ld(a0, sp, 16)
+ %ld(a0, sp, %PRIM_BV_APPEND_ENTRY_LOCALS.result)
})
# (string->symbol bv) -- intern the bytes and return the SYM-tagged
@@ -2952,8 +2828,8 @@
# append, so the bv's data buffer is safe to relocate afterwards.
:prim_string_to_symbol_entry
%car(t0, a0)
- %ld(a0, t0, 5) ; data ptr
- %ld(a1, t0, -3)
+ %heap_ld(a0, t0, %BV.data)
+ %heap_ld(a1, t0, %BV.hdr)
%shri(a1, a1, 8) ; length
%b(&intern)
@@ -2961,21 +2837,22 @@
# returns (ptr, len); bv_alloc gives us a clean wrapper; memcpy fills
# the data. Frame holds the (ptr, len) pair across bv_alloc and the
# resulting bv across memcpy.
-%fn(prim_symbol_to_string_entry, 24, {
+%struct PRIM_SYMBOL_TO_STRING_ENTRY_LOCALS { ptr len bv } # .SIZE = 24
+%fn(prim_symbol_to_string_entry, %PRIM_SYMBOL_TO_STRING_ENTRY_LOCALS.SIZE, {
%car(a0, a0)
%sari(a0, a0, 3) ; raw sym idx
%call(&sym_name) ; -> ptr (a0), len (a1)
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+ %st(a0, sp, %PRIM_SYMBOL_TO_STRING_ENTRY_LOCALS.ptr)
+ %st(a1, sp, %PRIM_SYMBOL_TO_STRING_ENTRY_LOCALS.len)
%mov(a0, a1)
%call(&bv_alloc) ; tagged bv in a0
- %st(a0, sp, 16)
- %ld(a1, sp, 0) ; src ptr
- %ld(a2, sp, 8) ; len
- %ld(t0, a0, 5) ; dst = bv.data
+ %st(a0, sp, %PRIM_SYMBOL_TO_STRING_ENTRY_LOCALS.bv)
+ %ld(a1, sp, %PRIM_SYMBOL_TO_STRING_ENTRY_LOCALS.ptr) ; src ptr
+ %ld(a2, sp, %PRIM_SYMBOL_TO_STRING_ENTRY_LOCALS.len) ; len
+ %heap_ld(t0, a0, %BV.data) ; dst = bv.data
%mov(a0, t0)
%call(&memcpy)
- %ld(a0, sp, 16)
+ %ld(a0, sp, %PRIM_SYMBOL_TO_STRING_ENTRY_LOCALS.bv)
})
# (number->string n [radix]) -- decimal repr in a fresh bv. The radix
@@ -2984,13 +2861,14 @@
# is silently ignored. bv_putint takes the raw value, so untag first;
# bv_alloc(0) gives an empty wrapper that bv_putint grows in place.
# +0 holds the raw value across bv_alloc.
-%fn(prim_number_to_string_entry, 16, {
+%struct PRIM_NUMBER_TO_STRING_ENTRY_LOCALS { value pad } # .SIZE = 16
+%fn(prim_number_to_string_entry, %PRIM_NUMBER_TO_STRING_ENTRY_LOCALS.SIZE, {
%car(t0, a0)
%sari(t0, t0, 3) ; raw value
- %st(t0, sp, 0)
+ %st(t0, sp, %PRIM_NUMBER_TO_STRING_ENTRY_LOCALS.value)
%li(a0, 0)
%call(&bv_alloc)
- %ld(a1, sp, 0)
+ %ld(a1, sp, %PRIM_NUMBER_TO_STRING_ENTRY_LOCALS.value)
%tail(&bv_putint)
})
@@ -3007,8 +2885,8 @@
%li(t1, %HDR.BV)
%bne(t0, t1, &::fail)
- %ld(t0, a0, 5) ; data ptr
- %ld(t1, a0, -3)
+ %heap_ld(t0, a0, %BV.data)
+ %heap_ld(t1, a0, %BV.hdr)
%shri(t1, t1, 8) ; length
%mov(a0, t0)
%mov(a1, t1)
@@ -3262,11 +3140,9 @@
:alloc_bytes
%scope alloc_bytes
%alignup(a0, a0, 8, t0)
- %la(t2, &heap_next)
- %ld(t1, t2, 0)
+ %lda_global(t1, t2, &heap_next)
%add(t0, t1, a0)
- %la(a3, &heap_end)
- %ld(a3, a3, 0)
+ %ld_global(a3, &heap_end)
%bltu(a3, t0, &::oom)
%st(t0, t2, 0)
%mov(a0, t1)
@@ -3299,23 +3175,24 @@
# +0 raw_len
# +8 capacity
# +16 data_ptr (raw)
-%fn(bv_alloc, 24, {
- %st(a0, sp, 0)
+%struct BV_ALLOC_LOCALS { raw_len capacity data_ptr } # .SIZE = 24
+%fn(bv_alloc, %BV_ALLOC_LOCALS.SIZE, {
+ %st(a0, sp, %BV_ALLOC_LOCALS.raw_len)
%call(&bv_capacity_for)
- %st(a0, sp, 8)
+ %st(a0, sp, %BV_ALLOC_LOCALS.capacity)
%call(&alloc_bytes)
- %st(a0, sp, 16)
+ %st(a0, sp, %BV_ALLOC_LOCALS.data_ptr)
- %ld(a1, sp, 0)
+ %ld(a1, sp, %BV_ALLOC_LOCALS.raw_len)
%shli(a1, a1, 8) ; hdr = (raw_len << 8) | HDR.BV (BV == 0)
%li(a0, 24)
%call(&alloc_hdr)
- %ld(t0, sp, 16)
- %st(t0, a0, 5)
- %ld(t1, sp, 8)
- %st(t1, a0, 13)
+ %ld(t0, sp, %BV_ALLOC_LOCALS.data_ptr)
+ %heap_st(t0, a0, %BV.data)
+ %ld(t1, sp, %BV_ALLOC_LOCALS.capacity)
+ %st(t1, a0, 13) ; bv.cap (raw offset 16; not in BV struct)
})
# bv_grow(bv=a0, min_cap=a1) -> bv (a0). Doubles capacity until ≥ min_cap;
@@ -3328,49 +3205,51 @@
# +8 min_cap (input) / new_cap (during loop)
# +16 new_data_ptr
# +24 raw length
-%fn(bv_grow, 32, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct BV_GROW_LOCALS { bv min_cap new_data_ptr raw } # .SIZE = 32
+%fn(bv_grow, %BV_GROW_LOCALS.SIZE, {
+ %st(a0, sp, %BV_GROW_LOCALS.bv)
+ %st(a1, sp, %BV_GROW_LOCALS.min_cap)
- %ld(t0, a0, 13)
+ %ld(t0, a0, 13) ; bv.cap (raw offset 16; not in BV struct)
%bltu(t0, a1, &::need)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %BV_GROW_LOCALS.bv)
%eret
::need
::loop
%shli(t0, t0, 1)
- %ld(t1, sp, 8)
+ %ld(t1, sp, %BV_GROW_LOCALS.min_cap)
%bltu(t0, t1, &::loop)
- %st(t0, sp, 8)
+ %st(t0, sp, %BV_GROW_LOCALS.min_cap)
%mov(a0, t0)
%call(&alloc_bytes)
- %st(a0, sp, 16)
+ %st(a0, sp, %BV_GROW_LOCALS.new_data_ptr)
- %ld(t0, sp, 0)
- %ld(t1, t0, -3)
+ %ld(t0, sp, %BV_GROW_LOCALS.bv)
+ %heap_ld(t1, t0, %BV.hdr)
%shri(t1, t1, 8) ; raw length
- %st(t1, sp, 24)
- %ld(a0, sp, 16)
- %ld(a1, t0, 5) ; old data ptr
- %ld(a2, sp, 24)
+ %st(t1, sp, %BV_GROW_LOCALS.raw)
+ %ld(a0, sp, %BV_GROW_LOCALS.new_data_ptr)
+ %heap_ld(a1, t0, %BV.data) ; old data ptr
+ %ld(a2, sp, %BV_GROW_LOCALS.raw)
%call(&memcpy)
- %ld(t0, sp, 0)
- %ld(t1, sp, 16)
- %st(t1, t0, 5)
- %ld(t1, sp, 8)
- %st(t1, t0, 13)
- %ld(a0, sp, 0)
+ %ld(t0, sp, %BV_GROW_LOCALS.bv)
+ %ld(t1, sp, %BV_GROW_LOCALS.new_data_ptr)
+ %heap_st(t1, t0, %BV.data)
+ %ld(t1, sp, %BV_GROW_LOCALS.min_cap)
+ %st(t1, t0, 13) ; bv.cap (raw offset 16; not in BV struct)
+ %ld(a0, sp, %BV_GROW_LOCALS.bv)
})
# (make-bytevector len) or (make-bytevector len fill)
-%fn(prim_make_bytevector_entry, 24, {
+%struct PRIM_MAKE_BYTEVECTOR_ENTRY_LOCALS { args fill wrapper } # .SIZE = 24
+%fn(prim_make_bytevector_entry, %PRIM_MAKE_BYTEVECTOR_ENTRY_LOCALS.SIZE, {
# +0 args
# +8 fill (raw byte)
# +16 wrapper (saved across fill loop)
- %st(a0, sp, 0)
+ %st(a0, sp, %PRIM_MAKE_BYTEVECTOR_ENTRY_LOCALS.args)
%li(t2, 0)
%cdr(t0, a0)
@@ -3378,19 +3257,19 @@
%car(t0, t0)
%sari(t2, t0, 3)
::no_fill
- %st(t2, sp, 8)
+ %st(t2, sp, %PRIM_MAKE_BYTEVECTOR_ENTRY_LOCALS.fill)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %PRIM_MAKE_BYTEVECTOR_ENTRY_LOCALS.args)
%car_fix(a0, a0)
%bltz(a0, &::bad_len)
%call(&bv_alloc)
- %st(a0, sp, 16)
+ %st(a0, sp, %PRIM_MAKE_BYTEVECTOR_ENTRY_LOCALS.wrapper)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PRIM_MAKE_BYTEVECTOR_ENTRY_LOCALS.args)
%car_fix(t0, t0) ; raw_len
- %ld(t1, sp, 8) ; fill
- %ld(a1, sp, 16)
- %ld(t2, a1, 5) ; data_ptr
+ %ld(t1, sp, %PRIM_MAKE_BYTEVECTOR_ENTRY_LOCALS.fill) ; fill
+ %ld(a1, sp, %PRIM_MAKE_BYTEVECTOR_ENTRY_LOCALS.wrapper)
+ %heap_ld(t2, a1, %BV.data)
%li(a1, 0)
::fill_loop
@@ -3401,7 +3280,7 @@
%b(&::fill_loop)
::fill_done
- %ld(a0, sp, 16)
+ %ld(a0, sp, %PRIM_MAKE_BYTEVECTOR_ENTRY_LOCALS.wrapper)
%eret
::bad_len
@@ -3410,7 +3289,7 @@
:prim_bv_length_entry
%car(t0, a0)
- %ld(t1, t0, -3)
+ %heap_ld(t1, t0, %BV.hdr)
%shri(a0, t1, 5)
%ret
@@ -3419,13 +3298,13 @@
%args2(t0, t1, a0) ; bv, tagged idx
%sari(t1, t1, 3) ; raw idx
%bltz(t1, &::oob)
- %ld(a0, t0, -3)
+ %heap_ld(a0, t0, %BV.hdr)
%shri(a0, a0, 8) ; length
%bltu(t1, a0, &::ok)
::oob
%die(msg_bv_oob)
::ok
- %ld(t2, t0, 5)
+ %heap_ld(t2, t0, %BV.data)
%add(t2, t2, t1)
%lb(a0, t2, 0)
%mkfix(a0, a0)
@@ -3438,13 +3317,13 @@
%sari(t2, t2, 3) ; raw idx
%sari(t1, t1, 3) ; raw val
%bltz(t2, &::oob)
- %ld(a0, t0, -3)
+ %heap_ld(a0, t0, %BV.hdr)
%shri(a0, a0, 8) ; length
%bltu(t2, a0, &::ok)
::oob
%die(msg_bv_oob)
::ok
- %ld(a0, t0, 5)
+ %heap_ld(a0, t0, %BV.data)
%add(a0, a0, t2)
%sb(t1, a0, 0)
%li(a0, %imm_val(%IMM.UNSPEC))
@@ -3458,11 +3337,12 @@
# +0 args
# +8 src tagged
# +16 wrapper (saved after bv_alloc)
-%fn(prim_bv_copy_entry, 24, {
- %st(a0, sp, 0)
+%struct PRIM_BV_COPY_ENTRY_LOCALS { args src wrapper } # .SIZE = 24
+%fn(prim_bv_copy_entry, %PRIM_BV_COPY_ENTRY_LOCALS.SIZE, {
+ %st(a0, sp, %PRIM_BV_COPY_ENTRY_LOCALS.args)
%args3(t0, t2, t1, a0) ; src, start, end
- %st(t0, sp, 8)
+ %st(t0, sp, %PRIM_BV_COPY_ENTRY_LOCALS.src)
%sari(t2, t2, 3) ; raw start
%sari(t1, t1, 3) ; raw end
@@ -3470,24 +3350,24 @@
# start is now non-negative); src.length >= end.
%bltz(t2, &::oob)
%blt(t1, t2, &::oob)
- %ld(a0, t0, -3)
+ %heap_ld(a0, t0, %BV.hdr)
%shri(a0, a0, 8) ; src.length
%blt(a0, t1, &::oob)
%sub(a0, t1, t2) ; count
%call(&bv_alloc)
- %st(a0, sp, 16)
+ %st(a0, sp, %PRIM_BV_COPY_ENTRY_LOCALS.wrapper)
# Recompute src ptr at start; dst ptr at 0; count from new bv's hdr.
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PRIM_BV_COPY_ENTRY_LOCALS.args)
%cdr(t0, t0)
%car_fix(t0, t0) ; raw start
- %ld(t1, sp, 8)
- %ld(t2, t1, 5)
+ %ld(t1, sp, %PRIM_BV_COPY_ENTRY_LOCALS.src)
+ %heap_ld(t2, t1, %BV.data)
%add(t2, t2, t0) ; src ptr
- %ld(a3, sp, 16)
- %ld(a2, a3, 5) ; dst ptr
- %ld(a1, a3, -3)
+ %ld(a3, sp, %PRIM_BV_COPY_ENTRY_LOCALS.wrapper)
+ %heap_ld(a2, a3, %BV.data) ; dst ptr
+ %heap_ld(a1, a3, %BV.hdr)
%shri(a1, a1, 8) ; count
::copy_loop
@@ -3500,7 +3380,7 @@
%b(&::copy_loop)
::copy_done
- %ld(a0, sp, 16)
+ %ld(a0, sp, %PRIM_BV_COPY_ENTRY_LOCALS.wrapper)
%eret
::oob
@@ -3517,58 +3397,59 @@
# +16 src (tagged)
# +24 src-start (raw)
# +32 src-end (raw)
-%fn(prim_bv_copy_bang_entry, 40, {
+%struct PRIM_BV_COPY_BANG_ENTRY_LOCALS { dst dst_start src src_start src_end } # .SIZE = 40
+%fn(prim_bv_copy_bang_entry, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.SIZE, {
%car(t0, a0)
- %st(t0, sp, 0) ; dst
+ %st(t0, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.dst) ; dst
%cdr(a0, a0)
%car(t0, a0)
%sari(t0, t0, 3)
- %st(t0, sp, 8) ; dst-start
+ %st(t0, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.dst_start) ; dst-start
%cdr(a0, a0)
%car(t0, a0)
- %st(t0, sp, 16) ; src
+ %st(t0, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.src) ; src
%cdr(a0, a0)
%car(t0, a0)
%sari(t0, t0, 3)
- %st(t0, sp, 24) ; src-start
+ %st(t0, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.src_start) ; src-start
%cdr(a0, a0)
%car(t0, a0)
%sari(t0, t0, 3)
- %st(t0, sp, 32) ; src-end
+ %st(t0, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.src_end) ; src-end
# src-start >= 0
- %ld(t0, sp, 24)
+ %ld(t0, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.src_start)
%bltz(t0, &::oob)
# src-end >= src-start (signed catches negative src-end)
- %ld(t1, sp, 32)
+ %ld(t1, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.src_end)
%blt(t1, t0, &::oob)
# src-end <= src.length
- %ld(t2, sp, 16)
- %ld(a0, t2, -3)
+ %ld(t2, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.src)
+ %heap_ld(a0, t2, %BV.hdr)
%shri(a0, a0, 8)
%blt(a0, t1, &::oob)
# dst-start >= 0
- %ld(t2, sp, 8)
+ %ld(t2, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.dst_start)
%bltz(t2, &::oob)
# dst-start + count <= dst.length
%sub(a0, t1, t0) ; count = src-end - src-start
%add(a0, a0, t2) ; dst-start + count
- %ld(t1, sp, 0)
- %ld(t2, t1, -3)
+ %ld(t1, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.dst)
+ %heap_ld(t2, t1, %BV.hdr)
%shri(t2, t2, 8)
%blt(t2, a0, &::oob)
# Set up copy. dst ptr = dst.data + dst-start; src ptr = src.data +
# src-start; count = src-end - src-start.
- %ld(t0, sp, 0)
- %ld(t0, t0, 5)
- %ld(a1, sp, 8)
+ %ld(t0, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.dst)
+ %heap_ld(t0, t0, %BV.data)
+ %ld(a1, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.dst_start)
%add(t0, t0, a1) ; dst ptr
- %ld(a1, sp, 16)
- %ld(a1, a1, 5)
- %ld(a2, sp, 24)
+ %ld(a1, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.src)
+ %heap_ld(a1, a1, %BV.data)
+ %ld(a2, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.src_start)
%add(a1, a1, a2) ; src ptr
- %ld(a3, sp, 32)
+ %ld(a3, sp, %PRIM_BV_COPY_BANG_ENTRY_LOCALS.src_end)
%sub(a3, a3, a2) ; count
::loop
@@ -3595,14 +3476,14 @@
# on every backend, so a single %bne is enough for the byte test.
:bv_equal_check
%scope bv_equal_check
- %ld(t0, a0, -3)
+ %heap_ld(t0, a0, %BV.hdr)
%shri(t0, t0, 8) ; len_a
- %ld(t1, a1, -3)
+ %heap_ld(t1, a1, %BV.hdr)
%shri(t1, t1, 8) ; len_b
%bne(t0, t1, &::false)
- %ld(a2, a0, 5) ; data ptr a
- %ld(a3, a1, 5) ; data ptr b
+ %heap_ld(a2, a0, %BV.data)
+ %heap_ld(a3, a1, %BV.data)
::loop
%beqz(t0, &::true)
@@ -3655,9 +3536,10 @@
# identity-only). Tail-calls the cdr-side recursion and the BV check.
#
# Frame: 16 bytes (a, b spilled across each %call).
-%fn(equal_recurse, 16, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EQUAL_RECURSE_LOCALS { a b } # .SIZE = 16
+%fn(equal_recurse, %EQUAL_RECURSE_LOCALS.SIZE, {
+ %st(a0, sp, %EQUAL_RECURSE_LOCALS.a)
+ %st(a1, sp, %EQUAL_RECURSE_LOCALS.b)
%beq(a0, a1, &::true)
@@ -3672,22 +3554,22 @@
%b(&::false)
::pair
- %ld(t0, sp, 0)
- %ld(t1, sp, 8)
+ %ld(t0, sp, %EQUAL_RECURSE_LOCALS.a)
+ %ld(t1, sp, %EQUAL_RECURSE_LOCALS.b)
%car(a0, t0)
%car(a1, t1)
%call(&equal_recurse)
%li(t0, %imm_val(%IMM.FALSE))
%beq(a0, t0, &::done)
- %ld(t0, sp, 0)
- %ld(t1, sp, 8)
+ %ld(t0, sp, %EQUAL_RECURSE_LOCALS.a)
+ %ld(t1, sp, %EQUAL_RECURSE_LOCALS.b)
%cdr(a0, t0)
%cdr(a1, t1)
%tail(&equal_recurse)
::heap
- %ld(t0, sp, 0)
- %ld(t1, sp, 8)
+ %ld(t0, sp, %EQUAL_RECURSE_LOCALS.a)
+ %ld(t1, sp, %EQUAL_RECURSE_LOCALS.b)
%hdr_type(t2, t0)
%hdr_type(a0, t1)
%bne(t2, a0, &::false) ; differing heap classes -> #f
@@ -3727,39 +3609,40 @@
# +8 b (rec, tagged)
# +16 i (raw counter)
# +24 nfields (raw)
-%fn(rec_equal_check, 32, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct REC_EQUAL_CHECK_LOCALS { a b i nfields } # .SIZE = 32
+%fn(rec_equal_check, %REC_EQUAL_CHECK_LOCALS.SIZE, {
+ %st(a0, sp, %REC_EQUAL_CHECK_LOCALS.a)
+ %st(a1, sp, %REC_EQUAL_CHECK_LOCALS.b)
- %ld(t0, a0, 5) ; td_a
- %ld(t1, a1, 5) ; td_b
+ %heap_ld(t0, a0, %REC.td) ; td_a
+ %heap_ld(t1, a1, %REC.td) ; td_b
%bne(t0, t1, &::false)
- %ld(t1, t0, 13) ; nfields (raw)
- %st(t1, sp, 24)
+ %heap_ld(t1, t0, %TD.nfields)
+ %st(t1, sp, %REC_EQUAL_CHECK_LOCALS.nfields)
%li(t0, 0)
- %st(t0, sp, 16) ; i = 0
+ %st(t0, sp, %REC_EQUAL_CHECK_LOCALS.i) ; i = 0
::loop
- %ld(t0, sp, 16)
- %ld(t1, sp, 24)
+ %ld(t0, sp, %REC_EQUAL_CHECK_LOCALS.i)
+ %ld(t1, sp, %REC_EQUAL_CHECK_LOCALS.nfields)
%beq(t0, t1, &::true)
%shli(t2, t0, 3)
%addi(t2, t2, 13) ; field offset = 13 + 8*i
- %ld(t1, sp, 0)
+ %ld(t1, sp, %REC_EQUAL_CHECK_LOCALS.a)
%add(t1, t1, t2)
%ld(a0, t1, 0) ; a's field i
- %ld(t1, sp, 8)
+ %ld(t1, sp, %REC_EQUAL_CHECK_LOCALS.b)
%add(t1, t1, t2)
%ld(a1, t1, 0) ; b's field i
%call(&equal_recurse)
%li(t0, %imm_val(%IMM.FALSE))
%beq(a0, t0, &::done)
- %ld(t0, sp, 16)
+ %ld(t0, sp, %REC_EQUAL_CHECK_LOCALS.i)
%addi(t0, t0, 1)
- %st(t0, sp, 16)
+ %st(t0, sp, %REC_EQUAL_CHECK_LOCALS.i)
%b(&::loop)
::true
@@ -3791,12 +3674,13 @@
# clobber it freely while assembling args, then tail-call apply, which
# re-derives a1 from the callee fn it dispatches on. Outer convention
# stays intact end-to-end.
-%fn(prim_apply_entry, 16, {
- %st(a0, sp, 0)
+%struct PRIM_APPLY_ENTRY_LOCALS { args pad } # .SIZE = 16
+%fn(prim_apply_entry, %PRIM_APPLY_ENTRY_LOCALS.SIZE, {
+ %st(a0, sp, %PRIM_APPLY_ENTRY_LOCALS.args)
%cdr(a0, a0)
%call(&apply_build_args)
%mov(t0, a0)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %PRIM_APPLY_ENTRY_LOCALS.args)
%car(a0, a0)
%mov(a1, t0)
%tail(&apply)
@@ -3813,14 +3697,15 @@
# +0 walk (advances; current cell of rest)
# +8 head (NIL until first leading arg appended)
# +16 tail (most recent cell; set-cdr! target)
-%fn(apply_build_args, 24, {
- %st(a0, sp, 0)
+%struct APPLY_BUILD_ARGS_LOCALS { walk head tail } # .SIZE = 24
+%fn(apply_build_args, %APPLY_BUILD_ARGS_LOCALS.SIZE, {
+ %st(a0, sp, %APPLY_BUILD_ARGS_LOCALS.walk)
%li(t0, %imm_val(%IMM.NIL))
- %st(t0, sp, 8)
- %st(t0, sp, 16)
+ %st(t0, sp, %APPLY_BUILD_ARGS_LOCALS.head)
+ %st(t0, sp, %APPLY_BUILD_ARGS_LOCALS.tail)
::loop
- %ld(t0, sp, 0)
+ %ld(t0, sp, %APPLY_BUILD_ARGS_LOCALS.walk)
%cdr(t1, t0)
%if_nil(t2, t1, &::last)
@@ -3829,16 +3714,16 @@
%li(a1, %imm_val(%IMM.NIL))
%call(&cons)
- %ld(t0, sp, 8)
+ %ld(t0, sp, %APPLY_BUILD_ARGS_LOCALS.head)
%if_nil(t1, t0, &::first)
- %ld(t0, sp, 16)
- %st(a0, t0, 7)
- %st(a0, sp, 16)
+ %ld(t0, sp, %APPLY_BUILD_ARGS_LOCALS.tail)
+ %set_cdr(a0, t0)
+ %st(a0, sp, %APPLY_BUILD_ARGS_LOCALS.tail)
%b(&::advance)
::first
- %st(a0, sp, 8)
- %st(a0, sp, 16)
+ %st(a0, sp, %APPLY_BUILD_ARGS_LOCALS.head)
+ %st(a0, sp, %APPLY_BUILD_ARGS_LOCALS.tail)
::advance
%advance_walk(0)
@@ -3849,11 +3734,11 @@
# args -- return the trailing list directly. Otherwise splice it onto
# the tail and return head.
%car(a0, t0)
- %ld(t1, sp, 8)
+ %ld(t1, sp, %APPLY_BUILD_ARGS_LOCALS.head)
%if_nil(t2, t1, &::done)
- %ld(t1, sp, 16)
- %st(a0, t1, 7)
- %ld(a0, sp, 8)
+ %ld(t1, sp, %APPLY_BUILD_ARGS_LOCALS.tail)
+ %set_cdr(a0, t1)
+ %ld(a0, sp, %APPLY_BUILD_ARGS_LOCALS.head)
::done
})
@@ -3867,18 +3752,19 @@
# make_param_prim(entry=a0, data=a1) -> prim (a0). Allocates a 24-byte
# PRIM, sets the entry label and data word.
-%fn(make_param_prim, 16, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct MAKE_PARAM_PRIM_LOCALS { entry data } # .SIZE = 16
+%fn(make_param_prim, %MAKE_PARAM_PRIM_LOCALS.SIZE, {
+ %st(a0, sp, %MAKE_PARAM_PRIM_LOCALS.entry)
+ %st(a1, sp, %MAKE_PARAM_PRIM_LOCALS.data)
%li(a0, 24)
%li(a1, %HDR.PRIM)
%call(&alloc_hdr)
- %ld(t0, sp, 0)
- %st(t0, a0, 5)
- %ld(t1, sp, 8)
- %st(t1, a0, 13)
+ %ld(t0, sp, %MAKE_PARAM_PRIM_LOCALS.entry)
+ %heap_st(t0, a0, %PRIM.entry_w)
+ %ld(t1, sp, %MAKE_PARAM_PRIM_LOCALS.data)
+ %heap_st(t1, a0, %PRIM.data)
})
# Parameterized PRIM entries used by define-record-type. Each receives
@@ -3892,13 +3778,14 @@
# ctor: prim.data = TD (HEAP); args = (f0 f1 ...). Inlines the
# %make-record body so we don't have to cons (TD . args) first.
-%fn(prim_ctor_entry, 24, {
+%struct PRIM_CTOR_ENTRY_LOCALS { args td record } # .SIZE = 24
+%fn(prim_ctor_entry, %PRIM_CTOR_ENTRY_LOCALS.SIZE, {
# +0 args
# +8 td (from prim.data)
# +16 record
- %st(a0, sp, 0)
- %ld(t0, a1, 13)
- %st(t0, sp, 8)
+ %st(a0, sp, %PRIM_CTOR_ENTRY_LOCALS.args)
+ %heap_ld(t0, a1, %PRIM.data)
+ %st(t0, sp, %PRIM_CTOR_ENTRY_LOCALS.td)
# Count = length(args).
%call(&list_length)
@@ -3906,12 +3793,12 @@
%addi(a0, a0, 16)
%li(a1, %HDR.REC)
%call(&alloc_hdr)
- %st(a0, sp, 16)
+ %st(a0, sp, %PRIM_CTOR_ENTRY_LOCALS.record)
- %ld(t0, sp, 8)
- %st(t0, a0, 5)
+ %ld(t0, sp, %PRIM_CTOR_ENTRY_LOCALS.td)
+ %heap_st(t0, a0, %REC.td)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PRIM_CTOR_ENTRY_LOCALS.args)
%addi(t1, a0, 13)
::fill_loop
@@ -3923,14 +3810,14 @@
%b(&::fill_loop)
::fill_done
- %ld(a0, sp, 16)
+ %ld(a0, sp, %PRIM_CTOR_ENTRY_LOCALS.record)
})
# predicate: prim.data = TD; args = (rec).
:prim_predicate_entry
%scope prim_predicate
%car(t0, a0)
- %ld(t1, a1, 13)
+ %heap_ld(t1, a1, %PRIM.data)
%tagof(t2, t0)
%li(a0, %imm_val(%IMM.FALSE))
%li(a2, %TAG.HEAP)
@@ -3938,7 +3825,7 @@
%hdr_type(t2, t0)
%li(a2, %HDR.REC)
%bne(t2, a2, &::end)
- %ld(t2, t0, 5)
+ %heap_ld(t2, t0, %REC.td)
%bne(t2, t1, &::end)
%li(a0, %imm_val(%IMM.TRUE))
::end
@@ -3948,7 +3835,7 @@
# accessor: prim.data = tagged field index; args = (rec).
:prim_accessor_entry
%car(t0, a0)
- %ld(t1, a1, 13)
+ %heap_ld(t1, a1, %PRIM.data)
%addi(t1, t1, 13)
%add(t1, t1, t0)
%ld(a0, t1, 0)
@@ -3960,7 +3847,7 @@
%car(t0, a0)
%cdr(t1, a0)
%car(t1, t1)
- %ld(t2, a1, 13)
+ %heap_ld(t2, a1, %PRIM.data)
%addi(t2, t2, 13)
%add(t2, t2, t0)
%st(t1, t2, 0)
@@ -3981,35 +3868,36 @@
# +24 walk (clauses, advancing)
# +32 idx (raw counter)
# +40 nfields
-%fn(eval_define_record_type, 56, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct EVAL_DEFINE_RECORD_TYPE_LOCALS { rest env td walk idx nfields pad } # .SIZE = 56
+%fn(eval_define_record_type, %EVAL_DEFINE_RECORD_TYPE_LOCALS.SIZE, {
+ %st(a0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.rest)
+ %st(a1, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.env)
# clauses = cdddr(rest); count them via list_length.
- %ld(a0, sp, 0)
+ %ld(a0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.rest)
%cdr(a0, a0)
%cdr(a0, a0)
%cdr(a0, a0)
- %st(a0, sp, 24)
+ %st(a0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.walk)
%call(&list_length)
- %st(a0, sp, 40)
+ %st(a0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.nfields)
# td = alloc_hdr(24, HDR.TD); td.name = type-name; td.nfields = nfields.
%li(a0, 24)
%li(a1, %HDR.TD)
%call(&alloc_hdr)
- %st(a0, sp, 16)
- %ld(t0, sp, 0)
+ %st(a0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.td)
+ %ld(t0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.rest)
%car(t0, t0)
- %st(t0, a0, 5)
- %ld(t1, sp, 40)
- %st(t1, a0, 13)
+ %heap_st(t0, a0, %TD.name)
+ %ld(t1, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.nfields)
+ %heap_st(t1, a0, %TD.nfields)
# ctor-prim = make_param_prim(prim_ctor_entry, td); bind ctor-name.
%la(a0, &prim_ctor_entry)
- %ld(a1, sp, 16)
+ %ld(a1, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.td)
%call(&make_param_prim)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.rest)
%cdr(t0, t0)
%car(t0, t0)
%car(t0, t0)
@@ -4017,9 +3905,9 @@
# pred-prim = make_param_prim(prim_predicate_entry, td); bind pred.
%la(a0, &prim_predicate_entry)
- %ld(a1, sp, 16)
+ %ld(a1, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.td)
%call(&make_param_prim)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.rest)
%cdr(t0, t0)
%cdr(t0, t0)
%car(t0, t0)
@@ -4027,37 +3915,37 @@
# Iterate clauses: bind accessor + optional mutator per clause.
%li(t0, 0)
- %st(t0, sp, 32)
+ %st(t0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.idx)
::clause_loop
- %ld(t0, sp, 24)
+ %ld(t0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.walk)
%if_nil(t1, t0, &::done)
# accessor-prim with data = tagged idx; bind cadr(clause).
- %ld(a1, sp, 32)
+ %ld(a1, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.idx)
%shli(a1, a1, 3)
%la(a0, &prim_accessor_entry)
%call(&make_param_prim)
- %ld(t0, sp, 24)
+ %ld(t0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.walk)
%car(t0, t0)
%cdr(t0, t0)
%car(t0, t0)
%bind_global_from_t0()
# Mutator? If cddr(clause) is a pair, bind it.
- %ld(t0, sp, 24)
+ %ld(t0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.walk)
%car(t0, t0)
%cdr(t0, t0)
%cdr(t0, t0)
%if_nil(t1, t0, &::no_mutator)
- %ld(a1, sp, 32)
+ %ld(a1, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.idx)
%shli(a1, a1, 3)
%la(a0, &prim_mutator_entry)
%call(&make_param_prim)
- %ld(t0, sp, 24)
+ %ld(t0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.walk)
%car(t0, t0)
%cdr(t0, t0)
%cdr(t0, t0)
@@ -4066,9 +3954,9 @@
::no_mutator
%advance_walk(24)
- %ld(t0, sp, 32)
+ %ld(t0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.idx)
%addi(t0, t0, 1)
- %st(t0, sp, 32)
+ %st(t0, sp, %EVAL_DEFINE_RECORD_TYPE_LOCALS.idx)
%b(&::clause_loop)
::done
@@ -4102,89 +3990,89 @@
# `length` after append is left zero (preserved by the cap > length
# invariant from bv_capacity_for + the BSS-zero heap), so syscalls that
# read the data_ptr as a C string still see a NUL terminator.
-%fn(bv_putn, 32, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
- %st(a2, sp, 16)
+%struct BV_PUTN_LOCALS { bv src n old_len } # .SIZE = 32
+%fn(bv_putn, %BV_PUTN_LOCALS.SIZE, {
+ %st(a0, sp, %BV_PUTN_LOCALS.bv)
+ %st(a1, sp, %BV_PUTN_LOCALS.src)
+ %st(a2, sp, %BV_PUTN_LOCALS.n)
- %ld(t0, a0, -3)
+ %heap_ld(t0, a0, %BV.hdr)
%shri(t0, t0, 8) ; old_len
- %st(t0, sp, 24)
+ %st(t0, sp, %BV_PUTN_LOCALS.old_len)
# bv_grow ensures cap >= old_len + n + 1, so cap > new_len.
%add(a1, t0, a2)
%addi(a1, a1, 1)
%call(&bv_grow)
- %ld(t0, sp, 0)
- %ld(a0, t0, 5)
- %ld(t1, sp, 24)
+ %ld(t0, sp, %BV_PUTN_LOCALS.bv)
+ %heap_ld(a0, t0, %BV.data)
+ %ld(t1, sp, %BV_PUTN_LOCALS.old_len)
%add(a0, a0, t1) ; dst = data + old_len
- %ld(a1, sp, 8)
- %ld(a2, sp, 16)
+ %ld(a1, sp, %BV_PUTN_LOCALS.src)
+ %ld(a2, sp, %BV_PUTN_LOCALS.n)
%call(&memcpy)
# hdr = (old_len + n) << 8 | HDR.BV. HDR.BV is 0.
- %ld(t0, sp, 24)
- %ld(t1, sp, 16)
+ %ld(t0, sp, %BV_PUTN_LOCALS.old_len)
+ %ld(t1, sp, %BV_PUTN_LOCALS.n)
%add(t0, t0, t1)
%shli(t0, t0, 8)
- %ld(t1, sp, 0)
- %st(t0, t1, -3)
+ %ld(t1, sp, %BV_PUTN_LOCALS.bv)
+ %heap_st(t0, t1, %BV.hdr)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %BV_PUTN_LOCALS.bv)
})
# bv_putc(bv=a0, byte=a1) -> bv (a0). Append a single byte (low 8 bits
# of a1). Same growth + length-update protocol as bv_putn.
-%fn(bv_putc, 16, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct BV_PUTC_LOCALS { bv byte } # .SIZE = 16
+%fn(bv_putc, %BV_PUTC_LOCALS.SIZE, {
+ %st(a0, sp, %BV_PUTC_LOCALS.bv)
+ %st(a1, sp, %BV_PUTC_LOCALS.byte)
- %ld(t0, a0, -3)
+ %heap_ld(t0, a0, %BV.hdr)
%shri(t0, t0, 8) ; old_len
%addi(a1, t0, 2) ; min_cap = old_len + 2
%call(&bv_grow)
- %ld(t0, sp, 0)
- %ld(t1, t0, -3)
+ %ld(t0, sp, %BV_PUTC_LOCALS.bv)
+ %heap_ld(t1, t0, %BV.hdr)
%shri(t1, t1, 8) ; old_len (re-read after grow)
- %ld(t2, t0, 5)
+ %heap_ld(t2, t0, %BV.data)
%add(t2, t2, t1)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %BV_PUTC_LOCALS.byte)
%sb(a0, t2, 0)
%addi(t1, t1, 1)
%shli(t1, t1, 8)
- %st(t1, t0, -3)
+ %heap_st(t1, t0, %BV.hdr)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %BV_PUTC_LOCALS.bv)
})
# bv_putint(bv=a0, value=a1) -> bv (a0). Append decimal repr of (raw,
# untagged) value. Uses :writer_num_buf as a 24-byte scratch buffer
# (fmt_dec writes at most 20 bytes for a 64-bit signed integer).
-%fn(bv_putint, 16, {
- %st(a0, sp, 0)
+%struct BV_PUTINT_LOCALS { bv pad } # .SIZE = 16
+%fn(bv_putint, %BV_PUTINT_LOCALS.SIZE, {
+ %st(a0, sp, %BV_PUTINT_LOCALS.bv)
%la(a0, &writer_num_buf)
%call(&fmt_dec) ; n_bytes (a0)
%mov(a2, a0)
%la(a1, &writer_num_buf)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %BV_PUTINT_LOCALS.bv)
%tail(&bv_putn)
})
# sym_name(idx=a0) -> (ptr=a0, len=a1). Leaf. idx is the untagged sym
# slot index; both fields come straight out of the symtab entry.
:sym_name
- %la(t0, &symtab_buf_ptr)
- %ld(t0, t0, 0)
- %shli(t1, a0, 5)
- %add(t0, t0, t1)
- %ld(a1, t0, 8)
- %ld(a0, t0, 0)
+ %ld_global(t0, &symtab_buf_ptr)
+ %lda_array(a1, t1, t0, %SYMENT.SIZE, a0, %SYMENT.name_len)
+ %ld(a0, t1, %SYMENT.name_ptr)
%ret
# write_to_bv(val=a0, bv=a1, mode=a2) -> bv (a0). Recursively appends
@@ -4192,10 +4080,11 @@
# bytes (display); mode = 1 emits them as `"..."` (write). Pairs are
# delegated to write_pair_to_bv so the recursion through PAIR has its
# own frame.
-%fn(write_to_bv, 32, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
- %st(a2, sp, 16)
+%struct WRITE_TO_BV_LOCALS { val bv mode pad } # .SIZE = 32
+%fn(write_to_bv, %WRITE_TO_BV_LOCALS.SIZE, {
+ %st(a0, sp, %WRITE_TO_BV_LOCALS.val)
+ %st(a1, sp, %WRITE_TO_BV_LOCALS.bv)
+ %st(a2, sp, %WRITE_TO_BV_LOCALS.mode)
%tagof(t0, a0)
%li(t1, %TAG.PAIR)
@@ -4208,24 +4097,24 @@
%beq(t0, t1, &::imm)
# Fall-through: FIXNUM (the only remaining tag).
- %ld(a0, sp, 8)
- %ld(a1, sp, 0)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
+ %ld(a1, sp, %WRITE_TO_BV_LOCALS.val)
%sari(a1, a1, 3)
%tail(&bv_putint)
::sym
- %ld(a0, sp, 0)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.val)
%sari(a0, a0, 3)
%call(&sym_name)
%mov(a2, a1)
%mov(a1, a0)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
::pair
- %ld(a0, sp, 0)
- %ld(a1, sp, 8)
- %ld(a2, sp, 16)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.val)
+ %ld(a1, sp, %WRITE_TO_BV_LOCALS.bv)
+ %ld(a2, sp, %WRITE_TO_BV_LOCALS.mode)
%tail(&write_pair_to_bv)
::heap
@@ -4243,60 +4132,60 @@
%b(&::heap_unknown)
::heap_bv
- %ld(t0, sp, 16)
+ %ld(t0, sp, %WRITE_TO_BV_LOCALS.mode)
%beqz(t0, &::heap_bv_raw)
# write mode: emit `"`, then the raw bytes, then `"`.
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%li(a1, 34)
%call(&bv_putc)
- %ld(t0, sp, 0)
- %ld(a1, t0, 5)
- %ld(a2, t0, -3)
+ %ld(t0, sp, %WRITE_TO_BV_LOCALS.val)
+ %heap_ld(a1, t0, %BV.data)
+ %heap_ld(a2, t0, %BV.hdr)
%shri(a2, a2, 8)
%call(&bv_putn)
%li(a1, 34)
%tail(&bv_putc)
::heap_bv_raw
- %ld(t0, sp, 0)
- %ld(a1, t0, 5)
- %ld(a2, t0, -3)
+ %ld(t0, sp, %WRITE_TO_BV_LOCALS.val)
+ %heap_ld(a1, t0, %BV.data)
+ %heap_ld(a2, t0, %BV.hdr)
%shri(a2, a2, 8)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
::heap_closure
%la(a1, &str_closure)
%li(a2, 10)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
::heap_prim
%la(a1, &str_prim)
%li(a2, 7)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
::heap_td
%la(a1, &str_td)
%li(a2, 11)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
::heap_rec
%la(a1, &str_rec)
%li(a2, 9)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
::heap_unknown
%la(a1, &str_unknown)
%li(a2, 10)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
::imm
- %ld(a0, sp, 0)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.val)
%sari(a0, a0, 3)
%beqz(a0, &::imm_false)
%addi(t0, a0, -1)
@@ -4310,37 +4199,37 @@
# EOF (idx == 5) is the only remaining IMM.
%la(a1, &str_eof)
%li(a2, 5)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
::imm_false
%la(a1, &str_false)
%li(a2, 2)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
::imm_true
%la(a1, &str_true)
%li(a2, 2)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
::imm_nil
%la(a1, &str_nil)
%li(a2, 2)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
::imm_unspec
%la(a1, &str_unspec)
%li(a2, 8)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
::imm_unbound
%la(a1, &str_unbound)
%li(a2, 9)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_TO_BV_LOCALS.bv)
%tail(&bv_putn)
})
@@ -4354,25 +4243,26 @@
# +0 pair walk
# +8 bv (stable wrapper; reused across recursive calls)
# +16 mode
-%fn(write_pair_to_bv, 32, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
- %st(a2, sp, 16)
+%struct WRITE_PAIR_TO_BV_LOCALS { pair bv mode pad } # .SIZE = 32
+%fn(write_pair_to_bv, %WRITE_PAIR_TO_BV_LOCALS.SIZE, {
+ %st(a0, sp, %WRITE_PAIR_TO_BV_LOCALS.pair)
+ %st(a1, sp, %WRITE_PAIR_TO_BV_LOCALS.bv)
+ %st(a2, sp, %WRITE_PAIR_TO_BV_LOCALS.mode)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_PAIR_TO_BV_LOCALS.bv)
%li(a1, 40)
%call(&bv_putc)
::loop
- %ld(t0, sp, 0)
+ %ld(t0, sp, %WRITE_PAIR_TO_BV_LOCALS.pair)
%car(a0, t0)
- %ld(a1, sp, 8)
- %ld(a2, sp, 16)
+ %ld(a1, sp, %WRITE_PAIR_TO_BV_LOCALS.bv)
+ %ld(a2, sp, %WRITE_PAIR_TO_BV_LOCALS.mode)
%call(&write_to_bv)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %WRITE_PAIR_TO_BV_LOCALS.pair)
%cdr(t0, t0)
- %st(t0, sp, 0)
+ %st(t0, sp, %WRITE_PAIR_TO_BV_LOCALS.pair)
%if_nil(t1, t0, &::done)
%tagof(t1, t0)
@@ -4380,29 +4270,29 @@
%beq(t1, t2, &::cont)
# Dotted tail: emit ` . ` then write_to_bv(cdr).
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_PAIR_TO_BV_LOCALS.bv)
%li(a1, 32)
%call(&bv_putc)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_PAIR_TO_BV_LOCALS.bv)
%li(a1, 46)
%call(&bv_putc)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_PAIR_TO_BV_LOCALS.bv)
%li(a1, 32)
%call(&bv_putc)
- %ld(a0, sp, 0)
- %ld(a1, sp, 8)
- %ld(a2, sp, 16)
+ %ld(a0, sp, %WRITE_PAIR_TO_BV_LOCALS.pair)
+ %ld(a1, sp, %WRITE_PAIR_TO_BV_LOCALS.bv)
+ %ld(a2, sp, %WRITE_PAIR_TO_BV_LOCALS.mode)
%call(&write_to_bv)
%b(&::done)
::cont
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_PAIR_TO_BV_LOCALS.bv)
%li(a1, 32)
%call(&bv_putc)
%b(&::loop)
::done
- %ld(a0, sp, 8)
+ %ld(a0, sp, %WRITE_PAIR_TO_BV_LOCALS.bv)
%li(a1, 41)
%tail(&bv_putc)
})
@@ -4411,14 +4301,15 @@
# delegate to write_to_bv; helper for display / write. The 16-byte
# starting capacity is the floor from bv_capacity_for; bv_putn /
# bv_putc grow as needed.
-%fn(value_to_bv, 16, {
- %st(a0, sp, 0)
- %st(a1, sp, 8)
+%struct VALUE_TO_BV_LOCALS { val mode } # .SIZE = 16
+%fn(value_to_bv, %VALUE_TO_BV_LOCALS.SIZE, {
+ %st(a0, sp, %VALUE_TO_BV_LOCALS.val)
+ %st(a1, sp, %VALUE_TO_BV_LOCALS.mode)
%li(a0, 0)
%call(&bv_alloc)
%mov(a1, a0)
- %ld(a0, sp, 0)
- %ld(a2, sp, 8)
+ %ld(a0, sp, %VALUE_TO_BV_LOCALS.val)
+ %ld(a2, sp, %VALUE_TO_BV_LOCALS.mode)
%tail(&write_to_bv)
})
@@ -4431,8 +4322,8 @@
%car(a0, a0)
%li(a1, 0)
%call(&value_to_bv)
- %ld(a1, a0, 5)
- %ld(a2, a0, -3)
+ %heap_ld(a1, a0, %BV.data)
+ %heap_ld(a2, a0, %BV.hdr)
%shri(a2, a2, 8)
%li(a0, 1)
%call(&sys_write)
@@ -4443,8 +4334,8 @@
%car(a0, a0)
%li(a1, 1)
%call(&value_to_bv)
- %ld(a1, a0, 5)
- %ld(a2, a0, -3)
+ %heap_ld(a1, a0, %BV.data)
+ %heap_ld(a2, a0, %BV.hdr)
%shri(a2, a2, 8)
%li(a0, 1)
%call(&sys_write)
@@ -4460,51 +4351,52 @@
# Frame: 16 bytes
# +0 walk (initially args; advances over irritants)
# +8 bv
-%fn(prim_error_entry, 16, {
- %st(a0, sp, 0)
+%struct PRIM_ERROR_ENTRY_LOCALS { walk bv } # .SIZE = 16
+%fn(prim_error_entry, %PRIM_ERROR_ENTRY_LOCALS.SIZE, {
+ %st(a0, sp, %PRIM_ERROR_ENTRY_LOCALS.walk)
%li(a0, 0)
%call(&bv_alloc)
- %st(a0, sp, 8)
+ %st(a0, sp, %PRIM_ERROR_ENTRY_LOCALS.bv)
%la(a1, &str_error_prefix)
%li(a2, 16)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %PRIM_ERROR_ENTRY_LOCALS.bv)
%call(&bv_putn)
# First arg (the message) goes through write_to_bv with display mode.
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PRIM_ERROR_ENTRY_LOCALS.walk)
%car(a0, t0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %PRIM_ERROR_ENTRY_LOCALS.bv)
%li(a2, 0)
%call(&write_to_bv)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PRIM_ERROR_ENTRY_LOCALS.walk)
%cdr(t0, t0)
- %st(t0, sp, 0)
+ %st(t0, sp, %PRIM_ERROR_ENTRY_LOCALS.walk)
::loop
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PRIM_ERROR_ENTRY_LOCALS.walk)
%if_nil(t1, t0, &::done)
- %ld(a0, sp, 8)
+ %ld(a0, sp, %PRIM_ERROR_ENTRY_LOCALS.bv)
%li(a1, 32)
%call(&bv_putc)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PRIM_ERROR_ENTRY_LOCALS.walk)
%car(a0, t0)
- %ld(a1, sp, 8)
+ %ld(a1, sp, %PRIM_ERROR_ENTRY_LOCALS.bv)
%li(a2, 0)
%call(&write_to_bv)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PRIM_ERROR_ENTRY_LOCALS.walk)
%cdr(t0, t0)
- %st(t0, sp, 0)
+ %st(t0, sp, %PRIM_ERROR_ENTRY_LOCALS.walk)
%b(&::loop)
::done
- %ld(t0, sp, 8)
- %ld(a0, t0, 5)
+ %ld(t0, sp, %PRIM_ERROR_ENTRY_LOCALS.bv)
+ %heap_ld(a0, t0, %BV.data)
%tail(&runtime_error)
})
@@ -4519,30 +4411,31 @@
# +8 template bv
# +16 args walk
# +24 idx (current byte offset into template)
-%fn(prim_format_entry, 32, {
- %st(a0, sp, 16) ; spill incoming args while we set up
+%struct PRIM_FORMAT_ENTRY_LOCALS { out template args idx } # .SIZE = 32
+%fn(prim_format_entry, %PRIM_FORMAT_ENTRY_LOCALS.SIZE, {
+ %st(a0, sp, %PRIM_FORMAT_ENTRY_LOCALS.args) ; spill incoming args while we set up
%li(a0, 0)
%call(&bv_alloc)
- %st(a0, sp, 0)
+ %st(a0, sp, %PRIM_FORMAT_ENTRY_LOCALS.out)
- %ld(t0, sp, 16)
+ %ld(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.args)
%car(t1, t0)
- %st(t1, sp, 8)
+ %st(t1, sp, %PRIM_FORMAT_ENTRY_LOCALS.template)
%cdr(t0, t0)
- %st(t0, sp, 16)
+ %st(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.args)
%li(t0, 0)
- %st(t0, sp, 24)
+ %st(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.idx)
::loop
- %ld(t1, sp, 8)
- %ld(t2, t1, -3)
+ %ld(t1, sp, %PRIM_FORMAT_ENTRY_LOCALS.template)
+ %heap_ld(t2, t1, %BV.hdr)
%shri(t2, t2, 8) ; template length
- %ld(t0, sp, 24)
+ %ld(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.idx)
%beq(t0, t2, &::done)
- %ld(a3, t1, 5)
+ %heap_ld(a3, t1, %BV.data)
%add(a3, a3, t0)
%lb(a3, a3, 0) ; byte = template.data[idx]
@@ -4550,28 +4443,28 @@
%beqz(t1, &::tilde)
# Plain byte: emit and advance.
- %ld(a0, sp, 0)
+ %ld(a0, sp, %PRIM_FORMAT_ENTRY_LOCALS.out)
%mov(a1, a3)
%call(&bv_putc)
- %ld(t0, sp, 24)
+ %ld(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.idx)
%addi(t0, t0, 1)
- %st(t0, sp, 24)
+ %st(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.idx)
%b(&::loop)
::tilde
- %ld(t0, sp, 24)
+ %ld(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.idx)
%addi(t0, t0, 1)
- %ld(t1, sp, 8)
- %ld(t2, t1, -3)
+ %ld(t1, sp, %PRIM_FORMAT_ENTRY_LOCALS.template)
+ %heap_ld(t2, t1, %BV.hdr)
%shri(t2, t2, 8)
%beq(t0, t2, &::tilde_lit)
- %ld(t1, t1, 5)
+ %heap_ld(t1, t1, %BV.data)
%add(t1, t1, t0)
%lb(a3, t1, 0) ; spec
%addi(t0, t0, 1) ; advance past spec
- %st(t0, sp, 24)
+ %st(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.idx)
%addi(t1, a3, -97) ; 'a'
%beqz(t1, &::spec_a)
@@ -4586,73 +4479,73 @@
# Unknown directive: emit `~` then the spec byte verbatim. Re-read
# the spec byte from the template since bv_putc may clobber a3.
- %ld(a0, sp, 0)
+ %ld(a0, sp, %PRIM_FORMAT_ENTRY_LOCALS.out)
%li(a1, 126)
%call(&bv_putc)
- %ld(t0, sp, 8)
- %ld(t1, t0, 5)
- %ld(t0, sp, 24)
+ %ld(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.template)
+ %heap_ld(t1, t0, %BV.data)
+ %ld(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.idx)
%addi(t0, t0, -1)
%add(t1, t1, t0)
%lb(a1, t1, 0)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %PRIM_FORMAT_ENTRY_LOCALS.out)
%call(&bv_putc)
%b(&::loop)
::tilde_lit
# `~` at end of template: emit literal `~` and finish next iter.
- %ld(a0, sp, 0)
+ %ld(a0, sp, %PRIM_FORMAT_ENTRY_LOCALS.out)
%li(a1, 126)
%call(&bv_putc)
- %ld(t0, sp, 24)
+ %ld(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.idx)
%addi(t0, t0, 1)
- %st(t0, sp, 24)
+ %st(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.idx)
%b(&::loop)
::spec_a
- %ld(t0, sp, 16)
+ %ld(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.args)
%car(a0, t0)
%cdr(t0, t0)
- %st(t0, sp, 16)
- %ld(a1, sp, 0)
+ %st(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.args)
+ %ld(a1, sp, %PRIM_FORMAT_ENTRY_LOCALS.out)
%li(a2, 0)
%call(&write_to_bv)
%b(&::loop)
::spec_s
- %ld(t0, sp, 16)
+ %ld(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.args)
%car(a0, t0)
%cdr(t0, t0)
- %st(t0, sp, 16)
- %ld(a1, sp, 0)
+ %st(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.args)
+ %ld(a1, sp, %PRIM_FORMAT_ENTRY_LOCALS.out)
%li(a2, 1)
%call(&write_to_bv)
%b(&::loop)
::spec_d
- %ld(t0, sp, 16)
+ %ld(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.args)
%car(t1, t0)
%cdr(t0, t0)
- %st(t0, sp, 16)
+ %st(t0, sp, %PRIM_FORMAT_ENTRY_LOCALS.args)
%sari(a1, t1, 3)
- %ld(a0, sp, 0)
+ %ld(a0, sp, %PRIM_FORMAT_ENTRY_LOCALS.out)
%call(&bv_putint)
%b(&::loop)
::spec_pct
- %ld(a0, sp, 0)
+ %ld(a0, sp, %PRIM_FORMAT_ENTRY_LOCALS.out)
%li(a1, 10)
%call(&bv_putc)
%b(&::loop)
::spec_tilde
- %ld(a0, sp, 0)
+ %ld(a0, sp, %PRIM_FORMAT_ENTRY_LOCALS.out)
%li(a1, 126)
%call(&bv_putc)
%b(&::loop)
::done
- %ld(a0, sp, 0)
+ %ld(a0, sp, %PRIM_FORMAT_ENTRY_LOCALS.out)
})
# =========================================================================
@@ -4669,15 +4562,16 @@
# to syscalls expecting a C string.
# wrap_syscall_result(raw=a0) -> (#t . r) or (#f . errno).
-%fn(wrap_syscall_result, 16, {
- %st(a0, sp, 0)
+%struct WRAP_SYSCALL_RESULT_LOCALS { raw pad } # .SIZE = 16
+%fn(wrap_syscall_result, %WRAP_SYSCALL_RESULT_LOCALS.SIZE, {
+ %st(a0, sp, %WRAP_SYSCALL_RESULT_LOCALS.raw)
%bltz(a0, &::err)
%shli(a1, a0, 3)
%li(a0, %imm_val(%IMM.TRUE))
%tail(&cons)
::err
- %ld(t0, sp, 0)
+ %ld(t0, sp, %WRAP_SYSCALL_RESULT_LOCALS.raw)
%li(t1, 0)
%sub(t0, t1, t0)
%shli(a1, t0, 3)
@@ -4698,8 +4592,9 @@
# sys_clone() -> r (a0). Linux clone(SIGCHLD, 0, 0, 0, 0) -- fork-style.
# Saves and restores s0 around the syscall because %p1_syscall reads s0
# as the 5th OS-syscall argument.
-%fn(sys_clone, 16, {
- %st(s0, sp, 0)
+%struct SYS_CLONE_LOCALS { saved_s0 pad } # .SIZE = 16
+%fn(sys_clone, %SYS_CLONE_LOCALS.SIZE, {
+ %st(s0, sp, %SYS_CLONE_LOCALS.saved_s0)
%li(s0, 0)
%li(a1, 17)
@@ -4709,7 +4604,7 @@
%li(a0, %p1_sys_clone)
%syscall
- %ld(s0, sp, 0)
+ %ld(s0, sp, %SYS_CLONE_LOCALS.saved_s0)
})
# sys_execve(path=a0, argv=a1, envp=a2) -> -errno (a0). Only returns on
@@ -4740,23 +4635,24 @@
# +0 list
# +8 count
# +16 array ptr (raw)
-%fn(build_execve_argv, 24, {
- %st(a0, sp, 0)
+%struct BUILD_EXECVE_ARGV_LOCALS { list count array } # .SIZE = 24
+%fn(build_execve_argv, %BUILD_EXECVE_ARGV_LOCALS.SIZE, {
+ %st(a0, sp, %BUILD_EXECVE_ARGV_LOCALS.list)
%call(&list_length) ; clobbers a0 -> count
- %st(a0, sp, 8)
+ %st(a0, sp, %BUILD_EXECVE_ARGV_LOCALS.count)
%addi(a0, a0, 1)
%shli(a0, a0, 3)
%call(&alloc_bytes)
- %st(a0, sp, 16)
+ %st(a0, sp, %BUILD_EXECVE_ARGV_LOCALS.array)
- %ld(t0, sp, 0)
- %ld(t1, sp, 16)
+ %ld(t0, sp, %BUILD_EXECVE_ARGV_LOCALS.list)
+ %ld(t1, sp, %BUILD_EXECVE_ARGV_LOCALS.array)
::fill_loop
%if_nil(t2, t0, &::fill_done)
%car(a3, t0)
- %ld(a2, a3, 5)
+ %heap_ld(a2, a3, %BV.data)
%st(a2, t1, 0)
%addi(t1, t1, 8)
%cdr(t0, t0)
@@ -4766,14 +4662,14 @@
%li(t2, 0)
%st(t2, t1, 0)
- %ld(a0, sp, 16)
+ %ld(a0, sp, %BUILD_EXECVE_ARGV_LOCALS.array)
})
# (sys-read fd buf count)
%fn(prim_sys_read_entry, 0, {
%args3(t0, t1, t2, a0)
%sari(t0, t0, 3) ; fd
- %ld(t1, t1, 5) ; buf data ptr
+ %heap_ld(t1, t1, %BV.data) ; buf data ptr
%sari(t2, t2, 3) ; count
%mov(a0, t0)
%mov(a1, t1)
@@ -4786,7 +4682,7 @@
%fn(prim_sys_write_entry, 0, {
%args3(t0, t1, t2, a0)
%sari(t0, t0, 3) ; fd
- %ld(t1, t1, 5) ; buf data ptr
+ %heap_ld(t1, t1, %BV.data) ; buf data ptr
%sari(t2, t2, 3) ; count
%mov(a0, t0)
%mov(a1, t1)
@@ -4806,7 +4702,7 @@
%fn(prim_sys_openat_entry, 0, {
%args4(t0, t1, t2, a3, a0)
%sari(t0, t0, 3) ; dirfd
- %ld(t1, t1, 5) ; path data_ptr
+ %heap_ld(t1, t1, %BV.data) ; path data_ptr
%sari(t2, t2, 3) ; flags
%sari(a3, a3, 3) ; mode
%mov(a0, t0)
@@ -4823,13 +4719,14 @@
})
# (sys-execve path argv-list)
-%fn(prim_sys_execve_entry, 16, {
+%struct PRIM_SYS_EXECVE_ENTRY_LOCALS { path pad } # .SIZE = 16
+%fn(prim_sys_execve_entry, %PRIM_SYS_EXECVE_ENTRY_LOCALS.SIZE, {
%args2(t0, a0, a0) ; t0 = path bv, a0 = argv-list
- %st(t0, sp, 0)
+ %st(t0, sp, %PRIM_SYS_EXECVE_ENTRY_LOCALS.path)
%call(&build_execve_argv)
%mov(a1, a0)
- %ld(a0, sp, 0)
- %ld(a0, a0, 5) ; path data ptr
+ %ld(a0, sp, %PRIM_SYS_EXECVE_ENTRY_LOCALS.path)
+ %heap_ld(a0, a0, %BV.data) ; path data ptr
%li(a2, 0)
%call(&sys_execve)
%tail(&wrap_syscall_result)
@@ -4840,7 +4737,7 @@
%args4(t0, t1, t2, a3, a0)
%sari(t0, t0, 3) ; idtype
%sari(t1, t1, 3) ; id
- %ld(t2, t2, 5) ; infop bv data ptr
+ %heap_ld(t2, t2, %BV.data) ; infop bv data ptr
%sari(a3, a3, 3) ; options
%mov(a0, t0)
%mov(a1, t1)
@@ -4859,66 +4756,65 @@
# +16 list head
# +24 list tail
# +32 current bv (across memcpy)
-%fn(prim_sys_argv_entry, 40, {
- %la(t0, &saved_argv)
- %ld(t0, t0, 0)
- %st(t0, sp, 0)
- %la(t0, &saved_argc)
- %ld(t0, t0, 0)
- %st(t0, sp, 8)
+%struct PRIM_SYS_ARGV_ENTRY_LOCALS { argv count head tail bv } # .SIZE = 40
+%fn(prim_sys_argv_entry, %PRIM_SYS_ARGV_ENTRY_LOCALS.SIZE, {
+ %ld_global(t0, &saved_argv)
+ %st(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.argv)
+ %ld_global(t0, &saved_argc)
+ %st(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.count)
%li(t0, %imm_val(%IMM.NIL))
- %st(t0, sp, 16)
- %st(t0, sp, 24)
+ %st(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.head)
+ %st(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.tail)
::loop
- %ld(t0, sp, 8)
+ %ld(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.count)
%beqz(t0, &::done)
# len = strlen(*argv)
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.argv)
%ld(a0, t0, 0)
%call(&strlen)
# bv = bv_alloc(len)
%call(&bv_alloc)
- %st(a0, sp, 32)
+ %st(a0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.bv)
# memcpy(bv.data_ptr, *argv, len-from-bv-hdr).
- %ld(t0, sp, 32)
- %ld(a0, t0, 5)
- %ld(t1, sp, 0)
+ %ld(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.bv)
+ %heap_ld(a0, t0, %BV.data)
+ %ld(t1, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.argv)
%ld(a1, t1, 0)
- %ld(t1, t0, -3)
+ %heap_ld(t1, t0, %BV.hdr)
%shri(a2, t1, 8)
%call(&memcpy)
# cell = cons(bv, NIL); append to list head/tail.
- %ld(a0, sp, 32)
+ %ld(a0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.bv)
%li(a1, %imm_val(%IMM.NIL))
%call(&cons)
- %ld(t0, sp, 16)
+ %ld(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.head)
%if_nil(t1, t0, &::first)
- %ld(t0, sp, 24)
- %st(a0, t0, 7)
- %st(a0, sp, 24)
+ %ld(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.tail)
+ %set_cdr(a0, t0)
+ %st(a0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.tail)
%b(&::advance)
::first
- %st(a0, sp, 16)
- %st(a0, sp, 24)
+ %st(a0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.head)
+ %st(a0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.tail)
::advance
- %ld(t0, sp, 0)
+ %ld(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.argv)
%addi(t0, t0, 8)
- %st(t0, sp, 0)
- %ld(t0, sp, 8)
+ %st(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.argv)
+ %ld(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.count)
%addi(t0, t0, -1)
- %st(t0, sp, 8)
+ %st(t0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.count)
%b(&::loop)
::done
- %ld(a0, sp, 16)
+ %ld(a0, sp, %PRIM_SYS_ARGV_ENTRY_LOCALS.head)
})
# (eof-object) and (eof-object? x).
@@ -5130,6 +5026,50 @@
:name_ch_newline "newline"
# =========================================================================
+# Startup -- bss_init / heap_init
+# =========================================================================
+
+# bss_init() -> none. Walks bss_init_tbl once and writes &ELF_end + OFF_*
+# into each pointer slot. Same idiom as M1pp.P1: a tiny init table walked
+# once. Leaf.
+:bss_init
+%scope bss_init
+ %la(t0, &ELF_end)
+ %la(t1, &bss_init_tbl)
+ %la(t2, &bss_init_tbl_end)
+
+ ::loop
+ %beq(t1, t2, &::done)
+ %ld(a0, t1, 0)
+ %ld(a2, t1, 8)
+ %add(a2, a2, t0)
+ %st(a2, a0, 0)
+ %addi(t1, t1, 16)
+ %b(&::loop)
+ ::done
+
+ %ret
+%endscope
+
+# heap_init() -> none. Sets heap_next (&heap_buf rounded up to 8-byte
+# alignment) and heap_end (heap_buf + HEAP_CAP_BYTES). cons assumes
+# 8-byte-aligned heap_next so every pair pointer's low 3 bits are exactly
+# the PAIR tag; &ELF_end's alignment depends on the data section above
+# it. cons / alloc_hdr / alloc_bytes test (heap_next + bytes <= heap_end)
+# on every allocation and abort via runtime_error on overflow. Leaf.
+:heap_init
+ %ld_global(t0, &heap_buf_ptr)
+ %alignup(t0, t0, 8, t1)
+ %st_global(t0, &heap_next, t1)
+
+ %ld_global(t0, &heap_buf_ptr)
+ %li(t1, %HEAP_CAP_BYTES)
+ %add(t0, t0, t1)
+ %st_global(t0, &heap_end, t1)
+
+ %ret
+
+# =========================================================================
# BSS pointer-init table
# =========================================================================
#