Skip to content

Commit 9d3ccf3

Browse files
authored
native: support initializing a dynamic arrays with values (#25425)
1 parent ca5f2da commit 9d3ccf3

5 files changed

Lines changed: 115 additions & 10 deletions

File tree

‎vlib/builtin/builtin.c.v‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,8 @@ pub fn vcalloc(n isize) &u8 {
682682
}
683683
$if prealloc {
684684
return unsafe { prealloc_calloc(n) }
685+
} $else $if native {
686+
return unsafe { C.calloc(1, n) }
685687
} $else $if gcboehm ? {
686688
return unsafe { &u8(C.GC_MALLOC(n)) }
687689
} $else {

‎vlib/v/gen/native/amd64.v‎

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,7 +1879,7 @@ fn (mut c Amd64) div_reg_rax(b Amd64Register) {
18791879
// rax % b
18801880
fn (mut c Amd64) mod_reg_rax(b Amd64Register) {
18811881
c.div_reg_rax(b)
1882-
c.mov_reg(Amd64Register.rdx, Amd64Register.rax)
1882+
c.mov_reg(Amd64Register.rax, Amd64Register.rdx)
18831883
}
18841884

18851885
fn (mut c Amd64) sub_reg(a Amd64Register, b Amd64Register) {
@@ -2515,8 +2515,9 @@ fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.E
25152515
match node.op {
25162516
.decl_assign {
25172517
if right.is_fixed {
2518-
c.g.n_error('${@LOCATION} Unexpected operator `${node.op}`')
2519-
} else {
2518+
c.g.n_error('${@LOCATION} Unsupported ${node} ${right}')
2519+
} else if right.exprs.len == 0 {
2520+
// `[]int{len: 6, cap:10, init:22}`
25202521
c.g.allocate_by_type(ident.name, ast.array_type)
25212522
len := ast.CallArg{
25222523
expr: if right.has_len {
@@ -2550,9 +2551,61 @@ fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.E
25502551
return_type: ast.array_type
25512552
nr_ret_values: 1
25522553
is_return_used: true
2553-
})
2554+
}) // rax: address of returned array struct
25542555
c.lea_var_to_reg(Amd64Register.rdx, c.g.get_var_offset(ident.name))
2555-
c.move_struct(.rax, .rdx, c.g.get_type_size(ast.array_type))
2556+
c.move_struct(.rdx, .rax, c.g.get_type_size(ast.array_type))
2557+
} else {
2558+
// `[1, 2, 3]`
2559+
2560+
// array struct
2561+
c.g.allocate_by_type(ident.name, ast.array_type)
2562+
len := ast.CallArg{
2563+
expr: ast.IntegerLiteral{right.exprs.len.str(), right.pos}
2564+
typ: ast.int_type
2565+
pos: right.pos
2566+
}
2567+
cap := len
2568+
elem_size := c.g.get_type_size(right.elem_type)
2569+
size := ast.CallArg{
2570+
expr: ast.IntegerLiteral{elem_size.str(), right.pos}
2571+
typ: ast.int_type
2572+
pos: right.pos
2573+
}
2574+
c.call_fn(ast.CallExpr{
2575+
pos: right.pos
2576+
name: '__new_array'
2577+
args: [len, cap, size]
2578+
expected_arg_types: [ast.int_type, ast.int_type, ast.int_type]
2579+
language: .v
2580+
return_type: ast.array_type
2581+
nr_ret_values: 1
2582+
is_return_used: true
2583+
}) // rax: address of returned array struct
2584+
c.lea_var_to_reg(Amd64Register.rdx, c.g.get_var_offset(ident.name))
2585+
c.move_struct(.rdx, .rax, c.g.get_type_size(ast.array_type))
2586+
2587+
// init array
2588+
e_ts := c.g.table.sym(right.elem_type)
2589+
c.g.expr(node.left[i])
2590+
offset := c.g.get_field_offset(ast.array_type, 'data')
2591+
if offset != 0 {
2592+
c.add(Amd64Register.rax, offset)
2593+
}
2594+
c.mov_deref(Amd64Register.rdx, Amd64Register.rax, ast.u64_type) // address of the data
2595+
for e in right.exprs {
2596+
c.g.expr(e) // rax
2597+
if e_ts.info is ast.Struct {
2598+
c.move_struct(.rdx, .rax, elem_size)
2599+
} else {
2600+
c.mov_store(.rdx, .rax, match elem_size {
2601+
1 { ._8 }
2602+
2 { ._16 }
2603+
4 { ._32 }
2604+
else { ._64 }
2605+
})
2606+
}
2607+
c.add(Amd64Register.rdx, elem_size)
2608+
}
25562609
}
25572610
}
25582611
else {
@@ -2735,12 +2788,13 @@ fn (mut c Amd64) gen_index_expr(node ast.IndexExpr) {
27352788
c.mul_reg_main(Amd64Register.rbx)
27362789
c.add_reg2(Amd64Register.rax, Amd64Register.rcx)
27372790
} else if node.is_array {
2791+
// TODO: use functions from builtin instead (array.set, array.get...)
27382792
c.g.expr(node.left)
27392793
offset := c.g.get_field_offset(ast.array_type, 'data')
27402794
if offset != 0 {
27412795
c.add(Amd64Register.rax, offset)
27422796
}
2743-
c.mov_reg(Amd64Register.rcx, Amd64Register.rax)
2797+
c.mov_deref(Amd64Register.rcx, Amd64Register.rax, ast.u64_type)
27442798
// add the index times the size (bytes) of the type
27452799
c.g.expr(node.index)
27462800
c.mov(Amd64Register.rbx, i32(c.g.get_type_size(node.typ)))

‎vlib/v/gen/native/gen.v‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -819,8 +819,12 @@ fn (mut g Gen) get_var_offset(var_name string) i32 {
819819
fn (mut g Gen) get_field_offset(in_type ast.Type, name string) i32 {
820820
typ := g.unwrap(in_type)
821821
ts := g.table.sym(typ)
822-
field := ts.find_field(name) or {
823-
g.n_error('${@LOCATION} Could not find field `${name}` on init')
822+
field := if ts.kind == .array {
823+
g.table.sym(ast.array_type).find_field(name) or {
824+
g.n_error('${@LOCATION} Could not find field `${name}` on init ${g.table.sym(ast.array_type)}')
825+
}
826+
} else {
827+
ts.find_field(name) or { g.n_error('${@LOCATION} Could not find field `${name}` on init') }
824828
}
825829
return g.structs[typ.idx()].offsets[field.i]
826830
}

‎vlib/v/gen/native/tests/arrays.vv‎

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
fn main() {
22
assert [1, 2, 3] != []
3-
mut my_array := []int{len:3}
3+
array_with_len()
4+
array_with_values()
5+
}
6+
7+
fn array_with_len() {
8+
len := 20
9+
mut my_array := []int{len:20}
10+
for i in 0 .. len {
11+
assert my_array[i] == 0
12+
unsafe {
13+
assert &int(my_array.data)[i] == 0
14+
}
15+
}
416
my_array[0] = 4
517
my_array[1] = 5
618
my_array[2] = 6
@@ -10,4 +22,37 @@ fn main() {
1022
assert my_array[0] == 4
1123
assert my_array[1] == 5
1224
assert my_array[2] == 6
25+
unsafe {
26+
assert &int(my_array.data)[0] == 4
27+
assert &int(my_array.data)[1] == 5
28+
assert &int(my_array.data)[2] == 6
29+
}
30+
assert my_array.len == len
31+
assert my_array.cap == len
32+
}
33+
34+
fn array_with_values() {
35+
mut arr := [2, 4, 8, 16, 32, 64, 128]
36+
assert arr[0] == 2
37+
assert arr[1] == 4
38+
assert arr[2] == 8
39+
assert arr[3] == 16
40+
assert arr[4] == 32
41+
assert arr[5] == 64
42+
assert arr[6] == 128
43+
// below taken from builtin/array_test.v
44+
arr[0] = 2
45+
arr[1] &= 255
46+
arr[2] |= 255
47+
arr[3] <<= 4
48+
arr[4] >>= 4
49+
arr[5] %= 5
50+
arr[6] ^= 3
51+
assert arr[0] == 2
52+
assert arr[1] == 4 & 255
53+
assert arr[2] == 8 | 255
54+
assert arr[3] == 16 << 4
55+
assert arr[4] == 32 >> 4
56+
assert arr[5] == 64 % 5
57+
assert arr[6] == 128 ^ 3
1358
}

‎vlib/v/gen/native/tests/native_test.v‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ fn test_native() {
6161

6262
bench.set_total_expected_steps(tests.len)
6363
for test in tests {
64-
if skip_vv && test in ['libc.vv', 'linux.vv'] {
64+
if skip_vv && test in ['libc.vv', 'linux.vv', 'arrays.vv'] {
6565
// TODO: remove the skip here, when the native backend is more advanced
6666
println('>>> SKIPPING ${test} since VNATIVE_SKIP_LIBC_VV is defined')
6767
continue

0 commit comments

Comments
 (0)