native: integer-to-string conversion (#14758)
parent
67716b5b59
commit
2f1a896d18
|
@ -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')
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -4,3 +4,7 @@ Hello World
|
|||
4
|
||||
8
|
||||
0
|
||||
5
|
||||
-8
|
||||
123
|
||||
-456
|
Loading…
Reference in New Issue