native: support nested structs, improve support for right expr of IndexExpr (#24627)

This commit is contained in:
Eliyaan (Nopana) 2025-05-31 23:46:54 +02:00 committed by GitHub
parent 64872fe858
commit da8d8fa27c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 104 additions and 14 deletions

View file

@ -631,7 +631,7 @@ fn (mut c Amd64) mov_deref(r Register, rptr Register, typ ast.Type) {
}) })
} }
c.g.write8(i32(reg) % 8 * 8 + i32(regptr) % 8) c.g.write8(i32(reg) % 8 * 8 + i32(regptr) % 8)
c.g.println('mov ${reg}, [${regptr}]') c.g.println('mov ${reg}, [${regptr}]; size ${size}')
} }
fn (mut c Amd64) mov_store(regptr Amd64Register, reg Amd64Register, size Size) { fn (mut c Amd64) mov_store(regptr Amd64Register, reg Amd64Register, size Size) {
@ -1887,7 +1887,7 @@ pub fn (mut c Amd64) call_fn(node ast.CallExpr) {
c.bitand_reg(.rdx, .rbx) c.bitand_reg(.rdx, .rbx)
} }
} }
else {} else {} // handled below
} }
} }
if is_floats[i] { if is_floats[i] {
@ -2214,12 +2214,13 @@ fn (mut c Amd64) mov_float_xmm0_var(reg Amd64Register, var_type ast.Type) {
} }
} }
fn (mut c Amd64) create_string_struct(typ ast.Type, name string, str string) { fn (mut c Amd64) create_string_struct(typ ast.Type, name string, str string) i32 {
dest := c.allocate_var(name, c.g.get_type_size(typ), i64(0)) dest := c.allocate_var(name, c.g.get_type_size(typ), i64(0))
c.learel(Amd64Register.rsi, c.g.allocate_string(str, 3, .rel32)) c.learel(Amd64Register.rsi, c.g.allocate_string(str, 3, .rel32))
c.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, Amd64Register.rsi) c.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, Amd64Register.rsi)
offset := c.g.get_field_offset(typ, 'len') offset := c.g.get_field_offset(typ, 'len')
c.mov_int_to_var(LocalVar{dest, ast.i32_type_idx, name}, i32(str.len), offset: offset) c.mov_int_to_var(LocalVar{dest, ast.i32_type_idx, name}, i32(str.len), offset: offset)
return dest
} }
fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.Expr, name string, ident ast.Ident) { fn (mut c Amd64) assign_ident_right_expr(node ast.AssignStmt, i i32, right ast.Expr, name string, ident ast.Ident) {
@ -3698,14 +3699,20 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
else {} else {}
} }
for f in init.init_fields { for f in init.init_fields {
c.g.println('; ${var.name}.${f.name}')
field := ts.find_field(f.name) or { field := ts.find_field(f.name) or {
c.g.n_error('${@LOCATION} Could not find field `${f.name}` on init (${ts.info})') c.g.n_error('${@LOCATION} Could not find field `${f.name}` on init (${ts.info})')
} }
offset := c.g.structs[typ.idx()].offsets[field.i] f_offset := c.g.structs[typ.idx()].offsets[field.i]
f_ts := c.g.table.sym(field.typ)
c.g.expr(f.expr) c.g.expr(f.expr)
// TODO: expr not on rax if f_ts.info is ast.Struct {
c.mov_reg_to_var(var, Amd64Register.rax, offset: offset, typ: field.typ) c.copy_struct_to_struct(field, f_offset, 0, var)
} else {
// TODO: expr not on rax -> may be done
c.mov_reg_to_var(var, Amd64Register.rax, offset: f_offset, typ: field.typ)
}
} }
} }
GlobalVar { GlobalVar {
@ -3714,6 +3721,36 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
} }
} }
// f_offset is the offset of the field in the root struct
// data_offset is the offset to add to rax to find the data
// needs rax to hold the address of the root field data
fn (mut c Amd64) copy_struct_to_struct(field ast.StructField, f_offset i32, data_offset i32, var LocalVar) {
f_typ_idx := field.typ.idx()
f_ts := c.g.table.sym(field.typ)
for f2 in (f_ts.info as ast.Struct).fields {
c.g.println('; ${var.name}. ... .${f2.name}')
field2 := f_ts.find_field(f2.name) or {
c.g.n_error('${@LOCATION} Could not find field `${f2.name}` on init (${f_ts.info})')
}
f2_offset := c.g.structs[f_typ_idx].offsets[field2.i]
f2_ts := c.g.table.sym(field2.typ)
if f2_ts.info is ast.Struct {
c.copy_struct_to_struct(field2, f_offset + f2_offset, data_offset + f2_offset,
var)
} else {
c.mov_reg(Amd64Register.rdx, Amd64Register.rax)
c.add(Amd64Register.rdx, data_offset + f2_offset)
c.mov_deref(Amd64Register.rdx, Amd64Register.rdx, field2.typ)
c.mov_reg_to_var(var, Amd64Register.rdx,
offset: f_offset + f2_offset
typ: field2.typ
)
}
}
}
fn (mut c Amd64) init_array(var Var, node ast.ArrayInit) { fn (mut c Amd64) init_array(var Var, node ast.ArrayInit) {
match var { match var {
ast.Ident { ast.Ident {

View file

@ -543,7 +543,7 @@ fn (mut c Arm64) cmp_reg2(reg Register, reg2 Register) {
panic('Arm64.add_reg2() not implemented') panic('Arm64.add_reg2() not implemented')
} }
fn (mut c Arm64) create_string_struct(typ ast.Type, name string, str string) { fn (mut c Arm64) create_string_struct(typ ast.Type, name string, str string) i32 {
panic('Arm64.add_reg2() not implemented') panic('Arm64.add_reg2() not implemented')
} }

View file

@ -78,7 +78,8 @@ fn (mut g Gen) expr(node ast.Expr) {
} }
ast.StringLiteral { ast.StringLiteral {
str := g.eval_str_lit_escape_codes(node) str := g.eval_str_lit_escape_codes(node)
g.code_gen.create_string_struct(ast.string_type_idx, 'string_lit', str) pos := g.code_gen.create_string_struct(ast.string_type_idx, 'str_lit', str)
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), pos)
} }
ast.CharLiteral { ast.CharLiteral {
bytes := g.eval_escape_codes(node.val) bytes := g.eval_escape_codes(node.val)
@ -131,9 +132,14 @@ fn (mut g Gen) expr(node ast.Expr) {
ast.IndexExpr { ast.IndexExpr {
if node.left_type.is_string() { if node.left_type.is_string() {
g.expr(node.index) g.expr(node.index)
g.code_gen.mov_var_to_reg(Amd64Register.rdx, node.left as ast.Ident) // load address of string g.code_gen.push(Amd64Register.rax)
g.code_gen.add_reg2(Amd64Register.rdx, Amd64Register.rax) // add the offset to the address
g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rdx, ast.u8_type_idx) g.expr(node.left) // load address of string struct
g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.u64_type_idx) // load value of the str pointer
g.code_gen.pop2(Amd64Register.rdx) // index
g.code_gen.add_reg2(Amd64Register.rax, Amd64Register.rdx) // add the offset to the address
g.code_gen.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.u8_type_idx)
} else if node.left_type.is_pointer() { } else if node.left_type.is_pointer() {
dump(node) dump(node)
g.n_error('${@LOCATION} expr: unhandled node type: Index expr is not applied on string') g.n_error('${@LOCATION} expr: unhandled node type: Index expr is not applied on string')
@ -464,9 +470,12 @@ fn (mut g Gen) gen_selector_expr(expr ast.SelectorExpr) {
g.code_gen.add(main_reg, offset) 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) 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) ts := g.table.sym(expr.typ)
if ts.info !is ast.Struct {
g.code_gen.mov_deref(main_reg, main_reg, expr.typ)
}
} }
g.println('; .${expr.field_name} {') g.println('; .${expr.field_name} }')
} }
fn (mut g Gen) gen_left_value(node ast.Expr) { fn (mut g Gen) gen_left_value(node ast.Expr) {

View file

@ -100,7 +100,7 @@ mut:
convert_bool_to_string(r Register) convert_bool_to_string(r Register)
convert_int_to_string(a Register, b Register) convert_int_to_string(a Register, b Register)
convert_rune_to_string(r Register, buffer i32, var Var, config VarConfig) convert_rune_to_string(r Register, buffer i32, var Var, config VarConfig)
create_string_struct(typ ast.Type, name string, str string) create_string_struct(typ ast.Type, name string, str string) i32
dec_var(var Var, config VarConfig) dec_var(var Var, config VarConfig)
fn_decl(node ast.FnDecl) fn_decl(node ast.FnDecl)
gen_asm_stmt(asm_node ast.AsmStmt) gen_asm_stmt(asm_node ast.AsmStmt)

View file

@ -16,6 +16,10 @@ fn test_string_len() {
println(d.len) println(d.len)
} }
struct Idx {
a string
}
fn test_string_index() { fn test_string_index() {
a := '1234' a := '1234'
assert a[0] == `1` assert a[0] == `1`
@ -26,6 +30,10 @@ fn test_string_index() {
assert a[1] != `0` assert a[1] != `0`
assert a[2] != `0` assert a[2] != `0`
assert a[3] != `0` assert a[3] != `0`
x := Idx{'abc'}
assert x.a[1] == `b`
assert x.a[2] != `b`
} }
fn test_for_i_in_len() { fn test_for_i_in_len() {

View file

@ -196,9 +196,45 @@ fn assign_fields() {
assert f.a == 2 assert f.a == 2
} }
struct Nest {
a string
}
struct Nest2 {
a Nest
}
struct Nest3 {
a Nest2
}
struct Int {
a int
}
struct NestMixed {
s string
b Int
}
fn nested_test() {
x := Nest{'abc'}
assert x.a[1] == `b`
x2 := Nest2{Nest{'def'}}
assert x2.a.a[2] == `f`
x3 := Nest3{Nest2{Nest{'ghi'}}}
assert x3.a.a.a[1] == `h`
x4 := NestMixed{'abc', Int{3}}
assert x4.b.a == 3
}
fn main() { fn main() {
struct_test() struct_test()
return_test() return_test()
alias_test() alias_test()
assign_fields() assign_fields()
nested_test()
} }