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) {
|
fn (mut g Gen) inc(reg Register) {
|
||||||
g.write16(0xff49)
|
g.write8(0x48)
|
||||||
match reg {
|
g.write8(0xff)
|
||||||
.rcx { g.write8(0xc1) }
|
g.write8(0xc0 + int(reg))
|
||||||
.r12 { g.write8(0xc4) }
|
|
||||||
else { panic('unhandled inc $reg') }
|
|
||||||
}
|
|
||||||
g.println('inc $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 {
|
else {
|
||||||
g.n_error('Cannot compare $reg and $reg2')
|
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) {
|
fn (mut g Gen) tmp_jle(addr i64) {
|
||||||
// Calculate the relative offset to jump to
|
// Calculate the relative offset to jump to
|
||||||
// (`addr` is absolute address)
|
// (`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(0x7e)
|
||||||
g.write8(offset)
|
g.write8(offset)
|
||||||
g.println('jle')
|
g.println('jle')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) jl(addr i64) {
|
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(0x7c)
|
||||||
g.write8(offset)
|
g.write8(offset)
|
||||||
g.println('jl')
|
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) {
|
fn (mut g Gen) lea_var_to_reg(reg Register, var_offset int) {
|
||||||
match reg {
|
match reg {
|
||||||
.rax, .rbx, .rsi {
|
.rax, .rbx, .rsi, .rdi {
|
||||||
g.write8(0x48)
|
g.write8(0x48)
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
|
@ -445,6 +452,11 @@ fn (mut g Gen) syscall() {
|
||||||
g.println('syscall')
|
g.println('syscall')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) cdq() {
|
||||||
|
g.write8(0x99)
|
||||||
|
g.println('cdq')
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) ret() {
|
pub fn (mut g Gen) ret() {
|
||||||
g.write8(0xc3)
|
g.write8(0xc3)
|
||||||
g.println('ret')
|
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) {
|
pub fn (mut g Gen) add8(reg Register, val int) {
|
||||||
g.write8(0x48)
|
g.write8(0x48)
|
||||||
g.write8(0x83)
|
g.write8(0x83)
|
||||||
// g.write8(0xe8 + reg) // TODO rax is different?
|
g.write8(0xc0 + int(reg))
|
||||||
g.write8(0xc4)
|
|
||||||
g.write8(val)
|
g.write8(val)
|
||||||
g.println('add8 $reg,$val.hex2()')
|
g.println('add8 $reg,$val.hex2()')
|
||||||
}
|
}
|
||||||
|
@ -595,9 +606,18 @@ pub fn (mut g Gen) rep_stosb() {
|
||||||
g.println('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.write8(0xfc)
|
||||||
g.println('cld')
|
g.println('cld')
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut g Gen) cld_repne_scasb() {
|
||||||
|
g.cld()
|
||||||
g.write8(0xf2)
|
g.write8(0xf2)
|
||||||
g.write8(0xae)
|
g.write8(0xae)
|
||||||
g.println('repne scasb')
|
g.println('repne scasb')
|
||||||
|
@ -931,6 +951,9 @@ fn (mut g Gen) mov(reg Register, val int) {
|
||||||
g.write8(0x41)
|
g.write8(0x41)
|
||||||
g.write8(0xbc) // r11 is 0xbb etc
|
g.write8(0xbc) // r11 is 0xbb etc
|
||||||
}
|
}
|
||||||
|
.rbx {
|
||||||
|
g.write8(0xbb)
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
g.n_error('unhandled mov $reg')
|
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(0x48)
|
||||||
g.write8(0x89)
|
g.write8(0x89)
|
||||||
g.write8(0xc7)
|
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 {
|
} else {
|
||||||
g.n_error('unhandled mov_reg combination for $a $b')
|
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.labels.addrs[skip_zero_label] = g.pos()
|
||||||
g.println('; label $skip_zero_label')
|
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
|
// detect if value in rax is negative
|
||||||
g.cmp_zero(.rax)
|
g.cmp_zero(.rax)
|
||||||
skip_minus_label := g.labels.new_label()
|
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
|
// add a `-` sign as the first character
|
||||||
g.mov_int_to_var(buffer, ._8, '-'[0])
|
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.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.labels.addrs[end_label] = g.pos()
|
||||||
g.println('; label $end_label')
|
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
|
x := 0
|
||||||
println(x)
|
println(x)
|
||||||
|
|
||||||
// y := -5
|
y := 5
|
||||||
// println(y)
|
println(y)
|
||||||
|
|
||||||
|
z := -8
|
||||||
|
println(z)
|
||||||
|
|
||||||
|
a := 123
|
||||||
|
println(a)
|
||||||
|
|
||||||
|
b := -456
|
||||||
|
println(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -4,3 +4,7 @@ Hello World
|
||||||
4
|
4
|
||||||
8
|
8
|
||||||
0
|
0
|
||||||
|
5
|
||||||
|
-8
|
||||||
|
123
|
||||||
|
-456
|
Loading…
Reference in New Issue