From a7ad64033eef81575de73595ae4027b79e403d1c Mon Sep 17 00:00:00 2001 From: lemon Date: Sat, 1 Oct 2022 20:42:26 +0900 Subject: [PATCH] native: support assigning to struct fields (#15938) --- vlib/v/gen/native/amd64.v | 151 ++++++++++++++++-- vlib/v/gen/native/gen.v | 3 + vlib/v/gen/native/tests/expressions.vv | 10 ++ vlib/v/gen/native/tests/method.vv | 6 +- vlib/v/gen/native/tests/struct.vv | 64 ++------ vlib/v/gen/native/tests/struct_with_fn.vv | 79 +++++++++ vlib/v/gen/native/tests/struct_with_fn.vv.out | 0 7 files changed, 243 insertions(+), 70 deletions(-) create mode 100644 vlib/v/gen/native/tests/struct_with_fn.vv create mode 100644 vlib/v/gen/native/tests/struct_with_fn.vv.out diff --git a/vlib/v/gen/native/amd64.v b/vlib/v/gen/native/amd64.v index 0fd17cbbc0..7c2b05db83 100644 --- a/vlib/v/gen/native/amd64.v +++ b/vlib/v/gen/native/amd64.v @@ -584,15 +584,20 @@ fn (mut g Gen) mov_reg_to_var(var Var, reg Register, config VarConfig) { size_str = 'BYTE' } else { - ts := g.table.sym(typ.idx()) - if ts.info is ast.Enum { - if is_extended_register { - g.write8(0x44) - } - g.write8(0x89) - size_str = 'DWORD' + if typ.is_real_pointer() { + g.write16(0x8948 + if is_extended_register { 4 } else { 0 }) + size_str = 'QWORD' } else { - g.n_error('unsupported type for mov_reg_to_var') + ts := g.table.sym(typ.idx()) + if ts.info is ast.Enum { + if is_extended_register { + g.write8(0x44) + } + g.write8(0x89) + size_str = 'DWORD' + } else { + g.n_error('unsupported type for mov_reg_to_var') + } } } } @@ -1021,6 +1026,13 @@ fn (mut g Gen) bitxor_reg(a Register, b Register) { g.println('xor $a, $b') } +fn (mut g Gen) bitnot_reg(a Register) { + g.write8(0x48 + if int(a) >= int(Register.r8) { 1 } else { 0 }) + g.write8(0xf7) + g.write8(0xd0 + int(a) % 8) + g.println('not $a') +} + fn (mut g Gen) shl_reg(a Register, b Register) { if b != .rcx { g.mov_reg(.rcx, b) @@ -1822,8 +1834,86 @@ fn (mut g Gen) assign_stmt(node ast.AssignStmt) { // `a := 1` | `a,b := 1,2` for i, left in node.left { right := node.right[i] + if left !is ast.Ident { + g.gen_left_value(left) + g.push(.rax) + g.expr(right) + g.pop(.rdx) + typ := node.left_types[i] + if typ.is_number() || typ.is_real_pointer() || typ.is_bool() { + match node.op { + .assign { + g.mov_store(.rdx, .rax, match g.get_type_size(typ) { + 1 { ._8 } + 2 { ._16 } + 3 { ._32 } + else { ._64 } + }) + } + else { + g.n_error('Unsupported assign instruction') + } + } + } else { + if node.op != .assign { + g.n_error('Unsupported assign instruction') + } + ts := g.table.sym(typ) + match ts.kind { + .struct_ { + size := g.get_type_size(typ) + if size >= 8 { + for j in 0 .. size / 8 { + g.mov_deref(.rcx, .rdx, ast.u64_type_idx) + g.mov_store(.rax, .rcx, ._64) + offset := if j == size / 8 - 1 && size % 8 != 0 { + size % 8 + } else { + 8 + } + g.add(.rax, offset) + g.add(.rdx, offset) + } + if size % 8 != 0 { + g.mov_deref(.rcx, .rdx, ast.u64_type_idx) + g.mov_store(.rax, .rcx, ._64) + } + } else { + mut left_size := if size >= 4 { + g.mov_deref(.rcx, .rdx, ast.u32_type_idx) + g.mov_store(.rax, .rcx, ._32) + if size > 4 { + g.add(.rax, 4) + g.add(.rdx, 4) + } + size - 4 + } else { + size + } + if left_size >= 2 { + g.mov_deref(.rcx, .rdx, ast.u16_type_idx) + g.mov_store(.rax, .rcx, ._16) + if left_size > 2 { + g.add(.rax, 2) + g.add(.rdx, 2) + } + left_size -= 2 + } + if left_size == 1 { + g.mov_deref(.rcx, .rdx, ast.u8_type_idx) + g.mov_store(.rax, .rcx, ._8) + } + } + } + .enum_ { + g.mov_store(.rdx, .rax, ._32) + } + else {} + } + } + continue + } name := left.str() - // if left is ast.Ident { ident := left as ast.Ident match right { ast.IntegerLiteral { @@ -2227,6 +2317,20 @@ fn (mut g Gen) gen_left_value(node ast.Expr) { offset := g.get_var_offset(node.name) g.lea_var_to_reg(.rax, offset) } + ast.SelectorExpr { + g.expr(node.expr) + offset := g.get_field_offset(node.expr_type, node.field_name) + if offset != 0 { + g.add(.rax, offset) + } + } + ast.IndexExpr {} // TODO + ast.PrefixExpr { + if node.op != .mul { + g.n_error('Unsupported left value') + } + g.expr(node.right) + } else { g.n_error('Unsupported left value') } @@ -2234,8 +2338,30 @@ fn (mut g Gen) gen_left_value(node ast.Expr) { } fn (mut g Gen) prefix_expr(node ast.PrefixExpr) { - if node.op == .amp { - g.gen_left_value(node.right) + match node.op { + .minus { + g.expr(node.right) + g.neg(.rax) + } + .amp { + g.gen_left_value(node.right) + } + .mul { + g.expr(node.right) + g.mov_deref(.rax, .rax, node.right_type.deref()) + } + .not { + g.expr(node.right) + g.cmp_zero(.rax) + // TODO mov_extend_reg + g.mov64(.rax, 0) + g.cset(.e) + } + .bit_not { + g.expr(node.right) + g.bitnot_reg(.rax) + } + else {} } } @@ -2297,6 +2423,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { match node.op { .eq, .ne, .gt, .lt, .ge, .le { g.cmp_reg(.rax, .rdx) + // TODO mov_extend_reg g.mov64(.rax, 0) g.cset_op(node.op) } @@ -2976,7 +3103,7 @@ fn (mut g Gen) init_struct(var Var, init ast.StructInit) { g.mov(.rcx, size / 8) g.lea_var_to_reg(.rdi, var.offset) g.write([u8(0xf3), 0x48, 0xab]) - g.println('; rep stosq') + g.println('rep stosq') size % 8 } else { size diff --git a/vlib/v/gen/native/gen.v b/vlib/v/gen/native/gen.v index bdd4b290a5..95b556fcc8 100644 --- a/vlib/v/gen/native/gen.v +++ b/vlib/v/gen/native/gen.v @@ -1375,6 +1375,9 @@ fn (mut g Gen) expr(node ast.Expr) { type_name := g.table.get_type_name(node.typ) g.mov(.rax, g.enum_vals[type_name].fields[node.val]) } + ast.UnsafeExpr { + g.expr(node.expr) + } else { g.n_error('expr: unhandled node type: $node.type_name()') } diff --git a/vlib/v/gen/native/tests/expressions.vv b/vlib/v/gen/native/tests/expressions.vv index b1555f909e..4bc7dd3843 100644 --- a/vlib/v/gen/native/tests/expressions.vv +++ b/vlib/v/gen/native/tests/expressions.vv @@ -74,6 +74,16 @@ fn test_multiple() { println(result) } +fn test_prefix() { + a := 3 + assert -a == -3 + b := true + assert !b == false + assert !!b == true + c := u8(73) + assert ~c == 182 +} + fn main() { println('start') test_add() diff --git a/vlib/v/gen/native/tests/method.vv b/vlib/v/gen/native/tests/method.vv index aed51b35c8..e8ae65684c 100644 --- a/vlib/v/gen/native/tests/method.vv +++ b/vlib/v/gen/native/tests/method.vv @@ -1,4 +1,5 @@ struct Size7 { +mut: a i8 b u8 c i8 @@ -27,7 +28,7 @@ fn (s &Size7) get_c_ref() i8 { } fn (mut s Size7) modify_c(a i8) i8 { - // s.c = a + s.c = a return s.c } @@ -35,8 +36,7 @@ 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 + assert a.modify_c(7) == 7 b := Size28{c: 6} assert b.get_c() == 6 } diff --git a/vlib/v/gen/native/tests/struct.vv b/vlib/v/gen/native/tests/struct.vv index d94cf6df55..0ea7c3c353 100644 --- a/vlib/v/gen/native/tests/struct.vv +++ b/vlib/v/gen/native/tests/struct.vv @@ -8,24 +8,6 @@ struct Size7 { g u8 } -struct Size8 { - a int - b i16 - c i8 -} - -struct Size12 { - a int - b int - c int -} - -struct Size16 { - a int - b i8 - c i64 -} - struct Size28 { a int b i16 @@ -42,42 +24,9 @@ struct StructWithDefault { c int = 5 } -fn get_7(s Size7) Size7 { - return s -} - -fn get_8(s Size8) Size8 { - return s -} - -fn get_12(s Size12) Size12 { - return s -} - -fn get_16(s Size16) Size16 { - return s -} - -fn get_28(s Size28) Size28 { - return s -} - -fn struct_fn_test() { - a := Size7{b: 2} - assert get_7(a).b == 2 - assert get_7(Size7{c: 3}).c == 3 - b := Size8{b: 2} - assert get_8(b).b == 2 - assert get_8(Size8{c: 3}).c == 3 - c := Size12{b: 2} - assert get_12(c).b == 2 - assert get_12(Size12{c: 3}).c == 3 - d := Size16{b: 2} - assert get_16(d).b == 2 - assert get_16(Size16{c: 3}).c == 3 - e := Size28{b: 2} - assert get_28(e).b == 2 - assert get_28(Size28{c: 3}).c == 3 +struct Mutable { +mut: + a int } fn struct_test() { @@ -93,9 +42,14 @@ fn struct_test() { assert d.a == 8 assert d.b == 2 assert d.c == 3 + mut e := Mutable{1} + e.a = 2 + assert e.a == 2 + mut f := &e + f.a = 3 + assert e.a == 3 } fn main() { struct_test() - struct_fn_test() } diff --git a/vlib/v/gen/native/tests/struct_with_fn.vv b/vlib/v/gen/native/tests/struct_with_fn.vv new file mode 100644 index 0000000000..84d5c8d4e8 --- /dev/null +++ b/vlib/v/gen/native/tests/struct_with_fn.vv @@ -0,0 +1,79 @@ +struct Size7 { + a i8 + b u8 + c i8 + d i8 + e u8 + f i8 + g u8 +} + +struct Size8 { + a int + b i16 + c i8 +} + +struct Size12 { + a int + b int + c int +} + +struct Size16 { + a int + b i8 + c i64 +} + +struct Size28 { + a int + b i16 + c int + d u32 + e i8 + f int + g int +} + +fn get_7(s Size7) Size7 { + return s +} + +fn get_8(s Size8) Size8 { + return s +} + +fn get_12(s Size12) Size12 { + return s +} + +fn get_16(s Size16) Size16 { + return s +} + +fn get_28(s Size28) Size28 { + return s +} + +fn struct_fn_test() { + a := Size7{b: 2} + assert get_7(a).b == 2 + assert get_7(Size7{c: 3}).c == 3 + b := Size8{b: 2} + assert get_8(b).b == 2 + assert get_8(Size8{c: 3}).c == 3 + c := Size12{b: 2} + assert get_12(c).b == 2 + assert get_12(Size12{c: 3}).c == 3 + d := Size16{b: 2} + assert get_16(d).b == 2 + assert get_16(Size16{c: 3}).c == 3 + e := Size28{b: 2} + assert get_28(e).b == 2 + assert get_28(Size28{c: 3}).c == 3 +} + +fn main() { + struct_fn_test() +} diff --git a/vlib/v/gen/native/tests/struct_with_fn.vv.out b/vlib/v/gen/native/tests/struct_with_fn.vv.out new file mode 100644 index 0000000000..e69de29bb2