vq / vlib / v / gen / wasm / ops.v
165 lines · 152 sloc · 4.16 KB · 863a2090f8eda7dc75e061b26e0bca252f167e24
Raw
1// Copyright (c) 2023 l-m.dev. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module wasm
5
6import v.ast
7import v.token
8import wasm
9
10pub fn (mut g Gen) as_numtype(a wasm.ValType) wasm.NumType {
11 if a in [.funcref_t, .externref_t, .v128_t] {
12 g.w_error("as_numtype: called with '${a}'")
13 }
14
15 return unsafe { wasm.NumType(a) }
16}
17
18// unwraps int_literal to i64_t
19pub fn (mut g Gen) get_wasm_type_int_literal(typ_ ast.Type) wasm.ValType {
20 if typ_ == ast.int_literal_type_idx {
21 return wasm.ValType.i64_t
22 }
23 return g.get_wasm_type(typ_)
24}
25
26// "Register size" types such as int, i64 and bool boil down to their WASM counterparts.
27// Structures and unions are pointers, i32.
28pub fn (mut g Gen) get_wasm_type(typ_ ast.Type) wasm.ValType {
29 typ := ast.mktyp(typ_)
30 if typ == ast.void_type_idx {
31 g.w_error("get_wasm_type: called with 'void'")
32 }
33 if typ.is_ptr() || typ.is_pointer() {
34 return wasm.ValType.i32_t
35 }
36 if typ in ast.number_type_idxs {
37 return match typ {
38 ast.isize_type_idx, ast.usize_type_idx, ast.i8_type_idx, ast.u8_type_idx,
39 ast.char_type_idx, ast.rune_type_idx, ast.i16_type_idx, ast.u16_type_idx,
40 ast.i32_type_idx, ast.u32_type_idx {
41 wasm.ValType.i32_t
42 }
43 ast.int_type_idx {
44 $if new_int ? && x64 {
45 wasm.ValType.i64_t
46 } $else {
47 wasm.ValType.i32_t
48 }
49 }
50 ast.i64_type_idx, ast.u64_type_idx {
51 wasm.ValType.i64_t
52 }
53 ast.f32_type_idx {
54 wasm.ValType.f32_t
55 }
56 ast.f64_type_idx {
57 wasm.ValType.f64_t
58 }
59 else {
60 wasm.ValType.i32_t
61 }
62 }
63 }
64 if typ == ast.bool_type_idx {
65 return wasm.ValType.i32_t
66 }
67 ts := g.table.sym(typ)
68 match ts.info {
69 ast.Struct {
70 g.pool.type_size(typ)
71 return wasm.ValType.i32_t // pointer
72 }
73 ast.Alias {
74 return g.get_wasm_type(ts.info.parent_type)
75 }
76 ast.ArrayFixed {
77 return wasm.ValType.i32_t // pointer
78 }
79 ast.Enum {
80 return g.get_wasm_type(ts.info.typ)
81 }
82 ast.FnType {
83 return wasm.ValType.i32_t // index into the indirect function table
84 }
85 else {}
86 }
87
88 g.w_error("get_wasm_type: unreachable type '${*g.table.sym(typ)}' ${ts.info}")
89}
90
91pub fn (mut g Gen) infix_param_type(typ ast.Type, op token.Kind) {
92 match typ {
93 ast.string_type {
94 g.handle_string_operation(op)
95 }
96 else {
97 eprintln(*g.table.sym(typ))
98 panic('unimplemented infix operation for type')
99 }
100 }
101}
102
103pub fn (mut g Gen) infix_from_typ(typ ast.Type, op token.Kind) {
104 if g.is_param_type(typ) {
105 g.infix_param_type(typ, op)
106 } else {
107 g.infix_numeric_type(typ, op)
108 }
109}
110
111fn (mut g Gen) infix_numeric_type(typ ast.Type, op token.Kind) {
112 wasm_typ := g.as_numtype(g.get_wasm_type(typ))
113
114 // This adds two tiers of comparaison but is a lot cleaner
115 match op {
116 .plus, .minus, .mul, .div, .mod {
117 g.emit_arithmetic_op(wasm_typ, typ, op)
118 }
119 .eq, .ne, .gt, .lt, .ge, .le {
120 g.emit_comparison_op(wasm_typ, typ, op)
121 }
122 .xor, .pipe, .amp, .left_shift, .right_shift, .unsigned_right_shift {
123 g.emit_bitwise_op(wasm_typ, typ, op)
124 }
125 else {
126 g.w_error('bad infix: op `${op}`')
127 }
128 }
129}
130
131fn (mut g Gen) emit_arithmetic_op(wasm_typ wasm.NumType, typ ast.Type, op token.Kind) {
132 match op {
133 .plus { g.func.add(wasm_typ) }
134 .minus { g.func.sub(wasm_typ) }
135 .mul { g.func.mul(wasm_typ) }
136 .div { g.func.div(wasm_typ, typ.is_signed()) }
137 .mod { g.func.rem(wasm_typ, typ.is_signed()) }
138 else { g.w_error('invalid aritmetic op: `${op}`') }
139 }
140}
141
142fn (mut g Gen) emit_comparison_op(wasm_typ wasm.NumType, typ ast.Type, op token.Kind) {
143 is_signed := typ.is_signed()
144 match op {
145 .eq { g.func.eq(wasm_typ) }
146 .ne { g.func.ne(wasm_typ) }
147 .gt { g.func.gt(wasm_typ, is_signed) }
148 .lt { g.func.lt(wasm_typ, is_signed) }
149 .ge { g.func.ge(wasm_typ, is_signed) }
150 .le { g.func.le(wasm_typ, is_signed) }
151 else { g.w_error('invalid comparison op: `${op}`') }
152 }
153}
154
155fn (mut g Gen) emit_bitwise_op(wasm_typ wasm.NumType, _typ ast.Type, op token.Kind) {
156 match op {
157 .xor { g.func.b_xor(wasm_typ) }
158 .pipe { g.func.b_or(wasm_typ) }
159 .amp { g.func.b_and(wasm_typ) }
160 .left_shift { g.func.b_shl(wasm_typ) }
161 .right_shift { g.func.b_shr(wasm_typ, true) }
162 .unsigned_right_shift { g.func.b_shr(wasm_typ, false) }
163 else { g.w_error('invalid bitwise op: `${op}`') }
164 }
165}
166