native: integer-to-string conversion (#14758)

master
Spydr 2022-06-13 23:35:25 +02:00 committed by GitHub
parent 67716b5b59
commit 2f1a896d18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 159 additions and 16 deletions

View File

@ -59,12 +59,9 @@ fn byt(n int, s int) u8 {
}
fn (mut g Gen) inc(reg Register) {
g.write16(0xff49)
match reg {
.rcx { g.write8(0xc1) }
.r12 { g.write8(0xc4) }
else { panic('unhandled inc $reg') }
}
g.write8(0x48)
g.write8(0xff)
g.write8(0xc0 + int(reg))
g.println('inc $reg')
}
@ -138,6 +135,16 @@ fn (mut g Gen) cmp_reg(reg Register, reg2 Register) {
}
}
}
.rdi {
match reg2 {
.rsi {
g.write([u8(0x48), 0x39, 0xf7])
}
else {
g.n_error('Cannot compare $reg and $reg2')
}
}
}
else {
g.n_error('Cannot compare $reg and $reg2')
}
@ -235,14 +242,14 @@ fn abs(a i64) i64 {
fn (mut g Gen) tmp_jle(addr i64) {
// Calculate the relative offset to jump to
// (`addr` is absolute address)
offset := 0xff - int(abs(addr - g.buf.len)) - 1
offset := 0xff - g.abs_to_rel_addr(addr)
g.write8(0x7e)
g.write8(offset)
g.println('jle')
}
fn (mut g Gen) jl(addr i64) {
offset := 0xff - int(abs(addr - g.buf.len)) - 1
offset := 0xff - g.abs_to_rel_addr(addr)
g.write8(0x7c)
g.write8(offset)
g.println('jl')
@ -381,7 +388,7 @@ fn (mut g Gen) mov_int_to_var(var_offset int, size Size, integer int) {
fn (mut g Gen) lea_var_to_reg(reg Register, var_offset int) {
match reg {
.rax, .rbx, .rsi {
.rax, .rbx, .rsi, .rdi {
g.write8(0x48)
}
else {}
@ -445,6 +452,11 @@ fn (mut g Gen) syscall() {
g.println('syscall')
}
fn (mut g Gen) cdq() {
g.write8(0x99)
g.println('cdq')
}
pub fn (mut g Gen) ret() {
g.write8(0xc3)
g.println('ret')
@ -509,8 +521,7 @@ pub fn (mut g Gen) add(reg Register, val int) {
pub fn (mut g Gen) add8(reg Register, val int) {
g.write8(0x48)
g.write8(0x83)
// g.write8(0xe8 + reg) // TODO rax is different?
g.write8(0xc4)
g.write8(0xc0 + int(reg))
g.write8(val)
g.println('add8 $reg,$val.hex2()')
}
@ -595,9 +606,18 @@ pub fn (mut g Gen) rep_stosb() {
g.println('rep stosb')
}
pub fn (mut g Gen) cld_repne_scasb() {
pub fn (mut g Gen) std() {
g.write8(0xfd)
g.println('std')
}
pub fn (mut g Gen) cld() {
g.write8(0xfc)
g.println('cld')
}
pub fn (mut g Gen) cld_repne_scasb() {
g.cld()
g.write8(0xf2)
g.write8(0xae)
g.println('repne scasb')
@ -931,6 +951,9 @@ fn (mut g Gen) mov(reg Register, val int) {
g.write8(0x41)
g.write8(0xbc) // r11 is 0xbb etc
}
.rbx {
g.write8(0xbb)
}
else {
g.n_error('unhandled mov $reg')
}
@ -1084,6 +1107,18 @@ fn (mut g Gen) mov_reg(a Register, b Register) {
g.write8(0x48)
g.write8(0x89)
g.write8(0xc7)
} else if a == .r12 && b == .rdi {
g.write8(0x49)
g.write8(0x89)
g.write8(0xfc)
} else if a == .rdi && b == .r12 {
g.write8(0x4c)
g.write8(0x89)
g.write8(0xe7)
} else if a == .rsi && b == .rdi {
g.write8(0x48)
g.write8(0x89)
g.write8(0xfe)
} else {
g.n_error('unhandled mov_reg combination for $a $b')
}
@ -1988,6 +2023,9 @@ fn (mut g Gen) convert_int_to_string(r Register, buffer int) {
g.labels.addrs[skip_zero_label] = g.pos()
g.println('; label $skip_zero_label')
// load a pointer to the string to rdi
g.lea_var_to_reg(.rdi, buffer)
// detect if value in rax is negative
g.cmp_zero(.rax)
skip_minus_label := g.labels.new_label()
@ -2000,11 +2038,103 @@ fn (mut g Gen) convert_int_to_string(r Register, buffer int) {
// add a `-` sign as the first character
g.mov_int_to_var(buffer, ._8, '-'[0])
g.neg(.rax)
g.neg(.rax) // negate our integer to make it positive
g.inc(.rdi) // increment rdi to skip the `-` character
g.labels.addrs[skip_minus_label] = g.pos()
g.println('; label $skip_minus_label')
// TODO: convert non-zero integer to string
g.mov_reg(.r12, .rdi) // copy the buffer position to rcx
loop_label := g.labels.new_label()
loop_start := g.pos()
g.println('; label $loop_label')
g.push(.rax)
g.mov(.rdx, 0)
g.mov(.rbx, 10)
g.div_reg(.rax, .rbx)
g.add8(.rdx, '0'[0])
g.write8(0x66)
g.write8(0x89)
g.write8(0x17)
g.println('mov BYTE PTR [rdi], rdx')
// divide the integer in rax by 10 for next iteration
g.pop(.rax)
g.mov(.rbx, 10)
g.cdq()
g.write8(0x48)
g.write8(0xf7)
g.write8(0xfb)
g.println('idiv rbx')
// go to the next character
g.inc(.rdi)
// if the number in rax still isn't zero, repeat
g.cmp_zero(.rax)
loop_cjmp_addr := g.cjmp(.jg)
g.labels.patches << LabelPatch{
id: loop_label
pos: loop_cjmp_addr
}
g.println('; jump to label $skip_minus_label')
g.labels.addrs[loop_label] = loop_start
// after all was converted, reverse the string
g.reverse_string(.r12)
g.labels.addrs[end_label] = g.pos()
g.println('; label $end_label')
}
fn (mut g Gen) reverse_string(reg Register) {
if reg != .rdi {
g.mov_reg(.rdi, reg)
}
g.mov(.eax, 0)
g.write8(0x48)
g.write8(0x8d)
g.write8(0x48)
g.write8(0xff)
g.println('lea rcx, [rax-0x1]')
g.mov_reg(.rsi, .rdi)
g.write8(0xf2)
g.write8(0xae)
g.println('repnz scas al, BYTE PTR es:[rdi]')
g.sub8(.rdi, 0x2)
g.cmp_reg(.rdi, .rsi)
g.write8(0x7e)
g.write8(0x0a)
g.println('jle 0x1e')
g.write8(0x86)
g.write8(0x07)
g.println('xchg BYTE PTR [rdi], al')
g.write8(0x86)
g.write8(0x06)
g.println('xchg BYTE PTR [rsi], al')
g.std()
g.write8(0xaa)
g.println('stos BYTE PTR es:[rdi], al')
g.cld()
g.write8(0xac)
g.println('lods al, BYTE PTR ds:[rsi]')
g.write8(0xeb)
g.write8(0xf1)
g.println('jmp 0xf')
}

View File

@ -33,8 +33,17 @@ fn test_idents() {
x := 0
println(x)
// y := -5
// println(y)
y := 5
println(y)
z := -8
println(z)
a := 123
println(a)
b := -456
println(b)
}
fn main() {

View File

@ -4,3 +4,7 @@ Hello World
4
8
0
5
-8
123
-456