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

native: move functions out of amd64.v (#18857)

This commit is contained in:
Eliyaan (Nopana) 2023-07-14 11:15:22 +02:00 committed by GitHub
parent a9a94cfd51
commit 3081919a8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 200 additions and 260 deletions

View File

@ -530,7 +530,9 @@ fn (mut c Amd64) movabs(r Register, val i64) {
c.g.println('movabs ${reg}, ${val}')
}
fn (mut c Amd64) mov_deref(reg Amd64Register, regptr Amd64Register, typ ast.Type) {
fn (mut c Amd64) mov_deref(r Register, rptr Register, typ ast.Type) {
reg := r as Amd64Register
regptr := rptr as Amd64Register
size := c.g.get_type_size(typ)
if size !in [1, 2, 4, 8] {
c.g.n_error('Invalid size on dereferencing')
@ -1038,7 +1040,8 @@ pub fn (mut c Amd64) sub(reg Amd64Register, val int) {
c.g.println('sub ${reg},${val.hex2()}')
}
pub fn (mut c Amd64) add(reg Amd64Register, val int) {
pub fn (mut c Amd64) add(r Register, val int) {
reg := r as Amd64Register
c.g.write8(0x48)
if reg == .rax {
c.g.write8(0x05)
@ -1556,7 +1559,9 @@ fn (mut c Amd64) add_reg(a Amd64Register, b Amd64Register) {
c.g.println('add ${a}, ${b}')
}
fn (mut c Amd64) mov_reg_amd64(a Amd64Register, b Amd64Register) {
fn (mut c Amd64) mov_reg(a_reg Register, b_reg Register) {
a := a_reg as Amd64Register
b := b_reg as Amd64Register
if int(a) <= int(Amd64Register.r15) && int(b) <= int(Amd64Register.r15) {
c.g.write8(0x48 + if int(a) >= int(Amd64Register.r8) { 1 } else { 0 } +
if int(b) >= int(Amd64Register.r8) { 4 } else { 0 })
@ -1568,10 +1573,6 @@ fn (mut c Amd64) mov_reg_amd64(a Amd64Register, b Amd64Register) {
c.g.println('mov ${a}, ${b}')
}
fn (mut c Amd64) mov_reg(a Register, b Register) {
c.mov_reg_amd64(a as Amd64Register, b as Amd64Register)
}
fn (mut c Amd64) add_store(a Amd64Register, b Amd64Register, size Size) {
if size == ._16 {
c.g.write8(0x66)
@ -1727,17 +1728,17 @@ pub fn (mut c Amd64) call_fn(node ast.CallExpr) {
if c.g.table.sym(args[i].typ).kind == .struct_ && !args[i].typ.is_ptr() {
match args_size[i] {
1...8 {
c.mov_deref(.rax, .rax, ast.i64_type_idx)
c.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.i64_type_idx)
if args_size[i] != 8 {
c.movabs(Amd64Register.rdx, i64((u64(1) << (args_size[i] * 8)) - 1))
c.bitand_reg(.rax, .rdx)
}
}
9...16 {
c.add(.rax, 8)
c.mov_deref(.rdx, .rax, ast.i64_type_idx)
c.add(Amd64Register.rax, 8)
c.mov_deref(Amd64Register.rdx, Amd64Register.rax, ast.i64_type_idx)
c.sub(.rax, 8)
c.mov_deref(.rax, .rax, ast.i64_type_idx)
c.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.i64_type_idx)
if args_size[i] != 16 {
c.movabs(Amd64Register.rbx, i64((u64(1) << ((args_size[i] - 8) * 8)) - 1))
c.bitand_reg(.rdx, .rbx)
@ -1762,9 +1763,9 @@ pub fn (mut c Amd64) call_fn(node ast.CallExpr) {
c.push(Amd64Register.rax)
}
else {
c.add(.rax, args_size[i] - ((args_size[i] + 7) % 8 + 1))
c.add(Amd64Register.rax, args_size[i] - ((args_size[i] + 7) % 8 + 1))
for _ in 0 .. (args_size[i] + 7) / 8 {
c.mov_deref(.rdx, .rax, ast.i64_type_idx)
c.mov_deref(Amd64Register.rdx, Amd64Register.rax, ast.i64_type_idx)
c.push(Amd64Register.rdx)
c.sub(.rax, 8)
}
@ -1855,55 +1856,6 @@ fn (mut c Amd64) call_builtin(name Builtin) i64 {
return call_addr
}
fn (mut c Amd64) gen_concat_expr(node ast.ConcatExpr) {
typ := node.return_type
ts := c.g.table.sym(typ)
size := c.g.get_type_size(typ)
// construct a struct variable contains the return value
var := LocalVar{
offset: c.g.allocate_by_type('', typ)
typ: typ
}
// zero fill
mut left := if size >= 16 {
c.mov(Amd64Register.rax, 0)
c.mov(Amd64Register.rcx, size / 8)
c.lea_var_to_reg(Amd64Register.rdi, var.offset)
c.g.write([u8(0xf3), 0x48, 0xab])
c.g.println('rep stosq')
size % 8
} else {
size
}
if left >= 8 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i64_type_idx)
left -= 8
}
if left >= 4 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.int_type_idx)
left -= 4
}
if left >= 2 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i16_type_idx)
left -= 2
}
if left == 1 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i8_type_idx)
}
// store exprs to the variable
for i, expr in node.vals {
offset := c.g.structs[typ.idx()].offsets[i]
c.g.expr(expr)
// TODO expr not on rax
c.mov_reg_to_var(var, c.main_reg(),
offset: offset
typ: ts.mr_info().types[i]
)
}
// store the multi return struct value
c.lea_var_to_reg(c.main_reg(), var.offset)
}
fn (mut c Amd64) assign_struct_var(ident_var IdentVar, typ ast.Type, s int) {
// struct types bigger are passed around as a pointer in rax.
// we need to dereference and copy the contents one after the other
@ -1917,48 +1869,48 @@ fn (mut c Amd64) assign_struct_var(ident_var IdentVar, typ ast.Type, s int) {
mut offset := 0
for size >= 8 {
c.mov_deref(.rbx, .rax, ast.u64_type_idx)
c.mov_deref(Amd64Register.rbx, Amd64Register.rax, ast.u64_type_idx)
c.mov_reg_to_var(var, Amd64Register.rbx,
offset: offset
typ: ast.u64_type_idx
)
c.add(.rax, 8)
c.add(Amd64Register.rax, 8)
size -= 8
offset += 8
}
if size >= 4 {
c.mov_deref(.rbx, .rax, ast.u32_type_idx)
c.mov_deref(Amd64Register.rbx, Amd64Register.rax, ast.u32_type_idx)
c.mov_reg_to_var(var, Amd64Register.rbx,
offset: offset
typ: ast.u32_type_idx
)
c.add(.rax, 4)
c.add(Amd64Register.rax, 4)
size -= 4
offset += 4
}
if size >= 2 {
c.mov_deref(.rbx, .rax, ast.u16_type_idx)
c.mov_deref(Amd64Register.rbx, Amd64Register.rax, ast.u16_type_idx)
c.mov_reg_to_var(var, Amd64Register.rbx,
offset: offset
typ: ast.u16_type_idx
)
c.add(.rax, 2)
c.add(Amd64Register.rax, 2)
size -= 2
offset += 2
}
if size == 1 {
c.mov_deref(.rbx, .rax, ast.u8_type_idx)
c.mov_deref(Amd64Register.rbx, Amd64Register.rax, ast.u8_type_idx)
c.mov_reg_to_var(var, Amd64Register.rbx,
offset: offset
typ: ast.u8_type_idx
)
c.add(.rax, 1)
c.add(Amd64Register.rax, 1)
size--
offset++
@ -1996,7 +1948,7 @@ fn (mut c Amd64) assign_int(node ast.AssignStmt, i int, name string, ident ast.I
match node.op {
.plus_assign {
c.mov_var_to_reg(Amd64Register.rax, ident)
c.add(.rax, int_lit.val.int())
c.add(Amd64Register.rax, int_lit.val.int())
c.mov_reg_to_var(ident, Amd64Register.rax)
}
.minus_assign {
@ -2177,7 +2129,7 @@ fn (mut c Amd64) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, n
c.lea_var_to_reg(Amd64Register.rax, dest)
c.mov_var_to_reg(Amd64Register.rdi, ie_ident)
c.add_reg(.rax, .rdi)
c.mov_deref(.rax, .rax, ast.i64_type_idx)
c.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.i64_type_idx)
} else {
c.g.n_error('only integers and idents can be used as indexes')
}
@ -2287,16 +2239,16 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
match ts.kind {
.struct_, .multi_return {
if size <= 8 {
c.mov_deref(.rax, .rax, ast.i64_type_idx)
c.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.i64_type_idx)
if size != 8 {
c.movabs(Amd64Register.rbx, i64((u64(1) << (size * 8)) - 1))
c.bitand_reg(.rax, .rbx)
}
} else if size <= 16 {
c.add(.rax, 8)
c.mov_deref(.rdx, .rax, ast.i64_type_idx)
c.add(Amd64Register.rax, 8)
c.mov_deref(Amd64Register.rdx, Amd64Register.rax, ast.i64_type_idx)
c.sub(.rax, 8)
c.mov_deref(.rax, .rax, ast.i64_type_idx)
c.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.i64_type_idx)
if size != 16 {
c.movabs(Amd64Register.rbx, i64((u64(1) << ((size - 8) * 8)) - 1))
c.bitand_reg(.rdx, .rbx)
@ -2308,17 +2260,17 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
typ: ast.i64_type_idx
})
for i in 0 .. size / 8 {
c.mov_deref(.rcx, .rax, ast.i64_type_idx)
c.mov_deref(Amd64Register.rcx, Amd64Register.rax, ast.i64_type_idx)
c.mov_store(.rdx, .rcx, ._64)
if i != size / 8 - 1 {
c.add(.rax, 8)
c.add(.rdx, 8)
c.add(Amd64Register.rax, 8)
c.add(Amd64Register.rdx, 8)
}
}
if size % 8 != 0 {
c.add(.rax, size % 8)
c.add(.rdx, size % 8)
c.mov_deref(.rcx, .rax, ast.i64_type_idx)
c.add(Amd64Register.rax, size % 8)
c.add(Amd64Register.rdx, size % 8)
c.mov_deref(Amd64Register.rcx, Amd64Register.rax, ast.i64_type_idx)
c.mov_store(.rdx, .rcx, ._64)
}
c.mov_var_to_reg(c.main_reg(), LocalVar{
@ -2340,32 +2292,9 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
offset: c.g.allocate_by_type('', typ)
typ: typ
}
// zero fill
mut left := if size >= 16 {
c.mov(Amd64Register.rax, 0)
c.mov(Amd64Register.rcx, size / 8)
c.lea_var_to_reg(Amd64Register.rdi, var.offset)
c.g.write([u8(0xf3), 0x48, 0xab])
c.g.println('rep stosq')
size % 8
} else {
size
}
if left >= 8 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i64_type_idx)
left -= 8
}
if left >= 4 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.int_type_idx)
left -= 4
}
if left >= 2 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i16_type_idx)
left -= 2
}
if left == 1 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i8_type_idx)
}
c.zero_fill(size, var)
// store exprs to the variable
for i, expr in node.exprs {
offset := c.g.structs[typ.idx()].offsets[i]
@ -2377,16 +2306,16 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
c.lea_var_to_reg(Amd64Register.rax, var.offset)
if c.g.pref.arch == .amd64 {
if size <= 8 {
c.mov_deref(.rax, .rax, ast.i64_type_idx)
c.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.i64_type_idx)
if size != 8 {
c.movabs(Amd64Register.rbx, i64((u64(1) << (size * 8)) - 1))
c.bitand_reg(.rax, .rbx)
}
} else if size <= 16 {
c.add(.rax, 8)
c.mov_deref(.rdx, .rax, ast.i64_type_idx)
c.sub(.rax, 8)
c.mov_deref(.rax, .rax, ast.i64_type_idx)
c.add(Amd64Register.rax, 8)
c.mov_deref(Amd64Register.rdx, Amd64Register.rax, ast.i64_type_idx)
c.sub(Amd64Register.rax, 8)
c.mov_deref(Amd64Register.rax, Amd64Register.rax, ast.i64_type_idx)
if size != 16 {
c.movabs(Amd64Register.rbx, i64((u64(1) << ((size - 8) * 8)) - 1))
c.bitand_reg(.rdx, .rbx)
@ -2398,17 +2327,17 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
typ: ast.i64_type_idx
})
for i in 0 .. size / 8 {
c.mov_deref(.rcx, .rax, ast.i64_type_idx)
c.mov_deref(Amd64Register.rcx, Amd64Register.rax, ast.i64_type_idx)
c.mov_store(.rdx, .rcx, ._64)
if i != size / 8 - 1 {
c.add(.rax, 8)
c.add(.rdx, 8)
c.add(Amd64Register.rax, 8)
c.add(Amd64Register.rdx, 8)
}
}
if size % 8 != 0 {
c.add(.rax, size % 8)
c.add(.rdx, size % 8)
c.mov_deref(.rcx, .rax, ast.i64_type_idx)
c.add(Amd64Register.rax, size % 8)
c.add(Amd64Register.rdx, size % 8)
c.mov_deref(Amd64Register.rcx, Amd64Register.rax, ast.i64_type_idx)
c.mov_store(.rdx, .rcx, ._64)
}
c.mov_var_to_reg(c.main_reg(), LocalVar{
@ -2441,32 +2370,9 @@ fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
var := LocalVar{
offset: c.g.stack_var_pos
}
// zero fill
mut left := if size >= 16 {
c.mov(Amd64Register.rax, 0)
c.mov(Amd64Register.rcx, size / 8)
c.lea_var_to_reg(Amd64Register.rdi, var.offset)
c.g.write([u8(0xf3), 0x48, 0xab])
c.g.println('rep stosq')
size % 8
} else {
size
}
if left >= 8 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i64_type_idx)
left -= 8
}
if left >= 4 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.int_type_idx)
left -= 4
}
if left >= 2 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i16_type_idx)
left -= 2
}
if left == 1 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i8_type_idx)
}
c.zero_fill(size, var)
// store exprs to the variable
for i, expr in node.right {
offset := multi_return.offsets[i]
@ -2493,14 +2399,14 @@ fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
}
}
if offset != current_offset {
c.add(.rdx, offset - current_offset)
c.add(Amd64Register.rdx, offset - current_offset)
current_offset = offset
}
c.gen_left_value(node.left[i])
c.g.gen_left_value(node.left[i])
left_type := node.left_types[i]
right_type := node.right_types[i]
if c.g.is_register_type(right_type) {
c.mov_deref(.rcx, .rdx, right_type)
c.mov_deref(Amd64Register.rcx, Amd64Register.rdx, right_type)
} else if node.right_types[i].is_pure_float() {
c.mov_deref_sse(.xmm0, .rdx, right_type)
}
@ -2580,7 +2486,7 @@ fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
if left is ast.Ident && node.op == .decl_assign {
c.g.allocate_by_type((left as ast.Ident).name, typ)
}
c.gen_left_value(left)
c.g.gen_left_value(left)
c.push(Amd64Register.rax)
c.g.expr(right)
c.pop(.rdx)
@ -2643,43 +2549,43 @@ fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
size := c.g.get_type_size(typ)
if size >= 8 {
for j in 0 .. size / 8 {
c.mov_deref(.rcx, .rdx, ast.u64_type_idx)
c.mov_deref(Amd64Register.rcx, Amd64Register.rdx, ast.u64_type_idx)
c.mov_store(.rax, .rcx, ._64)
offset := if j == size / 8 - 1 && size % 8 != 0 {
size % 8
} else {
8
}
c.add(.rax, offset)
c.add(.rdx, offset)
c.add(Amd64Register.rax, offset)
c.add(Amd64Register.rdx, offset)
}
if size % 8 != 0 {
c.mov_deref(.rcx, .rdx, ast.u64_type_idx)
c.mov_deref(Amd64Register.rcx, Amd64Register.rdx, ast.u64_type_idx)
c.mov_store(.rax, .rcx, ._64)
}
} else {
mut left_size := if size >= 4 {
c.mov_deref(.rcx, .rdx, ast.u32_type_idx)
c.mov_deref(Amd64Register.rcx, Amd64Register.rdx, ast.u32_type_idx)
c.mov_store(.rax, .rcx, ._32)
if size > 4 {
c.add(.rax, 4)
c.add(.rdx, 4)
c.add(Amd64Register.rax, 4)
c.add(Amd64Register.rdx, 4)
}
size - 4
} else {
size
}
if left_size >= 2 {
c.mov_deref(.rcx, .rdx, ast.u16_type_idx)
c.mov_deref(Amd64Register.rcx, Amd64Register.rdx, ast.u16_type_idx)
c.mov_store(.rax, .rcx, ._16)
if left_size > 2 {
c.add(.rax, 2)
c.add(.rdx, 2)
c.add(Amd64Register.rax, 2)
c.add(Amd64Register.rdx, 2)
}
left_size -= 2
}
if left_size == 1 {
c.mov_deref(.rcx, .rdx, ast.u8_type_idx)
c.mov_deref(Amd64Register.rcx, Amd64Register.rdx, ast.u8_type_idx)
c.mov_store(.rax, .rcx, ._8)
}
}
@ -2719,35 +2625,6 @@ fn (mut c Amd64) cset_op(op token.Kind) {
}
}
fn (mut c Amd64) gen_left_value(node ast.Expr) {
match node {
ast.Ident {
offset := c.g.get_var_offset(node.name)
c.lea_var_to_reg(Amd64Register.rax, offset)
}
ast.SelectorExpr {
c.g.expr(node.expr)
offset := c.g.get_field_offset(node.expr_type, node.field_name)
if offset != 0 {
c.add(.rax, offset)
}
}
ast.StructInit, ast.ArrayInit {
c.g.expr(node)
}
ast.IndexExpr {} // TODO
ast.PrefixExpr {
if node.op != .mul {
c.g.n_error('Unsupported left value')
}
c.g.expr(node.right)
}
else {
c.g.n_error('Unsupported left value')
}
}
}
fn (mut c Amd64) prefix_expr(node ast.PrefixExpr) {
match node.op {
.minus {
@ -2766,11 +2643,11 @@ fn (mut c Amd64) prefix_expr(node ast.PrefixExpr) {
}
}
.amp {
c.gen_left_value(node.right)
c.g.gen_left_value(node.right)
}
.mul {
c.g.expr(node.right)
c.mov_deref(.rax, .rax, node.right_type.deref())
c.mov_deref(Amd64Register.rax, Amd64Register.rax, node.right_type.deref())
}
.not {
c.g.expr(node.right)
@ -3072,29 +2949,6 @@ fn (mut c Amd64) gen_asm_stmt(asm_node ast.AsmStmt) {
}
}
fn (mut c Amd64) gen_selector_expr(expr ast.SelectorExpr) {
c.g.expr(expr.expr)
offset := c.g.get_field_offset(expr.expr_type, expr.field_name)
c.add(.rax, offset)
c.mov_deref(.rax, .rax, expr.typ)
}
fn (mut c Amd64) gen_assert(assert_node ast.AssertStmt) {
mut cjmp_addr := 0
ane := assert_node.expr
label := c.g.labels.new_label()
cjmp_addr = c.g.condition(ane, true)
c.g.labels.patches << LabelPatch{
id: label
pos: cjmp_addr
}
c.g.println('; jump to label ${label}')
c.g.expr(assert_node.expr)
c.trap()
c.g.labels.addrs[label] = c.g.pos()
c.g.println('; label ${label}')
}
fn (mut c Amd64) cjmp_notop(op token.Kind) int {
return match op {
.gt {
@ -3345,6 +3199,34 @@ pub fn (mut c Amd64) allocate_var(name string, size int, initial_val int) int {
return c.g.stack_var_pos
}
fn (mut c Amd64) zero_fill(size int, var LocalVar) {
mut left := if size >= 16 {
c.mov(Amd64Register.rax, 0)
c.mov(Amd64Register.rcx, size / 8)
c.lea_var_to_reg(Amd64Register.rdi, var.offset)
c.g.write([u8(0xf3), 0x48, 0xab])
c.g.println('rep stosq')
size % 8
} else {
size
}
if left >= 8 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i64_type_idx)
left -= 8
}
if left >= 4 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.int_type_idx)
left -= 4
}
if left >= 2 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i16_type_idx)
left -= 2
}
if left == 1 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i8_type_idx)
}
}
fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
match var {
ast.Ident {
@ -3366,32 +3248,7 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
typ := c.g.unwrap(var.typ)
size := c.g.get_type_size(typ)
// zero fill
mut left := if size >= 16 {
c.mov(Amd64Register.rax, 0)
c.mov(Amd64Register.rcx, size / 8)
c.lea_var_to_reg(Amd64Register.rdi, var.offset)
c.g.write([u8(0xf3), 0x48, 0xab])
c.g.println('rep stosq')
size % 8
} else {
size
}
if left >= 8 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i64_type_idx)
left -= 8
}
if left >= 4 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.int_type_idx)
left -= 4
}
if left >= 2 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i16_type_idx)
left -= 2
}
if left == 1 {
c.mov_int_to_var(var, 0, offset: size - left, typ: ast.i8_type_idx)
}
c.zero_fill(size, var)
ts := c.g.table.sym(typ)
match ts.info {
@ -3506,11 +3363,11 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) {
r2 := b as Amd64Register
if r1 != .rax {
c.mov_reg_amd64(.rax, r1)
c.mov_reg(Amd64Register.rax, r1)
}
if r2 != .rdi {
c.mov_reg_amd64(.rdi, r2)
c.mov_reg(Amd64Register.rdi, r2)
}
// check if value in rax is zero
@ -3566,7 +3423,7 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) {
c.g.labels.addrs[skip_minus_label] = c.g.pos()
c.g.println('; label ${skip_minus_label}')
c.mov_reg_amd64(.r12, .rdi) // copy the buffer position to r12
c.mov_reg(Amd64Register.r12, Amd64Register.rdi) // copy the buffer position to r12
loop_label := c.g.labels.new_label()
loop_start := c.g.pos()
@ -3608,7 +3465,7 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) {
// after all was converted, reverse the string
reg := c.g.get_builtin_arg_reg(.reverse_string, 0) as Amd64Register
c.mov_reg_amd64(reg, .r12)
c.mov_reg(reg, Amd64Register.r12)
c.g.call_builtin(.reverse_string)
c.g.labels.addrs[end_label] = c.g.pos()
@ -3619,7 +3476,7 @@ fn (mut c Amd64) reverse_string(r Register) {
reg := r as Amd64Register
if reg != .rdi {
c.mov_reg_amd64(.rdi, reg)
c.mov_reg(Amd64Register.rdi, reg)
}
c.mov(Amd64Register.eax, 0)
@ -3630,7 +3487,7 @@ fn (mut c Amd64) reverse_string(r Register) {
c.g.write8(0xff)
c.g.println('lea rcx, [rax-0x1]')
c.mov_reg_amd64(.rsi, .rdi)
c.mov_reg(Amd64Register.rsi, Amd64Register.rdi)
c.g.write8(0xf2)
c.g.write8(0xae)

View File

@ -430,10 +430,6 @@ fn (mut c Arm64) gen_asm_stmt(asm_node ast.AsmStmt) {
panic('Arm64.gen_asm_stmt() not implemented')
}
fn (mut c Arm64) gen_assert(assert_node ast.AssertStmt) {
panic('Arm64.gen_assert() not implemented')
}
fn (mut c Arm64) infloop() {
c.g.write32(u8(0x14))
c.g.println('jmp $$')
@ -515,12 +511,12 @@ fn (mut c Arm64) call(addr int) i64 {
panic('Arm64.call() not implemented')
}
fn (mut c Arm64) call_addr_at(addr int, at i64) i64 {
panic('Arm64.call_addr_at() not implemented')
fn (mut c Arm64) zero_fill(size int, var LocalVar) {
panic('Arm64.zero_fill() not implemented')
}
fn (mut c Arm64) gen_concat_expr(expr ast.ConcatExpr) {
panic('Arm64.gen_concat_expr() not implemented')
fn (mut c Arm64) call_addr_at(addr int, at i64) i64 {
panic('Arm64.call_addr_at() not implemented')
}
fn (mut c Arm64) cmp_to_stack_top(reg Register) {
@ -530,3 +526,11 @@ fn (mut c Arm64) cmp_to_stack_top(reg Register) {
fn (mut c Arm64) push(r Register) {
panic('Arm64.push() not implemented')
}
pub fn (mut c Arm64) add(r Register, val int) {
panic('Arm64.add() not implemented')
}
fn (mut c Arm64) mov_deref(reg Register, regptr Register, typ ast.Type) {
panic('Arm64.mov_deref() not implemented')
}

View File

@ -98,7 +98,7 @@ fn (mut g Gen) expr(node ast.Expr) {
g.code_gen.gen_match_expr(node)
}
ast.SelectorExpr {
g.code_gen.gen_selector_expr(node)
g.gen_selector_expr(node)
}
ast.CastExpr {
g.code_gen.gen_cast_expr(node)
@ -111,7 +111,7 @@ fn (mut g Gen) expr(node ast.Expr) {
g.expr(node.expr)
}
ast.ConcatExpr {
g.code_gen.gen_concat_expr(node)
g.gen_concat_expr(node)
}
ast.TypeOf {
g.gen_typeof_expr(node, false)
@ -420,3 +420,40 @@ 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) {
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)
}
fn (mut g Gen) gen_left_value(node ast.Expr) {
match node {
ast.Ident {
offset := g.get_var_offset(node.name)
g.code_gen.lea_var_to_reg(Amd64Register.rax, offset)
}
ast.SelectorExpr {
g.expr(node.expr)
offset := g.get_field_offset(node.expr_type, node.field_name)
if offset != 0 {
g.code_gen.add(Amd64Register.rax, offset)
}
}
ast.StructInit, ast.ArrayInit {
g.expr(node)
}
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')
}
}
}

View File

@ -67,6 +67,7 @@ mut:
interface CodeGen {
mut:
g &Gen
add(r Register, val int)
address_size() int
adr(r Arm64Register, delta int) // Note: Temporary!
allocate_var(name string, size int, initial_val int) int
@ -88,14 +89,11 @@ mut:
dec_var(var Var, config VarConfig)
fn_decl(node ast.FnDecl)
gen_asm_stmt(asm_node ast.AsmStmt)
gen_assert(assert_node ast.AssertStmt)
gen_cast_expr(expr ast.CastExpr)
gen_concat_expr(expr ast.ConcatExpr)
gen_exit(expr ast.Expr)
gen_match_expr(expr ast.MatchExpr)
gen_print_reg(r Register, n int, fd int)
gen_print(s string, fd int)
gen_selector_expr(expr ast.SelectorExpr)
gen_syscall(node ast.CallExpr)
inc_var(var Var, config VarConfig)
infix_expr(node ast.InfixExpr) // TODO: make platform-independant
@ -110,6 +108,7 @@ mut:
load_fp_var(var Var, config VarConfig)
load_fp(val f64)
main_reg() Register
mov_deref(reg Register, regptr Register, typ ast.Type)
mov_int_to_var(var Var, integer int, config VarConfig)
mov_reg_to_var(var Var, reg Register, config VarConfig)
mov_reg(r1 Register, r2 Register)
@ -125,6 +124,7 @@ mut:
svc()
syscall() // unix syscalls
trap()
zero_fill(size int, var LocalVar)
}
type Register = Amd64Register | Arm64Register
@ -1083,3 +1083,29 @@ pub fn (mut g Gen) v_error(s string, pos token.Pos) {
}
}
}
fn (mut g Gen) gen_concat_expr(node ast.ConcatExpr) {
typ := node.return_type
ts := g.table.sym(typ)
size := g.get_type_size(typ)
// construct a struct variable contains the return value
var := LocalVar{
offset: g.allocate_by_type('', typ)
typ: typ
}
g.code_gen.zero_fill(size, var)
main_reg := g.code_gen.main_reg()
// store exprs to the variable
for i, expr in node.vals {
offset := g.structs[typ.idx()].offsets[i]
g.expr(expr)
// TODO expr not on rax
g.code_gen.mov_reg_to_var(var, main_reg,
offset: offset
typ: ts.mr_info().types[i]
)
}
// store the multi return struct value
g.code_gen.lea_var_to_reg(main_reg, var.offset)
}

View File

@ -95,7 +95,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
g.code_gen.gen_asm_stmt(node)
}
ast.AssertStmt {
g.code_gen.gen_assert(node)
g.gen_assert(node)
}
ast.GlobalDecl {
g.warning('globals are not supported yet', node.pos)
@ -323,3 +323,19 @@ fn (mut g Gen) for_in_stmt(node ast.ForInStmt) { // Work on that
g.v_error('for-in statement is not yet implemented', node.pos)
}
}
fn (mut g Gen) gen_assert(assert_node ast.AssertStmt) {
mut cjmp_addr := 0
ane := assert_node.expr
label := g.labels.new_label()
cjmp_addr = g.condition(ane, true)
g.labels.patches << LabelPatch{
id: label
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}')
}