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:
parent
f122703a43
commit
c4ba47a131
@ -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 })
|
||||
|
@ -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')
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user