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