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 rbp
rsi rsi
rdi rdi
eax
edi
edx
r8 r8
r9 r9
r10 r10
@ -32,6 +29,9 @@ enum Register {
r13 r13
r14 r14
r15 r15
eax
edi
edx
} }
const ( const (
@ -176,40 +176,132 @@ fn (mut g Gen) cmp_zero(reg Register) {
g.println('cmp $reg, 0') g.println('cmp $reg, 0')
} }
fn (mut g Gen) cmp_var_reg(var_name string, reg Register) { 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(0x48) // 83 for 1 byte?
g.write8(0x39) g.write8(0x39)
g.write8(0x45) g.write8(0x45)
offset := g.get_var_offset(var_name) offset := var.offset - config.offset
g.write8(0xff - offset + 1) g.write8(0xff - offset + 1)
g.println('cmp var `$var_name`, $reg') g.println('cmp var `$var.name`, $reg')
}
GlobalVar {
// TODO
}
}
} }
fn (mut g Gen) cmp_var(var_name string, val int) { 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(0x81) // 83 for 1 byte?
g.write8(0x7d) g.write8(0x7d)
offset := g.get_var_offset(var_name) offset := var.offset - config.offset
g.write8(0xff - offset + 1) g.write8(0xff - offset + 1)
g.write32(val) g.write32(val)
g.println('cmp var `$var_name` $val') g.println('cmp var `$var.name` $val')
}
GlobalVar {
// TODO
}
}
} }
// `sub DWORD [rbp-0x4], 1` // `sub DWORD [rbp-0x4], 1`
fn (mut g Gen) dec_var(var_name string) { 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 g.write16(0x6d81) // 83 for 1 byte
offset := g.get_var_offset(var_name) offset := var.offset - config.offset
g.write8(0xff - offset + 1) g.write8(0xff - offset + 1)
g.write32(1) g.write32(1)
g.println('dec_var `$var_name`') g.println('dec_var `$var.name`')
}
GlobalVar {
// TODO
}
}
} }
// `add DWORD [rbp-0x4], 1` // `add DWORD [rbp-0x4], 1`
fn (mut g Gen) inc_var(var_name string) { 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 g.write16(0x4581) // 83 for 1 byte
offset := g.get_var_offset(var_name) offset := var.offset - config.offset
g.write8(0xff - offset + 1) g.write8(0xff - offset + 1)
g.write32(1) g.write32(1)
g.println('inc_var `$var_name`') g.println('inc_var `$var.name`')
}
GlobalVar {
// TODO
}
}
} }
enum JumpOp { enum JumpOp {
@ -351,18 +443,58 @@ fn (mut g Gen) movabs(reg Register, val i64) {
g.println('movabs $reg, $val') 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 { if g.pref.arch != .amd64 {
panic('invalid arch for mov_reg_to_var') panic('invalid arch for mov_reg_to_var')
} }
// 89 7d fc mov DWORD PTR [rbp-0x4],edi match var {
match reg { ast.Ident {
.rax { var_object := g.get_var_from_ident(var)
g.write8(0x48) match var_object {
LocalVar {
g.mov_reg_to_var(var_object as LocalVar, reg, config)
} }
else {} 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) 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 { match reg {
.eax, .rax { g.write8(0x45) } .eax, .rax { g.write8(0x45) }
.edi, .rdi { g.write8(0x7d) } .edi, .rdi { g.write8(0x7d) }
@ -371,23 +503,60 @@ fn (mut g Gen) mov_reg_to_var(var_offset int, reg Register) {
.rcx { g.write8(0x4d) } .rcx { g.write8(0x4d) }
else { g.n_error('mov_from_reg $reg') } else { g.n_error('mov_from_reg $reg') }
} }
g.write8(0xff - var_offset + 1) g.write8(0xff - offset + 1)
g.println('mov DWORD PTR[rbp-$var_offset.hex2()],$reg') g.println('mov $size PTR [rbp-$offset.hex2()],$reg')
}
GlobalVar {
// TODO
}
}
} }
fn (mut g Gen) mov_int_to_var(var_offset int, size Size, integer int) { fn (mut g Gen) mov_int_to_var(var Var, integer int, config VarConfig) {
var_addr := 0xff - var_offset + 1 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
}
}
}
LocalVar {
offset := var.offset - config.offset
typ := if config.typ == 0 { var.typ } else { config.typ }
var_addr := 0xff - offset + 1
match size { match typ {
._8 { ast.i8_type_idx, ast.u8_type_idx, ast.char_type_idx {
g.write8(0xc6) g.write8(0xc6)
g.write8(0x45) g.write8(0x45)
g.write8(var_addr) g.write8(var_addr)
g.write8(u8(integer)) g.write8(u8(integer))
g.println('mov BYTE PTR[rbp-$var_offset.hex2()], $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 { else {
g.n_error('unhandled mov int') g.n_error('unhandled mov int type: $typ')
}
}
}
GlobalVar {
// TODO
} }
} }
} }
@ -413,15 +582,68 @@ fn (mut g Gen) lea_var_to_reg(reg Register, var_offset int) {
g.println('lea $reg, [rbp-$var_offset.hex2()]') g.println('lea $reg, [rbp-$var_offset.hex2()]')
} }
fn (mut g Gen) mov_var_to_reg(reg Register, var_offset int) { fn (mut g Gen) mov_var_to_reg(reg Register, var Var, config VarConfig) {
// 8b 7d f8 mov edi,DWORD PTR [rbp-0x8] match var {
match reg { ast.Ident {
.rax, .rbx, .rsi { var_object := g.get_var_from_ident(var)
g.write8(0x48) match var_object {
LocalVar {
g.mov_var_to_reg(reg, var_object as LocalVar, config)
} }
else {} 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) 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 { match reg {
.eax, .rax { g.write8(0x45) } .eax, .rax { g.write8(0x45) }
.edi, .rdi { g.write8(0x7d) } .edi, .rdi { g.write8(0x7d) }
@ -431,8 +653,13 @@ fn (mut g Gen) mov_var_to_reg(reg Register, var_offset int) {
.rcx { g.write8(0x4d) } .rcx { g.write8(0x4d) }
else { g.n_error('mov_var_to_reg $reg') } else { g.n_error('mov_var_to_reg $reg') }
} }
g.write8(0xff - var_offset + 1) g.write8(0xff - offset + 1)
g.println('mov $reg,DWORD PTR[rbp-$var_offset.hex2()]') g.println('$instruction $reg, $size PTR [rbp-$offset.hex2()]')
}
GlobalVar {
// TODO
}
}
} }
fn (mut g Gen) call(addr int) { fn (mut g Gen) call(addr int) {
@ -496,14 +723,6 @@ pub fn (mut g Gen) pop(reg Register) {
g.println('pop $reg') 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) { pub fn (mut g Gen) sub8(reg Register, val int) {
g.write8(0x48) g.write8(0x48)
g.write8(0x83) 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) { pub fn (mut g Gen) sub(reg Register, val int) {
g.write8(0x48) g.write8(0x48)
if reg == .rax {
g.write8(0x2d)
} else {
g.write8(0x81) g.write8(0x81)
g.write8(0xe8 + int(reg)) // TODO rax is different? g.write8(0xe8 + int(reg))
}
g.write32(val) 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) { pub fn (mut g Gen) add(reg Register, val int) {
if reg != .rax {
panic('add only works with .rax')
}
g.write8(0x48) g.write8(0x48)
if reg == .rax {
g.write8(0x05) g.write8(0x05)
} else {
g.write8(0x81)
g.write8(0xc0 + int(reg))
}
g.write32(val) g.write32(val)
g.println('add $reg,$val.hex2()') 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()') 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) { fn (mut g Gen) add8_var(reg Register, var_offset int) {
g.write8(0x03) g.write8(0x03)
match reg { 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()]') 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) { fn (mut g Gen) sub8_var(reg Register, var_offset int) {
g.write8(0x2b) g.write8(0x2b)
match reg { 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()]') 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) { fn (mut g Gen) div8_var(reg Register, var_offset int) {
if reg == .rax || reg == .eax { 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.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 { } else {
panic('div8_var invalid source register') 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) { fn (mut g Gen) mul8_var(reg Register, var_offset int) {
g.write8(0x0f) g.write8(0x0f)
g.write8(0xaf) g.write8(0xaf)
@ -603,6 +836,7 @@ pub fn (mut g Gen) allocate_string(s string, opsize int, typ RelocType) int {
return str_pos return str_pos
} }
// not used?
pub fn (mut g Gen) var_zero(vo int, size int) { pub fn (mut g Gen) var_zero(vo int, size int) {
g.mov32(.rcx, size) g.mov32(.rcx, size)
g.lea_var_to_reg(.rdi, vo) 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') g.n_error('native exit builtin: Unsupported call $right')
} }
ast.Ident { ast.Ident {
var_offset := g.get_var_offset(expr.name) g.mov_var_to_reg(.edi, expr as ast.Ident)
g.mov_var_to_reg(.edi, var_offset)
} }
ast.IntegerLiteral { ast.IntegerLiteral {
g.mov(.edi, expr.val.int()) 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) { fn (mut g Gen) mov_reg(a Register, b Register) {
if a == .rax && b == .rsi { if int(a) <= int(Register.r15) && int(b) <= int(Register.r15) {
g.write([u8(0x48), 0x89, 0xf0]) g.write8(0x48 + if int(a) >= int(Register.r8) { 1 } else { 0 } +
} else if a == .rbp && b == .rsp { if int(b) >= int(Register.r8) { 4 } else { 0 })
g.write8(0x48)
g.write8(0x89) g.write8(0x89)
} else if a == .rdx && b == .rax { g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
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)
} else { } else {
g.n_error('unhandled mov_reg combination for $a $b') 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') 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) { pub fn (mut g Gen) call_fn(node ast.CallExpr) {
if g.pref.arch == .arm64 { if g.pref.arch == .arm64 {
g.call_fn_arm64(node) 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('i=$i fn name= $name offset=$var_offset')
println(int(native.fn_arg_registers[i])) 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 { else {
g.v_error('unhandled call_fn (name=$name) node: $expr.type_name()', node.pos) 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] right := node.right[i]
name := left.str() name := left.str()
// if left is ast.Ident { // if left is ast.Ident {
// ident := left as ast.Ident ident := left as ast.Ident
match right { match right {
ast.IntegerLiteral { ast.IntegerLiteral {
// g.allocate_var(name, 4, right.val.int()) // g.allocate_var(name, 4, right.val.int())
match node.op { match node.op {
.plus_assign { .plus_assign {
dest := g.get_var_offset(name) g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rax, dest)
g.add(.rax, right.val.int()) g.add(.rax, right.val.int())
g.mov_reg_to_var(dest, .rax) g.mov_reg_to_var(ident, .rax)
} }
.minus_assign { .minus_assign {
dest := g.get_var_offset(name) g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rax, dest) g.sub(.rax, right.val.int())
g.mov_var_to_reg(.rbx, g.get_var_offset(name)) g.mov_reg_to_var(ident, .rax)
g.sub_reg(.rax, .rbx)
g.mov_reg_to_var(dest, .rax)
} }
.mult_assign { .mult_assign {
dest := g.get_var_offset(name) g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rax, dest) g.mov64(.rdx, right.val.int())
g.mov_var_to_reg(.rbx, g.get_var_offset(name)) g.mul_reg(.rax, .rdx)
g.mul_reg(.rax, .rbx) g.mov_reg_to_var(ident, .rax)
g.mov_reg_to_var(dest, .rax)
} }
.div_assign { .div_assign {
dest := g.get_var_offset(name) g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rax, dest) g.mov64(.rdx, right.val.int())
g.mov_var_to_reg(.rbx, g.get_var_offset(name)) g.div_reg(.rax, .rdx)
g.div_reg(.rax, .rbx) g.mov_reg_to_var(ident, .rax)
g.mov_reg_to_var(dest, .rax)
} }
.decl_assign { .decl_assign {
g.allocate_var(name, 8, right.val.int()) 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]}' // lname := '${node.left[i]}'
// g.expr(node.right[i]) // g.expr(node.right[i])
g.mov(.rax, right.val.int()) g.mov(.rax, right.val.int())
offset := g.get_var_offset('i') // node.left[i]) g.mov_reg_to_var(ident, .rax)
g.mov_reg_to_var(offset, .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 { else {
tn := node.left[i].type_name() tn := node.left[i].type_name()
dump(node.left_types) dump(node.left_types)
@ -1347,45 +1487,43 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
ast.InfixExpr { ast.InfixExpr {
// eprintln('infix') dump(node) dump(right) // eprintln('infix') dump(node) dump(right)
g.infix_expr(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` // `mov DWORD PTR [rbp-0x8],eax`
if g.pref.is_verbose { if g.pref.is_verbose {
println('infix assignment $name offset=$offset.hex2()') println('infix assignment $name offset=$offset.hex2()')
} }
g.mov_reg_to_var(offset, .rax) g.mov_reg_to_var(ident, .rax)
} }
ast.Ident { ast.Ident {
// eprintln('identr') dump(node) dump(right) // eprintln('identr') dump(node) dump(right)
match node.op { match node.op {
.plus_assign { .plus_assign {
dest := g.get_var_offset(name) g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rax, dest) g.mov_var_to_reg(.rbx, right as ast.Ident)
g.add8_var(.rax, g.get_var_offset(right.name)) g.add_reg(.rax, .rbx)
g.mov_reg_to_var(dest, .rax) g.mov_reg_to_var(ident, .rax)
} }
.minus_assign { .minus_assign {
dest := g.get_var_offset(name) g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rax, dest) g.mov_var_to_reg(.rbx, right as ast.Ident)
g.mov_var_to_reg(.rbx, g.get_var_offset(right.name))
g.sub_reg(.rax, .rbx) g.sub_reg(.rax, .rbx)
g.mov_reg_to_var(dest, .rax) g.mov_reg_to_var(ident, .rax)
} }
.div_assign { .div_assign {
// this should be called when `a /= b` but it's not :? // this should be called when `a /= b` but it's not :?
dest := g.get_var_offset(name) g.mov_var_to_reg(.rax, ident)
g.mov_var_to_reg(.rax, dest) g.mov_var_to_reg(.rbx, right as ast.Ident)
g.mov_var_to_reg(.rbx, g.get_var_offset(right.name))
g.div_reg(.rax, .rbx) g.div_reg(.rax, .rbx)
g.mov_reg_to_var(dest, .rax) g.mov_reg_to_var(ident, .rax)
} }
.decl_assign { .decl_assign {
dest := g.allocate_var(name, 8, 0) g.allocate_var(name, g.get_sizeof_ident(ident), 0)
g.mov_var_to_reg(.rax, g.get_var_offset(right.name)) g.mov_var_to_reg(.rbx, right as ast.Ident)
g.mov_reg_to_var(dest, .rax) g.mov_reg_to_var(ident, .rax)
} }
.assign { .assign {
g.mov_var_to_reg(.rax, g.get_var_offset(right.name)) g.mov_var_to_reg(.rbx, right as ast.Ident)
g.mov_reg_to_var(g.get_var_offset(name), .rax) g.mov_reg_to_var(ident, .rax)
} }
else { else {
eprintln('TODO: unhandled assign ident case') eprintln('TODO: unhandled assign ident case')
@ -1411,13 +1549,13 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
match e { match e {
ast.IntegerLiteral { ast.IntegerLiteral {
g.mov(.rax, e.val.int()) 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 pos += 8
} }
ast.StringLiteral { ast.StringLiteral {
// TODO: use learel // TODO: use learel
g.mov64(.rsi, g.allocate_string('$e.val', 2, .abs64)) // for rsi its 2 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 pos += 8
} }
else { else {
@ -1429,40 +1567,40 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
} }
ast.IndexExpr { ast.IndexExpr {
// a := arr[0] // 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 { if g.pref.is_verbose {
println('infix assignment $name offset=$offset.hex2()') println('infix assignment $name offset=$offset.hex2()')
} }
ie := node.right[i] as ast.IndexExpr ie := node.right[i] as ast.IndexExpr
var_name := ie.left.str() var := ie.left as ast.Ident
mut dest := g.get_var_offset(var_name) dest := g.get_var_offset(var.name)
if ie.index is ast.IntegerLiteral { if ie.index is ast.IntegerLiteral {
index := ie.index index := ie.index
dest += index.val.int() * 8 ie_offset := index.val.int() * 8
g.mov_var_to_reg(.rax, dest) g.mov_var_to_reg(.rax, var, typ: ast.i64_type_idx, offset: ie_offset)
} else if ie.index is ast.Ident { } else if ie.index is ast.Ident {
ident := ie.index ie_ident := ie.index
var_offset := g.get_var_offset(ident.name) g.lea_var_to_reg(.rax, dest)
g.mov_var_to_reg(.edi, var_offset) g.mov_var_to_reg(.rdi, ie_ident)
g.mov_var_to_reg(.rax, dest)
g.add_reg(.rax, .rdi) g.add_reg(.rax, .rdi)
g.mov_deref(.rax, .rax)
} else { } else {
g.n_error('only integers and idents can be used as indexes') g.n_error('only integers and idents can be used as indexes')
} }
// TODO check if out of bounds access // TODO check if out of bounds access
g.mov_reg_to_var(offset, .eax) g.mov_reg_to_var(ident, .eax)
} }
ast.StringLiteral { ast.StringLiteral {
dest := g.allocate_var(name, 4, 0) dest := g.allocate_var(name, 8, 0)
ie := node.right[i] as ast.StringLiteral ie := node.right[i] as ast.StringLiteral
g.learel(.rsi, g.allocate_string(ie.val.str(), 3, .rel32)) 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 { ast.CallExpr {
dest := g.allocate_var(name, 4, 0) g.allocate_var(name, g.get_sizeof_ident(ident), 0)
g.call_fn(right) g.call_fn(right)
g.mov_reg_to_var(dest, .rax) g.mov_reg_to_var(ident, .rax)
g.mov_var_to_reg(.rsi, dest) g.mov_var_to_reg(.rsi, ident)
} }
ast.SelectorExpr { ast.SelectorExpr {
g.v_error('unhandled selectors', node.pos) g.v_error('unhandled selectors', node.pos)
@ -1508,7 +1646,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
} }
match node.left { match node.left {
ast.Ident { 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 {} else {}
} }
@ -1731,7 +1869,7 @@ fn (mut g Gen) condition(infix_expr ast.InfixExpr, neg bool) int {
ast.Ident { ast.Ident {
// 3 < var // 3 < var
// lit := infix_expr.right as 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, lit.val.int())
// +not // +not
g.n_error('unsupported if construction') g.n_error('unsupported if construction')
} }
@ -1745,7 +1883,7 @@ fn (mut g Gen) condition(infix_expr ast.InfixExpr, neg bool) int {
ast.IntegerLiteral { ast.IntegerLiteral {
// var < 4 // var < 4
lit := infix_expr.right as 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())
} }
ast.Ident { ast.Ident {
// var < var2 // var < var2
@ -1862,13 +2000,12 @@ fn (mut g Gen) for_stmt(node ast.ForStmt) {
ast.Ident { ast.Ident {
match infix_expr.right { match infix_expr.right {
ast.Ident { ast.Ident {
var_offset := g.get_var_offset(infix_expr.right.name) g.mov_var_to_reg(.rax, infix_expr.right as ast.Ident)
g.mov_var_to_reg(.rax, var_offset) g.cmp_var_reg(infix_expr.left as ast.Ident, .rax)
g.cmp_var_reg(infix_expr.left.name, .rax)
} }
ast.IntegerLiteral { ast.IntegerLiteral {
lit := infix_expr.right as 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 { else {
g.n_error('unhandled expression type') 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) { fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
g.push(.rbp) g.push(.rbp)
g.mov_rbp_rsp() g.mov_reg(.rbp, .rsp)
locals_count := node.scope.objects.len + node.params.len + node.defer_stmts.len local_alloc_pos := g.pos()
g.stackframe_size = (locals_count * 8) + 0x10 g.sub(.rsp, 0)
g.sub8(.rsp, g.stackframe_size)
// Copy values from registers to local vars (calling convention) // Copy values from registers to local vars (calling convention)
mut offset := 0 mut offset := 0
@ -1927,7 +2063,8 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
g.allocate_var(name, 4, 0) g.allocate_var(name, 4, 0)
// `mov DWORD PTR [rbp-0x4],edi` // `mov DWORD PTR [rbp-0x4],edi`
offset += 4 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 // define defer vars
for i in 0 .. node.defer_stmts.len { 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.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' is_main := node.name == 'main.main'
if is_main { if is_main {
// println('end of main: gen exit') // println('end of main: gen exit')
@ -1951,8 +2090,9 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
// save return value // save return value
g.push(.rax) g.push(.rax)
for defer_stmt in g.defer_stmts.reverse() { for defer_stmt in g.defer_stmts.reverse() {
defer_var := g.get_var_offset('_defer$defer_stmt.idx_in_fn') name := '_defer$defer_stmt.idx_in_fn'
g.mov_var_to_reg(.rax, defer_var) 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) g.cmp_zero(.rax)
label := g.labels.new_label() label := g.labels.new_label()
jump_addr := g.cjmp(.je) jump_addr := g.cjmp(.je)
@ -1965,7 +2105,7 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
} }
g.pop(.rax) g.pop(.rax)
} }
g.add8(.rsp, g.stackframe_size) g.mov_reg(.rsp, .rbp)
g.pop(.rbp) g.pop(.rbp)
g.ret() 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.write8(0xff - n + 1)
g.stack_var_pos += size g.stack_var_pos += size
g.var_offset[name] = g.stack_var_pos g.var_offset[name] = g.stack_var_pos
g.var_alloc_size[name] = size
// Generate the value assigned to the variable // Generate the value assigned to the variable
match size { 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') g.println('; jump to label $skip_zero_label')
// handle zeros seperately // 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_label := g.labels.new_label()
end_jmp_addr := g.jmp(0) end_jmp_addr := g.jmp(0)
g.labels.patches << LabelPatch{ 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') g.println('; jump to label $skip_minus_label')
// 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(LocalVar{buffer, ast.u8_type_idx, ''}, '-'[0])
g.neg(.rax) // negate our integer to make it positive g.neg(.rax) // negate our integer to make it positive
g.inc(.rdi) // increment rdi to skip the `-` character 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()

View File

@ -32,12 +32,12 @@ mut:
buf []u8 buf []u8
sect_header_name_pos int sect_header_name_pos int
offset i64 offset i64
stackframe_size int
file_size_pos i64 file_size_pos i64
main_fn_addr i64 main_fn_addr i64
code_start_pos i64 // location of the start of the assembly instructions code_start_pos i64 // location of the start of the assembly instructions
fn_addr map[string]i64 fn_addr map[string]i64
var_offset map[string]int // local var stack offset var_offset map[string]int // local var stack offset
var_alloc_size map[string]int // local var allocation size
stack_var_pos int stack_var_pos int
debug_pos int debug_pos int
errors []errors.Error errors []errors.Error
@ -105,6 +105,44 @@ enum Size {
_64 _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 { fn get_backend(arch pref.Arch) ?CodeGen {
match arch { match arch {
.arm64 { .arm64 {
@ -338,15 +376,61 @@ fn (mut g Gen) get_var_offset(var_name string) int {
return r 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) { fn (mut g Gen) gen_typeof_expr(it ast.TypeOf, newline bool) {
nl := if newline { '\n' } else { '' } nl := if newline { '\n' } else { '' }
r := g.typ(it.expr_type).name r := g.typ(it.expr_type).name
g.learel(.rax, g.allocate_string('$r$nl', 3, .rel32)) 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 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.convert_int_to_string(reg, buffer)
g.lea_var_to_reg(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) vo := g.try_var_offset(expr.name)
if vo != -1 { 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) g.gen_print_reg(.rax, 3, fd)
if newline { if newline {
g.gen_print('\n', fd) g.gen_print('\n', fd)
@ -565,7 +649,7 @@ fn (mut g Gen) gen_forc_stmt(node ast.ForCStmt) {
match cond.left { match cond.left {
ast.Ident { ast.Ident {
lit := cond.right as ast.IntegerLiteral 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 { match cond.op {
.gt { .gt {
jump_addr = g.cjmp(.jle) 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 { // for a in node.cond .. node.high {
i := g.allocate_var(node.val_var, 8, 0) // iterator variable i := g.allocate_var(node.val_var, 8, 0) // iterator variable
g.expr(node.cond) 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 := g.pos() // label-begin:
start_label := g.labels.new_label() 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.expr(node.high) // final value
g.cmp_reg(.rbx, .rax) // rbx = iterator, rax = max value g.cmp_reg(.rbx, .rax) // rbx = iterator, rax = max value
jump_addr := g.cjmp(.jge) // leave loop if i is beyond end 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.stmts(node.stmts)
g.labels.addrs[start_label] = g.pos() g.labels.addrs[start_label] = g.pos()
g.println('; label $start_label') 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.labels.branches.pop()
g.jmp(int(0xffffffff - (g.pos() + 5 - start) + 1)) g.jmp(int(0xffffffff - (g.pos() + 5 - start) + 1))
g.labels.addrs[end_label] = g.pos() g.labels.addrs[end_label] = g.pos()
@ -697,8 +781,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
} }
ast.ConstDecl {} ast.ConstDecl {}
ast.DeferStmt { ast.DeferStmt {
defer_var := g.get_var_offset('_defer$g.defer_stmts.len') name := '_defer$g.defer_stmts.len'
g.mov_int_to_var(defer_var, ._8, 1) 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 << node
g.defer_stmts[g.defer_stmts.len - 1].idx_in_fn = g.defer_stmts.len - 1 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.FloatLiteral {}
ast.Ident { 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 // XXX this is intel specific
g.mov_var_to_reg(.rax, offset) g.mov_var_to_reg(.rax, node as ast.Ident)
} }
ast.IfExpr { ast.IfExpr {
if node.is_comptime { if node.is_comptime {
@ -918,13 +998,12 @@ fn (mut g Gen) postfix_expr(node ast.PostfixExpr) {
return return
} }
ident := node.expr as ast.Ident ident := node.expr as ast.Ident
var_name := ident.name
match node.op { match node.op {
.inc { .inc {
g.inc_var(var_name) g.inc_var(ident)
} }
.dec { .dec {
g.dec_var(var_name) g.dec_var(ident)
} }
else {} else {}
} }