native: added new helper functions (#14723)
parent
f58e5a94c2
commit
8563696476
|
@ -135,6 +135,24 @@ fn (mut g Gen) cmp_reg(reg Register, reg2 Register) {
|
|||
g.println('cmp $reg, $reg2')
|
||||
}
|
||||
|
||||
// cmp $reg, 0
|
||||
fn (mut g Gen) cmp_zero(reg Register) {
|
||||
g.write8(0x48)
|
||||
g.write8(0x39)
|
||||
|
||||
match reg {
|
||||
.rax {
|
||||
g.write8(0x04)
|
||||
g.write8(0x25)
|
||||
}
|
||||
else {
|
||||
panic('unhandled cmp $reg, 0')
|
||||
}
|
||||
}
|
||||
|
||||
g.write32(0)
|
||||
}
|
||||
|
||||
fn (mut g Gen) cmp_var_reg(var_name string, reg Register) {
|
||||
g.write8(0x48) // 83 for 1 byte?
|
||||
g.write8(0x39)
|
||||
|
@ -225,6 +243,26 @@ fn (mut g Gen) jmp(addr i64) {
|
|||
g.write8(offset)
|
||||
}
|
||||
*/
|
||||
|
||||
fn (mut g Gen) mov32(reg Register, val int) {
|
||||
match reg {
|
||||
.rax {
|
||||
g.write8(0xb8)
|
||||
}
|
||||
.rdi {
|
||||
g.write8(0xbf)
|
||||
}
|
||||
.rcx {
|
||||
g.write8(0xb9)
|
||||
}
|
||||
else {
|
||||
panic('unhandled mov32 $reg')
|
||||
}
|
||||
}
|
||||
g.write32(val)
|
||||
g.println('mov32 $reg, $val')
|
||||
}
|
||||
|
||||
fn (mut g Gen) mov64(reg Register, val i64) {
|
||||
match reg {
|
||||
.eax {
|
||||
|
@ -272,6 +310,21 @@ fn (mut g Gen) mov64(reg Register, val i64) {
|
|||
g.println('mov64 $reg, $val')
|
||||
}
|
||||
|
||||
fn (mut g Gen) movabs(reg Register, val i64) {
|
||||
match reg {
|
||||
.rsi {
|
||||
g.write8(0x48)
|
||||
g.write8(0xbe)
|
||||
}
|
||||
else {
|
||||
panic('unhandled movabs $reg, $val')
|
||||
}
|
||||
}
|
||||
|
||||
g.write64(val)
|
||||
g.println('movabs $reg, $val')
|
||||
}
|
||||
|
||||
fn (mut g Gen) mov_reg_to_var(var_offset int, reg Register) {
|
||||
// 89 7d fc mov DWORD PTR [rbp-0x4],edi
|
||||
match reg {
|
||||
|
@ -293,6 +346,27 @@ fn (mut g Gen) mov_reg_to_var(var_offset int, reg Register) {
|
|||
g.println('mov DWORD PTR[rbp-$var_offset.hex2()],$reg')
|
||||
}
|
||||
|
||||
fn (mut g Gen) lea_var_to_reg(reg Register, var_offset int) {
|
||||
match reg {
|
||||
.rax, .rbx, .rsi {
|
||||
g.write8(0x48)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
g.write8(0x8d)
|
||||
match reg {
|
||||
.eax, .rax { g.write8(0x45) }
|
||||
.edi, .rdi { g.write8(0x7d) }
|
||||
.rsi { g.write8(0x75) }
|
||||
.rdx { g.write8(0x55) }
|
||||
.rbx { g.write8(0x5d) }
|
||||
.rcx { g.write8(0x4d) }
|
||||
else { g.n_error('lea_var_to_reg $reg') }
|
||||
}
|
||||
g.write8(0xff - var_offset + 1)
|
||||
g.println('lea $reg, [rbp-$var_offset.hex2()]')
|
||||
}
|
||||
|
||||
fn (mut g Gen) mov_var_to_reg(reg Register, var_offset int) {
|
||||
// 8b 7d f8 mov edi,DWORD PTR [rbp-0x8]
|
||||
match reg {
|
||||
|
@ -473,6 +547,21 @@ pub fn (mut g Gen) allocate_string(s string, opsize int, typ RelocType) int {
|
|||
return str_pos
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) var_zero(vo int, size int) {
|
||||
g.mov32(.rcx, size)
|
||||
g.lea_var_to_reg(.rdi, vo)
|
||||
g.write8(0xb0)
|
||||
g.write8(0x00)
|
||||
g.println('mov al, 0')
|
||||
g.rep_stosb()
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) rep_stosb() {
|
||||
g.write8(0xf3)
|
||||
g.write8(0xaa)
|
||||
g.println('rep stosb')
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) cld_repne_scasb() {
|
||||
g.write8(0xfc)
|
||||
g.println('cld')
|
||||
|
@ -500,6 +589,20 @@ pub fn (mut g Gen) xor(r Register, v int) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) test_reg(r Register) {
|
||||
match r {
|
||||
.rdi {
|
||||
g.write8(0x48)
|
||||
g.write8(0x85)
|
||||
g.write8(0xff)
|
||||
g.println('test rdi, rdi')
|
||||
}
|
||||
else {
|
||||
panic('unhandled test $r, $r')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return length in .rax of string pointed by given register
|
||||
pub fn (mut g Gen) inline_strlen(r Register) {
|
||||
g.mov_reg(.rdi, r)
|
||||
|
@ -676,8 +779,11 @@ fn (mut g Gen) learel(reg Register, val int) {
|
|||
.rsi {
|
||||
g.write8(0x35)
|
||||
}
|
||||
.rcx {
|
||||
g.write8(0x0d)
|
||||
}
|
||||
else {
|
||||
g.n_error('learel must use rsi or rax')
|
||||
g.n_error('learel must use rsi, rcx or rax')
|
||||
}
|
||||
}
|
||||
g.write32(val)
|
||||
|
@ -823,6 +929,20 @@ fn (mut g Gen) mul_reg(a Register, b Register) {
|
|||
g.println('mul $a')
|
||||
}
|
||||
|
||||
fn (mut g Gen) imul_reg(r Register) {
|
||||
match r {
|
||||
.rsi {
|
||||
g.write8(0x48)
|
||||
g.write8(0xf7)
|
||||
g.write8(0xee)
|
||||
g.println('imul $r')
|
||||
}
|
||||
else {
|
||||
panic('unhandled imul $r')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) div_reg(a Register, b Register) {
|
||||
if a != .rax {
|
||||
panic('div always operates on rax')
|
||||
|
@ -846,11 +966,24 @@ fn (mut g Gen) div_reg(a Register, b Register) {
|
|||
g.println('div $a')
|
||||
}
|
||||
|
||||
fn (mut g Gen) mod_reg(a Register, b Register) {
|
||||
g.div_reg(a, b)
|
||||
g.mov_reg(.rdx, .rax)
|
||||
}
|
||||
|
||||
fn (mut g Gen) sub_reg(a Register, b Register) {
|
||||
if a == .rax && b == .rbx {
|
||||
g.write8(0x48)
|
||||
g.write8(0x29)
|
||||
g.write8(0xd8)
|
||||
} else if a == .rdx && b == .rax {
|
||||
g.write8(0x48)
|
||||
g.write8(0x29)
|
||||
g.write8(0xc2)
|
||||
} else if a == .rdi && b == .rax {
|
||||
g.write8(0x48)
|
||||
g.write8(0x29)
|
||||
g.write8(0xc7)
|
||||
} else {
|
||||
panic('unhandled add $a, $b')
|
||||
}
|
||||
|
@ -866,6 +999,10 @@ fn (mut g Gen) add_reg(a Register, b Register) {
|
|||
g.write8(0x48)
|
||||
g.write8(0x01)
|
||||
g.write8(0xf8)
|
||||
} else if a == .rax && b == .rax {
|
||||
g.write8(0x48)
|
||||
g.write8(0x01)
|
||||
g.write8(0xc0)
|
||||
} else {
|
||||
panic('unhandled add $a, $b')
|
||||
}
|
||||
|
@ -906,12 +1043,39 @@ fn (mut g Gen) mov_reg(a Register, b Register) {
|
|||
g.write8(0x48)
|
||||
g.write8(0x89)
|
||||
g.write8(0xc6)
|
||||
} else if a == .rdi && b == .rdx {
|
||||
g.write8(0x48)
|
||||
g.write8(0x89)
|
||||
g.write8(0xd7)
|
||||
} else if a == .rdi && b == .rax {
|
||||
g.write8(0x48)
|
||||
g.write8(0x89)
|
||||
g.write8(0xc7)
|
||||
} else {
|
||||
g.n_error('unhandled mov_reg combination for $a $b')
|
||||
}
|
||||
g.println('mov $a, $b')
|
||||
}
|
||||
|
||||
fn (mut g Gen) sar8(r Register, val u8) {
|
||||
g.write8(0x48)
|
||||
g.write8(0xc1)
|
||||
|
||||
match r {
|
||||
.rax {
|
||||
g.write8(0xf8)
|
||||
}
|
||||
.rdx {
|
||||
g.write8(0xfa)
|
||||
}
|
||||
else {
|
||||
panic('unhandled sar $r, $val')
|
||||
}
|
||||
}
|
||||
g.write8(val)
|
||||
g.println('sar $r, $val')
|
||||
}
|
||||
|
||||
// generates `mov rbp, rsp`
|
||||
fn (mut g Gen) mov_rbp_rsp() {
|
||||
g.write8(0x48)
|
||||
|
@ -1668,9 +1832,32 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int {
|
|||
g.write8(0xff - n + 1)
|
||||
g.stack_var_pos += size
|
||||
g.var_offset[name] = g.stack_var_pos
|
||||
|
||||
// Generate the value assigned to the variable
|
||||
match size {
|
||||
1 {
|
||||
g.write8(initial_val)
|
||||
}
|
||||
4 {
|
||||
g.write32(initial_val)
|
||||
}
|
||||
8 {
|
||||
g.write32(initial_val) // fixme: 64-bit segfaulting
|
||||
}
|
||||
else {
|
||||
g.n_error('allocate_var: bad size $size')
|
||||
}
|
||||
}
|
||||
|
||||
// println('allocate_var(size=$size, initial_val=$initial_val)')
|
||||
g.println('mov [rbp-$n.hex2()], $initial_val ; Allocate var `$name`')
|
||||
return g.stack_var_pos
|
||||
}
|
||||
|
||||
fn (mut g Gen) convert_int_to_string(r Register, buffer int) {
|
||||
if r != .rax {
|
||||
g.mov_reg(.rax, r)
|
||||
}
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
|
|
@ -299,6 +299,12 @@ fn (mut g Gen) gen_typeof_expr(it ast.TypeOf, newline bool) {
|
|||
g.learel(.rax, g.allocate_string('$r$nl', 3, .rel32))
|
||||
}
|
||||
|
||||
fn (mut g Gen) gen_var_to_string(reg Register, vo int) {
|
||||
buffer := g.allocate_array('itoa-buffer', 1, 32) // 32 characters should be enough
|
||||
g.convert_int_to_string(reg, buffer)
|
||||
g.lea_var_to_reg(reg, buffer)
|
||||
}
|
||||
|
||||
pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) {
|
||||
newline := name in ['println', 'eprintln']
|
||||
fd := if name in ['eprint', 'eprintln'] { 2 } else { 1 }
|
||||
|
@ -316,17 +322,16 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) {
|
|||
}
|
||||
ast.Ident {
|
||||
vo := g.try_var_offset(expr.name)
|
||||
|
||||
if vo != -1 {
|
||||
g.n_error('Printing idents is not yet supported in the native backend')
|
||||
// g.mov_var_to_reg(.rsi, vo)
|
||||
// g.mov_reg(.rax, .rsi)
|
||||
// g.learel(.rax, vo * 8)
|
||||
// g.relpc(.rax, .rsi)
|
||||
// g.learel(.rax, g.allocate_string('$vo\n', 3, .rel32))
|
||||
// g.expr(expr)
|
||||
g.gen_var_to_string(.rax, vo)
|
||||
if newline {
|
||||
g.gen_print('\n', fd)
|
||||
}
|
||||
} else {
|
||||
g.gen_print_reg(.rax, 3, fd)
|
||||
}
|
||||
}
|
||||
ast.IntegerLiteral {
|
||||
g.learel(.rax, g.allocate_string('$expr.val\n', 3, .rel32))
|
||||
g.gen_print_reg(.rax, 3, fd)
|
||||
|
@ -775,7 +780,9 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||
ast.PostfixExpr {
|
||||
g.postfix_expr(node)
|
||||
}
|
||||
ast.StringLiteral {}
|
||||
ast.StringLiteral {
|
||||
g.allocate_string(node.val, 3, .rel32)
|
||||
}
|
||||
ast.StructInit {}
|
||||
ast.GoExpr {
|
||||
g.v_error('native backend doesnt support threads yet', node.pos)
|
||||
|
|
|
@ -29,9 +29,15 @@ fn test_stderr() {
|
|||
eprintln('2(World)')
|
||||
}
|
||||
|
||||
fn test_idents() {
|
||||
x := 5
|
||||
// println(x) uncomment again when int-to-string conversion is working
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_stdout()
|
||||
test_stderr()
|
||||
test_numbers()
|
||||
test_oof()
|
||||
test_idents()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue