From b55a594339229294bf6c1eeabd4acb0431f32d9b Mon Sep 17 00:00:00 2001 From: Nopana_Eliyaan Date: Fri, 12 Sep 2025 17:09:15 +0200 Subject: [PATCH 1/3] array size, pointer index expr (read/write) --- vlib/v/gen/native/amd64.v | 7 ++++++- vlib/v/gen/native/arm64.v | 4 ++++ vlib/v/gen/native/expr.v | 26 ++++++++++++++++++++++---- vlib/v/gen/native/gen.v | 19 ++++++++++++++++++- vlib/v/gen/native/tests/pointers.vv | 11 +++++++++++ 5 files changed, 61 insertions(+), 6 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 346965632e..7db476a6e2 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -1798,6 +1798,10 @@ fn (mut c Amd64) mov(r Register, val i32) { } } +fn (mut c Amd64) mul_reg_main(b Register) { + c.mul_reg_rax(b as Amd64Register) +} + // rax times b fn (mut c Amd64) mul_reg_rax(b Amd64Register) { match b { @@ -3109,7 +3113,6 @@ fn (mut c Amd64) assign_stmt(node ast.AssignStmt) { c.push(c.main_reg()) c.g.gen_left_value(left) c.mov_reg(Amd64Register.rbx, Amd64Register.rax) // effective address of the left expr - c.mov_deref(Amd64Register.rax, Amd64Register.rbx, var_type) // value of left expr c.pop(.rcx) // value of right expr c.gen_type_promotion(node.right_types[0], var_type) @@ -3124,10 +3127,12 @@ fn (mut c Amd64) assign_stmt(node ast.AssignStmt) { c.mov_store(.rbx, .rcx, size) } .boolean_and_assign { + c.mov_deref(Amd64Register.rax, Amd64Register.rbx, var_type) // value of left expr c.bitand_reg(.rax, .rcx) c.mov_store(.rbx, .rax, size) } .boolean_or_assign { + c.mov_deref(Amd64Register.rax, Amd64Register.rbx, var_type) // value of left expr c.bitor_reg(.rax, .rcx) c.mov_store(.rbx, .rax, size) } diff --git a/vlib/v/gen/native/arm64.v b/vlib/v/gen/native/arm64.v index 7b4e24bdec..199125052a 100644 --- a/vlib/v/gen/native/arm64.v +++ b/vlib/v/gen/native/arm64.v @@ -554,3 +554,7 @@ fn (mut c Arm64) mov_deref(reg Register, regptr Register, typ ast.Type) { fn (mut c Arm64) patch_relative_jmp(pos i32, addr i64) { panic('Arm64.patch_relative_jmp() not implemented') } + +fn (mut c Arm64) mul_reg_main(b Register) { + panic('Arm64.mul_reg_main() not implemented') +} diff --git a/vlib/v/gen/native/expr.v b/vlib/v/gen/native/expr.v index 51cbb201cc..ec4cddf4e3 100644 --- a/vlib/v/gen/native/expr.v +++ b/vlib/v/gen/native/expr.v @@ -160,9 +160,16 @@ fn (mut g Gen) expr(node ast.Expr) { g.code_gen.pop2(Amd64Register.rdx) // index g.code_gen.add_reg2(Amd64Register.rax, Amd64Register.rdx) // add the offset to the address g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.u8_type_idx) - } else if node.left_type.is_pointer() { - dump(node) - g.n_error('${@LOCATION} expr: unhandled node type: Index expr is not applied on string') + } else if node.left_type.is_any_kind_of_pointer() { + // load the pointer + g.expr(node.left) + g.code_gen.mov_reg(Amd64Register.rcx, Amd64Register.rax) + // add the index times the size (bytes) of the type + g.expr(node.index) + g.code_gen.mov(Amd64Register.rbx, i32(g.get_type_size(node.typ))) + g.code_gen.mul_reg_main(Amd64Register.rbx) + g.code_gen.add_reg2(Amd64Register.rax, Amd64Register.rcx) + g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, node.typ) } else { g.n_error('${@LOCATION} expr: unhandled node type: Index expr is not applied on string') } @@ -557,7 +564,18 @@ fn (mut g Gen) gen_left_value(node ast.Expr) { g.expr(node) // TODO: add a test that uses this } ast.IndexExpr { // TODO - g.n_error('${@LOCATION} Unsupported IndexExpr left value') + if node.left_type.is_any_kind_of_pointer() { + // load the pointer + g.expr(node.left) + g.code_gen.mov_reg(Amd64Register.rcx, Amd64Register.rax) + // add the index times the size (bytes) of the type + g.expr(node.index) + g.code_gen.mov(Amd64Register.rbx, i32(g.get_type_size(node.typ))) + g.code_gen.mul_reg_main(Amd64Register.rbx) + g.code_gen.add_reg2(Amd64Register.rax, Amd64Register.rcx) + } else { + g.n_error('${@LOCATION} Unsupported IndexExpr left value') + } } ast.PrefixExpr { if node.op != .mul { diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 2c8c3e593f..ee1001b585 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -139,6 +139,7 @@ mut: mov(r Register, val i32) mov64(r Register, val Number) movabs(reg Register, val i64) + mul_reg_main(b Register) patch_relative_jmp(pos i32, addr i64) pop2(r Register) prefix_expr(node ast.PrefixExpr) @@ -891,7 +892,7 @@ fn (mut g Gen) get_type_size(raw_type ast.Type) i32 { return 1 } ts := g.table.sym(typ) - if ts.size != -1 { + if ts.size != -1 && ts.size != 0 { return i32(ts.size) } mut size := i32(0) @@ -929,6 +930,22 @@ fn (mut g Gen) get_type_size(raw_type ast.Type) i32 { } g.structs[typ.idx()] = strc } + ast.Array { + // TODO: replace u32 by the enum ArrayFlags size + for f_typ in [ast.voidptr_type, ast.int_type, ast.int_type, ast.int_type, ast.u32_type, + ast.int_type] { + f_size := g.get_type_size(f_typ) + f_align := g.get_type_align(f_typ) + padding := (f_align - size % f_align) % f_align + strc.offsets << size + padding + size += f_size + padding + if f_align > align { + align = f_align + } + } + size = (size + align - 1) / align * align + g.structs[typ.idx()] = strc + } else {} } mut ts_ := g.table.sym(typ) diff --git a/vlib/v/gen/native/tests/pointers.vv b/vlib/v/gen/native/tests/pointers.vv index c4522c6120..ae01f64b2e 100644 --- a/vlib/v/gen/native/tests/pointers.vv +++ b/vlib/v/gen/native/tests/pointers.vv @@ -3,9 +3,20 @@ fn main() { test_lt_gt() test_ref_deref() test_nil() + index_expr_test() println("ok") } +fn index_expr_test() { + mut buf := C.malloc(2) + unsafe { + buf[0] = 1 + buf[1] = 2 + assert buf[0] == 1 + assert buf[1] == 2 + } +} + fn test_eq_ne() { unsafe { mut a := voidptr(0) From 2b9013c7ee13fee72265ed2097b4a5353312f68a Mon Sep 17 00:00:00 2001 From: Nopana_Eliyaan Date: Sat, 13 Sep 2025 10:32:29 +0200 Subject: [PATCH 2/3] const strings, fix tests, fix malloc_noscan --- vlib/builtin/builtin.c.v | 4 +++- vlib/v/gen/native/amd64.v | 1 + vlib/v/gen/native/expr.v | 12 +++++++++++- vlib/v/gen/native/tests/pointers.vv | 5 +++++ vlib/v/gen/native/tests/string.vv | 8 ++++++++ vlib/v/gen/native/tests/string.vv.out | 1 + 6 files changed, 29 insertions(+), 2 deletions(-) diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index 564212a50b..19bf1c2930 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -486,7 +486,9 @@ pub fn malloc_noscan(n isize) &u8 { _memory_panic(@FN, n) } mut res := &u8(unsafe { nil }) - $if prealloc { + $if native { + res = unsafe { C.malloc(n) } + } $else $if prealloc { return unsafe { prealloc_malloc(n) } } $else $if gcboehm ? { $if gcboehm_opt ? { diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 7db476a6e2..57bfa4cddc 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -3137,6 +3137,7 @@ fn (mut c Amd64) assign_stmt(node ast.AssignStmt) { c.mov_store(.rbx, .rax, size) } else { + c.mov_deref(Amd64Register.rax, Amd64Register.rbx, var_type) // value of left expr c.apply_op_int(.rax, .rcx, node.op) c.mov_store(.rbx, .rax, size) } diff --git a/vlib/v/gen/native/expr.v b/vlib/v/gen/native/expr.v index ec4cddf4e3..88cef8a2d8 100644 --- a/vlib/v/gen/native/expr.v +++ b/vlib/v/gen/native/expr.v @@ -217,8 +217,18 @@ fn (mut g Gen) global_var_ident(ident ast.Ident, var GlobalVar) { fn (mut g Gen) const_var_ident(ident ast.Ident, var ConstVar) { if g.is_register_type(var.typ) { g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), ident) - } else { + } else if g.is_fp_type(var.typ) { g.n_error('${@LOCATION} Unsupported variable type ${ident} ${var}') + } else { + ts := g.table.sym(g.unwrap(var.typ)) + match ts.info { + ast.Struct { + g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), ident) + } + else { + g.n_error('${@LOCATION} Unsupported variable type ${ident} ${var} ${ts.info}') + } + } } } diff --git a/vlib/v/gen/native/tests/pointers.vv b/vlib/v/gen/native/tests/pointers.vv index ae01f64b2e..5d6260302c 100644 --- a/vlib/v/gen/native/tests/pointers.vv +++ b/vlib/v/gen/native/tests/pointers.vv @@ -14,6 +14,11 @@ fn index_expr_test() { buf[1] = 2 assert buf[0] == 1 assert buf[1] == 2 + buf = malloc_noscan(2) + buf[0] = 3 + buf[1] = 4 + assert buf[0] == 3 + assert buf[1] == 4 } } diff --git a/vlib/v/gen/native/tests/string.vv b/vlib/v/gen/native/tests/string.vv index 398494c4e9..b995740ae8 100644 --- a/vlib/v/gen/native/tests/string.vv +++ b/vlib/v/gen/native/tests/string.vv @@ -85,6 +85,13 @@ fn test_runes() { println(`\xe2\x98\x85`) } +const a = 'my string' + +fn const_test() { + b := a + println(b) +} + fn main() { test_unicode_characters() test_string_len() @@ -93,4 +100,5 @@ fn main() { test_escape_codes() test_raw_string() test_runes() + const_test() } diff --git a/vlib/v/gen/native/tests/string.vv.out b/vlib/v/gen/native/tests/string.vv.out index 654b6ca1c7..48f1a774ae 100644 --- a/vlib/v/gen/native/tests/string.vv.out +++ b/vlib/v/gen/native/tests/string.vv.out @@ -23,3 +23,4 @@ V 😀 🚀 ★★★★ +my string From 90a1acb2440a3b5cfeddad7ab545c2a7475307be Mon Sep 17 00:00:00 2001 From: Nopana_Eliyaan Date: Sat, 13 Sep 2025 12:18:13 +0200 Subject: [PATCH 3/3] arrays! --- vlib/v/gen/native/amd64.v | 74 ++++++++++++++++++++++- vlib/v/gen/native/arm64.v | 4 ++ vlib/v/gen/native/blacklist.v | 86 +++++++++++++++------------ vlib/v/gen/native/expr.v | 41 +++---------- vlib/v/gen/native/gen.v | 1 + vlib/v/gen/native/tests/arrays.vv | 10 ++++ vlib/v/gen/native/tests/arrays.vv.out | 3 + 7 files changed, 145 insertions(+), 74 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 57bfa4cddc..7e2c172c14 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -2514,8 +2514,42 @@ fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.E ast.ArrayInit { match node.op { .decl_assign { - c.g.allocate_by_type(name, right.typ) - c.init_array(ident, right) + c.g.allocate_by_type(ident.name, ast.array_type) + len := ast.CallArg{ + expr: if right.has_len { + right.len_expr + } else { + ast.IntegerLiteral{'0', right.pos} + } + typ: ast.int_type + pos: right.pos + } + cap := ast.CallArg{ + expr: if right.has_cap { + right.cap_expr + } else { + ast.IntegerLiteral{'0', right.pos} + } + typ: ast.int_type + pos: right.pos + } + size := ast.CallArg{ + expr: ast.IntegerLiteral{c.g.get_type_size(right.elem_type).str(), right.pos} + typ: ast.int_type + pos: right.pos + } + c.call_fn(ast.CallExpr{ + pos: right.pos + name: '__new_array' + args: [len, cap, size] + expected_arg_types: [ast.int_type, ast.int_type, ast.int_type] + language: .v + return_type: ast.array_type + nr_ret_values: 1 + is_return_used: true + }) + c.lea_var_to_reg(Amd64Register.rdx, c.g.get_var_offset(ident.name)) + c.move_struct(.rax, .rdx, c.g.get_type_size(ast.array_type)) } else { c.g.n_error('${@LOCATION} Unexpected operator `${node.op}`') @@ -2677,6 +2711,42 @@ fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.E }*/ } +fn (mut c Amd64) gen_index_expr(node ast.IndexExpr) { + if node.left_type.is_string() { + c.g.expr(node.index) + c.push(Amd64Register.rax) + + c.g.expr(node.left) // load address of string struct + c.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.u64_type_idx) // load value of the str pointer + + c.pop2(Amd64Register.rdx) // index + c.add_reg2(Amd64Register.rax, Amd64Register.rdx) // add the offset to the address + } else if node.left_type.is_any_kind_of_pointer() { + // load the pointer + c.g.expr(node.left) + c.mov_reg(Amd64Register.rcx, Amd64Register.rax) + // add the index times the size (bytes) of the type + c.g.expr(node.index) + c.mov(Amd64Register.rbx, i32(c.g.get_type_size(node.typ))) + c.mul_reg_main(Amd64Register.rbx) + c.add_reg2(Amd64Register.rax, Amd64Register.rcx) + } else if node.is_array { + c.g.expr(node.left) + offset := c.g.get_field_offset(ast.array_type, 'data') + if offset != 0 { + c.add(Amd64Register.rax, offset) + } + c.mov_reg(Amd64Register.rcx, Amd64Register.rax) + // add the index times the size (bytes) of the type + c.g.expr(node.index) + c.mov(Amd64Register.rbx, i32(c.g.get_type_size(node.typ))) + c.mul_reg_main(Amd64Register.rbx) + c.add_reg2(Amd64Register.rax, Amd64Register.rcx) + } else { + c.g.n_error('${@LOCATION} index expr: unhandled node type {node}') + } +} + // /!\ for div, mul, mod the left value should always be .rax fn (mut c Amd64) apply_op_int(left_value Amd64Register, right_value Amd64Register, op token.Kind) { match op { diff --git a/vlib/v/gen/native/arm64.v b/vlib/v/gen/native/arm64.v index 199125052a..1919294288 100644 --- a/vlib/v/gen/native/arm64.v +++ b/vlib/v/gen/native/arm64.v @@ -558,3 +558,7 @@ fn (mut c Arm64) patch_relative_jmp(pos i32, addr i64) { fn (mut c Arm64) mul_reg_main(b Register) { panic('Arm64.mul_reg_main() not implemented') } + +fn (mut c Arm64) gen_index_expr(node ast.IndexExpr) { + panic('Arm64.gen_index_expr{) not implemented') +} diff --git a/vlib/v/gen/native/blacklist.v b/vlib/v/gen/native/blacklist.v index 142ea843eb..3552985510 100644 --- a/vlib/v/gen/native/blacklist.v +++ b/vlib/v/gen/native/blacklist.v @@ -29,45 +29,53 @@ already compiling functions: // false: whitelist function // true: blacklist function const blacklist = { - 'main.main': false - 'c_error_number_str': false - 'exit': false - 'gc_is_enabled': false - 'int_max': false - 'int_min': false - 'flush_stdout': false - 'flush_stderr': false - 'print_character': false - 'u8.is_alnum': false - 'u8.is_bin_digit': false - 'u8.is_capital': false - 'u8.is_digit': false - 'u8.is_hex_digit': false - 'u8.is_letter': false - 'u8.is_oct_digit': false - 'u8.is_space': false - 'string.is_capital': false - 'string.is_ascii': false - 'string.is_identifier': false - 'string.is_blank': false - 'string.indent_width': false - 'string.index_u8': false - 'string.last_index': true - 'string.last_index_u8': false - 'string.contains_u8': false - 'malloc_noscan': false - 'malloc': false - 'is_nil': false - 'memdup': false - 'vcalloc': false - 'vmemcpy': false - 'eprint': false - 'eprintln': false - '_write_buf_to_fd': false - '_writeln_to_fd': false - '_memory_panic': false - 'panic': false - 'vcurrent_hash': false + 'main.main': false + 'c_error_number_str': false + 'exit': false + 'gc_is_enabled': false + 'int_max': false + 'int_min': false + 'flush_stdout': false + 'flush_stderr': false + 'print_character': false + 'u8.is_alnum': false + 'u8.is_bin_digit': false + 'u8.is_capital': false + 'u8.is_digit': false + 'u8.is_hex_digit': false + 'u8.is_letter': false + 'u8.is_oct_digit': false + 'u8.is_space': false + 'string.is_capital': false + 'string.is_ascii': false + 'string.is_identifier': false + 'string.is_blank': false + 'string.indent_width': false + 'string.index_u8': false + 'string.last_index': true + 'string.last_index_u8': false + 'string.contains_u8': false + 'malloc_noscan': false + 'malloc': false + 'is_nil': false + 'memdup': false + 'vcalloc': false + 'vmemcpy': false + 'eprint': false + 'eprintln': false + '_write_buf_to_fd': false + '_writeln_to_fd': false + '_memory_panic': false + 'panic': false + 'vcurrent_hash': false + '__new_array': false + 'panic_on_negative_len': false + 'panic_on_negative_cap': false + 'panic_n': false + 'impl_i64_to_string': false + 'vmemmove': false + 'tos': false + 'strings.new_builder': true } const windows_blacklist = { diff --git a/vlib/v/gen/native/expr.v b/vlib/v/gen/native/expr.v index 88cef8a2d8..85c9738f48 100644 --- a/vlib/v/gen/native/expr.v +++ b/vlib/v/gen/native/expr.v @@ -150,28 +150,11 @@ fn (mut g Gen) expr(node ast.Expr) { g.gen_sizeof_expr(node) } ast.IndexExpr { + g.code_gen.gen_index_expr(node) if node.left_type.is_string() { - g.expr(node.index) - g.code_gen.push(Amd64Register.rax) - - g.expr(node.left) // load address of string struct - g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.u64_type_idx) // load value of the str pointer - - g.code_gen.pop2(Amd64Register.rdx) // index - g.code_gen.add_reg2(Amd64Register.rax, Amd64Register.rdx) // add the offset to the address g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.u8_type_idx) - } else if node.left_type.is_any_kind_of_pointer() { - // load the pointer - g.expr(node.left) - g.code_gen.mov_reg(Amd64Register.rcx, Amd64Register.rax) - // add the index times the size (bytes) of the type - g.expr(node.index) - g.code_gen.mov(Amd64Register.rbx, i32(g.get_type_size(node.typ))) - g.code_gen.mul_reg_main(Amd64Register.rbx) - g.code_gen.add_reg2(Amd64Register.rax, Amd64Register.rcx) - g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, node.typ) } else { - g.n_error('${@LOCATION} expr: unhandled node type: Index expr is not applied on string') + g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, node.typ) } } else { @@ -199,8 +182,11 @@ fn (mut g Gen) local_var_ident(ident ast.Ident, var LocalVar) { ast.Enum { g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), ident) } + ast.Array { + g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), g.get_var_offset(ident.name)) + } else { - g.n_error('${@LOCATION} Unsupported variable type') + g.n_error('${@LOCATION} Unsupported variable type ${ts.info}') } } } @@ -573,19 +559,8 @@ fn (mut g Gen) gen_left_value(node ast.Expr) { ast.ArrayInit { g.expr(node) // TODO: add a test that uses this } - ast.IndexExpr { // TODO - if node.left_type.is_any_kind_of_pointer() { - // load the pointer - g.expr(node.left) - g.code_gen.mov_reg(Amd64Register.rcx, Amd64Register.rax) - // add the index times the size (bytes) of the type - g.expr(node.index) - g.code_gen.mov(Amd64Register.rbx, i32(g.get_type_size(node.typ))) - g.code_gen.mul_reg_main(Amd64Register.rbx) - g.code_gen.add_reg2(Amd64Register.rax, Amd64Register.rcx) - } else { - g.n_error('${@LOCATION} Unsupported IndexExpr left value') - } + ast.IndexExpr { + g.code_gen.gen_index_expr(node) } ast.PrefixExpr { if node.op != .mul { diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index ee1001b585..80890978a0 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -114,6 +114,7 @@ mut: gen_asm_stmt(asm_node ast.AsmStmt) gen_cast_expr(expr ast.CastExpr) gen_exit(expr ast.Expr) + gen_index_expr(ast.IndexExpr) gen_match_expr(expr ast.MatchExpr) gen_print_reg(r Register, n i32, fd i32) gen_print(s string, fd i32) diff --git a/vlib/v/gen/native/tests/arrays.vv b/vlib/v/gen/native/tests/arrays.vv index 67fb141bb4..2268edc09b 100644 --- a/vlib/v/gen/native/tests/arrays.vv +++ b/vlib/v/gen/native/tests/arrays.vv @@ -1,3 +1,13 @@ fn main() { assert [1, 2, 3] != [] + mut my_array := []int{len:3} + my_array[0] = 4 + my_array[1] = 5 + my_array[2] = 6 + println(my_array[0]) + println(my_array[1]) + println(my_array[2]) + assert my_array[0] == 4 + assert my_array[1] == 5 + assert my_array[2] == 6 } diff --git a/vlib/v/gen/native/tests/arrays.vv.out b/vlib/v/gen/native/tests/arrays.vv.out index e69de29bb2..4578bc10fe 100644 --- a/vlib/v/gen/native/tests/arrays.vv.out +++ b/vlib/v/gen/native/tests/arrays.vv.out @@ -0,0 +1,3 @@ +4 +5 +6