From 8563696476b50c5fb9c260bf5e546268bd00cea4 Mon Sep 17 00:00:00 2001 From: Spydr <58859306+Spydr06@users.noreply.github.com> Date: Wed, 8 Jun 2022 22:16:15 +0200 Subject: [PATCH] native: added new helper functions (#14723) --- vlib/v/gen/native/amd64.v | 191 ++++++++++++++++++++++++++++++- vlib/v/gen/native/gen.v | 25 ++-- vlib/v/gen/native/tests/print.vv | 6 + 3 files changed, 211 insertions(+), 11 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index a059a46e3c..ae7c80bfe4 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -135,6 +135,24 @@ fn (mut g Gen) cmp_reg(reg Register, reg2 Register) { g.println('cmp $reg, $reg2') } +// cmp $reg, 0 +fn (mut g Gen) cmp_zero(reg Register) { + g.write8(0x48) + g.write8(0x39) + + match reg { + .rax { + g.write8(0x04) + g.write8(0x25) + } + else { + panic('unhandled cmp $reg, 0') + } + } + + g.write32(0) +} + fn (mut g Gen) cmp_var_reg(var_name string, reg Register) { g.write8(0x48) // 83 for 1 byte? g.write8(0x39) @@ -225,6 +243,26 @@ fn (mut g Gen) jmp(addr i64) { g.write8(offset) } */ + +fn (mut g Gen) mov32(reg Register, val int) { + match reg { + .rax { + g.write8(0xb8) + } + .rdi { + g.write8(0xbf) + } + .rcx { + g.write8(0xb9) + } + else { + panic('unhandled mov32 $reg') + } + } + g.write32(val) + g.println('mov32 $reg, $val') +} + fn (mut g Gen) mov64(reg Register, val i64) { match reg { .eax { @@ -272,6 +310,21 @@ fn (mut g Gen) mov64(reg Register, val i64) { g.println('mov64 $reg, $val') } +fn (mut g Gen) movabs(reg Register, val i64) { + match reg { + .rsi { + g.write8(0x48) + g.write8(0xbe) + } + else { + panic('unhandled movabs $reg, $val') + } + } + + g.write64(val) + g.println('movabs $reg, $val') +} + fn (mut g Gen) mov_reg_to_var(var_offset int, reg Register) { // 89 7d fc mov DWORD PTR [rbp-0x4],edi match reg { @@ -293,6 +346,27 @@ fn (mut g Gen) mov_reg_to_var(var_offset int, reg Register) { g.println('mov DWORD PTR[rbp-$var_offset.hex2()],$reg') } +fn (mut g Gen) lea_var_to_reg(reg Register, var_offset int) { + match reg { + .rax, .rbx, .rsi { + g.write8(0x48) + } + else {} + } + g.write8(0x8d) + 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 { g.n_error('lea_var_to_reg $reg') } + } + g.write8(0xff - var_offset + 1) + g.println('lea $reg, [rbp-$var_offset.hex2()]') +} + fn (mut g Gen) mov_var_to_reg(reg Register, var_offset int) { // 8b 7d f8 mov edi,DWORD PTR [rbp-0x8] match reg { @@ -473,6 +547,21 @@ pub fn (mut g Gen) allocate_string(s string, opsize int, typ RelocType) int { return str_pos } +pub fn (mut g Gen) var_zero(vo int, size int) { + g.mov32(.rcx, size) + g.lea_var_to_reg(.rdi, vo) + g.write8(0xb0) + g.write8(0x00) + g.println('mov al, 0') + g.rep_stosb() +} + +pub fn (mut g Gen) rep_stosb() { + g.write8(0xf3) + g.write8(0xaa) + g.println('rep stosb') +} + pub fn (mut g Gen) cld_repne_scasb() { g.write8(0xfc) g.println('cld') @@ -500,6 +589,20 @@ pub fn (mut g Gen) xor(r Register, v int) { } } +pub fn (mut g Gen) test_reg(r Register) { + match r { + .rdi { + g.write8(0x48) + g.write8(0x85) + g.write8(0xff) + g.println('test rdi, rdi') + } + else { + panic('unhandled test $r, $r') + } + } +} + // return length in .rax of string pointed by given register pub fn (mut g Gen) inline_strlen(r Register) { g.mov_reg(.rdi, r) @@ -676,8 +779,11 @@ fn (mut g Gen) learel(reg Register, val int) { .rsi { g.write8(0x35) } + .rcx { + g.write8(0x0d) + } else { - g.n_error('learel must use rsi or rax') + g.n_error('learel must use rsi, rcx or rax') } } g.write32(val) @@ -823,6 +929,20 @@ fn (mut g Gen) mul_reg(a Register, b Register) { g.println('mul $a') } +fn (mut g Gen) imul_reg(r Register) { + match r { + .rsi { + g.write8(0x48) + g.write8(0xf7) + g.write8(0xee) + g.println('imul $r') + } + else { + panic('unhandled imul $r') + } + } +} + fn (mut g Gen) div_reg(a Register, b Register) { if a != .rax { panic('div always operates on rax') @@ -846,11 +966,24 @@ fn (mut g Gen) div_reg(a Register, b Register) { g.println('div $a') } +fn (mut g Gen) mod_reg(a Register, b Register) { + g.div_reg(a, b) + g.mov_reg(.rdx, .rax) +} + fn (mut g Gen) sub_reg(a Register, b Register) { if a == .rax && b == .rbx { g.write8(0x48) g.write8(0x29) g.write8(0xd8) + } else if a == .rdx && b == .rax { + g.write8(0x48) + g.write8(0x29) + g.write8(0xc2) + } else if a == .rdi && b == .rax { + g.write8(0x48) + g.write8(0x29) + g.write8(0xc7) } else { panic('unhandled add $a, $b') } @@ -866,6 +999,10 @@ fn (mut g Gen) add_reg(a Register, b Register) { g.write8(0x48) g.write8(0x01) g.write8(0xf8) + } else if a == .rax && b == .rax { + g.write8(0x48) + g.write8(0x01) + g.write8(0xc0) } else { panic('unhandled add $a, $b') } @@ -906,12 +1043,39 @@ fn (mut g Gen) mov_reg(a Register, b Register) { g.write8(0x48) g.write8(0x89) g.write8(0xc6) + } else if a == .rdi && b == .rdx { + g.write8(0x48) + g.write8(0x89) + g.write8(0xd7) + } else if a == .rdi && b == .rax { + g.write8(0x48) + g.write8(0x89) + g.write8(0xc7) } else { g.n_error('unhandled mov_reg combination for $a $b') } g.println('mov $a, $b') } +fn (mut g Gen) sar8(r Register, val u8) { + g.write8(0x48) + g.write8(0xc1) + + match r { + .rax { + g.write8(0xf8) + } + .rdx { + g.write8(0xfa) + } + else { + panic('unhandled sar $r, $val') + } + } + g.write8(val) + g.println('sar $r, $val') +} + // generates `mov rbp, rsp` fn (mut g Gen) mov_rbp_rsp() { g.write8(0x48) @@ -1668,9 +1832,32 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int { g.write8(0xff - n + 1) g.stack_var_pos += size g.var_offset[name] = g.stack_var_pos + // Generate the value assigned to the variable - g.write32(initial_val) + match size { + 1 { + g.write8(initial_val) + } + 4 { + g.write32(initial_val) + } + 8 { + g.write32(initial_val) // fixme: 64-bit segfaulting + } + else { + g.n_error('allocate_var: bad size $size') + } + } + // println('allocate_var(size=$size, initial_val=$initial_val)') g.println('mov [rbp-$n.hex2()], $initial_val ; Allocate var `$name`') return g.stack_var_pos } + +fn (mut g Gen) convert_int_to_string(r Register, buffer int) { + if r != .rax { + g.mov_reg(.rax, r) + } + + // TODO +} diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 374e7ea587..b2bcb4311a 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -299,6 +299,12 @@ fn (mut g Gen) gen_typeof_expr(it ast.TypeOf, newline bool) { g.learel(.rax, g.allocate_string('$r$nl', 3, .rel32)) } +fn (mut g Gen) gen_var_to_string(reg Register, vo int) { + buffer := g.allocate_array('itoa-buffer', 1, 32) // 32 characters should be enough + g.convert_int_to_string(reg, buffer) + g.lea_var_to_reg(reg, buffer) +} + pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) { newline := name in ['println', 'eprintln'] fd := if name in ['eprint', 'eprintln'] { 2 } else { 1 } @@ -316,16 +322,15 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) { } ast.Ident { vo := g.try_var_offset(expr.name) + if vo != -1 { - g.n_error('Printing idents is not yet supported in the native backend') - // g.mov_var_to_reg(.rsi, vo) - // g.mov_reg(.rax, .rsi) - // g.learel(.rax, vo * 8) - // g.relpc(.rax, .rsi) - // g.learel(.rax, g.allocate_string('$vo\n', 3, .rel32)) - // g.expr(expr) + g.gen_var_to_string(.rax, vo) + if newline { + g.gen_print('\n', fd) + } + } else { + g.gen_print_reg(.rax, 3, fd) } - g.gen_print_reg(.rax, 3, fd) } ast.IntegerLiteral { g.learel(.rax, g.allocate_string('$expr.val\n', 3, .rel32)) @@ -775,7 +780,9 @@ fn (mut g Gen) expr(node ast.Expr) { ast.PostfixExpr { g.postfix_expr(node) } - ast.StringLiteral {} + ast.StringLiteral { + g.allocate_string(node.val, 3, .rel32) + } ast.StructInit {} ast.GoExpr { g.v_error('native backend doesnt support threads yet', node.pos) diff --git a/vlib/v/gen/native/tests/print.vv b/vlib/v/gen/native/tests/print.vv index e8d96fdaa3..86f297e1d4 100644 --- a/vlib/v/gen/native/tests/print.vv +++ b/vlib/v/gen/native/tests/print.vv @@ -29,9 +29,15 @@ fn test_stderr() { eprintln('2(World)') } +fn test_idents() { + x := 5 + // println(x) uncomment again when int-to-string conversion is working +} + fn main() { test_stdout() test_stderr() test_numbers() test_oof() + test_idents() }