1const std = @import("std");
2const mem = std.mem;
3const assert = std.debug.assert;
4const CodeGen = @import("CodeGen.zig");
5const Mir = @import("Mir.zig");
6
7pub const LocalMap = std.array_hash_map.String(u32);
8
9pub fn assemble(
10 cg: *CodeGen,
11 source: [:0]const u8,
12 local_map: *const LocalMap,
13) !void {
14 var line_it = mem.tokenizeAny(u8, source, "\n\r;");
15 next_line: while (line_it.next()) |line| {
16 var word_it = mem.tokenizeAny(u8, line, " \t");
17 const inst = word_it.next() orelse continue :next_line;
18
19 if (mem.eql(u8, inst, "unreachable")) {
20 try cg.addTag(.@"unreachable");
21 } else if (mem.eql(u8, inst, "block")) {
22 try cg.addTag(.block);
23 } else if (mem.eql(u8, inst, "loop")) {
24 try cg.addTag(.loop);
25 } else if (mem.eql(u8, inst, "end")) {
26 try cg.addTag(.end);
27 } else if (mem.eql(u8, inst, "br")) {
28 const label = try parseLabel(cg, inst, &word_it);
29 try cg.addLabel(.br, label);
30 } else if (mem.eql(u8, inst, "br_if")) {
31 const label = try parseLabel(cg, inst, &word_it);
32 try cg.addLabel(.br_if, label);
33 } else if (mem.eql(u8, inst, "return")) {
34 try cg.addTag(.@"return");
35 } else if (mem.eql(u8, inst, "drop")) {
36 try cg.addTag(.drop);
37 } else if (mem.eql(u8, inst, "select")) {
38 try cg.addTag(.select);
39 } else if (mem.eql(u8, inst, "local.get")) {
40 const local = try parseLocalArg(cg, inst, &word_it, local_map);
41 try cg.addLocal(.local_get, local);
42 } else if (mem.eql(u8, inst, "local.set")) {
43 const local = try parseLocalArg(cg, inst, &word_it, local_map);
44 try cg.addLocal(.local_set, local);
45 } else if (mem.eql(u8, inst, "local.tee")) {
46 const local = try parseLocalArg(cg, inst, &word_it, local_map);
47 try cg.addLocal(.local_tee, local);
48 } else if (mem.eql(u8, inst, "i32.load")) {
49 const mem_arg = try parseMemArg(cg, inst, &word_it);
50 try cg.addMemArg(.i32_load, mem_arg);
51 } else if (mem.eql(u8, inst, "i64.load")) {
52 const mem_arg = try parseMemArg(cg, inst, &word_it);
53 try cg.addMemArg(.i64_load, mem_arg);
54 } else if (mem.eql(u8, inst, "f32.load")) {
55 const mem_arg = try parseMemArg(cg, inst, &word_it);
56 try cg.addMemArg(.f32_load, mem_arg);
57 } else if (mem.eql(u8, inst, "f64.load")) {
58 const mem_arg = try parseMemArg(cg, inst, &word_it);
59 try cg.addMemArg(.f64_load, mem_arg);
60 } else if (mem.eql(u8, inst, "i32.load8_s")) {
61 const mem_arg = try parseMemArg(cg, inst, &word_it);
62 try cg.addMemArg(.i32_load8_s, mem_arg);
63 } else if (mem.eql(u8, inst, "i32.load8_u")) {
64 const mem_arg = try parseMemArg(cg, inst, &word_it);
65 try cg.addMemArg(.i32_load8_u, mem_arg);
66 } else if (mem.eql(u8, inst, "i32.load16_s")) {
67 const mem_arg = try parseMemArg(cg, inst, &word_it);
68 try cg.addMemArg(.i32_load16_s, mem_arg);
69 } else if (mem.eql(u8, inst, "i32.load16_u")) {
70 const mem_arg = try parseMemArg(cg, inst, &word_it);
71 try cg.addMemArg(.i32_load16_u, mem_arg);
72 } else if (mem.eql(u8, inst, "i64.load8_s")) {
73 const mem_arg = try parseMemArg(cg, inst, &word_it);
74 try cg.addMemArg(.i64_load8_s, mem_arg);
75 } else if (mem.eql(u8, inst, "i64.load8_u")) {
76 const mem_arg = try parseMemArg(cg, inst, &word_it);
77 try cg.addMemArg(.i64_load8_u, mem_arg);
78 } else if (mem.eql(u8, inst, "i64.load16_s")) {
79 const mem_arg = try parseMemArg(cg, inst, &word_it);
80 try cg.addMemArg(.i64_load16_s, mem_arg);
81 } else if (mem.eql(u8, inst, "i64.load16_u")) {
82 const mem_arg = try parseMemArg(cg, inst, &word_it);
83 try cg.addMemArg(.i64_load16_u, mem_arg);
84 } else if (mem.eql(u8, inst, "i64.load32_s")) {
85 const mem_arg = try parseMemArg(cg, inst, &word_it);
86 try cg.addMemArg(.i64_load32_s, mem_arg);
87 } else if (mem.eql(u8, inst, "i64.load32_u")) {
88 const mem_arg = try parseMemArg(cg, inst, &word_it);
89 try cg.addMemArg(.i64_load32_u, mem_arg);
90 } else if (mem.eql(u8, inst, "i32.store")) {
91 const mem_arg = try parseMemArg(cg, inst, &word_it);
92 try cg.addMemArg(.i32_store, mem_arg);
93 } else if (mem.eql(u8, inst, "i64.store")) {
94 const mem_arg = try parseMemArg(cg, inst, &word_it);
95 try cg.addMemArg(.i64_store, mem_arg);
96 } else if (mem.eql(u8, inst, "f32.store")) {
97 const mem_arg = try parseMemArg(cg, inst, &word_it);
98 try cg.addMemArg(.f32_store, mem_arg);
99 } else if (mem.eql(u8, inst, "f64.store")) {
100 const mem_arg = try parseMemArg(cg, inst, &word_it);
101 try cg.addMemArg(.f64_store, mem_arg);
102 } else if (mem.eql(u8, inst, "i32.store8")) {
103 const mem_arg = try parseMemArg(cg, inst, &word_it);
104 try cg.addMemArg(.i32_store8, mem_arg);
105 } else if (mem.eql(u8, inst, "i32.store16")) {
106 const mem_arg = try parseMemArg(cg, inst, &word_it);
107 try cg.addMemArg(.i32_store16, mem_arg);
108 } else if (mem.eql(u8, inst, "i64.store8")) {
109 const mem_arg = try parseMemArg(cg, inst, &word_it);
110 try cg.addMemArg(.i64_store8, mem_arg);
111 } else if (mem.eql(u8, inst, "i64.store16")) {
112 const mem_arg = try parseMemArg(cg, inst, &word_it);
113 try cg.addMemArg(.i64_store16, mem_arg);
114 } else if (mem.eql(u8, inst, "i64.store32")) {
115 const mem_arg = try parseMemArg(cg, inst, &word_it);
116 try cg.addMemArg(.i64_store32, mem_arg);
117 } else if (mem.eql(u8, inst, "memory.size")) {
118 try cg.addLabel(.memory_size, 0);
119 } else if (mem.eql(u8, inst, "memory.grow")) {
120 try cg.addLabel(.memory_grow, 0);
121 } else if (mem.eql(u8, inst, "i32.const")) {
122 const value = try parseInt(i32, cg, inst, &word_it);
123 try cg.addImm32(@bitCast(value));
124 } else if (mem.eql(u8, inst, "i64.const")) {
125 const value = try parseInt(i64, cg, inst, &word_it);
126 try cg.addImm64(@bitCast(value));
127 } else if (mem.eql(u8, inst, "f32.const")) {
128 const value = try parseFloat(f32, cg, inst, &word_it);
129 try cg.addFloat32(value);
130 } else if (mem.eql(u8, inst, "f64.const")) {
131 const value = try parseFloat(f64, cg, inst, &word_it);
132 try cg.addFloat64(value);
133 } else if (mem.eql(u8, inst, "i32.eqz")) {
134 try cg.addTag(.i32_eqz);
135 } else if (mem.eql(u8, inst, "i32.eq")) {
136 try cg.addTag(.i32_eq);
137 } else if (mem.eql(u8, inst, "i32.ne")) {
138 try cg.addTag(.i32_ne);
139 } else if (mem.eql(u8, inst, "i32.lt_s")) {
140 try cg.addTag(.i32_lt_s);
141 } else if (mem.eql(u8, inst, "i32.lt_u")) {
142 try cg.addTag(.i32_lt_u);
143 } else if (mem.eql(u8, inst, "i32.gt_s")) {
144 try cg.addTag(.i32_gt_s);
145 } else if (mem.eql(u8, inst, "i32.gt_u")) {
146 try cg.addTag(.i32_gt_u);
147 } else if (mem.eql(u8, inst, "i32.le_s")) {
148 try cg.addTag(.i32_le_s);
149 } else if (mem.eql(u8, inst, "i32.le_u")) {
150 try cg.addTag(.i32_le_u);
151 } else if (mem.eql(u8, inst, "i32.ge_s")) {
152 try cg.addTag(.i32_ge_s);
153 } else if (mem.eql(u8, inst, "i32.ge_u")) {
154 try cg.addTag(.i32_ge_u);
155 } else if (mem.eql(u8, inst, "i64.eqz")) {
156 try cg.addTag(.i64_eqz);
157 } else if (mem.eql(u8, inst, "i64.eq")) {
158 try cg.addTag(.i64_eq);
159 } else if (mem.eql(u8, inst, "i64.ne")) {
160 try cg.addTag(.i64_ne);
161 } else if (mem.eql(u8, inst, "i64.lt_s")) {
162 try cg.addTag(.i64_lt_s);
163 } else if (mem.eql(u8, inst, "i64.lt_u")) {
164 try cg.addTag(.i64_lt_u);
165 } else if (mem.eql(u8, inst, "i64.gt_s")) {
166 try cg.addTag(.i64_gt_s);
167 } else if (mem.eql(u8, inst, "i64.gt_u")) {
168 try cg.addTag(.i64_gt_u);
169 } else if (mem.eql(u8, inst, "i64.le_s")) {
170 try cg.addTag(.i64_le_s);
171 } else if (mem.eql(u8, inst, "i64.le_u")) {
172 try cg.addTag(.i64_le_u);
173 } else if (mem.eql(u8, inst, "i64.ge_s")) {
174 try cg.addTag(.i64_ge_s);
175 } else if (mem.eql(u8, inst, "i64.ge_u")) {
176 try cg.addTag(.i64_ge_u);
177 } else if (mem.eql(u8, inst, "f32.eq")) {
178 try cg.addTag(.f32_eq);
179 } else if (mem.eql(u8, inst, "f32.ne")) {
180 try cg.addTag(.f32_ne);
181 } else if (mem.eql(u8, inst, "f32.lt")) {
182 try cg.addTag(.f32_lt);
183 } else if (mem.eql(u8, inst, "f32.gt")) {
184 try cg.addTag(.f32_gt);
185 } else if (mem.eql(u8, inst, "f32.le")) {
186 try cg.addTag(.f32_le);
187 } else if (mem.eql(u8, inst, "f32.ge")) {
188 try cg.addTag(.f32_ge);
189 } else if (mem.eql(u8, inst, "f64.eq")) {
190 try cg.addTag(.f64_eq);
191 } else if (mem.eql(u8, inst, "f64.ne")) {
192 try cg.addTag(.f64_ne);
193 } else if (mem.eql(u8, inst, "f64.lt")) {
194 try cg.addTag(.f64_lt);
195 } else if (mem.eql(u8, inst, "f64.gt")) {
196 try cg.addTag(.f64_gt);
197 } else if (mem.eql(u8, inst, "f64.le")) {
198 try cg.addTag(.f64_le);
199 } else if (mem.eql(u8, inst, "f64.ge")) {
200 try cg.addTag(.f64_ge);
201 } else if (mem.eql(u8, inst, "i32.clz")) {
202 try cg.addTag(.i32_clz);
203 } else if (mem.eql(u8, inst, "i32.ctz")) {
204 try cg.addTag(.i32_ctz);
205 } else if (mem.eql(u8, inst, "i32.popcnt")) {
206 try cg.addTag(.i32_popcnt);
207 } else if (mem.eql(u8, inst, "i32.add")) {
208 try cg.addTag(.i32_add);
209 } else if (mem.eql(u8, inst, "i32.sub")) {
210 try cg.addTag(.i32_sub);
211 } else if (mem.eql(u8, inst, "i32.mul")) {
212 try cg.addTag(.i32_mul);
213 } else if (mem.eql(u8, inst, "i32.div_s")) {
214 try cg.addTag(.i32_div_s);
215 } else if (mem.eql(u8, inst, "i32.div_u")) {
216 try cg.addTag(.i32_div_u);
217 } else if (mem.eql(u8, inst, "i32.rem_s")) {
218 try cg.addTag(.i32_rem_s);
219 } else if (mem.eql(u8, inst, "i32.rem_u")) {
220 try cg.addTag(.i32_rem_u);
221 } else if (mem.eql(u8, inst, "i32.and")) {
222 try cg.addTag(.i32_and);
223 } else if (mem.eql(u8, inst, "i32.or")) {
224 try cg.addTag(.i32_or);
225 } else if (mem.eql(u8, inst, "i32.xor")) {
226 try cg.addTag(.i32_xor);
227 } else if (mem.eql(u8, inst, "i32.shl")) {
228 try cg.addTag(.i32_shl);
229 } else if (mem.eql(u8, inst, "i32.shr_s")) {
230 try cg.addTag(.i32_shr_s);
231 } else if (mem.eql(u8, inst, "i32.shr_u")) {
232 try cg.addTag(.i32_shr_u);
233 } else if (mem.eql(u8, inst, "i64.clz")) {
234 try cg.addTag(.i64_clz);
235 } else if (mem.eql(u8, inst, "i64.ctz")) {
236 try cg.addTag(.i64_ctz);
237 } else if (mem.eql(u8, inst, "i64.popcnt")) {
238 try cg.addTag(.i64_popcnt);
239 } else if (mem.eql(u8, inst, "i64.add")) {
240 try cg.addTag(.i64_add);
241 } else if (mem.eql(u8, inst, "i64.sub")) {
242 try cg.addTag(.i64_sub);
243 } else if (mem.eql(u8, inst, "i64.mul")) {
244 try cg.addTag(.i64_mul);
245 } else if (mem.eql(u8, inst, "i64.div_s")) {
246 try cg.addTag(.i64_div_s);
247 } else if (mem.eql(u8, inst, "i64.div_u")) {
248 try cg.addTag(.i64_div_u);
249 } else if (mem.eql(u8, inst, "i64.rem_s")) {
250 try cg.addTag(.i64_rem_s);
251 } else if (mem.eql(u8, inst, "i64.rem_u")) {
252 try cg.addTag(.i64_rem_u);
253 } else if (mem.eql(u8, inst, "i64.and")) {
254 try cg.addTag(.i64_and);
255 } else if (mem.eql(u8, inst, "i64.or")) {
256 try cg.addTag(.i64_or);
257 } else if (mem.eql(u8, inst, "i64.xor")) {
258 try cg.addTag(.i64_xor);
259 } else if (mem.eql(u8, inst, "i64.shl")) {
260 try cg.addTag(.i64_shl);
261 } else if (mem.eql(u8, inst, "i64.shr_s")) {
262 try cg.addTag(.i64_shr_s);
263 } else if (mem.eql(u8, inst, "i64.shr_u")) {
264 try cg.addTag(.i64_shr_u);
265 } else if (mem.eql(u8, inst, "f32.abs")) {
266 try cg.addTag(.f32_abs);
267 } else if (mem.eql(u8, inst, "f32.neg")) {
268 try cg.addTag(.f32_neg);
269 } else if (mem.eql(u8, inst, "f32.ceil")) {
270 try cg.addTag(.f32_ceil);
271 } else if (mem.eql(u8, inst, "f32.floor")) {
272 try cg.addTag(.f32_floor);
273 } else if (mem.eql(u8, inst, "f32.trunc")) {
274 try cg.addTag(.f32_trunc);
275 } else if (mem.eql(u8, inst, "f32.nearest")) {
276 try cg.addTag(.f32_nearest);
277 } else if (mem.eql(u8, inst, "f32.sqrt")) {
278 try cg.addTag(.f32_sqrt);
279 } else if (mem.eql(u8, inst, "f32.add")) {
280 try cg.addTag(.f32_add);
281 } else if (mem.eql(u8, inst, "f32.sub")) {
282 try cg.addTag(.f32_sub);
283 } else if (mem.eql(u8, inst, "f32.mul")) {
284 try cg.addTag(.f32_mul);
285 } else if (mem.eql(u8, inst, "f32.div")) {
286 try cg.addTag(.f32_div);
287 } else if (mem.eql(u8, inst, "f32.min")) {
288 try cg.addTag(.f32_min);
289 } else if (mem.eql(u8, inst, "f32.max")) {
290 try cg.addTag(.f32_max);
291 } else if (mem.eql(u8, inst, "f32.copysign")) {
292 try cg.addTag(.f32_copysign);
293 } else if (mem.eql(u8, inst, "f64.abs")) {
294 try cg.addTag(.f64_abs);
295 } else if (mem.eql(u8, inst, "f64.neg")) {
296 try cg.addTag(.f64_neg);
297 } else if (mem.eql(u8, inst, "f64.ceil")) {
298 try cg.addTag(.f64_ceil);
299 } else if (mem.eql(u8, inst, "f64.floor")) {
300 try cg.addTag(.f64_floor);
301 } else if (mem.eql(u8, inst, "f64.trunc")) {
302 try cg.addTag(.f64_trunc);
303 } else if (mem.eql(u8, inst, "f64.nearest")) {
304 try cg.addTag(.f64_nearest);
305 } else if (mem.eql(u8, inst, "f64.sqrt")) {
306 try cg.addTag(.f64_sqrt);
307 } else if (mem.eql(u8, inst, "f64.add")) {
308 try cg.addTag(.f64_add);
309 } else if (mem.eql(u8, inst, "f64.sub")) {
310 try cg.addTag(.f64_sub);
311 } else if (mem.eql(u8, inst, "f64.mul")) {
312 try cg.addTag(.f64_mul);
313 } else if (mem.eql(u8, inst, "f64.div")) {
314 try cg.addTag(.f64_div);
315 } else if (mem.eql(u8, inst, "f64.min")) {
316 try cg.addTag(.f64_min);
317 } else if (mem.eql(u8, inst, "f64.max")) {
318 try cg.addTag(.f64_max);
319 } else if (mem.eql(u8, inst, "f64.copysign")) {
320 try cg.addTag(.f64_copysign);
321 } else if (mem.eql(u8, inst, "i32.wrap_i64")) {
322 try cg.addTag(.i32_wrap_i64);
323 } else if (mem.eql(u8, inst, "i32.trunc_f32_s")) {
324 try cg.addTag(.i32_trunc_f32_s);
325 } else if (mem.eql(u8, inst, "i32.trunc_f32_u")) {
326 try cg.addTag(.i32_trunc_f32_u);
327 } else if (mem.eql(u8, inst, "i32.trunc_f64_s")) {
328 try cg.addTag(.i32_trunc_f64_s);
329 } else if (mem.eql(u8, inst, "i32.trunc_f64_u")) {
330 try cg.addTag(.i32_trunc_f64_u);
331 } else if (mem.eql(u8, inst, "i64.extend_i32_s")) {
332 try cg.addTag(.i64_extend_i32_s);
333 } else if (mem.eql(u8, inst, "i64.extend_i32_u")) {
334 try cg.addTag(.i64_extend_i32_u);
335 } else if (mem.eql(u8, inst, "i64.trunc_f32_s")) {
336 try cg.addTag(.i64_trunc_f32_s);
337 } else if (mem.eql(u8, inst, "i64.trunc_f32_u")) {
338 try cg.addTag(.i64_trunc_f32_u);
339 } else if (mem.eql(u8, inst, "i64.trunc_f64_s")) {
340 try cg.addTag(.i64_trunc_f64_s);
341 } else if (mem.eql(u8, inst, "i64.trunc_f64_u")) {
342 try cg.addTag(.i64_trunc_f64_u);
343 } else if (mem.eql(u8, inst, "f32.convert_i32_s")) {
344 try cg.addTag(.f32_convert_i32_s);
345 } else if (mem.eql(u8, inst, "f32.convert_i32_u")) {
346 try cg.addTag(.f32_convert_i32_u);
347 } else if (mem.eql(u8, inst, "f32.convert_i64_s")) {
348 try cg.addTag(.f32_convert_i64_s);
349 } else if (mem.eql(u8, inst, "f32.convert_i64_u")) {
350 try cg.addTag(.f32_convert_i64_u);
351 } else if (mem.eql(u8, inst, "f32.demote_f64")) {
352 try cg.addTag(.f32_demote_f64);
353 } else if (mem.eql(u8, inst, "f64.convert_i32_s")) {
354 try cg.addTag(.f64_convert_i32_s);
355 } else if (mem.eql(u8, inst, "f64.convert_i32_u")) {
356 try cg.addTag(.f64_convert_i32_u);
357 } else if (mem.eql(u8, inst, "f64.convert_i64_s")) {
358 try cg.addTag(.f64_convert_i64_s);
359 } else if (mem.eql(u8, inst, "f64.convert_i64_u")) {
360 try cg.addTag(.f64_convert_i64_u);
361 } else if (mem.eql(u8, inst, "f64.promote_f32")) {
362 try cg.addTag(.f64_promote_f32);
363 } else if (mem.eql(u8, inst, "i32.reinterpret_f32")) {
364 try cg.addTag(.i32_reinterpret_f32);
365 } else if (mem.eql(u8, inst, "i64.reinterpret_f64")) {
366 try cg.addTag(.i64_reinterpret_f64);
367 } else if (mem.eql(u8, inst, "f32.reinterpret_i32")) {
368 try cg.addTag(.f32_reinterpret_i32);
369 } else if (mem.eql(u8, inst, "f64.reinterpret_i64")) {
370 try cg.addTag(.f64_reinterpret_i64);
371 } else if (mem.eql(u8, inst, "i32.extend8_s")) {
372 try cg.addTag(.i32_extend8_s);
373 } else if (mem.eql(u8, inst, "i32.extend16_s")) {
374 try cg.addTag(.i32_extend16_s);
375 } else if (mem.eql(u8, inst, "i64.extend8_s")) {
376 try cg.addTag(.i64_extend8_s);
377 } else if (mem.eql(u8, inst, "i64.extend16_s")) {
378 try cg.addTag(.i64_extend16_s);
379 } else if (mem.eql(u8, inst, "i64.extend32_s")) {
380 try cg.addTag(.i64_extend32_s);
381 } else if (mem.eql(u8, inst, "i32.trunc_sat_f32_s")) {
382 try cg.addExtended(.i32_trunc_sat_f32_s);
383 } else if (mem.eql(u8, inst, "i32.trunc_sat_f32_u")) {
384 try cg.addExtended(.i32_trunc_sat_f32_u);
385 } else if (mem.eql(u8, inst, "i32.trunc_sat_f64_s")) {
386 try cg.addExtended(.i32_trunc_sat_f64_s);
387 } else if (mem.eql(u8, inst, "i32.trunc_sat_f64_u")) {
388 try cg.addExtended(.i32_trunc_sat_f64_u);
389 } else if (mem.eql(u8, inst, "i64.trunc_sat_f32_s")) {
390 try cg.addExtended(.i64_trunc_sat_f32_s);
391 } else if (mem.eql(u8, inst, "i64.trunc_sat_f32_u")) {
392 try cg.addExtended(.i64_trunc_sat_f32_u);
393 } else if (mem.eql(u8, inst, "i64.trunc_sat_f64_s")) {
394 try cg.addExtended(.i64_trunc_sat_f64_s);
395 } else if (mem.eql(u8, inst, "i64.trunc_sat_f64_u")) {
396 try cg.addExtended(.i64_trunc_sat_f64_u);
397 } else if (mem.eql(u8, inst, "memory.init")) {
398 try cg.addExtended(.memory_init);
399 } else if (mem.eql(u8, inst, "data.drop")) {
400 try cg.addExtended(.data_drop);
401 } else if (mem.eql(u8, inst, "memory.copy")) {
402 const str1 = word_it.next();
403 if (str1 == null or !mem.eql(u8, str1.?, "0,")) {
404 return cg.fail("Self-hosted backend requires memory.copy be in form of \"memory.copy 0, 0\"", .{});
405 }
406 const str2 = word_it.next();
407 if (str2 == null or !mem.eql(u8, str2.?, "0")) {
408 return cg.fail("Self-hosted backend requires memory.copy be in form of \"memory.copy 0, 0\"", .{});
409 }
410 try cg.addExtended(.memory_copy);
411 } else if (mem.eql(u8, inst, "memory.fill")) {
412 const str = word_it.next();
413 if (str == null or !mem.eql(u8, str.?, "0")) {
414 return cg.fail("Self-hosted backend requires memory.fill be in form of \"memory.fill 0\"", .{});
415 }
416 try cg.addExtended(.memory_fill);
417 } else if (mem.eql(u8, inst, "table.init")) {
418 try cg.addExtended(.table_init);
419 } else if (mem.eql(u8, inst, "elem.drop")) {
420 try cg.addExtended(.elem_drop);
421 } else if (mem.eql(u8, inst, "table.copy")) {
422 try cg.addExtended(.table_copy);
423 } else if (mem.eql(u8, inst, "table.grow")) {
424 try cg.addExtended(.table_grow);
425 } else if (mem.eql(u8, inst, "table.size")) {
426 try cg.addExtended(.table_size);
427 } else if (mem.eql(u8, inst, "table.fill")) {
428 try cg.addExtended(.table_fill);
429 } else if (mem.eql(u8, inst, "memory.atomic.notify")) {
430 const mem_arg = try parseMemArg(cg, inst, &word_it);
431 try cg.addAtomicMemArg(.memory_atomic_notify, mem_arg);
432 } else if (mem.eql(u8, inst, "memory.atomic.wait32")) {
433 const mem_arg = try parseMemArg(cg, inst, &word_it);
434 try cg.addAtomicMemArg(.memory_atomic_wait32, mem_arg);
435 } else if (mem.eql(u8, inst, "memory.atomic.wait64")) {
436 const mem_arg = try parseMemArg(cg, inst, &word_it);
437 try cg.addAtomicMemArg(.memory_atomic_wait64, mem_arg);
438 } else if (mem.eql(u8, inst, "atomic.fence")) {
439 try cg.addAtomicTag(.atomic_fence);
440 } else if (mem.eql(u8, inst, "i32.atomic.load")) {
441 const mem_arg = try parseMemArg(cg, inst, &word_it);
442 try cg.addAtomicMemArg(.i32_atomic_load, mem_arg);
443 } else if (mem.eql(u8, inst, "i64.atomic.load")) {
444 const mem_arg = try parseMemArg(cg, inst, &word_it);
445 try cg.addAtomicMemArg(.i64_atomic_load, mem_arg);
446 } else if (mem.eql(u8, inst, "i32.atomic.load8_u")) {
447 const mem_arg = try parseMemArg(cg, inst, &word_it);
448 try cg.addAtomicMemArg(.i32_atomic_load8_u, mem_arg);
449 } else if (mem.eql(u8, inst, "i32.atomic.load16_u")) {
450 const mem_arg = try parseMemArg(cg, inst, &word_it);
451 try cg.addAtomicMemArg(.i32_atomic_load16_u, mem_arg);
452 } else if (mem.eql(u8, inst, "i64.atomic.load8_u")) {
453 const mem_arg = try parseMemArg(cg, inst, &word_it);
454 try cg.addAtomicMemArg(.i64_atomic_load8_u, mem_arg);
455 } else if (mem.eql(u8, inst, "i64.atomic.load16_u")) {
456 const mem_arg = try parseMemArg(cg, inst, &word_it);
457 try cg.addAtomicMemArg(.i64_atomic_load16_u, mem_arg);
458 } else if (mem.eql(u8, inst, "i64.atomic.load32_u")) {
459 const mem_arg = try parseMemArg(cg, inst, &word_it);
460 try cg.addAtomicMemArg(.i64_atomic_load32_u, mem_arg);
461 } else if (mem.eql(u8, inst, "i32.atomic.store")) {
462 const mem_arg = try parseMemArg(cg, inst, &word_it);
463 try cg.addAtomicMemArg(.i32_atomic_store, mem_arg);
464 } else if (mem.eql(u8, inst, "i64.atomic.store")) {
465 const mem_arg = try parseMemArg(cg, inst, &word_it);
466 try cg.addAtomicMemArg(.i64_atomic_store, mem_arg);
467 } else if (mem.eql(u8, inst, "i32.atomic.store8")) {
468 const mem_arg = try parseMemArg(cg, inst, &word_it);
469 try cg.addAtomicMemArg(.i32_atomic_store8, mem_arg);
470 } else if (mem.eql(u8, inst, "i32.atomic.store16")) {
471 const mem_arg = try parseMemArg(cg, inst, &word_it);
472 try cg.addAtomicMemArg(.i32_atomic_store16, mem_arg);
473 } else if (mem.eql(u8, inst, "i64.atomic.store8")) {
474 const mem_arg = try parseMemArg(cg, inst, &word_it);
475 try cg.addAtomicMemArg(.i64_atomic_store8, mem_arg);
476 } else if (mem.eql(u8, inst, "i64.atomic.store16")) {
477 const mem_arg = try parseMemArg(cg, inst, &word_it);
478 try cg.addAtomicMemArg(.i64_atomic_store16, mem_arg);
479 } else if (mem.eql(u8, inst, "i64.atomic.store32")) {
480 const mem_arg = try parseMemArg(cg, inst, &word_it);
481 try cg.addAtomicMemArg(.i64_atomic_store32, mem_arg);
482 } else if (mem.eql(u8, inst, "i32.atomic.rmw.add")) {
483 const mem_arg = try parseMemArg(cg, inst, &word_it);
484 try cg.addAtomicMemArg(.i32_atomic_rmw_add, mem_arg);
485 } else if (mem.eql(u8, inst, "i64.atomic.rmw.add")) {
486 const mem_arg = try parseMemArg(cg, inst, &word_it);
487 try cg.addAtomicMemArg(.i64_atomic_rmw_add, mem_arg);
488 } else if (mem.eql(u8, inst, "i32.atomic.rmw8.add_u")) {
489 const mem_arg = try parseMemArg(cg, inst, &word_it);
490 try cg.addAtomicMemArg(.i32_atomic_rmw8_add_u, mem_arg);
491 } else if (mem.eql(u8, inst, "i32.atomic.rmw16.add_u")) {
492 const mem_arg = try parseMemArg(cg, inst, &word_it);
493 try cg.addAtomicMemArg(.i32_atomic_rmw16_add_u, mem_arg);
494 } else if (mem.eql(u8, inst, "i64.atomic.rmw8.add_u")) {
495 const mem_arg = try parseMemArg(cg, inst, &word_it);
496 try cg.addAtomicMemArg(.i64_atomic_rmw8_add_u, mem_arg);
497 } else if (mem.eql(u8, inst, "i64.atomic.rmw16.add_u")) {
498 const mem_arg = try parseMemArg(cg, inst, &word_it);
499 try cg.addAtomicMemArg(.i64_atomic_rmw16_add_u, mem_arg);
500 } else if (mem.eql(u8, inst, "i64.atomic.rmw32.add_u")) {
501 const mem_arg = try parseMemArg(cg, inst, &word_it);
502 try cg.addAtomicMemArg(.i64_atomic_rmw32_add_u, mem_arg);
503 } else if (mem.eql(u8, inst, "i32.atomic.rmw.sub")) {
504 const mem_arg = try parseMemArg(cg, inst, &word_it);
505 try cg.addAtomicMemArg(.i32_atomic_rmw_sub, mem_arg);
506 } else if (mem.eql(u8, inst, "i64.atomic.rmw.sub")) {
507 const mem_arg = try parseMemArg(cg, inst, &word_it);
508 try cg.addAtomicMemArg(.i64_atomic_rmw_sub, mem_arg);
509 } else if (mem.eql(u8, inst, "i32.atomic.rmw8.sub_u")) {
510 const mem_arg = try parseMemArg(cg, inst, &word_it);
511 try cg.addAtomicMemArg(.i32_atomic_rmw8_sub_u, mem_arg);
512 } else if (mem.eql(u8, inst, "i32.atomic.rmw16.sub_u")) {
513 const mem_arg = try parseMemArg(cg, inst, &word_it);
514 try cg.addAtomicMemArg(.i32_atomic_rmw16_sub_u, mem_arg);
515 } else if (mem.eql(u8, inst, "i64.atomic.rmw8.sub_u")) {
516 const mem_arg = try parseMemArg(cg, inst, &word_it);
517 try cg.addAtomicMemArg(.i64_atomic_rmw8_sub_u, mem_arg);
518 } else if (mem.eql(u8, inst, "i64.atomic.rmw16.sub_u")) {
519 const mem_arg = try parseMemArg(cg, inst, &word_it);
520 try cg.addAtomicMemArg(.i64_atomic_rmw16_sub_u, mem_arg);
521 } else if (mem.eql(u8, inst, "i64.atomic.rmw32.sub_u")) {
522 const mem_arg = try parseMemArg(cg, inst, &word_it);
523 try cg.addAtomicMemArg(.i64_atomic_rmw32_sub_u, mem_arg);
524 } else if (mem.eql(u8, inst, "i32.atomic.rmw.and")) {
525 const mem_arg = try parseMemArg(cg, inst, &word_it);
526 try cg.addAtomicMemArg(.i32_atomic_rmw_and, mem_arg);
527 } else if (mem.eql(u8, inst, "i64.atomic.rmw.and")) {
528 const mem_arg = try parseMemArg(cg, inst, &word_it);
529 try cg.addAtomicMemArg(.i64_atomic_rmw_and, mem_arg);
530 } else if (mem.eql(u8, inst, "i32.atomic.rmw8.and_u")) {
531 const mem_arg = try parseMemArg(cg, inst, &word_it);
532 try cg.addAtomicMemArg(.i32_atomic_rmw8_and_u, mem_arg);
533 } else if (mem.eql(u8, inst, "i32.atomic.rmw16.and_u")) {
534 const mem_arg = try parseMemArg(cg, inst, &word_it);
535 try cg.addAtomicMemArg(.i32_atomic_rmw16_and_u, mem_arg);
536 } else if (mem.eql(u8, inst, "i64.atomic.rmw8.and_u")) {
537 const mem_arg = try parseMemArg(cg, inst, &word_it);
538 try cg.addAtomicMemArg(.i64_atomic_rmw8_and_u, mem_arg);
539 } else if (mem.eql(u8, inst, "i64.atomic.rmw16.and_u")) {
540 const mem_arg = try parseMemArg(cg, inst, &word_it);
541 try cg.addAtomicMemArg(.i64_atomic_rmw16_and_u, mem_arg);
542 } else if (mem.eql(u8, inst, "i64.atomic.rmw32.and_u")) {
543 const mem_arg = try parseMemArg(cg, inst, &word_it);
544 try cg.addAtomicMemArg(.i64_atomic_rmw32_and_u, mem_arg);
545 } else if (mem.eql(u8, inst, "i32.atomic.rmw.or")) {
546 const mem_arg = try parseMemArg(cg, inst, &word_it);
547 try cg.addAtomicMemArg(.i32_atomic_rmw_or, mem_arg);
548 } else if (mem.eql(u8, inst, "i64.atomic.rmw.or")) {
549 const mem_arg = try parseMemArg(cg, inst, &word_it);
550 try cg.addAtomicMemArg(.i64_atomic_rmw_or, mem_arg);
551 } else if (mem.eql(u8, inst, "i32.atomic.rmw8.or_u")) {
552 const mem_arg = try parseMemArg(cg, inst, &word_it);
553 try cg.addAtomicMemArg(.i32_atomic_rmw8_or_u, mem_arg);
554 } else if (mem.eql(u8, inst, "i32.atomic.rmw16.or_u")) {
555 const mem_arg = try parseMemArg(cg, inst, &word_it);
556 try cg.addAtomicMemArg(.i32_atomic_rmw16_or_u, mem_arg);
557 } else if (mem.eql(u8, inst, "i64.atomic.rmw8.or_u")) {
558 const mem_arg = try parseMemArg(cg, inst, &word_it);
559 try cg.addAtomicMemArg(.i64_atomic_rmw8_or_u, mem_arg);
560 } else if (mem.eql(u8, inst, "i64.atomic.rmw16.or_u")) {
561 const mem_arg = try parseMemArg(cg, inst, &word_it);
562 try cg.addAtomicMemArg(.i64_atomic_rmw16_or_u, mem_arg);
563 } else if (mem.eql(u8, inst, "i64.atomic.rmw32.or_u")) {
564 const mem_arg = try parseMemArg(cg, inst, &word_it);
565 try cg.addAtomicMemArg(.i64_atomic_rmw32_or_u, mem_arg);
566 } else if (mem.eql(u8, inst, "i32.atomic.rmw.xor")) {
567 const mem_arg = try parseMemArg(cg, inst, &word_it);
568 try cg.addAtomicMemArg(.i32_atomic_rmw_xor, mem_arg);
569 } else if (mem.eql(u8, inst, "i64.atomic.rmw.xor")) {
570 const mem_arg = try parseMemArg(cg, inst, &word_it);
571 try cg.addAtomicMemArg(.i64_atomic_rmw_xor, mem_arg);
572 } else if (mem.eql(u8, inst, "i32.atomic.rmw8.xor_u")) {
573 const mem_arg = try parseMemArg(cg, inst, &word_it);
574 try cg.addAtomicMemArg(.i32_atomic_rmw8_xor_u, mem_arg);
575 } else if (mem.eql(u8, inst, "i32.atomic.rmw16.xor_u")) {
576 const mem_arg = try parseMemArg(cg, inst, &word_it);
577 try cg.addAtomicMemArg(.i32_atomic_rmw16_xor_u, mem_arg);
578 } else if (mem.eql(u8, inst, "i64.atomic.rmw8.xor_u")) {
579 const mem_arg = try parseMemArg(cg, inst, &word_it);
580 try cg.addAtomicMemArg(.i64_atomic_rmw8_xor_u, mem_arg);
581 } else if (mem.eql(u8, inst, "i64.atomic.rmw16.xor_u")) {
582 const mem_arg = try parseMemArg(cg, inst, &word_it);
583 try cg.addAtomicMemArg(.i64_atomic_rmw16_xor_u, mem_arg);
584 } else if (mem.eql(u8, inst, "i64.atomic.rmw32.xor_u")) {
585 const mem_arg = try parseMemArg(cg, inst, &word_it);
586 try cg.addAtomicMemArg(.i64_atomic_rmw32_xor_u, mem_arg);
587 } else if (mem.eql(u8, inst, "i32.atomic.rmw.xchg")) {
588 const mem_arg = try parseMemArg(cg, inst, &word_it);
589 try cg.addAtomicMemArg(.i32_atomic_rmw_xchg, mem_arg);
590 } else if (mem.eql(u8, inst, "i64.atomic.rmw.xchg")) {
591 const mem_arg = try parseMemArg(cg, inst, &word_it);
592 try cg.addAtomicMemArg(.i64_atomic_rmw_xchg, mem_arg);
593 } else if (mem.eql(u8, inst, "i32.atomic.rmw8.xchg_u")) {
594 const mem_arg = try parseMemArg(cg, inst, &word_it);
595 try cg.addAtomicMemArg(.i32_atomic_rmw8_xchg_u, mem_arg);
596 } else if (mem.eql(u8, inst, "i32.atomic.rmw16.xchg_u")) {
597 const mem_arg = try parseMemArg(cg, inst, &word_it);
598 try cg.addAtomicMemArg(.i32_atomic_rmw16_xchg_u, mem_arg);
599 } else if (mem.eql(u8, inst, "i64.atomic.rmw8.xchg_u")) {
600 const mem_arg = try parseMemArg(cg, inst, &word_it);
601 try cg.addAtomicMemArg(.i64_atomic_rmw8_xchg_u, mem_arg);
602 } else if (mem.eql(u8, inst, "i64.atomic.rmw16.xchg_u")) {
603 const mem_arg = try parseMemArg(cg, inst, &word_it);
604 try cg.addAtomicMemArg(.i64_atomic_rmw16_xchg_u, mem_arg);
605 } else if (mem.eql(u8, inst, "i64.atomic.rmw32.xchg_u")) {
606 const mem_arg = try parseMemArg(cg, inst, &word_it);
607 try cg.addAtomicMemArg(.i64_atomic_rmw32_xchg_u, mem_arg);
608 } else if (mem.eql(u8, inst, "i32.atomic.rmw.cmpxchg")) {
609 const mem_arg = try parseMemArg(cg, inst, &word_it);
610 try cg.addAtomicMemArg(.i32_atomic_rmw_cmpxchg, mem_arg);
611 } else if (mem.eql(u8, inst, "i64.atomic.rmw.cmpxchg")) {
612 const mem_arg = try parseMemArg(cg, inst, &word_it);
613 try cg.addAtomicMemArg(.i64_atomic_rmw_cmpxchg, mem_arg);
614 } else if (mem.eql(u8, inst, "i32.atomic.rmw8.cmpxchg_u")) {
615 const mem_arg = try parseMemArg(cg, inst, &word_it);
616 try cg.addAtomicMemArg(.i32_atomic_rmw8_cmpxchg_u, mem_arg);
617 } else if (mem.eql(u8, inst, "i32.atomic.rmw16.cmpxchg_u")) {
618 const mem_arg = try parseMemArg(cg, inst, &word_it);
619 try cg.addAtomicMemArg(.i32_atomic_rmw16_cmpxchg_u, mem_arg);
620 } else if (mem.eql(u8, inst, "i64.atomic.rmw8.cmpxchg_u")) {
621 const mem_arg = try parseMemArg(cg, inst, &word_it);
622 try cg.addAtomicMemArg(.i64_atomic_rmw8_cmpxchg_u, mem_arg);
623 } else if (mem.eql(u8, inst, "i64.atomic.rmw16.cmpxchg_u")) {
624 const mem_arg = try parseMemArg(cg, inst, &word_it);
625 try cg.addAtomicMemArg(.i64_atomic_rmw16_cmpxchg_u, mem_arg);
626 } else if (mem.eql(u8, inst, "i64.atomic.rmw32.cmpxchg_u")) {
627 const mem_arg = try parseMemArg(cg, inst, &word_it);
628 try cg.addAtomicMemArg(.i64_atomic_rmw32_cmpxchg_u, mem_arg);
629 } else {
630 if (mem.startsWith(u8, inst, "#")) continue :next_line;
631 if (mem.startsWith(u8, inst, "//")) continue :next_line;
632
633 return cg.fail("Malformed assembly, unknown instruction \"{s}\"", .{inst});
634 }
635
636 const remaining = word_it.next() orelse continue :next_line;
637 if (mem.startsWith(u8, inst, "#")) continue :next_line;
638 if (mem.startsWith(u8, inst, "//")) continue :next_line;
639 return cg.fail("Malformed assembly, unknown string after instruction \"{s}\"", .{remaining});
640 }
641}
642
643fn parseLocalArg(
644 cg: *CodeGen,
645 inst: []const u8,
646 word_it: *mem.TokenIterator(u8, .any),
647 local_map: *const LocalMap,
648) !u32 {
649 const arg = word_it.next() orelse {
650 return cg.fail("Malformed assembly, argument not found for \"{s}\"", .{inst});
651 };
652 if (arg.len < 3 or arg[0] != '%' or arg[1] != '[' or arg[arg.len - 1] != ']') {
653 const local = std.fmt.parseInt(u32, arg, 0) catch {
654 return cg.fail("Malformed assembly, malformed argument \"{s}\"", .{arg});
655 };
656 return local;
657 }
658 const name = arg[2 .. arg.len - 1];
659 return local_map.get(name) orelse {
660 return cg.fail("Malformed assembly, unknown name \"{s}\"", .{name});
661 };
662}
663
664fn parseLabel(cg: *CodeGen, inst: []const u8, word_it: *mem.TokenIterator(u8, .any)) !u32 {
665 const label_str = word_it.next() orelse {
666 return cg.fail("Malformed assembly, label not found for \"{s}\"", .{inst});
667 };
668 const label = std.fmt.parseInt(u32, label_str, 0) catch {
669 return cg.fail("Malformed assembly, malformed label \"{s}\"", .{label_str});
670 };
671 return label;
672}
673
674fn parseMemArg(cg: *CodeGen, inst: []const u8, word_it: *mem.TokenIterator(u8, .any)) !Mir.MemArg {
675 const mem_arg_str = word_it.next() orelse {
676 return cg.fail("Malformed assembly, memory argument not found for \"{s}\"", .{inst});
677 };
678 if (mem.cut(u8, mem_arg_str, ":p2align=")) |oa| {
679 const offset_str = oa[0];
680 const alignment_str = oa[1];
681
682 const offset = std.fmt.parseInt(i32, offset_str, 0) catch {
683 return cg.fail("Malformed assembly, malformed offset \"{s}\"", .{offset_str});
684 };
685 const alignment_p2 = std.fmt.parseInt(u5, alignment_str, 0) catch {
686 return cg.fail("Malformed assembly, malformed offset \"{s}\"", .{alignment_str});
687 };
688
689 return .{ .offset = @bitCast(offset), .alignment = @as(u32, 1) << alignment_p2 };
690 } else {
691 const offset_str = mem_arg_str;
692 const offset = std.fmt.parseInt(i32, offset_str, 0) catch {
693 return cg.fail("Malformed assembly, malformed offset \"{s}\"", .{offset_str});
694 };
695 return .{ .offset = @bitCast(offset), .alignment = 1 };
696 }
697}
698
699fn parseInt(comptime T: type, cg: *CodeGen, inst: []const u8, word_it: *mem.TokenIterator(u8, .any)) !T {
700 const value_str = word_it.next() orelse {
701 return cg.fail("Malformed assembly, value not found for \"{s}\"", .{inst});
702 };
703 const value = std.fmt.parseInt(T, value_str, 0) catch {
704 return cg.fail("Malformed assembly, malformed integer value \"{s}\"", .{value_str});
705 };
706 return value;
707}
708
709fn parseFloat(comptime T: type, cg: *CodeGen, inst: []const u8, word_it: *mem.TokenIterator(u8, .any)) !T {
710 const value_str = word_it.next() orelse {
711 return cg.fail("Malformed assembly, value not found for \"{s}\"", .{inst});
712 };
713 const value = std.fmt.parseFloat(T, value_str) catch {
714 return cg.fail("Malformed assembly, malformed float value \"{s}\"", .{value_str});
715 };
716 return value;
717}