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:
parent
0e49ce427e
commit
7f30519544
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
50
vlib/v/gen/native/tests/method.vv
Normal file
50
vlib/v/gen/native/tests/method.vv
Normal 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()
|
||||
}
|
0
vlib/v/gen/native/tests/method.vv.out
Normal file
0
vlib/v/gen/native/tests/method.vv.out
Normal file
Loading…
Reference in New Issue
Block a user