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}')
}
[inline]
fn byt(n int, s int) u8 {
return u8((n >> (s * 8)) & 0xff)
}
fn (mut c Amd64) inc(reg Amd64Register) {
c.g.write8(0x48)
c.g.write8(0xff)
@ -1009,6 +1004,7 @@ fn (mut c Amd64) push(reg Amd64Register) {
}
c.is_16bit_aligned = !c.is_16bit_aligned
c.g.println('push ${reg}')
c.g.stack_depth++
}
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.is_16bit_aligned = !c.is_16bit_aligned
c.g.println('pop ${reg}')
c.g.stack_depth--
}
pub fn (mut c Amd64) sub8(reg Amd64Register, val int) {
@ -2102,8 +2099,14 @@ fn (mut c Amd64) assign_right_expr(node ast.AssignStmt, i int, right ast.Expr, n
ast.StructInit {
match node.op {
.decl_assign {
c.g.allocate_by_type(name, right.typ)
c.init_struct(ident, right)
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)
}
}
else {
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)
}
}
ast.StructInit, ast.ArrayInit {
c.g.expr(node)
}
ast.IndexExpr {} // TODO
ast.PrefixExpr {
if node.op != .mul {
@ -2825,6 +2831,58 @@ fn (mut c Amd64) prefix_expr(node ast.PrefixExpr) {
}
}
fn (mut c Amd64) fp_infix_expr(node ast.InfixExpr, left_type ast.Type) {
// optimize for ast.Ident
match node.left {
ast.Ident {
c.mov_ssereg(.xmm1, .xmm0)
c.mov_var_to_ssereg(.xmm0, node.left as ast.Ident)
}
else {
c.push_sse(.xmm0)
c.g.expr(node.left)
c.pop_sse(.xmm1)
}
}
match node.op {
.eq, .ne {
c.g.write32(0xc1c20ff3)
c.g.write8(if node.op == .eq { 0x00 } else { 0x04 })
inst := if node.op == .eq { 'cmpeqss' } else { 'cmpneqss' }
c.g.println('${inst} xmm0, xmm1')
c.mov_ssereg_to_reg(.rax, .xmm0, ast.f32_type_idx)
c.g.write([u8(0x83), 0xe0, 0x01])
c.g.println('and eax, 0x1')
}
.gt, .lt, .ge, .le {
c.cmp_sse(.xmm0, .xmm1, left_type)
// TODO mov_extend_reg
c.mov64(Amd64Register.rax, 0)
c.cset(match node.op {
.gt { .a }
.lt { .b }
.ge { .ae }
else { .be }
})
}
.plus {
c.add_sse(.xmm0, .xmm1, left_type)
}
.minus {
c.sub_sse(.xmm0, .xmm1, left_type)
}
.mul {
c.mul_sse(.xmm0, .xmm1, left_type)
}
.div {
c.div_sse(.xmm0, .xmm1, left_type)
}
else {
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)
@ -2838,163 +2896,115 @@ fn (mut c Amd64) infix_expr(node ast.InfixExpr) {
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
match node.left {
ast.Ident {
c.mov_ssereg(.xmm1, .xmm0)
c.mov_var_to_ssereg(.xmm0, node.left as ast.Ident)
}
else {
c.push_sse(.xmm0)
c.g.expr(node.left)
c.pop_sse(.xmm1)
}
}
match node.op {
.eq, .ne {
c.g.write32(0xc1c20ff3)
c.g.write8(if node.op == .eq { 0x00 } else { 0x04 })
inst := if node.op == .eq { 'cmpeqss' } else { 'cmpneqss' }
c.g.println('${inst} xmm0, xmm1')
c.mov_ssereg_to_reg(.rax, .xmm0, ast.f32_type_idx)
c.g.write([u8(0x83), 0xe0, 0x01])
c.g.println('and eax, 0x1')
}
.gt, .lt, .ge, .le {
c.cmp_sse(.xmm0, .xmm1, typ)
// TODO mov_extend_reg
c.mov64(Amd64Register.rax, 0)
c.cset(match node.op {
.gt { .a }
.lt { .b }
.ge { .ae }
else { .be }
})
}
.plus {
c.add_sse(.xmm0, .xmm1, typ)
}
.minus {
c.sub_sse(.xmm0, .xmm1, typ)
}
.mul {
c.mul_sse(.xmm0, .xmm1, typ)
}
.div {
c.div_sse(.xmm0, .xmm1, typ)
}
else {
c.g.n_error('`${node.op}` expression is not supported right now')
}
}
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
match node.left {
ast.Ident {
c.mov_reg(match node.op {
.left_shift, .right_shift, .unsigned_right_shift, .div, .mod { Amd64Register.rcx }
else { Amd64Register.rdx }
}, Amd64Register.rax)
c.mov_var_to_reg(Amd64Register.rax, node.left as ast.Ident)
}
// optimize for ast.Ident
match node.left {
ast.Ident {
c.mov_reg(match node.op {
.left_shift, .right_shift, .unsigned_right_shift, .div, .mod { Amd64Register.rcx }
else { Amd64Register.rdx }
}, Amd64Register.rax)
c.mov_var_to_reg(Amd64Register.rax, node.left as ast.Ident)
}
else {
c.push(Amd64Register.rax)
c.g.expr(node.left)
c.pop(match node.op {
.left_shift, .right_shift, .unsigned_right_shift, .div, .mod { .rcx }
else { .rdx }
})
else {
c.push(Amd64Register.rax)
c.g.expr(node.left)
c.pop(match node.op {
.left_shift, .right_shift, .unsigned_right_shift, .div, .mod { .rcx }
else { .rdx }
})
}
}
if left_type !in ast.integer_type_idxs && left_type != ast.bool_type_idx
&& c.g.table.sym(left_type).info !is ast.Enum && !left_type.is_any_kind_of_pointer()
&& node.left_type.is_any_kind_of_pointer() {
c.g.n_error('unsupported type for `${node.op}`: ${left_type}')
}
// left: rax, right: rdx
match node.op {
.eq, .ne, .gt, .lt, .ge, .le {
c.cmp_reg(.rax, .rdx)
// TODO mov_extend_reg
c.mov64(Amd64Register.rax, 0)
c.cset_op(node.op)
}
.plus {
c.add_reg(.rax, .rdx)
}
.minus {
c.sub_reg(.rax, .rdx)
}
.mul {
c.g.write32(0xc2af0f48)
c.g.println('imul rax, rdx')
}
.div {
if left_type in ast.unsigned_integer_type_idxs {
c.g.write8(0xba)
c.g.write32(0)
c.g.println('mov edx, 0')
c.g.write([u8(0x48), 0xf7, 0xf1])
c.g.println('div rcx')
} else {
c.g.write16(0x9948)
c.g.println('cqo')
c.g.write([u8(0x48), 0xf7, 0xf9])
c.g.println('idiv rcx')
}
}
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()
&& !node.left_type.is_voidptr() {
c.g.n_error('unsupported type for `${node.op}`: ${node.left_type}')
.mod {
if left_type in ast.unsigned_integer_type_idxs {
c.g.write8(0xba)
c.g.write32(0)
c.g.println('mov edx, 0')
c.g.write([u8(0x48), 0xf7, 0xf1])
c.g.println('div rcx')
} else {
c.g.write16(0x9948)
c.g.println('cqo')
c.g.write([u8(0x48), 0xf7, 0xf9])
c.g.println('idiv rcx')
}
c.mov_reg(Amd64Register.rax, Amd64Register.rdx)
}
// left: rax, right: rdx
match node.op {
.eq, .ne, .gt, .lt, .ge, .le {
c.cmp_reg(.rax, .rdx)
// TODO mov_extend_reg
c.mov64(Amd64Register.rax, 0)
c.cset_op(node.op)
}
.plus {
c.add_reg(.rax, .rdx)
}
.minus {
c.sub_reg(.rax, .rdx)
}
.mul {
c.g.write32(0xc2af0f48)
c.g.println('imul rax, rdx')
}
.div {
if node.left_type in ast.unsigned_integer_type_idxs {
c.g.write8(0xba)
c.g.write32(0)
c.g.println('mov edx, 0')
c.g.write([u8(0x48), 0xf7, 0xf1])
c.g.println('div rcx')
} else {
c.g.write16(0x9948)
c.g.println('cqo')
c.g.write([u8(0x48), 0xf7, 0xf9])
c.g.println('idiv rcx')
}
}
.mod {
if node.left_type in ast.unsigned_integer_type_idxs {
c.g.write8(0xba)
c.g.write32(0)
c.g.println('mov edx, 0')
c.g.write([u8(0x48), 0xf7, 0xf1])
c.g.println('div rcx')
} else {
c.g.write16(0x9948)
c.g.println('cqo')
c.g.write([u8(0x48), 0xf7, 0xf9])
c.g.println('idiv rcx')
}
c.mov_reg(Amd64Register.rax, Amd64Register.rdx)
}
.amp {
c.bitand_reg(.rax, .rdx)
}
.pipe {
c.bitor_reg(.rax, .rdx)
}
.xor {
c.bitxor_reg(.rax, .rdx)
}
.left_shift {
c.shl_reg(.rax, .rcx)
}
.right_shift {
c.sar_reg(.rax, .rcx)
}
.unsigned_right_shift {
c.shr_reg(.rax, .rcx)
}
else {
c.g.n_error('`${node.op}` expression is not supported right now')
}
.amp {
c.bitand_reg(.rax, .rdx)
}
.pipe {
c.bitor_reg(.rax, .rdx)
}
.xor {
c.bitxor_reg(.rax, .rdx)
}
.left_shift {
c.shl_reg(.rax, .rcx)
}
.right_shift {
c.sar_reg(.rax, .rcx)
}
.unsigned_right_shift {
c.shr_reg(.rax, .rcx)
}
else {
c.g.n_error('`${node.op}` expression is not supported right now')
}
}
}
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')
}
@ -3993,6 +4003,7 @@ fn (mut c Amd64) push_sse(reg Amd64SSERegister) {
c.g.println('movsd [rsp], ${reg}')
c.is_16bit_aligned = !c.is_16bit_aligned
c.g.println('; push ${reg}')
c.g.stack_depth++
}
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.is_16bit_aligned = !c.is_16bit_aligned
c.g.println('; pop ${reg}')
c.g.stack_depth--
}
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() {
panic('Arm64.trap() not implemented')
c.g.write32(0xcccccccc)
c.g.println('trap')
}
fn (mut c Arm64) leave() {

View File

@ -4,6 +4,7 @@
module native
import v.ast
import v.util
fn (mut g Gen) expr(node ast.Expr) {
match node {
@ -16,23 +17,24 @@ fn (mut g Gen) expr(node ast.Expr) {
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
})
g.code_gen.mov64(g.code_gen.main_reg(), int(node.val))
}
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)
match node.name {
'C.syscall' {
g.code_gen.gen_syscall(node)
}
'exit' {
g.code_gen.gen_exit(node.args[0].expr)
}
'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 {
@ -41,29 +43,9 @@ fn (mut g Gen) expr(node ast.Expr) {
}
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(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')
}
}
}
g.local_var_ident(node, var)
}
else {
g.n_error('Unsupported variable kind')
@ -131,12 +113,38 @@ fn (mut g Gen) expr(node ast.Expr) {
ast.ConcatExpr {
g.code_gen.gen_concat_expr(node)
}
ast.TypeOf {
g.gen_typeof_expr(node, false)
}
else {
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 {
g.expr(expr)
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 { '' }
r := g.typ(it.typ).name
g.code_gen.learel(g.code_gen.main_reg(), g.allocate_string('${r}${nl}', 3, .rel32))
ts := g.table.sym(node.typ)
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) {

View File

@ -41,6 +41,7 @@ mut:
var_offset map[string]int // local var stack offset
var_alloc_size map[string]int // local var allocation size
stack_var_pos int
stack_depth int
debug_pos int
errors []errors.Error
warnings []errors.Warning
@ -230,6 +231,11 @@ union F64I64 {
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 {
mut obj := ident.obj
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
}
fn (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()
|| typ.is_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() || 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 {
@ -981,12 +993,17 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
}
g.stack_var_pos = 0
g.stack_depth = 0
g.register_function_address(name)
g.labels = &LabelTable{}
g.defer_stmts.clear()
g.return_type = node.return_type
g.code_gen.fn_decl(node)
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) {

View File

@ -1,6 +1,8 @@
fn main() {
test_int()
test_fp()
test_unsafe()
test_alias(100, 9)
}
fn test_int() {
@ -25,4 +27,21 @@ fn test_fp() {
b /= 2
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
3
3
14
109

View File

@ -56,6 +56,9 @@ fn struct_test() {
mut f := &e
f.a = 3
assert e.a == 3
g := &Mutable{2}
assert g.a == 2
}
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() {
// strings
a := 'string'
t := typeof(a)
println(t)
t2 := typeof('another string')
println(t2)
// integers
n := 123
t3 := typeof(n)
println(t3)
t4 := typeof(123)
println(t4)
// id := 'hello world'
// println(id)
test_alias(0)
// 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
int
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