1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

native: refer to types to generate code (#15077)

This commit is contained in:
lemon 2022-07-15 20:18:32 +09:00 committed by GitHub
parent 57c4188d98
commit f2961ec862
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 500 additions and 280 deletions

View File

@ -21,9 +21,6 @@ enum Register {
rbp
rsi
rdi
eax
edi
edx
r8
r9
r10
@ -32,6 +29,9 @@ enum Register {
r13
r14
r15
eax
edi
edx
}
const (
@ -176,40 +176,132 @@ fn (mut g Gen) cmp_zero(reg Register) {
g.println('cmp $reg, 0')
}
fn (mut g Gen) cmp_var_reg(var_name string, reg Register) {
g.write8(0x48) // 83 for 1 byte?
g.write8(0x39)
g.write8(0x45)
offset := g.get_var_offset(var_name)
g.write8(0xff - offset + 1)
g.println('cmp var `$var_name`, $reg')
fn (mut g Gen) cmp_var_reg(var Var, reg Register, config VarConfig) {
match var {
ast.Ident {
var_object := g.get_var_from_ident(var)
match var_object {
LocalVar {
g.cmp_var_reg(var_object as LocalVar, reg, config)
}
GlobalVar {
g.cmp_var_reg(var_object as GlobalVar, reg, config)
}
Register {
// TODO
// g.cmp()
}
}
}
LocalVar {
// TODO: size
g.write8(0x48) // 83 for 1 byte?
g.write8(0x39)
g.write8(0x45)
offset := var.offset - config.offset
g.write8(0xff - offset + 1)
g.println('cmp var `$var.name`, $reg')
}
GlobalVar {
// TODO
}
}
}
fn (mut g Gen) cmp_var(var_name string, val int) {
g.write8(0x81) // 83 for 1 byte?
g.write8(0x7d)
offset := g.get_var_offset(var_name)
g.write8(0xff - offset + 1)
g.write32(val)
g.println('cmp var `$var_name` $val')
fn (mut g Gen) cmp_var(var Var, val int, config VarConfig) {
match var {
ast.Ident {
var_object := g.get_var_from_ident(var)
match var_object {
LocalVar {
g.cmp_var(var_object as LocalVar, val, config)
}
GlobalVar {
g.cmp_var(var_object as GlobalVar, val, config)
}
Register {
// TODO
// g.cmp()
}
}
}
LocalVar {
// TODO: size
g.write8(0x81) // 83 for 1 byte?
g.write8(0x7d)
offset := var.offset - config.offset
g.write8(0xff - offset + 1)
g.write32(val)
g.println('cmp var `$var.name` $val')
}
GlobalVar {
// TODO
}
}
}
// `sub DWORD [rbp-0x4], 1`
fn (mut g Gen) dec_var(var_name string) {
g.write16(0x6d81) // 83 for 1 byte
offset := g.get_var_offset(var_name)
g.write8(0xff - offset + 1)
g.write32(1)
g.println('dec_var `$var_name`')
fn (mut g Gen) dec_var(var Var, config VarConfig) {
match var {
ast.Ident {
var_object := g.get_var_from_ident(var)
match var_object {
LocalVar {
g.dec_var(var_object as LocalVar, config)
}
GlobalVar {
g.dec_var(var_object as GlobalVar, config)
}
Register {
// TODO
// g.dec()
}
}
}
LocalVar {
// TODO: size
g.write16(0x6d81) // 83 for 1 byte
offset := var.offset - config.offset
g.write8(0xff - offset + 1)
g.write32(1)
g.println('dec_var `$var.name`')
}
GlobalVar {
// TODO
}
}
}
// `add DWORD [rbp-0x4], 1`
fn (mut g Gen) inc_var(var_name string) {
g.write16(0x4581) // 83 for 1 byte
offset := g.get_var_offset(var_name)
g.write8(0xff - offset + 1)
g.write32(1)
g.println('inc_var `$var_name`')
fn (mut g Gen) inc_var(var Var, config VarConfig) {
match var {
ast.Ident {
var_object := g.get_var_from_ident(var)
match var_object {
LocalVar {
g.inc_var(var_object as LocalVar, config)
}
GlobalVar {
g.inc_var(var_object as GlobalVar, config)
}
Register {
// TODO
// g.inc()
}
}
}
LocalVar {
// TODO: size
g.write16(0x4581) // 83 for 1 byte
offset := var.offset - config.offset
g.write8(0xff - offset + 1)
g.write32(1)
g.println('inc_var `$var.name`')
}
GlobalVar {
// TODO
}
}
}
enum JumpOp {
@ -351,43 +443,120 @@ fn (mut g Gen) movabs(reg Register, val i64) {
g.println('movabs $reg, $val')
}
fn (mut g Gen) mov_reg_to_var(var_offset int, reg Register) {
fn (mut g Gen) mov_deref(reg Register, regptr Register) {
g.write8(0x48 + int(reg) / 8 * 4 + int(regptr) / 8)
g.write8(0x8b)
g.write8(int(reg) % 8 * 8 + int(regptr) % 8)
}
fn (mut g Gen) mov_reg_to_var(var Var, reg Register, config VarConfig) {
if g.pref.arch != .amd64 {
panic('invalid arch for mov_reg_to_var')
}
// 89 7d fc mov DWORD PTR [rbp-0x4],edi
match reg {
.rax {
g.write8(0x48)
match var {
ast.Ident {
var_object := g.get_var_from_ident(var)
match var_object {
LocalVar {
g.mov_reg_to_var(var_object as LocalVar, reg, config)
}
GlobalVar {
g.mov_reg_to_var(var_object as GlobalVar, reg, config)
}
Register {
// TODO
}
}
}
LocalVar {
offset := var.offset - config.offset
typ := if config.typ == 0 { var.typ } else { config.typ }
size := match typ {
ast.i64_type_idx, ast.u64_type_idx, ast.isize_type_idx, ast.usize_type_idx,
ast.int_literal_type_idx {
g.write16(0x8948)
'QWORD'
}
ast.int_type_idx, ast.u32_type_idx, ast.rune_type_idx {
g.write8(0x89)
'DWORD'
}
ast.i16_type_idx, ast.u16_type_idx {
g.write16(0x8966)
'WORD'
}
ast.i8_type_idx, ast.u8_type_idx, ast.char_type_idx {
g.write8(0x88)
'BYTE'
}
else {
g.n_error('unsupported type for mov_reg_to_var')
'UNKNOWN'
}
}
match reg {
.eax, .rax { g.write8(0x45) }
.edi, .rdi { g.write8(0x7d) }
.rsi { g.write8(0x75) }
.rdx { g.write8(0x55) }
.rcx { g.write8(0x4d) }
else { g.n_error('mov_from_reg $reg') }
}
g.write8(0xff - offset + 1)
g.println('mov $size PTR [rbp-$offset.hex2()],$reg')
}
GlobalVar {
// TODO
}
else {}
}
g.write8(0x89)
match reg {
.eax, .rax { g.write8(0x45) }
.edi, .rdi { g.write8(0x7d) }
.rsi { g.write8(0x75) }
.rdx { g.write8(0x55) }
.rcx { g.write8(0x4d) }
else { g.n_error('mov_from_reg $reg') }
}
g.write8(0xff - var_offset + 1)
g.println('mov DWORD PTR[rbp-$var_offset.hex2()],$reg')
}
fn (mut g Gen) mov_int_to_var(var_offset int, size Size, integer int) {
var_addr := 0xff - var_offset + 1
match size {
._8 {
g.write8(0xc6)
g.write8(0x45)
g.write8(var_addr)
g.write8(u8(integer))
g.println('mov BYTE PTR[rbp-$var_offset.hex2()], $integer')
fn (mut g Gen) mov_int_to_var(var Var, integer int, config VarConfig) {
match var {
ast.Ident {
var_object := g.get_var_from_ident(var)
match var_object {
LocalVar {
g.mov_int_to_var(var_object as LocalVar, integer, config)
}
GlobalVar {
g.mov_int_to_var(var_object as GlobalVar, integer, config)
}
Register {
// TODO
}
}
}
else {
g.n_error('unhandled mov int')
LocalVar {
offset := var.offset - config.offset
typ := if config.typ == 0 { var.typ } else { config.typ }
var_addr := 0xff - offset + 1
match typ {
ast.i8_type_idx, ast.u8_type_idx, ast.char_type_idx {
g.write8(0xc6)
g.write8(0x45)
g.write8(var_addr)
g.write8(u8(integer))
g.println('mov BYTE PTR[rbp-$offset.hex2()], $integer')
}
ast.i64_type_idx, ast.u64_type_idx, ast.isize_type_idx, ast.usize_type_idx,
ast.int_literal_type_idx {
g.write8(0x48)
g.write8(0xc7)
g.write8(0x45)
g.write8(var_addr)
g.write32(integer)
g.println('mov QWORD PTR[rbp-$offset.hex2()], $integer')
}
else {
g.n_error('unhandled mov int type: $typ')
}
}
}
GlobalVar {
// TODO
}
}
}
@ -413,26 +582,84 @@ fn (mut g Gen) lea_var_to_reg(reg Register, var_offset int) {
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 {
.rax, .rbx, .rsi {
g.write8(0x48)
fn (mut g Gen) mov_var_to_reg(reg Register, var Var, config VarConfig) {
match var {
ast.Ident {
var_object := g.get_var_from_ident(var)
match var_object {
LocalVar {
g.mov_var_to_reg(reg, var_object as LocalVar, config)
}
GlobalVar {
g.mov_var_to_reg(reg, var_object as GlobalVar, config)
}
Register {
// TODO
}
}
}
LocalVar {
offset := var.offset - config.offset
typ := if config.typ == 0 { var.typ } else { config.typ }
instruction, size := match typ {
ast.i64_type_idx, ast.u64_type_idx, ast.isize_type_idx, ast.usize_type_idx,
ast.int_literal_type_idx {
// mov rax, QWORD PTR [rbp-0x8]
g.write16(0x8b48)
'mov', 'QWORD'
}
ast.int_type_idx {
// movsxd rax, DWORD PTR [rbp-0x8]
g.write16(0x6348)
'movsxd', 'DWORD'
}
ast.u32_type_idx, ast.rune_type_idx {
// mov eax, DWORD PTR [rbp-0x8]
g.write8(0x8b)
'mov', 'DWORD'
}
ast.i16_type_idx {
// movsx rax, WORD PTR [rbp-0x8]
g.write([u8(0x48), 0x0f, 0xbf])
'movsx', 'WORD'
}
ast.u16_type_idx {
// movzx rax, WORD PTR [rbp-0x8]
g.write([u8(0x48), 0x0f, 0xb7])
'movzx', 'WORD'
}
ast.i8_type_idx {
// movsx rax, BYTE PTR [rbp-0x8]
g.write([u8(0x48), 0x0f, 0xbe])
'movsx', 'BYTE'
}
ast.u8_type_idx, ast.char_type_idx {
// movzx rax, BYTE PTR [rbp-0x8]
g.write([u8(0x48), 0x0f, 0xb6])
'movzx', 'BYTE'
}
else {
g.n_error('unhandled mov var to reg')
'mov', 'UNKNOWN'
}
}
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('mov_var_to_reg $reg') }
}
g.write8(0xff - offset + 1)
g.println('$instruction $reg, $size PTR [rbp-$offset.hex2()]')
}
GlobalVar {
// TODO
}
else {}
}
g.write8(0x8b)
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('mov_var_to_reg $reg') }
}
g.write8(0xff - var_offset + 1)
g.println('mov $reg,DWORD PTR[rbp-$var_offset.hex2()]')
}
fn (mut g Gen) call(addr int) {
@ -496,14 +723,6 @@ pub fn (mut g Gen) pop(reg Register) {
g.println('pop $reg')
}
pub fn (mut g Gen) sub32(reg Register, val int) {
g.write8(0x48)
g.write8(0x81)
g.write8(0xe8 + int(reg)) // TODO rax is different?
g.write32(val)
g.println('sub32 $reg,$val.hex2()')
}
pub fn (mut g Gen) sub8(reg Register, val int) {
g.write8(0x48)
g.write8(0x83)
@ -514,18 +733,24 @@ pub fn (mut g Gen) sub8(reg Register, val int) {
pub fn (mut g Gen) sub(reg Register, val int) {
g.write8(0x48)
g.write8(0x81)
g.write8(0xe8 + int(reg)) // TODO rax is different?
if reg == .rax {
g.write8(0x2d)
} else {
g.write8(0x81)
g.write8(0xe8 + int(reg))
}
g.write32(val)
g.println('add $reg,$val.hex2()')
g.println('sub $reg,$val.hex2()')
}
pub fn (mut g Gen) add(reg Register, val int) {
if reg != .rax {
panic('add only works with .rax')
}
g.write8(0x48)
g.write8(0x05)
if reg == .rax {
g.write8(0x05)
} else {
g.write8(0x81)
g.write8(0xc0 + int(reg))
}
g.write32(val)
g.println('add $reg,$val.hex2()')
}
@ -538,6 +763,8 @@ pub fn (mut g Gen) add8(reg Register, val int) {
g.println('add8 $reg,$val.hex2()')
}
[deprecated: 'use add_reg']
[deprecated_after: '2999-01-01']
fn (mut g Gen) add8_var(reg Register, var_offset int) {
g.write8(0x03)
match reg {
@ -548,6 +775,8 @@ fn (mut g Gen) add8_var(reg Register, var_offset int) {
g.println('add8 $reg,DWORD PTR[rbp-$var_offset.hex2()]')
}
[deprecated: 'use sub_reg']
[deprecated_after: '2999-01-01']
fn (mut g Gen) sub8_var(reg Register, var_offset int) {
g.write8(0x2b)
match reg {
@ -558,16 +787,20 @@ fn (mut g Gen) sub8_var(reg Register, var_offset int) {
g.println('sub8 $reg,DWORD PTR[rbp-$var_offset.hex2()]')
}
[deprecated: 'use div_reg']
[deprecated_after: '2999-01-01']
fn (mut g Gen) div8_var(reg Register, var_offset int) {
if reg == .rax || reg == .eax {
g.mov_var_to_reg(.rbx, var_offset)
g.mov_var_to_reg(.rbx, LocalVar{var_offset, ast.i64_type_idx, ''})
g.div_reg(.rax, .rbx)
g.mov_reg_to_var(var_offset, .rax)
g.mov_reg_to_var(LocalVar{var_offset, ast.i64_type_idx, ''}, .rax)
} else {
panic('div8_var invalid source register')
}
}
[deprecated: 'use mul_reg']
[deprecated_after: '2999-01-01']
fn (mut g Gen) mul8_var(reg Register, var_offset int) {
g.write8(0x0f)
g.write8(0xaf)
@ -603,6 +836,7 @@ pub fn (mut g Gen) allocate_string(s string, opsize int, typ RelocType) int {
return str_pos
}
// not used?
pub fn (mut g Gen) var_zero(vo int, size int) {
g.mov32(.rcx, size)
g.lea_var_to_reg(.rdi, vo)
@ -789,8 +1023,7 @@ pub fn (mut g Gen) gen_amd64_exit(expr ast.Expr) {
g.n_error('native exit builtin: Unsupported call $right')
}
ast.Ident {
var_offset := g.get_var_offset(expr.name)
g.mov_var_to_reg(.edi, var_offset)
g.mov_var_to_reg(.edi, expr as ast.Ident)
}
ast.IntegerLiteral {
g.mov(.edi, expr.val.int())
@ -1078,59 +1311,11 @@ fn (mut g Gen) add_reg(a Register, b Register) {
}
fn (mut g Gen) mov_reg(a Register, b Register) {
if a == .rax && b == .rsi {
g.write([u8(0x48), 0x89, 0xf0])
} else if a == .rbp && b == .rsp {
g.write8(0x48)
if int(a) <= int(Register.r15) && int(b) <= int(Register.r15) {
g.write8(0x48 + if int(a) >= int(Register.r8) { 1 } else { 0 } +
if int(b) >= int(Register.r8) { 4 } else { 0 })
g.write8(0x89)
} else if a == .rdx && b == .rax {
g.write8(0x48)
g.write8(0x89)
g.write8(0xc2)
} else if a == .rax && b == .rcx {
g.write8(0x48)
g.write8(0x89)
g.write8(0xc8)
} else if a == .rax && b == .rdi {
g.write8(0x48)
g.write8(0x89)
g.write8(0xf8)
} else if a == .rcx && b == .rdi {
g.write8(0x48)
g.write8(0x89)
g.write8(0xf9)
} else if a == .rcx && b == .rax {
g.write8(0x48)
g.write8(0x89)
g.write8(0xc1)
} else if a == .rdi && b == .rsi {
g.write8(0x48)
g.write8(0x89)
g.write8(0xf7)
} else if a == .rsi && b == .rax {
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 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)
g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
} else {
g.n_error('unhandled mov_reg combination for $a $b')
}
@ -1156,14 +1341,6 @@ fn (mut g Gen) sar8(r Register, val u8) {
g.println('sar $r, $val')
}
// generates `mov rbp, rsp`
fn (mut g Gen) mov_rbp_rsp() {
g.write8(0x48)
g.write8(0x89)
g.write8(0xe5)
g.println('mov rbp, rsp')
}
pub fn (mut g Gen) call_fn(node ast.CallExpr) {
if g.pref.arch == .arm64 {
g.call_fn_arm64(node)
@ -1191,7 +1368,7 @@ pub fn (mut g Gen) call_fn(node ast.CallExpr) {
println('i=$i fn name= $name offset=$var_offset')
println(int(native.fn_arg_registers[i]))
}
g.mov_var_to_reg(native.fn_arg_registers[i], var_offset)
g.mov_var_to_reg(native.fn_arg_registers[i], expr as ast.Ident)
}
else {
g.v_error('unhandled call_fn (name=$name) node: $expr.type_name()', node.pos)
@ -1255,37 +1432,32 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
right := node.right[i]
name := left.str()
// if left is ast.Ident {
// ident := left as ast.Ident
ident := left as ast.Ident
match right {
ast.IntegerLiteral {
// g.allocate_var(name, 4, right.val.int())
match node.op {
.plus_assign {
dest := g.get_var_offset(name)
g.mov_var_to_reg(.rax, dest)
g.mov_var_to_reg(.rax, ident)
g.add(.rax, right.val.int())
g.mov_reg_to_var(dest, .rax)
g.mov_reg_to_var(ident, .rax)
}
.minus_assign {
dest := g.get_var_offset(name)
g.mov_var_to_reg(.rax, dest)
g.mov_var_to_reg(.rbx, g.get_var_offset(name))
g.sub_reg(.rax, .rbx)
g.mov_reg_to_var(dest, .rax)
g.mov_var_to_reg(.rax, ident)
g.sub(.rax, right.val.int())
g.mov_reg_to_var(ident, .rax)
}
.mult_assign {
dest := g.get_var_offset(name)
g.mov_var_to_reg(.rax, dest)
g.mov_var_to_reg(.rbx, g.get_var_offset(name))
g.mul_reg(.rax, .rbx)
g.mov_reg_to_var(dest, .rax)
g.mov_var_to_reg(.rax, ident)
g.mov64(.rdx, right.val.int())
g.mul_reg(.rax, .rdx)
g.mov_reg_to_var(ident, .rax)
}
.div_assign {
dest := g.get_var_offset(name)
g.mov_var_to_reg(.rax, dest)
g.mov_var_to_reg(.rbx, g.get_var_offset(name))
g.div_reg(.rax, .rbx)
g.mov_reg_to_var(dest, .rax)
g.mov_var_to_reg(.rax, ident)
g.mov64(.rdx, right.val.int())
g.div_reg(.rax, .rdx)
g.mov_reg_to_var(ident, .rax)
}
.decl_assign {
g.allocate_var(name, 8, right.val.int())
@ -1297,40 +1469,8 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
// lname := '${node.left[i]}'
// g.expr(node.right[i])
g.mov(.rax, right.val.int())
offset := g.get_var_offset('i') // node.left[i])
g.mov_reg_to_var(offset, .rax)
g.mov_reg_to_var(ident, .rax)
}
ast.InfixExpr {
// eprintln('assign')
// dump(node.left[i])
offset := g.get_var_offset('i') // node.left[i])
g.mov_reg_to_var(offset, native.fn_arg_registers[i])
}
/*
ast.int_type_idx {
g.expr(node.left[i])
match node.left[i] {
ast.IndexExpr {
ie := node.left[i] as ast.IndexExpr
bracket := name.index('[') or {
g.v_error('bracket expected', node.pos)
exit(1)
}
var_name := name[0 .. bracket]
mut dest := g.get_var_offset(var_name)
index := ie.index as ast.IntegerLiteral
dest += index.val.int() * 8
// TODO check if out of bounds access
g.mov(.rax, right.val.int())
g.mov_reg_to_var(dest, .rax)
// eprintln('${var_name}[$index] = ${right.val.int()}')
} else {
dump(node)
g.v_error('oops', node.pos)
}
}
}
*/
else {
tn := node.left[i].type_name()
dump(node.left_types)
@ -1347,45 +1487,43 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
ast.InfixExpr {
// eprintln('infix') dump(node) dump(right)
g.infix_expr(right)
offset := g.allocate_var(name, 8, 0)
offset := g.allocate_var(name, g.get_sizeof_ident(ident), 0)
// `mov DWORD PTR [rbp-0x8],eax`
if g.pref.is_verbose {
println('infix assignment $name offset=$offset.hex2()')
}
g.mov_reg_to_var(offset, .rax)
g.mov_reg_to_var(ident, .rax)
}
ast.Ident {
// eprintln('identr') dump(node) dump(right)
match node.op {
.plus_assign {
dest := g.get_var_offset(name)
g.mov_var_to_reg(.rax, dest)
g.add8_var(.rax, g.get_var_offset(right.name))
g.mov_reg_to_var(dest, .rax)
g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rbx, right as ast.Ident)
g.add_reg(.rax, .rbx)
g.mov_reg_to_var(ident, .rax)
}
.minus_assign {
dest := g.get_var_offset(name)
g.mov_var_to_reg(.rax, dest)
g.mov_var_to_reg(.rbx, g.get_var_offset(right.name))
g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rbx, right as ast.Ident)
g.sub_reg(.rax, .rbx)
g.mov_reg_to_var(dest, .rax)
g.mov_reg_to_var(ident, .rax)
}
.div_assign {
// this should be called when `a /= b` but it's not :?
dest := g.get_var_offset(name)
g.mov_var_to_reg(.rax, dest)
g.mov_var_to_reg(.rbx, g.get_var_offset(right.name))
g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rbx, right as ast.Ident)
g.div_reg(.rax, .rbx)
g.mov_reg_to_var(dest, .rax)
g.mov_reg_to_var(ident, .rax)
}
.decl_assign {
dest := g.allocate_var(name, 8, 0)
g.mov_var_to_reg(.rax, g.get_var_offset(right.name))
g.mov_reg_to_var(dest, .rax)
g.allocate_var(name, g.get_sizeof_ident(ident), 0)
g.mov_var_to_reg(.rbx, right as ast.Ident)
g.mov_reg_to_var(ident, .rax)
}
.assign {
g.mov_var_to_reg(.rax, g.get_var_offset(right.name))
g.mov_reg_to_var(g.get_var_offset(name), .rax)
g.mov_var_to_reg(.rbx, right as ast.Ident)
g.mov_reg_to_var(ident, .rax)
}
else {
eprintln('TODO: unhandled assign ident case')
@ -1411,13 +1549,13 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
match e {
ast.IntegerLiteral {
g.mov(.rax, e.val.int())
g.mov_reg_to_var(pos, .rax)
g.mov_reg_to_var(LocalVar{pos, ast.i64_type_idx, ''}, .rax)
pos += 8
}
ast.StringLiteral {
// TODO: use learel
g.mov64(.rsi, g.allocate_string('$e.val', 2, .abs64)) // for rsi its 2
g.mov_reg_to_var(pos, .rsi)
g.mov_reg_to_var(LocalVar{pos, ast.u64_type_idx, ''}, .rsi)
pos += 8
}
else {
@ -1429,40 +1567,40 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
}
ast.IndexExpr {
// a := arr[0]
offset := g.allocate_var(name, 8, 0)
offset := g.allocate_var(name, g.get_sizeof_ident(ident), 0)
if g.pref.is_verbose {
println('infix assignment $name offset=$offset.hex2()')
}
ie := node.right[i] as ast.IndexExpr
var_name := ie.left.str()
mut dest := g.get_var_offset(var_name)
var := ie.left as ast.Ident
dest := g.get_var_offset(var.name)
if ie.index is ast.IntegerLiteral {
index := ie.index
dest += index.val.int() * 8
g.mov_var_to_reg(.rax, dest)
ie_offset := index.val.int() * 8
g.mov_var_to_reg(.rax, var, typ: ast.i64_type_idx, offset: ie_offset)
} else if ie.index is ast.Ident {
ident := ie.index
var_offset := g.get_var_offset(ident.name)
g.mov_var_to_reg(.edi, var_offset)
g.mov_var_to_reg(.rax, dest)
ie_ident := ie.index
g.lea_var_to_reg(.rax, dest)
g.mov_var_to_reg(.rdi, ie_ident)
g.add_reg(.rax, .rdi)
g.mov_deref(.rax, .rax)
} else {
g.n_error('only integers and idents can be used as indexes')
}
// TODO check if out of bounds access
g.mov_reg_to_var(offset, .eax)
g.mov_reg_to_var(ident, .eax)
}
ast.StringLiteral {
dest := g.allocate_var(name, 4, 0)
dest := g.allocate_var(name, 8, 0)
ie := node.right[i] as ast.StringLiteral
g.learel(.rsi, g.allocate_string(ie.val.str(), 3, .rel32))
g.mov_reg_to_var(dest, .rsi)
g.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, .rsi)
}
ast.CallExpr {
dest := g.allocate_var(name, 4, 0)
g.allocate_var(name, g.get_sizeof_ident(ident), 0)
g.call_fn(right)
g.mov_reg_to_var(dest, .rax)
g.mov_var_to_reg(.rsi, dest)
g.mov_reg_to_var(ident, .rax)
g.mov_var_to_reg(.rsi, ident)
}
ast.SelectorExpr {
g.v_error('unhandled selectors', node.pos)
@ -1508,7 +1646,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
}
match node.left {
ast.Ident {
g.mov_var_to_reg(.eax, g.get_var_offset(node.left.name))
g.mov_var_to_reg(.eax, node.left as ast.Ident)
}
else {}
}
@ -1731,7 +1869,7 @@ fn (mut g Gen) condition(infix_expr ast.InfixExpr, neg bool) int {
ast.Ident {
// 3 < var
// lit := infix_expr.right as ast.IntegerLiteral
// g.cmp_var(infix_expr.left.name, lit.val.int())
// g.cmp_var(infix_expr.left, lit.val.int())
// +not
g.n_error('unsupported if construction')
}
@ -1745,7 +1883,7 @@ fn (mut g Gen) condition(infix_expr ast.InfixExpr, neg bool) int {
ast.IntegerLiteral {
// var < 4
lit := infix_expr.right as ast.IntegerLiteral
g.cmp_var(infix_expr.left.name, lit.val.int())
g.cmp_var(infix_expr.left as ast.Ident, lit.val.int())
}
ast.Ident {
// var < var2
@ -1862,13 +2000,12 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) {
ast.Ident {
match infix_expr.right {
ast.Ident {
var_offset := g.get_var_offset(infix_expr.right.name)
g.mov_var_to_reg(.rax, var_offset)
g.cmp_var_reg(infix_expr.left.name, .rax)
g.mov_var_to_reg(.rax, infix_expr.right as ast.Ident)
g.cmp_var_reg(infix_expr.left as ast.Ident, .rax)
}
ast.IntegerLiteral {
lit := infix_expr.right as ast.IntegerLiteral
g.cmp_var(infix_expr.left.name, lit.val.int())
g.cmp_var(infix_expr.left as ast.Ident, lit.val.int())
}
else {
g.n_error('unhandled expression type')
@ -1914,10 +2051,9 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) {
fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
g.push(.rbp)
g.mov_rbp_rsp()
locals_count := node.scope.objects.len + node.params.len + node.defer_stmts.len
g.stackframe_size = (locals_count * 8) + 0x10
g.sub8(.rsp, g.stackframe_size)
g.mov_reg(.rbp, .rsp)
local_alloc_pos := g.pos()
g.sub(.rsp, 0)
// Copy values from registers to local vars (calling convention)
mut offset := 0
@ -1927,7 +2063,8 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
g.allocate_var(name, 4, 0)
// `mov DWORD PTR [rbp-0x4],edi`
offset += 4
g.mov_reg_to_var(offset, native.fn_arg_registers[i])
// TODO size
g.mov_reg_to_var(LocalVar{offset, ast.int_type_idx, name}, native.fn_arg_registers[i])
}
// define defer vars
for i in 0 .. node.defer_stmts.len {
@ -1936,6 +2073,8 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
}
//
g.stmts(node.stmts)
g.println('; stack frame size: $g.stack_var_pos')
g.write32_at(local_alloc_pos + 3, g.stack_var_pos)
is_main := node.name == 'main.main'
if is_main {
// println('end of main: gen exit')
@ -1951,8 +2090,9 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
// save return value
g.push(.rax)
for defer_stmt in g.defer_stmts.reverse() {
defer_var := g.get_var_offset('_defer$defer_stmt.idx_in_fn')
g.mov_var_to_reg(.rax, defer_var)
name := '_defer$defer_stmt.idx_in_fn'
defer_var := g.get_var_offset(name)
g.mov_var_to_reg(.rax, LocalVar{defer_var, ast.i64_type_idx, name})
g.cmp_zero(.rax)
label := g.labels.new_label()
jump_addr := g.cjmp(.je)
@ -1965,7 +2105,7 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
}
g.pop(.rax)
}
g.add8(.rsp, g.stackframe_size)
g.mov_reg(.rsp, .rbp)
g.pop(.rbp)
g.ret()
}
@ -2014,6 +2154,7 @@ 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
g.var_alloc_size[name] = size
// Generate the value assigned to the variable
match size {
@ -2052,7 +2193,7 @@ fn (mut g Gen) convert_int_to_string(r Register, buffer int) {
g.println('; jump to label $skip_zero_label')
// handle zeros seperately
g.mov_int_to_var(buffer, ._8, '0'[0])
g.mov_int_to_var(LocalVar{buffer, ast.u8_type_idx, ''}, '0'[0])
end_label := g.labels.new_label()
end_jmp_addr := g.jmp(0)
g.labels.patches << LabelPatch{
@ -2078,7 +2219,7 @@ fn (mut g Gen) convert_int_to_string(r Register, buffer int) {
g.println('; jump to label $skip_minus_label')
// add a `-` sign as the first character
g.mov_int_to_var(buffer, ._8, '-'[0])
g.mov_int_to_var(LocalVar{buffer, ast.u8_type_idx, ''}, '-'[0])
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()

View File

@ -32,12 +32,12 @@ mut:
buf []u8
sect_header_name_pos int
offset i64
stackframe_size int
file_size_pos i64
main_fn_addr i64
code_start_pos i64 // location of the start of the assembly instructions
fn_addr map[string]i64
var_offset map[string]int // local var stack offset
var_alloc_size map[string]int // local var allocation size
stack_var_pos int
debug_pos int
errors []errors.Error
@ -105,6 +105,44 @@ enum Size {
_64
}
// you can use these structs manually if you don't have ast.Ident
struct LocalVar {
offset int // offset from the base pointer
typ ast.Type
name string
}
struct GlobalVar {}
[params]
struct VarConfig {
offset int // offset from the variable
typ ast.Type // type of the value you want to process e.g. struct fields.
}
type Var = GlobalVar | LocalVar | ast.Ident
fn (mut g Gen) get_var_from_ident(ident ast.Ident) LocalVar|GlobalVar|Register {
mut obj := ident.obj
if obj !in [ast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister] {
obj = ident.scope.find(ident.name) or { g.n_error('unknown variable $ident.name') }
}
match obj {
ast.Var {
offset := g.get_var_offset(obj.name)
typ := obj.typ
return LocalVar{
offset: offset
typ: typ
name: obj.name
}
}
else {
g.n_error('unsupported variable type type:$obj name:$ident.name')
}
}
}
fn get_backend(arch pref.Arch) ?CodeGen {
match arch {
.arm64 {
@ -338,15 +376,61 @@ fn (mut g Gen) get_var_offset(var_name string) int {
return r
}
fn (mut g Gen) get_type_size(typ ast.Type) int {
if typ in ast.number_type_idxs {
return match typ {
ast.i8_type_idx { 1 }
ast.u8_type_idx { 1 }
ast.i16_type_idx { 2 }
ast.u16_type_idx { 2 }
ast.int_type_idx { 4 }
ast.u32_type_idx { 4 }
ast.i64_type_idx { 8 }
ast.u64_type_idx { 8 }
ast.isize_type_idx { 8 }
ast.usize_type_idx { 8 }
ast.int_literal_type_idx { 8 }
ast.f32_type_idx { 4 }
ast.f64_type_idx { 8 }
ast.float_literal_type_idx { 8 }
ast.char_type_idx { 1 }
ast.rune_type_idx { 4 }
else { 8 }
}
}
if typ in ast.pointer_type_idxs {
return 8
}
// g.n_error('unknown type size')
return 8
}
fn (mut g Gen) get_sizeof_ident(ident ast.Ident) int {
typ := match ident.obj {
ast.AsmRegister { ast.i64_type_idx }
ast.ConstField { ident.obj.typ }
ast.GlobalField { ident.obj.typ }
ast.Var { ident.obj.typ }
}
if typ != 0 {
return g.get_type_size(typ)
}
size := g.var_alloc_size[ident.name] or {
g.n_error('unknown variable `$ident`')
return 0
}
return size
}
fn (mut g Gen) gen_typeof_expr(it ast.TypeOf, newline bool) {
nl := if newline { '\n' } else { '' }
r := g.typ(it.expr_type).name
g.learel(.rax, g.allocate_string('$r$nl', 3, .rel32))
}
fn (mut g Gen) gen_var_to_string(reg Register, vo int) {
fn (mut g Gen) gen_var_to_string(reg Register, var Var, config VarConfig) {
buffer := g.allocate_array('itoa-buffer', 1, 32) // 32 characters should be enough
g.mov_var_to_reg(reg, vo)
g.mov_var_to_reg(reg, var, config)
g.convert_int_to_string(reg, buffer)
g.lea_var_to_reg(reg, buffer)
}
@ -370,7 +454,7 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) {
vo := g.try_var_offset(expr.name)
if vo != -1 {
g.gen_var_to_string(.rax, vo)
g.gen_var_to_string(.rax, expr as ast.Ident)
g.gen_print_reg(.rax, 3, fd)
if newline {
g.gen_print('\n', fd)
@ -565,7 +649,7 @@ fn (mut g Gen) gen_forc_stmt(node ast.ForCStmt) {
match cond.left {
ast.Ident {
lit := cond.right as ast.IntegerLiteral
g.cmp_var(cond.left.name, lit.val.int())
g.cmp_var(cond.left as ast.Ident, lit.val.int())
match cond.op {
.gt {
jump_addr = g.cjmp(.jle)
@ -622,10 +706,10 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
// for a in node.cond .. node.high {
i := g.allocate_var(node.val_var, 8, 0) // iterator variable
g.expr(node.cond)
g.mov_reg_to_var(i, .rax) // i = node.cond // initial value
g.mov_reg_to_var(LocalVar{i, ast.i64_type_idx, node.val_var}, .rax) // i = node.cond // initial value
start := g.pos() // label-begin:
start_label := g.labels.new_label()
g.mov_var_to_reg(.rbx, i) // rbx = iterator value
g.mov_var_to_reg(.rbx, LocalVar{i, ast.i64_type_idx, node.val_var}) // rbx = iterator value
g.expr(node.high) // final value
g.cmp_reg(.rbx, .rax) // rbx = iterator, rax = max value
jump_addr := g.cjmp(.jge) // leave loop if i is beyond end
@ -643,7 +727,7 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) {
g.stmts(node.stmts)
g.labels.addrs[start_label] = g.pos()
g.println('; label $start_label')
g.inc_var(node.val_var)
g.inc_var(LocalVar{i, ast.i64_type_idx, node.val_var})
g.labels.branches.pop()
g.jmp(int(0xffffffff - (g.pos() + 5 - start) + 1))
g.labels.addrs[end_label] = g.pos()
@ -697,8 +781,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
}
ast.ConstDecl {}
ast.DeferStmt {
defer_var := g.get_var_offset('_defer$g.defer_stmts.len')
g.mov_int_to_var(defer_var, ._8, 1)
name := '_defer$g.defer_stmts.len'
defer_var := g.get_var_offset(name)
g.mov_int_to_var(LocalVar{defer_var, ast.i64_type_idx, name}, 1)
g.defer_stmts << node
g.defer_stmts[g.defer_stmts.len - 1].idx_in_fn = g.defer_stmts.len - 1
}
@ -867,13 +952,8 @@ fn (mut g Gen) expr(node ast.Expr) {
}
ast.FloatLiteral {}
ast.Ident {
offset := g.try_var_offset(node.obj.name) // i := 0
if offset == -1 {
g.n_error('invalid ident $node.obj.name')
}
// offset := g.get_var_offset(node.name)
// XXX this is intel specific
g.mov_var_to_reg(.rax, offset)
g.mov_var_to_reg(.rax, node as ast.Ident)
}
ast.IfExpr {
if node.is_comptime {
@ -918,13 +998,12 @@ fn (mut g Gen) postfix_expr(node ast.PostfixExpr) {
return
}
ident := node.expr as ast.Ident
var_name := ident.name
match node.op {
.inc {
g.inc_var(var_name)
g.inc_var(ident)
}
.dec {
g.dec_var(var_name)
g.dec_var(ident)
}
else {}
}