From 1b721250e09d72b2f8505752b7099f35f1e2a1cf Mon Sep 17 00:00:00 2001 From: Spydr <58859306+Spydr06@users.noreply.github.com> Date: Mon, 31 Oct 2022 16:43:02 +0100 Subject: [PATCH] native: enable printing for all supported expressions (#16270) --- vlib/v/gen/native/amd64.v | 11 +- vlib/v/gen/native/gen.v | 170 ++++++++++++--------------- vlib/v/gen/native/tests/print.vv | 28 ++++- vlib/v/gen/native/tests/print.vv.out | 7 +- 4 files changed, 112 insertions(+), 104 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 080dc0c1b5..b4f78924ba 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -1225,9 +1225,8 @@ pub fn (mut g Gen) inline_strlen(r Register) { // TODO: strlen of string at runtime pub fn (mut g Gen) gen_print_reg(r Register, n int, fd int) { - mystrlen := true // if n < 0 maybe? g.mov_reg(.rsi, r) - if mystrlen { + if n < 0 { g.inline_strlen(.rsi) g.mov_reg(.rdx, .rax) } else { @@ -2621,14 +2620,6 @@ fn (mut g Gen) trap() { g.println('trap') } -fn (mut g Gen) gen_asm_stmt(asm_node ast.AsmStmt) { - if g.pref.arch == .arm64 { - g.gen_asm_stmt_arm64(asm_node) - } else { - g.gen_asm_stmt_amd64(asm_node) - } -} - fn (mut g Gen) gen_asm_stmt_amd64(asm_node ast.AsmStmt) { // inline assembly using vasm g.println('// asm inline') diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 935607f993..f71eb001de 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -660,11 +660,11 @@ fn (mut g Gen) eval_escape_codes(str_lit ast.StringLiteral) string { // skip \ i++ match str[i] { - `\\` { - buffer << `\\` + `\\`, `'`, `"` { + buffer << str[i] i++ } - `a` | `b` | `f` { + `a`, `b`, `f` { buffer << str[i] - u8(90) i++ } @@ -720,6 +720,33 @@ fn (mut g Gen) eval_escape_codes(str_lit ast.StringLiteral) string { return buffer.bytestr() } +fn (mut g Gen) gen_to_string(reg Register, typ ast.Type) { + if typ.is_int() { + buffer := g.allocate_array('itoa-buffer', 1, 32) // 32 characters should be enough + g.lea_var_to_reg(g.get_builtin_arg_reg('int_to_string', 1), buffer) + + arg0_reg := g.get_builtin_arg_reg('int_to_string', 0) + if arg0_reg != reg { + g.mov_reg(arg0_reg, reg) + } + + g.call_builtin('int_to_string') + g.lea_var_to_reg(.rax, buffer) + } else if typ.is_bool() { + arg_reg := g.get_builtin_arg_reg('bool_to_string', 0) + if arg_reg != reg { + g.mov_reg(arg_reg, reg) + } + g.call_builtin('bool_to_string') + } else if typ.is_string() { + if reg != .rax { + g.mov_reg(.rax, reg) + } + } else { + g.n_error('int-to-string conversion not implemented for type $typ') + } +} + fn (mut g Gen) gen_var_to_string(reg Register, var Var, config VarConfig) { typ := g.get_type_from_var(var) if typ.is_int() { @@ -738,7 +765,7 @@ fn (mut g Gen) gen_var_to_string(reg Register, var Var, config VarConfig) { } } -pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) { +pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) { newline := name in ['println', 'eprintln'] fd := if name in ['eprint', 'eprintln'] { 2 } else { 1 } match expr { @@ -750,70 +777,66 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) { g.gen_print(str, fd) } } - ast.CallExpr { - g.call_fn(expr) - g.gen_print_reg(.rax, 3, fd) - } ast.Ident { vo := g.try_var_offset(expr.name) if vo != -1 { g.gen_var_to_string(.rax, expr as ast.Ident) - g.gen_print_reg(.rax, 3, fd) + g.gen_print_reg(.rax, -1, fd) if newline { g.gen_print('\n', fd) } } else { - g.gen_print_reg(.rax, 3, fd) + g.gen_print_reg(.rax, -1, fd) } } ast.IntegerLiteral { - g.learel(.rax, g.allocate_string('$expr.val\n', 3, .rel32)) - g.gen_print_reg(.rax, 3, fd) + if newline { + g.gen_print('$expr.val\n', fd) + } else { + g.gen_print('$expr.val', fd) + } } ast.BoolLiteral { // register 'true' and 'false' strings // g.expr(expr) // XXX mov64 shuoldnt be used for addressing + nl := if newline { '\n' } else { '' } + if expr.val { - g.learel(.rax, g.allocate_string('true', 3, .rel32)) + g.gen_print('true' + nl, fd) } else { - g.learel(.rax, g.allocate_string('false', 3, .rel32)) + g.gen_print('false' + nl, fd) + } + } + ast.SizeOf { + size := g.get_type_size(expr.typ) + if newline { + g.gen_print('$size\n', fd) + } else { + g.gen_print('$size', fd) } - g.gen_print_reg(.rax, 3, fd) } - ast.SizeOf {} ast.OffsetOf { styp := g.typ(expr.struct_type) field_name := expr.field if styp.kind == .struct_ { off := g.get_field_offset(expr.struct_type, field_name) - g.learel(.rax, g.allocate_string('$off\n', 3, .rel32)) - g.gen_print_reg(.rax, 3, fd) + if newline { + g.gen_print('$off\n', fd) + } else { + g.gen_print('$off', fd) + } } else { g.v_error('_offsetof expects a struct Type as first argument', expr.pos) } } - ast.None {} - ast.EmptyExpr { - g.n_error('unhandled EmptyExpr') - } - ast.PostfixExpr {} - ast.PrefixExpr {} - ast.SelectorExpr { - // struct.field - g.expr(expr) - g.gen_print_reg(.rax, 3, fd) - /* - field_name := expr.field_name -g.expr - if expr.is_mut { - // mutable field access (rw) + ast.None { + if newline { + g.gen_print('\n', fd) + } else { + g.gen_print('', fd) } - */ - dump(expr) - g.v_error('struct.field selector not yet implemented for this backend', expr.pos) } - ast.NodeError {} ast.AtExpr { if newline { g.gen_print(g.comptime_at(expr) + '\n', fd) @@ -821,54 +844,6 @@ g.expr g.gen_print(g.comptime_at(expr), fd) } } - /* - ast.AnonFn {} - ast.ArrayDecompose {} - ast.ArrayInit {} - ast.AsCast {} - ast.Assoc {} - ast.CTempVar {} - ast.CastExpr {} - ast.ChanInit {} - ast.CharLiteral {} - ast.Comment {} - ast.ComptimeCall {} - ast.ComptimeSelector {} - ast.ConcatExpr {} - ast.DumpExpr {} - ast.EnumVal {} - ast.GoExpr {} - ast.IfGuardExpr {} - ast.IndexExpr {} - ast.InfixExpr {} - ast.IsRefType {} - ast.MapInit {} - ast.OrExpr {} - ast.ParExpr {} - ast.RangeExpr {} - ast.SelectExpr {} - ast.SqlExpr {} - ast.TypeNode {} - */ - ast.MatchExpr { - g.gen_match_expr(expr) - } - ast.TypeOf { - g.gen_typeof_expr(expr, newline) - } - ast.LockExpr { - // passthru - eprintln('Warning: locks not implemented yet in the native backend') - g.expr(expr) - } - ast.Likely { - // passthru - g.expr(expr) - } - ast.UnsafeExpr { - // passthru - g.expr(expr) - } ast.StringInterLiteral { g.n_error('Interlaced string literals are not yet supported in the native backend.') // , expr.pos) } @@ -877,7 +852,7 @@ g.expr if stmts := g.comptime_conditional(expr) { for i, stmt in stmts { if i + 1 == stmts.len && stmt is ast.ExprStmt { - g.gen_print_from_expr(stmt.expr, name) + g.gen_print_from_expr(stmt.expr, stmt.typ, name) } else { g.stmt(stmt) } @@ -886,14 +861,16 @@ g.expr g.n_error('nothing to print') } } else { - g.n_error('non-comptime if exprs not yet implemented') + g.n_error('non-comptime conditionals are not implemented yet.') } } else { - dump(typeof(expr).name) - dump(expr) - // g.v_error('expected string as argument for print', expr.pos) - g.n_error('expected string as argument for print') // , expr.pos) + g.expr(expr) + g.gen_to_string(.rax, typ) + g.gen_print_reg(.rax, -1, fd) + if newline { + g.gen_print('\n', fd) + } } } } @@ -1244,6 +1221,14 @@ fn (mut g Gen) stmt(node ast.Stmt) { } } +fn (mut g Gen) gen_asm_stmt(asm_node ast.AsmStmt) { + if g.pref.arch == .arm64 { + g.gen_asm_stmt_arm64(asm_node) + } else { + g.gen_asm_stmt_amd64(asm_node) + } +} + fn C.strtol(str &char, endptr &&char, base int) int fn (mut g Gen) gen_syscall(node ast.CallExpr) { @@ -1321,7 +1306,8 @@ fn (mut g Gen) expr(node ast.Expr) { g.gen_exit(node.args[0].expr) } else if node.name in ['println', 'print', 'eprintln', 'eprint'] { expr := node.args[0].expr - g.gen_print_from_expr(expr, node.name) + typ := node.args[0].typ + g.gen_print_from_expr(expr, typ, node.name) } else { g.call_fn(node) } diff --git a/vlib/v/gen/native/tests/print.vv b/vlib/v/gen/native/tests/print.vv index 35c953f51f..b2db7814db 100644 --- a/vlib/v/gen/native/tests/print.vv +++ b/vlib/v/gen/native/tests/print.vv @@ -31,7 +31,7 @@ fn test_stderr() { fn test_idents() { // signed integer - + x := 0 println(x) @@ -70,10 +70,36 @@ fn test_idents() { println(r'hello\tworld\n') } +fn test_exprs() { + t := true + print(t == false) + print(' ') + println(t == true) + + i := 123 + println(i + 456) + + j := 2 + println(j + j * j) + + println(none) +} + +fn test_sizeof() { + i := 0 + + print('sizeof: ') + print(sizeof(i)) + print(', ') + println(sizeof(Foo)) +} + fn main() { test_stdout() test_stderr() test_numbers() test_oof() test_idents() + test_exprs() + test_sizeof() } diff --git a/vlib/v/gen/native/tests/print.vv.out b/vlib/v/gen/native/tests/print.vv.out index b9e1877cf1..f66e535748 100644 --- a/vlib/v/gen/native/tests/print.vv.out +++ b/vlib/v/gen/native/tests/print.vv.out @@ -13,4 +13,9 @@ false string blah blah blah ๐Ÿ˜€๐Ÿ˜†๐Ÿ˜Ž๐Ÿ’ป๐ŸŒŽ ใ“ใ‚“ใซใกใฏ -hello\tworld\n \ No newline at end of file +hello\tworld\n +false true +579 +6 + +sizeof: 4, 12