boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

commit d58e86959f8f535523f43e86174c3db43f297b44
parent 916cf97b8f41509b44ffed37e1ca56534882f07a
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 30 Apr 2026 17:43:15 -0700

scheme1: tidy

Diffstat:
Mscheme1/scheme1.P1pp | 1789++++++++++++++++++++++++++++++++++++-------------------------------------------
1 file changed, 807 insertions(+), 982 deletions(-)

diff --git a/scheme1/scheme1.P1pp b/scheme1/scheme1.P1pp @@ -79,17 +79,58 @@ %lb(rd, rd, 0) %endm +# Increment cursor and store it back. `addr_reg` is the address of +# readbuf_pos as returned by %lda_global (the second output register). +%macro readbuf_advance(pos_reg, addr_reg) + %addi(pos_reg, pos_reg, 1) + %st(pos_reg, addr_reg, 0) +%endm + +# Load readbuf_len into len_reg and branch to target if cursor is at EOF. +%macro readbuf_at_eof(pos_reg, len_reg, target) + %ld_global(len_reg, &readbuf_len) + %beq(pos_reg, len_reg, target) +%endm + +# Branch character equal/not-equal: if (c == expect) / (c != expect) goto target. +# expect passed as -(char_code). scratch is clobbered. +%macro bceq(c, neg_cv, target, scratch) + %addi(scratch, c, neg_cv) + %beqz(scratch, target) +%endm + +%macro bcne(c, neg_cv, target, scratch) + %addi(scratch, c, neg_cv) + %bnez(scratch, target) +%endm + +# Branch immediate equal/not-equal: if (reg == value) / (reg != value) goto target. +# scratch is clobbered. +%macro bieq(reg, value, target, scratch) + %li(scratch, value) + %beq(reg, scratch, target) +%endm + +%macro bine(reg, value, target, scratch) + %li(scratch, value) + %bne(reg, scratch, target) +%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) + %bceq(ch_reg, -32, target, scratch) ; SP + %bceq(ch_reg, -9, target, scratch) ; HT + %bceq(ch_reg, -10, target, scratch) ; LF + %bceq(ch_reg, -13, target, scratch) ; CR +%endm + +# Branch to `target` if lo_neg <= c < lo_neg+count (unsigned). Both +# scratch and count_scratch are clobbered. +%macro brange(c, lo_neg, count, scratch, count_scratch, target) + %addi(scratch, c, lo_neg) + %li(count_scratch, count) + %bltu(scratch, count_scratch, target) %endm # Compute &symtab_buf + idx_reg * SYMENT.SIZE into rd. `scratch` is @@ -142,21 +183,19 @@ %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) +# Advance a named list-cursor local to its cdr. t0 is the implicit scratch +# register; callers must ensure it's free. +%macro advance_walk(name) + %ldl(t0, name) %cdr(t0, t0) - %st(t0, sp, slot) + %stl(t0, name) %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) +# Set a global binding. sym is a tagged symbol, val is the new value. +# Untags sym into the idx ABI position and calls sym_set_global. +%macro set_global(sym, val) + %mov(a1, val) + %untag_sym(a0, sym) %call(&sym_set_global) %endm @@ -220,15 +259,7 @@ %call(&heap_init) %call(&intern_special_forms) %call(&register_primitives) - - # Bind `eof` as a direct global -> IMM.EOF value. (Predicate is `eof?`, - # registered via prim_table.) Cheaper and shorter than a 0-arg thunk. - %la(a0, &name_eof) - %li(a1, 3) - %call(&intern) - %untag_sym(a0, a0) - %li(a1, %imm_val(%IMM.EOF)) - %call(&sym_set_global) + %call(&register_globals) # load_source(argv[1]) %ld_global(a0, &saved_argv) @@ -277,22 +308,19 @@ %beq(t0, t1, &::done) %readbuf_byte(a0, t0) %is_ws_branch(a1, a0, &::step) - %addi(a1, a0, -59) ; ';' - %beqz(a1, &::comment) + %bceq(a0, -59, &::comment, a1) ; ';' %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) + %bcne(a0, -10, &::comment, a1) ; LF ::step %addi(t0, t0, 1) %b(&::loop) ::done + %st(t0, t2, 0) %li(a0, 1) %beq(t0, t1, &::ret) @@ -309,26 +337,19 @@ %ld_global(t0, &readbuf_pos) %readbuf_byte(a0, t0) - %addi(a1, a0, -40) - %beqz(a1, &::lparen) - %addi(a1, a0, -41) - %beqz(a1, &::rparen) - %addi(a1, a0, -35) - %beqz(a1, &::hash) - %addi(a1, a0, -39) ; '\'' - %beqz(a1, &::quote) - %addi(a1, a0, -44) ; ',' - %beqz(a1, &::comma) - %addi(a1, a0, -34) ; '"' - %beqz(a1, &::string) + %bceq(a0, -40, &::lparen, a1) + %bceq(a0, -41, &::rparen, a1) + %bceq(a0, -35, &::hash, a1) + %bceq(a0, -39, &::quote, a1) + %bceq(a0, -44, &::comma, a1) + %bceq(a0, -34, &::string, a1) %tail(&parse_atom) ::lparen # Consume '(' and read items until ')'. %lda_global(t1, t0, &readbuf_pos) - %addi(t1, t1, 1) - %st(t1, t0, 0) + %readbuf_advance(t1, t0) %tail(&parse_list) ::rparen @@ -338,31 +359,22 @@ # Consume opening '"' and tail to parse_string. parse_string scans # through the matching '"' (consuming it) and returns a tagged bv. %lda_global(t1, t0, &readbuf_pos) - %addi(t1, t1, 1) - %st(t1, t0, 0) + %readbuf_advance(t1, t0) %tail(&parse_string) ::hash # Consume '#' plus its type byte; dispatch on the type byte. %lda_global(t0, t2, &readbuf_pos) %addi(t0, t0, 1) - %ld_global(t1, &readbuf_len) - %beq(t0, t1, &::eof) + %readbuf_at_eof(t0, t1, &::eof) %readbuf_byte(a0, t0) - %addi(t0, t0, 1) - %st(t0, t2, 0) - %addi(a1, a0, -116) ; 't' - %beqz(a1, &::true_lit) - %addi(a1, a0, -102) ; 'f' - %beqz(a1, &::false_lit) - %addi(a1, a0, -120) ; 'x' - %beqz(a1, &::hex_lit) - %addi(a1, a0, -88) ; 'X' - %beqz(a1, &::hex_lit) - %addi(a1, a0, -92) ; '\\' - %beqz(a1, &::char_lit) - %addi(a1, a0, -117) ; 'u' - %beqz(a1, &::u8_lit) + %readbuf_advance(t0, t2) + %bceq(a0, -116, &::true_lit, a1) ; 't' + %bceq(a0, -102, &::false_lit, a1) ; 'f' + %bceq(a0, -120, &::hex_lit, a1) ; 'x' + %bceq(a0, -88, &::hex_lit, a1) ; 'X' + %bceq(a0, -92, &::char_lit, a1) ; '\\' + %bceq(a0, -117, &::u8_lit, a1) ; 'u' %die(msg_bad_hash) ::true_lit @@ -381,10 +393,8 @@ %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) + %bceq(a0, -40, &::hex_end, a1) + %bceq(a0, -41, &::hex_end, a1) %addi(t0, t0, 1) %b(&::hex_scan) ::hex_end @@ -412,8 +422,7 @@ # Consume the leading '\''; recurse into parse_one for the datum; # then build (quote <datum>). %lda_global(t0, t2, &readbuf_pos) - %addi(t0, t0, 1) - %st(t0, t2, 0) + %readbuf_advance(t0, t2) %call(&parse_one) %li(a1, %imm_val(%IMM.NIL)) %call(&cons) @@ -429,8 +438,7 @@ # `(unquote x)` reaches eval as an application of the unbound # `unquote` and dies through the standard unbound-variable path. %lda_global(t0, t2, &readbuf_pos) - %addi(t0, t0, 1) - %st(t0, t2, 0) + %readbuf_advance(t0, t2) %call(&parse_one) %li(a1, %imm_val(%IMM.NIL)) %call(&cons) @@ -448,18 +456,14 @@ # 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. %lda_global(t0, t2, &readbuf_pos) - %ld_global(t1, &readbuf_len) - %beq(t0, t1, &::u8_bad) + %readbuf_at_eof(t0, t1, &::u8_bad) %readbuf_byte(a0, t0) - %addi(a1, a0, -56) ; '8' - %bnez(a1, &::u8_bad) + %bcne(a0, -56, &::u8_bad, a1) ; '8' %addi(t0, t0, 1) %beq(t0, t1, &::u8_bad) %readbuf_byte(a0, t0) - %addi(a1, a0, -40) ; '(' - %bnez(a1, &::u8_bad) - %addi(t0, t0, 1) - %st(t0, t2, 0) + %bcne(a0, -40, &::u8_bad, a1) ; '(' + %readbuf_advance(t0, t2) %tail(&parse_u8_body) ::u8_bad @@ -487,21 +491,17 @@ %ld_global(t1, &readbuf_len) %readbuf_byte(a0, t0) - %addi(a1, a0, -41) - %beqz(a1, &::close) + %bceq(a0, -41, &::close, a1) # Dotted-pair separator: '.' followed by ws/paren/EOF (otherwise the # '.' is part of an identifier and parse_atom handles it). - %addi(a1, a0, -46) - %bnez(a1, &::not_dot) + %bcne(a0, -46, &::not_dot, a1) ; '.' %addi(a2, t0, 1) %beq(a2, t1, &::do_dot) %readbuf_byte(a3, a2) %is_ws_branch(a1, a3, &::do_dot) - %addi(a1, a3, -40) - %beqz(a1, &::do_dot) - %addi(a1, a3, -41) - %beqz(a1, &::do_dot) + %bceq(a3, -40, &::do_dot, a1) + %bceq(a3, -41, &::do_dot, a1) ::not_dot # Not ')': parse one item, append. @@ -511,8 +511,7 @@ # If head is NIL, both head and tail = new cons; else set-cdr! tail = new. %ldl(t0, head) - %li(t1, %imm_val(%IMM.NIL)) - %bne(t0, t1, &::link) + %bine(t0, %imm_val(%IMM.NIL), &::link, t1) %stl(a0, head) %stl(a0, tail) %b(&::loop) @@ -528,8 +527,7 @@ # Consume the '.', read one datum, splice it in as the cdr of the # tail cons. Then expect a closing ')' (with optional ws). %lda_global(t0, t1, &readbuf_pos) - %addi(t0, t0, 1) - %st(t0, t1, 0) + %readbuf_advance(t0, t1) %call(&parse_one) %ldl(t0, tail) %set_cdr(a0, t0) @@ -537,18 +535,15 @@ %bnez(a0, &::eof) %lda_global(t0, t1, &readbuf_pos) %readbuf_byte(a0, t0) - %addi(a1, a0, -41) - %bnez(a1, &::eof) - %addi(t0, t0, 1) - %st(t0, t1, 0) + %bcne(a0, -41, &::eof, a1) ; ')' + %readbuf_advance(t0, t1) %ldl(a0, head) %eret ::close # Consume ')' and return head. %lda_global(t1, t0, &readbuf_pos) - %addi(t1, t1, 1) - %st(t1, t0, 0) + %readbuf_advance(t1, t0) %ldl(a0, head) %eret @@ -578,7 +573,7 @@ ::loop %if_nil(t1, a0, &::done) %car(t1, a0) - %sari(t1, t1, 3) ; untag fixnum -> raw byte + %untag_fix(t1, t1) %sb(t1, t0, 0) %addi(t0, t0, 1) %cdr(a0, a0) @@ -593,52 +588,32 @@ # Clobbers t0, t1, a1. :is_ident_byte %scope is_ident_byte - %addi(t0, a0, -48) ; '0' - %li(t1, 10) - %bltu(t0, t1, &::ok) ; '0'..'9' - %li(t1, 26) - %addi(t0, a0, -65) ; 'A' - %bltu(t0, t1, &::ok) ; 'A'..'Z' - %addi(t0, a0, -97) ; 'a' - %bltu(t0, t1, &::ok) ; 'a'..'z' - %addi(t0, a0, -33) ; '!' - %beqz(t0, &::ok) - %addi(t0, a0, -36) ; '$' - %beqz(t0, &::ok) - %addi(t0, a0, -37) ; '%' - %beqz(t0, &::ok) - %addi(t0, a0, -38) ; '&' - %beqz(t0, &::ok) - %addi(t0, a0, -42) ; '*' - %beqz(t0, &::ok) - %addi(t0, a0, -43) ; '+' - %beqz(t0, &::ok) - %addi(t0, a0, -45) ; '-' - %beqz(t0, &::ok) - %addi(t0, a0, -46) ; '.' - %beqz(t0, &::ok) - %addi(t0, a0, -47) ; '/' - %beqz(t0, &::ok) - %addi(t0, a0, -58) ; ':' - %beqz(t0, &::ok) - %addi(t0, a0, -60) ; '<' - %beqz(t0, &::ok) - %addi(t0, a0, -61) ; '=' - %beqz(t0, &::ok) - %addi(t0, a0, -62) ; '>' - %beqz(t0, &::ok) - %addi(t0, a0, -63) ; '?' - %beqz(t0, &::ok) - %addi(t0, a0, -64) ; '@' - %beqz(t0, &::ok) - %addi(t0, a0, -94) ; '^' - %beqz(t0, &::ok) - %addi(t0, a0, -95) ; '_' - %beqz(t0, &::ok) - %addi(t0, a0, -126) ; '~' - %beqz(t0, &::ok) + %brange(a0, -48, 10, t0, t1, &::ok) ; '0'..'9' + %brange(a0, -65, 26, t0, t1, &::ok) ; 'A'..'Z' + %brange(a0, -97, 26, t0, t1, &::ok) ; 'a'..'z' + + %bceq(a0, -33, &::ok, t0) ; '!' + %bceq(a0, -36, &::ok, t0) ; '$' + %bceq(a0, -37, &::ok, t0) ; '%' + %bceq(a0, -38, &::ok, t0) ; '&' + %bceq(a0, -42, &::ok, t0) ; '*' + %bceq(a0, -43, &::ok, t0) ; '+' + %bceq(a0, -45, &::ok, t0) ; '-' + %bceq(a0, -46, &::ok, t0) ; '.' + %bceq(a0, -47, &::ok, t0) ; '/' + %bceq(a0, -58, &::ok, t0) ; ':' + %bceq(a0, -60, &::ok, t0) ; '<' + %bceq(a0, -61, &::ok, t0) ; '=' + %bceq(a0, -62, &::ok, t0) ; '>' + %bceq(a0, -63, &::ok, t0) ; '?' + %bceq(a0, -64, &::ok, t0) ; '@' + %bceq(a0, -94, &::ok, t0) ; '^' + %bceq(a0, -95, &::ok, t0) ; '_' + %bceq(a0, -126, &::ok, t0) ; '~' + %li(a1, 0) %ret + ::ok %li(a1, 1) %ret @@ -665,11 +640,8 @@ %readbuf_byte(a0, t1) %is_ws_branch(a1, a0, &::end) - # paren? - %addi(a1, a0, -40) - %beqz(a1, &::end) - %addi(a1, a0, -41) - %beqz(a1, &::end) + %bceq(a0, -40, &::end, a1) ; '(' + %bceq(a0, -41, &::end, a1) ; ')' %addi(t1, t1, 1) %b(&::scan) @@ -690,10 +662,8 @@ %bltu(a1, a2, &::is_int) # '-' or '+' followed by digit -> int. A lone '+' or '-' falls # through to is_sym (those tokens stay valid identifiers). - %addi(a1, t1, -45) - %beqz(a1, &::sign) - %addi(a1, t1, -43) - %beqz(a1, &::sign) + %bceq(t1, -45, &::sign, a1) ; '-' + %bceq(t1, -43, &::sign, a1) ; '+' %b(&::is_sym) ::sign %ldl(t2, end) @@ -733,13 +703,22 @@ %tail(&intern) ::is_int - %ldl(t0, start) ; start_off - %ldl(t1, end) ; end_off + %ldl(t0, start) + %ldl(t1, end) %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) - %beqz(a1, &::int_bad) + %add(a0, a0, t0) + %sub(a1, t1, t0) ; len = end - start + # P1pp's parse_dec handles '-' but not '+'; strip '+' here. + %lb(t2, a0, 0) + %bcne(t2, -43, &::no_plus, t2) ; '+' + %addi(a0, a0, 1) + %addi(a1, a1, -1) + ::no_plus + %stl(a1, cursor) ; save adjusted len (cursor slot is free on int path) + %call(&parse_dec) ; P1pp: -> (raw_val=a0, consumed=a1) + %ldl(t0, cursor) + %bne(a1, t0, &::int_bad) ; partial parse -> bad + %mkfix(a0, a0) %eret ::int_bad %die(msg_bad_number) @@ -767,10 +746,8 @@ ::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) + %bceq(a3, -34, &::scan_done, a1) ; '"' + %bceq(a3, -92, &::scan_esc, a1) ; '\\' %addi(t1, t1, 1) %addi(a0, a0, 1) %b(&::scan) @@ -782,8 +759,7 @@ %addi(t1, t1, 1) %beq(t1, t2, &::eof) %readbuf_byte(a3, t1) - %addi(a1, a3, -120) ; 'x' - %beqz(a1, &::scan_hex) + %bceq(a3, -120, &::scan_hex, a1) ; 'x' %addi(t1, t1, 1) %addi(a0, a0, 1) %b(&::scan) @@ -796,8 +772,7 @@ ::scan_hex_loop %beq(t1, t2, &::eof) %readbuf_byte(a3, t1) - %addi(a1, a3, -59) ; ';' - %beqz(a1, &::scan_hex_done) + %bceq(a3, -59, &::scan_hex_done, a1) ; ';' %addi(t1, t1, 1) %b(&::scan_hex_loop) ::scan_hex_done @@ -811,15 +786,14 @@ %stl(a0, bv) # Pass 2: decode into the freshly allocated data buffer. - %ldl(t1, start) ; start - %ldl(t2, end) ; end + %ldl(t1, start) + %ldl(t2, end) %heap_ld(a3, a0, %BV.data) ::fill %beq(t1, t2, &::fill_done) %readbuf_byte(a1, t1) - %addi(a2, a1, -92) ; '\\' - %beqz(a2, &::fill_esc) + %bceq(a1, -92, &::fill_esc, a2) ; '\\' %sb(a1, a3, 0) %addi(a3, a3, 1) %addi(t1, t1, 1) @@ -828,18 +802,12 @@ ::fill_esc %addi(t1, t1, 1) ; consume backslash %readbuf_byte(a1, t1) - %addi(a2, a1, -110) ; 'n' - %beqz(a2, &::esc_n) - %addi(a2, a1, -116) ; 't' - %beqz(a2, &::esc_t) - %addi(a2, a1, -114) ; 'r' - %beqz(a2, &::esc_r) - %addi(a2, a1, -92) ; '\\' - %beqz(a2, &::write_byte) - %addi(a2, a1, -34) ; '"' - %beqz(a2, &::write_byte) - %addi(a2, a1, -120) ; 'x' - %beqz(a2, &::esc_hex) + %bceq(a1, -110, &::esc_n, a2) ; 'n' + %bceq(a1, -116, &::esc_t, a2) ; 't' + %bceq(a1, -114, &::esc_r, a2) ; 'r' + %bceq(a1, -92, &::write_byte, a2) ; '\\' + %bceq(a1, -34, &::write_byte, a2) ; '"' + %bceq(a1, -120, &::esc_hex, a2) ; 'x' %die(msg_bad_escape) ::esc_n @@ -876,8 +844,7 @@ %ldl(t2, end) %beq(t1, t2, &::hex_bad) %readbuf_byte(t0, t1) - %addi(t0, t0, -59) ; ';' - %bnez(t0, &::hex_bad) + %bcne(t0, -59, &::hex_bad, t0) ; ';' %addi(t1, t1, 1) ; consume ';' %ldl(a3, spill) %sb(a0, a3, 0) @@ -897,6 +864,20 @@ %die(msg_unterm_string) }) +# Emit one named-char arm inside parse_char's multi-byte dispatch. t2 +# must hold the slice pointer; ::bad must be in scope. name_label is a +# full label reference (e.g. &name_ch_tab). +%macro match_named_char(name_label, len, value) + %mov(a0, t2) + %la(a1, name_label) + %li(a2, len) + %call(&memcmp) + %bnez(a0, &::bad) + %li(a0, value) + %mkfix(a0, a0) + %eret +%endm + # parse_char() -> tagged fixnum (the u8 char value) in a0. Cursor sits # past '#\\' (consumed by parse_one's hash dispatch). Always consumes # at least one byte; then continues until ws/paren/EOF. Single-byte @@ -922,10 +903,8 @@ %beq(t1, t2, &::scan_done) %readbuf_byte(a0, t1) %is_ws_branch(a1, a0, &::scan_done) - %addi(a1, a0, -40) ; '(' - %beqz(a1, &::scan_done) - %addi(a1, a0, -41) ; ')' - %beqz(a1, &::scan_done) + %bceq(a0, -40, &::scan_done, a1) ; '(' + %bceq(a0, -41, &::scan_done, a1) ; ')' %addi(t1, t1, 1) %b(&::scan) @@ -937,8 +916,7 @@ %ldl(t1, end) %sub(a2, t1, t0) ; length - %li(a3, 1) - %beq(a2, a3, &::single) + %bieq(a2, 1, &::single, a3) %ld_global(t2, &readbuf_buf_ptr) %add(t2, t2, t0) ; t2 = slice ptr @@ -949,16 +927,11 @@ %beqz(a1, &::hex_form) # Named form: dispatch on length. - %li(a3, 3) - %beq(a2, a3, &::try_tab) - %li(a3, 4) - %beq(a2, a3, &::try_null) - %li(a3, 5) - %beq(a2, a3, &::try_space) - %li(a3, 6) - %beq(a2, a3, &::try_return) - %li(a3, 7) - %beq(a2, a3, &::try_newline) + %bieq(a2, 3, &::try_tab, a3) + %bieq(a2, 4, &::try_null, a3) + %bieq(a2, 5, &::try_space, a3) + %bieq(a2, 6, &::try_return, a3) + %bieq(a2, 7, &::try_newline, a3) %b(&::bad) ::single @@ -976,54 +949,19 @@ %eret ::try_tab - %mov(a0, t2) - %la(a1, &name_ch_tab) - %li(a2, 3) - %call(&memcmp) - %bnez(a0, &::bad) - %li(a0, 9) - %mkfix(a0, a0) - %eret + %match_named_char(&name_ch_tab, 3, 9) ::try_null - %mov(a0, t2) - %la(a1, &name_ch_null) - %li(a2, 4) - %call(&memcmp) - %bnez(a0, &::bad) - %li(a0, 0) - %mkfix(a0, a0) - %eret + %match_named_char(&name_ch_null, 4, 0) ::try_space - %mov(a0, t2) - %la(a1, &name_ch_space) - %li(a2, 5) - %call(&memcmp) - %bnez(a0, &::bad) - %li(a0, 32) - %mkfix(a0, a0) - %eret + %match_named_char(&name_ch_space, 5, 32) ::try_return - %mov(a0, t2) - %la(a1, &name_ch_return) - %li(a2, 6) - %call(&memcmp) - %bnez(a0, &::bad) - %li(a0, 13) - %mkfix(a0, a0) - %eret + %match_named_char(&name_ch_return, 6, 13) ::try_newline - %mov(a0, t2) - %la(a1, &name_ch_newline) - %li(a2, 7) - %call(&memcmp) - %bnez(a0, &::bad) - %li(a0, 10) - %mkfix(a0, a0) - %eret + %match_named_char(&name_ch_newline, 7, 10) ::bad %die(msg_bad_char) @@ -1032,84 +970,10 @@ %die(msg_bad_char) }) -# parse_dec(data_ptr=a0, len=a1) -> (tagged fixnum=a0, ok=a1). Leaf. -# Accepts an optional leading '+' or '-' followed by one or more decimal -# digits. ok=1 on a fully-consumed valid input; ok=0 on empty input, a -# lone sign, or any non-digit byte. On failure a0 still holds the -# best-effort accumulator (sign-applied, retagged) so reader-style -# callers that don't check ok get the same garbage they got before this -# routine validated. UB on integer overflow. Uses only t0..t2. -# -# Register map: -# t0 = current ptr a0 = byte / digit / final value -# t1 = remaining length a1 = ok flag (output) -# t2 = constant 10 a2 = sign flag (1 = negative) -# a3 = accumulator (raw value) -:parse_dec -%scope parse_dec - %mov(t0, a0) - %mov(t1, a1) - %li(a2, 0) - %li(a3, 0) - %beqz(t1, &::fail) - - %lb(a0, t0, 0) - %addi(t2, a0, -45) ; '-' - %beqz(t2, &::neg) - %addi(t2, a0, -43) ; '+' - %bnez(t2, &::loop_init) - %b(&::skip_sign) - ::neg - %li(a2, 1) - ::skip_sign - %addi(t0, t0, 1) - %addi(t1, t1, -1) - %beqz(t1, &::fail) - - ::loop_init - %li(t2, 10) - - ::loop - %beqz(t1, &::done) - %lb(a0, t0, 0) - %addi(a0, a0, -48) - %bltz(a0, &::fail) - %bltu(a0, t2, &::digit_ok) - %b(&::fail) - ::digit_ok - %mul(a3, a3, t2) - %add(a3, a3, a0) - %addi(t0, t0, 1) - %addi(t1, t1, -1) - %b(&::loop) - - ::done - %beqz(a2, &::tag) - %li(t2, 0) - %sub(a3, t2, a3) - ::tag - %mkfix(a0, a3) - %li(a1, 1) - %ret - - ::fail - %beqz(a2, &::fail_tag) - %li(t2, 0) - %sub(a3, t2, a3) - ::fail_tag - %mkfix(a0, a3) - %li(a1, 0) - %ret -%endscope # ========================================================================= # eval / apply # ========================================================================= -# -# eval is the only place that touches tag bits at runtime; the table -# below is a flat compare cascade for now (5 tags). When special-form -# dispatch is wired up the SYM/PAIR paths split further per LISP-C.md -# §Eval. # eval(expr=a0, env=a1) -> value (a0) # @@ -1123,10 +987,8 @@ %stl(a1, env) %tagof(t0, a0) - %li(t1, %TAG.PAIR) - %beq(t0, t1, &::pair) - %li(t1, %TAG.SYM) - %beq(t0, t1, &::sym) + %bieq(t0, %TAG.SYM, &::sym, t1) + %bieq(t0, %TAG.PAIR, &::pair, t1) # FIXNUM, HEAP, IMM all self-evaluate. %eret @@ -1149,14 +1011,15 @@ ::env_miss %untag_sym(a0, a0) %call(&sym_global) - %li(t0, %imm_val(%IMM.UNBOUND)) - %beq(a0, t0, &::unbound) + %bieq(a0, %imm_val(%IMM.UNBOUND), &::unbound, t0) %eret ::unbound %die(msg_unbound) + ::pair + # 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. @@ -1181,31 +1044,25 @@ %dispatch_form(&sym_pmatch, &::do_pmatch) %dispatch_form(&sym_do, &::do_do) - # head = eval(car(expr), env) + # Apply car to cdr + # fn = eval(car(expr), env) %ldl(a0, expr) %car(a0, a0) %ldl(a1, env) %call(&eval) %stl(a0, fn) - # args = eval_args(cdr(expr), env) %ldl(a0, expr) %cdr(a0, a0) %ldl(a1, env) %call(&eval_args) - # apply(fn, args) -- tail call %mov(a1, a0) %ldl(a0, fn) %tail(&apply) ::do_quote - # (quote datum) -> car(cdr(expr)) - %ldl(a0, expr) - %cdr(a0, a0) - %car(a0, a0) - %eret - + %tail_to_handler(&eval_quote) ::do_if %tail_to_handler(&eval_if) ::do_lambda @@ -1261,34 +1118,34 @@ %stl(t0, tail) ::loop - %ldl(t0, args) - %if_nil(t1, t0, &::done) + %ldl(t0, args) + %if_nil(t1, t0, &::done) - # val = eval(car(args), env) - %car(a0, t0) - %ldl(a1, env) - %call(&eval) - - # cell = cons(val, NIL); append to head/tail. - %li(a1, %imm_val(%IMM.NIL)) - %call(&cons) + # val = eval(car(args), env) + %car(a0, t0) + %ldl(a1, env) + %call(&eval) - %ldl(t0, head) - %if_nil(t1, t0, &::first) - %ldl(t0, tail) - %set_cdr(a0, t0) - %stl(a0, tail) - %b(&::advance) + # cell = cons(val, NIL); append to head/tail. + %li(a1, %imm_val(%IMM.NIL)) + %call(&cons) - ::first - %stl(a0, head) - %stl(a0, tail) + %ldl(t0, head) + %if_nil(t1, t0, &::first) + %ldl(t0, tail) + %set_cdr(a0, t0) + %stl(a0, tail) + %b(&::advance) - ::advance - %advance_walk(0) - %b(&::loop) + ::first + %stl(a0, head) + %stl(a0, tail) + ::advance + %advance_walk(args) + %b(&::loop) ::done + %ldl(a0, head) }) @@ -1301,22 +1158,12 @@ %fn2(apply, {args body}, { %stl(a1, args) - # Only HEAP-tagged values can be applicable. - %tagof(t0, a0) - %li(t1, %TAG.HEAP) - %bne(t0, t1, &::not_proc) - %hdr_type(t0, a0) - %li(t1, %HDR.PRIM) - %beq(t0, t1, &::prim) - %li(t1, %HDR.CLOSURE) - %beq(t0, t1, &::closure) - - ::not_proc - %die(msg_not_proc) + %bieq(t0, %HDR.PRIM, &::prim, t1) + %bieq(t0, %HDR.CLOSURE, &::closure, t1) ::prim - # Primitive calling convention (interface, not coincidence): + # Primitive calling convention: # a0 = args list (proper list of evaluated args) # a1 = the PRIM object itself (HEAP-tagged) # Parameterized PRIMs (e.g. the per-field record accessors built @@ -1333,13 +1180,13 @@ ::closure # Closure layout (HEAP-tagged): [hdr][params][body][env] - # field offsets from tagged ptr: params=5, body=13, env=21. - %heap_ld(t1, a0, %CLOSURE.body) ; must survive bind_params - %stl(t1, body) - %heap_ld(t2, a0, %CLOSURE.env) %heap_ld(t0, a0, %CLOSURE.params) + %heap_ld(t1, a0, %CLOSURE.body) + %heap_ld(t2, a0, %CLOSURE.env) + %stl(t1, body) ; persist body past bind_params - %mov(a0, t0) ; bind_params(params, args, env) + # bind_params(params, args, env) + %mov(a0, t0) %ldl(a1, args) %mov(a2, t2) %call(&bind_params) @@ -1348,7 +1195,6 @@ %mov(a1, a0) %ldl(a0, body) %tail(&eval_body) - }) # ========================================================================= @@ -1388,6 +1234,11 @@ %intern_form(&name_dollar, 1, &sym_dollar) }) +# eval_quote(rest=a0, env=a1) -> value (a0). rest is (datum); return datum. +%fn(eval_quote, 0, { + %car(a0, a0) +}) + # eval_if(rest=a0, env=a1) -> value (a0). `rest` is (test then) or # (test then else). Single-arm form returns UNSPEC when test is #f. # No arity check beyond that -- spec policy: malformed special forms @@ -1404,8 +1255,7 @@ %car(a0, a0) %call(&eval) - %li(t0, %imm_val(%IMM.FALSE)) - %beq(a0, t0, &::else_branch) + %bieq(a0, %imm_val(%IMM.FALSE), &::else_branch, t0) # then-branch: tail-eval(cadr(rest), env) %ldl(a0, rest) @@ -1442,7 +1292,7 @@ %stl(a0, rest) %stl(a1, env) - %li(a0, 32) + %li(a0, %CLOSURE.SIZE) %li(a1, %HDR.CLOSURE) %call(&alloc_hdr) %stl(a0, closure) @@ -1484,8 +1334,7 @@ # If car(rest) is a pair, this is the lambda-sugar form. %car(t0, a0) %tagof(t1, t0) - %li(t2, %TAG.PAIR) - %beq(t1, t2, &::sugar) + %bieq(t1, %TAG.PAIR, &::sugar, t2) # Plain define: value = eval(car(cdr(rest)), env) %ldl(t0, rest) @@ -1496,7 +1345,7 @@ %ldl(t0, rest) %car(t0, t0) - %bind_global_from_t0() + %set_global(t0, a0) %li(a0, %imm_val(%IMM.UNSPEC)) %eret @@ -1514,7 +1363,7 @@ %ldl(t0, rest) %car(t0, t0) %car(t0, t0) ; name - %bind_global_from_t0() + %set_global(t0, a0) %li(a0, %imm_val(%IMM.UNSPEC)) }) @@ -1546,29 +1395,29 @@ %ldl(t1, rest) %car(t1, t1) ; target sym - ::lp - %ldl(t2, env) - %if_nil(t0, t2, &::ms) - %car(t0, t2) - %car(t0, t0) ; cell sym - %beq(t0, t1, &::ht) - %cdr(t2, t2) - %stl(t2, env) - %b(&::lp) - - ::ht + ::loop + %ldl(t2, env) + %if_nil(t0, t2, &::miss) + %car(t0, t2) + %car(t0, t0) ; cell sym + %beq(t0, t1, &::hit) + %cdr(t2, t2) + %stl(t2, env) + %b(&::loop) + + ::hit %car(t0, t2) ; re-fetch binding cell %ldl(a0, saved) %set_cdr(a0, t0) ; mutate cell's cdr %li(a0, %imm_val(%IMM.UNSPEC)) %eret - ::ms + ::miss # Miss: rebind global. %ldl(a0, saved) %ldl(t0, rest) %car(t0, t0) - %bind_global_from_t0() + %set_global(t0, a0) %li(a0, %imm_val(%IMM.UNSPEC)) }) @@ -1589,19 +1438,19 @@ ::loop %ldl(t0, clauses) - %if_nil(t1, t0, &::nm) + %if_nil(t1, t0, &::no_match) %car(t1, t0) ; clause %car(t2, t1) ; test_expr %ld_global(a0, &sym_else) - %beq(t2, a0, &::dm) + %beq(t2, a0, &::else_clause) %mov(a0, t2) %ldl(a1, env) %call(&eval) %li(t0, %imm_val(%IMM.FALSE)) - %beq(a0, t0, &::nx) + %beq(a0, t0, &::next) # Truthy. Spill test value and inspect cdr(clause): empty -> UNSPEC, # car == => -> arrow path, else regular body. @@ -1609,16 +1458,16 @@ %ldl(t0, clauses) %car(t0, t0) %cdr(t0, t0) - %if_nil(t1, t0, &::nm) + %if_nil(t1, t0, &::no_match) %car(t1, t0) %ld_global(t2, &sym_arrow) - %beq(t1, t2, &::ar) + %beq(t1, t2, &::arrow) %mov(a0, t0) ; regular body %ldl(a1, env) %tail(&eval_body) - ::ar + ::arrow %cdr(t0, t0) %car(a0, t0) ; proc-expr %ldl(a1, env) @@ -1631,18 +1480,18 @@ %ldl(a0, proc) %tail(&apply) - ::dm + ::else_clause %ldl(t0, clauses) %car(t0, t0) %cdr(a0, t0) %ldl(a1, env) %tail(&eval_body) - ::nx - %advance_walk(0) + ::next + %advance_walk(clauses) %b(&::loop) - ::nm + ::no_match %li(a0, %imm_val(%IMM.UNSPEC)) }) @@ -1665,8 +1514,7 @@ # Named let? %car(t0, a0) %tagof(t1, t0) - %li(t2, %TAG.SYM) - %beq(t1, t2, &::named) + %bieq(t1, %TAG.SYM, &::named, t2) %ldl(t0, rest) %car(t0, t0) ; bindings @@ -1700,7 +1548,7 @@ %call(&cons) %stl(a0, new_env) - %advance_walk(16) + %advance_walk(walk) %b(&::loop) ::done @@ -1735,33 +1583,33 @@ %stl(t0, new_env) ::loop - %ldl(t0, walk) - %if_nil(t1, t0, &::done) - - %car(t1, t0) - %cdr(t2, t1) - %car(t2, t2) + %ldl(t0, walk) + %if_nil(t1, t0, &::done) - # val = eval(init, new_env) - %mov(a0, t2) - %ldl(a1, new_env) - %call(&eval) + %car(t1, t0) + %cdr(t2, t1) + %car(t2, t2) - %ldl(t0, walk) - %car(t1, t0) - %car(t2, t1) - %mov(a1, a0) - %mov(a0, t2) - %call(&cons) + # val = eval(init, new_env) + %mov(a0, t2) + %ldl(a1, new_env) + %call(&eval) - %ldl(a1, new_env) - %call(&cons) - %stl(a0, new_env) + %ldl(t0, walk) + %car(t1, t0) + %car(t2, t1) + %mov(a1, a0) + %mov(a0, t2) + %call(&cons) - %advance_walk(16) - %b(&::loop) + %ldl(a1, new_env) + %call(&cons) + %stl(a0, new_env) + %advance_walk(walk) + %b(&::loop) ::done + %ldl(a0, rest) %cdr(a0, a0) %ldl(a1, new_env) @@ -1790,35 +1638,35 @@ %stl(t0, new_env) ; new_env = env ::loop - %ldl(t0, walk) - %if_nil(t1, t0, &::done) - - %car(t1, t0) ; clause = (formals init) - %cdr(t2, t1) - %car(t2, t2) ; init + %ldl(t0, walk) + %if_nil(t1, t0, &::done) - # val = eval(init, env_orig) - %mov(a0, t2) - %ldl(a1, env) - %call(&eval) + %car(t1, t0) ; clause = (formals init) + %cdr(t2, t1) + %car(t2, t2) ; init - # vals = mv_to_list(val) - %call(&mv_to_list) + # val = eval(init, env_orig) + %mov(a0, t2) + %ldl(a1, env) + %call(&eval) - # new_env = bind_params(formals, vals, new_env) - %ldl(t0, walk) - %car(t1, t0) - %car(t1, t1) ; formals - %mov(a1, a0) - %mov(a0, t1) - %ldl(a2, new_env) - %call(&bind_params) - %stl(a0, new_env) + # vals = mv_to_list(val) + %call(&mv_to_list) - %advance_walk(16) - %b(&::loop) + # new_env = bind_params(formals, vals, new_env) + %ldl(t0, walk) + %car(t1, t0) + %car(t1, t1) ; formals + %mov(a1, a0) + %mov(a0, t1) + %ldl(a2, new_env) + %call(&bind_params) + %stl(a0, new_env) + %advance_walk(walk) + %b(&::loop) ::done + %ldl(a0, rest) %cdr(a0, a0) ; body %ldl(a1, new_env) @@ -1845,33 +1693,33 @@ %stl(t0, new_env) ::loop - %ldl(t0, walk) - %if_nil(t1, t0, &::done) - - %car(t1, t0) - %cdr(t2, t1) - %car(t2, t2) ; init + %ldl(t0, walk) + %if_nil(t1, t0, &::done) - # val = eval(init, new_env) - %mov(a0, t2) - %ldl(a1, new_env) - %call(&eval) + %car(t1, t0) + %cdr(t2, t1) + %car(t2, t2) ; init - %call(&mv_to_list) + # val = eval(init, new_env) + %mov(a0, t2) + %ldl(a1, new_env) + %call(&eval) - %ldl(t0, walk) - %car(t1, t0) - %car(t1, t1) ; formals - %mov(a1, a0) - %mov(a0, t1) - %ldl(a2, new_env) - %call(&bind_params) - %stl(a0, new_env) + %call(&mv_to_list) - %advance_walk(16) - %b(&::loop) + %ldl(t0, walk) + %car(t1, t0) + %car(t1, t1) ; formals + %mov(a1, a0) + %mov(a0, t1) + %ldl(a2, new_env) + %call(&bind_params) + %stl(a0, new_env) + %advance_walk(walk) + %b(&::loop) ::done + %ldl(a0, rest) %cdr(a0, a0) %ldl(a1, new_env) @@ -1891,30 +1739,30 @@ %if_nil(t1, a0, &::done_imm) ::loop - %stl(a0, rest) - %stl(a1, env) + %stl(a0, rest) + %stl(a1, env) - # If cdr(rest) is NIL, the head is the last form -> tail-eval. - %cdr(t0, a0) - %if_nil(t1, t0, &::last) + # If cdr(rest) is NIL, the head is the last form -> tail-eval. + %cdr(t0, a0) + %if_nil(t1, t0, &::last) - # Non-last: eval, short-circuit on #f, otherwise advance. - %car(a0, a0) - %call(&eval) - %li(t0, %imm_val(%IMM.FALSE)) - %beq(a0, t0, &::done) - %ldl(a0, rest) - %cdr(a0, a0) - %ldl(a1, env) - %b(&::loop) - - ::last - %ldl(a0, rest) - %car(a0, a0) - %ldl(a1, env) - %tail(&eval) + # Non-last: eval, short-circuit on #f, otherwise advance. + %car(a0, a0) + %call(&eval) + %li(t0, %imm_val(%IMM.FALSE)) + %beq(a0, t0, &::done) + %ldl(a0, rest) + %cdr(a0, a0) + %ldl(a1, env) + %b(&::loop) + ::last + %ldl(a0, rest) + %car(a0, a0) + %ldl(a1, env) + %tail(&eval) ::done + %eret ::done_imm @@ -1934,28 +1782,27 @@ %if_nil(t1, a0, &::done_imm) ::loop - %stl(a0, rest) - %stl(a1, env) - - %cdr(t0, a0) - %if_nil(t1, t0, &::last) + %stl(a0, rest) + %stl(a1, env) - %car(a0, a0) - %call(&eval) - %li(t0, %imm_val(%IMM.FALSE)) - %bne(a0, t0, &::done) - %ldl(a0, rest) - %cdr(a0, a0) - %ldl(a1, env) - %b(&::loop) + %cdr(t0, a0) + %if_nil(t1, t0, &::last) - ::last - %ldl(a0, rest) - %car(a0, a0) - %ldl(a1, env) - %tail(&eval) + %car(a0, a0) + %call(&eval) + %bine(a0, %imm_val(%IMM.FALSE), &::done, t0) + %ldl(a0, rest) + %cdr(a0, a0) + %ldl(a1, env) + %b(&::loop) + ::last + %ldl(a0, rest) + %car(a0, a0) + %ldl(a1, env) + %tail(&eval) ::done + %eret ::done_imm @@ -1977,8 +1824,7 @@ %car(a0, a0) ; test %call(&eval) - %li(t0, %imm_val(%IMM.FALSE)) - %beq(a0, t0, &::skip) + %bieq(a0, %imm_val(%IMM.FALSE), &::skip, t0) %ldl(a0, rest) %cdr(a0, a0) ; body @@ -2017,46 +1863,46 @@ %stl(a0, subject) ::loop - %ldl(t0, clauses) - %if_nil(t1, t0, &::no_match) - - %car(t1, t0) ; clause - %car(t2, t1) ; head: datum-list or `else` - - %ld_global(a3, &sym_else) - %beq(t2, a3, &::do_else) - - # Walk the datum list, eq?-compare each against subject. - %stl(t2, datums) - %ldl(a0, subject) - ::scan - %ldl(t0, datums) - %if_nil(t1, t0, &::next_clause) - %car(t1, t0) ; datum - %beq(t1, a0, &::do_body) - %cdr(t0, t0) - %stl(t0, datums) - %b(&::scan) - - ::do_body - %ldl(t0, clauses) - %car(t0, t0) - %cdr(a0, t0) ; body - %ldl(a1, env) - %tail(&eval_body) - - ::do_else - %ldl(t0, clauses) - %car(t0, t0) - %cdr(a0, t0) ; body - %ldl(a1, env) - %tail(&eval_body) + %ldl(t0, clauses) + %if_nil(t1, t0, &::no_match) + + %car(t1, t0) ; clause + %car(t2, t1) ; head: datum-list or `else` + + %ld_global(a3, &sym_else) + %beq(t2, a3, &::do_else) + + # Walk the datum list, eq?-compare each against subject. + %stl(t2, datums) + %ldl(a0, subject) + ::scan + %ldl(t0, datums) + %if_nil(t1, t0, &::next_clause) + %car(t1, t0) ; datum + %beq(t1, a0, &::do_body) + %cdr(t0, t0) + %stl(t0, datums) + %b(&::scan) - ::next_clause - %ldl(t0, clauses) - %cdr(t0, t0) - %stl(t0, clauses) - %b(&::loop) + ::do_body + %ldl(t0, clauses) + %car(t0, t0) + %cdr(a0, t0) ; body + %ldl(a1, env) + %tail(&eval_body) + + ::do_else + %ldl(t0, clauses) + %car(t0, t0) + %cdr(a0, t0) ; body + %ldl(a1, env) + %tail(&eval_body) + + ::next_clause + %ldl(t0, clauses) + %cdr(t0, t0) + %stl(t0, clauses) + %b(&::loop) ::no_match %li(a0, %imm_val(%IMM.UNSPEC)) @@ -2094,88 +1940,85 @@ %stl(a0, subject) ::loop - %ldl(t0, clauses) - %if_nil(t1, t0, &::no_match) - - %car(t1, t0) ; clause - %car(t2, t1) ; pat - - %ld_global(a3, &sym_else) - %beq(t2, a3, &::do_else) - - # pmatch_match(pat, subject, env_outer) -> (a0=env_ext, a1=ok) - %mov(a0, t2) - %ldl(a1, subject) - %ldl(a2, env_outer) - %call(&pmatch_match) - %beqz(a1, &::next) - - %stl(a0, env_ext) ; env_ext - - # tail = cdr(clause) - %ldl(t0, clauses) - %car(t0, t0) - %cdr(t0, t0) ; tail = (body...) or ((guard ...) body...) - - # Guard form? tail is a pair, car(tail) is a pair, head of car(tail) - # eq? sym_guard. - %tagof(t1, t0) - %li(t2, %TAG.PAIR) - %bne(t1, t2, &::body_simple) - %car(t1, t0) ; first form of tail - %tagof(t2, t1) - %li(a0, %TAG.PAIR) - %bne(t2, a0, &::body_simple) - %car(a0, t1) ; head of first form - %ld_global(a1, &sym_guard) - %bne(a0, a1, &::body_simple) - - # Guard clause. guards = cdr(car(tail)); body = cdr(tail). - %cdr(a0, t1) - %stl(a0, guard) - %cdr(t0, t0) - %stl(t0, body) - - ::g_loop - %ldl(t0, guard) - %if_nil(t1, t0, &::body_run) - - %car(a0, t0) ; guard expr - %ldl(a1, env_ext) ; env_ext - %call(&eval) - %li(t0, %imm_val(%IMM.FALSE)) - %beq(a0, t0, &::next) - - %ldl(t0, guard) - %cdr(t0, t0) - %stl(t0, guard) - %b(&::g_loop) - - ::body_run - %ldl(a0, body) - %ldl(a1, env_ext) - %tail(&eval_body) - - ::body_simple - # tail itself is the body (no guard wrapper). Tail-call eval_body - # with the extended env; tail position of the matched clause's body - # is preserved. - %mov(a0, t0) - %ldl(a1, env_ext) - %tail(&eval_body) - - ::do_else - %ldl(t0, clauses) - %car(t0, t0) - %cdr(a0, t0) ; body - %ldl(a1, env_outer) ; env_outer (no bindings introduced) - %tail(&eval_body) - - ::next - %ldl(t0, clauses) - %cdr(t0, t0) - %stl(t0, clauses) - %b(&::loop) + %ldl(t0, clauses) + %if_nil(t1, t0, &::no_match) + + %car(t1, t0) ; clause + %car(t2, t1) ; pat + + %ld_global(a3, &sym_else) + %beq(t2, a3, &::do_else) + + # pmatch_match(pat, subject, env_outer) -> (a0=env_ext, a1=ok) + %mov(a0, t2) + %ldl(a1, subject) + %ldl(a2, env_outer) + %call(&pmatch_match) + %beqz(a1, &::next) + + %stl(a0, env_ext) ; env_ext + + # tail = cdr(clause) + %ldl(t0, clauses) + %car(t0, t0) + %cdr(t0, t0) ; tail = (body...) or ((guard ...) body...) + + # Guard form? tail is a pair, car(tail) is a pair, head of car(tail) + # eq? sym_guard. + %tagof(t1, t0) + %bine(t1, %TAG.PAIR, &::body_simple, t2) + %car(t1, t0) ; first form of tail + %tagof(t2, t1) + %bine(t2, %TAG.PAIR, &::body_simple, a0) + %car(a0, t1) ; head of first form + %ld_global(a1, &sym_guard) + %bne(a0, a1, &::body_simple) + + # Guard clause. guards = cdr(car(tail)); body = cdr(tail). + %cdr(a0, t1) + %stl(a0, guard) + %cdr(t0, t0) + %stl(t0, body) + + ::g_loop + %ldl(t0, guard) + %if_nil(t1, t0, &::body_run) + + %car(a0, t0) ; guard expr + %ldl(a1, env_ext) ; env_ext + %call(&eval) + %bieq(a0, %imm_val(%IMM.FALSE), &::next, t0) + + %ldl(t0, guard) + %cdr(t0, t0) + %stl(t0, guard) + %b(&::g_loop) + + ::body_run + %ldl(a0, body) + %ldl(a1, env_ext) + %tail(&eval_body) + + ::body_simple + # tail itself is the body (no guard wrapper). Tail-call eval_body + # with the extended env; tail position of the matched clause's body + # is preserved. + %mov(a0, t0) + %ldl(a1, env_ext) + %tail(&eval_body) + + ::do_else + %ldl(t0, clauses) + %car(t0, t0) + %cdr(a0, t0) ; body + %ldl(a1, env_outer) ; env_outer (no bindings introduced) + %tail(&eval_body) + + ::next + %ldl(t0, clauses) + %cdr(t0, t0) + %stl(t0, clauses) + %b(&::loop) ::no_match %die(msg_pmatch_no_match) @@ -2227,71 +2070,71 @@ %stl(t0, vals_tail) ::init_loop - %ldl(t0, walk) - %if_nil(t1, t0, &::init_done) - - # spec = car(walk); init-expr = car(cdr(spec)). - %car(t1, t0) - %cdr(a0, t1) - %car(a0, a0) ; init expression - - # val = eval(init, env) - %ldl(a1, env) - %call(&eval) - - # binding pair = cons(var, val); var = car(car(walk)). - %ldl(t0, walk) - %car(t1, t0) - %car(t2, t1) ; var - %mov(a1, a0) - %mov(a0, t2) - %call(&cons) ; a0 = binding pair - - # new_env = cons(pair, new_env). cons clobbers t0/t1/t2 so we don't - # spill pair into a t-reg; recover it as car(new_env) afterwards. - %ldl(a1, new_env) - %call(&cons) - %stl(a0, new_env) - - # pcell = cons(pair, NIL). pair = car(new_env), and a0 still holds - # the new_env list pointer from the cons above. - %car(a0, a0) - %li(a1, %imm_val(%IMM.NIL)) - %call(&cons) - - %ldl(t0, pairs_head) - %if_nil(t1, t0, &::pairs_first) - %ldl(t0, pairs_tail) - %set_cdr(a0, t0) - %stl(a0, pairs_tail) - %b(&::vals_alloc) - - ::pairs_first - %stl(a0, pairs_head) - %stl(a0, pairs_tail) - - ::vals_alloc - # vcell = cons(NIL, NIL). Append onto vals list. - %li(a0, %imm_val(%IMM.NIL)) - %li(a1, %imm_val(%IMM.NIL)) - %call(&cons) - - %ldl(t0, vals_head) - %if_nil(t1, t0, &::vals_first) - %ldl(t0, vals_tail) - %set_cdr(a0, t0) - %stl(a0, vals_tail) - %b(&::init_advance) + %ldl(t0, walk) + %if_nil(t1, t0, &::init_done) - ::vals_first - %stl(a0, vals_head) - %stl(a0, vals_tail) + # spec = car(walk); init-expr = car(cdr(spec)). + %car(t1, t0) + %cdr(a0, t1) + %car(a0, a0) ; init expression - ::init_advance - %advance_walk(24) - %b(&::init_loop) + # val = eval(init, env) + %ldl(a1, env) + %call(&eval) + # binding pair = cons(var, val); var = car(car(walk)). + %ldl(t0, walk) + %car(t1, t0) + %car(t2, t1) ; var + %mov(a1, a0) + %mov(a0, t2) + %call(&cons) ; a0 = binding pair + + # new_env = cons(pair, new_env). cons clobbers t0/t1/t2 so we don't + # spill pair into a t-reg; recover it as car(new_env) afterwards. + %ldl(a1, new_env) + %call(&cons) + %stl(a0, new_env) + + # pcell = cons(pair, NIL). pair = car(new_env), and a0 still holds + # the new_env list pointer from the cons above. + %car(a0, a0) + %li(a1, %imm_val(%IMM.NIL)) + %call(&cons) + + %ldl(t0, pairs_head) + %if_nil(t1, t0, &::pairs_first) + %ldl(t0, pairs_tail) + %set_cdr(a0, t0) + %stl(a0, pairs_tail) + %b(&::vals_alloc) + + ::pairs_first + %stl(a0, pairs_head) + %stl(a0, pairs_tail) + + ::vals_alloc + # vcell = cons(NIL, NIL). Append onto vals list. + %li(a0, %imm_val(%IMM.NIL)) + %li(a1, %imm_val(%IMM.NIL)) + %call(&cons) + + %ldl(t0, vals_head) + %if_nil(t1, t0, &::vals_first) + %ldl(t0, vals_tail) + %set_cdr(a0, t0) + %stl(a0, vals_tail) + %b(&::init_advance) + + ::vals_first + %stl(a0, vals_head) + %stl(a0, vals_tail) + + ::init_advance + %advance_walk(walk) + %b(&::init_loop) ::init_done + # body = cddr(rest). %ldl(t0, rest) %cdr(t0, t0) @@ -2307,8 +2150,7 @@ %ldl(a1, new_env) %call(&eval) - %li(t0, %imm_val(%IMM.FALSE)) - %beq(a0, t0, &::commands) + %bieq(a0, %imm_val(%IMM.FALSE), &::commands, t0) # Truthy: results = cdr(car(cdr(rest))). %ldl(t0, rest) @@ -2334,7 +2176,7 @@ %car(a0, t0) %ldl(a1, new_env) %call(&eval) - %advance_walk(24) + %advance_walk(walk) %b(&::cmd_loop) ::step_phase @@ -2373,9 +2215,9 @@ %ldl(t0, val_walk) %set_car(a0, t0) - %advance_walk(24) - %advance_walk(72) - %advance_walk(80) + %advance_walk(walk) + %advance_walk(pair_walk) + %advance_walk(val_walk) %b(&::step_loop) ::update_phase @@ -2392,8 +2234,8 @@ %ldl(t0, val_walk) %car(t2, t0) ; new val %set_cdr(t2, t1) - %advance_walk(72) - %advance_walk(80) + %advance_walk(pair_walk) + %advance_walk(val_walk) %b(&::update_loop) }) @@ -2442,20 +2284,15 @@ %beq(a0, a1, &::ok) # HDR.BV equality. - %li(t1, %TAG.HEAP) - %bne(t0, t1, &::no) + %bine(t0, %TAG.HEAP, &::no, t1) %hdr_type(t1, a0) - %li(t2, %HDR.BV) - %bne(t1, t2, &::no) + %bine(t1, %HDR.BV, &::no, t2) %tagof(t1, a1) - %li(t2, %TAG.HEAP) - %bne(t1, t2, &::no) + %bine(t1, %TAG.HEAP, &::no, t2) %hdr_type(t1, a1) - %li(t2, %HDR.BV) - %bne(t1, t2, &::no) + %bine(t1, %HDR.BV, &::no, t2) %call(&bv_equal_check) - %li(t0, %imm_val(%IMM.TRUE)) - %beq(a0, t0, &::ok) + %bieq(a0, %imm_val(%IMM.TRUE), &::ok, t0) %b(&::no) ::pair_pat @@ -2467,8 +2304,7 @@ # Structural pair. subj must be a pair too. %tagof(t0, a1) - %li(t1, %TAG.PAIR) - %bne(t0, t1, &::no) + %bine(t0, %TAG.PAIR, &::no, t1) # Recurse on the cars; on success, recurse on the cdrs as a tail call. %ldl(t0, pat) @@ -2492,15 +2328,12 @@ %ldl(t0, pat) %cdr(t1, t0) ; cdr(pat) %tagof(t0, t1) - %li(t2, %TAG.PAIR) - %bne(t0, t2, &::bad) + %bine(t0, %TAG.PAIR, &::bad, t2) %cdr(t0, t1) ; cdr(cdr(pat)) - %li(t2, %imm_val(%IMM.NIL)) - %bne(t0, t2, &::bad) + %bine(t0, %imm_val(%IMM.NIL), &::bad, t2) %car(t0, t1) ; pident (kept in t0) %tagof(t2, t0) - %li(a3, %TAG.SYM) - %bne(t2, a3, &::bad) + %bine(t2, %TAG.SYM, &::bad, a3) # Wildcard? Compare against sym_underscore; if so, no binding. %ld_global(t1, &sym_underscore) @@ -2525,12 +2358,10 @@ %ldl(t0, pat) %cdr(t1, t0) ; (pred-sym . clauses) %tagof(t0, t1) - %li(t2, %TAG.PAIR) - %bne(t0, t2, &::no) + %bine(t0, %TAG.PAIR, &::no, t2) %car(t0, t1) ; t0 = pred-sym %tagof(t2, t0) - %li(a3, %TAG.SYM) - %bne(t2, a3, &::no) + %bine(t2, %TAG.SYM, &::no, a3) %cdr(t2, t1) ; t2 = clauses %stl(t2, flw) @@ -2542,11 +2373,9 @@ # Verify HEAP / HDR.PRIM, entry == &prim_predicate_entry; extract TD # from PRIM.data; sanity-check TD is HEAP / HDR.TD. %tagof(t0, a0) - %li(t1, %TAG.HEAP) - %bne(t0, t1, &::no) + %bine(t0, %TAG.HEAP, &::no, t1) %hdr_type(t0, a0) - %li(t1, %HDR.PRIM) - %bne(t0, t1, &::no) + %bine(t0, %HDR.PRIM, &::no, t1) %heap_ld(t1, a0, %PRIM.entry_w) %la(t2, &prim_predicate_entry) %bne(t1, t2, &::no) @@ -2577,13 +2406,11 @@ %if_nil(t1, t0, &::ok) %car(t1, t0) ; t1 = clause %tagof(t0, t1) - %li(t2, %TAG.PAIR) - %bne(t0, t2, &::no) + %bine(t0, %TAG.PAIR, &::no, t2) %car(t2, t1) ; t2 = fname %cdr(t1, t1) ; t1 = (pat_i) %tagof(t0, t1) - %li(a3, %TAG.PAIR) - %bne(t0, a3, &::no) + %bine(t0, %TAG.PAIR, &::no, a3) %car(a3, t1) ; a3 = pat_i %stl(a3, pat) ; reuse `pat` local for pat_i across recursion @@ -2696,7 +2523,7 @@ %stl(a0, tail) ::p1_advance - %advance_walk(32) + %advance_walk(walk) %b(&::p1_loop) ::p1_done @@ -2738,7 +2565,7 @@ %stl(a0, tail) ::p2_advance - %advance_walk(32) + %advance_walk(walk) %b(&::p2_loop) ::p2_done @@ -2775,31 +2602,31 @@ %stl(a2, env) ::loop - %ldl(t0, params) - %tagof(t1, t0) - %li(t2, %TAG.PAIR) - %beq(t1, t2, &::pair) - %li(t2, %TAG.SYM) - %beq(t1, t2, &::rest_bind) - %b(&::done) - - ::pair - # binding = cons(car(params), car(args)) - %ldl(t0, params) - %car(a0, t0) - %ldl(t0, args) - %car(a1, t0) - %call(&cons) - - # env = cons(binding, env) - %ldl(a1, env) - %call(&cons) - %stl(a0, env) + %ldl(t0, params) + %tagof(t1, t0) + %li(t2, %TAG.PAIR) + %beq(t1, t2, &::pair) + %li(t2, %TAG.SYM) + %beq(t1, t2, &::rest_bind) + %b(&::done) - # advance params and args - %advance_walk(0) - %advance_walk(8) - %b(&::loop) + ::pair + # binding = cons(car(params), car(args)) + %ldl(t0, params) + %car(a0, t0) + %ldl(t0, args) + %car(a1, t0) + %call(&cons) + + # env = cons(binding, env) + %ldl(a1, env) + %call(&cons) + %stl(a0, env) + + # advance params and args + %advance_walk(params) + %advance_walk(args) + %b(&::loop) ::rest_bind # binding = cons(params_sym, args_list); env = cons(binding, env) @@ -3070,11 +2897,9 @@ # count (remaining slot count) %fn2(mv_to_list, {ptr count}, { %tagof(t0, a0) - %li(t1, %TAG.HEAP) - %bne(t0, t1, &::single) + %bine(t0, %TAG.HEAP, &::single, t1) %hdr_type(t0, a0) - %li(t1, %HDR.MV) - %bne(t0, t1, &::single) + %bine(t0, %HDR.MV, &::single, t1) # MV-pack: count = (hdr >> 8); header sits at raw+0 = tagged-3. %ld(t0, a0, -3) @@ -3280,6 +3105,17 @@ ::done }) +%fn(register_globals, 0, { + # Bind `eof` as a direct global -> IMM.EOF value. (Predicate is `eof?`, + # registered via prim_table.) Cheaper and shorter than a 0-arg thunk. + %la(a0, &name_eof) + %li(a1, 3) + %call(&intern) + %untag_sym(a0, a0) + %li(a1, %imm_val(%IMM.EOF)) + %call(&sym_set_global) +}) + # Each primitive is a leaf reached via apply's %tailr: args list is in a0, # and the result goes back in a0. Most use no frame at all; the few that # need recursion (apply) carry a small one via %fn. @@ -3445,8 +3281,7 @@ %car(a0, t2) ; (car pair) %ldl(a1, key) %call(&equal_recurse) - %li(t0, %imm_val(%IMM.FALSE)) - %beq(a0, t0, &::next) + %bieq(a0, %imm_val(%IMM.FALSE), &::next, t0) %ldl(a0, pair) %eret @@ -3509,13 +3344,13 @@ %li(t0, 0) %mov(t1, a0) ::sum_loop - %if_nil(t2, t1, &::sum_done) - %car(t2, t1) - %heap_ld(a0, t2, %BV.hdr) - %shri(a0, a0, 8) - %add(t0, t0, a0) - %cdr(t1, t1) - %b(&::sum_loop) + %if_nil(t2, t1, &::sum_done) + %car(t2, t1) + %heap_ld(a0, t2, %BV.hdr) + %shri(a0, a0, 8) + %add(t0, t0, a0) + %cdr(t1, t1) + %b(&::sum_loop) ::sum_done %stl(t0, total) @@ -3527,28 +3362,28 @@ %stl(t0, write) ::copy_loop - %ldl(t0, args) - %if_nil(t1, t0, &::copy_done) - %car(t1, t0) ; src bv - %heap_ld(t2, t1, %BV.hdr) - %shri(t2, t2, 8) ; src length - - %ldl(a0, result) - %heap_ld(a0, a0, %BV.data) ; result.data - %ldl(a3, write) - %add(a0, a0, a3) ; dst = result.data + offset - %heap_ld(a1, t1, %BV.data) ; src.data - %mov(a2, t2) ; count - - %add(a3, a3, t2) - %stl(a3, write) - %cdr(t0, t0) - %stl(t0, args) - - %call(&memcpy) - %b(&::copy_loop) - + %ldl(t0, args) + %if_nil(t1, t0, &::copy_done) + %car(t1, t0) ; src bv + %heap_ld(t2, t1, %BV.hdr) + %shri(t2, t2, 8) ; src length + + %ldl(a0, result) + %heap_ld(a0, a0, %BV.data) ; result.data + %ldl(a3, write) + %add(a0, a0, a3) ; dst = result.data + offset + %heap_ld(a1, t1, %BV.data) ; src.data + %mov(a2, t2) ; count + + %add(a3, a3, t2) + %stl(a3, write) + %cdr(t0, t0) + %stl(t0, args) + + %call(&memcpy) + %b(&::copy_loop) ::copy_done + %ldl(a0, result) }) @@ -3608,8 +3443,7 @@ %call(&str_alloc) %ldl(a1, value) %ldl(t0, radix) - %li(t1, 16) - %beq(t0, t1, &::hex) + %bieq(t0, 16, &::hex, t1) %tail(&str_putint) ::hex %tail(&str_puthex) @@ -3626,11 +3460,9 @@ %car(t2, a0) %tagof(t0, t2) - %li(t1, %TAG.HEAP) - %bne(t0, t1, &::fail) + %bine(t0, %TAG.HEAP, &::fail, t1) %hdr_type(t0, t2) - %li(t1, %HDR.BV) - %bne(t0, t1, &::fail) + %bine(t0, %HDR.BV, &::fail, t1) %heap_ld(t0, t2, %BV.data) %heap_ld(t1, t2, %BV.hdr) @@ -3644,15 +3476,24 @@ %if_nil(t1, t0, &::dec) %car(t1, t0) %sari(t1, t1, 3) - %li(t2, 16) - %beq(t1, t2, &::hex) + %bieq(t1, 16, &::hex, t2) ::dec %ldl(a0, ptr) %ldl(a1, len) - %call(&parse_dec) ; -> (a0=value, a1=ok) - %bnez(a1, &::end) - %b(&::fail) + %beqz(a1, &::fail) + %lb(t0, a0, 0) + %bcne(t0, -43, &::dec_no_plus, t0) ; '+' + %addi(a0, a0, 1) + %addi(a1, a1, -1) + %beqz(a1, &::fail) + ::dec_no_plus + %stl(a1, len) ; save adjusted len + %call(&parse_dec) ; P1pp: -> (raw_val=a0, consumed=a1) + %ldl(t0, len) + %bne(a1, t0, &::fail) ; partial parse -> fail + %mkfix(a0, a0) + %b(&::end) ::hex # Strip optional leading '+' / '-'. @@ -3690,7 +3531,7 @@ %li(t1, 0) %sub(a0, t1, a0) ::hex_pos - %shli(a0, a0, 3) ; mkfix + %mkfix(a0, a0) %b(&::end) ::fail @@ -3797,11 +3638,11 @@ %scope prim_plus %li(t0, 0) ; tagged 0; tag bits stay 0 across %add ::loop - %if_nil(t1, a0, &::done) - %car(t1, a0) - %add(t0, t0, t1) - %cdr(a0, a0) - %b(&::loop) + %if_nil(t1, a0, &::done) + %car(t1, a0) + %add(t0, t0, t1) + %cdr(a0, a0) + %b(&::loop) ::done %mov(a0, t0) %ret @@ -3815,11 +3656,11 @@ %cdr(a0, a0) %if_nil(t1, a0, &::neg) ::loop - %if_nil(t1, a0, &::done) - %car(t1, a0) - %sub(t0, t0, t1) - %cdr(a0, a0) - %b(&::loop) + %if_nil(t1, a0, &::done) + %car(t1, a0) + %sub(t0, t0, t1) + %cdr(a0, a0) + %b(&::loop) ::neg %li(t1, 0) ; unary: 0 - seed %sub(t0, t1, t0) @@ -3834,12 +3675,12 @@ %scope prim_mult %li(t0, 8) ; tagged 1 = mkfix(1) ::loop - %if_nil(t1, a0, &::done) - %car(t1, a0) - %untag_fix(t1, t1) - %mul(t0, t0, t1) - %cdr(a0, a0) - %b(&::loop) + %if_nil(t1, a0, &::done) + %car(t1, a0) + %untag_fix(t1, t1) + %mul(t0, t0, t1) + %cdr(a0, a0) + %b(&::loop) ::done %mov(a0, t0) %ret @@ -3853,12 +3694,12 @@ %car(t0, a0) ; prev = first %cdr(a0, a0) ::loop - %if_nil(t1, a0, &::true) - %car(t1, a0) ; curr - %bne(t0, t1, &::false) - %mov(t0, t1) - %cdr(a0, a0) - %b(&::loop) + %if_nil(t1, a0, &::true) + %car(t1, a0) ; curr + %bne(t0, t1, &::false) + %mov(t0, t1) + %cdr(a0, a0) + %b(&::loop) ::true %li(a0, %imm_val(%IMM.TRUE)) %ret @@ -3872,15 +3713,15 @@ %car(t0, a0) %cdr(a0, a0) ::loop - %if_nil(t1, a0, &::true) - %car(t1, a0) - %blt(t0, t1, &::ok) ; prev < curr -> continue - %li(a0, %imm_val(%IMM.FALSE)) - %ret - ::ok - %mov(t0, t1) - %cdr(a0, a0) - %b(&::loop) + %if_nil(t1, a0, &::true) + %car(t1, a0) + %blt(t0, t1, &::ok) ; prev < curr -> continue + %li(a0, %imm_val(%IMM.FALSE)) + %ret + ::ok + %mov(t0, t1) + %cdr(a0, a0) + %b(&::loop) ::true %li(a0, %imm_val(%IMM.TRUE)) %ret @@ -3891,15 +3732,15 @@ %car(t0, a0) %cdr(a0, a0) ::loop - %if_nil(t1, a0, &::true) - %car(t1, a0) - %blt(t1, t0, &::ok) ; curr < prev <=> prev > curr -> continue - %li(a0, %imm_val(%IMM.FALSE)) - %ret - ::ok - %mov(t0, t1) - %cdr(a0, a0) - %b(&::loop) + %if_nil(t1, a0, &::true) + %car(t1, a0) + %blt(t1, t0, &::ok) ; curr < prev <=> prev > curr -> continue + %li(a0, %imm_val(%IMM.FALSE)) + %ret + ::ok + %mov(t0, t1) + %cdr(a0, a0) + %b(&::loop) ::true %li(a0, %imm_val(%IMM.TRUE)) %ret @@ -3928,11 +3769,11 @@ %scope prim_bit_and %li(t0, -8) ; tagged -1; AND-identity preserves the tag ::loop - %if_nil(t1, a0, &::done) - %car(t1, a0) - %and(t0, t0, t1) - %cdr(a0, a0) - %b(&::loop) + %if_nil(t1, a0, &::done) + %car(t1, a0) + %and(t0, t0, t1) + %cdr(a0, a0) + %b(&::loop) ::done %mov(a0, t0) %ret @@ -3942,11 +3783,11 @@ %scope prim_bit_or %li(t0, 0) ::loop - %if_nil(t1, a0, &::done) - %car(t1, a0) - %or(t0, t0, t1) - %cdr(a0, a0) - %b(&::loop) + %if_nil(t1, a0, &::done) + %car(t1, a0) + %or(t0, t0, t1) + %cdr(a0, a0) + %b(&::loop) ::done %mov(a0, t0) %ret @@ -3956,11 +3797,11 @@ %scope prim_bit_xor %li(t0, 0) ::loop - %if_nil(t1, a0, &::done) - %car(t1, a0) - %xor(t0, t0, t1) - %cdr(a0, a0) - %b(&::loop) + %if_nil(t1, a0, &::done) + %car(t1, a0) + %xor(t0, t0, t1) + %cdr(a0, a0) + %b(&::loop) ::done %mov(a0, t0) %ret @@ -4171,13 +4012,13 @@ %li(a1, 0) ::fill_loop - %beq(a1, t0, &::fill_done) - %sb(t1, t2, 0) - %addi(t2, t2, 1) - %addi(a1, a1, 1) - %b(&::fill_loop) - + %beq(a1, t0, &::fill_done) + %sb(t1, t2, 0) + %addi(t2, t2, 1) + %addi(a1, a1, 1) + %b(&::fill_loop) ::fill_done + %ldl(a0, wrapper) %eret @@ -4363,12 +4204,12 @@ %sub(a3, a3, a2) ; count ::loop - %beqz(a3, &::done) - %lb(t1, a1, 0) - %sb(t1, t0, 0) - %addi(t0, t0, 1) - %addi(a1, a1, 1) - %addi(a3, a3, -1) + %beqz(a3, &::done) + %lb(t1, a1, 0) + %sb(t1, t0, 0) + %addi(t0, t0, 1) + %addi(a1, a1, 1) + %addi(a3, a3, -1) %b(&::loop) ::done @@ -4396,13 +4237,13 @@ %heap_ld(a3, a1, %BV.data) ::loop - %beqz(t0, &::true) - %lb(t1, a2, 0) - %lb(t2, a3, 0) - %bne(t1, t2, &::false) - %addi(a2, a2, 1) - %addi(a3, a3, 1) - %addi(t0, t0, -1) + %beqz(t0, &::true) + %lb(t1, a2, 0) + %lb(t2, a3, 0) + %bne(t1, t2, &::false) + %addi(a2, a2, 1) + %addi(a3, a3, 1) + %addi(t0, t0, -1) %b(&::loop) ::true @@ -4458,10 +4299,8 @@ %tagof(t1, a1) %bne(t0, t1, &::false) - %li(t1, %TAG.PAIR) - %beq(t0, t1, &::pair) - %li(t1, %TAG.HEAP) - %beq(t0, t1, &::heap) + %bieq(t0, %TAG.PAIR, &::pair, t1) + %bieq(t0, %TAG.HEAP, &::heap, t1) %b(&::false) ::pair @@ -4470,8 +4309,7 @@ %car(a0, t0) %car(a1, t1) %call(&equal_recurse) - %li(t0, %imm_val(%IMM.FALSE)) - %beq(a0, t0, &::done) + %bieq(a0, %imm_val(%IMM.FALSE), &::done, t0) %ldl(t0, a) %ldl(t1, b) %cdr(a0, t0) @@ -4547,8 +4385,7 @@ %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) + %bieq(a0, %imm_val(%IMM.FALSE), &::done, t0) %ldl(t0, i) %addi(t0, t0, 1) @@ -4614,29 +4451,29 @@ %stl(t0, tail) ::loop - %ldl(t0, walk) - %cdr(t1, t0) - %if_nil(t2, t1, &::last) + %ldl(t0, walk) + %cdr(t1, t0) + %if_nil(t2, t1, &::last) - # cell = cons(car(walk), NIL); append to head/tail. - %car(a0, t0) - %li(a1, %imm_val(%IMM.NIL)) - %call(&cons) + # cell = cons(car(walk), NIL); append to head/tail. + %car(a0, t0) + %li(a1, %imm_val(%IMM.NIL)) + %call(&cons) - %ldl(t0, head) - %if_nil(t1, t0, &::first) - %ldl(t0, tail) - %set_cdr(a0, t0) - %stl(a0, tail) - %b(&::advance) + %ldl(t0, head) + %if_nil(t1, t0, &::first) + %ldl(t0, tail) + %set_cdr(a0, t0) + %stl(a0, tail) + %b(&::advance) - ::first - %stl(a0, head) - %stl(a0, tail) + ::first + %stl(a0, head) + %stl(a0, tail) - ::advance - %advance_walk(0) - %b(&::loop) + ::advance + %advance_walk(walk) + %b(&::loop) ::last # car(walk) is the trailing list. If head is NIL there were no leading @@ -4710,14 +4547,14 @@ %addi(t1, a0, 13) ::fill_loop - %if_nil(t2, t0, &::fill_done) - %car(t2, t0) - %st(t2, t1, 0) - %addi(t1, t1, 8) - %cdr(t0, t0) - %b(&::fill_loop) - + %if_nil(t2, t0, &::fill_done) + %car(t2, t0) + %st(t2, t1, 0) + %addi(t1, t1, 8) + %cdr(t0, t0) + %b(&::fill_loop) ::fill_done + %ldl(a0, record) }) @@ -4728,11 +4565,9 @@ %heap_ld(t1, a1, %PRIM.data) %tagof(t2, t0) %li(a0, %imm_val(%IMM.FALSE)) - %li(a2, %TAG.HEAP) - %bne(t2, a2, &::end) + %bine(t2, %TAG.HEAP, &::end, a2) %hdr_type(t2, t0) - %li(a2, %HDR.REC) - %bne(t2, a2, &::end) + %bine(t2, %HDR.REC, &::end, a2) %heap_ld(t2, t0, %REC.td) %bne(t2, t1, &::end) %li(a0, %imm_val(%IMM.TRUE)) @@ -4831,8 +4666,7 @@ # Splice into list: if head is NIL, head = tail = cell. # Else set-cdr!(tail, cell); tail = cell. %ldl(t1, fl_head) - %li(t2, %imm_val(%IMM.NIL)) - %bne(t1, t2, &::fl_append) + %bine(t1, %imm_val(%IMM.NIL), &::fl_append, t2) %stl(a0, fl_head) %stl(a0, fl_tail) %b(&::fl_next) @@ -4859,7 +4693,7 @@ %cdr(t0, t0) %car(t0, t0) %car(t0, t0) - %bind_global_from_t0() + %set_global(t0, a0) # pred-prim = make_param_prim(prim_predicate_entry, td); bind pred. %la(a0, &prim_predicate_entry) @@ -4869,7 +4703,7 @@ %cdr(t0, t0) %cdr(t0, t0) %car(t0, t0) - %bind_global_from_t0() + %set_global(t0, a0) # Iterate clauses: bind accessor + optional mutator per clause. %li(t0, 0) @@ -4881,7 +4715,7 @@ # accessor-prim with data = tagged idx; bind cadr(clause). %ldl(a1, idx) - %shli(a1, a1, 3) + %mkfix(a1, a1) %la(a0, &prim_accessor_entry) %call(&make_param_prim) @@ -4889,7 +4723,7 @@ %car(t0, t0) %cdr(t0, t0) %car(t0, t0) - %bind_global_from_t0() + %set_global(t0, a0) # Mutator? If cddr(clause) is a pair, bind it. %ldl(t0, walk) @@ -4899,7 +4733,7 @@ %if_nil(t1, t0, &::no_mutator) %ldl(a1, idx) - %shli(a1, a1, 3) + %mkfix(a1, a1) %la(a0, &prim_mutator_entry) %call(&make_param_prim) @@ -4908,10 +4742,10 @@ %cdr(t0, t0) %cdr(t0, t0) %car(t0, t0) - %bind_global_from_t0() + %set_global(t0, a0) ::no_mutator - %advance_walk(24) + %advance_walk(walk) %ldl(t0, idx) %addi(t0, t0, 1) %stl(t0, idx) @@ -5175,14 +5009,10 @@ %stl(a2, mode) %tagof(t0, a0) - %li(t1, %TAG.PAIR) - %beq(t0, t1, &::pair) - %li(t1, %TAG.SYM) - %beq(t0, t1, &::sym) - %li(t1, %TAG.HEAP) - %beq(t0, t1, &::heap) - %li(t1, %TAG.IMM) - %beq(t0, t1, &::imm) + %bieq(t0, %TAG.PAIR, &::pair, t1) + %bieq(t0, %TAG.SYM, &::sym, t1) + %bieq(t0, %TAG.HEAP, &::heap, t1) + %bieq(t0, %TAG.IMM, &::imm, t1) # Fall-through: FIXNUM (the only remaining tag). %ldl(a0, bv) @@ -5207,16 +5037,11 @@ ::heap %hdr_type(t0, a0) - %li(t1, %HDR.BV) - %beq(t0, t1, &::heap_bv) - %li(t1, %HDR.CLOSURE) - %beq(t0, t1, &::heap_closure) - %li(t1, %HDR.PRIM) - %beq(t0, t1, &::heap_prim) - %li(t1, %HDR.TD) - %beq(t0, t1, &::heap_td) - %li(t1, %HDR.REC) - %beq(t0, t1, &::heap_rec) + %bieq(t0, %HDR.BV, &::heap_bv, t1) + %bieq(t0, %HDR.CLOSURE, &::heap_closure, t1) + %bieq(t0, %HDR.PRIM, &::heap_prim, t1) + %bieq(t0, %HDR.TD, &::heap_td, t1) + %bieq(t0, %HDR.REC, &::heap_rec, t1) %b(&::heap_unknown) ::heap_bv @@ -5668,7 +5493,7 @@ %fn2(wrap_syscall_result, {raw pad}, { %stl(a0, raw) %bltz(a0, &::err) - %shli(a1, a0, 3) + %mkfix(a1, a0) %li(a0, %imm_val(%IMM.TRUE)) %tail(&cons) @@ -5676,7 +5501,7 @@ %ldl(t0, raw) %li(t1, 0) %sub(t0, t1, t0) - %shli(a1, t0, 3) + %mkfix(a1, t0) %li(a0, %imm_val(%IMM.FALSE)) %tail(&cons) }) @@ -6262,6 +6087,44 @@ %tail(&apply) }) +# ========================================================================= +# Startup -- heap_init +# ========================================================================= + +# heap_init() -> none. Initializes the main heap (heap_next / +# heap_end), the scratch heap (scratch_next / scratch_end), and points +# current_heap_*_ptr at the main slots so cons / alloc_hdr / +# alloc_bytes default to allocating in main. Both _next slots are +# rounded up to 8-byte alignment so every PAIR/HEAP tag bit is exact; +# &ELF_end's alignment depends on the data section above it. cons / +# alloc_hdr / alloc_bytes test (*current_next + bytes <= *current_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) + + %ld_global(t0, &scratch_buf_ptr) + %alignup(t0, t0, 8, t1) + %st_global(t0, &scratch_next, t1) + + %ld_global(t0, &scratch_buf_ptr) + %li(t1, %SCRATCH_CAP_BYTES) + %add(t0, t0, t1) + %st_global(t0, &scratch_end, t1) + + %la(t0, &heap_next) + %st_global(t0, &current_heap_next_ptr, t1) + %la(t0, &heap_end) + %st_global(t0, &current_heap_end_ptr, t1) + + %ret + # Sentinel: marks the boundary between executable text and rodata. # Read by scripts/disasm-elf.sh (via scripts/m1-symbols.py) to bound # disassembly so trailing strings don't decode as bogus instructions. @@ -6517,44 +6380,6 @@ :name_ch_newline "newline" ;; 7+1+0=8 # ========================================================================= -# Startup -- heap_init -# ========================================================================= - -# heap_init() -> none. Initializes the main heap (heap_next / -# heap_end), the scratch heap (scratch_next / scratch_end), and points -# current_heap_*_ptr at the main slots so cons / alloc_hdr / -# alloc_bytes default to allocating in main. Both _next slots are -# rounded up to 8-byte alignment so every PAIR/HEAP tag bit is exact; -# &ELF_end's alignment depends on the data section above it. cons / -# alloc_hdr / alloc_bytes test (*current_next + bytes <= *current_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) - - %ld_global(t0, &scratch_buf_ptr) - %alignup(t0, t0, 8, t1) - %st_global(t0, &scratch_next, t1) - - %ld_global(t0, &scratch_buf_ptr) - %li(t1, %SCRATCH_CAP_BYTES) - %add(t0, t0, t1) - %st_global(t0, &scratch_end, t1) - - %la(t0, &heap_next) - %st_global(t0, &current_heap_next_ptr, t1) - %la(t0, &heap_end) - %st_global(t0, &current_heap_end_ptr, t1) - - %ret - -# ========================================================================= # BSS arena table # ========================================================================= #