native: support more arithmetic, int/string arrays, function returns and internal_strlen (#10279)

pull/10374/head
pancake 2021-06-06 15:19:10 +02:00 committed by GitHub
parent 04e77419cc
commit 012f866619
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 512 additions and 54 deletions

View File

@ -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

View File

@ -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) mul_reg(a Register, b Register) {
if a != .rax {
panic('mul always operates on rax')
}
match b {
.rax {
g.write8(0x48)
g.write8(0xf7)
g.write8(0xe8)
g.println('mul $a')
}
.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) {
match a {
.rbp {
if a == .rbp && b == .rsp {
g.write8(0x48)
g.write8(0x89)
}
else {}
} 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())
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) {
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
}

View File

@ -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)
}

View File

@ -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)