mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
native: split codegen into multiple files and refactor assign statement generation (#18546)
This commit is contained in:
parent
e9960339f9
commit
31f68eea94
@ -1,3 +1,6 @@
|
|||||||
|
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
module native
|
module native
|
||||||
|
|
||||||
import arrays
|
import arrays
|
||||||
@ -648,6 +651,7 @@ fn (mut c Amd64) mov_reg_to_var(var Var, r Register, config VarConfig) {
|
|||||||
far_var_offset := if is_far_var { 0x40 } else { 0 }
|
far_var_offset := if is_far_var { 0x40 } else { 0 }
|
||||||
match reg {
|
match reg {
|
||||||
.eax, .rax, .r8 { c.g.write8(0x45 + far_var_offset) }
|
.eax, .rax, .r8 { c.g.write8(0x45 + far_var_offset) }
|
||||||
|
.rbx { c.g.write8(0x5d + far_var_offset) }
|
||||||
.edi, .rdi { c.g.write8(0x7d + far_var_offset) }
|
.edi, .rdi { c.g.write8(0x7d + far_var_offset) }
|
||||||
.rsi { c.g.write8(0x75 + far_var_offset) }
|
.rsi { c.g.write8(0x75 + far_var_offset) }
|
||||||
.rdx { c.g.write8(0x55 + far_var_offset) }
|
.rdx { c.g.write8(0x55 + far_var_offset) }
|
||||||
@ -1942,267 +1946,150 @@ fn (mut c Amd64) gen_concat_expr(node ast.ConcatExpr) {
|
|||||||
c.lea_var_to_reg(c.main_reg(), var.offset)
|
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) {
|
||||||
// TODO: this *must* be done better and platform independant
|
// struct types bigger are passed around as a pointer in rax.
|
||||||
// !!!!!
|
// we need to dereference and copy the contents one after the other
|
||||||
fn (mut c Amd64) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, name string, ident ast.Ident) {
|
if ident_var !is LocalVar {
|
||||||
match right {
|
c.g.n_error('cannot assign struct to global var or register yet')
|
||||||
ast.IntegerLiteral {
|
}
|
||||||
// c.allocate_var(name, 4, right.val.int())
|
|
||||||
match node.op {
|
var := ident_var as LocalVar
|
||||||
.plus_assign {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, ident)
|
mut size := s
|
||||||
c.add(.rax, right.val.int())
|
|
||||||
|
mut offset := 0
|
||||||
|
for size >= 8 {
|
||||||
|
c.mov_deref(.rbx, .rax, ast.u64_type_idx)
|
||||||
|
c.mov_reg_to_var(var, Amd64Register.rbx,
|
||||||
|
offset: offset
|
||||||
|
typ: ast.u64_type_idx
|
||||||
|
)
|
||||||
|
c.add(.rax, 8)
|
||||||
|
|
||||||
|
size -= 8
|
||||||
|
offset += 8
|
||||||
|
}
|
||||||
|
|
||||||
|
if size >= 4 {
|
||||||
|
c.mov_deref(.rbx, .rax, ast.u32_type_idx)
|
||||||
|
c.mov_reg_to_var(var, Amd64Register.rbx,
|
||||||
|
offset: offset
|
||||||
|
typ: ast.u32_type_idx
|
||||||
|
)
|
||||||
|
c.add(.rax, 4)
|
||||||
|
|
||||||
|
size -= 4
|
||||||
|
offset += 4
|
||||||
|
}
|
||||||
|
|
||||||
|
if size >= 2 {
|
||||||
|
c.mov_deref(.rbx, .rax, ast.u16_type_idx)
|
||||||
|
c.mov_reg_to_var(var, Amd64Register.rbx,
|
||||||
|
offset: offset
|
||||||
|
typ: ast.u16_type_idx
|
||||||
|
)
|
||||||
|
c.add(.rax, 2)
|
||||||
|
|
||||||
|
size -= 2
|
||||||
|
offset += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if size == 1 {
|
||||||
|
c.mov_deref(.rbx, .rax, ast.u8_type_idx)
|
||||||
|
c.mov_reg_to_var(var, Amd64Register.rbx,
|
||||||
|
offset: offset
|
||||||
|
typ: ast.u8_type_idx
|
||||||
|
)
|
||||||
|
c.add(.rax, 1)
|
||||||
|
|
||||||
|
size--
|
||||||
|
offset++
|
||||||
|
}
|
||||||
|
|
||||||
|
assert size == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut c Amd64) assign_var(var IdentVar, typ ast.Type) {
|
||||||
|
size := c.g.get_type_size(typ)
|
||||||
|
if typ.is_pure_float() {
|
||||||
|
match var {
|
||||||
|
LocalVar { c.mov_ssereg_to_var(var as LocalVar, .xmm0) }
|
||||||
|
GlobalVar { c.mov_ssereg_to_var(var as GlobalVar, .xmm0) }
|
||||||
|
// Amd64Register { c.g.mov_ssereg(var as Amd64Register, .xmm0) }
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
} else if c.g.table.sym(typ).info is ast.Struct && !typ.is_any_kind_of_pointer() {
|
||||||
|
c.assign_struct_var(var, typ, size)
|
||||||
|
} else if size in [1, 2, 4, 8] {
|
||||||
|
match var {
|
||||||
|
LocalVar { c.mov_reg_to_var(var as LocalVar, Amd64Register.rax) }
|
||||||
|
GlobalVar { c.mov_reg_to_var(var as GlobalVar, Amd64Register.rax) }
|
||||||
|
Register { c.mov_reg(var as Amd64Register, Amd64Register.rax) }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.g.n_error('error assigning type ${typ} with size ${size}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut c Amd64) assign_int(node ast.AssignStmt, i int, name string, ident ast.Ident, int_lit ast.IntegerLiteral) {
|
||||||
|
match node.op {
|
||||||
|
.plus_assign {
|
||||||
|
c.mov_var_to_reg(Amd64Register.rax, ident)
|
||||||
|
c.add(.rax, int_lit.val.int())
|
||||||
|
c.mov_reg_to_var(ident, Amd64Register.rax)
|
||||||
|
}
|
||||||
|
.minus_assign {
|
||||||
|
c.mov_var_to_reg(Amd64Register.rax, ident)
|
||||||
|
c.sub(.rax, int_lit.val.int())
|
||||||
|
c.mov_reg_to_var(ident, Amd64Register.rax)
|
||||||
|
}
|
||||||
|
.mult_assign {
|
||||||
|
c.mov_var_to_reg(Amd64Register.rax, ident)
|
||||||
|
c.mov64(Amd64Register.rdx, int_lit.val.int())
|
||||||
|
c.mul_reg(.rax, .rdx)
|
||||||
|
c.mov_reg_to_var(ident, Amd64Register.rax)
|
||||||
|
}
|
||||||
|
.div_assign {
|
||||||
|
c.mov_var_to_reg(Amd64Register.rax, ident)
|
||||||
|
c.mov64(Amd64Register.rdx, int_lit.val.int())
|
||||||
|
c.div_reg(.rax, .rdx)
|
||||||
|
c.mov_reg_to_var(ident, Amd64Register.rax)
|
||||||
|
}
|
||||||
|
.decl_assign {
|
||||||
|
c.allocate_var(name, 8, int_lit.val.int())
|
||||||
|
}
|
||||||
|
.assign {
|
||||||
|
match node.left[i] {
|
||||||
|
ast.Ident {
|
||||||
|
c.mov(Amd64Register.rax, int_lit.val.int())
|
||||||
c.mov_reg_to_var(ident, Amd64Register.rax)
|
c.mov_reg_to_var(ident, Amd64Register.rax)
|
||||||
}
|
}
|
||||||
.minus_assign {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, ident)
|
|
||||||
c.sub(.rax, right.val.int())
|
|
||||||
c.mov_reg_to_var(ident, Amd64Register.rax)
|
|
||||||
}
|
|
||||||
.mult_assign {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, ident)
|
|
||||||
c.mov64(Amd64Register.rdx, right.val.int())
|
|
||||||
c.mul_reg(.rax, .rdx)
|
|
||||||
c.mov_reg_to_var(ident, Amd64Register.rax)
|
|
||||||
}
|
|
||||||
.div_assign {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, ident)
|
|
||||||
c.mov64(Amd64Register.rdx, right.val.int())
|
|
||||||
c.div_reg(.rax, .rdx)
|
|
||||||
c.mov_reg_to_var(ident, Amd64Register.rax)
|
|
||||||
}
|
|
||||||
.decl_assign {
|
|
||||||
c.allocate_var(name, 8, right.val.int())
|
|
||||||
}
|
|
||||||
.assign {
|
|
||||||
// dump(c.g.typ(node.left_types[i]))
|
|
||||||
match node.left[i] {
|
|
||||||
ast.Ident {
|
|
||||||
// lname := '${node.left[i]}'
|
|
||||||
// c.g.expr(node.right[i])
|
|
||||||
c.mov(Amd64Register.rax, right.val.int())
|
|
||||||
c.mov_reg_to_var(ident, Amd64Register.rax)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tn := node.left[i].type_name()
|
|
||||||
dump(node.left_types)
|
|
||||||
c.g.n_error('unhandled assign type: ${tn}')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
eprintln('ERROR 2')
|
tn := node.left[i].type_name()
|
||||||
dump(node)
|
dump(node.left_types)
|
||||||
|
c.g.n_error('unhandled assign type: ${tn}')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.Ident {
|
else {
|
||||||
// eprintln('identr') dump(node) dump(right)
|
c.g.n_error('unexpected assignment op ${node.op}')
|
||||||
match node.op {
|
}
|
||||||
.plus_assign {
|
}
|
||||||
c.mov_var_to_reg(Amd64Register.rax, ident)
|
}
|
||||||
c.mov_var_to_reg(Amd64Register.rbx, right as ast.Ident)
|
|
||||||
c.add_reg(.rax, .rbx)
|
fn (mut c Amd64) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, name string, ident ast.Ident) {
|
||||||
c.mov_reg_to_var(ident, Amd64Register.rax)
|
match right {
|
||||||
}
|
ast.IntegerLiteral {
|
||||||
.minus_assign {
|
c.assign_int(node, i, name, ident, right)
|
||||||
c.mov_var_to_reg(Amd64Register.rax, ident)
|
return
|
||||||
c.mov_var_to_reg(Amd64Register.rbx, right as ast.Ident)
|
}
|
||||||
c.sub_reg(.rax, .rbx)
|
ast.StringLiteral {
|
||||||
c.mov_reg_to_var(ident, Amd64Register.rax)
|
dest := c.allocate_var(name, 8, 0)
|
||||||
}
|
ie := right as ast.StringLiteral
|
||||||
.div_assign {
|
str := c.g.eval_str_lit_escape_codes(ie)
|
||||||
// this should be called when `a /= b` but it's not :?
|
c.learel(Amd64Register.rsi, c.g.allocate_string(str, 3, .rel32))
|
||||||
c.mov_var_to_reg(Amd64Register.rax, ident)
|
c.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, Amd64Register.rsi)
|
||||||
c.mov_var_to_reg(Amd64Register.rbx, right as ast.Ident)
|
return
|
||||||
c.div_reg(.rax, .rbx)
|
|
||||||
c.mov_reg_to_var(ident, Amd64Register.rax)
|
|
||||||
}
|
|
||||||
.decl_assign {
|
|
||||||
typ := node.left_types[i]
|
|
||||||
if typ.is_number() || typ.is_any_kind_of_pointer() || typ.is_bool() {
|
|
||||||
c.allocate_var(name, c.g.get_type_size(typ), 0)
|
|
||||||
} else {
|
|
||||||
ts := c.g.table.sym(typ)
|
|
||||||
match ts.info {
|
|
||||||
ast.Struct {
|
|
||||||
c.g.allocate_by_type(name, typ)
|
|
||||||
}
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var_ := c.g.get_var_from_ident(ident)
|
|
||||||
// TODO global var
|
|
||||||
right_var := c.g.get_var_from_ident(right) as LocalVar
|
|
||||||
match var_ {
|
|
||||||
LocalVar {
|
|
||||||
var := var_ as LocalVar
|
|
||||||
if var.typ.is_number() || var.typ.is_any_kind_of_pointer()
|
|
||||||
|| var.typ.is_bool() {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, right as ast.Ident)
|
|
||||||
c.mov_reg_to_var(ident, Amd64Register.rax)
|
|
||||||
} else {
|
|
||||||
ts := c.g.table.sym(var.typ)
|
|
||||||
match ts.info {
|
|
||||||
ast.Struct {
|
|
||||||
size := c.g.get_type_size(var.typ)
|
|
||||||
if size >= 8 {
|
|
||||||
for offset in 0 .. size / 8 {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, right_var,
|
|
||||||
offset: offset * 8
|
|
||||||
typ: ast.i64_type_idx
|
|
||||||
)
|
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax,
|
|
||||||
offset: offset * 8
|
|
||||||
typ: ast.i64_type_idx
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if size % 8 != 0 {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, right_var,
|
|
||||||
offset: size - 8
|
|
||||||
typ: ast.i64_type_idx
|
|
||||||
)
|
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax,
|
|
||||||
offset: size - 8
|
|
||||||
typ: ast.i64_type_idx
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mut left_size := if size >= 4 {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, right_var,
|
|
||||||
typ: ast.int_type_idx
|
|
||||||
)
|
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax,
|
|
||||||
typ: ast.int_type_idx
|
|
||||||
)
|
|
||||||
size - 4
|
|
||||||
} else {
|
|
||||||
size
|
|
||||||
}
|
|
||||||
if left_size >= 2 {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, right_var,
|
|
||||||
offset: size - left_size
|
|
||||||
typ: ast.i16_type_idx
|
|
||||||
)
|
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax,
|
|
||||||
offset: size - left_size
|
|
||||||
typ: ast.i16_type_idx
|
|
||||||
)
|
|
||||||
left_size -= 2
|
|
||||||
}
|
|
||||||
if left_size == 1 {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, right_var,
|
|
||||||
offset: size - left_size
|
|
||||||
typ: ast.i8_type_idx
|
|
||||||
)
|
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax,
|
|
||||||
offset: size - left_size
|
|
||||||
typ: ast.i8_type_idx
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
c.g.n_error('Unsupported variable type')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
c.g.n_error('Unsupported variable kind')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.assign {
|
|
||||||
var_ := c.g.get_var_from_ident(ident)
|
|
||||||
// TODO global var
|
|
||||||
right_var := c.g.get_var_from_ident(right) as LocalVar
|
|
||||||
match var_ {
|
|
||||||
LocalVar {
|
|
||||||
var := var_ as LocalVar
|
|
||||||
if var.typ.is_number() || var.typ.is_any_kind_of_pointer()
|
|
||||||
|| var.typ.is_bool() {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, right as ast.Ident)
|
|
||||||
c.mov_reg_to_var(ident, Amd64Register.rax)
|
|
||||||
} else {
|
|
||||||
ts := c.g.table.sym(var.typ)
|
|
||||||
match ts.info {
|
|
||||||
ast.Struct {
|
|
||||||
size := c.g.get_type_size(var.typ)
|
|
||||||
if size >= 8 {
|
|
||||||
for offset in 0 .. size / 8 {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, right_var,
|
|
||||||
offset: offset * 8
|
|
||||||
typ: ast.i64_type_idx
|
|
||||||
)
|
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax,
|
|
||||||
offset: offset * 8
|
|
||||||
typ: ast.i64_type_idx
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if size % 8 != 0 {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, right_var,
|
|
||||||
offset: size - 8
|
|
||||||
typ: ast.i64_type_idx
|
|
||||||
)
|
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax,
|
|
||||||
offset: size - 8
|
|
||||||
typ: ast.i64_type_idx
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mut left_size := if size >= 4 {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, right_var,
|
|
||||||
typ: ast.int_type_idx
|
|
||||||
)
|
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax,
|
|
||||||
typ: ast.int_type_idx
|
|
||||||
)
|
|
||||||
size - 4
|
|
||||||
} else {
|
|
||||||
size
|
|
||||||
}
|
|
||||||
if left_size >= 2 {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, right_var,
|
|
||||||
offset: size - left_size
|
|
||||||
typ: ast.i16_type_idx
|
|
||||||
)
|
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax,
|
|
||||||
offset: size - left_size
|
|
||||||
typ: ast.i16_type_idx
|
|
||||||
)
|
|
||||||
left_size -= 2
|
|
||||||
}
|
|
||||||
if left_size == 1 {
|
|
||||||
c.mov_var_to_reg(Amd64Register.rax, right_var,
|
|
||||||
offset: size - left_size
|
|
||||||
typ: ast.i8_type_idx
|
|
||||||
)
|
|
||||||
c.mov_reg_to_var(var, Amd64Register.rax,
|
|
||||||
offset: size - left_size
|
|
||||||
typ: ast.i8_type_idx
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
c.g.n_error('Unsupported variable type')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
c.g.n_error('Unsupported variable kind')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
eprintln('TODO: unhandled assign ident case')
|
|
||||||
dump(node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// a += b
|
|
||||||
}
|
}
|
||||||
ast.StructInit {
|
ast.StructInit {
|
||||||
match node.op {
|
match node.op {
|
||||||
@ -2214,33 +2101,95 @@ fn (mut c Amd64) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, n
|
|||||||
c.g.n_error('Unexpected operator `${node.op}`')
|
c.g.n_error('Unexpected operator `${node.op}`')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
ast.ArrayInit {
|
ast.ArrayInit {
|
||||||
// check if array is empty
|
match node.op {
|
||||||
mut pos := c.g.allocate_array(name, 8, right.exprs.len)
|
.decl_assign {
|
||||||
// allocate array of right.exprs.len vars
|
c.g.allocate_by_type(name, right.typ)
|
||||||
for e in right.exprs {
|
c.init_array(ident, right)
|
||||||
match e {
|
}
|
||||||
ast.IntegerLiteral {
|
else {
|
||||||
c.mov(Amd64Register.rax, e.val.int())
|
c.g.n_error('Unexpected operator `${node.op}`')
|
||||||
c.mov_reg_to_var(LocalVar{pos, ast.i64_type_idx, ''}, Amd64Register.rax)
|
|
||||||
pos += 8
|
|
||||||
}
|
|
||||||
ast.StringLiteral {
|
|
||||||
// TODO: use learel
|
|
||||||
str := c.g.eval_str_lit_escape_codes(e)
|
|
||||||
c.mov64(Amd64Register.rsi, c.g.allocate_string(str, 2, .abs64)) // for rsi its 2
|
|
||||||
c.mov_reg_to_var(LocalVar{pos, ast.u64_type_idx, ''}, Amd64Register.rsi)
|
|
||||||
pos += 8
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dump(e)
|
|
||||||
c.g.n_error('unhandled array init type')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
ast.IndexExpr {
|
ast.TypeOf {
|
||||||
|
c.g.gen_typeof_expr(right as ast.TypeOf, true)
|
||||||
|
c.mov_reg(Amd64Register.rsi, Amd64Register.rax)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ast.AtExpr {
|
||||||
|
dest := c.allocate_var(name, 8, 0)
|
||||||
|
c.learel(Amd64Register.rsi, c.g.allocate_string(c.g.comptime_at(right), 3,
|
||||||
|
.rel32))
|
||||||
|
c.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, Amd64Register.rsi)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ast.IfExpr {
|
||||||
|
if right.is_comptime {
|
||||||
|
if stmts := c.g.comptime_conditional(right) {
|
||||||
|
for j, stmt in stmts {
|
||||||
|
if j + 1 != stmts.len {
|
||||||
|
c.g.stmt(stmt)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if stmt is ast.ExprStmt {
|
||||||
|
c.assign_right_expr(node, i, stmt.expr, name, ident)
|
||||||
|
} else {
|
||||||
|
c.g.n_error('last stmt must be expr')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c.g.n_error('missing value for assignment')
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
|
||||||
|
left_type := node.left_types[i]
|
||||||
|
if node.op == .decl_assign {
|
||||||
|
c.g.allocate_by_type(name, left_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.g.expr(right)
|
||||||
|
|
||||||
|
if node.op in [.assign, .decl_assign] {
|
||||||
|
var := c.g.get_var_from_ident(ident)
|
||||||
|
c.assign_var(var, left_type)
|
||||||
|
} else if left_type.is_pure_float() {
|
||||||
|
c.mov_var_to_ssereg(.xmm1, ident)
|
||||||
|
|
||||||
|
match node.op {
|
||||||
|
.plus_assign { c.add_sse(.xmm1, .xmm0, left_type) }
|
||||||
|
.minus_assign { c.sub_sse(.xmm1, .xmm0, left_type) }
|
||||||
|
.mult_assign { c.mul_sse(.xmm1, .xmm0, left_type) }
|
||||||
|
.div_assign { c.div_sse(.xmm1, .xmm0, left_type) }
|
||||||
|
else { c.g.n_error('unexpected assignment operator ${node.op} for fp') }
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mov_ssereg_to_var(ident, .xmm1)
|
||||||
|
} else if left_type.is_int() {
|
||||||
|
c.mov_var_to_reg(Amd64Register.rbx, ident)
|
||||||
|
|
||||||
|
match node.op {
|
||||||
|
.plus_assign { c.add_reg(.rbx, .rax) }
|
||||||
|
.minus_assign { c.sub_reg(.rbx, .rax) }
|
||||||
|
.div_assign { c.div_reg(.rbx, .rax) }
|
||||||
|
.mult_assign { c.mul_reg(.rbx, .rax) }
|
||||||
|
else { c.g.n_error('unexpected assignment operator ${node.op} for int') }
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mov_reg_to_var(ident, Amd64Register.rbx)
|
||||||
|
} else {
|
||||||
|
c.g.n_error('assignment arithmetic not implemented for type ${node.left_types[i]}')
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
ast.IndexExpr {
|
||||||
// a := arr[0]
|
// a := arr[0]
|
||||||
offset := c.allocate_var(name, c.g.get_sizeof_ident(ident), 0)
|
offset := c.allocate_var(name, c.g.get_sizeof_ident(ident), 0)
|
||||||
if c.g.pref.is_verbose {
|
if c.g.pref.is_verbose {
|
||||||
@ -2268,73 +2217,7 @@ fn (mut c Amd64) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, n
|
|||||||
// TODO check if out of bounds access
|
// TODO check if out of bounds access
|
||||||
c.mov_reg_to_var(ident, Amd64Register.eax)
|
c.mov_reg_to_var(ident, Amd64Register.eax)
|
||||||
}
|
}
|
||||||
ast.StringLiteral {
|
}*/
|
||||||
dest := c.allocate_var(name, 8, 0)
|
|
||||||
ie := right as ast.StringLiteral
|
|
||||||
str := c.g.eval_str_lit_escape_codes(ie)
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
ast.GoExpr {
|
|
||||||
c.g.v_error('threads not implemented for the native backend', node.pos)
|
|
||||||
}
|
|
||||||
ast.TypeOf {
|
|
||||||
c.g.gen_typeof_expr(right as ast.TypeOf, true)
|
|
||||||
c.mov_reg(Amd64Register.rsi, Amd64Register.rax)
|
|
||||||
}
|
|
||||||
ast.AtExpr {
|
|
||||||
dest := c.allocate_var(name, 8, 0)
|
|
||||||
c.learel(Amd64Register.rsi, c.g.allocate_string(c.g.comptime_at(right), 3,
|
|
||||||
.rel32))
|
|
||||||
c.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, Amd64Register.rsi)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if right is ast.IfExpr && (right as ast.IfExpr).is_comptime {
|
|
||||||
if stmts := c.g.comptime_conditional(right) {
|
|
||||||
for j, stmt in stmts {
|
|
||||||
if j + 1 == stmts.len {
|
|
||||||
if stmt is ast.ExprStmt {
|
|
||||||
c.assign_right_expr(node, i, stmt.expr, name, ident)
|
|
||||||
} else {
|
|
||||||
c.g.n_error('last stmt must be expr')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c.g.stmt(stmt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c.g.n_error('missing value for assignment')
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// dump(node)
|
|
||||||
size := c.g.get_type_size(node.left_types[i])
|
|
||||||
if size !in [1, 2, 4, 8] || node.op !in [.assign, .decl_assign] {
|
|
||||||
c.g.v_error('unhandled assign_stmt expression: ${right.type_name()}',
|
|
||||||
right.pos())
|
|
||||||
}
|
|
||||||
if node.op == .decl_assign {
|
|
||||||
c.allocate_var(name, size, 0)
|
|
||||||
}
|
|
||||||
c.g.expr(right)
|
|
||||||
var := c.g.get_var_from_ident(ident)
|
|
||||||
if node.left_types[i].is_pure_float() {
|
|
||||||
match var {
|
|
||||||
LocalVar { c.mov_ssereg_to_var(var as LocalVar, .xmm0) }
|
|
||||||
GlobalVar { c.mov_ssereg_to_var(var as GlobalVar, .xmm0) }
|
|
||||||
// Amd64Register { c.g.mov_ssereg(var as Amd64Register, .xmm0) }
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match var {
|
|
||||||
LocalVar { c.mov_reg_to_var(var as LocalVar, Amd64Register.rax) }
|
|
||||||
GlobalVar { c.mov_reg_to_var(var as GlobalVar, Amd64Register.rax) }
|
|
||||||
Register { c.mov_reg(var as Amd64Register, Amd64Register.rax) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Amd64) gen_type_promotion(from ast.Type, to ast.Type, option Amd64RegisterOption) {
|
fn (mut c Amd64) gen_type_promotion(from ast.Type, to ast.Type, option Amd64RegisterOption) {
|
||||||
@ -3561,7 +3444,38 @@ fn (mut c Amd64) init_struct(var Var, init ast.StructInit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
GlobalVar {
|
GlobalVar {
|
||||||
// TODO
|
c.g.n_error('GlobalVar not implemented for ast.StructInit')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut c Amd64) init_array(var Var, node ast.ArrayInit) {
|
||||||
|
match var {
|
||||||
|
ast.Ident {
|
||||||
|
var_object := c.g.get_var_from_ident(var)
|
||||||
|
match var_object {
|
||||||
|
LocalVar {
|
||||||
|
c.init_array(var_object as LocalVar, node)
|
||||||
|
}
|
||||||
|
GlobalVar {
|
||||||
|
c.init_array(var_object as GlobalVar, node)
|
||||||
|
}
|
||||||
|
Register {
|
||||||
|
// TODO
|
||||||
|
// c.g.cmp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LocalVar {
|
||||||
|
mut offset := var.offset
|
||||||
|
for expr in node.exprs {
|
||||||
|
c.g.expr(expr)
|
||||||
|
c.mov_reg_to_var(LocalVar{offset, ast.i64_type_idx, ''}, c.main_reg())
|
||||||
|
offset += 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GlobalVar {
|
||||||
|
c.g.n_error('GlobalVar not implemented for ast.ArrayInit')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
module native
|
module native
|
||||||
|
|
||||||
import v.ast
|
import v.ast
|
||||||
@ -439,6 +442,10 @@ fn (mut c Arm64) init_struct(var Var, init ast.StructInit) {
|
|||||||
panic('Arm64.init_struct() not implemented')
|
panic('Arm64.init_struct() not implemented')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (mut c Arm64) init_array(var Var, init ast.ArrayInit) {
|
||||||
|
panic('Arm64.init_array() not implemented')
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut c Arm64) load_fp_var(var Var, config VarConfig) {
|
fn (mut c Arm64) load_fp_var(var Var, config VarConfig) {
|
||||||
panic('Arm64.load_fp_var() not implemented')
|
panic('Arm64.load_fp_var() not implemented')
|
||||||
}
|
}
|
||||||
|
347
vlib/v/gen/native/expr.v
Normal file
347
vlib/v/gen/native/expr.v
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
|
module native
|
||||||
|
|
||||||
|
import v.ast
|
||||||
|
|
||||||
|
fn (mut g Gen) expr(node ast.Expr) {
|
||||||
|
match node {
|
||||||
|
ast.ParExpr {
|
||||||
|
g.expr(node.expr)
|
||||||
|
}
|
||||||
|
ast.ArrayInit {
|
||||||
|
pos := g.allocate_array('_anonarray', 8, node.exprs.len)
|
||||||
|
g.code_gen.init_array(LocalVar{ offset: pos, typ: node.typ }, node)
|
||||||
|
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), pos)
|
||||||
|
}
|
||||||
|
ast.BoolLiteral {
|
||||||
|
g.code_gen.mov64(g.code_gen.main_reg(), if node.val {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ast.CallExpr {
|
||||||
|
if node.name == 'C.syscall' {
|
||||||
|
g.code_gen.gen_syscall(node)
|
||||||
|
} else if node.name == 'exit' {
|
||||||
|
g.code_gen.gen_exit(node.args[0].expr)
|
||||||
|
} else if node.name in ['println', 'print', 'eprintln', 'eprint'] {
|
||||||
|
expr := node.args[0].expr
|
||||||
|
typ := node.args[0].typ
|
||||||
|
g.gen_print_from_expr(expr, typ, node.name)
|
||||||
|
} else {
|
||||||
|
g.code_gen.call_fn(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.FloatLiteral {
|
||||||
|
val := g.eval.expr(node, ast.float_literal_type_idx).float_val()
|
||||||
|
g.code_gen.load_fp(val)
|
||||||
|
}
|
||||||
|
ast.Ident {
|
||||||
|
var := g.get_var_from_ident(node)
|
||||||
|
// XXX this is intel specific
|
||||||
|
match var {
|
||||||
|
LocalVar {
|
||||||
|
if g.is_register_type(var.typ) {
|
||||||
|
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), node as ast.Ident)
|
||||||
|
} else if var.typ.is_pure_float() {
|
||||||
|
g.code_gen.load_fp_var(node as ast.Ident)
|
||||||
|
} else {
|
||||||
|
ts := g.table.sym(var.typ)
|
||||||
|
match ts.info {
|
||||||
|
ast.Struct {
|
||||||
|
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), g.get_var_offset(node.name))
|
||||||
|
}
|
||||||
|
ast.Enum {
|
||||||
|
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), node as ast.Ident,
|
||||||
|
typ: ast.int_type_idx
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('Unsupported variable type')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('Unsupported variable kind')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.IfExpr {
|
||||||
|
g.if_expr(node)
|
||||||
|
}
|
||||||
|
ast.InfixExpr {
|
||||||
|
g.code_gen.infix_expr(node)
|
||||||
|
}
|
||||||
|
ast.IntegerLiteral {
|
||||||
|
g.code_gen.mov64(g.code_gen.main_reg(), i64(node.val.u64()))
|
||||||
|
}
|
||||||
|
ast.Nil {
|
||||||
|
g.code_gen.mov64(g.code_gen.main_reg(), 0)
|
||||||
|
}
|
||||||
|
ast.PostfixExpr {
|
||||||
|
g.postfix_expr(node)
|
||||||
|
}
|
||||||
|
ast.PrefixExpr {
|
||||||
|
g.code_gen.prefix_expr(node)
|
||||||
|
}
|
||||||
|
ast.StringLiteral {
|
||||||
|
str := g.eval_str_lit_escape_codes(node)
|
||||||
|
g.allocate_string(str, 3, .rel32)
|
||||||
|
}
|
||||||
|
ast.CharLiteral {
|
||||||
|
bytes := g.eval_escape_codes(node.val)
|
||||||
|
.bytes()
|
||||||
|
mut val := rune(0)
|
||||||
|
for i, v in bytes {
|
||||||
|
val |= v << (i * 8)
|
||||||
|
if i >= sizeof(rune) {
|
||||||
|
g.n_error('runes are only 4 bytes wide')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.code_gen.movabs(g.code_gen.main_reg(), i64(val))
|
||||||
|
}
|
||||||
|
ast.StructInit {
|
||||||
|
pos := g.allocate_by_type('_anonstruct', node.typ)
|
||||||
|
g.code_gen.init_struct(LocalVar{ offset: pos, typ: node.typ }, node)
|
||||||
|
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), pos)
|
||||||
|
}
|
||||||
|
ast.GoExpr {
|
||||||
|
g.v_error('native backend doesnt support threads yet', node.pos)
|
||||||
|
}
|
||||||
|
ast.MatchExpr {
|
||||||
|
g.code_gen.gen_match_expr(node)
|
||||||
|
}
|
||||||
|
ast.SelectorExpr {
|
||||||
|
g.code_gen.gen_selector_expr(node)
|
||||||
|
}
|
||||||
|
ast.CastExpr {
|
||||||
|
g.code_gen.gen_cast_expr(node)
|
||||||
|
}
|
||||||
|
ast.EnumVal {
|
||||||
|
type_name := g.table.get_type_name(node.typ)
|
||||||
|
g.code_gen.mov(g.code_gen.main_reg(), g.enum_vals[type_name].fields[node.val])
|
||||||
|
}
|
||||||
|
ast.UnsafeExpr {
|
||||||
|
g.expr(node.expr)
|
||||||
|
}
|
||||||
|
ast.ConcatExpr {
|
||||||
|
g.code_gen.gen_concat_expr(node)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('expr: unhandled node type: ${node.type_name()}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) condition(expr ast.Expr, neg bool) int {
|
||||||
|
g.expr(expr)
|
||||||
|
g.code_gen.cmp_zero(g.code_gen.main_reg())
|
||||||
|
return g.code_gen.cjmp(if neg { .jne } else { .je })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
|
if node.is_comptime {
|
||||||
|
if stmts := g.comptime_conditional(node) {
|
||||||
|
g.stmts(stmts)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if node.branches.len == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mut endif_label := 0
|
||||||
|
has_endif := node.branches.len > 1
|
||||||
|
if has_endif {
|
||||||
|
endif_label = g.labels.new_label()
|
||||||
|
}
|
||||||
|
for idx in 0 .. node.branches.len {
|
||||||
|
branch := node.branches[idx]
|
||||||
|
if idx == node.branches.len - 1 && node.has_else {
|
||||||
|
g.stmts(branch.stmts)
|
||||||
|
} else {
|
||||||
|
if branch.cond is ast.BoolLiteral {
|
||||||
|
if branch.cond.val {
|
||||||
|
g.stmts(branch.stmts)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
expr := branch.cond
|
||||||
|
label := g.labels.new_label()
|
||||||
|
cjmp_addr := g.condition(expr, false)
|
||||||
|
g.labels.patches << LabelPatch{
|
||||||
|
id: label
|
||||||
|
pos: cjmp_addr
|
||||||
|
}
|
||||||
|
g.println('; jump to label ${label}')
|
||||||
|
g.stmts(branch.stmts)
|
||||||
|
if has_endif {
|
||||||
|
jump_addr := g.code_gen.jmp(0)
|
||||||
|
g.labels.patches << LabelPatch{
|
||||||
|
id: endif_label
|
||||||
|
pos: jump_addr
|
||||||
|
}
|
||||||
|
g.println('; jump to label ${endif_label}')
|
||||||
|
}
|
||||||
|
// println('after if g.pos=$g.pos() jneaddr=$cjmp_addr')
|
||||||
|
g.labels.addrs[label] = g.pos()
|
||||||
|
g.println('; label ${label}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if has_endif {
|
||||||
|
g.labels.addrs[endif_label] = g.pos()
|
||||||
|
g.println('; label ${endif_label}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) postfix_expr(node ast.PostfixExpr) {
|
||||||
|
if node.expr !is ast.Ident {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ident := node.expr as ast.Ident
|
||||||
|
match node.op {
|
||||||
|
.inc {
|
||||||
|
g.code_gen.inc_var(ident)
|
||||||
|
}
|
||||||
|
.dec {
|
||||||
|
g.code_gen.dec_var(ident)
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_typeof_expr(it ast.TypeOf, newline bool) {
|
||||||
|
nl := if newline { '\n' } else { '' }
|
||||||
|
r := g.typ(it.typ).name
|
||||||
|
g.code_gen.learel(g.code_gen.main_reg(), g.allocate_string('${r}${nl}', 3, .rel32))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) {
|
||||||
|
newline := name in ['println', 'eprintln']
|
||||||
|
fd := if name in ['eprint', 'eprintln'] { 2 } else { 1 }
|
||||||
|
match expr {
|
||||||
|
ast.StringLiteral {
|
||||||
|
str := g.eval_str_lit_escape_codes(expr)
|
||||||
|
if newline {
|
||||||
|
g.code_gen.gen_print(str + '\n', fd)
|
||||||
|
} else {
|
||||||
|
g.code_gen.gen_print(str, fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.Nil {
|
||||||
|
str := '0x0'
|
||||||
|
if newline {
|
||||||
|
g.code_gen.gen_print(str + '\n', fd)
|
||||||
|
} else {
|
||||||
|
g.code_gen.gen_print(str, fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.CharLiteral {
|
||||||
|
str := g.eval_escape_codes(expr.val)
|
||||||
|
if newline {
|
||||||
|
g.code_gen.gen_print(str + '\n', fd)
|
||||||
|
} else {
|
||||||
|
g.code_gen.gen_print(str, fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.Ident {
|
||||||
|
vo := g.try_var_offset(expr.name)
|
||||||
|
|
||||||
|
reg := g.code_gen.main_reg()
|
||||||
|
if vo != -1 {
|
||||||
|
g.gen_var_to_string(reg, expr, expr as ast.Ident)
|
||||||
|
g.code_gen.gen_print_reg(reg, -1, fd)
|
||||||
|
if newline {
|
||||||
|
g.code_gen.gen_print('\n', fd)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g.code_gen.gen_print_reg(reg, -1, fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.IntegerLiteral {
|
||||||
|
if newline {
|
||||||
|
g.code_gen.gen_print('${expr.val}\n', fd)
|
||||||
|
} else {
|
||||||
|
g.code_gen.gen_print('${expr.val}', fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.BoolLiteral {
|
||||||
|
// register 'true' and 'false' strings // g.expr(expr)
|
||||||
|
// XXX mov64 shuoldnt be used for addressing
|
||||||
|
nl := if newline { '\n' } else { '' }
|
||||||
|
|
||||||
|
if expr.val {
|
||||||
|
g.code_gen.gen_print('true' + nl, fd)
|
||||||
|
} else {
|
||||||
|
g.code_gen.gen_print('false' + nl, fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.SizeOf {
|
||||||
|
size := g.get_type_size(expr.typ)
|
||||||
|
if newline {
|
||||||
|
g.code_gen.gen_print('${size}\n', fd)
|
||||||
|
} else {
|
||||||
|
g.code_gen.gen_print('${size}', fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.OffsetOf {
|
||||||
|
styp := g.typ(expr.struct_type)
|
||||||
|
field_name := expr.field
|
||||||
|
if styp.kind == .struct_ {
|
||||||
|
off := g.get_field_offset(expr.struct_type, field_name)
|
||||||
|
if newline {
|
||||||
|
g.code_gen.gen_print('${off}\n', fd)
|
||||||
|
} else {
|
||||||
|
g.code_gen.gen_print('${off}', fd)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g.v_error('_offsetof expects a struct Type as first argument', expr.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.None {
|
||||||
|
if newline {
|
||||||
|
g.code_gen.gen_print('<none>\n', fd)
|
||||||
|
} else {
|
||||||
|
g.code_gen.gen_print('<none>', fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.AtExpr {
|
||||||
|
if newline {
|
||||||
|
g.code_gen.gen_print(g.comptime_at(expr) + '\n', fd)
|
||||||
|
} else {
|
||||||
|
g.code_gen.gen_print(g.comptime_at(expr), fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.StringInterLiteral {
|
||||||
|
g.n_error('Interlaced string literals are not yet supported in the native backend.') // , expr.pos)
|
||||||
|
}
|
||||||
|
ast.IfExpr {
|
||||||
|
if expr.is_comptime {
|
||||||
|
if stmts := g.comptime_conditional(expr) {
|
||||||
|
for i, stmt in stmts {
|
||||||
|
if i + 1 == stmts.len && stmt is ast.ExprStmt {
|
||||||
|
g.gen_print_from_expr(stmt.expr, stmt.typ, name)
|
||||||
|
} else {
|
||||||
|
g.stmt(stmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g.n_error('nothing to print')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g.n_error('non-comptime conditionals are not implemented yet.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.expr(expr)
|
||||||
|
g.gen_to_string(g.code_gen.main_reg(), typ)
|
||||||
|
g.code_gen.gen_print_reg(g.code_gen.main_reg(), -1, fd)
|
||||||
|
if newline {
|
||||||
|
g.code_gen.gen_print('\n', fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,66 +16,6 @@ import v.eval
|
|||||||
import term
|
import term
|
||||||
import strconv
|
import strconv
|
||||||
|
|
||||||
interface CodeGen {
|
|
||||||
mut:
|
|
||||||
g &Gen
|
|
||||||
adr(r Arm64Register, delta int) // Note: Temporary!
|
|
||||||
allocate_var(name string, size int, initial_val int) int
|
|
||||||
apicall(call ApiCall) // winapi calls
|
|
||||||
assign_stmt(node ast.AssignStmt) // TODO: make platform-independant
|
|
||||||
builtin_decl(builtin BuiltinFn)
|
|
||||||
call_addr_at(addr int, at i64) i64
|
|
||||||
call_builtin(name Builtin) i64
|
|
||||||
call_fn(node ast.CallExpr)
|
|
||||||
call(addr int) i64
|
|
||||||
cjmp(op JumpOp) int
|
|
||||||
cmp_var_reg(var Var, reg Register, config VarConfig)
|
|
||||||
cmp_var(var Var, val int, config VarConfig)
|
|
||||||
cmp_zero(reg Register)
|
|
||||||
convert_bool_to_string(r Register)
|
|
||||||
convert_int_to_string(a Register, b Register)
|
|
||||||
convert_rune_to_string(r Register, buffer int, var Var, config VarConfig)
|
|
||||||
dec_var(var Var, config VarConfig)
|
|
||||||
fn_decl(node ast.FnDecl)
|
|
||||||
for_in_stmt(node ast.ForInStmt)
|
|
||||||
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
|
|
||||||
infloop()
|
|
||||||
init_struct(var Var, init ast.StructInit)
|
|
||||||
jmp_back(start i64)
|
|
||||||
jmp(addr int) int
|
|
||||||
lea_var_to_reg(r Register, var_offset int)
|
|
||||||
learel(reg Register, val int)
|
|
||||||
leave()
|
|
||||||
load_fp_var(var Var, config VarConfig)
|
|
||||||
load_fp(val f64)
|
|
||||||
main_reg() Register
|
|
||||||
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)
|
|
||||||
mov_var_to_reg(reg Register, var Var, config VarConfig)
|
|
||||||
mov(r Register, val int)
|
|
||||||
mov64(r Register, val i64)
|
|
||||||
movabs(reg Register, val i64)
|
|
||||||
prefix_expr(node ast.PrefixExpr)
|
|
||||||
ret()
|
|
||||||
return_stmt(node ast.Return)
|
|
||||||
reverse_string(r Register)
|
|
||||||
svc()
|
|
||||||
syscall() // unix syscalls
|
|
||||||
trap()
|
|
||||||
}
|
|
||||||
|
|
||||||
[heap; minify]
|
[heap; minify]
|
||||||
pub struct Gen {
|
pub struct Gen {
|
||||||
out_name string
|
out_name string
|
||||||
@ -123,6 +63,67 @@ mut:
|
|||||||
requires_linking bool
|
requires_linking bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CodeGen {
|
||||||
|
mut:
|
||||||
|
g &Gen
|
||||||
|
adr(r Arm64Register, delta int) // Note: Temporary!
|
||||||
|
allocate_var(name string, size int, initial_val int) int
|
||||||
|
apicall(call ApiCall) // winapi calls
|
||||||
|
assign_stmt(node ast.AssignStmt) // TODO: make platform-independant
|
||||||
|
builtin_decl(builtin BuiltinFn)
|
||||||
|
call_addr_at(addr int, at i64) i64
|
||||||
|
call_builtin(name Builtin) i64
|
||||||
|
call_fn(node ast.CallExpr)
|
||||||
|
call(addr int) i64
|
||||||
|
cjmp(op JumpOp) int
|
||||||
|
cmp_var_reg(var Var, reg Register, config VarConfig)
|
||||||
|
cmp_var(var Var, val int, config VarConfig)
|
||||||
|
cmp_zero(reg Register)
|
||||||
|
convert_bool_to_string(r Register)
|
||||||
|
convert_int_to_string(a Register, b Register)
|
||||||
|
convert_rune_to_string(r Register, buffer int, var Var, config VarConfig)
|
||||||
|
dec_var(var Var, config VarConfig)
|
||||||
|
fn_decl(node ast.FnDecl)
|
||||||
|
for_in_stmt(node ast.ForInStmt)
|
||||||
|
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
|
||||||
|
infloop()
|
||||||
|
init_struct(var Var, init ast.StructInit)
|
||||||
|
init_array(var Var, init ast.ArrayInit)
|
||||||
|
jmp_back(start i64)
|
||||||
|
jmp(addr int) int
|
||||||
|
lea_var_to_reg(r Register, var_offset int)
|
||||||
|
learel(reg Register, val int)
|
||||||
|
leave()
|
||||||
|
load_fp_var(var Var, config VarConfig)
|
||||||
|
load_fp(val f64)
|
||||||
|
main_reg() Register
|
||||||
|
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)
|
||||||
|
mov_var_to_reg(reg Register, var Var, config VarConfig)
|
||||||
|
mov(r Register, val int)
|
||||||
|
mov64(r Register, val i64)
|
||||||
|
movabs(reg Register, val i64)
|
||||||
|
prefix_expr(node ast.PrefixExpr)
|
||||||
|
ret()
|
||||||
|
return_stmt(node ast.Return)
|
||||||
|
reverse_string(r Register)
|
||||||
|
svc()
|
||||||
|
syscall() // unix syscalls
|
||||||
|
trap()
|
||||||
|
}
|
||||||
|
|
||||||
type Register = Amd64Register | Arm64Register
|
type Register = Amd64Register | Arm64Register
|
||||||
|
|
||||||
enum RelocType {
|
enum RelocType {
|
||||||
@ -223,6 +224,11 @@ enum JumpOp {
|
|||||||
jnb
|
jnb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
union F64I64 {
|
||||||
|
f f64
|
||||||
|
i i64
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar {
|
fn (mut g Gen) get_var_from_ident(ident ast.Ident) IdentVar {
|
||||||
mut obj := ident.obj
|
mut obj := ident.obj
|
||||||
if obj !in [ast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister] {
|
if obj !in [ast.Var, ast.ConstField, ast.GlobalField, ast.AsmRegister] {
|
||||||
@ -495,12 +501,6 @@ pub fn (mut g Gen) calculate_enum_fields() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) stmts(stmts []ast.Stmt) {
|
|
||||||
for stmt in stmts {
|
|
||||||
g.stmt(stmt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (g &Gen) pos() i64 {
|
pub fn (g &Gen) pos() i64 {
|
||||||
return g.buf.len
|
return g.buf.len
|
||||||
}
|
}
|
||||||
@ -773,12 +773,6 @@ fn (mut g Gen) allocate_array(name string, size int, items int) int {
|
|||||||
return pos
|
return pos
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_typeof_expr(it ast.TypeOf, newline bool) {
|
|
||||||
nl := if newline { '\n' } else { '' }
|
|
||||||
r := g.typ(it.typ).name
|
|
||||||
g.code_gen.learel(g.code_gen.main_reg(), g.allocate_string('${r}${nl}', 3, .rel32))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) eval_str_lit_escape_codes(str_lit ast.StringLiteral) string {
|
fn (mut g Gen) eval_str_lit_escape_codes(str_lit ast.StringLiteral) string {
|
||||||
if str_lit.is_raw {
|
if str_lit.is_raw {
|
||||||
return str_lit.val
|
return str_lit.val
|
||||||
@ -909,133 +903,6 @@ fn (mut g Gen) gen_var_to_string(reg Register, expr ast.Expr, var Var, config Va
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) {
|
|
||||||
newline := name in ['println', 'eprintln']
|
|
||||||
fd := if name in ['eprint', 'eprintln'] { 2 } else { 1 }
|
|
||||||
match expr {
|
|
||||||
ast.StringLiteral {
|
|
||||||
str := g.eval_str_lit_escape_codes(expr)
|
|
||||||
if newline {
|
|
||||||
g.code_gen.gen_print(str + '\n', fd)
|
|
||||||
} else {
|
|
||||||
g.code_gen.gen_print(str, fd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.Nil {
|
|
||||||
str := '0x0'
|
|
||||||
if newline {
|
|
||||||
g.code_gen.gen_print(str + '\n', fd)
|
|
||||||
} else {
|
|
||||||
g.code_gen.gen_print(str, fd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.CharLiteral {
|
|
||||||
str := g.eval_escape_codes(expr.val)
|
|
||||||
if newline {
|
|
||||||
g.code_gen.gen_print(str + '\n', fd)
|
|
||||||
} else {
|
|
||||||
g.code_gen.gen_print(str, fd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.Ident {
|
|
||||||
vo := g.try_var_offset(expr.name)
|
|
||||||
|
|
||||||
reg := g.code_gen.main_reg()
|
|
||||||
if vo != -1 {
|
|
||||||
g.gen_var_to_string(reg, expr, expr as ast.Ident)
|
|
||||||
g.code_gen.gen_print_reg(reg, -1, fd)
|
|
||||||
if newline {
|
|
||||||
g.code_gen.gen_print('\n', fd)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
g.code_gen.gen_print_reg(reg, -1, fd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.IntegerLiteral {
|
|
||||||
if newline {
|
|
||||||
g.code_gen.gen_print('${expr.val}\n', fd)
|
|
||||||
} else {
|
|
||||||
g.code_gen.gen_print('${expr.val}', fd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.BoolLiteral {
|
|
||||||
// register 'true' and 'false' strings // g.expr(expr)
|
|
||||||
// XXX mov64 shuoldnt be used for addressing
|
|
||||||
nl := if newline { '\n' } else { '' }
|
|
||||||
|
|
||||||
if expr.val {
|
|
||||||
g.code_gen.gen_print('true' + nl, fd)
|
|
||||||
} else {
|
|
||||||
g.code_gen.gen_print('false' + nl, fd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.SizeOf {
|
|
||||||
size := g.get_type_size(expr.typ)
|
|
||||||
if newline {
|
|
||||||
g.code_gen.gen_print('${size}\n', fd)
|
|
||||||
} else {
|
|
||||||
g.code_gen.gen_print('${size}', fd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.OffsetOf {
|
|
||||||
styp := g.typ(expr.struct_type)
|
|
||||||
field_name := expr.field
|
|
||||||
if styp.kind == .struct_ {
|
|
||||||
off := g.get_field_offset(expr.struct_type, field_name)
|
|
||||||
if newline {
|
|
||||||
g.code_gen.gen_print('${off}\n', fd)
|
|
||||||
} else {
|
|
||||||
g.code_gen.gen_print('${off}', fd)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
g.v_error('_offsetof expects a struct Type as first argument', expr.pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.None {
|
|
||||||
if newline {
|
|
||||||
g.code_gen.gen_print('<none>\n', fd)
|
|
||||||
} else {
|
|
||||||
g.code_gen.gen_print('<none>', fd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.AtExpr {
|
|
||||||
if newline {
|
|
||||||
g.code_gen.gen_print(g.comptime_at(expr) + '\n', fd)
|
|
||||||
} else {
|
|
||||||
g.code_gen.gen_print(g.comptime_at(expr), fd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.StringInterLiteral {
|
|
||||||
g.n_error('Interlaced string literals are not yet supported in the native backend.') // , expr.pos)
|
|
||||||
}
|
|
||||||
ast.IfExpr {
|
|
||||||
if expr.is_comptime {
|
|
||||||
if stmts := g.comptime_conditional(expr) {
|
|
||||||
for i, stmt in stmts {
|
|
||||||
if i + 1 == stmts.len && stmt is ast.ExprStmt {
|
|
||||||
g.gen_print_from_expr(stmt.expr, stmt.typ, name)
|
|
||||||
} else {
|
|
||||||
g.stmt(stmt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
g.n_error('nothing to print')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
g.n_error('non-comptime conditionals are not implemented yet.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.expr(expr)
|
|
||||||
g.gen_to_string(g.code_gen.main_reg(), typ)
|
|
||||||
g.code_gen.gen_print_reg(g.code_gen.main_reg(), -1, fd)
|
|
||||||
if newline {
|
|
||||||
g.code_gen.gen_print('\n', fd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) is_used_by_main(node ast.FnDecl) bool {
|
fn (mut g Gen) is_used_by_main(node ast.FnDecl) bool {
|
||||||
mut used := true
|
mut used := true
|
||||||
if g.pref.skip_unused {
|
if g.pref.skip_unused {
|
||||||
@ -1150,463 +1017,6 @@ fn (mut g Gen) println(comment string) {
|
|||||||
println(final)
|
println(final)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_forc_stmt(node ast.ForCStmt) {
|
|
||||||
if node.has_init {
|
|
||||||
g.stmts([node.init])
|
|
||||||
}
|
|
||||||
start := g.pos()
|
|
||||||
start_label := g.labels.new_label()
|
|
||||||
mut jump_addr := i64(0)
|
|
||||||
if node.has_cond {
|
|
||||||
cond := node.cond
|
|
||||||
match cond {
|
|
||||||
ast.InfixExpr {
|
|
||||||
match cond.left {
|
|
||||||
ast.Ident {
|
|
||||||
lit := cond.right as ast.IntegerLiteral
|
|
||||||
g.code_gen.cmp_var(cond.left as ast.Ident, lit.val.int())
|
|
||||||
match cond.op {
|
|
||||||
.gt {
|
|
||||||
jump_addr = g.code_gen.cjmp(.jle)
|
|
||||||
}
|
|
||||||
.lt {
|
|
||||||
jump_addr = g.code_gen.cjmp(.jge)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.n_error('unsupported conditional in for-c loop')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.n_error('unhandled infix.left')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
// dump(node.cond)
|
|
||||||
g.expr(node.cond)
|
|
||||||
}
|
|
||||||
end_label := g.labels.new_label()
|
|
||||||
g.labels.patches << LabelPatch{
|
|
||||||
id: end_label
|
|
||||||
pos: int(jump_addr)
|
|
||||||
}
|
|
||||||
g.println('; jump to label ${end_label}')
|
|
||||||
g.labels.branches << BranchLabel{
|
|
||||||
name: node.label
|
|
||||||
start: start_label
|
|
||||||
end: end_label
|
|
||||||
}
|
|
||||||
g.stmts(node.stmts)
|
|
||||||
g.labels.addrs[start_label] = g.pos()
|
|
||||||
g.println('; label ${start_label}')
|
|
||||||
if node.has_inc {
|
|
||||||
g.stmts([node.inc])
|
|
||||||
}
|
|
||||||
g.labels.branches.pop()
|
|
||||||
g.code_gen.jmp_back(start)
|
|
||||||
g.labels.addrs[end_label] = g.pos()
|
|
||||||
g.println('; jump to label ${end_label}')
|
|
||||||
|
|
||||||
// loop back
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) for_stmt(node ast.ForStmt) {
|
|
||||||
if node.is_inf {
|
|
||||||
if node.stmts.len == 0 {
|
|
||||||
g.code_gen.infloop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// infinite loop
|
|
||||||
start := g.pos()
|
|
||||||
start_label := g.labels.new_label()
|
|
||||||
g.labels.addrs[start_label] = start
|
|
||||||
g.println('; label ${start_label}')
|
|
||||||
end_label := g.labels.new_label()
|
|
||||||
g.labels.branches << BranchLabel{
|
|
||||||
name: node.label
|
|
||||||
start: start_label
|
|
||||||
end: end_label
|
|
||||||
}
|
|
||||||
g.stmts(node.stmts)
|
|
||||||
g.labels.branches.pop()
|
|
||||||
g.code_gen.jmp_back(start)
|
|
||||||
g.println('jmp after infinite for')
|
|
||||||
g.labels.addrs[end_label] = g.pos()
|
|
||||||
g.println('; label ${end_label}')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
infix_expr := node.cond as ast.InfixExpr
|
|
||||||
mut jump_addr := 0 // location of `jne *00 00 00 00*`
|
|
||||||
start := g.pos()
|
|
||||||
start_label := g.labels.new_label()
|
|
||||||
g.labels.addrs[start_label] = start
|
|
||||||
g.println('; label ${start_label}')
|
|
||||||
match infix_expr.left {
|
|
||||||
ast.Ident {
|
|
||||||
match infix_expr.right {
|
|
||||||
ast.Ident {
|
|
||||||
reg := g.code_gen.main_reg()
|
|
||||||
g.code_gen.mov_var_to_reg(reg, infix_expr.right as ast.Ident)
|
|
||||||
g.code_gen.cmp_var_reg(infix_expr.left as ast.Ident, reg)
|
|
||||||
}
|
|
||||||
ast.IntegerLiteral {
|
|
||||||
lit := infix_expr.right as ast.IntegerLiteral
|
|
||||||
g.code_gen.cmp_var(infix_expr.left as ast.Ident, lit.val.int())
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.n_error('unhandled expression type')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match infix_expr.left.tok_kind {
|
|
||||||
.lt {
|
|
||||||
jump_addr = g.code_gen.cjmp(.jge)
|
|
||||||
}
|
|
||||||
.gt {
|
|
||||||
jump_addr = g.code_gen.cjmp(.jle)
|
|
||||||
}
|
|
||||||
.le {
|
|
||||||
jump_addr = g.code_gen.cjmp(.jg)
|
|
||||||
}
|
|
||||||
.ge {
|
|
||||||
jump_addr = g.code_gen.cjmp(.jl)
|
|
||||||
}
|
|
||||||
.ne {
|
|
||||||
jump_addr = g.code_gen.cjmp(.je)
|
|
||||||
}
|
|
||||||
.eq {
|
|
||||||
jump_addr = g.code_gen.cjmp(.jne)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.n_error('unhandled infix cond token')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.n_error('unhandled infix.left')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end_label := g.labels.new_label()
|
|
||||||
g.labels.patches << LabelPatch{
|
|
||||||
id: end_label
|
|
||||||
pos: jump_addr
|
|
||||||
}
|
|
||||||
g.println('; jump to label ${end_label}')
|
|
||||||
g.labels.branches << BranchLabel{
|
|
||||||
name: node.label
|
|
||||||
start: start_label
|
|
||||||
end: end_label
|
|
||||||
}
|
|
||||||
g.stmts(node.stmts)
|
|
||||||
g.labels.branches.pop()
|
|
||||||
// Go back to `cmp ...`
|
|
||||||
g.code_gen.jmp_back(start)
|
|
||||||
// Update the jump addr to current pos
|
|
||||||
g.labels.addrs[end_label] = g.pos()
|
|
||||||
g.println('; label ${end_label}')
|
|
||||||
g.println('jmp after for')
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) stmt(node ast.Stmt) {
|
|
||||||
match node {
|
|
||||||
ast.AssignStmt {
|
|
||||||
g.code_gen.assign_stmt(node)
|
|
||||||
}
|
|
||||||
ast.Block {
|
|
||||||
g.stmts(node.stmts)
|
|
||||||
}
|
|
||||||
ast.BranchStmt {
|
|
||||||
label_name := node.label
|
|
||||||
for i := g.labels.branches.len - 1; i >= 0; i-- {
|
|
||||||
branch := g.labels.branches[i]
|
|
||||||
if label_name == '' || label_name == branch.name {
|
|
||||||
label := if node.kind == .key_break {
|
|
||||||
branch.end
|
|
||||||
} else { // continue
|
|
||||||
branch.start
|
|
||||||
}
|
|
||||||
jump_addr := g.code_gen.jmp(0)
|
|
||||||
g.labels.patches << LabelPatch{
|
|
||||||
id: label
|
|
||||||
pos: jump_addr
|
|
||||||
}
|
|
||||||
g.println('; jump to ${label}: ${node.kind}')
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.ConstDecl {}
|
|
||||||
ast.DeferStmt {
|
|
||||||
name := '_defer${g.defer_stmts.len}'
|
|
||||||
defer_var := g.get_var_offset(name)
|
|
||||||
g.code_gen.mov_int_to_var(LocalVar{defer_var, ast.i64_type_idx, name}, 1)
|
|
||||||
g.defer_stmts << node
|
|
||||||
g.defer_stmts[g.defer_stmts.len - 1].idx_in_fn = g.defer_stmts.len - 1
|
|
||||||
}
|
|
||||||
ast.ExprStmt {
|
|
||||||
g.expr(node.expr)
|
|
||||||
}
|
|
||||||
ast.FnDecl {
|
|
||||||
g.fn_decl(node)
|
|
||||||
}
|
|
||||||
ast.ForCStmt {
|
|
||||||
g.gen_forc_stmt(node)
|
|
||||||
}
|
|
||||||
ast.ForInStmt {
|
|
||||||
if node.stmts.len == 0 {
|
|
||||||
// if no statements, just dont make it
|
|
||||||
return
|
|
||||||
}
|
|
||||||
g.code_gen.for_in_stmt(node)
|
|
||||||
}
|
|
||||||
ast.ForStmt {
|
|
||||||
g.for_stmt(node)
|
|
||||||
}
|
|
||||||
ast.HashStmt {
|
|
||||||
words := node.val.split(' ')
|
|
||||||
for word in words {
|
|
||||||
if word.len != 2 {
|
|
||||||
g.n_error('opcodes format: xx xx xx xx\nhash statements are not allowed with the native backend, use the C backend for extended C interoperability.')
|
|
||||||
}
|
|
||||||
b := unsafe { C.strtol(&char(word.str), 0, 16) }
|
|
||||||
// b := word.u8()
|
|
||||||
// println('"$word" $b')
|
|
||||||
g.write8(b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.Module {}
|
|
||||||
ast.Return {
|
|
||||||
g.code_gen.return_stmt(node)
|
|
||||||
}
|
|
||||||
ast.AsmStmt {
|
|
||||||
g.code_gen.gen_asm_stmt(node)
|
|
||||||
}
|
|
||||||
ast.AssertStmt {
|
|
||||||
g.code_gen.gen_assert(node)
|
|
||||||
}
|
|
||||||
ast.Import {} // do nothing here
|
|
||||||
ast.StructDecl {}
|
|
||||||
ast.EnumDecl {}
|
|
||||||
else {
|
|
||||||
eprintln('native.stmt(): bad node: ' + node.type_name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn C.strtol(str &char, endptr &&char, base int) int
|
|
||||||
|
|
||||||
union F64I64 {
|
|
||||||
f f64
|
|
||||||
i i64
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) expr(node ast.Expr) {
|
|
||||||
match node {
|
|
||||||
ast.ParExpr {
|
|
||||||
g.expr(node.expr)
|
|
||||||
}
|
|
||||||
ast.ArrayInit {
|
|
||||||
g.n_error('array init expr not supported yet')
|
|
||||||
}
|
|
||||||
ast.BoolLiteral {
|
|
||||||
g.code_gen.mov64(g.code_gen.main_reg(), if node.val {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
ast.CallExpr {
|
|
||||||
if node.name == 'C.syscall' {
|
|
||||||
g.code_gen.gen_syscall(node)
|
|
||||||
} else if node.name == 'exit' {
|
|
||||||
g.code_gen.gen_exit(node.args[0].expr)
|
|
||||||
} else if node.name in ['println', 'print', 'eprintln', 'eprint'] {
|
|
||||||
expr := node.args[0].expr
|
|
||||||
typ := node.args[0].typ
|
|
||||||
g.gen_print_from_expr(expr, typ, node.name)
|
|
||||||
} else {
|
|
||||||
g.code_gen.call_fn(node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.FloatLiteral {
|
|
||||||
val := g.eval.expr(node, ast.float_literal_type_idx).float_val()
|
|
||||||
g.code_gen.load_fp(val)
|
|
||||||
}
|
|
||||||
ast.Ident {
|
|
||||||
var := g.get_var_from_ident(node)
|
|
||||||
// XXX this is intel specific
|
|
||||||
match var {
|
|
||||||
LocalVar {
|
|
||||||
if g.is_register_type(var.typ) {
|
|
||||||
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), node as ast.Ident)
|
|
||||||
} else if var.typ.is_pure_float() {
|
|
||||||
g.code_gen.load_fp_var(node as ast.Ident)
|
|
||||||
} else {
|
|
||||||
ts := g.table.sym(var.typ)
|
|
||||||
match ts.info {
|
|
||||||
ast.Struct {
|
|
||||||
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), g.get_var_offset(node.name))
|
|
||||||
}
|
|
||||||
ast.Enum {
|
|
||||||
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), node as ast.Ident,
|
|
||||||
typ: ast.int_type_idx
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.n_error('Unsupported variable type')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.n_error('Unsupported variable kind')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast.IfExpr {
|
|
||||||
g.if_expr(node)
|
|
||||||
}
|
|
||||||
ast.InfixExpr {
|
|
||||||
g.code_gen.infix_expr(node)
|
|
||||||
}
|
|
||||||
ast.IntegerLiteral {
|
|
||||||
g.code_gen.movabs(g.code_gen.main_reg(), i64(node.val.u64()))
|
|
||||||
}
|
|
||||||
ast.Nil {
|
|
||||||
g.code_gen.movabs(g.code_gen.main_reg(), 0)
|
|
||||||
}
|
|
||||||
ast.PostfixExpr {
|
|
||||||
g.postfix_expr(node)
|
|
||||||
}
|
|
||||||
ast.PrefixExpr {
|
|
||||||
g.code_gen.prefix_expr(node)
|
|
||||||
}
|
|
||||||
ast.StringLiteral {
|
|
||||||
str := g.eval_str_lit_escape_codes(node)
|
|
||||||
g.allocate_string(str, 3, .rel32)
|
|
||||||
}
|
|
||||||
ast.CharLiteral {
|
|
||||||
bytes := g.eval_escape_codes(node.val)
|
|
||||||
.bytes()
|
|
||||||
mut val := rune(0)
|
|
||||||
for i, v in bytes {
|
|
||||||
val |= v << (i * 8)
|
|
||||||
if i >= sizeof(rune) {
|
|
||||||
g.n_error('runes are only 4 bytes wide')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.code_gen.movabs(g.code_gen.main_reg(), i64(val))
|
|
||||||
}
|
|
||||||
ast.StructInit {
|
|
||||||
pos := g.allocate_by_type('_anonstruct', node.typ)
|
|
||||||
g.code_gen.init_struct(LocalVar{ offset: pos, typ: node.typ }, node)
|
|
||||||
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), pos)
|
|
||||||
}
|
|
||||||
ast.GoExpr {
|
|
||||||
g.v_error('native backend doesnt support threads yet', node.pos)
|
|
||||||
}
|
|
||||||
ast.MatchExpr {
|
|
||||||
g.code_gen.gen_match_expr(node)
|
|
||||||
}
|
|
||||||
ast.SelectorExpr {
|
|
||||||
g.code_gen.gen_selector_expr(node)
|
|
||||||
}
|
|
||||||
ast.CastExpr {
|
|
||||||
g.code_gen.gen_cast_expr(node)
|
|
||||||
}
|
|
||||||
ast.EnumVal {
|
|
||||||
type_name := g.table.get_type_name(node.typ)
|
|
||||||
g.code_gen.mov(g.code_gen.main_reg(), g.enum_vals[type_name].fields[node.val])
|
|
||||||
}
|
|
||||||
ast.UnsafeExpr {
|
|
||||||
g.expr(node.expr)
|
|
||||||
}
|
|
||||||
ast.ConcatExpr {
|
|
||||||
g.code_gen.gen_concat_expr(node)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.n_error('expr: unhandled node type: ${node.type_name()}')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) condition(expr ast.Expr, neg bool) int {
|
|
||||||
g.expr(expr)
|
|
||||||
g.code_gen.cmp_zero(g.code_gen.main_reg())
|
|
||||||
return g.code_gen.cjmp(if neg { .jne } else { .je })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) if_expr(node ast.IfExpr) {
|
|
||||||
if node.is_comptime {
|
|
||||||
if stmts := g.comptime_conditional(node) {
|
|
||||||
g.stmts(stmts)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if node.branches.len == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mut endif_label := 0
|
|
||||||
has_endif := node.branches.len > 1
|
|
||||||
if has_endif {
|
|
||||||
endif_label = g.labels.new_label()
|
|
||||||
}
|
|
||||||
for idx in 0 .. node.branches.len {
|
|
||||||
branch := node.branches[idx]
|
|
||||||
if idx == node.branches.len - 1 && node.has_else {
|
|
||||||
g.stmts(branch.stmts)
|
|
||||||
} else {
|
|
||||||
if branch.cond is ast.BoolLiteral {
|
|
||||||
if branch.cond.val {
|
|
||||||
g.stmts(branch.stmts)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
expr := branch.cond
|
|
||||||
label := g.labels.new_label()
|
|
||||||
cjmp_addr := g.condition(expr, false)
|
|
||||||
g.labels.patches << LabelPatch{
|
|
||||||
id: label
|
|
||||||
pos: cjmp_addr
|
|
||||||
}
|
|
||||||
g.println('; jump to label ${label}')
|
|
||||||
g.stmts(branch.stmts)
|
|
||||||
if has_endif {
|
|
||||||
jump_addr := g.code_gen.jmp(0)
|
|
||||||
g.labels.patches << LabelPatch{
|
|
||||||
id: endif_label
|
|
||||||
pos: jump_addr
|
|
||||||
}
|
|
||||||
g.println('; jump to label ${endif_label}')
|
|
||||||
}
|
|
||||||
// println('after if g.pos=$g.pos() jneaddr=$cjmp_addr')
|
|
||||||
g.labels.addrs[label] = g.pos()
|
|
||||||
g.println('; label ${label}')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if has_endif {
|
|
||||||
g.labels.addrs[endif_label] = g.pos()
|
|
||||||
g.println('; label ${endif_label}')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) postfix_expr(node ast.PostfixExpr) {
|
|
||||||
if node.expr !is ast.Ident {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ident := node.expr as ast.Ident
|
|
||||||
match node.op {
|
|
||||||
.inc {
|
|
||||||
g.code_gen.inc_var(ident)
|
|
||||||
}
|
|
||||||
.dec {
|
|
||||||
g.code_gen.dec_var(ident)
|
|
||||||
}
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[noreturn]
|
[noreturn]
|
||||||
pub fn (mut g Gen) n_error(s string) {
|
pub fn (mut g Gen) n_error(s string) {
|
||||||
util.verror('native error', s)
|
util.verror('native error', s)
|
||||||
|
258
vlib/v/gen/native/stmt.v
Normal file
258
vlib/v/gen/native/stmt.v
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
// Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
|
module native
|
||||||
|
|
||||||
|
import v.ast
|
||||||
|
|
||||||
|
fn C.strtol(str &char, endptr &&char, base int) int
|
||||||
|
|
||||||
|
pub fn (mut g Gen) stmts(stmts []ast.Stmt) {
|
||||||
|
for stmt in stmts {
|
||||||
|
g.stmt(stmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) stmt(node ast.Stmt) {
|
||||||
|
match node {
|
||||||
|
ast.AssignStmt {
|
||||||
|
g.code_gen.assign_stmt(node)
|
||||||
|
}
|
||||||
|
ast.Block {
|
||||||
|
g.stmts(node.stmts)
|
||||||
|
}
|
||||||
|
ast.BranchStmt {
|
||||||
|
label_name := node.label
|
||||||
|
for i := g.labels.branches.len - 1; i >= 0; i-- {
|
||||||
|
branch := g.labels.branches[i]
|
||||||
|
if label_name == '' || label_name == branch.name {
|
||||||
|
label := if node.kind == .key_break {
|
||||||
|
branch.end
|
||||||
|
} else { // continue
|
||||||
|
branch.start
|
||||||
|
}
|
||||||
|
jump_addr := g.code_gen.jmp(0)
|
||||||
|
g.labels.patches << LabelPatch{
|
||||||
|
id: label
|
||||||
|
pos: jump_addr
|
||||||
|
}
|
||||||
|
g.println('; jump to ${label}: ${node.kind}')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.ConstDecl {}
|
||||||
|
ast.DeferStmt {
|
||||||
|
name := '_defer${g.defer_stmts.len}'
|
||||||
|
defer_var := g.get_var_offset(name)
|
||||||
|
g.code_gen.mov_int_to_var(LocalVar{defer_var, ast.i64_type_idx, name}, 1)
|
||||||
|
g.defer_stmts << node
|
||||||
|
g.defer_stmts[g.defer_stmts.len - 1].idx_in_fn = g.defer_stmts.len - 1
|
||||||
|
}
|
||||||
|
ast.ExprStmt {
|
||||||
|
g.expr(node.expr)
|
||||||
|
}
|
||||||
|
ast.FnDecl {
|
||||||
|
g.fn_decl(node)
|
||||||
|
}
|
||||||
|
ast.ForCStmt {
|
||||||
|
g.gen_forc_stmt(node)
|
||||||
|
}
|
||||||
|
ast.ForInStmt {
|
||||||
|
if node.stmts.len == 0 {
|
||||||
|
// if no statements, just dont make it
|
||||||
|
return
|
||||||
|
}
|
||||||
|
g.code_gen.for_in_stmt(node)
|
||||||
|
}
|
||||||
|
ast.ForStmt {
|
||||||
|
g.for_stmt(node)
|
||||||
|
}
|
||||||
|
ast.HashStmt {
|
||||||
|
words := node.val.split(' ')
|
||||||
|
for word in words {
|
||||||
|
if word.len != 2 {
|
||||||
|
g.n_error('opcodes format: xx xx xx xx\nhash statements are not allowed with the native backend, use the C backend for extended C interoperability.')
|
||||||
|
}
|
||||||
|
b := unsafe { C.strtol(&char(word.str), 0, 16) }
|
||||||
|
// b := word.u8()
|
||||||
|
// println('"$word" $b')
|
||||||
|
g.write8(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.Module {}
|
||||||
|
ast.Return {
|
||||||
|
g.code_gen.return_stmt(node)
|
||||||
|
}
|
||||||
|
ast.AsmStmt {
|
||||||
|
g.code_gen.gen_asm_stmt(node)
|
||||||
|
}
|
||||||
|
ast.AssertStmt {
|
||||||
|
g.code_gen.gen_assert(node)
|
||||||
|
}
|
||||||
|
ast.Import {} // do nothing here
|
||||||
|
ast.StructDecl {}
|
||||||
|
ast.EnumDecl {}
|
||||||
|
else {
|
||||||
|
eprintln('native.stmt(): bad node: ' + node.type_name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_forc_stmt(node ast.ForCStmt) {
|
||||||
|
if node.has_init {
|
||||||
|
g.stmts([node.init])
|
||||||
|
}
|
||||||
|
start := g.pos()
|
||||||
|
start_label := g.labels.new_label()
|
||||||
|
mut jump_addr := i64(0)
|
||||||
|
if node.has_cond {
|
||||||
|
cond := node.cond
|
||||||
|
match cond {
|
||||||
|
ast.InfixExpr {
|
||||||
|
match cond.left {
|
||||||
|
ast.Ident {
|
||||||
|
lit := cond.right as ast.IntegerLiteral
|
||||||
|
g.code_gen.cmp_var(cond.left as ast.Ident, lit.val.int())
|
||||||
|
match cond.op {
|
||||||
|
.gt {
|
||||||
|
jump_addr = g.code_gen.cjmp(.jle)
|
||||||
|
}
|
||||||
|
.lt {
|
||||||
|
jump_addr = g.code_gen.cjmp(.jge)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('unsupported conditional in for-c loop')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('unhandled infix.left')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
// dump(node.cond)
|
||||||
|
g.expr(node.cond)
|
||||||
|
}
|
||||||
|
end_label := g.labels.new_label()
|
||||||
|
g.labels.patches << LabelPatch{
|
||||||
|
id: end_label
|
||||||
|
pos: int(jump_addr)
|
||||||
|
}
|
||||||
|
g.println('; jump to label ${end_label}')
|
||||||
|
g.labels.branches << BranchLabel{
|
||||||
|
name: node.label
|
||||||
|
start: start_label
|
||||||
|
end: end_label
|
||||||
|
}
|
||||||
|
g.stmts(node.stmts)
|
||||||
|
g.labels.addrs[start_label] = g.pos()
|
||||||
|
g.println('; label ${start_label}')
|
||||||
|
if node.has_inc {
|
||||||
|
g.stmts([node.inc])
|
||||||
|
}
|
||||||
|
g.labels.branches.pop()
|
||||||
|
g.code_gen.jmp_back(start)
|
||||||
|
g.labels.addrs[end_label] = g.pos()
|
||||||
|
g.println('; jump to label ${end_label}')
|
||||||
|
|
||||||
|
// loop back
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) for_stmt(node ast.ForStmt) {
|
||||||
|
if node.is_inf {
|
||||||
|
if node.stmts.len == 0 {
|
||||||
|
g.code_gen.infloop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// infinite loop
|
||||||
|
start := g.pos()
|
||||||
|
start_label := g.labels.new_label()
|
||||||
|
g.labels.addrs[start_label] = start
|
||||||
|
g.println('; label ${start_label}')
|
||||||
|
end_label := g.labels.new_label()
|
||||||
|
g.labels.branches << BranchLabel{
|
||||||
|
name: node.label
|
||||||
|
start: start_label
|
||||||
|
end: end_label
|
||||||
|
}
|
||||||
|
g.stmts(node.stmts)
|
||||||
|
g.labels.branches.pop()
|
||||||
|
g.code_gen.jmp_back(start)
|
||||||
|
g.println('jmp after infinite for')
|
||||||
|
g.labels.addrs[end_label] = g.pos()
|
||||||
|
g.println('; label ${end_label}')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
infix_expr := node.cond as ast.InfixExpr
|
||||||
|
mut jump_addr := 0 // location of `jne *00 00 00 00*`
|
||||||
|
start := g.pos()
|
||||||
|
start_label := g.labels.new_label()
|
||||||
|
g.labels.addrs[start_label] = start
|
||||||
|
g.println('; label ${start_label}')
|
||||||
|
match infix_expr.left {
|
||||||
|
ast.Ident {
|
||||||
|
match infix_expr.right {
|
||||||
|
ast.Ident {
|
||||||
|
reg := g.code_gen.main_reg()
|
||||||
|
g.code_gen.mov_var_to_reg(reg, infix_expr.right as ast.Ident)
|
||||||
|
g.code_gen.cmp_var_reg(infix_expr.left as ast.Ident, reg)
|
||||||
|
}
|
||||||
|
ast.IntegerLiteral {
|
||||||
|
lit := infix_expr.right as ast.IntegerLiteral
|
||||||
|
g.code_gen.cmp_var(infix_expr.left as ast.Ident, lit.val.int())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('unhandled expression type')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match infix_expr.left.tok_kind {
|
||||||
|
.lt {
|
||||||
|
jump_addr = g.code_gen.cjmp(.jge)
|
||||||
|
}
|
||||||
|
.gt {
|
||||||
|
jump_addr = g.code_gen.cjmp(.jle)
|
||||||
|
}
|
||||||
|
.le {
|
||||||
|
jump_addr = g.code_gen.cjmp(.jg)
|
||||||
|
}
|
||||||
|
.ge {
|
||||||
|
jump_addr = g.code_gen.cjmp(.jl)
|
||||||
|
}
|
||||||
|
.ne {
|
||||||
|
jump_addr = g.code_gen.cjmp(.je)
|
||||||
|
}
|
||||||
|
.eq {
|
||||||
|
jump_addr = g.code_gen.cjmp(.jne)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('unhandled infix cond token')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.n_error('unhandled infix.left')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end_label := g.labels.new_label()
|
||||||
|
g.labels.patches << LabelPatch{
|
||||||
|
id: end_label
|
||||||
|
pos: jump_addr
|
||||||
|
}
|
||||||
|
g.println('; jump to label ${end_label}')
|
||||||
|
g.labels.branches << BranchLabel{
|
||||||
|
name: node.label
|
||||||
|
start: start_label
|
||||||
|
end: end_label
|
||||||
|
}
|
||||||
|
g.stmts(node.stmts)
|
||||||
|
g.labels.branches.pop()
|
||||||
|
// Go back to `cmp ...`
|
||||||
|
g.code_gen.jmp_back(start)
|
||||||
|
// Update the jump addr to current pos
|
||||||
|
g.labels.addrs[end_label] = g.pos()
|
||||||
|
g.println('; label ${end_label}')
|
||||||
|
g.println('jmp after for')
|
||||||
|
}
|
28
vlib/v/gen/native/tests/assign.vv
Normal file
28
vlib/v/gen/native/tests/assign.vv
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
fn main() {
|
||||||
|
test_int()
|
||||||
|
test_fp()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_int() {
|
||||||
|
a := 100
|
||||||
|
mut b := a
|
||||||
|
b += b
|
||||||
|
b += 50
|
||||||
|
|
||||||
|
assert b == 250
|
||||||
|
|
||||||
|
mut c := u8(b)
|
||||||
|
d := 4
|
||||||
|
c += u8(-d)
|
||||||
|
println(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_fp() {
|
||||||
|
a := 1.0
|
||||||
|
mut b := a
|
||||||
|
b += 0.5
|
||||||
|
b *= 4
|
||||||
|
b /= 2
|
||||||
|
|
||||||
|
println(int(b))
|
||||||
|
}
|
2
vlib/v/gen/native/tests/assign.vv.out
Normal file
2
vlib/v/gen/native/tests/assign.vv.out
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
246
|
||||||
|
3
|
Loading…
x
Reference in New Issue
Block a user