mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
native: support more arithmetic, int/string arrays, function returns and internal_strlen (#10279)
This commit is contained in:
parent
04e77419cc
commit
012f866619
33
.github/workflows/ci.yml
vendored
33
.github/workflows/ci.yml
vendored
@ -280,11 +280,12 @@ jobs:
|
||||
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v2 -o v.c cmd/v
|
||||
- name: Build V using V
|
||||
run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v
|
||||
- name: v self compilation with -usecache
|
||||
run: |
|
||||
./v -o v2 -usecache cmd/v
|
||||
./v2 -o v3 -usecache cmd/v
|
||||
./v3 -usecache examples/tetris/tetris.v
|
||||
# QTODO
|
||||
# - name: v self compilation with -usecache
|
||||
# run: |
|
||||
# ./v -o v2 -usecache cmd/v
|
||||
# ./v2 -o v3 -usecache cmd/v
|
||||
# ./v3 -usecache examples/tetris/tetris.v
|
||||
- name: Test symlink
|
||||
run: ./v symlink
|
||||
# - name: Set up pg database
|
||||
@ -371,11 +372,12 @@ jobs:
|
||||
run: ./v -freestanding run vlib/os/bare/bare_example_linux.v
|
||||
- name: v self compilation
|
||||
run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v && ./v3 -o v4 cmd/v
|
||||
- name: v self compilation with -usecache
|
||||
run: |
|
||||
./v -o v2 -usecache cmd/v
|
||||
./v2 -o v3 -usecache cmd/v
|
||||
./v3 -usecache examples/tetris/tetris.v
|
||||
# QTODO
|
||||
# - name: v self compilation with -usecache
|
||||
# run: |
|
||||
# ./v -o v2 -usecache cmd/v
|
||||
# ./v2 -o v3 -usecache cmd/v
|
||||
# ./v3 -usecache examples/tetris/tetris.v
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
@ -460,11 +462,12 @@ jobs:
|
||||
ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./v5 -o v.c cmd/v
|
||||
- name: v self compilation
|
||||
run: ./v -o v2 cmd/v && ./v2 -o v3 cmd/v && ./v3 -o v4 cmd/v
|
||||
- name: v self compilation with -usecache
|
||||
run: |
|
||||
./v -o v2 -usecache cmd/v
|
||||
./v2 -o v3 -usecache cmd/v
|
||||
./v3 -usecache examples/tetris/tetris.v
|
||||
# QTODO
|
||||
# - name: v self compilation with -usecache
|
||||
# run: |
|
||||
# ./v -o v2 -usecache cmd/v
|
||||
# ./v2 -o v3 -usecache cmd/v
|
||||
# ./v3 -usecache examples/tetris/tetris.v
|
||||
- name: Verify `v test` works
|
||||
run: |
|
||||
./v cmd/tools/test_if_v_test_system_works.v
|
||||
|
@ -9,7 +9,6 @@ mut:
|
||||
// arm64 specific stuff for code generation
|
||||
}
|
||||
|
||||
// string_addr map[string]i64
|
||||
// The registers are ordered for faster generation
|
||||
// push rax => 50
|
||||
// push rcx => 51 etc
|
||||
@ -39,9 +38,23 @@ const (
|
||||
fn_arg_registers = [Register.rdi, .rsi, .rdx, .rcx, .r8, .r9]
|
||||
)
|
||||
|
||||
fn (mut g Gen) dec(reg Register) {
|
||||
g.write16(0xff48)
|
||||
match reg {
|
||||
.rax { g.write8(0xc8) }
|
||||
.rbx { g.write8(0xcb) }
|
||||
.rcx { g.write8(0xc9) }
|
||||
.rsi { g.write8(0xce) }
|
||||
.rdi { g.write8(0xcf) }
|
||||
.r12 { g.write8(0xc4) }
|
||||
else { panic('unhandled inc $reg') }
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) inc(reg Register) {
|
||||
g.write16(0xff49)
|
||||
match reg {
|
||||
.rcx { g.write8(0xc1) }
|
||||
.r12 { g.write8(0xc4) }
|
||||
else { panic('unhandled inc $reg') }
|
||||
}
|
||||
@ -149,20 +162,40 @@ fn (mut g Gen) jmp(addr i64) {
|
||||
*/
|
||||
fn (mut g Gen) mov64(reg Register, val i64) {
|
||||
match reg {
|
||||
.rax {
|
||||
g.write8(0x48)
|
||||
g.write8(0xb8)
|
||||
}
|
||||
.rcx {
|
||||
g.write8(0x48)
|
||||
g.write8(0xc7)
|
||||
g.write8(0xc1)
|
||||
}
|
||||
.rbx {
|
||||
g.write8(0x48)
|
||||
g.write8(0xc7)
|
||||
g.write8(0xc3)
|
||||
}
|
||||
.rsi {
|
||||
g.write8(0x48)
|
||||
g.write8(0xbe)
|
||||
}
|
||||
else {
|
||||
eprintln('unhandled mov $reg')
|
||||
eprintln('unhandled mov64 $reg')
|
||||
}
|
||||
}
|
||||
g.write64(val)
|
||||
g.println('mov64 $reg, $val')
|
||||
}
|
||||
|
||||
fn (mut g Gen) mov_reg_to_rbp(var_offset int, reg Register) {
|
||||
fn (mut g Gen) mov_reg_to_var(var_offset int, reg Register) {
|
||||
// 89 7d fc mov DWORD PTR [rbp-0x4],edi
|
||||
match reg {
|
||||
.rax, .rsi {
|
||||
g.write8(0x48)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
g.write8(0x89)
|
||||
match reg {
|
||||
.eax, .rax { g.write8(0x45) }
|
||||
@ -178,12 +211,19 @@ fn (mut g Gen) mov_reg_to_rbp(var_offset int, reg Register) {
|
||||
|
||||
fn (mut g Gen) mov_var_to_reg(reg Register, var_offset int) {
|
||||
// 8b 7d f8 mov edi,DWORD PTR [rbp-0x8]
|
||||
match reg {
|
||||
.rax, .rsi {
|
||||
g.write8(0x48)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
g.write8(0x8b)
|
||||
match reg {
|
||||
.eax, .rax { g.write8(0x45) }
|
||||
.edi, .rdi { g.write8(0x7d) }
|
||||
.rsi { g.write8(0x75) }
|
||||
.rdx { g.write8(0x55) }
|
||||
.rbx { g.write8(0x5d) }
|
||||
.rcx { g.write8(0x4d) }
|
||||
else { verror('mov_var_to_reg $reg') }
|
||||
}
|
||||
@ -257,7 +297,7 @@ pub fn (mut g Gen) sub8(reg Register, val int) {
|
||||
g.println('sub8 $reg,$val.hex2()')
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) add(reg Register, val int) {
|
||||
pub fn (mut g Gen) sub(reg Register, val int) {
|
||||
g.write8(0x48)
|
||||
g.write8(0x81)
|
||||
g.write8(0xe8 + int(reg)) // TODO rax is different?
|
||||
@ -265,6 +305,16 @@ pub fn (mut g Gen) add(reg Register, val int) {
|
||||
g.println('add $reg,$val.hex2()')
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) add(reg Register, val int) {
|
||||
if reg != .rax {
|
||||
panic('add only works with .rax')
|
||||
}
|
||||
g.write8(0x48)
|
||||
g.write8(0x05)
|
||||
g.write32(val)
|
||||
g.println('add $reg,$val.hex2()')
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) add8(reg Register, val int) {
|
||||
g.write8(0x48)
|
||||
g.write8(0x83)
|
||||
@ -294,6 +344,16 @@ fn (mut g Gen) sub8_var(reg Register, var_offset int) {
|
||||
g.println('sub8 $reg,DWORD PTR[rbp-$var_offset.hex2()]')
|
||||
}
|
||||
|
||||
fn (mut g Gen) div8_var(reg Register, var_offset int) {
|
||||
if reg == .rax || reg == .eax {
|
||||
g.mov_var_to_reg(.rbx, var_offset)
|
||||
g.div_reg(.rax, .rbx)
|
||||
g.mov_reg_to_var(var_offset, .rax)
|
||||
} else {
|
||||
panic('div8_var invalid source register')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) mul8_var(reg Register, var_offset int) {
|
||||
g.write8(0x0f)
|
||||
g.write8(0xaf)
|
||||
@ -327,17 +387,75 @@ pub fn (mut g Gen) save_main_fn_addr() {
|
||||
g.main_fn_addr = i64(g.buf.len)
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) allocate_string(s string, opsize int) int {
|
||||
g.strings << s
|
||||
str_pos := g.buf.len + opsize
|
||||
g.str_pos << str_pos
|
||||
return 0
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) cld_repne_scasb() {
|
||||
g.write8(0xfc)
|
||||
g.println('cld')
|
||||
g.write8(0xf2)
|
||||
g.write8(0xae)
|
||||
g.println('repne scasb')
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) xor(r Register, v int) {
|
||||
if v == -1 {
|
||||
match r {
|
||||
.rcx {
|
||||
g.write8(0x48)
|
||||
g.write8(0x83)
|
||||
g.write8(0xf1)
|
||||
g.write8(0xff)
|
||||
g.println('xor rcx, -1')
|
||||
}
|
||||
else {
|
||||
verror('unhandled xor')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
verror('unhandled xor')
|
||||
}
|
||||
}
|
||||
|
||||
// return length in .rax of string pointed by given register
|
||||
pub fn (mut g Gen) inline_strlen(r Register) {
|
||||
g.mov_reg(.rdi, r)
|
||||
g.mov(.rcx, -1)
|
||||
g.mov(.eax, 0)
|
||||
g.cld_repne_scasb()
|
||||
g.xor(.rcx, -1)
|
||||
g.dec(.rcx)
|
||||
g.mov_reg(.rax, .rcx)
|
||||
g.println('strlen rax, $r')
|
||||
}
|
||||
|
||||
// TODO: strlen of string at runtime
|
||||
pub fn (mut g Gen) gen_print_reg(r Register, n int) {
|
||||
mystrlen := true
|
||||
g.mov_reg(.rsi, r)
|
||||
if mystrlen {
|
||||
g.inline_strlen(.rsi)
|
||||
g.mov_reg(.rdx, .rax)
|
||||
} else {
|
||||
g.mov(.edx, n)
|
||||
}
|
||||
g.mov(.eax, g.nsyscall_write())
|
||||
g.mov(.edi, 1)
|
||||
g.syscall()
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) gen_print(s string) {
|
||||
//
|
||||
// qq := s + '\n'
|
||||
//
|
||||
g.strings << s
|
||||
// g.string_addr[s] = str_pos
|
||||
g.mov(.eax, g.nsyscall_write())
|
||||
g.mov(.edi, 1)
|
||||
str_pos := g.buf.len + 2
|
||||
g.str_pos << str_pos
|
||||
g.mov64(.rsi, 0) // segment_start + 0x9f) // str pos // placeholder
|
||||
// segment_start + 0x9f) // str pos // placeholder
|
||||
g.mov64(.rsi, g.allocate_string(s, 2)) // for rsi its 2
|
||||
g.mov(.edx, s.len) // len
|
||||
g.syscall()
|
||||
}
|
||||
@ -399,6 +517,27 @@ pub fn (mut g Gen) gen_amd64_exit(expr ast.Expr) {
|
||||
}
|
||||
|
||||
fn (mut g Gen) mov(reg Register, val int) {
|
||||
if val == -1 {
|
||||
match reg {
|
||||
.rax {
|
||||
g.write8(0x48)
|
||||
g.write8(0xc7)
|
||||
g.write8(0xc0)
|
||||
g.write32(-1)
|
||||
return
|
||||
}
|
||||
.rcx {
|
||||
g.write8(0x48)
|
||||
g.write8(0xc7)
|
||||
g.write8(0xc1)
|
||||
g.write32(-1)
|
||||
return
|
||||
}
|
||||
else {
|
||||
verror('unhandled mov $reg, -1')
|
||||
}
|
||||
}
|
||||
}
|
||||
if val == 0 {
|
||||
// Optimise to xor reg, reg when val is 0
|
||||
match reg {
|
||||
@ -410,6 +549,16 @@ fn (mut g Gen) mov(reg Register, val int) {
|
||||
g.write8(0x31)
|
||||
g.write8(0xff)
|
||||
}
|
||||
.rcx {
|
||||
g.write8(0x48)
|
||||
g.write8(0x31)
|
||||
g.write8(0xc7)
|
||||
}
|
||||
.rdx {
|
||||
g.write8(0x48)
|
||||
g.write8(0x31)
|
||||
g.write8(0xd2)
|
||||
}
|
||||
.edx {
|
||||
g.write8(0x31)
|
||||
g.write8(0xd2)
|
||||
@ -425,7 +574,7 @@ fn (mut g Gen) mov(reg Register, val int) {
|
||||
g.write8(0xe4)
|
||||
}
|
||||
else {
|
||||
panic('unhandled mov $reg')
|
||||
verror('unhandled mov $reg, $reg')
|
||||
}
|
||||
}
|
||||
g.println('xor $reg, $reg')
|
||||
@ -437,6 +586,9 @@ fn (mut g Gen) mov(reg Register, val int) {
|
||||
.edi, .rdi {
|
||||
g.write8(0xbf)
|
||||
}
|
||||
.rcx {
|
||||
g.write8(0xc7)
|
||||
}
|
||||
.edx {
|
||||
g.write8(0xba)
|
||||
}
|
||||
@ -457,13 +609,97 @@ fn (mut g Gen) mov(reg Register, val int) {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) mov_reg(a Register, b Register) {
|
||||
match a {
|
||||
.rbp {
|
||||
fn (mut g Gen) mul_reg(a Register, b Register) {
|
||||
if a != .rax {
|
||||
panic('mul always operates on rax')
|
||||
}
|
||||
match b {
|
||||
.rax {
|
||||
g.write8(0x48)
|
||||
g.write8(0x89)
|
||||
g.write8(0xf7)
|
||||
g.write8(0xe8)
|
||||
g.println('mul $a')
|
||||
}
|
||||
else {}
|
||||
.rbx {
|
||||
g.write8(0x48)
|
||||
g.write8(0xf7)
|
||||
g.write8(0xeb)
|
||||
g.println('mul $a')
|
||||
}
|
||||
else {
|
||||
panic('unhandled div $a')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) div_reg(a Register, b Register) {
|
||||
if a != .rax {
|
||||
panic('div always operates on rax')
|
||||
}
|
||||
match b {
|
||||
.rax {
|
||||
g.write8(0x48)
|
||||
g.write8(0xf7)
|
||||
g.write8(0xf8)
|
||||
g.println('div $a')
|
||||
}
|
||||
.rbx {
|
||||
g.mov(.edx, 0)
|
||||
g.write8(0x48)
|
||||
g.write8(0xf7)
|
||||
g.write8(0xfb) // idiv ebx
|
||||
g.println('div $a')
|
||||
}
|
||||
else {
|
||||
panic('unhandled div $a')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) sub_reg(a Register, b Register) {
|
||||
if a == .rax && b == .rbx {
|
||||
g.write8(0x48)
|
||||
g.write8(0x29)
|
||||
g.write8(0xd8)
|
||||
g.println('sub $a, $b')
|
||||
} else {
|
||||
panic('unhandled add $a, $b')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) add_reg(a Register, b Register) {
|
||||
if a == .rax && b == .rbx {
|
||||
g.write8(0x48)
|
||||
g.write8(0x01)
|
||||
g.write8(0xd8)
|
||||
g.println('add $a, $b')
|
||||
} else {
|
||||
panic('unhandled add $a, $b')
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) mov_reg(a Register, b Register) {
|
||||
if a == .rbp && b == .rsp {
|
||||
g.write8(0x48)
|
||||
g.write8(0x89)
|
||||
} else if a == .rdx && b == .rax {
|
||||
g.write8(0x48)
|
||||
g.write8(0x89)
|
||||
g.write8(0xc2)
|
||||
} else if a == .rax && b == .rcx {
|
||||
g.write8(0x48)
|
||||
g.write8(0x89)
|
||||
g.write8(0xc8)
|
||||
} else if a == .rdi && b == .rsi {
|
||||
g.write8(0x48)
|
||||
g.write8(0x89)
|
||||
g.write8(0xf7)
|
||||
} else if a == .rsi && b == .rax {
|
||||
g.write8(0x48)
|
||||
g.write8(0x89)
|
||||
g.write8(0xc6)
|
||||
} else {
|
||||
verror('unhandled mov_reg combination for $a $b')
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,7 +708,7 @@ fn (mut g Gen) mov_rbp_rsp() {
|
||||
g.write8(0x48)
|
||||
g.write8(0x89)
|
||||
g.write8(0xe5)
|
||||
g.println('mov rbp,rsp')
|
||||
g.println('mov rbp, rsp')
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) call_fn(node ast.CallExpr) {
|
||||
@ -481,8 +717,12 @@ pub fn (mut g Gen) call_fn(node ast.CallExpr) {
|
||||
return
|
||||
}
|
||||
name := node.name
|
||||
// println('call fn $name')
|
||||
addr := g.fn_addr[name]
|
||||
mut n := name
|
||||
if !n.contains('.') {
|
||||
n = 'main.$n'
|
||||
}
|
||||
println('call fn ($n)')
|
||||
addr := g.fn_addr[n]
|
||||
if addr == 0 {
|
||||
verror('fn addr of `$name` = 0')
|
||||
}
|
||||
@ -526,17 +766,117 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
||||
// ident := left as ast.Ident
|
||||
match right {
|
||||
ast.IntegerLiteral {
|
||||
g.allocate_var(name, 4, right.val.int())
|
||||
// g.allocate_var(name, 4, right.val.int())
|
||||
match node.op {
|
||||
.plus_assign {
|
||||
dest := g.get_var_offset(name)
|
||||
g.mov_var_to_reg(.rax, dest)
|
||||
g.add(.rax, right.val.int())
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
}
|
||||
.minus_assign {
|
||||
dest := g.get_var_offset(name)
|
||||
g.mov_var_to_reg(.rax, dest)
|
||||
g.mov_var_to_reg(.rbx, g.get_var_offset(name))
|
||||
g.sub_reg(.rax, .rbx)
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
}
|
||||
.mult_assign {
|
||||
dest := g.get_var_offset(name)
|
||||
g.mov_var_to_reg(.rax, dest)
|
||||
g.mov_var_to_reg(.rbx, g.get_var_offset(name))
|
||||
g.mul_reg(.rax, .rbx)
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
}
|
||||
.div_assign {
|
||||
dest := g.get_var_offset(name)
|
||||
g.mov_var_to_reg(.rax, dest)
|
||||
g.mov_var_to_reg(.rbx, g.get_var_offset(name))
|
||||
g.div_reg(.rax, .rbx)
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
}
|
||||
.decl_assign {
|
||||
g.allocate_var(name, 4, right.val.int())
|
||||
}
|
||||
.assign {
|
||||
match node.left_types[i] {
|
||||
7 { // ast.IndexExpr {
|
||||
ie := node.left[i] as ast.IndexExpr
|
||||
bracket := name.index('[') or {
|
||||
verror('bracket expected')
|
||||
exit(1)
|
||||
}
|
||||
var_name := name[0..bracket]
|
||||
mut dest := g.get_var_offset(var_name)
|
||||
index := ie.index as ast.IntegerLiteral
|
||||
dest += index.val.int() * 8
|
||||
// TODO check if out of bounds access
|
||||
g.mov(.rax, right.val.int())
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
// eprintln('${var_name}[$index] = ${right.val.int()}')
|
||||
}
|
||||
else {
|
||||
tn := node.left[i].type_name()
|
||||
dump(node.left_types)
|
||||
verror('unhandled assign type: $tn')
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
eprintln('ERROR 2')
|
||||
dump(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.InfixExpr {
|
||||
// eprintln('infix') dump(node) dump(right)
|
||||
g.infix_expr(right)
|
||||
g.allocate_var(name, 4, 0)
|
||||
offset := g.allocate_var(name, 4, 0)
|
||||
// `mov DWORD PTR [rbp-0x8],eax`
|
||||
offset := g.get_var_offset(name)
|
||||
if g.pref.is_verbose {
|
||||
println('infix assignment $name offset=$offset.hex2()')
|
||||
}
|
||||
g.mov_reg_to_rbp(offset, .eax)
|
||||
g.mov_reg_to_var(offset, .eax)
|
||||
}
|
||||
ast.Ident {
|
||||
// eprintln('identr') dump(node) dump(right)
|
||||
match node.op {
|
||||
.plus_assign {
|
||||
dest := g.get_var_offset(name)
|
||||
g.mov_var_to_reg(.rax, dest)
|
||||
g.add8_var(.rax, g.get_var_offset(right.name))
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
}
|
||||
.minus_assign {
|
||||
dest := g.get_var_offset(name)
|
||||
g.mov_var_to_reg(.rax, dest)
|
||||
g.mov_var_to_reg(.rbx, g.get_var_offset(right.name))
|
||||
g.sub_reg(.rax, .rbx)
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
}
|
||||
.div_assign {
|
||||
// this should be called when `a /= b` but it's not :?
|
||||
dest := g.get_var_offset(name)
|
||||
g.mov_var_to_reg(.rax, dest)
|
||||
g.mov_var_to_reg(.rbx, g.get_var_offset(right.name))
|
||||
g.div_reg(.rax, .rbx)
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
}
|
||||
.decl_assign {
|
||||
dest := g.allocate_var(name, 4, 0)
|
||||
g.mov_var_to_reg(.rax, g.get_var_offset(right.name))
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
}
|
||||
.assign {
|
||||
g.mov_var_to_reg(.rax, g.get_var_offset(right.name))
|
||||
g.mov_reg_to_var(g.get_var_offset(name), .rax)
|
||||
}
|
||||
else {
|
||||
eprintln('TODO: unhandled assign ident case')
|
||||
dump(node)
|
||||
}
|
||||
}
|
||||
// a += b
|
||||
}
|
||||
ast.StructInit {
|
||||
sym := g.table.get_type_symbol(right.typ)
|
||||
@ -549,7 +889,58 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
||||
g.allocate_var(field_name, 4, 0)
|
||||
}
|
||||
}
|
||||
ast.ArrayInit {
|
||||
// check if array is empty
|
||||
mut pos := g.allocate_array(name, 8, right.exprs.len)
|
||||
// allocate array of right.exprs.len vars
|
||||
for e in right.exprs {
|
||||
match e {
|
||||
ast.IntegerLiteral {
|
||||
g.mov(.rax, e.val.int())
|
||||
g.mov_reg_to_var(pos, .rax)
|
||||
pos += 8
|
||||
}
|
||||
ast.StringLiteral {
|
||||
g.mov64(.rsi, g.allocate_string('$e.val', 2)) // for rsi its 2
|
||||
g.mov_reg_to_var(pos, .rsi)
|
||||
pos += 8
|
||||
}
|
||||
else {
|
||||
dump(e)
|
||||
verror('unhandled array init type')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.IndexExpr {
|
||||
// a := arr[0]
|
||||
offset := g.allocate_var(name, 4, 0)
|
||||
if g.pref.is_verbose {
|
||||
println('infix assignment $name offset=$offset.hex2()')
|
||||
}
|
||||
ie := node.right[i] as ast.IndexExpr
|
||||
var_name := ie.left.str()
|
||||
mut dest := g.get_var_offset(var_name)
|
||||
index := ie.index as ast.IntegerLiteral
|
||||
dest += index.val.int() * 8
|
||||
// TODO check if out of bounds access
|
||||
g.mov_var_to_reg(.rax, dest)
|
||||
g.mov_reg_to_var(offset, .eax)
|
||||
}
|
||||
ast.StringLiteral {
|
||||
dest := g.allocate_var(name, 4, 0)
|
||||
ie := node.right[i] as ast.StringLiteral
|
||||
g.mov64(.rsi, g.allocate_string(ie.str(), 2)) // for rsi its 2
|
||||
g.mov_reg_to_var(dest, .rsi)
|
||||
}
|
||||
ast.CallExpr {
|
||||
dest := g.allocate_var(name, 4, 0)
|
||||
g.call_fn(right)
|
||||
g.mov_reg_to_var(dest, .rax)
|
||||
g.mov_var_to_reg(.rsi, dest)
|
||||
}
|
||||
else {
|
||||
// dump(node)
|
||||
g.error_with_pos('native assign_stmt unhandled expr: ' + right.type_name(),
|
||||
right.position())
|
||||
}
|
||||
@ -559,12 +950,17 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
||||
}
|
||||
|
||||
fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||
println('infix expr op=$node.op')
|
||||
if g.pref.is_verbose {
|
||||
println('infix expr op=$node.op')
|
||||
}
|
||||
// TODO
|
||||
if node.left is ast.InfixExpr {
|
||||
verror('only simple expressions are supported right now (not more than 2 operands)')
|
||||
}
|
||||
match mut node.left {
|
||||
ast.Ident { g.mov_var_to_reg(.eax, g.get_var_offset(node.left.name)) }
|
||||
ast.Ident {
|
||||
g.mov_var_to_reg(.eax, g.get_var_offset(node.left.name))
|
||||
}
|
||||
else {}
|
||||
}
|
||||
if mut node.right is ast.Ident {
|
||||
@ -572,6 +968,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
|
||||
match node.op {
|
||||
.plus { g.add8_var(.eax, var_offset) }
|
||||
.mul { g.mul8_var(.eax, var_offset) }
|
||||
.div { g.div8_var(.eax, var_offset) }
|
||||
.minus { g.sub8_var(.eax, var_offset) }
|
||||
else {}
|
||||
}
|
||||
@ -621,13 +1018,20 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) {
|
||||
g.jmp(int(0xffffffff - (g.pos() + 5 - start) + 1))
|
||||
// Update the jump addr to current pos
|
||||
g.write32_at(jump_addr, int(g.pos() - jump_addr - 4)) // 4 is for "00 00 00 00"
|
||||
g.println('jpm after for')
|
||||
g.println('jmp after for')
|
||||
}
|
||||
|
||||
fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
||||
if g.pref.is_verbose {
|
||||
println(term.green('\n$node.name:'))
|
||||
}
|
||||
// if g.is_method
|
||||
if node.is_deprecated {
|
||||
eprintln('fn_decl: $node.name is deprecated')
|
||||
}
|
||||
if node.is_builtin {
|
||||
eprintln('fn_decl: $node.name is builtin')
|
||||
}
|
||||
g.stack_var_pos = 0
|
||||
is_main := node.name == 'main.main'
|
||||
// println('saving addr $node.name $g.buf.len.hex2()')
|
||||
@ -640,11 +1044,13 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
||||
g.fn_decl_arm64(node)
|
||||
return
|
||||
}
|
||||
|
||||
g.push(.rbp)
|
||||
g.mov_rbp_rsp()
|
||||
// if !is_main {
|
||||
g.sub8(.rsp, 0x10)
|
||||
// }
|
||||
locals_count := node.scope.objects.len + node.params.len
|
||||
stackframe_size := (locals_count * 8) + 0x10
|
||||
g.sub8(.rsp, stackframe_size)
|
||||
|
||||
if node.params.len > 0 {
|
||||
// g.mov(.r12, 0x77777777)
|
||||
}
|
||||
@ -656,7 +1062,7 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
||||
g.allocate_var(name, 4, 0)
|
||||
// `mov DWORD PTR [rbp-0x4],edi`
|
||||
offset += 4
|
||||
g.mov_reg_to_rbp(offset, native.fn_arg_registers[i])
|
||||
g.mov_reg_to_var(offset, native.fn_arg_registers[i])
|
||||
}
|
||||
//
|
||||
g.stmts(node.stmts)
|
||||
@ -664,10 +1070,11 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
|
||||
// println('end of main: gen exit')
|
||||
zero := ast.IntegerLiteral{}
|
||||
g.gen_exit(zero)
|
||||
g.ret()
|
||||
return
|
||||
}
|
||||
// g.leave()
|
||||
g.add8(.rsp, 0x10)
|
||||
g.add8(.rsp, stackframe_size)
|
||||
g.pop(.rbp)
|
||||
g.ret()
|
||||
}
|
||||
@ -676,7 +1083,13 @@ pub fn (mut x Amd64) allocate_var(name string, size int, initial_val int) {
|
||||
// do nothing as interface call is crashing
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) {
|
||||
pub fn (mut g Gen) allocate_array(name string, size int, items int) int {
|
||||
pos := g.allocate_var(name, size, items)
|
||||
g.stack_var_pos += (size * items)
|
||||
return pos
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int {
|
||||
// `a := 3` =>
|
||||
// `move DWORD [rbp-0x4],0x3`
|
||||
match size {
|
||||
@ -709,4 +1122,5 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) {
|
||||
g.write32(initial_val)
|
||||
// println('allocate_var(size=$size, initial_val=$initial_val)')
|
||||
g.println('mov DWORD [rbp-$n.hex2()],$initial_val (Allocate var `$name`)')
|
||||
return g.stack_var_pos
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ fn (mut g Gen) write_string_with_padding(s string, max int) {
|
||||
fn (mut g Gen) get_var_offset(var_name string) int {
|
||||
offset := g.var_offset[var_name]
|
||||
if offset == 0 {
|
||||
panic('0 offset for var `$var_name`')
|
||||
verror('unknown variable `$var_name`')
|
||||
}
|
||||
return offset
|
||||
}
|
||||
@ -235,13 +235,24 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, newline bool) {
|
||||
g.gen_print(expr.val)
|
||||
}
|
||||
}
|
||||
else {}
|
||||
ast.CallExpr {
|
||||
g.call_fn(expr)
|
||||
g.gen_print_reg(.rax, 3)
|
||||
}
|
||||
ast.Ident {
|
||||
g.expr(expr)
|
||||
g.gen_print_reg(.rax, 3)
|
||||
}
|
||||
else {
|
||||
dump(expr)
|
||||
verror('expected string as argument for print')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) register_function_address(name string) {
|
||||
addr := g.pos()
|
||||
// println('reg fn addr $name $addr')
|
||||
// eprintln('register function $name = $addr')
|
||||
g.fn_addr[name] = addr
|
||||
}
|
||||
|
||||
@ -325,10 +336,36 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
||||
g.write8(b)
|
||||
}
|
||||
}
|
||||
ast.Module {}
|
||||
ast.Module {
|
||||
eprintln('module')
|
||||
dump(node)
|
||||
}
|
||||
ast.Return {
|
||||
zero := ast.IntegerLiteral{}
|
||||
g.gen_exit(zero)
|
||||
// dump(node.exprs[0])
|
||||
// if in main
|
||||
// zero := ast.IntegerLiteral{}
|
||||
// g.gen_exit(zero)
|
||||
dump(node)
|
||||
dump(node.types)
|
||||
mut s := '?' //${node.exprs[0].val.str()}'
|
||||
e0 := node.exprs[0]
|
||||
match e0 {
|
||||
ast.IntegerLiteral {
|
||||
// TODO
|
||||
}
|
||||
ast.StringLiteral {
|
||||
s = e0.val.str()
|
||||
eprintln('jlalala $s')
|
||||
}
|
||||
else {
|
||||
verror('unknown return type')
|
||||
}
|
||||
}
|
||||
g.expr(node.exprs[0])
|
||||
g.mov64(.rax, g.allocate_string(s, 2))
|
||||
// intel specific
|
||||
g.add8(.rsp, 0x20) // XXX depends on scope frame size
|
||||
g.pop(.rbp)
|
||||
g.ret()
|
||||
}
|
||||
ast.StructDecl {}
|
||||
@ -342,7 +379,9 @@ fn C.strtol(str &char, endptr &&char, base int) int
|
||||
|
||||
fn (mut g Gen) expr(node ast.Expr) {
|
||||
match node {
|
||||
ast.ArrayInit {}
|
||||
ast.ArrayInit {
|
||||
verror('array init expr not supported yet')
|
||||
}
|
||||
ast.BoolLiteral {}
|
||||
ast.CallExpr {
|
||||
if node.name == 'exit' {
|
||||
@ -391,6 +430,8 @@ fn (mut g Gen) postfix_expr(node ast.PostfixExpr) {
|
||||
}
|
||||
}
|
||||
|
||||
// not yet supported
|
||||
[noreturn]
|
||||
fn verror(s string) {
|
||||
util.verror('native gen error', s)
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ fn test_add() {
|
||||
y := 3
|
||||
sum := x + y
|
||||
product := x * y
|
||||
diff := y - x
|
||||
// diff := y - x
|
||||
print_number(x)
|
||||
print_number(y)
|
||||
print_number(sum)
|
||||
|
Loading…
Reference in New Issue
Block a user