diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 9f047968db..00133d930a 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -641,6 +641,31 @@ pub fn (mut g Gen) gen_amd64_exit(expr ast.Expr) { g.trap() // should never be reached, just in case } +fn (mut g Gen) relpc(dst Register, src Register) { + // 488d1d 00000000 lea 0(%rip),%dst + // 4801d8 add %dst, %src + match dst { + .rax { + match src { + .rsi { + g.write([byte(0x48), 0x8d, 0x35, 0x00, 0x00, 0x00, 0x00]) // lea rsi, rip + g.write([byte(0x48), 0x01, 0xf0]) // add rax, rsi + } + .rbx { + g.write([byte(0x48), 0x8d, 0x1d, 0x00, 0x00, 0x00, 0x00]) + g.write([byte(0x48), 0x01, 0xd8]) + } + else { + panic('relpc requires .rax, {.rsi,.rbx}') + } + } + } + else { + panic('relpc requires .rax, {.rsi,.rbx}') + } + } +} + fn (mut g Gen) learel(reg Register, val int) { g.write8(0x48) g.write8(0x8d) @@ -848,7 +873,9 @@ fn (mut g Gen) add_reg(a Register, b Register) { } fn (mut g Gen) mov_reg(a Register, b Register) { - if a == .rbp && b == .rsp { + if a == .rax && b == .rsi { + g.write([byte(0x48), 0x89, 0xf0]) + } else if a == .rbp && b == .rsp { g.write8(0x48) g.write8(0x89) } else if a == .rdx && b == .rax { @@ -1024,26 +1051,26 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) { /* ast.int_type_idx { g.expr(node.left[i]) -match node.left[i] { -ast.IndexExpr { - ie := node.left[i] as ast.IndexExpr - bracket := name.index('[') or { - g.v_error('bracket expected', node.pos) - exit(1) + match node.left[i] { + ast.IndexExpr { + ie := node.left[i] as ast.IndexExpr + bracket := name.index('[') or { + g.v_error('bracket expected', node.pos) + 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 { + dump(node) + g.v_error('oops', node.pos) + } } - 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 { -dump(node) -g.v_error('oops', node.pos) -} -} } */ else { @@ -1130,6 +1157,7 @@ g.v_error('oops', node.pos) pos += 8 } ast.StringLiteral { + // TODO: use learel g.mov64(.rsi, g.allocate_string('$e.val', 2, .abs64)) // for rsi its 2 g.mov_reg_to_var(pos, .rsi) pos += 8 @@ -1169,7 +1197,7 @@ g.v_error('oops', node.pos) 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, .abs64)) // for rsi its 2 + g.learel(.rsi, g.allocate_string(ie.val.str(), 3, .rel32)) g.mov_reg_to_var(dest, .rsi) } ast.CallExpr { @@ -1178,6 +1206,9 @@ g.v_error('oops', node.pos) g.mov_reg_to_var(dest, .rax) g.mov_var_to_reg(.rsi, dest) } + ast.SelectorExpr { + g.v_error('unhandled selectors', node.pos) + } ast.GoExpr { g.v_error('threads not implemented for the native backend', node.pos) } @@ -1195,6 +1226,14 @@ g.v_error('oops', node.pos) } } } + ast.FloatLiteral { + g.v_error('floating point arithmetic not yet implemented for the native backend', + node.pos) + } + ast.TypeOf { + g.gen_typeof_expr(node.right[i] as ast.TypeOf, true) + g.mov_reg(.rsi, .rax) + } else { // dump(node) g.v_error('unhandled assign_stmt expression: $right.type_name()', right.pos()) @@ -1286,9 +1325,11 @@ fn (mut g Gen) gen_asm_stmt_amd64(asm_node ast.AsmStmt) { } ast.AsmDisp { } - ast.FloatLiteral { - } */ + ast.FloatLiteral { + g.v_error('floating point arithmetic is not yet implemented for the native backend', + asm_node.pos) + } string { // XXX g.v_error('no strings allowed in this context', asm_node.pos) @@ -1630,6 +1671,6 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int { // Generate the value assigned to the variable g.write32(initial_val) // println('allocate_var(size=$size, initial_val=$initial_val)') - g.println('mov [rbp-$n.hex2()], $initial_val (Allocate var `$name`)') + g.println('mov [rbp-$n.hex2()], $initial_val ; Allocate var `$name`') return g.stack_var_pos } diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index e599b0278b..bd3ae37e54 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -157,7 +157,7 @@ pub fn (mut g Gen) create_executable() { os.write_file_array(g.out_name, g.buf) or { panic(err) } os.chmod(g.out_name, 0o775) or { panic(err) } // make it executable if g.pref.is_verbose { - println('\n$g.out_name: native binary has been successfully generated') + eprintln('\n$g.out_name: native binary has been successfully generated') } } @@ -277,14 +277,28 @@ 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] +fn (mut g Gen) try_var_offset(var_name string) int { + offset := g.var_offset[var_name] or { return -1 } if offset == 0 { - g.n_error('unknown variable `$var_name`') + return -1 } return offset } +fn (mut g Gen) get_var_offset(var_name string) int { + r := g.try_var_offset(var_name) + if r == -1 { + g.n_error('unknown variable `$var_name`') + } + return r +} + +fn (mut g Gen) gen_typeof_expr(it ast.TypeOf, newline bool) { + nl := if newline { '\n' } else { '' } + r := g.typ(it.expr_type).name + g.learel(.rax, g.allocate_string('$r$nl', 3, .rel32)) +} + 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 } @@ -301,13 +315,17 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) { g.gen_print_reg(.rax, 3, fd) } ast.Ident { - g.n_error('Printing idents is not yet supported in the native backend') - /* - vo := g.get_var_offset(expr.name) - g.mov_var_to_reg(.rax, vo) - //g.expr(expr) + 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_print_reg(.rax, 3, fd) - */ } ast.IntegerLiteral { g.learel(.rax, g.allocate_string('$expr.val\n', 3, .rel32)) @@ -394,8 +412,10 @@ g.expr ast.SelectExpr {} ast.SqlExpr {} ast.TypeNode {} - ast.TypeOf {} */ + ast.TypeOf { + g.gen_typeof_expr(expr, newline) + } ast.LockExpr { // passthru eprintln('Warning: locks not implemented yet in the native backend') @@ -728,7 +748,10 @@ fn (mut g Gen) expr(node ast.Expr) { } ast.FloatLiteral {} ast.Ident { - offset := g.get_var_offset(node.obj.name) // i := 0 + offset := g.try_var_offset(node.obj.name) // i := 0 + if offset == -1 { + g.n_error('invalid ident $node.obj.name') + } // offset := g.get_var_offset(node.name) // XXX this is intel specific g.mov_var_to_reg(.rax, offset) diff --git a/vlib/v/gen/native/tests/typeof.vv b/vlib/v/gen/native/tests/typeof.vv new file mode 100644 index 0000000000..5d99730e46 --- /dev/null +++ b/vlib/v/gen/native/tests/typeof.vv @@ -0,0 +1,16 @@ + + +fn main() { + a := 'string' + t := typeof(a) + println(t) + t2 := typeof('another string') + println(t2) + n := 123 + t3 := typeof(n) + println(t3) + t4 := typeof(123) + println(t4) +// id := 'hello world' +// println(id) +} diff --git a/vlib/v/gen/native/tests/typeof.vv.out b/vlib/v/gen/native/tests/typeof.vv.out new file mode 100644 index 0000000000..0fc858b170 --- /dev/null +++ b/vlib/v/gen/native/tests/typeof.vv.out @@ -0,0 +1,4 @@ +string +string +int +int literal