diff options
Diffstat (limited to 'apps/mu.subx')
-rw-r--r-- | apps/mu.subx | 157 |
1 files changed, 91 insertions, 66 deletions
diff --git a/apps/mu.subx b/apps/mu.subx index 191c94b3..4a4bde35 100644 --- a/apps/mu.subx +++ b/apps/mu.subx @@ -327,9 +327,9 @@ Var-name: # (handle array byte) 0/imm32 Var-type: # (handle tree type-id) 4/imm32 -Var-block-depth: # int +Var-block-depth: # int -- not available until code-generation time 8/imm32 -Var-offset: # int +Var-offset: # int -- not available until code-generation time 0xc/imm32 Var-register: # (handle array byte) -- name of a register 0x10/imm32 @@ -2748,7 +2748,6 @@ populate-mu-function-header: # first-line: (addr stream byte), out: (handle fun # next-mu-token(first-line, name) # assert(name not in '{' '}' '->') # out->name = slice-to-string(name) - # var next-offset: int = 8 # ## inouts # while true # ## name @@ -2758,8 +2757,6 @@ populate-mu-function-header: # first-line: (addr stream byte), out: (handle fun # assert(name != '}') # var v: (handle var) = parse-var-with-type(name, first-line) # assert(v->register == null) - # v->stack-offset = next-offset - # next-offset += size-of(v) # # v->block-depth is implicitly 0 # out->inouts = append(out->inouts, v) # push(vars, v) @@ -2788,8 +2785,6 @@ populate-mu-function-header: # first-line: (addr stream byte), out: (handle fun 68/push 0/imm32/end 68/push 0/imm32/start 89/<- %ecx 4/r32/esp - # var next-offset/edx = 8 - ba/copy-to-edx 8/imm32 # read function name (next-mu-token *(ebp+8) %ecx) # error checking @@ -2833,11 +2828,6 @@ $populate-mu-function-header:check-for-inout: # assert(v->register == null) 81 7/subop/compare *(ebx+0x10) 0/imm32 # Var-register 0f 85/jump-if-!= $populate-mu-function-header:error2/disp32 - # v->stack-offset = next-offset - 89/<- *(ebx+0xc) 2/r32/edx # Var-offset - # next-offset += size-of(v) - (size-of %ebx) # => eax - 01/add %edx 0/r32/eax # v->block-depth is implicitly 0 # # out->inouts = append(out->inouts, v) @@ -4056,9 +4046,6 @@ populate-mu-function-body: # in: (addr buffered-file), out: (handle function), 8b/-> *(ebp+8) 6/r32/esi # edi = out 8b/-> *(ebp+0xc) 7/r32/edi - # initialize some global state - c7 0/subop/copy *Curr-block-depth 1/imm32 - c7 0/subop/copy *Next-local-stack-offset -4/imm32 # var eax: (handle block) = parse-mu-block(in, vars, fn) (parse-mu-block %esi *(ebp+0x10) %edi) # => eax # out->body = eax @@ -4073,26 +4060,11 @@ $populate-mu-function-body:end: 5d/pop-to-ebp c3/return -== data - -# Global state added to each var record when parsing a function - -Curr-block-depth: # (addr int) - 0/imm32 -Next-local-stack-offset: # (addr int) - -4/imm32 - -Next-block-index: # (addr int) - 1/imm32 - -== code - # parses a block, assuming that the leading '{' has already been read by the caller parse-mu-block: # in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle block) # pseudocode: # var line: (stream byte 512) # var word-slice: slice - # increment *Curr-block-depth # result/eax = allocate(Heap, Stmt-size) # result->tag = 0/block # result->name = some unique name @@ -4122,7 +4094,6 @@ parse-mu-block: # in: (addr buffered-file), vars: (addr stack (handle var)), fn # else # stmt = parse-mu-stmt(line, vars, fn) # append-to-block(result, stmt) - # decrement *Curr-block-depth # return result # # . prologue @@ -4154,8 +4125,6 @@ parse-mu-block: # in: (addr buffered-file), vars: (addr stack (handle var)), fn 89/<- *(edi+8) 0/r32/eax # Block-var # push result->var to vars (push *(ebp+0xc) %eax) - # increment *Curr-block-depth - ff 0/subop/increment *Curr-block-depth { $parse-mu-block:line-loop: # line = read-line-buffered(in) @@ -4240,8 +4209,6 @@ $parse-mu-block:regular-stmt: (append-to-block Heap %edi %eax) e9/jump loop/disp32 } # end line loop - # decrement *Curr-block-depth - ff 1/subop/decrement *Curr-block-depth # (pop *(ebp+0xc)) # => eax # return result @@ -4327,6 +4294,14 @@ $new-block-name:end: 5d/pop-to-ebp c3/return +== data + +# Global state added to each var record when parsing a function +Next-block-index: # (addr int) + 1/imm32 + +== code + check-no-tokens-left: # line: (addr stream byte) # . prologue 55/push-ebp @@ -4377,7 +4352,6 @@ $check-no-tokens-left:end: parse-mu-named-block: # name: (addr slice), in: (addr buffered-file), vars: (addr stack (handle var)), fn: (handle function) -> result/eax: (handle stmt) # pseudocode: # var v: (handle var) = new-literal(name) - # v->block-depth = *Curr-block-depth # containing block depth # push(vars, v) # result = parse-mu-block(in, vars, fn) # pop(vars) @@ -4427,9 +4401,6 @@ parse-mu-var-def: # line: (addr stream byte), vars: (addr stack (handle var)) - (next-mu-token *(ebp+8) %ecx) (parse-var-with-type %ecx *(ebp+8)) # => eax 89/<- %edx 0/r32/eax - # v->block-depth = *Curr-block-depth - 8b/-> *Curr-block-depth 0/r32/eax - 89/<- *(edx+8) 0/r32/eax # (push *(ebp+0xc) %edx) # either v has no register and there's no more to this line @@ -4437,9 +4408,6 @@ parse-mu-var-def: # line: (addr stream byte), vars: (addr stack (handle var)) - 3d/compare-eax-and 0/imm32 { 75/jump-if-!= break/disp8 - # v->stack-offset = *Next-local-stack-offset - 8b/-> *Next-local-stack-offset 0/r32/eax - 89/<- *(edx+0xc) 0/r32/eax # Var-offset # TODO: ensure that there's nothing else on this line (new-var-def Heap %edx) # => eax eb/jump $parse-mu-var-def:end/disp8 @@ -4457,11 +4425,6 @@ parse-mu-var-def: # line: (addr stream byte), vars: (addr stack (handle var)) - (add-operation-and-inputs-to-stmt %eax *(ebp+8) *(ebp+0xc)) } $parse-mu-var-def:end: - # *Next-local-stack-offset -= size-of(v) - 50/push-eax - (size-of %edx) # => eax - 29/subtract-from *Next-local-stack-offset 0/r32/eax - 58/pop-to-eax # . reclaim locals 81 0/subop/add %esp 8/imm32 # . restore registers @@ -4494,8 +4457,6 @@ test-parse-mu-var-def: # setup (clear-stream _test-input-stream) (write _test-input-stream "n: int\n") # caller has consumed the 'var' - c7 0/subop/copy *Curr-block-depth 1/imm32 - c7 0/subop/copy *Next-local-stack-offset -4/imm32 # var vars/ecx: (stack (addr var) 4) 81 5/subop/subtract %esp 0x10/imm32 68/push 0x10/imm32/length @@ -4509,14 +4470,10 @@ test-parse-mu-var-def: 8b/-> *(eax+4) 0/r32/eax # Vardef-var (check-strings-equal *eax "n" "F - test-parse-mu-var-def/var-name") # Var-name (check-ints-equal *(eax+0x10) 0 "F - test-parse-mu-var-def/var-register") # Var-register - (check-ints-equal *(eax+8) 1 "F - test-parse-mu-reg-var-def/output-block-depth") # Var-block-depth - (check-ints-equal *(eax+0xc) -4 "F - test-parse-mu-reg-var-def/output-stack-offset") # Var-offset # ensure type is int 8b/-> *(eax+4) 0/r32/eax # Var-type (check-ints-equal *eax 1 "F - test-parse-mu-var-def/var-type:0") # Tree-left (check-ints-equal *(eax+4) 0 "F - test-parse-mu-var-def/var-type:0") # Tree-right - # globals - (check-ints-equal *Next-local-stack-offset -8 "F - test-parse-mu-reg-var-def/Next-local-stack-offset") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -4530,8 +4487,6 @@ test-parse-mu-reg-var-def: # setup (clear-stream _test-input-stream) (write _test-input-stream "n/eax: int <- copy 0\n") # caller has consumed the 'var' - c7 0/subop/copy *Curr-block-depth 1/imm32 - c7 0/subop/copy *Next-local-stack-offset -4/imm32 # var vars/ecx: (stack (addr var) 4) 81 5/subop/subtract %esp 0x10/imm32 68/push 0x10/imm32/length @@ -4547,14 +4502,10 @@ test-parse-mu-reg-var-def: 8b/-> *eax 0/r32/eax # Stmt-var-value (check-strings-equal *eax "n" "F - test-parse-mu-reg-var-def/output-name") # Var-name (check-strings-equal *(eax+0x10) "eax" "F - test-parse-mu-reg-var-def/output-register") # Var-register - (check-ints-equal *(eax+8) 1 "F - test-parse-mu-reg-var-def/output-block-depth") # Var-block-depth - (check-ints-equal *(eax+0xc) 0 "F - test-parse-mu-reg-var-def/output-stack-offset") # Var-offset # ensure type is int 8b/-> *(eax+4) 0/r32/eax # Var-type (check-ints-equal *eax 1 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-left (check-ints-equal *(eax+4) 0 "F - test-parse-mu-reg-var-def/output-type:0") # Tree-right - # globals - (check-ints-equal *Next-local-stack-offset -8 "F - test-parse-mu-reg-var-def/Next-local-stack-offset") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -5201,9 +5152,6 @@ new-literal: # ad: (addr allocation-descriptor), name: (addr slice) -> result/e (new-var *(ebp+8) %ecx) # => eax # result->type = type 89/<- *(eax+4) 2/r32/edx # Var-type - # result->block-depth = *Curr-block-depth - 8b/-> *Curr-block-depth 1/r32/ecx - 89/<- *(eax+8) 1/r32/ecx # Var-block-depth $new-literal:end: # . restore registers 5a/pop-to-edx @@ -6138,6 +6086,15 @@ $type-equal?:end: # Code-generation ####################################################### +== data + +Curr-block-depth: # (addr int) + 0/imm32 +Next-local-stack-offset: # (addr int) + -4/imm32 + +== code + emit-subx: # out: (addr buffered-file) # . prologue 55/push-ebp @@ -6173,6 +6130,8 @@ emit-subx-function: # out: (addr buffered-file), f: (handle function) # . prologue 55/push-ebp 89/<- %ebp 4/r32/esp + # some preprocessing + (populate-mu-type-offsets-in-inouts *(ebp+0xc)) # . save registers 50/push-eax 51/push-ecx @@ -6190,12 +6149,15 @@ emit-subx-function: # out: (addr buffered-file), f: (handle function) # (write-buffered %edi *ecx) (write-buffered %edi ":\n") - # Important: each block's depth during code-generation should be identical - # to what it was during parsing. + # initialize some global state c7 0/subop/copy *Curr-block-depth 1/imm32 + c7 0/subop/copy *Next-local-stack-offset -4/imm32 + # (emit-subx-prologue %edi) (emit-subx-block %edi *(ecx+0x10) %edx) # Function-body (emit-subx-epilogue %edi) + # TODO: validate that *Curr-block-depth and *Next-local-stack-offset have + # been cleaned up $emit-subx-function:end: # . reclaim locals 81 0/subop/add %esp 408/imm32 @@ -6209,6 +6171,48 @@ $emit-subx-function:end: 5d/pop-to-ebp c3/return +populate-mu-type-offsets-in-inouts: # f: (handle function) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + 57/push-edi + # var next-offset/edx: int = 8 + ba/copy-to-edx 8/imm32 + # var curr/ecx: (handle list var) = f->inouts + 8b/-> *(ebp+8) 1/r32/ecx + 8b/-> *(ecx+8) 1/r32/ecx # Function-inouts + { +$populate-mu-type-offsets-in-inouts:loop: + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 + # var v/ebx: (handle var) = curr->value + 8b/-> *ecx 3/r32/ebx # List-value + # v->offset = next-offset + 89/<- *(ebx+0xc) 2/r32/edx # Var-offset + # next-offset += size-of(v) + (size-of %ebx) # => eax + 01/add %edx 0/r32/eax + # curr = curr->next + 8b/-> *(ecx+4) 1/r32/ecx # List-next + eb/jump loop/disp8 + } +$populate-mu-type-offsets-in-inouts:end: + # . restore registers + 5f/pop-to-edi + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + emit-subx-stmt-list: # out: (addr buffered-file), stmts: (handle list stmt), vars: (addr stack (handle var)) # . prologue 55/push-ebp @@ -6408,6 +6412,9 @@ compute-reg-and-maybe-emit-spill: # out: (addr buffered-file), stmt: (handle re # var output/ecx: (handle var) = curr-stmt->outputs->value 8b/-> *(ecx+0xc) 1/r32/ecx # Regvardef-inouts 8b/-> *ecx 1/r32/ecx # List-value + # v->block-depth = *Curr-block-depth + 8b/-> *Curr-block-depth 0/r32/eax + 89/<- *(ecx+8) 0/r32/eax # Var-block-depth # var reg/eax: (handle array byte) = output->register 8b/-> *(ecx+0x10) 0/r32/eax # Var-register # ensure that output is in a register @@ -6417,6 +6424,9 @@ compute-reg-and-maybe-emit-spill: # out: (addr buffered-file), stmt: (handle re (already-spilled-this-block? %ecx *(ebp+0x10)) # => eax 3d/compare-eax-and 0/imm32/false 75/jump-if-!= $compute-reg-and-maybe-emit-spill:end/disp8 + # TODO: assert(sizeof(output) == 4) + # *Next-local-stack-offset -= 4 + 81 5/subop/subtract *Next-local-stack-offset 4/imm32 # emit spill (emit-indent *(ebp+8) *Curr-block-depth) (write-buffered *(ebp+8) "ff 6/subop/push %") @@ -6981,8 +6991,18 @@ emit-subx-var-def: # out: (addr buffered-file), stmt: (handle stmt) 51/push-ecx # eax = stmt 8b/-> *(ebp+0xc) 0/r32/eax + # var v/ecx: (handle var) + 8b/-> *(eax+4) 1/r32/ecx + # v->offset = *Next-local-stack-offset + 8b/-> *Next-local-stack-offset 0/r32/eax + 89/<- *(ecx+0xc) 0/r32/eax # Var-offset + # v->block-depth = *Curr-block-depth + 8b/-> *Curr-block-depth 0/r32/eax + 89/<- *(ecx+8) 0/r32/eax # Var-block-depth # var n/eax: int = size-of(stmt->var) - (size-of *(eax+4)) # Vardef-var => eax + (size-of %ecx) # Vardef-var => eax + # *Next-local-stack-offset -= n + 29/subtract-from *Next-local-stack-offset 0/r32/eax # while n > 0 { 3d/compare-eax-with 0/imm32 @@ -7421,6 +7441,10 @@ emit-subx-block: # out: (addr buffered-file), block: (handle block), vars: (add 56/push-esi # esi = block 8b/-> *(ebp+0xc) 6/r32/esi + # block->var->block-depth = *Curr-block-depth + 8b/-> *(esi+8) 0/r32/eax # Block-var + 8b/-> *Curr-block-depth 1/r32/ecx + 89/<- *(eax+8) 1/r32/ecx # Var-block-depth # var stmts/eax: (handle list stmt) = block->statements 8b/-> *(esi+4) 0/r32/eax # Block-stmts # @@ -7430,8 +7454,9 @@ $emit-subx-block:check-empty: 0f 84/jump-if-= break/disp32 (emit-indent *(ebp+8) *Curr-block-depth) (write-buffered *(ebp+8) "{\n") - # var v/ecx: (addr array byte) = block->var->name + # var v/ecx: (handle var) 8b/-> *(esi+8) 1/r32/ecx # Block-var + # (write-buffered *(ebp+8) *ecx) # Var-name (write-buffered *(ebp+8) ":loop:\n") ff 0/subop/increment *Curr-block-depth |