mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
native: structs multi_assign and multi_return (#25281)
This commit is contained in:
parent
a10c59704b
commit
b653d65676
2 changed files with 78 additions and 5 deletions
|
@ -953,7 +953,7 @@ fn (mut c Amd64) lea_var_to_reg(r Register, var_offset i32) {
|
||||||
|
|
||||||
is_far_var := var_offset > 0x80 || var_offset < -0x7f
|
is_far_var := var_offset > 0x80 || var_offset < -0x7f
|
||||||
match reg {
|
match reg {
|
||||||
.rax, .rbx, .rsi, .rdi {
|
.rax, .rbx, .rsi, .rdi, .rdx, .rcx {
|
||||||
c.g.write8(0x48)
|
c.g.write8(0x48)
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
|
@ -2753,6 +2753,7 @@ fn (mut c Amd64) gen_type_promotion(from ast.Type, to ast.Type, option Amd64Regi
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Amd64) return_stmt(node ast.Return) {
|
fn (mut c Amd64) return_stmt(node ast.Return) {
|
||||||
|
c.g.println('; return statement {')
|
||||||
mut s := '?' //${node.exprs[0].val.str()}'
|
mut s := '?' //${node.exprs[0].val.str()}'
|
||||||
if node.exprs.len == 1 {
|
if node.exprs.len == 1 {
|
||||||
match node.exprs[0] {
|
match node.exprs[0] {
|
||||||
|
@ -2812,6 +2813,8 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
|
||||||
c.add(Amd64Register.rax, size % 8)
|
c.add(Amd64Register.rax, size % 8)
|
||||||
c.add(Amd64Register.rdx, size % 8)
|
c.add(Amd64Register.rdx, size % 8)
|
||||||
c.mov_deref(Amd64Register.rcx, Amd64Register.rax, ast.i64_type_idx)
|
c.mov_deref(Amd64Register.rcx, Amd64Register.rax, ast.i64_type_idx)
|
||||||
|
// TODO: check if it does not write too far as the size of
|
||||||
|
// the remaining data is not 64bits
|
||||||
c.mov_store(.rdx, .rcx, ._64)
|
c.mov_store(.rdx, .rcx, ._64)
|
||||||
}
|
}
|
||||||
c.mov_var_to_reg(c.main_reg(), LocalVar{
|
c.mov_var_to_reg(c.main_reg(), LocalVar{
|
||||||
|
@ -2841,7 +2844,14 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
|
||||||
offset := c.g.structs[typ.idx()].offsets[i]
|
offset := c.g.structs[typ.idx()].offsets[i]
|
||||||
c.g.expr(expr)
|
c.g.expr(expr)
|
||||||
// TODO: expr not on rax
|
// TODO: expr not on rax
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax, offset: offset, typ: ts.mr_info().types[i])
|
e_typ := ts.mr_info().types[i]
|
||||||
|
e_ts := c.g.table.sym(e_typ)
|
||||||
|
if e_ts.info is ast.Struct {
|
||||||
|
c.lea_var_to_reg(Amd64Register.rdx, var.offset - offset)
|
||||||
|
c.move_struct(.rdx, .rax, c.g.get_type_size(e_typ))
|
||||||
|
} else {
|
||||||
|
c.mov_reg_to_var(var, Amd64Register.rax, offset: offset, typ: ts.mr_info().types[i])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// store the multi return struct value
|
// store the multi return struct value
|
||||||
c.lea_var_to_reg(Amd64Register.rax, var.offset)
|
c.lea_var_to_reg(Amd64Register.rax, var.offset)
|
||||||
|
@ -2897,6 +2907,7 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
|
||||||
pos: pos
|
pos: pos
|
||||||
}
|
}
|
||||||
c.g.println('; jump to label ${label}')
|
c.g.println('; jump to label ${label}')
|
||||||
|
c.g.println('; return statement }')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
|
fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
|
||||||
|
@ -2926,7 +2937,7 @@ fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
|
||||||
} else {
|
} else {
|
||||||
c.g.expr(node.right[0])
|
c.g.expr(node.right[0])
|
||||||
}
|
}
|
||||||
c.mov_reg(Amd64Register.rdx, Amd64Register.rax)
|
c.mov_reg(Amd64Register.rdx, Amd64Register.rax) // value of right expr(s)
|
||||||
|
|
||||||
mut current_offset := i32(0)
|
mut current_offset := i32(0)
|
||||||
for i, offset in multi_return.offsets {
|
for i, offset in multi_return.offsets {
|
||||||
|
@ -2943,7 +2954,7 @@ fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
|
||||||
c.add(Amd64Register.rdx, offset - current_offset)
|
c.add(Amd64Register.rdx, offset - current_offset)
|
||||||
current_offset = offset
|
current_offset = offset
|
||||||
}
|
}
|
||||||
c.g.gen_left_value(node.left[i])
|
c.g.gen_left_value(node.left[i]) // in rax
|
||||||
left_type := node.left_types[i]
|
left_type := node.left_types[i]
|
||||||
right_type := node.right_types[i]
|
right_type := node.right_types[i]
|
||||||
if c.g.is_register_type(right_type) {
|
if c.g.is_register_type(right_type) {
|
||||||
|
@ -3001,11 +3012,36 @@ fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
|
||||||
c.g.println('movsd [rax], xmm0')
|
c.g.println('movsd [rax], xmm0')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.g.n_error('${@LOCATION} multi return for struct is not supported yet')
|
c.move_struct(.rax, .rdx, c.g.get_type_size(left_type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Moves a struct of size `_size` (in bytes) from the address stored in input to the address stored in output
|
||||||
|
fn (mut c Amd64) move_struct(output Amd64Register, input Amd64Register, _size i32) {
|
||||||
|
mut size := _size
|
||||||
|
for size != 0 {
|
||||||
|
c.mov_deref(Amd64Register.rcx, input, ast.i64_type_idx)
|
||||||
|
// mov_store can only move powers of 2 bytes at once
|
||||||
|
// the remainder will then get handled the next iteration for simplicity
|
||||||
|
data_size := i32(match true {
|
||||||
|
size < 2 { 1 }
|
||||||
|
size < 4 { 2 }
|
||||||
|
size < 8 { 4 }
|
||||||
|
else { 8 }
|
||||||
|
})
|
||||||
|
c.mov_store(output, .rcx, match data_size {
|
||||||
|
1 { ._8 }
|
||||||
|
2 { ._16 }
|
||||||
|
4 { ._32 }
|
||||||
|
else { ._64 }
|
||||||
|
})
|
||||||
|
size -= data_size
|
||||||
|
c.add(output, data_size)
|
||||||
|
c.add(input, data_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
|
fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
|
||||||
// `a, b := foo()`
|
// `a, b := foo()`
|
||||||
// `a, b := if cond { 1, 2 } else { 3, 4 }`
|
// `a, b := if cond { 1, 2 } else { 3, 4 }`
|
||||||
|
|
|
@ -61,7 +61,44 @@ fn cross_assign_of_struct_test() { // from cross_assign_test.v
|
||||||
assert x.b == 1
|
assert x.b == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MyStruct {
|
||||||
|
a int
|
||||||
|
b u64
|
||||||
|
c u16
|
||||||
|
d u8
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyStruct2 {
|
||||||
|
a u8
|
||||||
|
b u8
|
||||||
|
c u8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_multi_return() (int, MyStruct) {
|
||||||
|
return 3, MyStruct{4, 5, 6, 7}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_multi_return2() (int, MyStruct2) {
|
||||||
|
return 3, MyStruct2{4, 5, 6}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_multi_return_test() {
|
||||||
|
a, b := struct_multi_return()
|
||||||
|
assert a == 3
|
||||||
|
assert b.a == 4
|
||||||
|
assert b.b == 5
|
||||||
|
assert b.c == 6
|
||||||
|
assert b.d == 7
|
||||||
|
|
||||||
|
c, d := struct_multi_return2()
|
||||||
|
assert c == 3
|
||||||
|
assert d.a == 4
|
||||||
|
assert d.b == 5
|
||||||
|
assert d.c == 6
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
fn_multi_return_test()
|
fn_multi_return_test()
|
||||||
cross_assign_of_struct_test()
|
cross_assign_of_struct_test()
|
||||||
|
struct_multi_return_test()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue