v2 / vlib / v / gen / wasm / asm.v
890 lines · 851 sloc · 15.4 KB · 8e35f4d9848f7ad35d857a187dddbfd2eca5e19d
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
7
8pub fn (mut g Gen) asm_call(node ast.AsmTemplate) {
9 // call 'main.test'
10 // call 'main.Struct.+'
11 //
12 // call 'wasi_unstable' 'proc_exit'
13 // call 'console' 'log'
14
15 if node.args.len !in [1, 2] {
16 g.v_error('incorrect number of arguments to `${node.name}`', node.pos)
17 }
18
19 arg0 := node.args[0]
20 sarg0 := if arg0 is string {
21 arg0
22 } else if node.args.len == 1 {
23 g.v_error('`${node.name}` must accept a string to call', node.pos)
24 } else {
25 g.v_error('`${node.name}` must accept a namespace for call', node.pos)
26 }
27
28 if node.args.len == 1 {
29 g.func.call(sarg0)
30 return
31 }
32
33 arg1 := node.args[1]
34 sarg1 := if arg1 is string {
35 arg1
36 } else {
37 g.v_error('`${node.name}` must accept a string for call', node.pos)
38 }
39
40 g.func.call_import(sarg0, sarg1)
41}
42
43pub fn (mut g Gen) asm_local_get_set_or_tee(node ast.AsmTemplate, vars AsmVars) {
44 if node.args.len != 1 {
45 g.v_error('incorrect number of arguments to `${node.name}`', node.pos)
46 }
47
48 arg0 := node.args[0]
49 alias := match arg0 {
50 ast.AsmAlias {
51 arg0
52 }
53 else {
54 g.v_error('must reference local by identifier', node.pos)
55 }
56 }
57
58 target_var := if alias.name == '__vbp' {
59 Var{
60 idx: g.bp()
61 }
62 } else {
63 var := vars[alias.name] or { g.v_error('unknown identifier', alias.pos) }
64 var
65 }
66 // -- doesn't work, cgen error
67 // else if var := vars[alias.name] {
68 // var
69 // }
70
71 if target_var.is_global {
72 g.v_error('`${alias.name}` is global, cannot use with this instruction', alias.pos)
73 }
74
75 match node.name {
76 'local.get' {
77 g.get(target_var)
78 }
79 'local.set' {
80 g.set(target_var)
81 }
82 'local.tee' {
83 g.tee(target_var)
84 }
85 else {
86 panic('unreachable')
87 }
88 }
89}
90
91pub fn (mut g Gen) asm_global_get_or_set(node ast.AsmTemplate, vars AsmVars) {
92 if node.args.len != 1 {
93 g.v_error('incorrect number of arguments to `${node.name}`', node.pos)
94 }
95
96 arg0 := node.args[0]
97 alias := match arg0 {
98 ast.AsmAlias {
99 arg0
100 }
101 else {
102 g.v_error('must reference global by identifier', node.pos)
103 }
104 }
105
106 target_var := if alias.name == '__vsp' {
107 Var{
108 g_idx: g.sp()
109 is_global: true
110 }
111 } else if alias.name == '__heap_base' {
112 Var{
113 g_idx: g.hp()
114 is_global: true
115 }
116 } else {
117 var := vars[alias.name] or { g.v_error('unknown identifier', alias.pos) }
118 var
119 }
120
121 if !target_var.is_global {
122 g.v_error('`${alias.name}` is a local, cannot use with this instruction', alias.pos)
123 }
124
125 match node.name {
126 'global.get' {
127 g.get(target_var)
128 }
129 'global.set' {
130 g.set(target_var)
131 }
132 else {
133 panic('unreachable')
134 }
135 }
136}
137
138pub fn (mut g Gen) asm_literal_arg(node ast.AsmTemplate) {
139 // i32.const
140 // i64.const
141 // f32.const
142 // f64.const
143
144 if node.args.len != 1 {
145 g.v_error('incorrect number of arguments to `${node.name}`', node.pos)
146 }
147
148 is_float := node.name[0] == `f`
149 arg := node.args[0]
150
151 if is_float {
152 literal := match arg {
153 ast.FloatLiteral {
154 arg.val
155 }
156 ast.IntegerLiteral {
157 arg.val
158 }
159 else {
160 g.v_error('must supply float value to `${node.name}`', node.pos)
161 }
162 }
163
164 match node.name {
165 'f32.const' {
166 g.func.f32_const(literal.f32())
167 }
168 'f64.const' {
169 g.func.f64_const(literal.f64())
170 }
171 else {
172 panic('unreachable')
173 }
174 }
175
176 return
177 }
178
179 literal := match arg {
180 ast.BoolLiteral {
181 if arg.val {
182 '1'
183 } else {
184 '0'
185 }
186 }
187 ast.CharLiteral {
188 u32(arg.val.runes()[0]).str() // there is a better way.
189 }
190 ast.IntegerLiteral {
191 arg.val
192 }
193 else {
194 g.v_error('must supply integer-like value to `${node.name}`', node.pos)
195 }
196 }
197
198 match node.name {
199 'i32.const' {
200 g.func.i32_const(i32(literal.int()))
201 }
202 'i64.const' {
203 g.func.i64_const(literal.i64())
204 }
205 else {
206 panic('unreachable')
207 }
208 }
209}
210
211pub fn (mut g Gen) asm_parse_align_offset(node ast.AsmTemplate) (int, int) {
212 if node.args.len != 2 {
213 g.v_error('incorrect number of arguments to `${node.name}`', node.pos)
214 }
215
216 arg0 := node.args[0]
217 arg1 := node.args[1]
218
219 align := match arg0 {
220 ast.IntegerLiteral {
221 arg0.val.int()
222 }
223 else {
224 g.v_error('must supply integer value to align', node.pos)
225 }
226 }
227
228 offset := match arg1 {
229 ast.IntegerLiteral {
230 arg1.val.int()
231 }
232 else {
233 g.v_error('must supply integer value to offset', node.pos)
234 }
235 }
236
237 return align, offset
238}
239
240pub fn (mut g Gen) asm_load_or_store(node ast.AsmTemplate) {
241 align, offset := g.asm_parse_align_offset(node)
242
243 match node.name {
244 'i32.load' {
245 g.func.load(.i32_t, align, offset)
246 }
247 'i64.load' {
248 g.func.load(.i64_t, align, offset)
249 }
250 'f32.load' {
251 g.func.load(.f32_t, align, offset)
252 }
253 'f64.load' {
254 g.func.load(.f64_t, align, offset)
255 }
256 'i32.store' {
257 g.func.store(.i32_t, align, offset)
258 }
259 'i64.store' {
260 g.func.store(.i64_t, align, offset)
261 }
262 'f32.store' {
263 g.func.store(.f32_t, align, offset)
264 }
265 'f64.store' {
266 g.func.store(.f64_t, align, offset)
267 }
268 'i32.load8_s' {
269 g.func.load8(.i32_t, true, align, offset)
270 }
271 'i64.load8_s' {
272 g.func.load8(.i64_t, true, align, offset)
273 }
274 'i32.load8_u' {
275 g.func.load8(.i32_t, false, align, offset)
276 }
277 'i64.load8_u' {
278 g.func.load8(.i64_t, false, align, offset)
279 }
280 'i32.load16_s' {
281 g.func.load16(.i32_t, true, align, offset)
282 }
283 'i64.load16_s' {
284 g.func.load16(.i64_t, true, align, offset)
285 }
286 'i32.load16_u' {
287 g.func.load16(.i32_t, false, align, offset)
288 }
289 'i64.load16_u' {
290 g.func.load16(.i64_t, false, align, offset)
291 }
292 'i64.load32_s' {
293 g.func.load32_i64(true, align, offset)
294 }
295 'i64.load32_u' {
296 g.func.load32_i64(false, align, offset)
297 }
298 'i32.store8' {
299 g.func.store8(.i32_t, align, offset)
300 }
301 'i64.store8' {
302 g.func.store8(.i64_t, align, offset)
303 }
304 'i32.store16' {
305 g.func.store16(.i32_t, align, offset)
306 }
307 'i64.store16' {
308 g.func.store16(.i64_t, align, offset)
309 }
310 'i64.store32' {
311 g.func.store32_i64(align, offset)
312 }
313 else {
314 panic('unreachable')
315 }
316 }
317}
318
319pub fn (mut g Gen) asm_template(parent ast.AsmStmt, node ast.AsmTemplate, vars AsmVars) {
320 if node.is_label || node.is_directive {
321 g.v_error("`asm wasm` doesn't support labels or directives", node.pos)
322 }
323
324 match node.name {
325 'unreachable' {
326 g.func.unreachable()
327 }
328 'nop' {
329 g.func.nop()
330 }
331 'drop' {
332 g.func.drop()
333 }
334 'return' {
335 g.func.c_return()
336 }
337 'select' {
338 g.func.c_select()
339 }
340 'i32.const' {
341 g.asm_literal_arg(node)
342 }
343 'i64.const' {
344 g.asm_literal_arg(node)
345 }
346 'f32.const' {
347 g.asm_literal_arg(node)
348 }
349 'f64.const' {
350 g.asm_literal_arg(node)
351 }
352 'local.get' {
353 g.asm_local_get_set_or_tee(node, vars)
354 }
355 'local.set' {
356 g.asm_local_get_set_or_tee(node, vars)
357 }
358 'local.tee' {
359 g.asm_local_get_set_or_tee(node, vars)
360 }
361 'global.get' {
362 g.asm_global_get_or_set(node, vars)
363 }
364 'global.set' {
365 g.asm_global_get_or_set(node, vars)
366 }
367 'i32.load' {
368 g.asm_load_or_store(node)
369 }
370 'i64.load' {
371 g.asm_load_or_store(node)
372 }
373 'f32.load' {
374 g.asm_load_or_store(node)
375 }
376 'f64.load' {
377 g.asm_load_or_store(node)
378 }
379 'i32.store' {
380 g.asm_load_or_store(node)
381 }
382 'i64.store' {
383 g.asm_load_or_store(node)
384 }
385 'f32.store' {
386 g.asm_load_or_store(node)
387 }
388 'f64.store' {
389 g.asm_load_or_store(node)
390 }
391 'i32.load8_s' {
392 g.asm_load_or_store(node)
393 }
394 'i64.load8_s' {
395 g.asm_load_or_store(node)
396 }
397 'i32.load8_u' {
398 g.asm_load_or_store(node)
399 }
400 'i64.load8_u' {
401 g.asm_load_or_store(node)
402 }
403 'i32.load16_s' {
404 g.asm_load_or_store(node)
405 }
406 'i64.load16_s' {
407 g.asm_load_or_store(node)
408 }
409 'i32.load16_u' {
410 g.asm_load_or_store(node)
411 }
412 'i64.load16_u' {
413 g.asm_load_or_store(node)
414 }
415 'i64.load32_s' {
416 g.asm_load_or_store(node)
417 }
418 'i64.load32_u' {
419 g.asm_load_or_store(node)
420 }
421 'i32.store8' {
422 g.asm_load_or_store(node)
423 }
424 'i64.store8' {
425 g.asm_load_or_store(node)
426 }
427 'i32.store16' {
428 g.asm_load_or_store(node)
429 }
430 'i64.store16' {
431 g.asm_load_or_store(node)
432 }
433 'i64.store32' {
434 g.asm_load_or_store(node)
435 }
436 'call' {
437 g.asm_call(node)
438 }
439 'i32.add' {
440 g.func.add(.i32_t)
441 }
442 'i32.sub' {
443 g.func.sub(.i32_t)
444 }
445 'i32.mul' {
446 g.func.mul(.i32_t)
447 }
448 'i32.div_s' {
449 g.func.div(.i32_t, true)
450 }
451 'i32.div_u' {
452 g.func.div(.i32_t, false)
453 }
454 'i32.rem_s' {
455 g.func.rem(.i32_t, true)
456 }
457 'i32.rem_u' {
458 g.func.rem(.i32_t, false)
459 }
460 'i64.add' {
461 g.func.add(.i64_t)
462 }
463 'i64.sub' {
464 g.func.sub(.i64_t)
465 }
466 'i64.mul' {
467 g.func.mul(.i64_t)
468 }
469 'i64.div_s' {
470 g.func.div(.i64_t, true)
471 }
472 'i64.div_u' {
473 g.func.div(.i64_t, false)
474 }
475 'i64.rem_s' {
476 g.func.rem(.i64_t, true)
477 }
478 'i64.rem_u' {
479 g.func.rem(.i64_t, false)
480 }
481 'f32.add' {
482 g.func.add(.f32_t)
483 }
484 'f32.sub' {
485 g.func.sub(.f32_t)
486 }
487 'f32.mul' {
488 g.func.mul(.f32_t)
489 }
490 'f32.div' {
491 g.func.div(.f32_t, true)
492 }
493 'f64.add' {
494 g.func.add(.f64_t)
495 }
496 'f64.sub' {
497 g.func.sub(.f64_t)
498 }
499 'f64.mul' {
500 g.func.mul(.f64_t)
501 }
502 'f64.div' {
503 g.func.div(.f64_t, true)
504 }
505 'i32.eqz' {
506 g.func.eqz(.i32_t)
507 }
508 'i32.eq' {
509 g.func.eq(.i32_t)
510 }
511 'i32.ne' {
512 g.func.ne(.i32_t)
513 }
514 'i32.lt_s' {
515 g.func.lt(.i32_t, true)
516 }
517 'i32.lt_u' {
518 g.func.lt(.i32_t, false)
519 }
520 'i32.gt_s' {
521 g.func.gt(.i32_t, true)
522 }
523 'i32.gt_u' {
524 g.func.gt(.i32_t, false)
525 }
526 'i32.le_s' {
527 g.func.le(.i32_t, true)
528 }
529 'i32.le_u' {
530 g.func.le(.i32_t, false)
531 }
532 'i32.ge_s' {
533 g.func.ge(.i32_t, true)
534 }
535 'i32.ge_u' {
536 g.func.ge(.i32_t, false)
537 }
538 'i64.eqz' {
539 g.func.eqz(.i64_t)
540 }
541 'i64.eq' {
542 g.func.eq(.i64_t)
543 }
544 'i64.ne' {
545 g.func.ne(.i64_t)
546 }
547 'i64.lt_s' {
548 g.func.lt(.i64_t, true)
549 }
550 'i64.lt_u' {
551 g.func.lt(.i64_t, false)
552 }
553 'i64.gt_s' {
554 g.func.gt(.i64_t, true)
555 }
556 'i64.gt_u' {
557 g.func.gt(.i64_t, false)
558 }
559 'i64.le_s' {
560 g.func.le(.i64_t, true)
561 }
562 'i64.le_u' {
563 g.func.le(.i64_t, false)
564 }
565 'i64.ge_s' {
566 g.func.ge(.i64_t, true)
567 }
568 'i64.ge_u' {
569 g.func.ge(.i64_t, false)
570 }
571 'f32.eq' {
572 g.func.eq(.f32_t)
573 }
574 'f32.ne' {
575 g.func.ne(.f32_t)
576 }
577 'f32.lt' {
578 g.func.lt(.f32_t, true)
579 }
580 'f32.gt' {
581 g.func.gt(.f32_t, true)
582 }
583 'f32.le' {
584 g.func.le(.f32_t, true)
585 }
586 'f32.ge' {
587 g.func.ge(.f32_t, true)
588 }
589 'f64.eq' {
590 g.func.eq(.f64_t)
591 }
592 'f64.ne' {
593 g.func.ne(.f64_t)
594 }
595 'f64.lt' {
596 g.func.lt(.f64_t, true)
597 }
598 'f64.gt' {
599 g.func.gt(.f64_t, true)
600 }
601 'f64.le' {
602 g.func.le(.f64_t, true)
603 }
604 'f64.ge' {
605 g.func.ge(.f64_t, true)
606 }
607 'i32.and' {
608 g.func.b_and(.i32_t)
609 }
610 'i32.or' {
611 g.func.b_or(.i32_t)
612 }
613 'i32.xor' {
614 g.func.b_xor(.i32_t)
615 }
616 'i32.shl' {
617 g.func.b_shl(.i32_t)
618 }
619 'i32.shr_s' {
620 g.func.b_shr(.i32_t, true)
621 }
622 'i32.shr_u' {
623 g.func.b_shr(.i32_t, true)
624 }
625 'i32.rotl' {
626 g.func.rotl(.i32_t)
627 }
628 'i32.rotr' {
629 g.func.rotr(.i32_t)
630 }
631 'i32.clz' {
632 g.func.clz(.i32_t)
633 }
634 'i32.ctz' {
635 g.func.ctz(.i32_t)
636 }
637 'i32.popcnt' {
638 g.func.popcnt(.i32_t)
639 }
640 'i64.and' {
641 g.func.b_and(.i64_t)
642 }
643 'i64.or' {
644 g.func.b_or(.i64_t)
645 }
646 'i64.xor' {
647 g.func.b_xor(.i64_t)
648 }
649 'i64.shl' {
650 g.func.b_shl(.i64_t)
651 }
652 'i64.shr_s' {
653 g.func.b_shr(.i64_t, true)
654 }
655 'i64.shr_u' {
656 g.func.b_shr(.i64_t, false)
657 }
658 'i64.rotl' {
659 g.func.rotl(.i64_t)
660 }
661 'i64.rotr' {
662 g.func.rotr(.i64_t)
663 }
664 'i64.clz' {
665 g.func.clz(.i64_t)
666 }
667 'i64.ctz' {
668 g.func.ctz(.i64_t)
669 }
670 'i64.popcnt' {
671 g.func.popcnt(.i64_t)
672 }
673 'f32.neg' {
674 g.func.neg(.f32_t)
675 }
676 'f32.ceil' {
677 g.func.ceil(.f32_t)
678 }
679 'f32.floor' {
680 g.func.floor(.f32_t)
681 }
682 'f32.trunc' {
683 g.func.trunc(.f32_t)
684 }
685 'f32.nearest' {
686 g.func.nearest(.f32_t)
687 }
688 'f32.sqrt' {
689 g.func.sqrt(.f32_t)
690 }
691 'f32.min' {
692 g.func.min(.f32_t)
693 }
694 'f32.max' {
695 g.func.max(.f32_t)
696 }
697 'f32.copysign' {
698 g.func.copysign(.f32_t)
699 }
700 'f64.abs' {
701 g.func.abs(.f64_t)
702 }
703 'f64.neg' {
704 g.func.neg(.f64_t)
705 }
706 'f64.ceil' {
707 g.func.ceil(.f64_t)
708 }
709 'f64.floor' {
710 g.func.floor(.f64_t)
711 }
712 'f64.trunc' {
713 g.func.trunc(.f64_t)
714 }
715 'f64.nearest' {
716 g.func.nearest(.f64_t)
717 }
718 'f64.sqrt' {
719 g.func.sqrt(.f64_t)
720 }
721 'f64.min' {
722 g.func.min(.f64_t)
723 }
724 'f64.max' {
725 g.func.max(.f64_t)
726 }
727 'f64.copysign' {
728 g.func.copysign(.f64_t)
729 }
730 'i32.wrap_i64' {
731 g.func.cast(.i64_t, false, .i32_t)
732 }
733 'i32.trunc_f32_s' {
734 g.func.cast_trapping(.f32_t, true, .i32_t)
735 }
736 'i32.trunc_f32_u' {
737 g.func.cast_trapping(.f32_t, false, .i32_t)
738 }
739 'i32.trunc_f64_s' {
740 g.func.cast_trapping(.f64_t, true, .i32_t)
741 }
742 'i32.trunc_f64_u' {
743 g.func.cast_trapping(.f64_t, false, .i32_t)
744 }
745 'i64.extend_i32_s' {
746 g.func.cast(.i32_t, true, .i64_t)
747 }
748 'i64.extend_i32_u' {
749 g.func.cast(.i32_t, false, .i64_t)
750 }
751 'i64.trunc_f32_s' {
752 g.func.cast_trapping(.f32_t, true, .i64_t)
753 }
754 'i64.trunc_f32_u' {
755 g.func.cast_trapping(.f32_t, false, .i64_t)
756 }
757 'i64.trunc_f64_s' {
758 g.func.cast_trapping(.f64_t, true, .i64_t)
759 }
760 'i64.trunc_f64_u' {
761 g.func.cast_trapping(.f64_t, false, .i64_t)
762 }
763 'f32.convert_i32_s' {
764 g.func.cast(.i32_t, true, .f32_t)
765 }
766 'f32.convert_i32_u' {
767 g.func.cast(.i32_t, false, .f32_t)
768 }
769 'f32.convert_i64_s' {
770 g.func.cast(.i64_t, true, .f32_t)
771 }
772 'f32.convert_i64_u' {
773 g.func.cast(.i64_t, false, .f32_t)
774 }
775 'f32.demote_f64' {
776 g.func.cast(.f64_t, true, .f32_t)
777 }
778 'f64.convert_i32_s' {
779 g.func.cast(.i32_t, true, .f64_t)
780 }
781 'f64.convert_i32_u' {
782 g.func.cast(.i32_t, false, .f64_t)
783 }
784 'f64.convert_i64_s' {
785 g.func.cast(.i64_t, true, .f64_t)
786 }
787 'f64.convert_i64_u' {
788 g.func.cast(.i64_t, false, .f64_t)
789 }
790 'f64.promote_f32' {
791 g.func.cast(.f32_t, true, .f64_t)
792 }
793 'i32.reinterpret_f32' {
794 g.func.reinterpret(.f32_t)
795 }
796 'i64.reinterpret_f64' {
797 g.func.reinterpret(.f64_t)
798 }
799 'f32.reinterpret_i32' {
800 g.func.reinterpret(.i32_t)
801 }
802 'f64.reinterpret_i64' {
803 g.func.reinterpret(.i64_t)
804 }
805 'i32.extend8_s' {
806 g.func.sign_extend8(.i32_t)
807 }
808 'i32.extend16_s' {
809 g.func.sign_extend16(.i32_t)
810 }
811 'i64.extend8_s' {
812 g.func.sign_extend8(.i64_t)
813 }
814 'i64.extend16_s' {
815 g.func.sign_extend16(.i64_t)
816 }
817 'i64.extend32_s' {
818 g.func.sign_extend32()
819 }
820 'i32.trunc_sat_f32_s' {
821 g.func.cast(.f32_t, true, .i32_t)
822 }
823 'i32.trunc_sat_f32_u' {
824 g.func.cast(.f32_t, false, .i32_t)
825 }
826 'i32.trunc_sat_f64_s' {
827 g.func.cast(.f64_t, true, .i32_t)
828 }
829 'i32.trunc_sat_f64_u' {
830 g.func.cast(.f64_t, false, .i32_t)
831 }
832 'i64.trunc_sat_f32_s' {
833 g.func.cast(.f32_t, true, .i64_t)
834 }
835 'i64.trunc_sat_f32_u' {
836 g.func.cast(.f32_t, false, .i64_t)
837 }
838 'i64.trunc_sat_f64_s' {
839 g.func.cast(.f64_t, true, .i64_t)
840 }
841 'i64.trunc_sat_f64_u' {
842 g.func.cast(.f64_t, false, .i64_t)
843 }
844 'memory.size' {
845 g.func.memory_size()
846 }
847 'memory.grow' {
848 g.func.memory_grow()
849 }
850 'memory.copy' {
851 g.func.memory_copy()
852 }
853 'memory.fill' {
854 g.func.memory_fill()
855 }
856 // TODO: impl later
857 /*
858 'ref.null' {
859 g.func.ref_null()
860 }
861 */
862 else {
863 g.v_error('unknown opcode', node.pos)
864 }
865 }
866}
867
868type AsmVars = map[string]Var
869
870pub fn (mut g Gen) asm_stmt(node ast.AsmStmt) {
871 mut vars := AsmVars(map[string]Var{})
872
873 for var_expr in node.output {
874 vars[var_expr.alias] = g.get_var_or_make_from_expr(var_expr.expr, var_expr.typ)
875 }
876 for var_expr in node.input {
877 vars[var_expr.alias] = g.get_var_or_make_from_expr(var_expr.expr, var_expr.typ)
878 }
879
880 if node.clobbered.len != 0 {
881 g.v_error('wasm does not support clobber lists', node.pos)
882 }
883 if node.global_labels.len != 0 || node.local_labels.len != 0 {
884 g.v_error('wasm does not support labels', node.pos)
885 }
886
887 for tmpl in node.templates {
888 g.asm_template(node, tmpl, vars)
889 }
890}
891