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
|
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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
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