1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

native: support assigning to struct fields (#15938)

This commit is contained in:
lemon 2022-10-01 20:42:26 +09:00 committed by GitHub
parent 5dae5b2a92
commit a7ad64033e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 243 additions and 70 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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