Skip to content

Commit 2f1a896

Browse files
authored
native: integer-to-string conversion (#14758)
1 parent 67716b5 commit 2f1a896

File tree

3 files changed

+159
-16
lines changed

3 files changed

+159
-16
lines changed

vlib/v/gen/native/amd64.v

Lines changed: 144 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,9 @@ fn byt(n int, s int) u8 {
5959
}
6060

6161
fn (mut g Gen) inc(reg Register) {
62-
g.write16(0xff49)
63-
match reg {
64-
.rcx { g.write8(0xc1) }
65-
.r12 { g.write8(0xc4) }
66-
else { panic('unhandled inc $reg') }
67-
}
62+
g.write8(0x48)
63+
g.write8(0xff)
64+
g.write8(0xc0 + int(reg))
6865
g.println('inc $reg')
6966
}
7067

@@ -138,6 +135,16 @@ fn (mut g Gen) cmp_reg(reg Register, reg2 Register) {
138135
}
139136
}
140137
}
138+
.rdi {
139+
match reg2 {
140+
.rsi {
141+
g.write([u8(0x48), 0x39, 0xf7])
142+
}
143+
else {
144+
g.n_error('Cannot compare $reg and $reg2')
145+
}
146+
}
147+
}
141148
else {
142149
g.n_error('Cannot compare $reg and $reg2')
143150
}
@@ -235,14 +242,14 @@ fn abs(a i64) i64 {
235242
fn (mut g Gen) tmp_jle(addr i64) {
236243
// Calculate the relative offset to jump to
237244
// (`addr` is absolute address)
238-
offset := 0xff - int(abs(addr - g.buf.len)) - 1
245+
offset := 0xff - g.abs_to_rel_addr(addr)
239246
g.write8(0x7e)
240247
g.write8(offset)
241248
g.println('jle')
242249
}
243250

244251
fn (mut g Gen) jl(addr i64) {
245-
offset := 0xff - int(abs(addr - g.buf.len)) - 1
252+
offset := 0xff - g.abs_to_rel_addr(addr)
246253
g.write8(0x7c)
247254
g.write8(offset)
248255
g.println('jl')
@@ -381,7 +388,7 @@ fn (mut g Gen) mov_int_to_var(var_offset int, size Size, integer int) {
381388

382389
fn (mut g Gen) lea_var_to_reg(reg Register, var_offset int) {
383390
match reg {
384-
.rax, .rbx, .rsi {
391+
.rax, .rbx, .rsi, .rdi {
385392
g.write8(0x48)
386393
}
387394
else {}
@@ -445,6 +452,11 @@ fn (mut g Gen) syscall() {
445452
g.println('syscall')
446453
}
447454

455+
fn (mut g Gen) cdq() {
456+
g.write8(0x99)
457+
g.println('cdq')
458+
}
459+
448460
pub fn (mut g Gen) ret() {
449461
g.write8(0xc3)
450462
g.println('ret')
@@ -509,8 +521,7 @@ pub fn (mut g Gen) add(reg Register, val int) {
509521
pub fn (mut g Gen) add8(reg Register, val int) {
510522
g.write8(0x48)
511523
g.write8(0x83)
512-
// g.write8(0xe8 + reg) // TODO rax is different?
513-
g.write8(0xc4)
524+
g.write8(0xc0 + int(reg))
514525
g.write8(val)
515526
g.println('add8 $reg,$val.hex2()')
516527
}
@@ -595,9 +606,18 @@ pub fn (mut g Gen) rep_stosb() {
595606
g.println('rep stosb')
596607
}
597608

598-
pub fn (mut g Gen) cld_repne_scasb() {
609+
pub fn (mut g Gen) std() {
610+
g.write8(0xfd)
611+
g.println('std')
612+
}
613+
614+
pub fn (mut g Gen) cld() {
599615
g.write8(0xfc)
600616
g.println('cld')
617+
}
618+
619+
pub fn (mut g Gen) cld_repne_scasb() {
620+
g.cld()
601621
g.write8(0xf2)
602622
g.write8(0xae)
603623
g.println('repne scasb')
@@ -931,6 +951,9 @@ fn (mut g Gen) mov(reg Register, val int) {
931951
g.write8(0x41)
932952
g.write8(0xbc) // r11 is 0xbb etc
933953
}
954+
.rbx {
955+
g.write8(0xbb)
956+
}
934957
else {
935958
g.n_error('unhandled mov $reg')
936959
}
@@ -1084,6 +1107,18 @@ fn (mut g Gen) mov_reg(a Register, b Register) {
10841107
g.write8(0x48)
10851108
g.write8(0x89)
10861109
g.write8(0xc7)
1110+
} else if a == .r12 && b == .rdi {
1111+
g.write8(0x49)
1112+
g.write8(0x89)
1113+
g.write8(0xfc)
1114+
} else if a == .rdi && b == .r12 {
1115+
g.write8(0x4c)
1116+
g.write8(0x89)
1117+
g.write8(0xe7)
1118+
} else if a == .rsi && b == .rdi {
1119+
g.write8(0x48)
1120+
g.write8(0x89)
1121+
g.write8(0xfe)
10871122
} else {
10881123
g.n_error('unhandled mov_reg combination for $a $b')
10891124
}
@@ -1988,6 +2023,9 @@ fn (mut g Gen) convert_int_to_string(r Register, buffer int) {
19882023
g.labels.addrs[skip_zero_label] = g.pos()
19892024
g.println('; label $skip_zero_label')
19902025

2026+
// load a pointer to the string to rdi
2027+
g.lea_var_to_reg(.rdi, buffer)
2028+
19912029
// detect if value in rax is negative
19922030
g.cmp_zero(.rax)
19932031
skip_minus_label := g.labels.new_label()
@@ -2000,11 +2038,103 @@ fn (mut g Gen) convert_int_to_string(r Register, buffer int) {
20002038

20012039
// add a `-` sign as the first character
20022040
g.mov_int_to_var(buffer, ._8, '-'[0])
2003-
g.neg(.rax)
2041+
g.neg(.rax) // negate our integer to make it positive
2042+
g.inc(.rdi) // increment rdi to skip the `-` character
20042043
g.labels.addrs[skip_minus_label] = g.pos()
2044+
g.println('; label $skip_minus_label')
2045+
2046+
g.mov_reg(.r12, .rdi) // copy the buffer position to rcx
2047+
2048+
loop_label := g.labels.new_label()
2049+
loop_start := g.pos()
2050+
g.println('; label $loop_label')
2051+
2052+
g.push(.rax)
2053+
2054+
g.mov(.rdx, 0)
2055+
g.mov(.rbx, 10)
2056+
g.div_reg(.rax, .rbx)
2057+
g.add8(.rdx, '0'[0])
20052058

2006-
// TODO: convert non-zero integer to string
2059+
g.write8(0x66)
2060+
g.write8(0x89)
2061+
g.write8(0x17)
2062+
g.println('mov BYTE PTR [rdi], rdx')
2063+
2064+
// divide the integer in rax by 10 for next iteration
2065+
g.pop(.rax)
2066+
g.mov(.rbx, 10)
2067+
g.cdq()
2068+
g.write8(0x48)
2069+
g.write8(0xf7)
2070+
g.write8(0xfb)
2071+
g.println('idiv rbx')
2072+
2073+
// go to the next character
2074+
g.inc(.rdi)
2075+
2076+
// if the number in rax still isn't zero, repeat
2077+
g.cmp_zero(.rax)
2078+
loop_cjmp_addr := g.cjmp(.jg)
2079+
g.labels.patches << LabelPatch{
2080+
id: loop_label
2081+
pos: loop_cjmp_addr
2082+
}
2083+
g.println('; jump to label $skip_minus_label')
2084+
g.labels.addrs[loop_label] = loop_start
2085+
2086+
// after all was converted, reverse the string
2087+
g.reverse_string(.r12)
20072088

20082089
g.labels.addrs[end_label] = g.pos()
20092090
g.println('; label $end_label')
20102091
}
2092+
2093+
fn (mut g Gen) reverse_string(reg Register) {
2094+
if reg != .rdi {
2095+
g.mov_reg(.rdi, reg)
2096+
}
2097+
2098+
g.mov(.eax, 0)
2099+
2100+
g.write8(0x48)
2101+
g.write8(0x8d)
2102+
g.write8(0x48)
2103+
g.write8(0xff)
2104+
g.println('lea rcx, [rax-0x1]')
2105+
2106+
g.mov_reg(.rsi, .rdi)
2107+
2108+
g.write8(0xf2)
2109+
g.write8(0xae)
2110+
g.println('repnz scas al, BYTE PTR es:[rdi]')
2111+
2112+
g.sub8(.rdi, 0x2)
2113+
g.cmp_reg(.rdi, .rsi)
2114+
2115+
g.write8(0x7e)
2116+
g.write8(0x0a)
2117+
g.println('jle 0x1e')
2118+
2119+
g.write8(0x86)
2120+
g.write8(0x07)
2121+
g.println('xchg BYTE PTR [rdi], al')
2122+
2123+
g.write8(0x86)
2124+
g.write8(0x06)
2125+
g.println('xchg BYTE PTR [rsi], al')
2126+
2127+
g.std()
2128+
2129+
g.write8(0xaa)
2130+
g.println('stos BYTE PTR es:[rdi], al')
2131+
2132+
g.cld()
2133+
2134+
g.write8(0xac)
2135+
g.println('lods al, BYTE PTR ds:[rsi]')
2136+
2137+
g.write8(0xeb)
2138+
g.write8(0xf1)
2139+
g.println('jmp 0xf')
2140+
}

vlib/v/gen/native/tests/print.vv

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,17 @@ fn test_idents() {
3333
x := 0
3434
println(x)
3535

36-
// y := -5
37-
// println(y)
36+
y := 5
37+
println(y)
38+
39+
z := -8
40+
println(z)
41+
42+
a := 123
43+
println(a)
44+
45+
b := -456
46+
println(b)
3847
}
3948

4049
fn main() {

vlib/v/gen/native/tests/print.vv.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@ Hello World
44
4
55
8
66
0
7+
5
8+
-8
9+
123
10+
-456

0 commit comments

Comments
 (0)