Skip to content

Commit

Permalink
native: fix convert_int_to_string, add comments in the verbose (-v) m…
Browse files Browse the repository at this point in the history
…ode (#23743)
  • Loading branch information
Eliyaan authored Feb 17, 2025
1 parent 997ffdc commit 6534616
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 35 deletions.
68 changes: 35 additions & 33 deletions vlib/v/gen/native/amd64.v
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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)
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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 {
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -1590,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)
Expand Down Expand Up @@ -1937,8 +1942,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
}

Expand Down Expand Up @@ -3478,6 +3483,13 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) {
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)
c.g.labels.patches << LabelPatch{
Expand Down Expand Up @@ -3513,32 +3525,18 @@ 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()
c.g.println('; label ${loop_label}')

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.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')

// divide the integer in rax by 10 for next iteration
c.pop(.rax)
c.mov(Amd64Register.rbx, 10)
c.cdq()
c.g.write8(0x48)
c.g.write8(0xf7)
c.g.write8(0xfb)
c.g.println('idiv rbx')
c.mov_store(.rdi, .rdx, ._8)

// go to the next character
c.inc(.rdi)
Expand All @@ -3550,9 +3548,15 @@ 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

// null terminate the string
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
c.mov_reg(reg, Amd64Register.r12)
Expand All @@ -3569,8 +3573,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)
Expand All @@ -3579,9 +3581,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)
Expand Down
10 changes: 8 additions & 2 deletions vlib/v/gen/native/gen.v
Original file line number Diff line number Diff line change
Expand Up @@ -856,9 +856,11 @@ fn (mut g Gen) allocate_string(s string, opsize i32, typ RelocType) i32 {
return str_pos
}

// 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 {
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 on the stack
g.stack_var_pos += (size * items) // reserve space on the stack for the items
return pos
}

Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions vlib/v/gen/native/tests/print.vv
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -113,4 +119,5 @@ fn main() {
test_exprs()
test_sizeof()
test_interpolated()
test_intermediate()
}
1 change: 1 addition & 0 deletions vlib/v/gen/native/tests/print.vv.out
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ false true
sizeof: 4, 12
this is an interpolated string
num: 42; bool: true
0

0 comments on commit 6534616

Please sign in to comment.