logicaffeine_compile/vm/wasm/
encode.rs1use crate::vm::instruction::Reg;
10
11pub(crate) const I64: u8 = 0x7E;
12pub(crate) const I32: u8 = 0x7F;
13pub(crate) const F64: u8 = 0x7C;
14pub(crate) const VOID_BLOCKTYPE: u8 = 0x40;
15
16pub(crate) fn leb_u32(out: &mut Vec<u8>, mut v: u32) {
17 loop {
18 let mut byte = (v & 0x7f) as u8;
19 v >>= 7;
20 if v != 0 {
21 byte |= 0x80;
22 }
23 out.push(byte);
24 if v == 0 {
25 break;
26 }
27 }
28}
29
30pub(crate) fn leb_i64(out: &mut Vec<u8>, mut v: i64) {
31 loop {
32 let byte = (v & 0x7f) as u8;
33 v >>= 7; let sign = byte & 0x40 != 0;
35 if (v == 0 && !sign) || (v == -1 && sign) {
36 out.push(byte);
37 break;
38 }
39 out.push(byte | 0x80);
40 }
41}
42
43pub(crate) fn section(out: &mut Vec<u8>, id: u8, content: &[u8]) {
44 out.push(id);
45 leb_u32(out, content.len() as u32);
46 out.extend_from_slice(content);
47}
48
49pub(crate) fn local_get(out: &mut Vec<u8>, idx: u32) {
50 out.push(0x20);
51 leb_u32(out, idx);
52}
53
54pub(crate) fn local_set(out: &mut Vec<u8>, idx: u32) {
55 out.push(0x21);
56 leb_u32(out, idx);
57}
58
59pub(crate) fn local_tee(out: &mut Vec<u8>, idx: u32) {
60 out.push(0x22);
61 leb_u32(out, idx);
62}
63
64pub(crate) fn global_get(out: &mut Vec<u8>, idx: u32) {
65 out.push(0x23);
66 leb_u32(out, idx);
67}
68
69pub(crate) fn global_set(out: &mut Vec<u8>, idx: u32) {
70 out.push(0x24);
71 leb_u32(out, idx);
72}
73
74pub(crate) fn leb_i32(out: &mut Vec<u8>, mut v: i32) {
76 loop {
77 let byte = (v & 0x7f) as u8;
78 v >>= 7; let sign = byte & 0x40 != 0;
80 if (v == 0 && !sign) || (v == -1 && sign) {
81 out.push(byte);
82 break;
83 }
84 out.push(byte | 0x80);
85 }
86}
87
88pub(crate) fn i32_const(out: &mut Vec<u8>, v: i32) {
89 out.push(0x41);
90 leb_i32(out, v);
91}
92
93fn mem_op(out: &mut Vec<u8>, opcode: u8, align: u32, offset: u32) {
96 out.push(opcode);
97 leb_u32(out, align);
98 leb_u32(out, offset);
99}
100
101pub(crate) fn i32_load(out: &mut Vec<u8>, offset: u32) {
102 mem_op(out, 0x28, 2, offset);
103}
104pub(crate) fn i32_store(out: &mut Vec<u8>, offset: u32) {
105 mem_op(out, 0x36, 2, offset);
106}
107pub(crate) fn i64_load(out: &mut Vec<u8>, offset: u32) {
108 mem_op(out, 0x29, 3, offset);
109}
110pub(crate) fn i64_store(out: &mut Vec<u8>, offset: u32) {
111 mem_op(out, 0x37, 3, offset);
112}
113pub(crate) fn f64_load(out: &mut Vec<u8>, offset: u32) {
114 mem_op(out, 0x2B, 3, offset);
115}
116pub(crate) fn f64_store(out: &mut Vec<u8>, offset: u32) {
117 mem_op(out, 0x39, 3, offset);
118}
119pub(crate) fn i32_load8_u(out: &mut Vec<u8>, offset: u32) {
121 mem_op(out, 0x2D, 0, offset);
122}
123pub(crate) fn i32_store8(out: &mut Vec<u8>, offset: u32) {
124 mem_op(out, 0x3A, 0, offset);
125}
126
127pub(crate) fn arith(out: &mut Vec<u8>, opcode: u8, dst: Reg, lhs: Reg, rhs: Reg) {
129 local_get(out, lhs as u32);
130 local_get(out, rhs as u32);
131 out.push(opcode);
132 local_set(out, dst as u32);
133}
134
135pub(crate) fn compare(out: &mut Vec<u8>, cmp_opcode: u8, dst: Reg, lhs: Reg, rhs: Reg) {
138 local_get(out, lhs as u32);
139 local_get(out, rhs as u32);
140 out.push(cmp_opcode);
141 out.push(0xAD); local_set(out, dst as u32);
143}
144
145pub(crate) fn emit_checked_addsub(out: &mut Vec<u8>, is_sub: bool, dst: Reg, lhs: Reg, rhs: Reg) {
153 local_get(out, lhs as u32);
154 local_get(out, rhs as u32);
155 out.push(if is_sub { 0x7D } else { 0x7C }); local_set(out, dst as u32);
157 if is_sub {
158 local_get(out, lhs as u32);
159 local_get(out, rhs as u32);
160 out.push(0x85); local_get(out, lhs as u32);
162 local_get(out, dst as u32);
163 out.push(0x85); } else {
165 local_get(out, lhs as u32);
166 local_get(out, dst as u32);
167 out.push(0x85); local_get(out, rhs as u32);
169 local_get(out, dst as u32);
170 out.push(0x85); }
172 out.push(0x83); out.push(0x42);
174 out.push(0x00); out.push(0x53); out.push(0x04);
177 out.push(0x40); out.push(0x00); out.push(0x0B); }
181
182pub(crate) fn emit_checked_mul(out: &mut Vec<u8>, dst: Reg, lhs: Reg, rhs: Reg) {
188 local_get(out, lhs as u32);
189 local_get(out, rhs as u32);
190 out.push(0x7E); local_set(out, dst as u32);
192 local_get(out, lhs as u32);
193 out.push(0x50); out.push(0x04);
195 out.push(0x40); out.push(0x05); local_get(out, dst as u32);
198 local_get(out, lhs as u32);
199 out.push(0x7F); local_get(out, rhs as u32);
201 out.push(0x52); out.push(0x04);
203 out.push(0x40); out.push(0x00); out.push(0x0B); out.push(0x0B); }
208
209pub(crate) fn emit_cond_jump(
213 code: &mut Vec<u8>,
214 cond: Reg,
215 jump_when_false: bool,
216 target_block: usize,
217 fallthrough_block: usize,
218 pc_local: u32,
219 loop_depth: u32,
220) {
221 code.push(0x41); leb_u32(code, target_block as u32);
224 code.push(0x41); leb_u32(code, fallthrough_block as u32);
226 local_get(code, cond as u32);
227 if jump_when_false {
228 code.push(0x50); } else {
230 code.push(0x50); code.push(0x45); }
234 code.push(0x1B); local_set(code, pc_local);
236 code.push(0x0C); leb_u32(code, loop_depth);
238}