6520 - new app: parse-int

Several bugs fixed in the process, and expectation of further bugs is growing.
I'd somehow started assuming I don't need to have separate cases for rm32
as a register vs mem. That's not right. We might need more reg-reg Primitives.
This commit is contained in:
Kartik Agaram 2020-06-14 00:24:47 -07:00
parent ead3d08e77
commit ad61776f49
16 changed files with 290 additions and 8 deletions

View File

@ -402,4 +402,65 @@ test-is-decimal-digit-above-9:
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
c3/return
to-decimal-digit: # in: byte -> out/eax: int
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# eax = in
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax
$to-decimal-digit:check0:
# if (eax < '0') goto abort
3d/compare-eax-with 0x30/imm32/0
7c/jump-if-< $to-decimal-digit:abort/disp8
$to-decimal-digit:check1:
# if (eax > '9') goto abort
3d/compare-eax-with 0x39/imm32/f
7f/jump-if-> $to-decimal-digit:abort/disp8
$to-decimal-digit:digit:
# return eax - '0'
2d/subtract-from-eax 0x30/imm32/0
$to-decimal-digit:end:
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
$to-decimal-digit:abort:
# . write-buffered(stderr, error)
# . . push args
68/push "to-decimal-digit: not a digit character: "/imm32
68/push Stderr/imm32
# . . call
e8/call write-buffered/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# . write-byte-buffered(stderr, %eax)
# . . push args
50/push-eax
68/push Stderr/imm32
# . . call
#? e8/call write-byte-buffered/disp32
e8/call print-int32-buffered/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# . write-buffered(stderr, "\n")
# . . push args
68/push Newline/imm32
68/push Stderr/imm32
# . . call
e8/call write-buffered/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# . flush(Stderr)
# . . push args
68/push Stderr/imm32
# . . call
e8/call flush/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# . syscall(exit, 1)
bb/copy-to-ebx 1/imm32
e8/call syscall_exit/disp32
# never gets here
# . . vim:nowrap:textwidth=0

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
apps/hex

Binary file not shown.

BIN
apps/mu

Binary file not shown.

View File

@ -6138,6 +6138,7 @@ parse-mu-var-def: # line: (addr stream byte), vars: (addr stack live-var), out:
{
0f 84/jump-if-= break/disp32
# TODO: disallow vars of type 'byte' in registers 'esi' or 'edi'
# TODO: vars of type 'byte' should only be initialized by clearing to 0
# ensure that the next word is '<-'
(next-mu-token *(ebp+8) %ecx)
(slice-equal? %ecx "<-") # => eax
@ -7968,17 +7969,24 @@ compute-size-of-type-id: # t: type-id -> result/eax: int
89/<- %ecx 4/r32/esp
# eax = t
8b/-> *(ebp+8) 0/r32/eax
# if v is a literal, return 0
# if t is a literal, return 0
3d/compare-eax-and 0/imm32/literal
74/jump-if-= $compute-size-of-type-id:end/disp8 # eax changes type from type-id to int
# if v is a byte, return 1
0f 84/jump-if-= $compute-size-of-type-id:end/disp32 # eax changes type from type-id to int
# if t is a byte, return 1
3d/compare-eax-and 8/imm32/byte
{
3d/compare-eax-and 8/imm32/byte
75/jump-if-!= break/disp8
b8/copy-to-eax 1/imm32
eb/jump $compute-size-of-type-id:end/disp8
}
# if v has a user-defined type, compute its size
# if t is a handle, return 8
3d/compare-eax-and 4/imm32/handle
{
75/jump-if-!= break/disp8
b8/copy-to-eax 8/imm32
eb/jump $compute-size-of-type-id:end/disp8 # eax changes type from type-id to int
}
# if t is a user-defined type, compute its size
# TODO: support non-atom type
(find-typeinfo %eax %ecx)
{
@ -8490,7 +8498,14 @@ size-of-type-id: # t: type-id -> result/eax: int
8b/-> *(ebp+8) 0/r32/eax
# if t is a literal, return 0
3d/compare-eax-and 0/imm32
74/jump-if-= $size-of-type-id:end/disp8 # eax changes type from type-id to int
0f 84/jump-if-= $size-of-type-id:end/disp32 # eax changes type from type-id to int
# if v is a byte, return 1
3d/compare-eax-and 8/imm32/byte
{
75/jump-if-!= break/disp8
b8/copy-to-eax 1/imm32
eb/jump $size-of-type-id:end/disp8
}
# if t is a handle, return 8
3d/compare-eax-and 4/imm32/handle
{
@ -9857,6 +9872,7 @@ translate-mu-length-stmt: # out: (addr buffered-file), stmt: (addr stmt), err:
{
81 7/subop/compare %ecx 1/imm32
75/jump-if-!= break/disp8
$translate-mu-length-stmt:size-1:
(emit-save-size-to *(ebp+8) %ebx %edx)
e9/jump $translate-mu-length-stmt:end/disp32
}
@ -9867,6 +9883,7 @@ translate-mu-length-stmt: # out: (addr buffered-file), stmt: (addr stmt), err:
74/jump-if-= break/disp8
81 7/subop/compare %ecx 0xff/imm32
7f/jump-if-> break/disp8
$translate-mu-length-stmt:size-power-of-2:
(emit-save-size-to *(ebp+8) %ebx %edx)
(emit-divide-by-shift-right *(ebp+8) %edx %ecx)
e9/jump $translate-mu-length-stmt:end/disp32
@ -9874,6 +9891,7 @@ translate-mu-length-stmt: # out: (addr buffered-file), stmt: (addr stmt), err:
# otherwise, the complex case
# . emit register spills
{
$translate-mu-length-stmt:complex:
(string-equal? %edx "eax") # => eax
3d/compare-eax-and 0/imm32/false
75/break-if-!= break/disp8
@ -11733,8 +11751,26 @@ _Primitive-address: # (payload primitive)
0/imm32/no-disp32
1/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
_Primitive-compare-mem-with-reg/imm32/next
_Primitive-compare-reg-with-reg/imm32/next
# - compare
_Primitive-compare-reg-with-reg: # (payload primitive)
0x11/imm32/alloc-id:fake:payload
# compare var1/reg1 var2/reg2 => 39/compare var1/rm32 var2/r32
0x11/imm32/alloc-id:fake
_string-compare/imm32/name
0x11/imm32/alloc-id:fake
Two-int-args-in-regs/imm32/inouts
0/imm32/no-outputs
0/imm32/no-outputs
0x11/imm32/alloc-id:fake
_string_39_compare->/imm32/subx-name
1/imm32/rm32-is-first-inout
2/imm32/r32-is-second-inout
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
_Primitive-compare-mem-with-reg/imm32/next
_Primitive-compare-mem-with-reg: # (payload primitive)
0x11/imm32/alloc-id:fake:payload
# compare var1 var2/reg => 39/compare var1/rm32 var2/r32
@ -11824,8 +11860,26 @@ _Primitive-compare-mem-with-literal: # (payload primitive)
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
_Primitive-multiply-reg-by-mem/imm32/next
_Primitive-multiply-reg-by-reg/imm32/next
# - multiply
_Primitive-multiply-reg-by-reg: # (payload primitive)
0x11/imm32/alloc-id:fake:payload
# var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
0x11/imm32/alloc-id:fake
_string-multiply/imm32/name
0x11/imm32/alloc-id:fake
Single-int-var-in-some-register/imm32/inouts
0x11/imm32/alloc-id:fake
Single-int-var-in-some-register/imm32/outputs
0x11/imm32/alloc-id:fake
_string_0f_af_multiply/imm32/subx-name
1/imm32/rm32-is-first-inout
3/imm32/r32-is-first-output
0/imm32/no-imm32
0/imm32/no-disp32
0/imm32/output-is-write-only
0x11/imm32/alloc-id:fake
_Primitive-multiply-reg-by-mem/imm32/next
_Primitive-multiply-reg-by-mem: # (payload primitive)
0x11/imm32/alloc-id:fake:payload
# var1/reg <- multiply var2 => 0f af/multiply var2/rm32 var1/r32
@ -13269,6 +13323,13 @@ Two-args-int-stack-int-reg: # (payload list var)
0x11/imm32/alloc-id:fake
Single-int-var-in-some-register/imm32/next
Two-int-args-in-regs: # (payload list var)
0x11/imm32/alloc-id:fake:payload
0x11/imm32/alloc-id:fake
Int-var-in-some-register/imm32
0x11/imm32/alloc-id:fake
Single-int-var-in-some-register/imm32/next
# Not really legal, but closest we can currently represent a dereference of an (addr byte)
Two-args-byte-stack-byte-reg: # (payload list var)
0x11/imm32/alloc-id:fake:payload
@ -15671,6 +15732,116 @@ $test-add-literal-to-mem:initialize-stmt-operation:
5d/pop-to-ebp
c3/return
test-compare-reg-with-reg:
# compare var1/ecx, var2/eax
# =>
# 39/compare %ecx 0/r32/eax
#
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# setup
(clear-stream _test-output-stream)
(clear-stream $_test-output-buffered-file->buffer)
$test-compare-reg-with-reg:initialize-type:
# var type/ecx: (payload tree type-id) = int
68/push 0/imm32/right:null
68/push 0/imm32/right:null
68/push 0/imm32/left:unused
68/push 1/imm32/value:int
68/push 1/imm32/is-atom?:true
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ecx 4/r32/esp
$test-compare-reg-with-reg:initialize-var1:
# var var1/ecx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
51/push-ecx
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %ecx 4/r32/esp
$test-compare-reg-with-reg:initialize-var1-name:
# var1->name = "var1"
8d/copy-address *(ecx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var1" %eax)
$test-compare-reg-with-reg:initialize-var1-register:
# var1->register = "ecx"
8d/copy-address *(ecx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "ecx" %eax)
$test-compare-reg-with-reg:initialize-var2:
# var var2/edx: (payload var)
68/push 0/imm32/register
68/push 0/imm32/register
68/push 0/imm32/no-stack-offset
68/push 1/imm32/block-depth
ff 6/subop/push *(ecx+0x10)
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/name
68/push 0/imm32/name
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %edx 4/r32/esp
$test-compare-reg-with-reg:initialize-var2-name:
# var2->name = "var2"
8d/copy-address *(edx+4) 0/r32/eax # Var-name + 4
(copy-array Heap "var2" %eax)
$test-compare-reg-with-reg:initialize-var2-register:
# var2->register = "eax"
8d/copy-address *(edx+0x1c) 0/r32/eax # Var-register + 4
(copy-array Heap "eax" %eax)
$test-compare-reg-with-reg:initialize-inouts:
# var inouts/esi: (payload stmt-var) = [var2]
68/push 0/imm32/is-deref:false
68/push 0/imm32/next
68/push 0/imm32/next
52/push-edx/var2
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %esi 4/r32/esp
# inouts = [var1, var2]
68/push 0/imm32/is-deref:false
56/push-esi/next
68/push 0x11/imm32/alloc-id:fake
51/push-ecx/var1
68/push 0x11/imm32/alloc-id:fake
68/push 0x11/imm32/alloc-id:fake:payload
89/<- %esi 4/r32/esp
$test-compare-reg-with-reg:initialize-stmt:
# var stmt/esi: (addr statement)
68/push 0/imm32/next
68/push 0/imm32/next
68/push 0/imm32/outputs
68/push 0/imm32/outputs
56/push-esi/inouts
68/push 0x11/imm32/alloc-id:fake
68/push 0/imm32/operation
68/push 0/imm32/operation
68/push 1/imm32/tag:stmt1
89/<- %esi 4/r32/esp
$test-compare-reg-with-reg:initialize-stmt-operation:
# stmt->operation = "compare"
8d/copy-address *(esi+4) 0/r32/eax # Stmt1-operation
(copy-array Heap "compare" %eax)
# convert
c7 0/subop/copy *Curr-block-depth 0/imm32
(emit-subx-stmt _test-output-buffered-file %esi Primitives Stderr 0)
(flush _test-output-buffered-file)
#? # dump _test-output-stream {{{
#? (write 2 "^")
#? (write-stream 2 _test-output-stream)
#? (write 2 "$\n")
#? (rewind-stream _test-output-stream)
#? # }}}
# check output
(check-next-stream-line-equal _test-output-stream "39/compare-> %ecx 0x00000000/r32" "F - test-compare-reg-with-reg")
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
test-compare-mem-with-reg:
# compare var1, var2/eax
# =>

BIN
apps/pack

Binary file not shown.

50
apps/parse-int.mu Normal file
View File

@ -0,0 +1,50 @@
# parse a decimal int at the commandline
#
# To run:
# $ ./translate_mu apps/parse-int.mu
# $ ./a.elf 123
# $ echo $?
# 123
fn main _args: (addr array (addr array byte)) -> exit-status/ebx: int {
$main-body: {
# if no args, print a message and exit
var args/esi: (addr array (addr array byte)) <- copy _args
var n/ecx: int <- length args
compare n, 1
{
break-if->
print-string "usage: parse-int <integer>\n"
exit-status <- copy 1
break $main-body
}
# otherwise parse the first arg as an integer
var in/ecx: (addr addr array byte) <- index args, 1
var out/eax: int <- parse-int *in
exit-status <- copy out
}
}
fn parse-int _in: (addr array byte) -> result/eax: int {
var in/esi: (addr array byte) <- copy _in
var len/edx: int <- length in
var i/ecx: int <- copy 0
var out/edi: int <- copy 0
{
compare i, len
break-if->=
# out *= 10
var ten/eax: int <- copy 0xa
out <- multiply ten
# c = in[i]
var tmp/ebx: (addr byte) <- index in, i
var c/eax: byte <- copy 0
c <- copy-byte *tmp
#
var digit/eax: int <- to-decimal-digit c
out <- add digit
i <- increment
loop
}
result <- copy out
}

Binary file not shown.

Binary file not shown.

Binary file not shown.