diff --git a/stage1/eval.s b/stage1/eval.s index b380d6c..431c970 100644 --- a/stage1/eval.s +++ b/stage1/eval.s @@ -18,84 +18,68 @@ # a1 = return value / error details object .global eval eval: - addi sp, sp, -0x20 + addi sp, sp, -0x18 sd ra, 0x00(sp) - sd s1, 0x08(sp) # s1 = expression to evaluate - sd s2, 0x10(sp) # s2 = local words list - sd s3, 0x18(sp) # cons tail (procedure arglist) - mv s1, a0 - mv s2, a1 + sd a0, 0x08(sp) # a0 = expression to evaluate + sd a1, 0x10(sp) # a1 = local words list # check type of expression - beqz s1, .Leval_literal # return literal nil - lwu t1, LISP_OBJECT_TYPE(s1) + beqz a0, .Leval_literal # return literal nil + lwu t1, LISP_OBJECT_TYPE(a0) li t2, LISP_OBJECT_TYPE_SYMBOL beq t1, t2, .Leval_symbol # eval symbol just looks it up li t2, LISP_OBJECT_TYPE_CONS bne t1, t2, .Leval_literal # anything other than a cons or sym is just returned literally - # destructure the cons to (s1 . s3) - call uncons - mv s1, a1 - mv s3, a2 - # if it's a cons, we evaluate head first, it should be a procedure - mv a0, s1 - mv a1, s2 + # evaluate the head from the cons, it should be a procedure + addi a0, sp, 0x08 call acquire_locals - call eval - mv s1, zero # used the head, so set to nil + call eval_head bnez a0, .Leval_ret # error # call the (assumed) procedure with the tail of the cons as argument list mv a0, a1 - mv a1, s3 - mv a2, s2 - # tail call: call_procedure + ld a1, 0x08(sp) # args + ld a2, 0x10(sp) # locals + # restore stack and tail call ld ra, 0x00(sp) - ld s1, 0x08(sp) - ld s2, 0x10(sp) - ld s3, 0x18(sp) - addi sp, sp, 0x20 + addi sp, sp, 0x18 j call_procedure .Leval_symbol: - # if it's a symbol we just look it up - mv a0, s1 call acquire_object # keep symbol, in case error - mv a1, s2 + # look the symbol up in locals + ld a1, 0x10(sp) + sd zero, 0x10(sp) # used call lookup_var - mv s2, zero # used beqz a0, .Leval_error_undefined - # release the symbol - mv s2, a1 # save found value - mv a0, s1 - call release_object - mv a0, zero # success - mv a1, s2 # found value - mv s1, zero # used - mv s2, zero # used - j .Leval_ret -.Leval_error_undefined: - li a0, EVAL_ERROR_UNDEFINED - mv a1, s1 # saved symbol as error details - mv s1, zero # used - j .Leval_ret -.Leval_literal: - mv a0, zero - mv a1, s1 - mv s1, zero # used + # return + li a0, 0 # success + # a1 = found value .Leval_ret: - # release s1 and s2 if they're still set, since they aren't part of the return value + # release the two values on the stack if they're still set, + # since they aren't part of the return value addi sp, sp, -0x10 sd a0, 0x00(sp) sd a1, 0x08(sp) - mv a0, s1 + ld a0, 0x18(sp) call release_object - mv a0, s2 + ld a0, 0x20(sp) call release_object ld a0, 0x00(sp) ld a1, 0x08(sp) ld ra, 0x10(sp) - ld s1, 0x18(sp) - ld s2, 0x20(sp) - ld s3, 0x28(sp) - addi sp, sp, 0x30 + addi sp, sp, 0x28 + ret +.Leval_error_undefined: + li a0, EVAL_ERROR_UNDEFINED + ld a1, 0x08(sp) # saved symbol as error details + sd zero, 0x08(sp) # used + j .Leval_ret +.Leval_literal: + # do quick return, just release locals + ld a0, 0x10(sp) + call release_object + ld ra, 0x00(sp) + mv a0, zero # ok + ld a1, 0x08(sp) + addi sp, sp, 0x18 ret # Call before eval to increment refcount on locals (a1) @@ -168,67 +152,60 @@ call_procedure: # Takes the first element of a list and evaluates it # -# a0 = pointer to structure. pass (list, _), will be written with (head, tail) +# a0 = pointer to pointer to tail - will be overwritten with next tail # a1 = local words # # Return: # # a0 = eval error -# a1 = eval error data if error +# a1 = evaluated head or eval error # -# The pointer will contain (nil, nil) on failure, no further release is necessary +# On error, nil will be written to the tail pointer and the remainder will be released. .global eval_head eval_head: - addi sp, sp, -0x28 + addi sp, sp, -0x18 sd ra, 0x00(sp) - sd s1, 0x08(sp) # s1 = a0, pointer to structure + sd a0, 0x08(sp) # pointer to pointer to tail sd a1, 0x10(sp) # locals - mv s1, a0 # uncons the list - ld t0, 0x00(a0) - sd zero, 0x00(a0) # taken - sd zero, 0x08(a0) # clear in case of error + ld t0, (a0) + sd zero, (a0) # taken mv a0, t0 call uncons beqz a0, .Leval_head_exc # not a cons # store the tail - sd a2, 0x08(s1) + ld t0, 0x08(sp) + sd a2, (t0) # eval head x locals mv a0, a1 ld a1, 0x10(sp) sd zero, 0x10(sp) # used call eval - bnez a0, .Leval_head_err # err - # store evaluated head - sd a1, 0x00(s1) - # set result to ok - sd zero, 0x18(sp) - sd zero, 0x20(sp) .Leval_head_ret: + addi sp, sp, -0x10 + # store result + sd a0, 0x00(sp) + sd a1, 0x08(sp) # release locals if not used - ld a0, 0x10(sp) + ld a0, 0x20(sp) + call release_object + # release tail if error + ld t0, 0x00(sp) + beqz t0, 1f + ld a0, 0x18(sp) + ld a0, (a0) call release_object - # restore and return - ld ra, 0x00(sp) - ld s1, 0x08(sp) ld a0, 0x18(sp) - ld a1, 0x20(sp) + sd zero, (a0) +1: + # restore and return + ld a0, 0x00(sp) + ld a1, 0x08(sp) + ld ra, 0x10(sp) addi sp, sp, 0x28 ret .Leval_head_exc: # set exception - li t0, EVAL_ERROR_EXCEPTION - sd t0, 0x18(sp) - sd zero, 0x20(sp) - j .Leval_head_err_ret -.Leval_head_err: - # store result from eval - sd a0, 0x18(sp) - sd a1, 0x20(sp) -.Leval_head_err_ret: - # release tail if it was set - ld a0, 0x08(s1) - call release_object - sd zero, 0x08(s1) # clear it because we released it - # return + li a0, EVAL_ERROR_EXCEPTION + mv a1, zero j .Leval_head_ret diff --git a/stage1/init.s b/stage1/init.s index be86b6c..8747de5 100644 --- a/stage1/init.s +++ b/stage1/init.s @@ -50,12 +50,14 @@ start: li a1, LINE_BUF_LENGTH call get_line beqz a0, .Lstart_end - mv a1, a0 - la a0, LINE_BUF + mv s4, a0 + la s3, LINE_BUF .Lstart_token_loop: # line buffer empty, end loop - beqz a1, .Lstart_parse_done + beqz s4, .Lstart_parse_done # loop through tokens and print them + mv a0, s3 + mv a1, s4 call get_token # make sure token is valid beqz a0, .Lstart_token_error @@ -67,7 +69,7 @@ start: la a0, PARSER_ARRAY call parse_token bgtz a0, .Lstart_eval # value produced - beqz a0, .Lstart_token_loop_next # ok but nothing produced + beqz a0, .Lstart_token_loop # ok but nothing produced # some kind of error li t0, PARSER_STATUS_OVERFLOW beq a0, t0, .Lstart_token_overflow @@ -147,11 +149,6 @@ start: call putc li a0, '\n' call putc -.Lstart_token_loop_next: - # restore the remaining line buffer to a0-a1 and loop - mv a0, s3 - mv a1, s4 - j .Lstart_token_loop .Lstart_parse_done: j .Lstart_repl .Lstart_token_overflow: diff --git a/stage1/proc_builtin.s b/stage1/proc_builtin.s index 4557f4c..94b7600 100644 --- a/stage1/proc_builtin.s +++ b/stage1/proc_builtin.s @@ -450,18 +450,18 @@ proc_cdr: .global proc_cons proc_cons: # reserve stack, preserve return addr - addi sp, sp, -0x28 + addi sp, sp, -0x20 sd ra, 0x00(sp) sd a1, 0x08(sp) # locals - sd a0, 0x10(sp) # cons head - sd zero, 0x18(sp) # cons tail - sd zero, 0x20(sp) # unused args + sd zero, 0x10(sp) # cons head + sd a0, 0x18(sp) # remaining args # evaluate first two args # arg 0 (head) - addi a0, sp, 0x10 + addi a0, sp, 0x18 call acquire_locals call eval_head bnez a0, .Lproc_cons_ret + sd a1, 0x10(sp) # arg 1 (tail) addi a0, sp, 0x18 ld a1, 0x08(sp) # locals @@ -470,9 +470,8 @@ proc_cons: bnez a0, .Lproc_cons_ret # cons head, tail ld a0, 0x10(sp) - ld a1, 0x18(sp) + # a1 = tail, from eval sd zero, 0x10(sp) # used - sd zero, 0x18(sp) # used call cons beqz a0, .Lproc_cons_no_mem mv a1, a0 # result @@ -482,20 +481,18 @@ proc_cons: addi sp, sp, -0x10 sd a0, 0x00(sp) sd a1, 0x08(sp) - # release from 0x18 .. 0x38 (sp) + # release from 0x18 .. 0x30 (sp) ld a0, 0x18(sp) call release_object ld a0, 0x20(sp) call release_object ld a0, 0x28(sp) call release_object - ld a0, 0x30(sp) - call release_object # load stashed data and return ld a0, 0x00(sp) ld a1, 0x08(sp) ld ra, 0x10(sp) - addi sp, sp, 0x38 + addi sp, sp, 0x30 ret .Lproc_cons_no_mem: li a0, EVAL_ERROR_NO_FREE_MEM @@ -631,20 +628,22 @@ proc_eval: addi sp, sp, -0x28 sd ra, 0x00(sp) sd a1, 0x08(sp) # locals (in) - sd a0, 0x10(sp) # arg 0 = provided locals + sd zero, 0x10(sp) # arg 0 = provided locals sd zero, 0x18(sp) # arg 1 = expression - sd zero, 0x20(sp) # unused args + sd a0, 0x20(sp) # remaining args # arg 0 - addi a0, sp, 0x10 + addi a0, sp, 0x20 call acquire_locals call eval_head bnez a0, .Lproc_eval_error + sd a1, 0x10(sp) # arg 1 - addi a0, sp, 0x18 + addi a0, sp, 0x20 ld a1, 0x08(sp) # locals sd zero, 0x08(sp) # used call eval_head bnez a0, .Lproc_eval_error + sd a1, 0x18(sp) # release rest of args ld a0, 0x20(sp) call release_object diff --git a/stage2/16-optimize-prims.lsp b/stage2/16-optimize-prims.lsp index 029fb55..98bcaab 100644 --- a/stage2/16-optimize-prims.lsp +++ b/stage2/16-optimize-prims.lsp @@ -31,13 +31,12 @@ (define eval-list (box-procedure (car (link (start ; stash locals, set up variables - (\addi $sp $sp -0x30) + (\addi $sp $sp -0x28) (\sd $ra $sp 0x00) (\sd $s1 $sp 0x08) (\sd $s2 $sp 0x10) (\sd $a1 $sp 0x18) ; locals - (\sd $a0 $sp 0x20) ; args / head - (\sd $zero $sp 0x28) ; tail + (\sd $a0 $sp 0x20) ; remaining args (\li $s1 0) ; return value (dest) (\li $s2 0) ; current node of dest to append to ) @@ -53,22 +52,23 @@ (\callr $ra (rel+ eval-head$)) (\bnez $a0 (rel ret)) ; swap provided locals into position - (\ld $t0 $sp 0x20) ; new locals + (\mv $t0 $a1) ; new locals (\ld $a1 $sp 0x18) ; old locals (use one more time) (\sd $t0 $sp 0x18) ; save new as locals - ; shuffle arg list back - (\ld $t0 $sp 0x28) - (\sd $t0 $sp 0x20) - (\sd $zero $sp 0x28) ; arg 1 - list to evaluate (\addi $a0 $sp 0x20) (\auipc $ra (rel eval-head$)) (\callr $ra (rel+ eval-head$)) (\bnez $a0 (rel ret)) + ; temporarily stash arg list in s1 + (\mv $s1 $a1) ; release rest of args - (\ld $a0 $sp 0x28) + (\ld $a0 $sp 0x20) (\auipc $ra (rel release-object$)) (\callr $ra (rel+ release-object$)) + ; store new args + (\sd $s1 $sp 0x20) + (\li $s1 0) ) (loop ; check if next is nil @@ -79,19 +79,15 @@ (\auipc $ra (rel acquire-object$)) (\callr $ra (rel+ acquire-object$)) (\mv $a1 $a0) - ; set address of head/tail + ; set address of args (\addi $a0 $sp 0x20) ; call eval-head$ (\auipc $ra (rel eval-head$)) (\callr $ra (rel+ eval-head$)) ; handle error (\bnez $a0 (rel ret)) - ; move tail back to args position - (\ld $a0 $sp 0x20) - (\ld $t0 $sp 0x28) - (\sd $t0 $sp 0x20) - (\sd $zero $sp 0x28) ; make cons with nil + (\mv $a0 $a1) (\li $a1 0) (\auipc $ra (rel cons$)) (\callr $ra (rel+ cons$)) @@ -125,7 +121,7 @@ (\ld $a0 $sp 0x28) (\auipc $ra (rel release-object$)) (\callr $ra (rel+ release-object$)) - ; free args/head (never need to free tail) + ; free args (\ld $a0 $sp 0x30) (\auipc $ra (rel release-object$)) (\callr $ra (rel+ release-object$)) @@ -139,7 +135,7 @@ (\ld $ra $sp 0x10) (\ld $s1 $sp 0x18) (\ld $s2 $sp 0x20) - (\addi $sp $sp 0x40) + (\addi $sp $sp 0x38) (\ret) ) (nomem @@ -154,20 +150,20 @@ ; unbox first arg into s1 ; args list on stack for eval-head (start - (\addi $sp $sp -0x48) + (\addi $sp $sp -0x40) (\sd $ra $sp 0x00) (\sd $s1 $sp 0x08) (\sd $a1 $sp 0x10) ; locals + (\sd $s2 $sp 0x18) (\sd $a0 $sp 0x20) ; args - (\sd $zero $sp 0x28) - (\sd $zero $sp 0x30) ; first flag + (\sd $zero $sp 0x28) ; first flag ; load address from data (\mv $a0 $a2) (\auipc $ra (rel unbox-integer$)) (\callr $ra (rel+ unbox-integer$)) (\beqz $a0 (rel exc)) (\beqz $a1 (rel exc)) - (\sd $a1 $sp 0x18) ; routine + (\mv $s2 $a1) ; routine ) (loop ; eval arg @@ -179,20 +175,16 @@ (\auipc $ra (rel eval-head$)) (\callr $ra (rel+ eval-head$)) (\bnez $a0 (rel ret)) ; err - ; shuffle and unbox - (\ld $a0 $sp 0x20) - (\ld $t0 $sp 0x28) - (\sd $t0 $sp 0x20) - (\sd $zero $sp 0x28) + ; unbox + (\mv $a0 $a1) (\auipc $ra (rel unbox-integer$)) (\callr $ra (rel+ unbox-integer$)) ; check if first - (\ld $t0 $sp 0x30) + (\ld $t0 $sp 0x28) (\beqz $t0 (rel first)) ; call routine with a0, a1 - (\ld $ra $sp 0x18) (\mv $a0 $s1) - (\callr $ra 0) + (\callr $s2 0) (\mv $s1 $a0) ; check if end (\ld $t0 $sp 0x20) @@ -203,7 +195,7 @@ ; move arg in (\mv $s1 $a1) (\li $t0 1) - (\sd $t0 $sp 0x30) ; set first flag + (\sd $t0 $sp 0x28) ; set first flag (\j (rel loop)) ) (end @@ -217,22 +209,23 @@ ) (ret ; stash result - (\sd $a0 $sp 0x38) - (\sd $a1 $sp 0x40) + (\sd $a0 $sp 0x30) + (\sd $a1 $sp 0x38) ; release locals (\ld $a0 $sp 0x10) (\auipc $ra (rel release-object$)) (\callr $ra (rel+ release-object$)) - ; release head + ; release args (\ld $a0 $sp 0x20) (\auipc $ra (rel release-object$)) (\callr $ra (rel+ release-object$)) ; restore saved (\ld $ra $sp 0x00) (\ld $s1 $sp 0x08) - (\ld $a0 $sp 0x38) - (\ld $a1 $sp 0x40) - (\addi $sp $sp 0x48) + (\ld $s2 $sp 0x18) + (\ld $a0 $sp 0x30) + (\ld $a1 $sp 0x38) + (\addi $sp $sp 0x40) (\ret) ) (nomem