v2 / vlib / v / gen / wasm / ops.v
162 lines · 149 sloc · 4.07 KB · 3d60410b605d001e54f280070d5f952da9de1112
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 else {}
83 }
84
85 g.w_error("get_wasm_type: unreachable type '${*g.table.sym(typ)}' ${ts.info}")
86}
87
88pub fn (mut g Gen) infix_param_type(typ ast.Type, op token.Kind) {
89 match typ {
90 ast.string_type {
91 g.handle_string_operation(op)
92 }
93 else {
94 eprintln(*g.table.sym(typ))
95 panic('unimplemented infix operation for type')
96 }
97 }
98}
99
100pub fn (mut g Gen) infix_from_typ(typ ast.Type, op token.Kind) {
101 if g.is_param_type(typ) {
102 g.infix_param_type(typ, op)
103 } else {
104 g.infix_numeric_type(typ, op)
105 }
106}
107
108fn (mut g Gen) infix_numeric_type(typ ast.Type, op token.Kind) {
109 wasm_typ := g.as_numtype(g.get_wasm_type(typ))
110
111 // This adds two tiers of comparaison but is a lot cleaner
112 match op {
113 .plus, .minus, .mul, .div, .mod {
114 g.emit_arithmetic_op(wasm_typ, typ, op)
115 }
116 .eq, .ne, .gt, .lt, .ge, .le {
117 g.emit_comparison_op(wasm_typ, typ, op)
118 }
119 .xor, .pipe, .amp, .left_shift, .right_shift, .unsigned_right_shift {
120 g.emit_bitwise_op(wasm_typ, typ, op)
121 }
122 else {
123 g.w_error('bad infix: op `${op}`')
124 }
125 }
126}
127
128fn (mut g Gen) emit_arithmetic_op(wasm_typ wasm.NumType, typ ast.Type, op token.Kind) {
129 match op {
130 .plus { g.func.add(wasm_typ) }
131 .minus { g.func.sub(wasm_typ) }
132 .mul { g.func.mul(wasm_typ) }
133 .div { g.func.div(wasm_typ, typ.is_signed()) }
134 .mod { g.func.rem(wasm_typ, typ.is_signed()) }
135 else { g.w_error('invalid aritmetic op: `${op}`') }
136 }
137}
138
139fn (mut g Gen) emit_comparison_op(wasm_typ wasm.NumType, typ ast.Type, op token.Kind) {
140 is_signed := typ.is_signed()
141 match op {
142 .eq { g.func.eq(wasm_typ) }
143 .ne { g.func.ne(wasm_typ) }
144 .gt { g.func.gt(wasm_typ, is_signed) }
145 .lt { g.func.lt(wasm_typ, is_signed) }
146 .ge { g.func.ge(wasm_typ, is_signed) }
147 .le { g.func.le(wasm_typ, is_signed) }
148 else { g.w_error('invalid comparison op: `${op}`') }
149 }
150}
151
152fn (mut g Gen) emit_bitwise_op(wasm_typ wasm.NumType, _typ ast.Type, op token.Kind) {
153 match op {
154 .xor { g.func.b_xor(wasm_typ) }
155 .pipe { g.func.b_or(wasm_typ) }
156 .amp { g.func.b_and(wasm_typ) }
157 .left_shift { g.func.b_shl(wasm_typ) }
158 .right_shift { g.func.b_shr(wasm_typ, true) }
159 .unsigned_right_shift { g.func.b_shr(wasm_typ, false) }
160 else { g.w_error('invalid bitwise op: `${op}`') }
161 }
162}
163