mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
native: add initial implementation of simple structs (#15722)
This commit is contained in:
@ -481,24 +481,52 @@ fn (mut g Gen) mov64(reg Register, val i64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) movabs(reg Register, val i64) {
|
fn (mut g Gen) movabs(reg Register, val i64) {
|
||||||
match reg {
|
g.write8(0x48 + int(reg) / 8)
|
||||||
.rsi {
|
g.write8(0xb8 + int(reg) % 8)
|
||||||
g.write8(0x48)
|
|
||||||
g.write8(0xbe)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
panic('unhandled movabs $reg, $val')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g.write64(val)
|
g.write64(val)
|
||||||
g.println('movabs $reg, $val')
|
g.println('movabs $reg, $val')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) mov_deref(reg Register, regptr Register) {
|
fn (mut g Gen) mov_deref(reg Register, regptr Register, typ ast.Type) {
|
||||||
g.write8(0x48 + int(reg) / 8 * 4 + int(regptr) / 8)
|
size := g.get_type_size(typ)
|
||||||
g.write8(0x8b)
|
if size !in [1, 2, 4, 8] {
|
||||||
|
g.n_error('Invalid size on dereferencing')
|
||||||
|
}
|
||||||
|
is_signed := !typ.is_real_pointer() && typ.is_signed()
|
||||||
|
rex := int(reg) / 8 * 4 + int(regptr) / 8
|
||||||
|
if size == 4 && !is_signed {
|
||||||
|
if rex > 0 {
|
||||||
|
g.write8(0x40 + rex)
|
||||||
|
}
|
||||||
|
g.write8(0x8b)
|
||||||
|
} else {
|
||||||
|
g.write8(0x48 + int(reg) / 8 * 4 + int(regptr) / 8)
|
||||||
|
if size <= 2 {
|
||||||
|
g.write8(0x0f)
|
||||||
|
}
|
||||||
|
g.write8(match true {
|
||||||
|
size == 1 && is_signed { 0xbe }
|
||||||
|
size == 1 && !is_signed { 0xb6 }
|
||||||
|
size == 2 && is_signed { 0xbf }
|
||||||
|
size == 2 && !is_signed { 0xb7 }
|
||||||
|
size == 4 && is_signed { 0x63 }
|
||||||
|
else { 0x8b }
|
||||||
|
})
|
||||||
|
}
|
||||||
g.write8(int(reg) % 8 * 8 + int(regptr) % 8)
|
g.write8(int(reg) % 8 * 8 + int(regptr) % 8)
|
||||||
|
g.println('mov $reg, [$regptr]')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) mov_store(regptr Register, reg Register, size Size) {
|
||||||
|
if size == ._16 {
|
||||||
|
g.write8(0x66)
|
||||||
|
}
|
||||||
|
if size == ._64 {
|
||||||
|
g.write8(0x48 + int(reg) / 8 * 4 + int(regptr) / 8)
|
||||||
|
}
|
||||||
|
g.write8(if size == ._8 { 0x88 } else { 0x89 })
|
||||||
|
g.write8(int(reg) % 8 * 8 + int(regptr) % 8)
|
||||||
|
g.println('mov [$regptr], $reg')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) mov_reg_to_var(var Var, reg Register, config VarConfig) {
|
fn (mut g Gen) mov_reg_to_var(var Var, reg Register, config VarConfig) {
|
||||||
@ -615,6 +643,28 @@ fn (mut g Gen) mov_int_to_var(var Var, integer int, config VarConfig) {
|
|||||||
g.write8(u8(integer))
|
g.write8(u8(integer))
|
||||||
g.println('mov BYTE PTR[rbp-$offset.hex2()], $integer')
|
g.println('mov BYTE PTR[rbp-$offset.hex2()], $integer')
|
||||||
}
|
}
|
||||||
|
ast.i16_type_idx, ast.u16_type_idx {
|
||||||
|
g.write16(0xc766)
|
||||||
|
g.write8(if is_far_var { 0x85 } else { 0x45 })
|
||||||
|
if is_far_var {
|
||||||
|
g.write32(int((0xffffffff - i64(offset) + 1) % 0x100000000))
|
||||||
|
} else {
|
||||||
|
g.write8((0xff - offset + 1) % 0x100)
|
||||||
|
}
|
||||||
|
g.write16(u16(integer))
|
||||||
|
g.println('mov WORD PTR[rbp-$offset.hex2()], $integer')
|
||||||
|
}
|
||||||
|
ast.int_type_idx, ast.u32_type_idx, ast.rune_type_idx {
|
||||||
|
g.write8(0xc7)
|
||||||
|
g.write8(if is_far_var { 0x85 } else { 0x45 })
|
||||||
|
if is_far_var {
|
||||||
|
g.write32(int((0xffffffff - i64(offset) + 1) % 0x100000000))
|
||||||
|
} else {
|
||||||
|
g.write8((0xff - offset + 1) % 0x100)
|
||||||
|
}
|
||||||
|
g.write32(integer)
|
||||||
|
g.println('mov DWORD PTR[rbp-$offset.hex2()], $integer')
|
||||||
|
}
|
||||||
ast.i64_type_idx, ast.u64_type_idx, ast.isize_type_idx, ast.usize_type_idx,
|
ast.i64_type_idx, ast.u64_type_idx, ast.isize_type_idx, ast.usize_type_idx,
|
||||||
ast.int_literal_type_idx {
|
ast.int_literal_type_idx {
|
||||||
g.write8(0x48)
|
g.write8(0x48)
|
||||||
@ -918,6 +968,7 @@ fn (mut g Gen) bitand_reg(a Register, b Register) {
|
|||||||
if int(b) >= int(Register.r8) { 4 } else { 0 })
|
if int(b) >= int(Register.r8) { 4 } else { 0 })
|
||||||
g.write8(0x21)
|
g.write8(0x21)
|
||||||
g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
|
g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
|
||||||
|
g.println('and $a, $b')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) bitor_reg(a Register, b Register) {
|
fn (mut g Gen) bitor_reg(a Register, b Register) {
|
||||||
@ -925,6 +976,7 @@ fn (mut g Gen) bitor_reg(a Register, b Register) {
|
|||||||
if int(b) >= int(Register.r8) { 4 } else { 0 })
|
if int(b) >= int(Register.r8) { 4 } else { 0 })
|
||||||
g.write8(0x09)
|
g.write8(0x09)
|
||||||
g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
|
g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
|
||||||
|
g.println('or $a, $b')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) bitxor_reg(a Register, b Register) {
|
fn (mut g Gen) bitxor_reg(a Register, b Register) {
|
||||||
@ -932,6 +984,7 @@ fn (mut g Gen) bitxor_reg(a Register, b Register) {
|
|||||||
if int(b) >= int(Register.r8) { 4 } else { 0 })
|
if int(b) >= int(Register.r8) { 4 } else { 0 })
|
||||||
g.write8(0x31)
|
g.write8(0x31)
|
||||||
g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
|
g.write8(0xc0 + int(a) % 8 + int(b) % 8 * 8)
|
||||||
|
g.println('xor $a, $b')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) shl_reg(a Register, b Register) {
|
fn (mut g Gen) shl_reg(a Register, b Register) {
|
||||||
@ -1507,20 +1560,100 @@ pub fn (mut g Gen) call_fn_amd64(node ast.CallExpr) {
|
|||||||
n = 'main.$n'
|
n = 'main.$n'
|
||||||
}
|
}
|
||||||
addr := g.fn_addr[n]
|
addr := g.fn_addr[n]
|
||||||
|
|
||||||
|
mut reg_args := []int{}
|
||||||
|
mut stack_args := []int{}
|
||||||
|
mut args_size := node.args.map(g.get_type_size(it.typ))
|
||||||
|
|
||||||
|
ts := g.table.sym(node.return_type)
|
||||||
|
return_size := g.get_type_size(node.return_type)
|
||||||
|
mut return_pos := -1
|
||||||
|
struct_arg_idx := node.args.len
|
||||||
|
if ts.kind == .struct_ {
|
||||||
|
return_pos = g.allocate_struct('', node.return_type)
|
||||||
|
if return_size > 16 {
|
||||||
|
reg_args << struct_arg_idx
|
||||||
|
args_size << 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mut reg_left := 6 - reg_args.len
|
||||||
|
for i, size in args_size {
|
||||||
|
if reg_left > 0 {
|
||||||
|
if size <= 8 {
|
||||||
|
reg_args << i
|
||||||
|
reg_left--
|
||||||
|
continue
|
||||||
|
} else if size <= 16 && reg_left > 1 {
|
||||||
|
reg_args << i
|
||||||
|
reg_left -= 2
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stack_args << i
|
||||||
|
}
|
||||||
|
reg_size := reg_args.map((args_size[it] + 7) / 8).reduce(fn (a int, b int) int {
|
||||||
|
return a + b
|
||||||
|
}, 0)
|
||||||
|
stack_size := stack_args.map((args_size[it] + 7) / 8).reduce(fn (a int, b int) int {
|
||||||
|
return a + b
|
||||||
|
}, 0)
|
||||||
|
|
||||||
// not aligned now XOR pushed args will be odd
|
// not aligned now XOR pushed args will be odd
|
||||||
is_16bit_aligned := if mut g.code_gen is Amd64 { g.code_gen.is_16bit_aligned } else { true } != (
|
is_16bit_aligned := if mut g.code_gen is Amd64 { g.code_gen.is_16bit_aligned } else { true } != (stack_size % 2 == 1)
|
||||||
node.args.len > 6 && node.args.len % 2 == 1)
|
|
||||||
if !is_16bit_aligned {
|
if !is_16bit_aligned {
|
||||||
// dummy data
|
// dummy data
|
||||||
g.push(.rbp)
|
g.push(.rbp)
|
||||||
}
|
}
|
||||||
for i_ in 0 .. node.args.len {
|
reg_args << stack_args
|
||||||
i := node.args.len - i_ - 1
|
for i in reg_args.reverse() {
|
||||||
|
if i == struct_arg_idx {
|
||||||
|
g.lea_var_to_reg(.rax, return_pos)
|
||||||
|
g.push(.rax)
|
||||||
|
continue
|
||||||
|
}
|
||||||
g.expr(node.args[i].expr)
|
g.expr(node.args[i].expr)
|
||||||
g.push(.rax)
|
if g.table.sym(node.args[i].typ).kind == .struct_ {
|
||||||
|
match args_size[i] {
|
||||||
|
1...8 {
|
||||||
|
g.mov_deref(.rax, .rax, ast.i64_type_idx)
|
||||||
|
if args_size[i] != 8 {
|
||||||
|
g.movabs(.rdx, (i64(1) << (args_size[i] * 8)) - 1)
|
||||||
|
g.bitand_reg(.rax, .rdx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
9...16 {
|
||||||
|
g.add(.rax, 8)
|
||||||
|
g.mov_deref(.rdx, .rax, ast.i64_type_idx)
|
||||||
|
g.sub(.rax, 8)
|
||||||
|
g.mov_deref(.rax, .rax, ast.i64_type_idx)
|
||||||
|
if args_size[i] != 16 {
|
||||||
|
g.movabs(.rbx, (i64(1) << ((args_size[i] - 8) * 8)) - 1)
|
||||||
|
g.bitand_reg(.rdx, .rbx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match args_size[i] {
|
||||||
|
1...8 {
|
||||||
|
g.push(.rax)
|
||||||
|
}
|
||||||
|
9...16 {
|
||||||
|
g.push(.rdx)
|
||||||
|
g.push(.rax)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.add(.rax, args_size[i] - ((args_size[i] + 7) % 8 + 1))
|
||||||
|
for _ in 0 .. (args_size[i] + 7) / 8 {
|
||||||
|
g.mov_deref(.rdx, .rax, ast.i64_type_idx)
|
||||||
|
g.push(.rdx)
|
||||||
|
g.sub(.rax, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
num_on_register := if node.args.len > 6 { 6 } else { node.args.len }
|
for i in 0 .. reg_size {
|
||||||
for i in 0 .. num_on_register {
|
|
||||||
g.pop(native.fn_arg_registers[i])
|
g.pop(native.fn_arg_registers[i])
|
||||||
}
|
}
|
||||||
if addr == 0 {
|
if addr == 0 {
|
||||||
@ -1530,11 +1663,54 @@ pub fn (mut g Gen) call_fn_amd64(node ast.CallExpr) {
|
|||||||
g.call(int(addr))
|
g.call(int(addr))
|
||||||
}
|
}
|
||||||
g.println('call `${name}()`')
|
g.println('call `${name}()`')
|
||||||
|
|
||||||
|
if ts.kind == .struct_ {
|
||||||
|
match return_size {
|
||||||
|
1...7 {
|
||||||
|
g.mov_var_to_reg(.rdx, LocalVar{ offset: return_pos, typ: ast.i64_type_idx })
|
||||||
|
g.movabs(.rcx, 0xffffffffffffffff - (i64(1) << (return_size * 8)) + 1)
|
||||||
|
g.bitand_reg(.rdx, .rcx)
|
||||||
|
g.bitor_reg(.rdx, .rax)
|
||||||
|
g.mov_reg_to_var(LocalVar{ offset: return_pos, typ: ast.i64_type_idx },
|
||||||
|
.rdx)
|
||||||
|
}
|
||||||
|
8 {
|
||||||
|
g.mov_reg_to_var(LocalVar{ offset: return_pos, typ: ast.i64_type_idx },
|
||||||
|
.rax)
|
||||||
|
}
|
||||||
|
9...15 {
|
||||||
|
g.mov_reg_to_var(LocalVar{ offset: return_pos, typ: ast.i64_type_idx },
|
||||||
|
.rax)
|
||||||
|
g.mov_var_to_reg(.rax, LocalVar{ offset: return_pos, typ: ast.i64_type_idx },
|
||||||
|
|
||||||
|
offset: 8
|
||||||
|
)
|
||||||
|
g.movabs(.rcx, 0xffffffffffffffff - (i64(1) << (return_size * 8)) + 1)
|
||||||
|
g.bitand_reg(.rax, .rcx)
|
||||||
|
g.bitor_reg(.rax, .rdx)
|
||||||
|
g.mov_reg_to_var(LocalVar{ offset: return_pos, typ: ast.i64_type_idx },
|
||||||
|
.rax,
|
||||||
|
offset: 8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
16 {
|
||||||
|
g.mov_reg_to_var(LocalVar{ offset: return_pos, typ: ast.i64_type_idx },
|
||||||
|
.rax)
|
||||||
|
g.mov_reg_to_var(LocalVar{ offset: return_pos, typ: ast.i64_type_idx },
|
||||||
|
.rdx,
|
||||||
|
offset: 8
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
g.lea_var_to_reg(.rax, return_pos)
|
||||||
|
}
|
||||||
|
|
||||||
if !is_16bit_aligned {
|
if !is_16bit_aligned {
|
||||||
// dummy data
|
// dummy data
|
||||||
g.pop(.rdi)
|
g.pop(.rdi)
|
||||||
}
|
}
|
||||||
for _ in 0 .. node.args.len - 6 {
|
for _ in 0 .. stack_size {
|
||||||
// args
|
// args
|
||||||
g.pop(.rdi)
|
g.pop(.rdi)
|
||||||
}
|
}
|
||||||
@ -1676,13 +1852,176 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||||||
g.mov_reg_to_var(ident, .rax)
|
g.mov_reg_to_var(ident, .rax)
|
||||||
}
|
}
|
||||||
.decl_assign {
|
.decl_assign {
|
||||||
g.allocate_var(name, g.get_sizeof_ident(ident), 0)
|
typ := node.left_types[i]
|
||||||
g.mov_var_to_reg(.rbx, right as ast.Ident)
|
if typ.is_number() || typ.is_real_pointer() || typ.is_bool() {
|
||||||
g.mov_reg_to_var(ident, .rax)
|
g.allocate_var(name, g.get_type_size(typ), 0)
|
||||||
|
} else {
|
||||||
|
ts := g.table.sym(typ)
|
||||||
|
match ts.info {
|
||||||
|
ast.Struct {
|
||||||
|
g.allocate_struct(name, typ)
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var_ := g.get_var_from_ident(ident)
|
||||||
|
// TODO global var
|
||||||
|
right_var := g.get_var_from_ident(right) as LocalVar
|
||||||
|
match var_ {
|
||||||
|
LocalVar {
|
||||||
|
var := var_ as LocalVar
|
||||||
|
if var.typ.is_number() || var.typ.is_real_pointer()
|
||||||
|
|| var.typ.is_bool() {
|
||||||
|
g.mov_var_to_reg(.rax, right as ast.Ident)
|
||||||
|
g.mov_reg_to_var(ident, .rax)
|
||||||
|
} else {
|
||||||
|
ts := g.table.sym(var.typ)
|
||||||
|
match ts.info {
|
||||||
|
ast.Struct {
|
||||||
|
size := g.get_type_size(var.typ)
|
||||||
|
if size >= 8 {
|
||||||
|
for offset in 0 .. size / 8 {
|
||||||
|
g.mov_var_to_reg(.rax, right_var,
|
||||||
|
offset: offset * 8, typ: ast.i64_type_idx)
|
||||||
|
g.mov_reg_to_var(var, .rax,
|
||||||
|
offset: offset * 8
|
||||||
|
typ: ast.i64_type_idx
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if size % 8 != 0 {
|
||||||
|
g.mov_var_to_reg(.rax, right_var,
|
||||||
|
offset: size - 8, typ: ast.i64_type_idx)
|
||||||
|
g.mov_reg_to_var(var, .rax,
|
||||||
|
offset: size - 8
|
||||||
|
typ: ast.i64_type_idx
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mut left_size := if size >= 4 {
|
||||||
|
g.mov_var_to_reg(.rax, right_var,
|
||||||
|
typ: ast.int_type_idx)
|
||||||
|
g.mov_reg_to_var(var, .rax,
|
||||||
|
typ: ast.int_type_idx
|
||||||
|
)
|
||||||
|
size - 4
|
||||||
|
} else {
|
||||||
|
size
|
||||||
|
}
|
||||||
|
if left_size >= 2 {
|
||||||
|
g.mov_var_to_reg(.rax, right_var,
|
||||||
|
|
||||||
|
offset: size - left_size
|
||||||
|
typ: ast.i16_type_idx
|
||||||
|
)
|
||||||
|
g.mov_reg_to_var(var, .rax,
|
||||||
|
offset: size - left_size
|
||||||
|
typ: ast.i16_type_idx
|
||||||
|
)
|
||||||
|
left_size -= 2
|
||||||
|
}
|
||||||
|
if left_size == 1 {
|
||||||
|
g.mov_var_to_reg(.rax, right_var,
|
||||||
|
|
||||||
|
offset: size - left_size
|
||||||
|
typ: ast.i8_type_idx
|
||||||
|
)
|
||||||
|
g.mov_reg_to_var(var, .rax,
|
||||||
|
offset: size - left_size
|
||||||
|
typ: ast.i8_type_idx
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('Unsupported variable type')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('Unsupported variable kind')
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.assign {
|
.assign {
|
||||||
g.mov_var_to_reg(.rbx, right as ast.Ident)
|
var_ := g.get_var_from_ident(ident)
|
||||||
g.mov_reg_to_var(ident, .rax)
|
// TODO global var
|
||||||
|
right_var := g.get_var_from_ident(right) as LocalVar
|
||||||
|
match var_ {
|
||||||
|
LocalVar {
|
||||||
|
var := var_ as LocalVar
|
||||||
|
if var.typ.is_number() || var.typ.is_real_pointer()
|
||||||
|
|| var.typ.is_bool() {
|
||||||
|
g.mov_var_to_reg(.rax, right as ast.Ident)
|
||||||
|
g.mov_reg_to_var(ident, .rax)
|
||||||
|
} else {
|
||||||
|
ts := g.table.sym(var.typ)
|
||||||
|
match ts.info {
|
||||||
|
ast.Struct {
|
||||||
|
size := g.get_type_size(var.typ)
|
||||||
|
if size >= 8 {
|
||||||
|
for offset in 0 .. size / 8 {
|
||||||
|
g.mov_var_to_reg(.rax, right_var,
|
||||||
|
offset: offset * 8, typ: ast.i64_type_idx)
|
||||||
|
g.mov_reg_to_var(var, .rax,
|
||||||
|
offset: offset * 8
|
||||||
|
typ: ast.i64_type_idx
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if size % 8 != 0 {
|
||||||
|
g.mov_var_to_reg(.rax, right_var,
|
||||||
|
offset: size - 8, typ: ast.i64_type_idx)
|
||||||
|
g.mov_reg_to_var(var, .rax,
|
||||||
|
offset: size - 8
|
||||||
|
typ: ast.i64_type_idx
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mut left_size := if size >= 4 {
|
||||||
|
g.mov_var_to_reg(.rax, right_var,
|
||||||
|
typ: ast.int_type_idx)
|
||||||
|
g.mov_reg_to_var(var, .rax,
|
||||||
|
typ: ast.int_type_idx
|
||||||
|
)
|
||||||
|
size - 4
|
||||||
|
} else {
|
||||||
|
size
|
||||||
|
}
|
||||||
|
if left_size >= 2 {
|
||||||
|
g.mov_var_to_reg(.rax, right_var,
|
||||||
|
|
||||||
|
offset: size - left_size
|
||||||
|
typ: ast.i16_type_idx
|
||||||
|
)
|
||||||
|
g.mov_reg_to_var(var, .rax,
|
||||||
|
offset: size - left_size
|
||||||
|
typ: ast.i16_type_idx
|
||||||
|
)
|
||||||
|
left_size -= 2
|
||||||
|
}
|
||||||
|
if left_size == 1 {
|
||||||
|
g.mov_var_to_reg(.rax, right_var,
|
||||||
|
|
||||||
|
offset: size - left_size
|
||||||
|
typ: ast.i8_type_idx
|
||||||
|
)
|
||||||
|
g.mov_reg_to_var(var, .rax,
|
||||||
|
offset: size - left_size
|
||||||
|
typ: ast.i8_type_idx
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('Unsupported variable type')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('Unsupported variable kind')
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
eprintln('TODO: unhandled assign ident case')
|
eprintln('TODO: unhandled assign ident case')
|
||||||
@ -1692,12 +2031,14 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||||||
// a += b
|
// a += b
|
||||||
}
|
}
|
||||||
ast.StructInit {
|
ast.StructInit {
|
||||||
sym := g.table.sym(right.typ)
|
match node.op {
|
||||||
info := sym.info as ast.Struct
|
.decl_assign {
|
||||||
for field in info.fields {
|
g.allocate_struct(name, right.typ)
|
||||||
field_name := name + '.' + field.name
|
g.init_struct(ident, right)
|
||||||
println(field_name)
|
}
|
||||||
g.allocate_var(field_name, 4, 0)
|
else {
|
||||||
|
g.n_error('Unexpected operator `$node.op`')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.ArrayInit {
|
ast.ArrayInit {
|
||||||
@ -1742,7 +2083,7 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||||||
g.lea_var_to_reg(.rax, dest)
|
g.lea_var_to_reg(.rax, dest)
|
||||||
g.mov_var_to_reg(.rdi, ie_ident)
|
g.mov_var_to_reg(.rdi, ie_ident)
|
||||||
g.add_reg(.rax, .rdi)
|
g.add_reg(.rax, .rdi)
|
||||||
g.mov_deref(.rax, .rax)
|
g.mov_deref(.rax, .rax, ast.i64_type_idx)
|
||||||
} 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')
|
||||||
}
|
}
|
||||||
@ -1761,9 +2102,6 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
|
|||||||
g.mov_reg_to_var(ident, .rax)
|
g.mov_reg_to_var(ident, .rax)
|
||||||
g.mov_var_to_reg(.rsi, ident)
|
g.mov_var_to_reg(.rsi, ident)
|
||||||
}
|
}
|
||||||
ast.SelectorExpr {
|
|
||||||
g.v_error('unhandled selectors', node.pos)
|
|
||||||
}
|
|
||||||
ast.GoExpr {
|
ast.GoExpr {
|
||||||
g.v_error('threads not implemented for the native backend', node.pos)
|
g.v_error('threads not implemented for the native backend', node.pos)
|
||||||
}
|
}
|
||||||
@ -2362,28 +2700,81 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
|
|||||||
g.sub(.rsp, 0)
|
g.sub(.rsp, 0)
|
||||||
|
|
||||||
// Copy values from registers to local vars (calling convention)
|
// Copy values from registers to local vars (calling convention)
|
||||||
mut offset := 0
|
mut reg_args := []int{}
|
||||||
for i in 0 .. node.params.len {
|
mut stack_args := []int{}
|
||||||
name := node.params[i].name
|
mut args_size := node.params.map(g.get_type_size(it.typ))
|
||||||
// TODO optimize. Right now 2 mov's are used instead of 1.
|
|
||||||
g.allocate_var(name, 4, 0)
|
ts := g.table.sym(node.return_type)
|
||||||
// `mov DWORD PTR [rbp-0x4],edi`
|
return_size := g.get_type_size(node.return_type)
|
||||||
offset += 4
|
struct_arg_idx := node.params.len
|
||||||
// TODO size
|
mut return_val_offset := -1
|
||||||
if i < 6 {
|
if ts.kind == .struct_ {
|
||||||
g.mov_reg_to_var(LocalVar{offset, ast.int_type_idx, name}, native.fn_arg_registers[i])
|
if return_size > 16 {
|
||||||
} else {
|
return_val_offset = g.allocate_var('_return_val_addr', 8, 0)
|
||||||
// &var = rbp + 16, 24, 32, ...
|
reg_args << struct_arg_idx
|
||||||
g.var_offset[name] = (4 - i) * 8
|
args_size << 8
|
||||||
g.var_alloc_size[name] = 4
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mut reg_left := 6
|
||||||
|
for i, size in args_size {
|
||||||
|
if reg_left > 0 {
|
||||||
|
if size <= 8 {
|
||||||
|
reg_args << i
|
||||||
|
reg_left--
|
||||||
|
continue
|
||||||
|
} else if size <= 16 && reg_left > 1 {
|
||||||
|
reg_args << i
|
||||||
|
reg_left -= 2
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stack_args << i
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
reg_size := reg_args.map((args_size[it] + 7) / 8).reduce(fn (a int, b int) int {
|
||||||
|
return a + b
|
||||||
|
}, 0)
|
||||||
|
stack_size := stack_args.map((args_size[it] + 7) / 8).reduce(fn (a int, b int) int {
|
||||||
|
return a + b
|
||||||
|
}, 0)*/
|
||||||
|
|
||||||
|
// define and copy args on register
|
||||||
|
mut reg_idx := 0
|
||||||
|
for i in reg_args {
|
||||||
|
name := if i == struct_arg_idx { '_return_val_addr' } else { node.params[i].name }
|
||||||
|
g.stack_var_pos += args_size[i] % 8
|
||||||
|
offset := if i == struct_arg_idx {
|
||||||
|
return_val_offset
|
||||||
|
} else {
|
||||||
|
g.allocate_struct(name, node.params[i].typ)
|
||||||
|
}
|
||||||
|
// copy
|
||||||
|
g.mov_reg_to_var(LocalVar{ offset: offset, typ: ast.i64_type_idx, name: name },
|
||||||
|
native.fn_arg_registers[reg_idx])
|
||||||
|
reg_idx++
|
||||||
|
if args_size[i] > 8 {
|
||||||
|
g.mov_reg_to_var(LocalVar{ offset: offset, typ: ast.i64_type_idx, name: name },
|
||||||
|
native.fn_arg_registers[reg_idx],
|
||||||
|
offset: 8
|
||||||
|
)
|
||||||
|
reg_idx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// define args on stack
|
||||||
|
mut offset := -2
|
||||||
|
for i in stack_args {
|
||||||
|
name := node.params[i].name
|
||||||
|
g.var_offset[name] = offset * 8
|
||||||
|
g.var_alloc_size[name] = args_size[i]
|
||||||
|
offset -= (args_size[i] + 7) / 8
|
||||||
|
}
|
||||||
// define defer vars
|
// define defer vars
|
||||||
for i in 0 .. node.defer_stmts.len {
|
for i in 0 .. node.defer_stmts.len {
|
||||||
name := '_defer$i'
|
name := '_defer$i'
|
||||||
g.allocate_var(name, 8, 0)
|
g.allocate_var(name, 8, 0)
|
||||||
}
|
}
|
||||||
//
|
// body
|
||||||
g.stmts(node.stmts)
|
g.stmts(node.stmts)
|
||||||
// 16 bytes align
|
// 16 bytes align
|
||||||
g.stack_var_pos += 23
|
g.stack_var_pos += 23
|
||||||
@ -2495,6 +2886,99 @@ pub fn (mut g Gen) allocate_var(name string, size int, initial_val int) int {
|
|||||||
return g.stack_var_pos
|
return g.stack_var_pos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) allocate_struct(name string, typ ast.Type) int {
|
||||||
|
if g.pref.arch == .arm64 {
|
||||||
|
// TODO
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
size := g.get_type_size(typ)
|
||||||
|
align := g.get_type_align(typ)
|
||||||
|
padding := (align - g.stack_var_pos % align) % align
|
||||||
|
g.stack_var_pos += size + padding
|
||||||
|
g.var_offset[name] = g.stack_var_pos
|
||||||
|
g.var_alloc_size[name] = size
|
||||||
|
|
||||||
|
return g.stack_var_pos
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) init_struct(var Var, init ast.StructInit) {
|
||||||
|
match var {
|
||||||
|
ast.Ident {
|
||||||
|
var_object := g.get_var_from_ident(var)
|
||||||
|
match var_object {
|
||||||
|
LocalVar {
|
||||||
|
g.init_struct(var_object as LocalVar, init)
|
||||||
|
}
|
||||||
|
GlobalVar {
|
||||||
|
g.init_struct(var_object as GlobalVar, init)
|
||||||
|
}
|
||||||
|
Register {
|
||||||
|
// TODO
|
||||||
|
// g.cmp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LocalVar {
|
||||||
|
size := g.get_type_size(var.typ)
|
||||||
|
|
||||||
|
// zero fill
|
||||||
|
mut left := if size >= 16 {
|
||||||
|
g.mov(.rax, 0)
|
||||||
|
g.mov(.rcx, size / 8)
|
||||||
|
g.lea_var_to_reg(.rdi, var.offset)
|
||||||
|
g.write([u8(0xf3), 0x48, 0xab])
|
||||||
|
g.println('; rep stosq')
|
||||||
|
size % 8
|
||||||
|
} else {
|
||||||
|
size
|
||||||
|
}
|
||||||
|
if left >= 8 {
|
||||||
|
g.mov_int_to_var(var, 0, offset: size - left, typ: ast.i64_type_idx)
|
||||||
|
left -= 8
|
||||||
|
}
|
||||||
|
if left >= 4 {
|
||||||
|
g.mov_int_to_var(var, 0, offset: size - left, typ: ast.int_type_idx)
|
||||||
|
left -= 4
|
||||||
|
}
|
||||||
|
if left >= 2 {
|
||||||
|
g.mov_int_to_var(var, 0, offset: size - left, typ: ast.i16_type_idx)
|
||||||
|
left -= 2
|
||||||
|
}
|
||||||
|
if left == 1 {
|
||||||
|
g.mov_int_to_var(var, 0, offset: size - left, typ: ast.i8_type_idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
ts := g.table.sym(var.typ)
|
||||||
|
match ts.info {
|
||||||
|
ast.Struct {
|
||||||
|
for i, f in ts.info.fields {
|
||||||
|
if f.has_default_expr && !init.fields.map(it.name).contains(f.name) {
|
||||||
|
offset := g.structs[var.typ.idx()].offsets[i]
|
||||||
|
g.expr(f.default_expr)
|
||||||
|
// TODO expr not on rax
|
||||||
|
g.mov_reg_to_var(var, .rax, offset: offset, typ: f.typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
for f in init.fields {
|
||||||
|
field := ts.find_field(f.name) or {
|
||||||
|
g.n_error('Could not find field `$f.name` on init')
|
||||||
|
}
|
||||||
|
offset := g.structs[var.typ.idx()].offsets[field.i]
|
||||||
|
|
||||||
|
g.expr(f.expr)
|
||||||
|
// TODO expr not on rax
|
||||||
|
g.mov_reg_to_var(var, .rax, offset: offset, typ: field.typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GlobalVar {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) convert_int_to_string(r1 Register, r2 Register) {
|
fn (mut g Gen) convert_int_to_string(r1 Register, r2 Register) {
|
||||||
if r1 != .rax {
|
if r1 != .rax {
|
||||||
g.mov_reg(.rax, r1)
|
g.mov_reg(.rax, r1)
|
||||||
|
@ -51,6 +51,7 @@ mut:
|
|||||||
labels &LabelTable
|
labels &LabelTable
|
||||||
defer_stmts []ast.DeferStmt
|
defer_stmts []ast.DeferStmt
|
||||||
builtins map[string]BuiltinFn
|
builtins map[string]BuiltinFn
|
||||||
|
structs []Struct
|
||||||
// macho specific
|
// macho specific
|
||||||
macho_ncmds int
|
macho_ncmds int
|
||||||
macho_cmdsize int
|
macho_cmdsize int
|
||||||
@ -100,6 +101,11 @@ fn (mut l LabelTable) new_label() int {
|
|||||||
return l.label_id
|
return l.label_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Struct {
|
||||||
|
mut:
|
||||||
|
offsets []int
|
||||||
|
}
|
||||||
|
|
||||||
enum Size {
|
enum Size {
|
||||||
_8
|
_8
|
||||||
_16
|
_16
|
||||||
@ -209,10 +215,12 @@ pub fn gen(files []&ast.File, table &ast.Table, out_name string, pref &pref.Pref
|
|||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
labels: 0
|
labels: 0
|
||||||
|
structs: []Struct{len: table.type_symbols.len}
|
||||||
}
|
}
|
||||||
g.code_gen.g = g
|
g.code_gen.g = g
|
||||||
g.generate_header()
|
g.generate_header()
|
||||||
g.init_builtins()
|
g.init_builtins()
|
||||||
|
g.calculate_all_size_align()
|
||||||
for file in files {
|
for file in files {
|
||||||
/*
|
/*
|
||||||
if file.warnings.len > 0 {
|
if file.warnings.len > 0 {
|
||||||
@ -311,6 +319,16 @@ pub fn (mut g Gen) link(obj_name string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut g Gen) calculate_all_size_align() {
|
||||||
|
for mut ts in g.table.type_symbols {
|
||||||
|
if ts.idx == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ts.size = g.get_type_size(ast.new_type(ts.idx))
|
||||||
|
ts.align = g.get_type_align(ast.new_type(ts.idx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) stmts(stmts []ast.Stmt) {
|
pub fn (mut g Gen) stmts(stmts []ast.Stmt) {
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
g.stmt(stmt)
|
g.stmt(stmt)
|
||||||
@ -421,7 +439,18 @@ fn (mut g Gen) get_var_offset(var_name string) int {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) get_field_offset(typ ast.Type, name string) int {
|
||||||
|
ts := g.table.sym(typ)
|
||||||
|
field := ts.find_field(name) or { g.n_error('Could not find field `$name` on init') }
|
||||||
|
return g.structs[typ.idx()].offsets[field.i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// get type size, and calculate size and align and store them to the cache when the type is struct
|
||||||
fn (mut g Gen) get_type_size(typ ast.Type) int {
|
fn (mut g Gen) get_type_size(typ ast.Type) int {
|
||||||
|
// TODO type flags
|
||||||
|
if typ.is_real_pointer() {
|
||||||
|
return 8
|
||||||
|
}
|
||||||
if typ in ast.number_type_idxs {
|
if typ in ast.number_type_idxs {
|
||||||
return match typ {
|
return match typ {
|
||||||
ast.i8_type_idx { 1 }
|
ast.i8_type_idx { 1 }
|
||||||
@ -443,13 +472,51 @@ fn (mut g Gen) get_type_size(typ ast.Type) int {
|
|||||||
else { 8 }
|
else { 8 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if typ in ast.pointer_type_idxs {
|
if typ.is_bool() {
|
||||||
return 8
|
|
||||||
}
|
|
||||||
if typ == ast.bool_type_idx {
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
ts := g.table.sym(typ)
|
||||||
|
if ts.size != -1 {
|
||||||
|
return ts.size
|
||||||
|
}
|
||||||
|
mut size := 0
|
||||||
|
mut align := 1
|
||||||
|
mut strc := Struct{}
|
||||||
|
match ts.info {
|
||||||
|
ast.Struct {
|
||||||
|
for f in ts.info.fields {
|
||||||
|
f_size := g.get_type_size(f.typ)
|
||||||
|
f_align := g.get_type_align(f.typ)
|
||||||
|
padding := (f_align - size % f_align) % f_align
|
||||||
|
strc.offsets << size + padding
|
||||||
|
size += f_size + padding
|
||||||
|
if f_align > align {
|
||||||
|
align = f_align
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size = (size + align - 1) / align * align
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
mut ts_ := g.table.sym(typ)
|
||||||
|
ts_.size = size
|
||||||
|
ts_.align = align
|
||||||
|
g.structs[typ.idx()] = strc
|
||||||
// g.n_error('unknown type size')
|
// g.n_error('unknown type size')
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) get_type_align(typ ast.Type) int {
|
||||||
|
// also calculate align of a struct
|
||||||
|
size := g.get_type_size(typ)
|
||||||
|
if typ in ast.number_type_idxs || typ.is_real_pointer() || typ.is_bool() {
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
ts := g.table.sym(typ)
|
||||||
|
if ts.align != -1 {
|
||||||
|
return ts.align
|
||||||
|
}
|
||||||
|
// g.n_error('unknown type align')
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,17 +619,9 @@ pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, name string) {
|
|||||||
styp := g.typ(expr.struct_type)
|
styp := g.typ(expr.struct_type)
|
||||||
field_name := expr.field
|
field_name := expr.field
|
||||||
if styp.kind == .struct_ {
|
if styp.kind == .struct_ {
|
||||||
s := styp.info as ast.Struct
|
off := g.get_field_offset(expr.struct_type, field_name)
|
||||||
ptrsz := 4 // should be 8, but for locals is used 8 and C backend shows that too
|
g.learel(.rax, g.allocate_string('$off\n', 3, .rel32))
|
||||||
mut off := 0
|
g.gen_print_reg(.rax, 3, fd)
|
||||||
for f in s.fields {
|
|
||||||
if f.name == field_name {
|
|
||||||
g.learel(.rax, g.allocate_string('$off\n', 3, .rel32))
|
|
||||||
g.gen_print_reg(.rax, 3, fd)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
off += ptrsz
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
g.v_error('_offsetof expects a struct Type as first argument', expr.pos)
|
g.v_error('_offsetof expects a struct Type as first argument', expr.pos)
|
||||||
}
|
}
|
||||||
@ -888,22 +947,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||||||
}
|
}
|
||||||
ast.Module {}
|
ast.Module {}
|
||||||
ast.Return {
|
ast.Return {
|
||||||
// dump(node.exprs[0])
|
|
||||||
// if in main
|
|
||||||
// zero := ast.IntegerLiteral{}
|
|
||||||
// g.gen_exit(zero)
|
|
||||||
// dump(node)
|
|
||||||
// dump(node.types)
|
|
||||||
mut s := '?' //${node.exprs[0].val.str()}'
|
mut s := '?' //${node.exprs[0].val.str()}'
|
||||||
// TODO: void return
|
|
||||||
if e0 := node.exprs[0] {
|
if e0 := node.exprs[0] {
|
||||||
match e0 {
|
match e0 {
|
||||||
ast.IntegerLiteral {
|
|
||||||
g.mov64(.rax, e0.val.int())
|
|
||||||
}
|
|
||||||
ast.InfixExpr {
|
|
||||||
g.infix_expr(e0)
|
|
||||||
}
|
|
||||||
ast.CastExpr {
|
ast.CastExpr {
|
||||||
g.mov64(.rax, e0.expr.str().int())
|
g.mov64(.rax, e0.expr.str().int())
|
||||||
// do the job
|
// do the job
|
||||||
@ -913,15 +959,61 @@ fn (mut g Gen) stmt(node ast.Stmt) {
|
|||||||
g.expr(node.exprs[0])
|
g.expr(node.exprs[0])
|
||||||
g.mov64(.rax, g.allocate_string(s, 2, .abs64))
|
g.mov64(.rax, g.allocate_string(s, 2, .abs64))
|
||||||
}
|
}
|
||||||
ast.Ident {
|
else {
|
||||||
g.expr(e0)
|
g.expr(e0)
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
size := g.get_type_size(node.types[0])
|
// store the struct value
|
||||||
if size !in [1, 2, 4, 8] {
|
typ := node.types[0]
|
||||||
g.n_error('unknown return type $e0.type_name()')
|
if !typ.is_real_pointer() && !typ.is_number() && !typ.is_bool() {
|
||||||
|
ts := g.table.sym(typ)
|
||||||
|
size := g.get_type_size(typ)
|
||||||
|
if g.pref.arch == .amd64 {
|
||||||
|
match ts.kind {
|
||||||
|
.struct_ {
|
||||||
|
if size <= 8 {
|
||||||
|
g.mov_deref(.rax, .rax, ast.i64_type_idx)
|
||||||
|
if size != 8 {
|
||||||
|
g.movabs(.rbx, (i64(1) << (size * 8)) - 1)
|
||||||
|
g.bitand_reg(.rax, .rbx)
|
||||||
|
}
|
||||||
|
} else if size <= 16 {
|
||||||
|
g.add(.rax, 8)
|
||||||
|
g.mov_deref(.rdx, .rax, ast.i64_type_idx)
|
||||||
|
g.sub(.rax, 8)
|
||||||
|
g.mov_deref(.rax, .rax, ast.i64_type_idx)
|
||||||
|
if size != 16 {
|
||||||
|
g.movabs(.rbx, (i64(1) << ((size - 8) * 8)) - 1)
|
||||||
|
g.bitand_reg(.rdx, .rbx)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
offset := g.get_var_offset('_return_val_addr')
|
||||||
|
g.mov_var_to_reg(.rdx, LocalVar{
|
||||||
|
offset: offset
|
||||||
|
typ: ast.i64_type_idx
|
||||||
|
})
|
||||||
|
for i in 0 .. size / 8 {
|
||||||
|
g.mov_deref(.rcx, .rax, ast.i64_type_idx)
|
||||||
|
g.mov_store(.rdx, .rcx, ._64)
|
||||||
|
if i != size / 8 - 1 {
|
||||||
|
g.add(.rax, 8)
|
||||||
|
g.add(.rdx, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if size % 8 != 0 {
|
||||||
|
g.add(.rax, size % 8)
|
||||||
|
g.add(.rdx, size % 8)
|
||||||
|
g.mov_deref(.rcx, .rax, ast.i64_type_idx)
|
||||||
|
g.mov_store(.rdx, .rcx, ._64)
|
||||||
|
}
|
||||||
|
g.mov_var_to_reg(.rax, LocalVar{
|
||||||
|
offset: offset
|
||||||
|
typ: ast.i64_type_idx
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {}
|
||||||
}
|
}
|
||||||
g.expr(e0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1028,8 +1120,28 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||||||
}
|
}
|
||||||
ast.FloatLiteral {}
|
ast.FloatLiteral {}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
|
var := g.get_var_from_ident(node)
|
||||||
// XXX this is intel specific
|
// XXX this is intel specific
|
||||||
g.mov_var_to_reg(.rax, node as ast.Ident)
|
match var {
|
||||||
|
LocalVar {
|
||||||
|
if var.typ.is_number() || var.typ.is_real_pointer() || var.typ.is_bool() {
|
||||||
|
g.mov_var_to_reg(.rax, node as ast.Ident)
|
||||||
|
} else {
|
||||||
|
ts := g.table.sym(var.typ)
|
||||||
|
match ts.info {
|
||||||
|
ast.Struct {
|
||||||
|
g.lea_var_to_reg(.rax, g.get_var_offset(node.name))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('Unsupported variable type')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('Unsupported variable kind')
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ast.IfExpr {
|
ast.IfExpr {
|
||||||
if node.is_comptime {
|
if node.is_comptime {
|
||||||
@ -1053,13 +1165,23 @@ fn (mut g Gen) expr(node ast.Expr) {
|
|||||||
ast.StringLiteral {
|
ast.StringLiteral {
|
||||||
g.allocate_string(node.val, 3, .rel32)
|
g.allocate_string(node.val, 3, .rel32)
|
||||||
}
|
}
|
||||||
ast.StructInit {}
|
ast.StructInit {
|
||||||
|
pos := g.allocate_struct('_anonstruct', node.typ)
|
||||||
|
g.init_struct(LocalVar{ offset: pos, typ: node.typ }, node)
|
||||||
|
g.lea_var_to_reg(.rax, pos)
|
||||||
|
}
|
||||||
ast.GoExpr {
|
ast.GoExpr {
|
||||||
g.v_error('native backend doesnt support threads yet', node.pos)
|
g.v_error('native backend doesnt support threads yet', node.pos)
|
||||||
}
|
}
|
||||||
ast.MatchExpr {
|
ast.MatchExpr {
|
||||||
g.gen_match_expr(node)
|
g.gen_match_expr(node)
|
||||||
}
|
}
|
||||||
|
ast.SelectorExpr {
|
||||||
|
g.expr(node.expr)
|
||||||
|
offset := g.get_field_offset(node.expr_type, node.field_name)
|
||||||
|
g.add(.rax, offset)
|
||||||
|
g.mov_deref(.rax, .rax, node.typ)
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
g.n_error('expr: unhandled node type: $node.type_name()')
|
g.n_error('expr: unhandled node type: $node.type_name()')
|
||||||
}
|
}
|
||||||
|
101
vlib/v/gen/native/tests/struct.vv
Normal file
101
vlib/v/gen/native/tests/struct.vv
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
struct Size7 {
|
||||||
|
a i8
|
||||||
|
b u8
|
||||||
|
c i8
|
||||||
|
d i8
|
||||||
|
e u8
|
||||||
|
f i8
|
||||||
|
g u8
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Size8 {
|
||||||
|
a int
|
||||||
|
b i16
|
||||||
|
c i8
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Size12 {
|
||||||
|
a int
|
||||||
|
b int
|
||||||
|
c int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Size16 {
|
||||||
|
a int
|
||||||
|
b i8
|
||||||
|
c i64
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Size28 {
|
||||||
|
a int
|
||||||
|
b i16
|
||||||
|
c int
|
||||||
|
d u32
|
||||||
|
e i8
|
||||||
|
f int
|
||||||
|
g int
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StructWithDefault {
|
||||||
|
a int = 8
|
||||||
|
b int
|
||||||
|
c int = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_7(s Size7) Size7 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_8(s Size8) Size8 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_12(s Size12) Size12 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_16(s Size16) Size16 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_28(s Size28) Size28 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_fn_test() {
|
||||||
|
a := Size7{b: 2}
|
||||||
|
assert get_7(a).b == 2
|
||||||
|
assert get_7(Size7{c: 3}).c == 3
|
||||||
|
b := Size8{b: 2}
|
||||||
|
assert get_8(b).b == 2
|
||||||
|
assert get_8(Size8{c: 3}).c == 3
|
||||||
|
c := Size12{b: 2}
|
||||||
|
assert get_12(c).b == 2
|
||||||
|
assert get_12(Size12{c: 3}).c == 3
|
||||||
|
d := Size16{b: 2}
|
||||||
|
assert get_16(d).b == 2
|
||||||
|
assert get_16(Size16{c: 3}).c == 3
|
||||||
|
e := Size28{b: 2}
|
||||||
|
assert get_28(e).b == 2
|
||||||
|
assert get_28(Size28{c: 3}).c == 3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_test() {
|
||||||
|
a := Size7{1, 2, 3, 4, 5, 6, 7}
|
||||||
|
b := a
|
||||||
|
assert a.c == 3
|
||||||
|
assert b.f == 6
|
||||||
|
c := Size28{d:1, f:2, a:3, c: 4}
|
||||||
|
assert c.a == 3
|
||||||
|
assert c.f == 2
|
||||||
|
assert c.e == 0
|
||||||
|
d := StructWithDefault{b: 2, c: 3}
|
||||||
|
assert d.a == 8
|
||||||
|
assert d.b == 2
|
||||||
|
assert d.c == 3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
struct_test()
|
||||||
|
struct_fn_test()
|
||||||
|
}
|
0
vlib/v/gen/native/tests/struct.vv.out
Normal file
0
vlib/v/gen/native/tests/struct.vv.out
Normal file
Reference in New Issue
Block a user