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 all 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
545 changes: 320 additions & 225 deletions vlib/v/gen/native/amd64.v

Large diffs are not rendered by default.

37 changes: 24 additions & 13 deletions vlib/v/gen/native/expr.v
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn (mut g Gen) expr(node ast.Expr) {
g.local_var_ident(node, var)
}
else {
g.n_error('Unsupported variable kind')
g.n_error('${@LOCATION} Unsupported variable kind')
}
}
}
Expand Down Expand Up @@ -90,7 +90,7 @@ fn (mut g Gen) expr(node ast.Expr) {
for i, v in bytes {
val |= v << (i * 8)
if i >= sizeof(rune) {
g.n_error('runes are only 4 bytes wide')
g.n_error('${@LOCATION} runes are only 4 bytes wide')
}
}
g.code_gen.movabs(g.code_gen.main_reg(), i64(val))
Expand Down Expand Up @@ -129,7 +129,7 @@ fn (mut g Gen) expr(node ast.Expr) {
g.gen_sizeof_expr(node)
}
else {
g.n_error('expr: unhandled node type: ${node.type_name()}')
g.n_error('${@LOCATION} expr: unhandled node type: ${node.type_name()}')
}
}
}
Expand All @@ -151,7 +151,7 @@ fn (mut g Gen) local_var_ident(ident ast.Ident, var LocalVar) {
)
}
else {
g.n_error('Unsupported variable type')
g.n_error('${@LOCATION} Unsupported variable type')
}
}
}
Expand Down Expand Up @@ -273,7 +273,7 @@ fn (mut g Gen) gen_typeof_expr(node ast.TypeOf, newline bool) {

match ts.kind {
.sum_type {
g.n_error('`typeof()` is not implemented for sum types yet')
g.n_error('${@LOCATION} `typeof()` is not implemented for sum types yet')
}
.array_fixed {
fixed_info := ts.info as ast.ArrayFixed
Expand Down Expand Up @@ -427,10 +427,10 @@ fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) {
}
}
} else {
g.n_error('nothing to print')
g.n_error('${@LOCATION} nothing to print')
}
} else {
g.n_error('non-comptime conditionals are not implemented yet.')
g.n_error('${@LOCATION} non-comptime conditionals are not implemented yet.')
}
}
else {
Expand All @@ -445,11 +445,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 != .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,18 +471,23 @@ 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('${@LOCATION} Unsupported IndexExpr left value')
}
ast.PrefixExpr {
if node.op != .mul {
g.n_error('Unsupported left value')
g.n_error('${@LOCATION} Unsupported left value')
}
g.expr(node.right)
}
else {
g.n_error('Unsupported left value')
g.n_error('${@LOCATION} Unsupported left value')
}
}
}
40 changes: 22 additions & 18 deletions vlib/v/gen/native/gen.v
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ fn byt(n i32, s i32) u8 {
fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar {
mut obj := ident.obj
if obj !in [ast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister] {
obj = ident.scope.find(ident.name) or { g.n_error('unknown variable ${ident.name}') }
obj = ident.scope.find(ident.name) or {
g.n_error('${@LOCATION} unknown variable ${ident.name}')
}
}
match obj {
ast.Var {
Expand All @@ -277,7 +279,7 @@ fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar {
}
}
else {
g.n_error('unsupported variable type type:${obj} name:${ident.name}')
g.n_error('${@LOCATION} unsupported variable type type:${obj} name:${ident.name}')
}
}
}
Expand All @@ -291,7 +293,7 @@ fn (mut g Gen) get_type_from_var(var Var) ast.Type {
return var.typ
}
GlobalVar {
g.n_error('cannot get type from GlobalVar yet')
g.n_error('${@LOCATION} cannot get type from GlobalVar yet')
}
}
}
Expand Down Expand Up @@ -452,7 +454,7 @@ pub fn (mut g Gen) generate_header() {
}
}
else {
g.n_error('only `raw`, `linux`, `windows` and `macos` are supported for -os in -native')
g.n_error('${@LOCATION} only `raw`, `linux`, `windows` and `macos` are supported for -os in -native')
}
}
}
Expand Down Expand Up @@ -517,7 +519,7 @@ pub fn (mut g Gen) link(obj_name string) {
// TODO: implement linking for macos!
}
else {
g.n_error('native linking is not implemented for ${g.pref.os}')
g.n_error('${@LOCATION} native linking is not implemented for ${g.pref.os}')
}
}
}
Expand Down Expand Up @@ -681,15 +683,17 @@ fn (mut g Gen) try_var_offset(var_name string) i32 {
fn (mut g Gen) get_var_offset(var_name string) i32 {
r := g.try_var_offset(var_name)
if r == -1 {
g.n_error('unknown variable `${var_name}`')
g.n_error('${@LOCATION} unknown variable `${var_name}`')
}
return r
}

fn (mut g Gen) get_field_offset(in_type ast.Type, name string) i32 {
typ := g.unwrap(in_type)
ts := g.table.sym(typ)
field := ts.find_field(name) or { g.n_error('Could not find field `${name}` on init') }
field := ts.find_field(name) or {
g.n_error('${@LOCATION} Could not find field `${name}` on init')
}
return g.structs[typ.idx()].offsets[field.i]
}

Expand Down Expand Up @@ -724,7 +728,7 @@ fn (mut g Gen) get_type_size(raw_type ast.Type) i32 {
ast.float_literal_type_idx { 8 }
ast.char_type_idx { 1 }
ast.rune_type_idx { 4 }
else { g.n_error('unknown type size ${typ}') }
else { g.n_error('${@LOCATION} unknown type size ${typ}') }
}
}
if typ.is_bool() {
Expand Down Expand Up @@ -835,7 +839,7 @@ fn (mut g Gen) get_sizeof_ident(ident ast.Ident) i32 {
return g.get_type_size(typ)
}
size := g.var_alloc_size[ident.name] or {
g.n_error('unknown variable `${ident}`')
g.n_error('${@LOCATION} unknown variable `${ident}`')
return 0
}
return size
Expand Down Expand Up @@ -911,7 +915,7 @@ fn (mut g Gen) eval_escape_codes(str string) string {
`u` {
i++
utf8 := strconv.parse_int(str[i..i + 4], 16, 16) or {
g.n_error('invalid \\u escape code (${str[i..i + 4]})')
g.n_error('${@LOCATION} invalid \\u escape code (${str[i..i + 4]})')
0
}
i += 4
Expand All @@ -925,22 +929,22 @@ fn (mut g Gen) eval_escape_codes(str string) string {
`x` {
i++
c := strconv.parse_int(str[i..i + 2], 16, 8) or {
g.n_error('invalid \\x escape code (${str[i..i + 2]})')
g.n_error('${@LOCATION} invalid \\x escape code (${str[i..i + 2]})')
0
}
i += 2
buffer << u8(c)
}
`0`...`7` {
c := strconv.parse_int(str[i..i + 3], 8, 8) or {
g.n_error('invalid escape code \\${str[i..i + 3]}')
g.n_error('${@LOCATION} invalid escape code \\${str[i..i + 3]}')
0
}
i += 3
buffer << u8(c)
}
else {
g.n_error('invalid escape code \\${str[i]}')
g.n_error('${@LOCATION} invalid escape code \\${str[i]}')
}
}
}
Expand Down Expand Up @@ -973,7 +977,7 @@ fn (mut g Gen) gen_to_string(reg Register, typ ast.Type) {
g.code_gen.mov_reg(g.code_gen.main_reg(), reg)
}
} else {
g.n_error('int-to-string conversion not implemented for type ${typ}')
g.n_error('${@LOCATION} int-to-string conversion not implemented for type ${typ}')
}
g.println('; to_string }')
}
Expand All @@ -986,7 +990,7 @@ fn (mut g Gen) gen_var_to_string(reg Register, expr ast.Expr, var Var, config Va
g.code_gen.convert_rune_to_string(reg, buffer, var, config)
} else if typ.is_int() {
if typ.is_unsigned() {
g.n_error('Unsigned integer print is not supported')
g.n_error('${@LOCATION} Unsigned integer print is not supported')
} else {
buffer := g.allocate_array('itoa-buffer', 1, 32) // 32 characters should be enough
end_of_buffer := buffer + 4 + 32 - 1 // 4 bytes for the size and 32 for the chars, -1 to not go out of array
Expand All @@ -1001,7 +1005,7 @@ fn (mut g Gen) gen_var_to_string(reg Register, expr ast.Expr, var Var, config Va
} else if typ.is_string() {
g.code_gen.mov_var_to_reg(reg, var, config)
} else {
g.n_error('int-to-string conversion not implemented for type ${typ}')
g.n_error('${@LOCATION} int-to-string conversion not implemented for type ${typ}')
}
g.println('; var_to_string }')
}
Expand All @@ -1019,7 +1023,7 @@ fn (mut g Gen) patch_calls() {
for c in g.callpatches {
addr := g.fn_addr[c.name]
if addr == 0 {
g.n_error('fn addr of `${c.name}` = 0')
g.n_error('${@LOCATION} fn addr of `${c.name}` = 0')
return
}
last := i32(g.buf.len)
Expand All @@ -1038,7 +1042,7 @@ fn (mut g Gen) patch_labels() {
for label in g.labels.patches {
addr := g.labels.addrs[label.id]
if addr == 0 {
g.n_error('label addr = 0')
g.n_error('${@LOCATION} label addr = 0')
return
}

Expand Down
30 changes: 20 additions & 10 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 @@ -110,11 +111,15 @@ fn (mut g Gen) stmt(node ast.Stmt) {
ast.TypeDecl {}
ast.InterfaceDecl {}
else {
g.n_error('native.stmt(): bad node: ' + node.type_name())
g.n_error('${@LOCATION} bad node: ' + node.type_name())
}
}
}

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 @@ -144,12 +149,12 @@ fn (mut g Gen) gen_forc_stmt(node ast.ForCStmt) {
jump_addr = g.code_gen.cjmp(.jg)
}
else {
g.n_error('unsupported conditional in for-c loop')
g.n_error('${@LOCATION} unsupported conditional in for-c loop')
}
}
}
else {
g.n_error('unhandled infix.left')
g.n_error('${@LOCATION} unhandled infix.left')
}
}
}
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 @@ -292,11 +301,12 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
} else if it.kind == .map {
*/
} else {
g.n_error('for-in ${node.kind} statement is not yet implemented')
g.n_error('${@LOCATION} for-in ${node.kind} statement is not yet implemented')
}
}

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.
Loading
Loading