From 31a8e1140677cb18022540cc3faa6e1cfe371d0b Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Sun, 16 Feb 2025 12:05:50 +0100 Subject: [PATCH 01/10] add comments & prints --- vlib/v/gen/native/amd64.v | 21 ++++++++++++++------- vlib/v/gen/native/gen.v | 10 ++++++++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index e87b54f8356238..ff41cfc83d1c83 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -466,7 +466,7 @@ fn (mut c Amd64) jmp(addr i32) i32 { c.g.write8(0xe9) pos := c.g.pos() c.g.write32(addr) // 0xffffff - c.g.println('jmp') + c.g.println('jmp ${int(pos+addr).hex2()}') // return the position of jump address for placeholder return i32(pos) } @@ -885,7 +885,7 @@ fn (mut c Amd64) mov_var_to_reg(reg Register, var Var, config VarConfig) { } else { c.g.write8((0xff - offset + 1) % 0x100) } - c.g.println('${instruction} ${reg}, ${size_str} PTR [rbp-${int(offset).hex2()}]') + c.g.println('${instruction} ${reg}, ${size_str} PTR [rbp-${int(offset).hex2()}] ; `${var.name}`') } GlobalVar { // TODO @@ -1263,6 +1263,7 @@ pub fn (mut c Amd64) test_reg(r Amd64Register) { // return length in .rax of string pointed by given register pub fn (mut c Amd64) inline_strlen(r Amd64Register) { + c.g.println('; inline_strlen: (reg:${r}) {') c.mov_reg(Amd64Register.rdi, r) c.mov(Amd64Register.rcx, -1) c.mov(Amd64Register.eax, 0) @@ -1271,6 +1272,7 @@ pub fn (mut c Amd64) inline_strlen(r Amd64Register) { c.dec(.rcx) c.mov_reg(Amd64Register.rax, Amd64Register.rcx) c.g.println('strlen rax, ${r}') + c.g.println('; inline_strlen }') } pub fn (mut c Amd64) get_dllcall_addr(import_addr i64) i64 { @@ -1296,6 +1298,7 @@ pub fn (mut c Amd64) dllcall(symbol string) { } fn (mut c Amd64) gen_print(s string, fd i32) { + c.g.println('; print: (fd:${fd} s:\'${s}\') {') if c.g.pref.os == .windows { c.sub(.rsp, 0x38) c.mov(Amd64Register.rcx, -10 - fd) @@ -1317,9 +1320,11 @@ fn (mut c Amd64) gen_print(s string, fd i32) { c.mov(Amd64Register.edx, i32(s.len)) // len c.syscall() } + c.g.println('; print }') } 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 } len_reg := if c.g.pref.os == .windows { Amd64Register.r8 } else { Amd64Register.rdx } c.mov_reg(str_reg, r) @@ -1347,6 +1352,7 @@ pub fn (mut c Amd64) gen_print_reg(r Register, n i32, fd i32) { c.mov(Amd64Register.edi, fd) c.syscall() } + c.g.println('; print_reg }') } pub fn (mut c Amd64) gen_exit(expr ast.Expr) { @@ -1604,7 +1610,7 @@ fn (mut c Amd64) div_reg(a Amd64Register, b Amd64Register) { panic('unhandled div ${b}') } } - c.g.println('div ${b}') + c.g.println('idiv ${b}') } fn (mut c Amd64) mod_reg(a Amd64Register, b Amd64Register) { @@ -1937,8 +1943,8 @@ pub fn (mut c Amd64) call_fn(node ast.CallExpr) { } fn (mut c Amd64) call_builtin(name Builtin) i64 { - call_addr := c.call(0) - c.g.println('call builtin `${name}`') + c.g.println('; call builtin `${name}`: (the 0 will get replaced)') + call_addr := c.call(0) // the 0 will get replaced by the right addr when the function will be generated return call_addr } @@ -3521,10 +3527,10 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { c.push(Amd64Register.rax) - c.mov(Amd64Register.rdx, 0) + c.mov(Amd64Register.rdx, 0) // upperhalf of the dividend c.mov(Amd64Register.rbx, 10) c.div_reg(.rax, .rbx) - c.add8(.rdx, '0'[0]) + c.add8(.rdx, i32(`0`)) // rdx is the remainder, add 48 to convert it into it's ascii representation c.g.write8(0x66) c.g.write8(0x89) @@ -3536,6 +3542,7 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { c.mov(Amd64Register.rbx, 10) c.cdq() c.g.write8(0x48) + c.g.write8(0x48) // REX.W prefix for dividend RDX:RAX and quotient RAX c.g.write8(0xf7) c.g.write8(0xfb) c.g.println('idiv rbx') diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index 458fd63a2d1358..ff38173b172b2e 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -856,9 +856,11 @@ fn (mut g Gen) allocate_string(s string, opsize i32, typ RelocType) i32 { return str_pos } +// name, size of stored type (nb of bytes), nb of items fn (mut g Gen) allocate_array(name string, size i32, items i32) i32 { - pos := g.code_gen.allocate_var(name, size, items) - g.stack_var_pos += (size * items) + 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 + g.stack_var_pos += (size * items) // reserve space on the stack return pos } @@ -945,6 +947,7 @@ fn (mut g Gen) eval_escape_codes(str string) string { } 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) @@ -969,9 +972,11 @@ fn (mut g Gen) gen_to_string(reg Register, typ ast.Type) { } else { g.n_error('int-to-string conversion not implemented for type ${typ}') } + g.println('; to_string }') } fn (mut g Gen) gen_var_to_string(reg Register, expr ast.Expr, var Var, config VarConfig) { + g.println('; var_to_string {') typ := g.get_type_from_var(var) if typ == ast.rune_type_idx { buffer := g.code_gen.allocate_var('rune-buffer', 8, 0) @@ -990,6 +995,7 @@ fn (mut g Gen) gen_var_to_string(reg Register, expr ast.Expr, var Var, config Va } else { g.n_error('int-to-string conversion not implemented for type ${typ}') } + g.println('; var_to_string }') } fn (mut g Gen) is_used_by_main(node ast.FnDecl) bool { From a8a9195892c71b357fba5f97383585a0926fd45b Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Sun, 16 Feb 2025 12:42:32 +0100 Subject: [PATCH 02/10] remove mov instruction --- vlib/v/gen/native/amd64.v | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index ff41cfc83d1c83..d73a8e67dd9103 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -1596,10 +1596,9 @@ fn (mut c Amd64) div_reg(a Amd64Register, b Amd64Register) { c.g.write8(0xf8) } .rbx { - c.mov(Amd64Register.edx, 0) c.g.write8(0x48) c.g.write8(0xf7) - c.g.write8(0xfb) // idiv ebx + c.g.write8(0xfb) } .rdx { c.g.write8(0x48) @@ -1610,7 +1609,7 @@ fn (mut c Amd64) div_reg(a Amd64Register, b Amd64Register) { panic('unhandled div ${b}') } } - c.g.println('idiv ${b}') + c.g.println('div ${b}') } fn (mut c Amd64) mod_reg(a Amd64Register, b Amd64Register) { From 9ed1218f06fc9a9a8dca87da6a1053b06c2a1853 Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Sun, 16 Feb 2025 13:53:32 +0100 Subject: [PATCH 03/10] add comments, replace manual div by c.div_reg, fix print label --- vlib/v/gen/native/amd64.v | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index d73a8e67dd9103..2a248424477c97 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -457,7 +457,7 @@ fn (op JumpOp) amd64() u16 { fn (mut c Amd64) cjmp(op JumpOp) i32 { c.g.write16(op.amd64()) pos := c.g.pos() - c.g.write32(placeholder) + c.g.write32(placeholder) // will get replaced by the right address c.g.println('${op}') return i32(pos) } @@ -3518,7 +3518,7 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { c.g.labels.addrs[skip_minus_label] = c.g.pos() c.g.println('; label ${skip_minus_label}') - c.mov_reg(Amd64Register.r12, Amd64Register.rdi) // copy the buffer position to r12 + c.mov_reg(Amd64Register.r12, Amd64Register.rdi) // copy the buffer position (start of the number without `-`) to r12 loop_label := c.g.labels.new_label() loop_start := c.g.pos() @@ -3540,11 +3540,7 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { c.pop(.rax) c.mov(Amd64Register.rbx, 10) c.cdq() - c.g.write8(0x48) - c.g.write8(0x48) // REX.W prefix for dividend RDX:RAX and quotient RAX - c.g.write8(0xf7) - c.g.write8(0xfb) - c.g.println('idiv rbx') + c.div_reg(.rax, .rbx) // go to the next character c.inc(.rdi) @@ -3556,7 +3552,7 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { id: loop_label pos: loop_cjmp_addr } - c.g.println('; jump to label ${skip_minus_label}') + c.g.println('; jump to label ${loop_label}') c.g.labels.addrs[loop_label] = loop_start // after all was converted, reverse the string From 0c460df3d87dc032a3881fd6dd48720adfe4d406 Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Sun, 16 Feb 2025 14:04:10 +0100 Subject: [PATCH 04/10] simplify the division --- vlib/v/gen/native/amd64.v | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 2a248424477c97..32be79eaf6411f 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -3524,11 +3524,9 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { loop_start := c.g.pos() c.g.println('; label ${loop_label}') - c.push(Amd64Register.rax) - c.mov(Amd64Register.rdx, 0) // upperhalf of the dividend c.mov(Amd64Register.rbx, 10) - c.div_reg(.rax, .rbx) + c.div_reg(.rax, .rbx) // rax will be the result of the division c.add8(.rdx, i32(`0`)) // rdx is the remainder, add 48 to convert it into it's ascii representation c.g.write8(0x66) @@ -3536,12 +3534,6 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { c.g.write8(0x17) c.g.println('mov BYTE PTR [rdi], rdx') - // divide the integer in rax by 10 for next iteration - c.pop(.rax) - c.mov(Amd64Register.rbx, 10) - c.cdq() - c.div_reg(.rax, .rbx) - // go to the next character c.inc(.rdi) From 6195a4af9fa3a96a2d0b2142994ac27eb26ff341 Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Sun, 16 Feb 2025 15:22:32 +0100 Subject: [PATCH 05/10] more comments --- vlib/v/gen/native/gen.v | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index ff38173b172b2e..27c78e35e5d38b 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -856,11 +856,11 @@ fn (mut g Gen) allocate_string(s string, opsize i32, typ RelocType) i32 { return str_pos } -// name, size of stored type (nb of bytes), nb of items +// 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 - g.stack_var_pos += (size * items) // reserve space on the stack + pos := g.code_gen.allocate_var(name, size, items) // store the lenght of the array on the stack + g.stack_var_pos += (size * items) // reserve space on the stack for the items return pos } From 1d604db3c0e928f57fa1f642c1e55ef7d372aefc Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Sun, 16 Feb 2025 16:06:10 +0100 Subject: [PATCH 06/10] clear the Direction flag to avoid inconsistencies --- vlib/v/gen/native/amd64.v | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 32be79eaf6411f..1b7adc2bfe0c92 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -3563,8 +3563,6 @@ fn (mut c Amd64) reverse_string(r Register) { c.mov_reg(Amd64Register.rdi, reg) } - c.mov(Amd64Register.eax, 0) - c.g.write8(0x48) c.g.write8(0x8d) c.g.write8(0x48) @@ -3573,9 +3571,9 @@ fn (mut c Amd64) reverse_string(r Register) { c.mov_reg(Amd64Register.rsi, Amd64Register.rdi) - c.g.write8(0xf2) - c.g.write8(0xae) - c.g.println('repnz scas al, BYTE PTR es:[rdi]') + // search for null at end of string + c.mov(Amd64Register.eax, 0) + c.cld_repne_scasb() c.sub8(.rdi, 0x2) c.cmp_reg(.rdi, .rsi) From c9a5ce8c1123e6cb33392f587d3aa80080c300ff Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Sun, 16 Feb 2025 17:13:47 +0100 Subject: [PATCH 07/10] null terminate the buffer (\0 is used to find it's lenght) --- vlib/v/gen/native/amd64.v | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 1b7adc2bfe0c92..d3c6e8a180673e 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -3482,6 +3482,13 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { c.g.write8(0x07) c.g.write8(0x30) c.g.println("mov BYTE PTR [rdi], '0'") + + // null terminate the string + c.inc(.rdi) + c.g.write8(0xc6) + c.g.write8(0x07) + c.g.write8(0x0) + c.g.println("mov BYTE PTR [rdi], `\0`") end_label := c.g.labels.new_label() end_jmp_addr := c.jmp(0) @@ -3546,6 +3553,13 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { } c.g.println('; jump to label ${loop_label}') c.g.labels.addrs[loop_label] = loop_start + + // null terminate the string + c.inc(.rdi) + c.g.write8(0xc6) + c.g.write8(0x07) + c.g.write8(0x0) + c.g.println("mov BYTE PTR [rdi], `\0`") // after all was converted, reverse the string reg := c.g.get_builtin_arg_reg(.reverse_string, 0) as Amd64Register From c31ffa23b6729948af3da2f65a733999956e1d91 Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Sun, 16 Feb 2025 18:34:06 +0100 Subject: [PATCH 08/10] add test --- vlib/v/gen/native/tests/print.vv | 7 +++++++ vlib/v/gen/native/tests/print.vv.out | 1 + 2 files changed, 8 insertions(+) diff --git a/vlib/v/gen/native/tests/print.vv b/vlib/v/gen/native/tests/print.vv index 9dde6f34d7d5b3..f86639d60e9a5e 100644 --- a/vlib/v/gen/native/tests/print.vv +++ b/vlib/v/gen/native/tests/print.vv @@ -104,6 +104,12 @@ fn test_interpolated() { println('num: ${num}; bool: ${boool}') } +fn test_intermediate() { + c := 0 + a := 'a' + println(c) +} + fn main() { test_stdout() test_stderr() @@ -113,4 +119,5 @@ fn main() { test_exprs() test_sizeof() test_interpolated() + test_intermediate() } diff --git a/vlib/v/gen/native/tests/print.vv.out b/vlib/v/gen/native/tests/print.vv.out index 9653ce9a200dc7..740ada47b83200 100644 --- a/vlib/v/gen/native/tests/print.vv.out +++ b/vlib/v/gen/native/tests/print.vv.out @@ -21,3 +21,4 @@ false true sizeof: 4, 12 this is an interpolated string num: 42; bool: true +0 From d0a74f7be791bc74f4b587acb06a9865bd6d0d2f Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Sun, 16 Feb 2025 18:50:22 +0100 Subject: [PATCH 09/10] vfmt --- vlib/v/gen/native/amd64.v | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index d3c6e8a180673e..8357316970734e 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -466,7 +466,7 @@ fn (mut c Amd64) jmp(addr i32) i32 { c.g.write8(0xe9) pos := c.g.pos() c.g.write32(addr) // 0xffffff - c.g.println('jmp ${int(pos+addr).hex2()}') + c.g.println('jmp ${int(pos + addr).hex2()}') // return the position of jump address for placeholder return i32(pos) } @@ -3482,13 +3482,13 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { c.g.write8(0x07) c.g.write8(0x30) c.g.println("mov BYTE PTR [rdi], '0'") - + // null terminate the string c.inc(.rdi) c.g.write8(0xc6) c.g.write8(0x07) c.g.write8(0x0) - c.g.println("mov BYTE PTR [rdi], `\0`") + c.g.println('mov BYTE PTR [rdi], `\0`') end_label := c.g.labels.new_label() end_jmp_addr := c.jmp(0) @@ -3525,7 +3525,7 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { c.g.labels.addrs[skip_minus_label] = c.g.pos() c.g.println('; label ${skip_minus_label}') - c.mov_reg(Amd64Register.r12, Amd64Register.rdi) // copy the buffer position (start of the number without `-`) to r12 + c.mov_reg(Amd64Register.r12, Amd64Register.rdi) // copy the buffer position (start of the number without `-`) to r12 loop_label := c.g.labels.new_label() loop_start := c.g.pos() @@ -3553,13 +3553,13 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { } c.g.println('; jump to label ${loop_label}') c.g.labels.addrs[loop_label] = loop_start - + // null terminate the string c.inc(.rdi) c.g.write8(0xc6) c.g.write8(0x07) c.g.write8(0x0) - c.g.println("mov BYTE PTR [rdi], `\0`") + c.g.println('mov BYTE PTR [rdi], `\0`') // after all was converted, reverse the string reg := c.g.get_builtin_arg_reg(.reverse_string, 0) as Amd64Register From 3e8133b270e88609e3883b55afb6a2bf56e732aa Mon Sep 17 00:00:00 2001 From: Eliyaan Date: Sun, 16 Feb 2025 20:56:14 +0100 Subject: [PATCH 10/10] fix null termination, change mov WORD to mov BYTE (was not the right hex code) fmt --- vlib/v/gen/native/amd64.v | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 8357316970734e..03a8370696b3fc 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -603,7 +603,7 @@ fn (mut c Amd64) mov_store(regptr Amd64Register, reg Amd64Register, size Size) { } c.g.write8(if size == ._8 { i32(0x88) } else { i32(0x89) }) c.g.write8(i32(reg) % 8 * 8 + i32(regptr) % 8) - c.g.println('mov [${regptr}], ${reg}') + c.g.println('mov [${regptr}], ${reg} ; size:${size}bits') } fn (mut c Amd64) mov_reg_to_var(var Var, r Register, config VarConfig) { @@ -3536,10 +3536,7 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { c.div_reg(.rax, .rbx) // rax will be the result of the division c.add8(.rdx, i32(`0`)) // rdx is the remainder, add 48 to convert it into it's ascii representation - c.g.write8(0x66) - c.g.write8(0x89) - c.g.write8(0x17) - c.g.println('mov BYTE PTR [rdi], rdx') + c.mov_store(.rdi, .rdx, ._8) // go to the next character c.inc(.rdi) @@ -3555,7 +3552,6 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) { c.g.labels.addrs[loop_label] = loop_start // null terminate the string - c.inc(.rdi) c.g.write8(0xc6) c.g.write8(0x07) c.g.write8(0x0)