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:
parent
57c4188d98
commit
f2961ec862
|
@ -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()
|
||||||
|
|
|
@ -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 {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user