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}') 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) size := c.g.get_type_size(typ)
if size !in [1, 2, 4, 8] { if size !in [1, 2, 4, 8] {
c.g.n_error('Invalid size on dereferencing') 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()}') 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) c.g.write8(0x48)
if reg == .rax { if reg == .rax {
c.g.write8(0x05) c.g.write8(0x05)
@ -1556,7 +1559,9 @@ fn (mut c Amd64) add_reg(a Amd64Register, b Amd64Register) {
c.g.println('add ${a}, ${b}') 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) { if int(a) <= int(Amd64Register.r15) && int(b) <= int(Amd64Register.r15) {
c.g.write8(0x48 + if int(a) >= int(Amd64Register.r8) { 1 } else { 0 } + c.g.write8(0x48 + if int(a) >= int(Amd64Register.r8) { 1 } else { 0 } +
if int(b) >= int(Amd64Register.r8) { 4 } 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}') 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) { fn (mut c Amd64) add_store(a Amd64Register, b Amd64Register, size Size) {
if size == ._16 { if size == ._16 {
c.g.write8(0x66) 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() { if c.g.table.sym(args[i].typ).kind == .struct_ && !args[i].typ.is_ptr() {
match args_size[i] { match args_size[i] {
1...8 { 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 { if args_size[i] != 8 {
c.movabs(Amd64Register.rdx, i64((u64(1) << (args_size[i] * 8)) - 1)) c.movabs(Amd64Register.rdx, i64((u64(1) << (args_size[i] * 8)) - 1))
c.bitand_reg(.rax, .rdx) c.bitand_reg(.rax, .rdx)
} }
} }
9...16 { 9...16 {
c.add(.rax, 8) c.add(Amd64Register.rax, 8)
c.mov_deref(.rdx, .rax, ast.i64_type_idx) c.mov_deref(Amd64Register.rdx, Amd64Register.rax, ast.i64_type_idx)
c.sub(.rax, 8) 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 { if args_size[i] != 16 {
c.movabs(Amd64Register.rbx, i64((u64(1) << ((args_size[i] - 8) * 8)) - 1)) c.movabs(Amd64Register.rbx, i64((u64(1) << ((args_size[i] - 8) * 8)) - 1))
c.bitand_reg(.rdx, .rbx) c.bitand_reg(.rdx, .rbx)
@ -1762,9 +1763,9 @@ pub fn (mut c Amd64) call_fn(node ast.CallExpr) {
c.push(Amd64Register.rax) c.push(Amd64Register.rax)
} }
else { 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 { 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.push(Amd64Register.rdx)
c.sub(.rax, 8) c.sub(.rax, 8)
} }
@ -1855,55 +1856,6 @@ fn (mut c Amd64) call_builtin(name Builtin) i64 {
return call_addr 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) { 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. // struct types bigger are passed around as a pointer in rax.
// we need to dereference and copy the contents one after the other // 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 mut offset := 0
for size >= 8 { 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, c.mov_reg_to_var(var, Amd64Register.rbx,
offset: offset offset: offset
typ: ast.u64_type_idx typ: ast.u64_type_idx
) )
c.add(.rax, 8) c.add(Amd64Register.rax, 8)
size -= 8 size -= 8
offset += 8 offset += 8
} }
if size >= 4 { 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, c.mov_reg_to_var(var, Amd64Register.rbx,
offset: offset offset: offset
typ: ast.u32_type_idx typ: ast.u32_type_idx
) )
c.add(.rax, 4) c.add(Amd64Register.rax, 4)
size -= 4 size -= 4
offset += 4 offset += 4
} }
if size >= 2 { 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, c.mov_reg_to_var(var, Amd64Register.rbx,
offset: offset offset: offset
typ: ast.u16_type_idx typ: ast.u16_type_idx
) )
c.add(.rax, 2) c.add(Amd64Register.rax, 2)
size -= 2 size -= 2
offset += 2 offset += 2
} }
if size == 1 { 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, c.mov_reg_to_var(var, Amd64Register.rbx,
offset: offset offset: offset
typ: ast.u8_type_idx typ: ast.u8_type_idx
) )
c.add(.rax, 1) c.add(Amd64Register.rax, 1)
size-- size--
offset++ offset++
@ -1996,7 +1948,7 @@ fn (mut c Amd64) assign_int(node ast.AssignStmt, i int, name string, ident ast.I
match node.op { match node.op {
.plus_assign { .plus_assign {
c.mov_var_to_reg(Amd64Register.rax, ident) 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) c.mov_reg_to_var(ident, Amd64Register.rax)
} }
.minus_assign { .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.lea_var_to_reg(Amd64Register.rax, dest)
c.mov_var_to_reg(Amd64Register.rdi, ie_ident) c.mov_var_to_reg(Amd64Register.rdi, ie_ident)
c.add_reg(.rax, .rdi) 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 { } else {
c.g.n_error('only integers and idents can be used as indexes') 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 { match ts.kind {
.struct_, .multi_return { .struct_, .multi_return {
if size <= 8 { 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 { if size != 8 {
c.movabs(Amd64Register.rbx, i64((u64(1) << (size * 8)) - 1)) c.movabs(Amd64Register.rbx, i64((u64(1) << (size * 8)) - 1))
c.bitand_reg(.rax, .rbx) c.bitand_reg(.rax, .rbx)
} }
} else if size <= 16 { } else if size <= 16 {
c.add(.rax, 8) c.add(Amd64Register.rax, 8)
c.mov_deref(.rdx, .rax, ast.i64_type_idx) c.mov_deref(Amd64Register.rdx, Amd64Register.rax, ast.i64_type_idx)
c.sub(.rax, 8) 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 { if size != 16 {
c.movabs(Amd64Register.rbx, i64((u64(1) << ((size - 8) * 8)) - 1)) c.movabs(Amd64Register.rbx, i64((u64(1) << ((size - 8) * 8)) - 1))
c.bitand_reg(.rdx, .rbx) c.bitand_reg(.rdx, .rbx)
@ -2308,17 +2260,17 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
typ: ast.i64_type_idx typ: ast.i64_type_idx
}) })
for i in 0 .. size / 8 { 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) c.mov_store(.rdx, .rcx, ._64)
if i != size / 8 - 1 { if i != size / 8 - 1 {
c.add(.rax, 8) c.add(Amd64Register.rax, 8)
c.add(.rdx, 8) c.add(Amd64Register.rdx, 8)
} }
} }
if size % 8 != 0 { if size % 8 != 0 {
c.add(.rax, size % 8) c.add(Amd64Register.rax, size % 8)
c.add(.rdx, size % 8) c.add(Amd64Register.rdx, 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) c.mov_store(.rdx, .rcx, ._64)
} }
c.mov_var_to_reg(c.main_reg(), LocalVar{ 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) offset: c.g.allocate_by_type('', typ)
typ: typ typ: typ
} }
// zero fill
mut left := if size >= 16 { c.zero_fill(size, var)
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 // store exprs to the variable
for i, expr in node.exprs { for i, expr in node.exprs {
offset := c.g.structs[typ.idx()].offsets[i] 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) c.lea_var_to_reg(Amd64Register.rax, var.offset)
if c.g.pref.arch == .amd64 { if c.g.pref.arch == .amd64 {
if size <= 8 { 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 { if size != 8 {
c.movabs(Amd64Register.rbx, i64((u64(1) << (size * 8)) - 1)) c.movabs(Amd64Register.rbx, i64((u64(1) << (size * 8)) - 1))
c.bitand_reg(.rax, .rbx) c.bitand_reg(.rax, .rbx)
} }
} else if size <= 16 { } else if size <= 16 {
c.add(.rax, 8) c.add(Amd64Register.rax, 8)
c.mov_deref(.rdx, .rax, ast.i64_type_idx) c.mov_deref(Amd64Register.rdx, Amd64Register.rax, ast.i64_type_idx)
c.sub(.rax, 8) c.sub(Amd64Register.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 { if size != 16 {
c.movabs(Amd64Register.rbx, i64((u64(1) << ((size - 8) * 8)) - 1)) c.movabs(Amd64Register.rbx, i64((u64(1) << ((size - 8) * 8)) - 1))
c.bitand_reg(.rdx, .rbx) c.bitand_reg(.rdx, .rbx)
@ -2398,17 +2327,17 @@ fn (mut c Amd64) return_stmt(node ast.Return) {
typ: ast.i64_type_idx typ: ast.i64_type_idx
}) })
for i in 0 .. size / 8 { 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) c.mov_store(.rdx, .rcx, ._64)
if i != size / 8 - 1 { if i != size / 8 - 1 {
c.add(.rax, 8) c.add(Amd64Register.rax, 8)
c.add(.rdx, 8) c.add(Amd64Register.rdx, 8)
} }
} }
if size % 8 != 0 { if size % 8 != 0 {
c.add(.rax, size % 8) c.add(Amd64Register.rax, size % 8)
c.add(.rdx, size % 8) c.add(Amd64Register.rdx, 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) c.mov_store(.rdx, .rcx, ._64)
} }
c.mov_var_to_reg(c.main_reg(), LocalVar{ 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{ var := LocalVar{
offset: c.g.stack_var_pos offset: c.g.stack_var_pos
} }
// zero fill
mut left := if size >= 16 { c.zero_fill(size, var)
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 // store exprs to the variable
for i, expr in node.right { for i, expr in node.right {
offset := multi_return.offsets[i] offset := multi_return.offsets[i]
@ -2493,14 +2399,14 @@ fn (mut c Amd64) multi_assign_stmt(node ast.AssignStmt) {
} }
} }
if offset != current_offset { if offset != current_offset {
c.add(.rdx, offset - current_offset) c.add(Amd64Register.rdx, offset - current_offset)
current_offset = 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] left_type := node.left_types[i]
right_type := node.right_types[i] right_type := node.right_types[i]
if c.g.is_register_type(right_type) { 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() { } else if node.right_types[i].is_pure_float() {
c.mov_deref_sse(.xmm0, .rdx, right_type) 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 { if left is ast.Ident && node.op == .decl_assign {
c.g.allocate_by_type((left as ast.Ident).name, typ) 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.push(Amd64Register.rax)
c.g.expr(right) c.g.expr(right)
c.pop(.rdx) c.pop(.rdx)
@ -2643,43 +2549,43 @@ fn (mut c Amd64) assign_stmt(node ast.AssignStmt) {
size := c.g.get_type_size(typ) size := c.g.get_type_size(typ)
if size >= 8 { if size >= 8 {
for j in 0 .. 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) c.mov_store(.rax, .rcx, ._64)
offset := if j == size / 8 - 1 && size % 8 != 0 { offset := if j == size / 8 - 1 && size % 8 != 0 {
size % 8 size % 8
} else { } else {
8 8
} }
c.add(.rax, offset) c.add(Amd64Register.rax, offset)
c.add(.rdx, offset) c.add(Amd64Register.rdx, offset)
} }
if size % 8 != 0 { 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) c.mov_store(.rax, .rcx, ._64)
} }
} else { } else {
mut left_size := if size >= 4 { 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) c.mov_store(.rax, .rcx, ._32)
if size > 4 { if size > 4 {
c.add(.rax, 4) c.add(Amd64Register.rax, 4)
c.add(.rdx, 4) c.add(Amd64Register.rdx, 4)
} }
size - 4 size - 4
} else { } else {
size size
} }
if left_size >= 2 { 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) c.mov_store(.rax, .rcx, ._16)
if left_size > 2 { if left_size > 2 {
c.add(.rax, 2) c.add(Amd64Register.rax, 2)
c.add(.rdx, 2) c.add(Amd64Register.rdx, 2)
} }
left_size -= 2 left_size -= 2
} }
if left_size == 1 { 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) 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) { fn (mut c Amd64) prefix_expr(node ast.PrefixExpr) {
match node.op { match node.op {
.minus { .minus {
@ -2766,11 +2643,11 @@ fn (mut c Amd64) prefix_expr(node ast.PrefixExpr) {
} }
} }
.amp { .amp {
c.gen_left_value(node.right) c.g.gen_left_value(node.right)
} }
.mul { .mul {
c.g.expr(node.right) 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 { .not {
c.g.expr(node.right) 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 { fn (mut c Amd64) cjmp_notop(op token.Kind) int {
return match op { return match op {
.gt { .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 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) { fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
match var { match var {
ast.Ident { ast.Ident {
@ -3366,32 +3248,7 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
typ := c.g.unwrap(var.typ) typ := c.g.unwrap(var.typ)
size := c.g.get_type_size(typ) size := c.g.get_type_size(typ)
// zero fill c.zero_fill(size, var)
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)
}
ts := c.g.table.sym(typ) ts := c.g.table.sym(typ)
match ts.info { match ts.info {
@ -3506,11 +3363,11 @@ fn (mut c Amd64) convert_int_to_string(a Register, b Register) {
r2 := b as Amd64Register r2 := b as Amd64Register
if r1 != .rax { if r1 != .rax {
c.mov_reg_amd64(.rax, r1) c.mov_reg(Amd64Register.rax, r1)
} }
if r2 != .rdi { if r2 != .rdi {
c.mov_reg_amd64(.rdi, r2) c.mov_reg(Amd64Register.rdi, r2)
} }
// check if value in rax is zero // 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.labels.addrs[skip_minus_label] = c.g.pos()
c.g.println('; label ${skip_minus_label}') 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_label := c.g.labels.new_label()
loop_start := c.g.pos() 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 // after all was converted, reverse the string
reg := c.g.get_builtin_arg_reg(.reverse_string, 0) as Amd64Register 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.call_builtin(.reverse_string)
c.g.labels.addrs[end_label] = c.g.pos() 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 reg := r as Amd64Register
if reg != .rdi { if reg != .rdi {
c.mov_reg_amd64(.rdi, reg) c.mov_reg(Amd64Register.rdi, reg)
} }
c.mov(Amd64Register.eax, 0) c.mov(Amd64Register.eax, 0)
@ -3630,7 +3487,7 @@ fn (mut c Amd64) reverse_string(r Register) {
c.g.write8(0xff) c.g.write8(0xff)
c.g.println('lea rcx, [rax-0x1]') 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(0xf2)
c.g.write8(0xae) 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') 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() { fn (mut c Arm64) infloop() {
c.g.write32(u8(0x14)) c.g.write32(u8(0x14))
c.g.println('jmp $$') c.g.println('jmp $$')
@ -515,12 +511,12 @@ fn (mut c Arm64) call(addr int) i64 {
panic('Arm64.call() not implemented') panic('Arm64.call() not implemented')
} }
fn (mut c Arm64) call_addr_at(addr int, at i64) i64 { fn (mut c Arm64) zero_fill(size int, var LocalVar) {
panic('Arm64.call_addr_at() not implemented') panic('Arm64.zero_fill() not implemented')
} }
fn (mut c Arm64) gen_concat_expr(expr ast.ConcatExpr) { fn (mut c Arm64) call_addr_at(addr int, at i64) i64 {
panic('Arm64.gen_concat_expr() not implemented') panic('Arm64.call_addr_at() not implemented')
} }
fn (mut c Arm64) cmp_to_stack_top(reg Register) { 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) { fn (mut c Arm64) push(r Register) {
panic('Arm64.push() not implemented') 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) g.code_gen.gen_match_expr(node)
} }
ast.SelectorExpr { ast.SelectorExpr {
g.code_gen.gen_selector_expr(node) g.gen_selector_expr(node)
} }
ast.CastExpr { ast.CastExpr {
g.code_gen.gen_cast_expr(node) g.code_gen.gen_cast_expr(node)
@ -111,7 +111,7 @@ fn (mut g Gen) expr(node ast.Expr) {
g.expr(node.expr) g.expr(node.expr)
} }
ast.ConcatExpr { ast.ConcatExpr {
g.code_gen.gen_concat_expr(node) g.gen_concat_expr(node)
} }
ast.TypeOf { ast.TypeOf {
g.gen_typeof_expr(node, false) 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 { interface CodeGen {
mut: mut:
g &Gen g &Gen
add(r Register, val int)
address_size() int address_size() int
adr(r Arm64Register, delta int) // Note: Temporary! adr(r Arm64Register, delta int) // Note: Temporary!
allocate_var(name string, size int, initial_val int) int allocate_var(name string, size int, initial_val int) int
@ -88,14 +89,11 @@ mut:
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)
gen_assert(assert_node ast.AssertStmt)
gen_cast_expr(expr ast.CastExpr) gen_cast_expr(expr ast.CastExpr)
gen_concat_expr(expr ast.ConcatExpr)
gen_exit(expr ast.Expr) gen_exit(expr ast.Expr)
gen_match_expr(expr ast.MatchExpr) gen_match_expr(expr ast.MatchExpr)
gen_print_reg(r Register, n int, fd int) gen_print_reg(r Register, n int, fd int)
gen_print(s string, fd int) gen_print(s string, fd int)
gen_selector_expr(expr ast.SelectorExpr)
gen_syscall(node ast.CallExpr) gen_syscall(node ast.CallExpr)
inc_var(var Var, config VarConfig) inc_var(var Var, config VarConfig)
infix_expr(node ast.InfixExpr) // TODO: make platform-independant infix_expr(node ast.InfixExpr) // TODO: make platform-independant
@ -110,6 +108,7 @@ mut:
load_fp_var(var Var, config VarConfig) load_fp_var(var Var, config VarConfig)
load_fp(val f64) load_fp(val f64)
main_reg() Register main_reg() Register
mov_deref(reg Register, regptr Register, typ ast.Type)
mov_int_to_var(var Var, integer int, config VarConfig) mov_int_to_var(var Var, integer int, config VarConfig)
mov_reg_to_var(var Var, reg Register, config VarConfig) mov_reg_to_var(var Var, reg Register, config VarConfig)
mov_reg(r1 Register, r2 Register) mov_reg(r1 Register, r2 Register)
@ -125,6 +124,7 @@ mut:
svc() svc()
syscall() // unix syscalls syscall() // unix syscalls
trap() trap()
zero_fill(size int, var LocalVar)
} }
type Register = Amd64Register | Arm64Register 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) g.code_gen.gen_asm_stmt(node)
} }
ast.AssertStmt { ast.AssertStmt {
g.code_gen.gen_assert(node) g.gen_assert(node)
} }
ast.GlobalDecl { ast.GlobalDecl {
g.warning('globals are not supported yet', node.pos) 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) 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}')
}