Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

native: cleanup assign, fix nested struct #23778

Merged
merged 6 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
458 changes: 276 additions & 182 deletions vlib/v/gen/native/amd64.v

Large diffs are not rendered by default.

20 changes: 16 additions & 4 deletions vlib/v/gen/native/expr.v
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module native

import v.ast
import v.util
import v.token

fn (mut g Gen) expr(node ast.Expr) {
match node {
Expand Down Expand Up @@ -445,11 +446,17 @@ fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) {
}

fn (mut g Gen) gen_selector_expr(expr ast.SelectorExpr) {
g.println('; .${expr.field_name} {')
main_reg := g.code_gen.main_reg()
g.expr(expr.expr)
offset := g.get_field_offset(expr.expr_type, expr.field_name)
g.code_gen.add(main_reg, offset)
g.code_gen.mov_deref(main_reg, main_reg, expr.typ)
if offset != 0 {
g.code_gen.add(main_reg, offset)
}
if expr.next_token != token.Kind.dot { // the deref needs to be on the last selector (that has no . after it)
g.code_gen.mov_deref(main_reg, main_reg, expr.typ)
}
g.println('; .${expr.field_name} {')
}

fn (mut g Gen) gen_left_value(node ast.Expr) {
Expand All @@ -465,10 +472,15 @@ fn (mut g Gen) gen_left_value(node ast.Expr) {
g.code_gen.add(Amd64Register.rax, offset)
}
}
ast.StructInit, ast.ArrayInit {
ast.StructInit {
g.expr(node)
}
ast.IndexExpr {} // TODO
ast.ArrayInit {
g.expr(node) // TODO: add a test that uses this
}
ast.IndexExpr { // TODO
g.n_error('Unsupported IndexExpr left value')
}
ast.PrefixExpr {
if node.op != .mul {
g.n_error('Unsupported left value')
Expand Down
22 changes: 16 additions & 6 deletions vlib/v/gen/native/stmt.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ pub fn (mut g Gen) stmts(stmts []ast.Stmt) {
fn (mut g Gen) stmt(node ast.Stmt) {
match node {
ast.AssignStmt {
g.code_gen.assign_stmt(node)
g.assign_stmt(node)
}
ast.Block {
g.stmts(node.stmts)
}
ast.BranchStmt {
label_name := node.label
// break / continue statements in for loops
for i := g.labels.branches.len - 1; i >= 0; i-- {
branch := g.labels.branches[i]
if label_name == '' || label_name == branch.name {
Expand Down Expand Up @@ -115,6 +116,10 @@ fn (mut g Gen) stmt(node ast.Stmt) {
}
}

fn (mut g Gen) assign_stmt(node ast.AssignStmt) {
g.code_gen.assign_stmt(node)
}

fn (mut g Gen) gen_forc_stmt(node ast.ForCStmt) {
if node.has_init {
g.stmts([node.init])
Expand Down Expand Up @@ -245,6 +250,7 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
if node.is_range {
g.println('; for ${node.val_var} in range {')
// for a in node.cond .. node.high {

i := g.code_gen.allocate_var(node.val_var, 8, 0) // iterator variable
g.println('; evaluate node.cond for lower bound:')
g.expr(node.cond) // outputs the lower loop bound (initial value) to the main reg
Expand All @@ -253,7 +259,6 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
g.code_gen.mov_reg_to_var(LocalVar{i, ast.i64_type_idx, node.val_var}, main_reg) // i = node.cond // initial value

start := g.pos() // label-begin:
start_label := g.labels.new_label()

g.println('; check iterator against upper loop bound')
g.code_gen.mov_var_to_reg(main_reg, LocalVar{i, ast.i64_type_idx, node.val_var})
Expand All @@ -267,18 +272,22 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
pos: jump_addr
}
g.println('; jump to label ${end_label} (end_label)')

start_label := g.labels.new_label() // used for continue
g.labels.branches << BranchLabel{
name: node.label
start: start_label
end: end_label
}

g.stmts(node.stmts) // writes the actual body of the loop
g.labels.addrs[start_label] = g.pos()
g.println('; label ${start_label} (start_label)')

g.labels.addrs[start_label] = g.pos() // used for continue (continue: jump before the inc)
g.println('; label ${start_label} (continue_label)')

g.code_gen.inc_var(LocalVar{i, ast.i64_type_idx, node.val_var})
g.labels.branches.pop()
g.code_gen.jmp_back(start) // loops

g.labels.addrs[end_label] = g.pos()
g.println('; label ${end_label} (end_label)')
g.println('; for ${node.val_var} in range }')
Expand All @@ -297,6 +306,7 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
}

fn (mut g Gen) gen_assert(assert_node ast.AssertStmt) {
g.println('; gen_assert {')
mut cjmp_addr := i32(0)
ane := assert_node.expr
label := g.labels.new_label()
Expand All @@ -306,10 +316,10 @@ fn (mut g Gen) gen_assert(assert_node ast.AssertStmt) {
pos: cjmp_addr
}
g.println('; jump to label ${label}')
g.expr(assert_node.expr)
g.code_gen.trap()
g.labels.addrs[label] = g.pos()
g.println('; label ${label}')
g.println('; gen_assert }')
}

fn (mut g Gen) gen_flag_hash_stmt(node ast.HashStmt) {
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/gen/native/tests/arrays.vv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
assert [1, 2, 3] != []
}
Empty file.
16 changes: 15 additions & 1 deletion vlib/v/gen/native/tests/assign.vv
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,29 @@ fn test_int() {
c += u8(-d)
// TODO: remove the int cast when unsigned integer print will be supported
println(int(c))

mut e := 3
assert e == 3
mut f := &e
assert *f == 3
unsafe{*f = 5}
assert *f == 5
assert e == 5
}

fn test_fp() {
a := 1.0
mut b := a
b += 0.5
b += 1.5
b -= 1.0
b *= 4
b /= 2

b += a
b -= a
b *= a
b /= a

println(int(b))
}

Expand Down
11 changes: 11 additions & 0 deletions vlib/v/gen/native/tests/float.vv
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ fn float_assign_test() {
assert a == 13.5
a /= 4.5
assert a == 3.0

a = 1.0
mut b := &a
unsafe{*b += 2.5}
assert a == 3.5
unsafe{*b -= 1.25}
assert a == 2.25
unsafe{*b *= 6.0}
assert a == 13.5
unsafe{*b /= 4.5}
assert a == 3.0
}
Comment on lines +31 to 42
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this may need a change too

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

however it can also serve as a check when the asserts and == work for f64, and the rest of the tests can cross check it, so imho it is good to merge as it is

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, I'll change that for the next PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will require to change all the tests in the file, as it is using asserts between floats for all checks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may wait until assert between floats are fixed as some of the tests would be interesting to keep as such.


fn float_cast_test() {
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/native/tests/native_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ fn test_native() {
mut found := res.output.trim_right('\r\n').replace('\r\n', '\n')
found = found.trim_space()
if expected != found {
println(term.red('FAIL'))
eprintln(bench.step_message_fail('${full_test_path} did not match expected output: '))
println('============')
println('expected: "${expected}" len=${expected.len}')
println('============')
Expand Down
99 changes: 95 additions & 4 deletions vlib/v/gen/native/tests/struct.vv
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct StructWithDefault {
struct Mutable {
mut:
a int
b int
}

fn struct_test() {
Expand All @@ -50,30 +51,37 @@ fn struct_test() {
assert d.a == 8
assert d.b == 2
assert d.c == 3
mut e := Mutable{1}
mut e := Mutable{1, 0}
e.a = 2
assert e.a == 2
assert e.b == 0
mut f := &e
f.a = 3
assert e.a == 3
f.b = 2
assert e.b == 2

g := &Mutable{2}
g := &Mutable{2, 1}
assert g.a == 2
assert g.b == 1
}

type AliasedStruct = Mutable
type AliasedPointer = &Mutable

fn alias_test() {
mut a := AliasedStruct{1}
mut a := AliasedStruct{1, 0}
a.a = 2
assert a.a == 2
mut b := &a
b.a = 3
assert a.a == 3
b.b = 2
assert a.b == 2

c := AliasedPointer{2}
c := AliasedPointer{2, 1}
assert c.a == 2
assert c.b == 1
}

fn init_size28() Size28 {
Expand Down Expand Up @@ -106,8 +114,91 @@ fn return_test() {
assert b.g == 7
}

struct Tree {
mut:
leaf Leaf
sp Species
h f32
age int
big_leaf BigLeaf
medium_leaf MediumLeaf
small_leaf SmallLeaf
}

enum Species {
oak
willow
}

struct Leaf {
a int
}

struct BigLeaf {
a i64
b int
c i64
}

struct MediumLeaf {
a i16
}

struct SmallLeaf {
a u8
}

fn assign_fields() {
// TODO: fix commented
mut a := Tree{}
println(a.leaf.a)
assert a.leaf.a == 0
assert a.sp == .oak
assert a.h == 0.0
assert a.age == 0

a = Tree{age: 3}
assert a.age == 3

// a = Tree{h: 2.0}
// assert a.h == 2.0

a.h = 1.1
assert a.h == 1.1

a.age = 3
assert a.age == 3

a.sp = .willow
assert a.sp == .willow

a.leaf = Leaf{2}
assert a.leaf.a == 2
println(a.leaf.a)

a.big_leaf = BigLeaf{1, 2, 3}
assert a.big_leaf.a == 1
assert a.big_leaf.b == 2
assert a.big_leaf.c == 3

a.small_leaf = SmallLeaf{5}
assert a.small_leaf.a == 5

a.medium_leaf = MediumLeaf{23}
assert a.medium_leaf.a == 23

mut f := Leaf{1}
assert f.a == 1
mut f2 := &f
assert f2.a == 1
unsafe{*f2 = Leaf{2}}
assert f2.a == 2
assert f.a == 2
}

fn main() {
struct_test()
return_test()
alias_test()
assign_fields()
}
2 changes: 2 additions & 0 deletions vlib/v/gen/native/tests/struct.vv.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
0
2
Loading