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

native: inital support for aliased types (#18703)

This commit is contained in:
Spydr 2023-06-29 20:30:48 +02:00 committed by GitHub
parent f122703a43
commit c4ba47a131
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 226 additions and 155 deletions

View File

@ -94,6 +94,10 @@ fn (mut c Amd64) main_reg() Register {
return Amd64Register.rax
}
fn (mut c Amd64) address_size() int {
return 8
}
fn (mut c Amd64) dec(reg Amd64Register) {
c.g.write16(0xff48)
match reg {
@ -593,44 +597,46 @@ fn (mut c Amd64) mov_reg_to_var(var Var, r Register, config VarConfig) {
LocalVar {
offset := var.offset - config.offset
is_far_var := offset > 0x80 || offset < -0x7f
typ := if config.typ == 0 { var.typ } else { config.typ }
raw_type := if config.typ == 0 { var.typ } else { config.typ }
typ := c.g.unwrap(raw_type)
mut size_str := 'UNKNOWN'
is_extended_register := int(reg) >= int(Amd64Register.r8)
&& int(reg) <= int(Amd64Register.r15)
match typ {
ast.i64_type_idx, ast.u64_type_idx, ast.isize_type_idx, ast.usize_type_idx,
ast.int_literal_type_idx {
c.g.write16(0x8948 + if is_extended_register { 4 } else { 0 })
size_str = 'QWORD'
}
ast.int_type_idx, ast.u32_type_idx, ast.rune_type_idx {
if is_extended_register {
c.g.write8(0x44)
}
c.g.write8(0x89)
size_str = 'DWORD'
}
ast.i16_type_idx, ast.u16_type_idx {
c.g.write8(0x66)
if is_extended_register {
c.g.write8(0x44)
}
c.g.write8(0x89)
size_str = 'WORD'
}
ast.i8_type_idx, ast.u8_type_idx, ast.char_type_idx, ast.bool_type_idx {
if is_extended_register {
c.g.write8(0x44)
}
c.g.write8(0x88)
size_str = 'BYTE'
}
else {
if typ.is_any_kind_of_pointer() {
if raw_type.is_any_kind_of_pointer() || typ.is_any_kind_of_pointer() {
c.g.write16(0x8948 + if is_extended_register { 4 } else { 0 })
size_str = 'QWORD'
} else {
match typ {
ast.i64_type_idx, ast.u64_type_idx, ast.isize_type_idx, ast.usize_type_idx,
ast.int_literal_type_idx {
c.g.write16(0x8948 + if is_extended_register { 4 } else { 0 })
size_str = 'QWORD'
} else {
}
ast.int_type_idx, ast.u32_type_idx, ast.rune_type_idx {
if is_extended_register {
c.g.write8(0x44)
}
c.g.write8(0x89)
size_str = 'DWORD'
}
ast.i16_type_idx, ast.u16_type_idx {
c.g.write8(0x66)
if is_extended_register {
c.g.write8(0x44)
}
c.g.write8(0x89)
size_str = 'WORD'
}
ast.i8_type_idx, ast.u8_type_idx, ast.char_type_idx, ast.bool_type_idx {
if is_extended_register {
c.g.write8(0x44)
}
c.g.write8(0x88)
size_str = 'BYTE'
}
else {
ts := c.g.table.sym(typ.idx())
if ts.info is ast.Enum {
if is_extended_register {
@ -639,7 +645,7 @@ fn (mut c Amd64) mov_reg_to_var(var Var, r Register, config VarConfig) {
c.g.write8(0x89)
size_str = 'DWORD'
} else {
c.g.n_error('unsupported type for mov_reg_to_var')
c.g.n_error('unsupported type for mov_reg_to_var ${ts.info}')
}
}
}
@ -685,7 +691,7 @@ fn (mut c Amd64) mov_int_to_var(var Var, integer int, config VarConfig) {
}
LocalVar {
offset := var.offset - config.offset
typ := if config.typ == 0 { var.typ } else { config.typ }
typ := c.g.unwrap(if config.typ == 0 { var.typ } else { config.typ })
is_far_var := offset > 0x80 || offset < -0x7f
match typ {
@ -1338,116 +1344,119 @@ fn (mut c Amd64) lea(reg Amd64Register, val int) {
c.g.println('lea ${reg}, ${val}')
}
fn (mut c Amd64) mov_neg1(reg Amd64Register) {
match reg {
.rax {
c.g.write8(0x48)
c.g.write8(0xc7)
c.g.write8(0xc0)
c.g.write32(-1)
}
.rcx {
c.g.write8(0x48)
c.g.write8(0xc7)
c.g.write8(0xc1)
c.g.write32(-1)
}
else {
c.g.n_error('unhandled mov ${reg}, -1')
}
}
c.g.println('mov ${reg}, -1')
}
fn (mut c Amd64) clear_reg(reg Amd64Register) {
// Optimise to xor reg, reg when val is 0
match reg {
.eax, .rax {
c.g.write8(0x31)
c.g.write8(0xc0)
}
.edi, .rdi {
c.g.write8(0x31)
c.g.write8(0xff)
}
.rcx {
c.g.write8(0x48)
c.g.write8(0x31)
c.g.write8(0xc7)
}
.rdx {
c.g.write8(0x48)
c.g.write8(0x31)
c.g.write8(0xd2)
}
.edx {
c.g.write8(0x31)
c.g.write8(0xd2)
}
.rsi {
c.g.write8(0x48)
c.g.write8(0x31)
c.g.write8(0xf6)
}
.r12 {
c.g.write8(0x4d)
c.g.write8(0x31)
c.g.write8(0xe4)
}
else {
c.g.n_error('unhandled xor ${reg}, ${reg}')
}
}
c.g.println('xor ${reg}, ${reg}')
}
fn (mut c Amd64) mov(r Register, val int) {
reg := r as Amd64Register
if val == -1 {
match reg {
.rax {
c.g.write8(0x48)
c.g.write8(0xc7)
c.g.write8(0xc0)
c.g.write32(-1)
c.g.println('mov ${reg}, ${val}')
}
.rcx {
if val == -1 {
match val {
-1 {
c.mov_neg1(reg)
}
0 {
c.clear_reg(reg)
}
else {
match reg {
.eax, .rax {
c.g.write8(0xb8)
}
.edi, .rdi {
c.g.write8(0xbf)
}
.rcx {
c.g.write8(0x48)
c.g.write8(0xc7)
c.g.write8(0xc1)
c.g.write32(-1)
} else {
c.g.write8(0xff)
c.g.write8(0xff) // mov rcx 0xffff5
}
c.g.println('mov ${reg}, ${val}')
}
else {
c.g.n_error('unhandled mov ${reg}, -1')
.r8 {
c.g.write8(0x41)
c.g.write8(0xb8)
}
.r9 {
c.g.write8(0xb9)
}
.rdx, .edx {
c.g.write8(0xba)
}
.rsi {
// c.g.write8(0x48) // its 32bit!
c.g.write8(0xbe)
}
.r12 {
c.g.write8(0x41)
c.g.write8(0xbc) // r11 is 0xbb etc
}
.rbx {
c.g.write8(0xbb)
}
else {
c.g.n_error('unhandled mov ${reg}')
}
}
c.g.write32(val)
c.g.println('mov ${reg}, ${val}')
}
c.g.println('mov ${reg}, ${val}')
return
}
if val == 0 {
// Optimise to xor reg, reg when val is 0
match reg {
.eax, .rax {
c.g.write8(0x31)
c.g.write8(0xc0)
}
.edi, .rdi {
c.g.write8(0x31)
c.g.write8(0xff)
}
.rcx {
c.g.write8(0x48)
c.g.write8(0x31)
c.g.write8(0xc7)
}
.rdx {
c.g.write8(0x48)
c.g.write8(0x31)
c.g.write8(0xd2)
}
.edx {
c.g.write8(0x31)
c.g.write8(0xd2)
}
.rsi {
c.g.write8(0x48)
c.g.write8(0x31)
c.g.write8(0xf6)
}
.r12 {
c.g.write8(0x4d)
c.g.write8(0x31)
c.g.write8(0xe4)
}
else {
c.g.n_error('unhandled mov ${reg}, ${reg}')
}
}
c.g.println('xor ${reg}, ${reg}')
} else {
match reg {
.eax, .rax {
c.g.write8(0xb8)
}
.edi, .rdi {
c.g.write8(0xbf)
}
.rcx {
c.g.write8(0x48)
c.g.write8(0xc7)
c.g.write8(0xc1)
}
.r8 {
c.g.write8(0x41)
c.g.write8(0xb8)
}
.r9 {
c.g.write8(0xb9)
}
.rdx, .edx {
c.g.write8(0xba)
}
.rsi {
// c.g.write8(0x48) // its 32bit!
c.g.write8(0xbe)
}
.r12 {
c.g.write8(0x41)
c.g.write8(0xbc) // r11 is 0xbb etc
}
.rbx {
c.g.write8(0xbb)
}
else {
c.g.n_error('unhandled mov ${reg}')
}
}
c.g.write32(val)
c.g.println('mov ${reg}, ${val}')
}
}
@ -2005,7 +2014,9 @@ fn (mut c Amd64) assign_struct_var(ident_var IdentVar, typ ast.Type, s int) {
assert size == 0
}
fn (mut c Amd64) assign_var(var IdentVar, typ ast.Type) {
fn (mut c Amd64) assign_var(var IdentVar, raw_type ast.Type) {
typ := c.g.unwrap(raw_type)
info := c.g.table.sym(typ).info
size := c.g.get_type_size(typ)
if typ.is_pure_float() {
match var {
@ -2014,7 +2025,8 @@ fn (mut c Amd64) assign_var(var IdentVar, typ ast.Type) {
// Amd64Register { c.g.mov_ssereg(var as Amd64Register, .xmm0) }
else {}
}
} else if c.g.table.sym(typ).info is ast.Struct && !typ.is_any_kind_of_pointer() {
} else if info is ast.Struct && !typ.is_any_kind_of_pointer()
&& !raw_type.is_any_kind_of_pointer() {
c.assign_struct_var(var, typ, size)
} else if size in [1, 2, 4, 8] {
match var {
@ -2023,7 +2035,7 @@ fn (mut c Amd64) assign_var(var IdentVar, typ ast.Type) {
Register { c.mov_reg(var as Amd64Register, Amd64Register.rax) }
}
} else {
c.g.n_error('error assigning type ${typ} with size ${size}')
c.g.n_error('error assigning type ${typ} with size ${size}: ${info}')
}
}
@ -2361,7 +2373,7 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
}
}
} else if node.exprs.len > 1 {
typ := c.g.return_type
typ := c.g.unwrap(c.g.return_type)
ts := c.g.table.sym(typ)
size := c.g.get_type_size(typ)
// construct a struct variable contains the return value
@ -3385,7 +3397,8 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
}
}
LocalVar {
size := c.g.get_type_size(var.typ)
typ := c.g.unwrap(var.typ)
size := c.g.get_type_size(typ)
// zero fill
mut left := if size >= 16 {
@ -3414,12 +3427,12 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i8_type_idx)
}
ts := c.g.table.sym(var.typ)
ts := c.g.table.sym(typ)
match ts.info {
ast.Struct {
for i, f in ts.info.fields {
if f.has_default_expr && !init.init_fields.map(it.name).contains(f.name) {
offset := c.g.structs[var.typ.idx()].offsets[i]
offset := c.g.structs[typ.idx()].offsets[i]
c.g.expr(f.default_expr)
// TODO expr not on rax
c.mov_reg_to_var(var, Amd64Register.rax, offset: offset, typ: f.typ)
@ -3430,9 +3443,9 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
}
for f in init.init_fields {
field := ts.find_field(f.name) or {
c.g.n_error('Could not find field `${f.name}` on init')
c.g.n_error('Could not find field `${f.name}` on init (${ts.info})')
}
offset := c.g.structs[var.typ.idx()].offsets[field.i]
offset := c.g.structs[typ.idx()].offsets[field.i]
c.g.expr(f.expr)
// TODO expr not on rax
@ -3777,7 +3790,7 @@ fn (mut c Amd64) mov_ssereg_to_var(var Var, reg Amd64SSERegister, config VarConf
LocalVar {
offset := var.offset - config.offset
is_far_var := offset > 0x80 || offset < -0x7f
typ := if config.typ == 0 { var.typ } else { config.typ }
typ := c.g.unwrap(if config.typ == 0 { var.typ } else { config.typ })
far_var_offset := if is_far_var { 0x40 } else { 0 }
c.g.write8(if typ == ast.f32_type_idx { 0xf3 } else { 0xf2 })
@ -3821,7 +3834,7 @@ fn (mut c Amd64) mov_var_to_ssereg(reg Amd64SSERegister, var Var, config VarConf
LocalVar {
offset := var.offset - config.offset
is_far_var := offset > 0x80 || offset < -0x7f
typ := if config.typ == 0 { var.typ } else { config.typ }
typ := c.g.unwrap(if config.typ == 0 { var.typ } else { config.typ })
far_var_offset := if is_far_var { 0x40 } else { 0 }
c.g.write8(if typ == ast.f32_type_idx { 0xf3 } else { 0xf2 })

View File

@ -320,6 +320,10 @@ pub fn (mut c Arm64) gen_arm64_exit(expr ast.Expr) {
c.svc()
}
fn (mut c Arm64) address_size() int {
return 8
}
fn (mut c Arm64) gen_print(s string, fd int) {
panic('Arm64.gen_print() is not implemented')
}

View File

@ -49,7 +49,7 @@ fn (mut g Gen) expr(node ast.Expr) {
} else if var.typ.is_pure_float() {
g.code_gen.load_fp_var(node as ast.Ident)
} else {
ts := g.table.sym(var.typ)
ts := g.table.sym(g.unwrap(var.typ))
match ts.info {
ast.Struct {
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), g.get_var_offset(node.name))

View File

@ -66,6 +66,7 @@ mut:
interface CodeGen {
mut:
g &Gen
address_size() int
adr(r Arm64Register, delta int) // Note: Temporary!
allocate_var(name string, size int, initial_val int) int
apicall(call ApiCall) // winapi calls
@ -237,10 +238,9 @@ fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar {
match obj {
ast.Var {
offset := g.get_var_offset(obj.name)
typ := obj.typ
return LocalVar{
offset: offset
typ: typ
typ: obj.typ
name: obj.name
}
}
@ -609,17 +609,24 @@ fn (mut g Gen) get_var_offset(var_name string) int {
return r
}
fn (mut g Gen) get_field_offset(typ ast.Type, name string) int {
fn (mut g Gen) get_field_offset(in_type ast.Type, name string) int {
typ := g.unwrap(in_type)
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]
}
fn (mut g Gen) unwrap(typ ast.Type) ast.Type {
ts := g.table.sym(typ)
return if ts.info is ast.Alias { g.unwrap(ts.info.parent_type) } else { typ }
}
// 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(raw_type ast.Type) int {
// TODO type flags
if typ.is_any_kind_of_pointer() {
return 8
typ := g.unwrap(raw_type)
if raw_type.is_any_kind_of_pointer() || typ.is_any_kind_of_pointer() {
return g.code_gen.address_size()
}
if typ in ast.number_type_idxs {
return match typ {
@ -699,7 +706,7 @@ fn (mut g Gen) get_type_align(typ ast.Type) int {
if g.is_register_type(typ) || typ.is_pure_float() {
return size
}
ts := g.table.sym(typ)
ts := g.table.sym(g.unwrap(typ))
if ts.align != -1 {
return ts.align
}

View File

@ -93,6 +93,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
ast.Import {} // do nothing here
ast.StructDecl {}
ast.EnumDecl {}
ast.TypeDecl {}
else {
eprintln('native.stmt(): bad node: ' + node.type_name())
}

View File

@ -58,6 +58,52 @@ fn struct_test() {
assert e.a == 3
}
type AliasedStruct = Mutable
type AliasedPointer = &Mutable
fn alias_test() {
mut a := AliasedStruct{1}
a.a = 2
assert a.a == 2
mut b := &a
b.a = 3
assert a.a == 3
c := AliasedPointer{2}
assert c.a == 2
}
fn init_size28() Size28 {
return Size28{1, 2, 3, 4, 5, 6, 7}
}
type AliasedSize28 = Size28
fn init_aliased() AliasedSize28 {
return AliasedSize28{1, 2, 3, 4, 5, 6, 7}
}
fn return_test() {
a := init_size28()
assert a.a == 1
assert a.b == 2
assert a.c == 3
assert a.d == 4
assert a.e == 5
assert a.f == 6
assert a.g == 7
b := init_aliased()
assert b.a == 1
assert b.b == 2
assert b.c == 3
assert b.d == 4
assert b.e == 5
assert b.f == 6
assert b.g == 7
}
fn main() {
struct_test()
return_test()
alias_test()
}