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

native: increase support for ast.Alias and ast.TypeOf (#18722)

This commit is contained in:
Spydr 2023-07-01 10:39:39 +02:00 committed by GitHub
parent 015ccc2a7f
commit ee429bb51d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 406 additions and 201 deletions

View File

@ -112,11 +112,6 @@ fn (mut c Amd64) dec(reg Amd64Register) {
c.g.println('dec ${reg}') c.g.println('dec ${reg}')
} }
[inline]
fn byt(n int, s int) u8 {
return u8((n >> (s * 8)) & 0xff)
}
fn (mut c Amd64) inc(reg Amd64Register) { fn (mut c Amd64) inc(reg Amd64Register) {
c.g.write8(0x48) c.g.write8(0x48)
c.g.write8(0xff) c.g.write8(0xff)
@ -1009,6 +1004,7 @@ fn (mut c Amd64) push(reg Amd64Register) {
} }
c.is_16bit_aligned = !c.is_16bit_aligned c.is_16bit_aligned = !c.is_16bit_aligned
c.g.println('push ${reg}') c.g.println('push ${reg}')
c.g.stack_depth++
} }
pub fn (mut c Amd64) pop(reg Amd64Register) { pub fn (mut c Amd64) pop(reg Amd64Register) {
@ -1018,6 +1014,7 @@ pub fn (mut c Amd64) pop(reg Amd64Register) {
c.g.write8(0x58 + int(reg) % 8) c.g.write8(0x58 + int(reg) % 8)
c.is_16bit_aligned = !c.is_16bit_aligned c.is_16bit_aligned = !c.is_16bit_aligned
c.g.println('pop ${reg}') c.g.println('pop ${reg}')
c.g.stack_depth--
} }
pub fn (mut c Amd64) sub8(reg Amd64Register, val int) { pub fn (mut c Amd64) sub8(reg Amd64Register, val int) {
@ -2102,9 +2099,15 @@ fn (mut c Amd64) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, n
ast.StructInit { ast.StructInit {
match node.op { match node.op {
.decl_assign { .decl_assign {
c.g.allocate_by_type(name, right.typ) dest := c.g.allocate_by_type(name, right.typ)
if right.typ.is_any_kind_of_pointer()
|| c.g.unwrap(right.typ).is_any_kind_of_pointer() {
c.g.expr(right)
c.mov_reg_to_var(LocalVar{dest, ast.u64_type_idx, name}, Amd64Register.rax)
} else {
c.init_struct(ident, right) c.init_struct(ident, right)
} }
}
else { else {
c.g.n_error('Unexpected operator `${node.op}`') c.g.n_error('Unexpected operator `${node.op}`')
} }
@ -2773,6 +2776,9 @@ fn (mut c Amd64) gen_left_value(node ast.Expr) {
c.add(.rax, offset) c.add(.rax, offset)
} }
} }
ast.StructInit, ast.ArrayInit {
c.g.expr(node)
}
ast.IndexExpr {} // TODO ast.IndexExpr {} // TODO
ast.PrefixExpr { ast.PrefixExpr {
if node.op != .mul { if node.op != .mul {
@ -2825,23 +2831,7 @@ fn (mut c Amd64) prefix_expr(node ast.PrefixExpr) {
} }
} }
fn (mut c Amd64) infix_expr(node ast.InfixExpr) { fn (mut c Amd64) fp_infix_expr(node ast.InfixExpr, left_type ast.Type) {
if node.op in [.logical_or, .and] {
c.g.expr(node.left)
label := c.g.labels.new_label()
c.cmp_zero(Amd64Register.rax)
jump_addr := c.cjmp(if node.op == .logical_or { .jne } else { .je })
c.g.labels.patches << LabelPatch{
id: label
pos: jump_addr
}
c.g.expr(node.right)
c.g.labels.addrs[label] = c.g.pos()
return
} else {
c.g.expr(node.right)
if node.left_type.is_pure_float() {
typ := node.left_type
// optimize for ast.Ident // optimize for ast.Ident
match node.left { match node.left {
ast.Ident { ast.Ident {
@ -2865,7 +2855,7 @@ fn (mut c Amd64) infix_expr(node ast.InfixExpr) {
c.g.println('and eax, 0x1') c.g.println('and eax, 0x1')
} }
.gt, .lt, .ge, .le { .gt, .lt, .ge, .le {
c.cmp_sse(.xmm0, .xmm1, typ) c.cmp_sse(.xmm0, .xmm1, left_type)
// TODO mov_extend_reg // TODO mov_extend_reg
c.mov64(Amd64Register.rax, 0) c.mov64(Amd64Register.rax, 0)
c.cset(match node.op { c.cset(match node.op {
@ -2876,23 +2866,47 @@ fn (mut c Amd64) infix_expr(node ast.InfixExpr) {
}) })
} }
.plus { .plus {
c.add_sse(.xmm0, .xmm1, typ) c.add_sse(.xmm0, .xmm1, left_type)
} }
.minus { .minus {
c.sub_sse(.xmm0, .xmm1, typ) c.sub_sse(.xmm0, .xmm1, left_type)
} }
.mul { .mul {
c.mul_sse(.xmm0, .xmm1, typ) c.mul_sse(.xmm0, .xmm1, left_type)
} }
.div { .div {
c.div_sse(.xmm0, .xmm1, typ) c.div_sse(.xmm0, .xmm1, left_type)
} }
else { else {
c.g.n_error('`${node.op}` expression is not supported right now') c.g.n_error('`${node.op}` expression is not supported right now')
} }
} }
}
fn (mut c Amd64) infix_expr(node ast.InfixExpr) {
if node.op in [.logical_or, .and] {
c.g.expr(node.left)
label := c.g.labels.new_label()
c.cmp_zero(Amd64Register.rax)
jump_addr := c.cjmp(if node.op == .logical_or { .jne } else { .je })
c.g.labels.patches << LabelPatch{
id: label
pos: jump_addr
}
c.g.expr(node.right)
c.g.labels.addrs[label] = c.g.pos()
return return
} }
c.g.expr(node.right)
left_type := c.g.unwrap(node.left_type)
if left_type.is_pure_float() {
c.fp_infix_expr(node, left_type)
return
}
// optimize for ast.Ident // optimize for ast.Ident
match node.left { match node.left {
ast.Ident { ast.Ident {
@ -2911,11 +2925,13 @@ fn (mut c Amd64) infix_expr(node ast.InfixExpr) {
}) })
} }
} }
if node.left_type !in ast.integer_type_idxs && node.left_type != ast.bool_type_idx
&& c.g.table.sym(node.left_type).info !is ast.Enum && !node.left_type.is_ptr() if left_type !in ast.integer_type_idxs && left_type != ast.bool_type_idx
&& !node.left_type.is_voidptr() { && c.g.table.sym(left_type).info !is ast.Enum && !left_type.is_any_kind_of_pointer()
c.g.n_error('unsupported type for `${node.op}`: ${node.left_type}') && node.left_type.is_any_kind_of_pointer() {
c.g.n_error('unsupported type for `${node.op}`: ${left_type}')
} }
// left: rax, right: rdx // left: rax, right: rdx
match node.op { match node.op {
.eq, .ne, .gt, .lt, .ge, .le { .eq, .ne, .gt, .lt, .ge, .le {
@ -2935,7 +2951,7 @@ fn (mut c Amd64) infix_expr(node ast.InfixExpr) {
c.g.println('imul rax, rdx') c.g.println('imul rax, rdx')
} }
.div { .div {
if node.left_type in ast.unsigned_integer_type_idxs { if left_type in ast.unsigned_integer_type_idxs {
c.g.write8(0xba) c.g.write8(0xba)
c.g.write32(0) c.g.write32(0)
c.g.println('mov edx, 0') c.g.println('mov edx, 0')
@ -2949,7 +2965,7 @@ fn (mut c Amd64) infix_expr(node ast.InfixExpr) {
} }
} }
.mod { .mod {
if node.left_type in ast.unsigned_integer_type_idxs { if left_type in ast.unsigned_integer_type_idxs {
c.g.write8(0xba) c.g.write8(0xba)
c.g.write32(0) c.g.write32(0)
c.g.println('mov edx, 0') c.g.println('mov edx, 0')
@ -2986,15 +3002,9 @@ fn (mut c Amd64) infix_expr(node ast.InfixExpr) {
} }
} }
} }
}
fn (mut c Amd64) trap() { fn (mut c Amd64) trap() {
// funnily works on x86 and arm64
if c.g.pref.arch == .arm64 {
c.g.write32(0xcccccccc)
} else {
c.g.write8(0xcc) c.g.write8(0xcc)
}
c.g.println('trap') c.g.println('trap')
} }
@ -3993,6 +4003,7 @@ fn (mut c Amd64) push_sse(reg Amd64SSERegister) {
c.g.println('movsd [rsp], ${reg}') c.g.println('movsd [rsp], ${reg}')
c.is_16bit_aligned = !c.is_16bit_aligned c.is_16bit_aligned = !c.is_16bit_aligned
c.g.println('; push ${reg}') c.g.println('; push ${reg}')
c.g.stack_depth++
} }
fn (mut c Amd64) pop_sse(reg Amd64SSERegister) { fn (mut c Amd64) pop_sse(reg Amd64SSERegister) {
@ -4008,6 +4019,7 @@ fn (mut c Amd64) pop_sse(reg Amd64SSERegister) {
c.g.println('add rsp, 0x8') c.g.println('add rsp, 0x8')
c.is_16bit_aligned = !c.is_16bit_aligned c.is_16bit_aligned = !c.is_16bit_aligned
c.g.println('; pop ${reg}') c.g.println('; pop ${reg}')
c.g.stack_depth--
} }
fn (mut c Amd64) gen_cast_expr(expr ast.CastExpr) { fn (mut c Amd64) gen_cast_expr(expr ast.CastExpr) {

View File

@ -385,7 +385,8 @@ fn (mut c Arm64) apicall(call ApiCall) {
} }
fn (mut c Arm64) trap() { fn (mut c Arm64) trap() {
panic('Arm64.trap() not implemented') c.g.write32(0xcccccccc)
c.g.println('trap')
} }
fn (mut c Arm64) leave() { fn (mut c Arm64) leave() {

View File

@ -4,6 +4,7 @@
module native module native
import v.ast import v.ast
import v.util
fn (mut g Gen) expr(node ast.Expr) { fn (mut g Gen) expr(node ast.Expr) {
match node { match node {
@ -16,54 +17,35 @@ fn (mut g Gen) expr(node ast.Expr) {
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), pos) g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), pos)
} }
ast.BoolLiteral { ast.BoolLiteral {
g.code_gen.mov64(g.code_gen.main_reg(), if node.val { g.code_gen.mov64(g.code_gen.main_reg(), int(node.val))
1
} else {
0
})
} }
ast.CallExpr { ast.CallExpr {
if node.name == 'C.syscall' { match node.name {
'C.syscall' {
g.code_gen.gen_syscall(node) g.code_gen.gen_syscall(node)
} else if node.name == 'exit' { }
'exit' {
g.code_gen.gen_exit(node.args[0].expr) g.code_gen.gen_exit(node.args[0].expr)
} else if node.name in ['println', 'print', 'eprintln', 'eprint'] { }
'println', 'print', 'eprintln', 'eprint' {
expr := node.args[0].expr expr := node.args[0].expr
typ := node.args[0].typ typ := node.args[0].typ
g.gen_print_from_expr(expr, typ, node.name) g.gen_print_from_expr(expr, typ, node.name)
} else { }
else {
g.code_gen.call_fn(node) g.code_gen.call_fn(node)
} }
} }
}
ast.FloatLiteral { ast.FloatLiteral {
val := g.eval.expr(node, ast.float_literal_type_idx).float_val() val := g.eval.expr(node, ast.float_literal_type_idx).float_val()
g.code_gen.load_fp(val) g.code_gen.load_fp(val)
} }
ast.Ident { ast.Ident {
var := g.get_var_from_ident(node) var := g.get_var_from_ident(node)
// XXX this is intel specific
match var { match var {
LocalVar { LocalVar {
if g.is_register_type(var.typ) { g.local_var_ident(node, var)
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(g.unwrap(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 { else {
g.n_error('Unsupported variable kind') g.n_error('Unsupported variable kind')
@ -131,12 +113,38 @@ fn (mut g Gen) expr(node ast.Expr) {
ast.ConcatExpr { ast.ConcatExpr {
g.code_gen.gen_concat_expr(node) g.code_gen.gen_concat_expr(node)
} }
ast.TypeOf {
g.gen_typeof_expr(node, false)
}
else { else {
g.n_error('expr: unhandled node type: ${node.type_name()}') g.n_error('expr: unhandled node type: ${node.type_name()}')
} }
} }
} }
fn (mut g Gen) local_var_ident(ident ast.Ident, var LocalVar) {
if g.is_register_type(var.typ) {
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), ident)
} else if g.is_fp_type(var.typ) {
g.code_gen.load_fp_var(ident)
} else {
ts := g.table.sym(g.unwrap(var.typ))
match ts.info {
ast.Struct {
g.code_gen.lea_var_to_reg(g.code_gen.main_reg(), g.get_var_offset(ident.name))
}
ast.Enum {
g.code_gen.mov_var_to_reg(g.code_gen.main_reg(), ident,
typ: ast.int_type_idx
)
}
else {
g.n_error('Unsupported variable type')
}
}
}
}
fn (mut g Gen) condition(expr ast.Expr, neg bool) int { fn (mut g Gen) condition(expr ast.Expr, neg bool) int {
g.expr(expr) g.expr(expr)
g.code_gen.cmp_zero(g.code_gen.main_reg()) g.code_gen.cmp_zero(g.code_gen.main_reg())
@ -213,10 +221,66 @@ fn (mut g Gen) postfix_expr(node ast.PostfixExpr) {
} }
} }
fn (mut g Gen) gen_typeof_expr(it ast.TypeOf, newline bool) { fn (mut g Gen) fn_decl_str(info ast.FnType) string {
mut fn_str := 'fn ('
for i, arg in info.func.params {
if arg.is_mut {
fn_str += 'mut '
}
if i > 0 {
fn_str += ', '
}
fn_str += util.strip_main_name(g.table.get_type_name(arg.typ))
}
fn_str += ')'
if info.func.return_type == ast.ovoid_type {
fn_str += ' ?'
} else if info.func.return_type == ast.rvoid_type {
fn_str += ' !'
} else if info.func.return_type != ast.void_type {
x := util.strip_main_name(g.table.get_type_name(info.func.return_type))
if info.func.return_type.has_flag(.option) {
fn_str += ' ?${x}'
} else if info.func.return_type.has_flag(.result) {
fn_str += ' !${x}'
} else {
fn_str += ' ${x}'
}
}
return fn_str
}
fn (mut g Gen) gen_typeof_expr(node ast.TypeOf, newline bool) {
nl := if newline { '\n' } else { '' } nl := if newline { '\n' } else { '' }
r := g.typ(it.typ).name ts := g.table.sym(node.typ)
g.code_gen.learel(g.code_gen.main_reg(), g.allocate_string('${r}${nl}', 3, .rel32)) mut str := ''
match ts.kind {
.sum_type {
g.n_error('`typeof()` is not implemented for sum types yet')
}
.array_fixed {
fixed_info := ts.info as ast.ArrayFixed
typ_name := g.table.get_type_name(fixed_info.elem_type)
str = '[${fixed_info.size}]${util.strip_main_name(typ_name)}'
}
.function {
func_info := ts.info as ast.FnType
if node.typ.is_ptr() {
str = '&'
}
str += g.fn_decl_str(func_info)
}
else {
str = util.strip_main_name(if node.typ.has_flag(.variadic) {
g.table.sym(g.table.value_type(node.typ)).name
} else {
g.table.type_to_str(node.typ)
})
}
}
g.code_gen.learel(g.code_gen.main_reg(), g.allocate_string('${str}${nl}', 3, .rel32))
} }
fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) { fn (mut g Gen) gen_print_from_expr(expr ast.Expr, typ ast.Type, name string) {

View File

@ -41,6 +41,7 @@ mut:
var_offset map[string]int // local var stack offset var_offset map[string]int // local var stack offset
var_alloc_size map[string]int // local var allocation size var_alloc_size map[string]int // local var allocation size
stack_var_pos int stack_var_pos int
stack_depth int
debug_pos int debug_pos int
errors []errors.Error errors []errors.Error
warnings []errors.Warning warnings []errors.Warning
@ -230,6 +231,11 @@ union F64I64 {
i i64 i i64
} }
[inline]
fn byt(n int, s int) u8 {
return u8((n >> (s * 8)) & 0xff)
}
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] {
@ -735,9 +741,15 @@ fn (mut g Gen) get_multi_return(types []ast.Type) MultiReturn {
return ret return ret
} }
fn (g Gen) is_register_type(typ ast.Type) bool { fn (mut g Gen) is_register_type(typ ast.Type) bool {
return typ.is_pure_int() || typ == ast.char_type_idx || typ.is_any_kind_of_pointer() return typ.is_pure_int() || typ == ast.char_type_idx
|| typ.is_bool() || typ.is_any_kind_of_pointer() || typ.is_bool()
|| (g.table.sym(typ).info is ast.Alias && g.is_register_type(g.unwrap(typ)))
}
fn (mut g Gen) is_fp_type(typ ast.Type) bool {
return typ.is_pure_float()
|| (g.table.sym(typ).info is ast.Alias && g.is_fp_type(g.unwrap(typ)))
} }
fn (mut g Gen) get_sizeof_ident(ident ast.Ident) int { fn (mut g Gen) get_sizeof_ident(ident ast.Ident) int {
@ -981,12 +993,17 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
} }
g.stack_var_pos = 0 g.stack_var_pos = 0
g.stack_depth = 0
g.register_function_address(name) g.register_function_address(name)
g.labels = &LabelTable{} g.labels = &LabelTable{}
g.defer_stmts.clear() g.defer_stmts.clear()
g.return_type = node.return_type g.return_type = node.return_type
g.code_gen.fn_decl(node) g.code_gen.fn_decl(node)
g.patch_labels() g.patch_labels()
if g.stack_depth != 0 {
g.println('^^^ stack_depth != 0 (${g.stack_depth}) !!!')
}
} }
pub fn (mut g Gen) register_function_address(name string) { pub fn (mut g Gen) register_function_address(name string) {

View File

@ -1,6 +1,8 @@
fn main() { fn main() {
test_int() test_int()
test_fp() test_fp()
test_unsafe()
test_alias(100, 9)
} }
fn test_int() { fn test_int() {
@ -26,3 +28,20 @@ fn test_fp() {
println(int(b)) println(int(b))
} }
fn test_unsafe() {
a := 10
unsafe {
b := 4
println(a + b)
}
}
type Integer = int
fn test_alias(a Integer, b Integer) {
e := a + b
assert e == a + b
println(e)
}

View File

@ -1,2 +1,4 @@
246 246
3 3
14
109

View File

@ -56,6 +56,9 @@ fn struct_test() {
mut f := &e mut f := &e
f.a = 3 f.a = 3
assert e.a == 3 assert e.a == 3
g := &Mutable{2}
assert g.a == 2
} }
type AliasedStruct = Mutable type AliasedStruct = Mutable

View File

@ -1,16 +1,86 @@
type IntegerAlias = int
struct Test {
a int = 0
b voidptr = voidptr(0)
c &Test = unsafe { 0 }
d map[int][3]string = {}
}
fn main() { fn main() {
// strings
a := 'string' a := 'string'
t := typeof(a) t := typeof(a)
println(t) println(t)
t2 := typeof('another string') t2 := typeof('another string')
println(t2) println(t2)
// integers
n := 123 n := 123
t3 := typeof(n) t3 := typeof(n)
println(t3) println(t3)
t4 := typeof(123) t4 := typeof(123)
println(t4) println(t4)
// id := 'hello world' test_alias(0)
// println(id)
// pointers
t5 := typeof(voidptr(0))
println(t5)
t6 := typeof(charptr(0))
println(t6)
t7 := typeof(&u8(3))
println(t7)
// functions
t8 := typeof(main)
println(t8)
t9 := typeof(test_alias)
println(t9)
t10 := typeof(return_func)
println(t10)
// arrays
t11 := typeof([]int{})
println(t11)
t12 := typeof([16]int{})
println(t12)
// maps
t13 := typeof(map[int]string)
println(t13)
t14 := typeof(map[int][2]int)
println(t14)
// options, results
t15 := typeof(result_func)
println(t15)
t16 := typeof(result_func())
println(t16)
t17 := typeof(opt_func)
println(t17)
t18 := typeof(opt_func())
println(t18)
// structs
t19 := typeof(Test{})
println(t19)
t20 := typeof(Test{}.d)
println(t20)
}
fn test_alias(t IntegerAlias) {
t1 := typeof(t)
println(t1)
}
fn return_func(foo int, bar []int, baz voidptr) string {
return ''
}
fn result_func() !int {
return 0
}
fn opt_func() ?int {
return 0
} }

View File

@ -2,3 +2,20 @@ string
string string
int int
int literal int literal
IntegerAlias
voidptr
charptr
&u8
fn ()
fn (IntegerAlias)
fn (int, []int, voidptr) string
[]int
[16]int
map[int]string
map[int][2]int
fn () !int
!int
fn () ?int
?int
Test
map[int][3]string