From be9b840400b2c0a375363f301e3f86d2698f0d9d Mon Sep 17 00:00:00 2001 From: Spydr06 Date: Sun, 26 Mar 2023 11:40:07 +0200 Subject: [PATCH 1/5] checker: enable builtin module for the native backend --- vlib/v/builder/nativebuilder/nativebuilder.v | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vlib/v/builder/nativebuilder/nativebuilder.v b/vlib/v/builder/nativebuilder/nativebuilder.v index 84fedf36970822..a928962aabb68d 100644 --- a/vlib/v/builder/nativebuilder/nativebuilder.v +++ b/vlib/v/builder/nativebuilder/nativebuilder.v @@ -13,8 +13,9 @@ pub fn start() { } pub fn compile_native(mut b builder.Builder) { - // v.files << v.v_files_from_dir(os.join_path(v.pref.vlib_path,'builtin','bare')) - files := [b.pref.path] + mut files := b.get_builtin_files() + files << b.pref.path + b.set_module_lookup_paths() build_native(mut b, files, b.pref.out_name) } From e0819b89bbfba694db60eb3a098279e422f6bf22 Mon Sep 17 00:00:00 2001 From: Spydr06 Date: Sun, 26 Mar 2023 14:40:45 +0200 Subject: [PATCH 2/5] native: remove errors for debugging purposes --- vlib/v/gen/native/amd64.v | 112 +++++++++++++++++++++++++++++++------- vlib/v/gen/native/gen.v | 69 ++++++++++++++++++++--- 2 files changed, 153 insertions(+), 28 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 27302b8c799ed7..adda751b760b01 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -508,9 +508,9 @@ fn (mut g Gen) movabs(reg Register, val i64) { fn (mut g Gen) mov_deref(reg Register, regptr Register, typ ast.Type) { size := g.get_type_size(typ) - if size !in [1, 2, 4, 8] { - g.n_error('Invalid size on dereferencing') - } + //if size !in [1, 2, 4, 8] { + // g.n_error('Invalid size on dereferencing') + //} is_signed := !typ.is_real_pointer() && typ.is_signed() rex := int(reg) / 8 * 4 + int(regptr) / 8 if size == 4 && !is_signed { @@ -615,7 +615,7 @@ fn (mut g Gen) mov_reg_to_var(var Var, reg Register, config VarConfig) { g.write8(0x89) size_str = 'DWORD' } else { - g.n_error('unsupported type for mov_reg_to_var') + //g.n_error('unsupported type for mov_reg_to_var') } } } @@ -1327,7 +1327,7 @@ pub fn (mut g Gen) gen_amd64_exit(expr ast.Expr) { g.mov(.edi, expr.val.int()) } else { - g.n_error('native builtin exit expects a numeric argument') + // g.n_error('native builtin exit expects a numeric argument') } } if g.pref.os == .windows { @@ -1521,8 +1521,14 @@ fn (mut g Gen) mul_reg(a Register, b Register) { g.write8(0xf7) g.write8(0xeb) } + .rdx { + g.write8(0x48) + g.write8(0x0f) + g.write8(0xaf) + g.write8(0xd0) + } else { - panic('unhandled div ${a}') + panic('unhandled mul ${b}') } } g.println('mul ${a}') @@ -1557,9 +1563,12 @@ fn (mut g Gen) div_reg(a Register, b Register) { g.write8(0x48) g.write8(0xf7) g.write8(0xfb) // idiv ebx + } + .rdx { + } else { - panic('unhandled div ${a}') + panic('unhandled div ${b}') } } g.println('div ${a}') @@ -2084,7 +2093,7 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam } } else { - g.n_error('Unsupported variable type') + //g.n_error('Unsupported variable type') } } } @@ -2190,7 +2199,7 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam g.init_struct(ident, right) } else { - g.n_error('Unexpected operator `${node.op}`') + //g.n_error('Unexpected operator `${node.op}`') } } } @@ -2214,7 +2223,7 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam } else { dump(e) - g.n_error('unhandled array init type') + //g.n_error('unhandled array init type ${e}') } } } @@ -2226,6 +2235,10 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam println('infix assignment ${name} offset=${offset.hex2()}') } ie := right as ast.IndexExpr + if ie.left !is ast.Ident { + println('ie.left is not ast.Ident, got: ${ie}') + return + } var := ie.left as ast.Ident dest := g.get_var_offset(var.name) if ie.index is ast.IntegerLiteral { @@ -2239,7 +2252,7 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam g.add_reg(.rax, .rdi) g.mov_deref(.rax, .rax, ast.i64_type_idx) } else { - g.n_error('only integers and idents can be used as indexes') + // g.n_error('only integers and idents can be used as indexes') } // TODO check if out of bounds access g.mov_reg_to_var(ident, .eax) @@ -2262,6 +2275,40 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam dest := g.allocate_var(name, 8, 0) g.learel(.rsi, g.allocate_string(g.comptime_at(right), 3, .rel32)) g.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, .rsi) + } + ast.CastExpr { + // TODO: generate cast expression + g.assign_right_expr(node, i, (right as ast.CastExpr).expr, name, ident) + return + } + ast.UnsafeExpr { + g.assign_right_expr(node, i, (right as ast.UnsafeExpr).expr, name, ident) + return + } + ast.CallExpr { + // TODO: implement + + } + ast.IfExpr { + // TODO + } + ast.MapInit { + // TODO + } + ast.InfixExpr { + // TODO + } + ast.ParExpr { + // TODO + } + ast.SelectorExpr { + // TODO + } + ast.PrefixExpr { + + } + ast.StringInterLiteral { + } else { if right is ast.IfExpr && (right as ast.IfExpr).is_comptime { @@ -2476,7 +2523,7 @@ fn (mut g Gen) multi_assign_stmt(node ast.AssignStmt) { }) } else { - g.n_error('Unsupported assign instruction') + g.n_error('Unsupported assign instruction ${node.op}') } } } else if left_type.is_pure_float() { @@ -2514,7 +2561,7 @@ fn (mut g Gen) multi_assign_stmt(node ast.AssignStmt) { g.println('movsd [rax], xmm0') } } else { - g.n_error('multi return for struct is not supported yet') + //g.n_error('multi return for struct is not supported yet') } } } @@ -2556,7 +2603,7 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) { }) } else { - g.n_error('Unsupported assign instruction') + //g.n_error('Unsupported assign instruction ${node.op}') } } } else if typ.is_pure_float() { @@ -2807,7 +2854,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { g.div_sse(.xmm0, .xmm1, typ) } else { - g.n_error('`${node.op}` expression is not supported right now') + // g.n_error('`${node.op}` expression is not supported right now') } } return @@ -2830,7 +2877,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { }) } } - if node.left_type !in ast.integer_type_idxs && node.left_type != ast.bool_type_idx + if node.left_type !in ast.integer_type_idxs && node.left_type != ast.bool_type_idx && node.op != .left_shift && node.op != .plus && node.op != .ne && node.op != .eq && g.table.sym(node.left_type).info !is ast.Enum { g.n_error('unsupported type for `${node.op}`: ${node.left_type}') } @@ -2900,7 +2947,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { g.shr_reg(.rax, .rcx) } else { - g.n_error('`${node.op}` expression is not supported right now') + // g.n_error('`${node.op}` expression is not supported right now') } } } @@ -3175,6 +3222,10 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) { g.println('; label ${end_label}') return } + if node.cond !is ast.InfixExpr { + println("node.cond is not InfixExpr, got: ${node.cond}") + return + } infix_expr := node.cond as ast.InfixExpr mut jump_addr := 0 // location of `jne *00 00 00 00*` start := g.pos() @@ -3193,7 +3244,7 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) { g.cmp_var(infix_expr.left as ast.Ident, lit.val.int()) } else { - g.n_error('unhandled expression type') + // g.n_error('unhandled expression type: ${infix_expr.right}') } } match infix_expr.left.tok_kind { @@ -3203,13 +3254,22 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) { .gt { jump_addr = g.cjmp(.jle) } + .le { + jump_addr = g.cjmp(.jg) + } + .ge { + jump_addr = g.cjmp(.jl) + } + .ne { + jump_addr = g.cjmp(.je) + } else { - g.n_error('unhandled infix cond token') + g.n_error('unhandled infix cond token ${infix_expr.left.tok_kind}') } } } else { - g.n_error('unhandled infix.left') + // g.n_error('unhandled infix.left: ${infix_expr.left}') } } end_label := g.labels.new_label() @@ -3388,6 +3448,9 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int { // BYTE g.write8(0xc6) g.write8(0x45 + far_var_offset) + } + 2 { + } 4 { // DWORD @@ -3400,6 +3463,9 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int { g.write8(0xc7) g.write8(0x45 + far_var_offset) } + 16 { + //TODO + } else { g.n_error('allocate_var: bad size ${size}') } @@ -3418,12 +3484,18 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int { match size { 1 { g.write8(initial_val) + } + 2 { + } 4 { g.write32(initial_val) } 8 { g.write32(initial_val) // fixme: 64-bit segfaulting + } + 16 { + } else { g.n_error('allocate_var: bad size ${size}') diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 950b80e341e5b9..537d0f0c6b2b4d 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -158,6 +158,15 @@ type Var = GlobalVar | LocalVar | ast.Ident type IdentVar = GlobalVar | LocalVar | Register fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar { + if ident.name.contains('C.') { + eprintln("found C function id `${ident.name}`, which is not supported right now") + return LocalVar{ + offset: 0 + typ: ast.new_type(2) + name: ident.name + } + } + mut obj := ident.obj if obj !in [ast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister] { obj = ident.scope.find(ident.name) or { g.n_error('unknown variable ${ident.name}') } @@ -172,6 +181,15 @@ fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar { name: obj.name } } + ast.ConstField { + // TODO + eprintln('const fields are not implemented') + return LocalVar{ + offset: 0 + typ: obj.typ + name: obj.name + } + } else { g.n_error('unsupported variable type type:${obj} name:${ident.name}') } @@ -519,14 +537,14 @@ fn (mut g Gen) try_var_offset(var_name string) int { 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}`') + //g.n_error('unknown variable `${var_name}`') } return r } fn (mut g Gen) get_field_offset(typ ast.Type, name string) int { ts := g.table.sym(typ) - field := ts.find_field(name) or { g.n_error('Could not find field `${name}` on init') } + field := ts.find_field(name) or { /*g.n_error('Could not find field `${name}` on init')*/ return 0 } return g.structs[typ.idx()].offsets[field.i] } @@ -890,7 +908,7 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) } } ast.StringInterLiteral { - g.n_error('Interlaced string literals are not yet supported in the native backend.') // , expr.pos) + //g.n_error('Interlaced string literals are not yet supported in the native backend.') // , expr.pos) } ast.IfExpr { if expr.is_comptime { @@ -1001,6 +1019,11 @@ fn (mut g Gen) gen_forc_stmt(node ast.ForCStmt) { // g.infix_expr(node.cond) match cond.left { ast.Ident { + if cond.right !is ast.IntegerLiteral { + println('cond.right is `${cond.right}`') + return + } + lit := cond.right as ast.IntegerLiteral g.cmp_var(cond.left as ast.Ident, lit.val.int()) match cond.op { @@ -1095,7 +1118,8 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { } else if it.kind == .map { */ } else { - g.v_error('for-in statement is not yet implemented', node.pos) + // g.v_error('for-in statement is not yet implemented', node.pos) + // TODO: implement for-in } } @@ -1159,7 +1183,7 @@ fn (mut g Gen) stmt(node ast.Stmt) { words := node.val.split(' ') for word in words { if word.len != 2 { - g.n_error('opcodes format: xx xx xx xx') + //g.n_error('opcodes format: xx xx xx xx') } b := unsafe { C.strtol(&char(word.str), 0, 16) } // b := word.u8() @@ -1426,7 +1450,7 @@ fn (mut g Gen) expr(node ast.Expr) { g.expr(node.expr) } ast.ArrayInit { - g.n_error('array init expr not supported yet') + // g.n_error('array init expr not supported yet') } ast.BoolLiteral { g.mov64(.rax, if node.val { 1 } else { 0 }) @@ -1467,16 +1491,27 @@ fn (mut g Gen) expr(node ast.Expr) { } else if var.typ.is_pure_float() { g.mov_var_to_ssereg(.xmm0, node as ast.Ident) } else { - ts := g.table.sym(var.typ) + mut ts := g.table.sym(var.typ) + + for mut ts.info is ast.Alias { + ts = g.table.sym(ts.info.parent_type) + } + match ts.info { ast.Struct { g.lea_var_to_reg(.rax, g.get_var_offset(node.name)) } + ast.Array { + // TODO: implement array loading + } ast.Enum { g.mov_var_to_reg(.rax, node as ast.Ident, typ: ast.int_type_idx) + } + ast.SumType { + } else { - g.n_error('Unsupported variable type') + //g.n_error('Unsupported variable type ${ts.info}') } } } @@ -1590,6 +1625,24 @@ fn (mut g Gen) expr(node ast.Expr) { } // store the multi return struct value g.lea_var_to_reg(.rax, var.offset) + } + ast.IndexExpr { + + } + ast.CharLiteral { + + } + ast.Nil { + + } + ast.StringInterLiteral { + + } + ast.ArrayDecompose { + + } + ast.SizeOf { + } else { g.n_error('expr: unhandled node type: ${node.type_name()}') From 6f570f06e514572e640b6d2a9aeda69aba4bb1ae Mon Sep 17 00:00:00 2001 From: Spydr06 Date: Sun, 26 Mar 2023 14:42:39 +0200 Subject: [PATCH 3/5] Revert "native: remove errors for debugging purposes" This reverts commit e0819b89bbfba694db60eb3a098279e422f6bf22. --- vlib/v/gen/native/amd64.v | 112 +++++++------------------------------- vlib/v/gen/native/gen.v | 69 +++-------------------- 2 files changed, 28 insertions(+), 153 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index adda751b760b01..27302b8c799ed7 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -508,9 +508,9 @@ fn (mut g Gen) movabs(reg Register, val i64) { fn (mut g Gen) mov_deref(reg Register, regptr Register, typ ast.Type) { size := g.get_type_size(typ) - //if size !in [1, 2, 4, 8] { - // g.n_error('Invalid size on dereferencing') - //} + if size !in [1, 2, 4, 8] { + g.n_error('Invalid size on dereferencing') + } is_signed := !typ.is_real_pointer() && typ.is_signed() rex := int(reg) / 8 * 4 + int(regptr) / 8 if size == 4 && !is_signed { @@ -615,7 +615,7 @@ fn (mut g Gen) mov_reg_to_var(var Var, reg Register, config VarConfig) { g.write8(0x89) size_str = 'DWORD' } else { - //g.n_error('unsupported type for mov_reg_to_var') + g.n_error('unsupported type for mov_reg_to_var') } } } @@ -1327,7 +1327,7 @@ pub fn (mut g Gen) gen_amd64_exit(expr ast.Expr) { g.mov(.edi, expr.val.int()) } else { - // g.n_error('native builtin exit expects a numeric argument') + g.n_error('native builtin exit expects a numeric argument') } } if g.pref.os == .windows { @@ -1521,14 +1521,8 @@ fn (mut g Gen) mul_reg(a Register, b Register) { g.write8(0xf7) g.write8(0xeb) } - .rdx { - g.write8(0x48) - g.write8(0x0f) - g.write8(0xaf) - g.write8(0xd0) - } else { - panic('unhandled mul ${b}') + panic('unhandled div ${a}') } } g.println('mul ${a}') @@ -1563,12 +1557,9 @@ fn (mut g Gen) div_reg(a Register, b Register) { g.write8(0x48) g.write8(0xf7) g.write8(0xfb) // idiv ebx - } - .rdx { - } else { - panic('unhandled div ${b}') + panic('unhandled div ${a}') } } g.println('div ${a}') @@ -2093,7 +2084,7 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam } } else { - //g.n_error('Unsupported variable type') + g.n_error('Unsupported variable type') } } } @@ -2199,7 +2190,7 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam g.init_struct(ident, right) } else { - //g.n_error('Unexpected operator `${node.op}`') + g.n_error('Unexpected operator `${node.op}`') } } } @@ -2223,7 +2214,7 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam } else { dump(e) - //g.n_error('unhandled array init type ${e}') + g.n_error('unhandled array init type') } } } @@ -2235,10 +2226,6 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam println('infix assignment ${name} offset=${offset.hex2()}') } ie := right as ast.IndexExpr - if ie.left !is ast.Ident { - println('ie.left is not ast.Ident, got: ${ie}') - return - } var := ie.left as ast.Ident dest := g.get_var_offset(var.name) if ie.index is ast.IntegerLiteral { @@ -2252,7 +2239,7 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam g.add_reg(.rax, .rdi) g.mov_deref(.rax, .rax, ast.i64_type_idx) } else { - // g.n_error('only integers and idents can be used as indexes') + g.n_error('only integers and idents can be used as indexes') } // TODO check if out of bounds access g.mov_reg_to_var(ident, .eax) @@ -2275,40 +2262,6 @@ fn (mut g Gen) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, nam dest := g.allocate_var(name, 8, 0) g.learel(.rsi, g.allocate_string(g.comptime_at(right), 3, .rel32)) g.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, .rsi) - } - ast.CastExpr { - // TODO: generate cast expression - g.assign_right_expr(node, i, (right as ast.CastExpr).expr, name, ident) - return - } - ast.UnsafeExpr { - g.assign_right_expr(node, i, (right as ast.UnsafeExpr).expr, name, ident) - return - } - ast.CallExpr { - // TODO: implement - - } - ast.IfExpr { - // TODO - } - ast.MapInit { - // TODO - } - ast.InfixExpr { - // TODO - } - ast.ParExpr { - // TODO - } - ast.SelectorExpr { - // TODO - } - ast.PrefixExpr { - - } - ast.StringInterLiteral { - } else { if right is ast.IfExpr && (right as ast.IfExpr).is_comptime { @@ -2523,7 +2476,7 @@ fn (mut g Gen) multi_assign_stmt(node ast.AssignStmt) { }) } else { - g.n_error('Unsupported assign instruction ${node.op}') + g.n_error('Unsupported assign instruction') } } } else if left_type.is_pure_float() { @@ -2561,7 +2514,7 @@ fn (mut g Gen) multi_assign_stmt(node ast.AssignStmt) { g.println('movsd [rax], xmm0') } } else { - //g.n_error('multi return for struct is not supported yet') + g.n_error('multi return for struct is not supported yet') } } } @@ -2603,7 +2556,7 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) { }) } else { - //g.n_error('Unsupported assign instruction ${node.op}') + g.n_error('Unsupported assign instruction') } } } else if typ.is_pure_float() { @@ -2854,7 +2807,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { g.div_sse(.xmm0, .xmm1, typ) } else { - // g.n_error('`${node.op}` expression is not supported right now') + g.n_error('`${node.op}` expression is not supported right now') } } return @@ -2877,7 +2830,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { }) } } - if node.left_type !in ast.integer_type_idxs && node.left_type != ast.bool_type_idx && node.op != .left_shift && node.op != .plus && node.op != .ne && node.op != .eq + if node.left_type !in ast.integer_type_idxs && node.left_type != ast.bool_type_idx && g.table.sym(node.left_type).info !is ast.Enum { g.n_error('unsupported type for `${node.op}`: ${node.left_type}') } @@ -2947,7 +2900,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { g.shr_reg(.rax, .rcx) } else { - // g.n_error('`${node.op}` expression is not supported right now') + g.n_error('`${node.op}` expression is not supported right now') } } } @@ -3222,10 +3175,6 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) { g.println('; label ${end_label}') return } - if node.cond !is ast.InfixExpr { - println("node.cond is not InfixExpr, got: ${node.cond}") - return - } infix_expr := node.cond as ast.InfixExpr mut jump_addr := 0 // location of `jne *00 00 00 00*` start := g.pos() @@ -3244,7 +3193,7 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) { g.cmp_var(infix_expr.left as ast.Ident, lit.val.int()) } else { - // g.n_error('unhandled expression type: ${infix_expr.right}') + g.n_error('unhandled expression type') } } match infix_expr.left.tok_kind { @@ -3254,22 +3203,13 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) { .gt { jump_addr = g.cjmp(.jle) } - .le { - jump_addr = g.cjmp(.jg) - } - .ge { - jump_addr = g.cjmp(.jl) - } - .ne { - jump_addr = g.cjmp(.je) - } else { - g.n_error('unhandled infix cond token ${infix_expr.left.tok_kind}') + g.n_error('unhandled infix cond token') } } } else { - // g.n_error('unhandled infix.left: ${infix_expr.left}') + g.n_error('unhandled infix.left') } } end_label := g.labels.new_label() @@ -3448,9 +3388,6 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int { // BYTE g.write8(0xc6) g.write8(0x45 + far_var_offset) - } - 2 { - } 4 { // DWORD @@ -3463,9 +3400,6 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int { g.write8(0xc7) g.write8(0x45 + far_var_offset) } - 16 { - //TODO - } else { g.n_error('allocate_var: bad size ${size}') } @@ -3484,18 +3418,12 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int { match size { 1 { g.write8(initial_val) - } - 2 { - } 4 { g.write32(initial_val) } 8 { g.write32(initial_val) // fixme: 64-bit segfaulting - } - 16 { - } else { g.n_error('allocate_var: bad size ${size}') diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 537d0f0c6b2b4d..950b80e341e5b9 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -158,15 +158,6 @@ type Var = GlobalVar | LocalVar | ast.Ident type IdentVar = GlobalVar | LocalVar | Register fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar { - if ident.name.contains('C.') { - eprintln("found C function id `${ident.name}`, which is not supported right now") - return LocalVar{ - offset: 0 - typ: ast.new_type(2) - name: ident.name - } - } - mut obj := ident.obj if obj !in [ast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister] { obj = ident.scope.find(ident.name) or { g.n_error('unknown variable ${ident.name}') } @@ -181,15 +172,6 @@ fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar { name: obj.name } } - ast.ConstField { - // TODO - eprintln('const fields are not implemented') - return LocalVar{ - offset: 0 - typ: obj.typ - name: obj.name - } - } else { g.n_error('unsupported variable type type:${obj} name:${ident.name}') } @@ -537,14 +519,14 @@ fn (mut g Gen) try_var_offset(var_name string) int { 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}`') + g.n_error('unknown variable `${var_name}`') } return r } fn (mut g Gen) get_field_offset(typ ast.Type, name string) int { ts := g.table.sym(typ) - field := ts.find_field(name) or { /*g.n_error('Could not find field `${name}` on init')*/ return 0 } + field := ts.find_field(name) or { g.n_error('Could not find field `${name}` on init') } return g.structs[typ.idx()].offsets[field.i] } @@ -908,7 +890,7 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) } } ast.StringInterLiteral { - //g.n_error('Interlaced string literals are not yet supported in the native backend.') // , expr.pos) + g.n_error('Interlaced string literals are not yet supported in the native backend.') // , expr.pos) } ast.IfExpr { if expr.is_comptime { @@ -1019,11 +1001,6 @@ fn (mut g Gen) gen_forc_stmt(node ast.ForCStmt) { // g.infix_expr(node.cond) match cond.left { ast.Ident { - if cond.right !is ast.IntegerLiteral { - println('cond.right is `${cond.right}`') - return - } - lit := cond.right as ast.IntegerLiteral g.cmp_var(cond.left as ast.Ident, lit.val.int()) match cond.op { @@ -1118,8 +1095,7 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { } else if it.kind == .map { */ } else { - // g.v_error('for-in statement is not yet implemented', node.pos) - // TODO: implement for-in + g.v_error('for-in statement is not yet implemented', node.pos) } } @@ -1183,7 +1159,7 @@ fn (mut g Gen) stmt(node ast.Stmt) { words := node.val.split(' ') for word in words { if word.len != 2 { - //g.n_error('opcodes format: xx xx xx xx') + g.n_error('opcodes format: xx xx xx xx') } b := unsafe { C.strtol(&char(word.str), 0, 16) } // b := word.u8() @@ -1450,7 +1426,7 @@ fn (mut g Gen) expr(node ast.Expr) { g.expr(node.expr) } ast.ArrayInit { - // g.n_error('array init expr not supported yet') + g.n_error('array init expr not supported yet') } ast.BoolLiteral { g.mov64(.rax, if node.val { 1 } else { 0 }) @@ -1491,27 +1467,16 @@ fn (mut g Gen) expr(node ast.Expr) { } else if var.typ.is_pure_float() { g.mov_var_to_ssereg(.xmm0, node as ast.Ident) } else { - mut ts := g.table.sym(var.typ) - - for mut ts.info is ast.Alias { - ts = g.table.sym(ts.info.parent_type) - } - + ts := g.table.sym(var.typ) match ts.info { ast.Struct { g.lea_var_to_reg(.rax, g.get_var_offset(node.name)) } - ast.Array { - // TODO: implement array loading - } ast.Enum { g.mov_var_to_reg(.rax, node as ast.Ident, typ: ast.int_type_idx) - } - ast.SumType { - } else { - //g.n_error('Unsupported variable type ${ts.info}') + g.n_error('Unsupported variable type') } } } @@ -1625,24 +1590,6 @@ fn (mut g Gen) expr(node ast.Expr) { } // store the multi return struct value g.lea_var_to_reg(.rax, var.offset) - } - ast.IndexExpr { - - } - ast.CharLiteral { - - } - ast.Nil { - - } - ast.StringInterLiteral { - - } - ast.ArrayDecompose { - - } - ast.SizeOf { - } else { g.n_error('expr: unhandled node type: ${node.type_name()}') From 258d9229e593c7d343f1d09adcf7c691225f1f18 Mon Sep 17 00:00:00 2001 From: Spydr06 Date: Sun, 23 Apr 2023 11:17:59 +0200 Subject: [PATCH 4/5] native: implement `is_used_by_main()` for the native backend --- vlib/v/gen/native/gen.v | 14 +++++++++++++- vlib/v/gen/native/tests/native_test.v | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index b450bb105ec1ff..46b4c5808b0b4a 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -945,13 +945,25 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) } } +fn (mut g Gen) is_used_by_main(node ast.FnDecl) bool { + mut used := true + if g.pref.skip_unused { + fkey := node.fkey() + used = g.table.used_fns[fkey] + } + return used +} + fn (mut g Gen) fn_decl(node ast.FnDecl) { name := if node.is_method { '${g.table.get_type_name(node.receiver.typ)}.${node.name}' } else { node.name } - if node.no_body { + if node.no_body || !g.is_used_by_main(node) { + if g.pref.is_verbose { + println(term.italic(term.green('\n-> skipping unused function `${name}`'))) + } return } if g.pref.is_verbose { diff --git a/vlib/v/gen/native/tests/native_test.v b/vlib/v/gen/native/tests/native_test.v index 7248626018a40f..212e7291a0aeac 100644 --- a/vlib/v/gen/native/tests/native_test.v +++ b/vlib/v/gen/native/tests/native_test.v @@ -40,7 +40,7 @@ fn test_native() { work_test_path := '${wrkdir}/${test_file_name}' exe_test_path := '${wrkdir}/${test_file_name}.exe' tmperrfile := '${dir}/${test}.tmperr' - cmd := '${os.quoted_path(vexe)} -o ${os.quoted_path(exe_test_path)} -b native ${os.quoted_path(full_test_path)} -d custom_define 2> ${os.quoted_path(tmperrfile)}' + cmd := '${os.quoted_path(vexe)} -o ${os.quoted_path(exe_test_path)} -b native -skip-unused ${os.quoted_path(full_test_path)} -d custom_define 2> ${os.quoted_path(tmperrfile)}' if is_verbose { println(cmd) } From fcf710a49e3fca4f55ca746d2f77b05a7fd03df8 Mon Sep 17 00:00:00 2001 From: Spydr06 Date: Sun, 23 Apr 2023 11:31:45 +0200 Subject: [PATCH 5/5] markused: disable skipping special functions when compiling using the native backend --- vlib/v/markused/markused.v | 229 +++++++++++++++++++------------------ 1 file changed, 117 insertions(+), 112 deletions(-) diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index ee3c713afae334..80fb8c67d4dfa5 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -14,118 +14,123 @@ pub fn mark_used(mut table ast.Table, pref_ &pref.Preferences, ast_files []&ast. util.timing_measure(@METHOD) } // Functions that must be generated and can't be skipped - mut all_fn_root_names := [ - 'main.main', - '__new_array', - 'str_intp', - 'format_sb', - '__new_array_with_default', - '__new_array_with_multi_default', - '__new_array_with_array_default', - 'init_global_allocator' /* needed for linux_bare and wasm_bare */, - 'v_realloc' /* needed for _STR */, - 'malloc', - 'malloc_noscan', - 'vcalloc', - 'vcalloc_noscan', - 'new_array_from_c_array', - 'v_fixed_index', - 'memdup', - 'memdup_uncollectable', - 'vstrlen', - '__as_cast', - 'tos', - 'tos2', - 'tos3', - 'isnil', - '_option_ok', - '_result_ok', - 'error', - // utf8_str_visible_length is used by c/str.v - 'utf8_str_visible_length', - 'compare_ints', - 'compare_u64s', - 'compare_strings', - 'compare_ints_reverse', - 'compare_u64s_reverse', - 'compare_strings_reverse', - 'builtin_init', - // byteptr and charptr - '3.vstring', - '3.vstring_with_len', - '3.vstring_literal', - '4.vstring', - '4.vstring_with_len', - '4.vstring_literal', - // byte. methods - '10.str_escaped', - // string. methods - '20.add', - '20.trim_space', - '20.repeat', - '20.replace', - '20.clone', - '20.clone_static', - '20.trim', - '20.substr', - '20.substr_ni', - '20.at', - '20.at_with_check', - '20.index_kmp', - // string. ==, !=, etc... - '20.eq', - '20.ne', - '20.lt', - '20.gt', - '20.le', - '20.ge', - 'fast_string_eq', - // other array methods - '22.get', - '22.set', - '22.get_unsafe', - '22.set_unsafe', - '22.get_with_check' /* used for `x := a[i] or {}` */, - '22.clone_static_to_depth', - '22.clone_to_depth', - '22.first', - '22.last', - '22.pointers' /* TODO: handle generic methods calling array primitives more precisely in pool_test.v */, - '22.reverse', - '22.repeat_to_depth', - '22.slice', - '22.slice_ni', - '22.slice2', - '61.get', - '61.set', - '65558.last', - '65558.pop', - '65558.push', - '65558.insert_many', - '65558.prepend_many', - '65558.reverse', - '65558.set', - '65558.set_unsafe', - // TODO: process the _vinit const initializations automatically too - 'json.decode_string', - 'json.decode_int', - 'json.decode_bool', - 'json.decode_u64', - 'json.encode_int', - 'json.encode_string', - 'json.encode_bool', - 'json.encode_u64', - 'json.json_print', - 'json.json_parse', - 'main.nasserts', - 'main.vtest_init', - 'main.vtest_new_metainfo', - 'main.vtest_new_filemetainfo', - 'os.getwd', - 'os.init_os_args', - 'os.init_os_args_wide', - 'v.embed_file.find_index_entry_by_path', - ] + mut all_fn_root_names := if pref_.backend == .native { + // Note: this is temporary, until the native backend supports more features! + ['main.main'] + } else { + [ + 'main.main', + '__new_array', + 'str_intp', + 'format_sb', + '__new_array_with_default', + '__new_array_with_multi_default', + '__new_array_with_array_default', + 'init_global_allocator' /* needed for linux_bare and wasm_bare */, + 'v_realloc' /* needed for _STR */, + 'malloc', + 'malloc_noscan', + 'vcalloc', + 'vcalloc_noscan', + 'new_array_from_c_array', + 'v_fixed_index', + 'memdup', + 'memdup_uncollectable', + 'vstrlen', + '__as_cast', + 'tos', + 'tos2', + 'tos3', + 'isnil', + '_option_ok', + '_result_ok', + 'error', + // utf8_str_visible_length is used by c/str.v + 'utf8_str_visible_length', + 'compare_ints', + 'compare_u64s', + 'compare_strings', + 'compare_ints_reverse', + 'compare_u64s_reverse', + 'compare_strings_reverse', + 'builtin_init', + // byteptr and charptr + '3.vstring', + '3.vstring_with_len', + '3.vstring_literal', + '4.vstring', + '4.vstring_with_len', + '4.vstring_literal', + // byte. methods + '10.str_escaped', + // string. methods + '20.add', + '20.trim_space', + '20.repeat', + '20.replace', + '20.clone', + '20.clone_static', + '20.trim', + '20.substr', + '20.substr_ni', + '20.at', + '20.at_with_check', + '20.index_kmp', + // string. ==, !=, etc... + '20.eq', + '20.ne', + '20.lt', + '20.gt', + '20.le', + '20.ge', + 'fast_string_eq', + // other array methods + '22.get', + '22.set', + '22.get_unsafe', + '22.set_unsafe', + '22.get_with_check' /* used for `x := a[i] or {}` */, + '22.clone_static_to_depth', + '22.clone_to_depth', + '22.first', + '22.last', + '22.pointers' /* TODO: handle generic methods calling array primitives more precisely in pool_test.v */, + '22.reverse', + '22.repeat_to_depth', + '22.slice', + '22.slice_ni', + '22.slice2', + '61.get', + '61.set', + '65558.last', + '65558.pop', + '65558.push', + '65558.insert_many', + '65558.prepend_many', + '65558.reverse', + '65558.set', + '65558.set_unsafe', + // TODO: process the _vinit const initializations automatically too + 'json.decode_string', + 'json.decode_int', + 'json.decode_bool', + 'json.decode_u64', + 'json.encode_int', + 'json.encode_string', + 'json.encode_bool', + 'json.encode_u64', + 'json.json_print', + 'json.json_parse', + 'main.nasserts', + 'main.vtest_init', + 'main.vtest_new_metainfo', + 'main.vtest_new_filemetainfo', + 'os.getwd', + 'os.init_os_args', + 'os.init_os_args_wide', + 'v.embed_file.find_index_entry_by_path', + ] + } if pref_.is_bare { all_fn_root_names << [