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

native: support method definition and call (#15736)

This commit is contained in:
lemon 2022-09-16 22:31:05 +09:00 committed by GitHub
parent 0e49ce427e
commit 7f30519544
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 145 additions and 57 deletions

View File

@ -553,20 +553,20 @@ fn (mut g Gen) mov_reg_to_var(var Var, reg Register, config VarConfig) {
is_far_var := offset > 0x80 || offset < -0x7f is_far_var := offset > 0x80 || offset < -0x7f
typ := if config.typ == 0 { var.typ } else { config.typ } typ := if config.typ == 0 { var.typ } else { config.typ }
mut size := 'UNKNOWN' mut size_str := 'UNKNOWN'
is_extended_register := int(reg) >= int(Register.r8) && int(reg) <= int(Register.r15) is_extended_register := int(reg) >= int(Register.r8) && int(reg) <= int(Register.r15)
match typ { match typ {
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.write16(0x8948 + if is_extended_register { 4 } else { 0 }) g.write16(0x8948 + if is_extended_register { 4 } else { 0 })
size = 'QWORD' size_str = 'QWORD'
} }
ast.int_type_idx, ast.u32_type_idx, ast.rune_type_idx { ast.int_type_idx, ast.u32_type_idx, ast.rune_type_idx {
if is_extended_register { if is_extended_register {
g.write8(0x44) g.write8(0x44)
} }
g.write8(0x89) g.write8(0x89)
size = 'DWORD' size_str = 'DWORD'
} }
ast.i16_type_idx, ast.u16_type_idx { ast.i16_type_idx, ast.u16_type_idx {
g.write8(0x66) g.write8(0x66)
@ -574,18 +574,17 @@ fn (mut g Gen) mov_reg_to_var(var Var, reg Register, config VarConfig) {
g.write8(0x44) g.write8(0x44)
} }
g.write8(0x89) g.write8(0x89)
size = 'WORD' size_str = 'WORD'
} }
ast.i8_type_idx, ast.u8_type_idx, ast.char_type_idx, ast.bool_type_idx { ast.i8_type_idx, ast.u8_type_idx, ast.char_type_idx, ast.bool_type_idx {
if is_extended_register { if is_extended_register {
g.write8(0x44) g.write8(0x44)
} }
g.write8(0x88) g.write8(0x88)
size = 'BYTE' size_str = 'BYTE'
} }
else { else {
g.n_error('unsupported type for mov_reg_to_var') g.n_error('unsupported type for mov_reg_to_var')
'UNKNOWN'
} }
} }
far_var_offset := if is_far_var { 0x40 } else { 0 } far_var_offset := if is_far_var { 0x40 } else { 0 }
@ -602,7 +601,7 @@ fn (mut g Gen) mov_reg_to_var(var Var, reg Register, config VarConfig) {
} else { } else {
g.write8((0xff - offset + 1) % 0x100) g.write8((0xff - offset + 1) % 0x100)
} }
g.println('mov $size PTR [rbp-$offset.hex2()],$reg') g.println('mov $size_str PTR [rbp-$offset.hex2()],$reg')
} }
GlobalVar { GlobalVar {
// TODO // TODO
@ -736,47 +735,44 @@ fn (mut g Gen) mov_var_to_reg(reg Register, var Var, config VarConfig) {
offset := var.offset - config.offset offset := var.offset - config.offset
is_far_var := offset > 0x80 || offset < -0x7f is_far_var := offset > 0x80 || offset < -0x7f
typ := if config.typ == 0 { var.typ } else { config.typ } typ := if config.typ == 0 { var.typ } else { config.typ }
size := g.get_type_size(typ)
is_signed := !typ.is_real_pointer() && typ.is_signed()
instruction, size := match typ { instruction, size_str := match true {
ast.i64_type_idx, ast.u64_type_idx, ast.isize_type_idx, ast.usize_type_idx, size == 4 && is_signed {
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] // movsxd rax, DWORD PTR [rbp-0x8]
g.write16(0x6348) g.write16(0x6348)
'movsxd', 'DWORD' 'movsxd', 'DWORD'
} }
ast.u32_type_idx, ast.rune_type_idx { size == 4 && !is_signed {
// mov eax, DWORD PTR [rbp-0x8] // mov eax, DWORD PTR [rbp-0x8]
g.write8(0x8b) g.write8(0x8b)
'mov', 'DWORD' 'mov', 'DWORD'
} }
ast.i16_type_idx { size == 2 && is_signed {
// movsx rax, WORD PTR [rbp-0x8] // movsx rax, WORD PTR [rbp-0x8]
g.write([u8(0x48), 0x0f, 0xbf]) g.write([u8(0x48), 0x0f, 0xbf])
'movsx', 'WORD' 'movsx', 'WORD'
} }
ast.u16_type_idx { size == 2 && !is_signed {
// movzx rax, WORD PTR [rbp-0x8] // movzx rax, WORD PTR [rbp-0x8]
g.write([u8(0x48), 0x0f, 0xb7]) g.write([u8(0x48), 0x0f, 0xb7])
'movzx', 'WORD' 'movzx', 'WORD'
} }
ast.i8_type_idx { size == 1 && is_signed {
// movsx rax, BYTE PTR [rbp-0x8] // movsx rax, BYTE PTR [rbp-0x8]
g.write([u8(0x48), 0x0f, 0xbe]) g.write([u8(0x48), 0x0f, 0xbe])
'movsx', 'BYTE' 'movsx', 'BYTE'
} }
ast.u8_type_idx, ast.char_type_idx, ast.bool_type_idx { size == 1 && !is_signed {
// movzx rax, BYTE PTR [rbp-0x8] // movzx rax, BYTE PTR [rbp-0x8]
g.write([u8(0x48), 0x0f, 0xb6]) g.write([u8(0x48), 0x0f, 0xb6])
'movzx', 'BYTE' 'movzx', 'BYTE'
} }
else { else {
g.n_error('unhandled mov var to reg') // mov rax, QWORD PTR [rbp-0x8]
'mov', 'UNKNOWN' g.write16(0x8b48)
'mov', 'QWORD'
} }
} }
far_var_offset := if is_far_var { 0x40 } else { 0 } far_var_offset := if is_far_var { 0x40 } else { 0 }
@ -794,7 +790,7 @@ fn (mut g Gen) mov_var_to_reg(reg Register, var Var, config VarConfig) {
} else { } else {
g.write8((0xff - offset + 1) % 0x100) g.write8((0xff - offset + 1) % 0x100)
} }
g.println('$instruction $reg, $size PTR [rbp-$offset.hex2()]') g.println('$instruction $reg, $size_str PTR [rbp-$offset.hex2()]')
} }
GlobalVar { GlobalVar {
// TODO // TODO
@ -1559,24 +1555,47 @@ pub fn (mut g Gen) call_fn_amd64(node ast.CallExpr) {
if !n.contains('.') { if !n.contains('.') {
n = 'main.$n' n = 'main.$n'
} }
if node.is_method {
n = '${g.table.get_type_name(node.receiver_type)}.$node.name'
}
addr := g.fn_addr[n] addr := g.fn_addr[n]
mut reg_args := []int{} mut reg_args := []int{}
mut stack_args := []int{} mut stack_args := []int{}
mut args_size := node.args.map(g.get_type_size(it.typ)) mut args := []ast.CallArg{cap: node.args.len + 2}
ts := g.table.sym(node.return_type) ts := g.table.sym(node.return_type)
return_size := g.get_type_size(node.return_type) return_size := g.get_type_size(node.return_type)
mut return_pos := -1 mut return_pos := -1
struct_arg_idx := node.args.len mut is_struct_return := false
if ts.kind == .struct_ { if ts.kind == .struct_ {
return_pos = g.allocate_struct('', node.return_type) return_pos = g.allocate_struct('', node.return_type)
if return_size > 16 { if return_size > 16 {
reg_args << struct_arg_idx is_struct_return = true
args_size << 8 args << ast.CallArg{
typ: ast.voidptr_type_idx
}
} }
} }
if node.is_method {
expr := if !node.left_type.is_ptr() && node.receiver_type.is_ptr() {
ast.Expr(ast.PrefixExpr{
op: .amp
right: node.left
})
} else {
node.left
}
args << ast.CallArg{
expr: expr
typ: node.receiver_type
}
}
args << node.args
args_size := args.map(g.get_type_size(it.typ))
mut reg_left := 6 - reg_args.len mut reg_left := 6 - reg_args.len
for i, size in args_size { for i, size in args_size {
if reg_left > 0 { if reg_left > 0 {
@ -1607,13 +1626,13 @@ pub fn (mut g Gen) call_fn_amd64(node ast.CallExpr) {
} }
reg_args << stack_args reg_args << stack_args
for i in reg_args.reverse() { for i in reg_args.reverse() {
if i == struct_arg_idx { if i == 0 && is_struct_return {
g.lea_var_to_reg(.rax, return_pos) g.lea_var_to_reg(.rax, return_pos)
g.push(.rax) g.push(.rax)
continue continue
} }
g.expr(node.args[i].expr) g.expr(args[i].expr)
if g.table.sym(node.args[i].typ).kind == .struct_ { if g.table.sym(args[i].typ).kind == .struct_ && !args[i].typ.is_ptr() {
match args_size[i] { match args_size[i] {
1...8 { 1...8 {
g.mov_deref(.rax, .rax, ast.i64_type_idx) g.mov_deref(.rax, .rax, ast.i64_type_idx)
@ -1657,12 +1676,12 @@ pub fn (mut g Gen) call_fn_amd64(node ast.CallExpr) {
g.pop(native.fn_arg_registers[i]) g.pop(native.fn_arg_registers[i])
} }
if addr == 0 { if addr == 0 {
g.delay_fn_call(name) g.delay_fn_call(n)
g.call(int(0)) g.call(int(0))
} else { } else {
g.call(int(addr)) g.call(int(addr))
} }
g.println('call `${name}()`') g.println('call `${n}()`')
if ts.kind == .struct_ { if ts.kind == .struct_ {
match return_size { match return_size {
@ -2176,6 +2195,24 @@ fn (mut g Gen) cset_op(op token.Kind) {
} }
} }
fn (mut g Gen) gen_left_value(node ast.Expr) {
match node {
ast.Ident {
offset := g.get_var_offset(node.name)
g.lea_var_to_reg(.rax, offset)
}
else {
g.n_error('Unsupported left value')
}
}
}
fn (mut g Gen) prefix_expr(node ast.PrefixExpr) {
if node.op == .amp {
g.gen_left_value(node.right)
}
}
fn (mut g Gen) infix_expr(node ast.InfixExpr) { fn (mut g Gen) infix_expr(node ast.InfixExpr) {
/* /*
if node.left is ast.Ident && node.right is ast.Ident { if node.left is ast.Ident && node.right is ast.Ident {
@ -2702,20 +2739,24 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
// Copy values from registers to local vars (calling convention) // Copy values from registers to local vars (calling convention)
mut reg_args := []int{} mut reg_args := []int{}
mut stack_args := []int{} mut stack_args := []int{}
mut args_size := node.params.map(g.get_type_size(it.typ)) mut params := []ast.Param{cap: node.params.len + 2}
// The first parameter is an address of returned struct if size > 16
ts := g.table.sym(node.return_type) ts := g.table.sym(node.return_type)
return_size := g.get_type_size(node.return_type) return_size := g.get_type_size(node.return_type)
struct_arg_idx := node.params.len
mut return_val_offset := -1
if ts.kind == .struct_ { if ts.kind == .struct_ {
if return_size > 16 { if return_size > 16 {
return_val_offset = g.allocate_var('_return_val_addr', 8, 0) params << ast.Param{
reg_args << struct_arg_idx name: '_return_val_addr'
args_size << 8 typ: ast.voidptr_type_idx
}
} }
} }
params << node.params
args_size := params.map(g.get_type_size(it.typ))
mut reg_left := 6 mut reg_left := 6
for i, size in args_size { for i, size in args_size {
if reg_left > 0 { if reg_left > 0 {
@ -2731,24 +2772,13 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
} }
stack_args << i 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 // define and copy args on register
mut reg_idx := 0 mut reg_idx := 0
for i in reg_args { for i in reg_args {
name := if i == struct_arg_idx { '_return_val_addr' } else { node.params[i].name } name := params[i].name
g.stack_var_pos += args_size[i] % 8 g.stack_var_pos += (8 - args_size[i] % 8) % 8
offset := if i == struct_arg_idx { offset := g.allocate_struct(name, params[i].typ)
return_val_offset
} else {
g.allocate_struct(name, node.params[i].typ)
}
// copy // copy
g.mov_reg_to_var(LocalVar{ offset: offset, typ: ast.i64_type_idx, name: name }, g.mov_reg_to_var(LocalVar{ offset: offset, typ: ast.i64_type_idx, name: name },
native.fn_arg_registers[reg_idx]) native.fn_arg_registers[reg_idx])
@ -2764,7 +2794,7 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
// define args on stack // define args on stack
mut offset := -2 mut offset := -2
for i in stack_args { for i in stack_args {
name := node.params[i].name name := params[i].name
g.var_offset[name] = offset * 8 g.var_offset[name] = offset * 8
g.var_alloc_size[name] = args_size[i] g.var_alloc_size[name] = args_size[i]
offset -= (args_size[i] + 7) / 8 offset -= (args_size[i] + 7) / 8

View File

@ -709,17 +709,22 @@ g.expr
} }
fn (mut g Gen) fn_decl(node ast.FnDecl) { fn (mut g Gen) fn_decl(node ast.FnDecl) {
name := if node.is_method {
'${g.table.get_type_name(node.receiver.typ)}.$node.name'
} else {
node.name
}
if g.pref.is_verbose { if g.pref.is_verbose {
println(term.green('\n$node.name:')) println(term.green('\n$name:'))
} }
if node.is_deprecated { if node.is_deprecated {
g.warning('fn_decl: $node.name is deprecated', node.pos) g.warning('fn_decl: $name is deprecated', node.pos)
} }
if node.is_builtin { if node.is_builtin {
g.warning('fn_decl: $node.name is builtin', node.pos) g.warning('fn_decl: $name is builtin', node.pos)
} }
g.stack_var_pos = 0 g.stack_var_pos = 0
g.register_function_address(node.name) g.register_function_address(name)
g.labels = &LabelTable{} g.labels = &LabelTable{}
g.defer_stmts.clear() g.defer_stmts.clear()
if g.pref.arch == .arm64 { if g.pref.arch == .arm64 {
@ -1162,6 +1167,9 @@ fn (mut g Gen) expr(node ast.Expr) {
ast.PostfixExpr { ast.PostfixExpr {
g.postfix_expr(node) g.postfix_expr(node)
} }
ast.PrefixExpr {
g.prefix_expr(node)
}
ast.StringLiteral { ast.StringLiteral {
g.allocate_string(node.val, 3, .rel32) g.allocate_string(node.val, 3, .rel32)
} }

View File

@ -0,0 +1,50 @@
struct Size7 {
a i8
b u8
c i8
d i8
e u8
f i8
g u8
}
struct Size28 {
a int
b i16
c int
d u32
e i8
f int
g int
}
fn (s Size7) get_c() i8 {
return s.c
}
fn (s &Size7) get_c_ref() i8 {
return s.c
}
fn (mut s Size7) modify_c(a i8) i8 {
// s.c = a
return s.c
}
fn struct_receiver_test() {
mut a := Size7{1,2,3,4,5,6,7}
assert a.get_c() == 3
assert a.get_c_ref() == 3
// should be 7 after implementing field assign
assert a.modify_c(7) == 3
b := Size28{c: 6}
assert b.get_c() == 6
}
fn (s Size28) get_c() int {
return s.c
}
fn main() {
struct_receiver_test()
}

View File