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
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)
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 + if is_extended_register { 4 } else { 0 })
size = 'QWORD'
size_str = 'QWORD'
}
ast.int_type_idx, ast.u32_type_idx, ast.rune_type_idx {
if is_extended_register {
g.write8(0x44)
}
g.write8(0x89)
size = 'DWORD'
size_str = 'DWORD'
}
ast.i16_type_idx, ast.u16_type_idx {
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(0x89)
size = 'WORD'
size_str = 'WORD'
}
ast.i8_type_idx, ast.u8_type_idx, ast.char_type_idx, ast.bool_type_idx {
if is_extended_register {
g.write8(0x44)
}
g.write8(0x88)
size = 'BYTE'
size_str = 'BYTE'
}
else {
g.n_error('unsupported type for mov_reg_to_var')
'UNKNOWN'
}
}
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 {
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 {
// TODO
@ -736,47 +735,44 @@ fn (mut g Gen) mov_var_to_reg(reg Register, var Var, config VarConfig) {
offset := var.offset - config.offset
is_far_var := offset > 0x80 || offset < -0x7f
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 {
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 {
instruction, size_str := match true {
size == 4 && is_signed {
// movsxd rax, DWORD PTR [rbp-0x8]
g.write16(0x6348)
'movsxd', 'DWORD'
}
ast.u32_type_idx, ast.rune_type_idx {
size == 4 && !is_signed {
// mov eax, DWORD PTR [rbp-0x8]
g.write8(0x8b)
'mov', 'DWORD'
}
ast.i16_type_idx {
size == 2 && is_signed {
// movsx rax, WORD PTR [rbp-0x8]
g.write([u8(0x48), 0x0f, 0xbf])
'movsx', 'WORD'
}
ast.u16_type_idx {
size == 2 && !is_signed {
// movzx rax, WORD PTR [rbp-0x8]
g.write([u8(0x48), 0x0f, 0xb7])
'movzx', 'WORD'
}
ast.i8_type_idx {
size == 1 && is_signed {
// movsx rax, BYTE PTR [rbp-0x8]
g.write([u8(0x48), 0x0f, 0xbe])
'movsx', 'BYTE'
}
ast.u8_type_idx, ast.char_type_idx, ast.bool_type_idx {
size == 1 && !is_signed {
// 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'
// mov rax, QWORD PTR [rbp-0x8]
g.write16(0x8b48)
'mov', 'QWORD'
}
}
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 {
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 {
// TODO
@ -1559,24 +1555,47 @@ pub fn (mut g Gen) call_fn_amd64(node ast.CallExpr) {
if !n.contains('.') {
n = 'main.$n'
}
if node.is_method {
n = '${g.table.get_type_name(node.receiver_type)}.$node.name'
}
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))
mut args := []ast.CallArg{cap: node.args.len + 2}
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
mut is_struct_return := false
if ts.kind == .struct_ {
return_pos = g.allocate_struct('', node.return_type)
if return_size > 16 {
reg_args << struct_arg_idx
args_size << 8
is_struct_return = true
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
for i, size in args_size {
if reg_left > 0 {
@ -1607,13 +1626,13 @@ pub fn (mut g Gen) call_fn_amd64(node ast.CallExpr) {
}
reg_args << stack_args
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.push(.rax)
continue
}
g.expr(node.args[i].expr)
if g.table.sym(node.args[i].typ).kind == .struct_ {
g.expr(args[i].expr)
if g.table.sym(args[i].typ).kind == .struct_ && !args[i].typ.is_ptr() {
match args_size[i] {
1...8 {
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])
}
if addr == 0 {
g.delay_fn_call(name)
g.delay_fn_call(n)
g.call(int(0))
} else {
g.call(int(addr))
}
g.println('call `${name}()`')
g.println('call `${n}()`')
if ts.kind == .struct_ {
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) {
/*
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)
mut reg_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)
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 return_size > 16 {
return_val_offset = g.allocate_var('_return_val_addr', 8, 0)
reg_args << struct_arg_idx
args_size << 8
params << ast.Param{
name: '_return_val_addr'
typ: ast.voidptr_type_idx
}
}
}
params << node.params
args_size := params.map(g.get_type_size(it.typ))
mut reg_left := 6
for i, size in args_size {
if reg_left > 0 {
@ -2731,24 +2772,13 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
}
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)
}
name := params[i].name
g.stack_var_pos += (8 - args_size[i] % 8) % 8
offset := g.allocate_struct(name, 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])
@ -2764,7 +2794,7 @@ fn (mut g Gen) fn_decl_amd64(node ast.FnDecl) {
// define args on stack
mut offset := -2
for i in stack_args {
name := node.params[i].name
name := params[i].name
g.var_offset[name] = offset * 8
g.var_alloc_size[name] = args_size[i]
offset -= (args_size[i] + 7) / 8

View File

@ -709,17 +709,22 @@ g.expr
}
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 {
println(term.green('\n$node.name:'))
println(term.green('\n$name:'))
}
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 {
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.register_function_address(node.name)
g.register_function_address(name)
g.labels = &LabelTable{}
g.defer_stmts.clear()
if g.pref.arch == .arm64 {
@ -1162,6 +1167,9 @@ fn (mut g Gen) expr(node ast.Expr) {
ast.PostfixExpr {
g.postfix_expr(node)
}
ast.PrefixExpr {
g.prefix_expr(node)
}
ast.StringLiteral {
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