From a290053319abbd04e71dd569b09766fc16ded9d6 Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Mon, 17 Feb 2025 10:43:45 +0100 Subject: [PATCH 1/3] fix int_to_string overwriting other vars on the stack --- vlib/v/gen/native/amd64.v | 1 + vlib/v/gen/native/builtins.v | 2 +- vlib/v/gen/native/gen.v | 12 +++++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 03a8370696b3fc..5982736013a681 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -1323,6 +1323,7 @@ fn (mut c Amd64) gen_print(s string, fd i32) { c.g.println('; print }') } +// write a string of size n stored in r to fd pub fn (mut c Amd64) gen_print_reg(r Register, n i32, fd i32) { c.g.println('; print_reg: (reg:${r} fd:${fd} len:${n}) {') str_reg := if c.g.pref.os == .windows { Amd64Register.rdx } else { Amd64Register.rsi } diff --git a/vlib/v/gen/native/builtins.v b/vlib/v/gen/native/builtins.v index 14b2427cd6f7ac..9f4196cf476118 100644 --- a/vlib/v/gen/native/builtins.v +++ b/vlib/v/gen/native/builtins.v @@ -30,7 +30,7 @@ pub fn (mut g Gen) init_builtins() { body: fn (builtin BuiltinFn, mut g Gen) { g.code_gen.convert_int_to_string(builtin.arg_regs[0], builtin.arg_regs[1]) } - arg_regs: [Amd64Register.rcx, Amd64Register.rdi] + arg_regs: [Amd64Register.rcx, Amd64Register.rdi] // rcx: int to convert, rdi: end of 32byte buffer (with 4 bytes at the beggining for len) see allocate_array } .bool_to_string: BuiltinFn{ body: fn (builtin BuiltinFn, mut g Gen) { diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 27c78e35e5d38b..7618fac8baa738 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -859,7 +859,7 @@ fn (mut g Gen) allocate_string(s string, opsize i32, typ RelocType) i32 { // allocates a buffer variable: name, size of stored type (nb of bytes), nb of items fn (mut g Gen) allocate_array(name string, size i32, items i32) i32 { g.println('; allocate array `${name}` item-size:${size} items:${items}:') - pos := g.code_gen.allocate_var(name, size, items) // store the lenght of the array on the stack + pos := g.code_gen.allocate_var(name, 4, items) // store the lenght of the array on the stack in a 4 byte var g.stack_var_pos += (size * items) // reserve space on the stack for the items return pos } @@ -950,7 +950,8 @@ fn (mut g Gen) gen_to_string(reg Register, typ ast.Type) { g.println('; to_string (reg:${reg}) {') if typ.is_int() { buffer := g.allocate_array('itoa-buffer', 1, 32) // 32 characters should be enough - g.code_gen.lea_var_to_reg(g.get_builtin_arg_reg(.int_to_string, 1), buffer) + end_of_buffer := buffer + 4 + 32 - 1 // 4 bytes for the size and 32 for the chars, -1 to not go out of array + g.code_gen.lea_var_to_reg(g.get_builtin_arg_reg(.int_to_string, 1), end_of_buffer) arg0_reg := g.get_builtin_arg_reg(.int_to_string, 0) if arg0_reg != reg { @@ -958,7 +959,7 @@ fn (mut g Gen) gen_to_string(reg Register, typ ast.Type) { } g.call_builtin(.int_to_string) - g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), buffer) + g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), end_of_buffer) // the (int) string starts at the end of the buffer } else if typ.is_bool() { arg_reg := g.get_builtin_arg_reg(.bool_to_string, 0) if arg_reg != reg { @@ -983,10 +984,11 @@ fn (mut g Gen) gen_var_to_string(reg Register, expr ast.Expr, var Var, config Va g.code_gen.convert_rune_to_string(reg, buffer, var, config) } else if typ.is_int() { buffer := g.allocate_array('itoa-buffer', 1, 32) // 32 characters should be enough + end_of_buffer := buffer + 4 + 32 - 1 // 4 bytes for the size and 32 for the chars, -1 to not go out of array g.code_gen.mov_var_to_reg(g.get_builtin_arg_reg(.int_to_string, 0), var, config) - g.code_gen.lea_var_to_reg(g.get_builtin_arg_reg(.int_to_string, 1), buffer) + g.code_gen.lea_var_to_reg(g.get_builtin_arg_reg(.int_to_string, 1), end_of_buffer) g.call_builtin(.int_to_string) - g.code_gen.lea_var_to_reg(reg, buffer) + g.code_gen.lea_var_to_reg(reg, end_of_buffer) // the (int) string starts at the end of the buffer } else if typ.is_bool() { g.code_gen.mov_var_to_reg(g.get_builtin_arg_reg(.bool_to_string, 0), var, config) g.call_builtin(.bool_to_string) From 4db233b34759bb68ff6818de1a755c06d13e9117 Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Mon, 17 Feb 2025 10:43:53 +0100 Subject: [PATCH 2/3] add tests --- vlib/v/gen/native/tests/print.vv | 14 ++++++++++++++ vlib/v/gen/native/tests/print.vv.out | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/vlib/v/gen/native/tests/print.vv b/vlib/v/gen/native/tests/print.vv index f86639d60e9a5e..091a8519d5b8eb 100644 --- a/vlib/v/gen/native/tests/print.vv +++ b/vlib/v/gen/native/tests/print.vv @@ -110,6 +110,18 @@ fn test_intermediate() { println(c) } +fn test_for_range() { + for i in 0 .. 10 { + println(i) + } +} + +fn test_2_in_a_row() { + a := 12345 + println(a) + println(a) +} + fn main() { test_stdout() test_stderr() @@ -120,4 +132,6 @@ fn main() { test_sizeof() test_interpolated() test_intermediate() + test_for_range() + test_2_in_a_row() } diff --git a/vlib/v/gen/native/tests/print.vv.out b/vlib/v/gen/native/tests/print.vv.out index 740ada47b83200..de9706ad9ceac2 100644 --- a/vlib/v/gen/native/tests/print.vv.out +++ b/vlib/v/gen/native/tests/print.vv.out @@ -22,3 +22,15 @@ sizeof: 4, 12 this is an interpolated string num: 42; bool: true 0 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +12345 +12345 From 4bf4749e5cc30eae45bebf3a218a8cc749ba8cab Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Mon, 17 Feb 2025 11:25:33 +0100 Subject: [PATCH 3/3] fix comments, add more tests --- vlib/v/gen/native/amd64.v | 2 +- vlib/v/gen/native/gen.v | 2 +- vlib/v/gen/native/tests/print.vv | 16 ++++++++++++++++ vlib/v/gen/native/tests/print.vv.out | 2 ++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 5982736013a681..89f7dbce96c087 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -1323,7 +1323,7 @@ fn (mut c Amd64) gen_print(s string, fd i32) { c.g.println('; print }') } -// write a string of size n stored in r to fd +// gen_print_reg writes a string of size n stored in r to fd pub fn (mut c Amd64) gen_print_reg(r Register, n i32, fd i32) { c.g.println('; print_reg: (reg:${r} fd:${fd} len:${n}) {') str_reg := if c.g.pref.os == .windows { Amd64Register.rdx } else { Amd64Register.rsi } diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 7618fac8baa738..9b33c03703a7b9 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -859,7 +859,7 @@ fn (mut g Gen) allocate_string(s string, opsize i32, typ RelocType) i32 { // allocates a buffer variable: name, size of stored type (nb of bytes), nb of items fn (mut g Gen) allocate_array(name string, size i32, items i32) i32 { g.println('; allocate array `${name}` item-size:${size} items:${items}:') - pos := g.code_gen.allocate_var(name, 4, items) // store the lenght of the array on the stack in a 4 byte var + pos := g.code_gen.allocate_var(name, 4, items) // store the length of the array on the stack in a 4 byte var g.stack_var_pos += (size * items) // reserve space on the stack for the items return pos } diff --git a/vlib/v/gen/native/tests/print.vv b/vlib/v/gen/native/tests/print.vv index 091a8519d5b8eb..3e777e8cd00d5b 100644 --- a/vlib/v/gen/native/tests/print.vv +++ b/vlib/v/gen/native/tests/print.vv @@ -116,6 +116,20 @@ fn test_for_range() { } } +fn test_for_range2() { + for i in 7 .. 9 { + println(i) + } +} + +/* Does not work yet +fn test_for_range3() { + for i in -2 .. 3 { + println(i) + } +} +*/ + fn test_2_in_a_row() { a := 12345 println(a) @@ -133,5 +147,7 @@ fn main() { test_interpolated() test_intermediate() test_for_range() + test_for_range2() +// test_for_range3() test_2_in_a_row() } diff --git a/vlib/v/gen/native/tests/print.vv.out b/vlib/v/gen/native/tests/print.vv.out index de9706ad9ceac2..4d843f696ff792 100644 --- a/vlib/v/gen/native/tests/print.vv.out +++ b/vlib/v/gen/native/tests/print.vv.out @@ -32,5 +32,7 @@ num: 42; bool: true 7 8 9 +7 +8 12345 12345