Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
interpret_visitor.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <sysio/vm/config.hpp>
4#include <sysio/vm/base_visitor.hpp>
5#include <sysio/vm/exceptions.hpp>
6#include <sysio/vm/opcodes.hpp>
7#include <sysio/vm/softfloat.hpp>
8#include <sysio/vm/stack_elem.hpp>
9#include <sysio/vm/utils.hpp>
10#include <sysio/vm/wasm_stack.hpp>
11
12#include <cstddef>
13#include <cstdint>
14#include <cstring>
15#include <limits>
16
17namespace sysio { namespace vm {
18
19 template <typename ExecutionContext>
20 struct interpret_visitor : base_visitor {
21 using base_visitor::operator();
22 interpret_visitor(ExecutionContext& ec) : context(ec) {}
23 ExecutionContext& context;
24
25 ExecutionContext& get_context() { return context; }
26
27 static inline constexpr void* align_address(void* addr, size_t align_amt) {
28 if constexpr (should_align_memory_ops) {
29 addr = (void*)(((uintptr_t)addr + (1 << align_amt) - 1) & ~((1 << align_amt) - 1));
30 return addr;
31 } else {
32 return addr;
33 }
34 }
35 template<typename T>
36 static inline T read_unaligned(const void* addr) {
37 T result;
38 std::memcpy(&result, addr, sizeof(T));
39 return result;
40 }
41 template<typename T>
42 static void write_unaligned(void* addr, T value) {
43 std::memcpy(addr, &value, sizeof(T));
44 }
45
46 [[gnu::always_inline]] inline void operator()(const unreachable_t& op) {
47 context.inc_pc();
48 throw wasm_interpreter_exception{ "unreachable" };
49 }
50
51 [[gnu::always_inline]] inline void operator()(const nop_t& op) { context.inc_pc(); }
52
53 [[gnu::always_inline]] inline void operator()(const end_t& op) { context.inc_pc(); }
54 [[gnu::always_inline]] inline void operator()(const return_t& op) { context.apply_pop_call(op.data, op.pc); }
55 [[gnu::always_inline]] inline void operator()(const block_t& op) { context.inc_pc(); }
56 [[gnu::always_inline]] inline void operator()(const loop_t& op) { context.inc_pc(); }
57 [[gnu::always_inline]] inline void operator()(const if_t& op) {
58 context.inc_pc();
59 const auto& oper = context.pop_operand();
60 if (!oper.to_ui32()) {
61 context.set_relative_pc(op.pc);
62 }
63 }
64 [[gnu::always_inline]] inline void operator()(const else_t& op) { context.set_relative_pc(op.pc); }
65 [[gnu::always_inline]] inline void operator()(const br_t& op) { context.jump(op.data, op.pc); }
66 [[gnu::always_inline]] inline void operator()(const br_if_t& op) {
67 const auto& val = context.pop_operand();
68 if (context.is_true(val)) {
69 context.jump(op.data, op.pc);
70 } else {
71 context.inc_pc();
72 }
73 }
74
75 [[gnu::always_inline]] inline void operator()(const br_table_data_t& op) {
76 context.inc_pc(op.index);
77 }
78 [[gnu::always_inline]] inline void operator()(const br_table_t& op) {
79 const auto& in = context.pop_operand().to_ui32();
80 const auto& entry = op.table[std::min(in, op.size)];
81 context.jump(entry.stack_pop, entry.pc);
82 }
83 [[gnu::always_inline]] inline void operator()(const call_t& op) {
84 context.call(op.index);
85 }
86 [[gnu::always_inline]] inline void operator()(const call_indirect_t& op) {
87 const auto& index = context.pop_operand().to_ui32();
88 uint32_t fn = context.table_elem(index);
89 const auto& expected_type = context.get_module().types.at(op.index);
90 const auto& actual_type = context.get_module().get_function_type(fn);
91 SYS_VM_ASSERT(actual_type == expected_type, wasm_interpreter_exception, "bad call_indirect type");
92 context.call(fn);
93 }
94 [[gnu::always_inline]] inline void operator()(const drop_t& op) {
95 context.pop_operand();
96 context.inc_pc();
97 }
98 [[gnu::always_inline]] inline void operator()(const select_t& op) {
99 const auto& c = context.pop_operand();
100 const auto& v2 = context.pop_operand();
101 if (c.to_ui32() == 0) {
102 context.peek_operand() = v2;
103 }
104 context.inc_pc();
105 }
106 [[gnu::always_inline]] inline void operator()(const get_local_t& op) {
107 context.inc_pc();
108 context.push_operand(context.get_operand(op.index));
109 }
110 [[gnu::always_inline]] inline void operator()(const set_local_t& op) {
111 context.inc_pc();
112 context.set_operand(op.index, context.pop_operand());
113 }
114 [[gnu::always_inline]] inline void operator()(const tee_local_t& op) {
115 context.inc_pc();
116 const auto& oper = context.pop_operand();
117 context.set_operand(op.index, oper);
118 context.push_operand(oper);
119 }
120 [[gnu::always_inline]] inline void operator()(const get_global_t& op) {
121 context.inc_pc();
122 const auto& gl = context.get_global(op.index);
123 context.push_operand(gl);
124 }
125 [[gnu::always_inline]] inline void operator()(const set_global_t& op) {
126 context.inc_pc();
127 const auto& oper = context.pop_operand();
128 context.set_global(op.index, oper);
129 }
130 template<typename Op>
131 inline void * pop_memop_addr(const Op& op) {
132 const auto& ptr = context.pop_operand();
133 return align_address((context.linear_memory() + op.offset + ptr.to_ui32()), op.flags_align);
134 }
135 [[gnu::always_inline]] inline void operator()(const i32_load_t& op) {
136 context.inc_pc();
137 void* _ptr = pop_memop_addr(op);
138 context.push_operand(i32_const_t{ read_unaligned<uint32_t>(_ptr) });
139 }
140 [[gnu::always_inline]] inline void operator()(const i32_load8_s_t& op) {
141 context.inc_pc();
142 void* _ptr = pop_memop_addr(op);
143 context.push_operand(i32_const_t{ static_cast<int32_t>(read_unaligned<int8_t>(_ptr) ) });
144 }
145 [[gnu::always_inline]] inline void operator()(const i32_load16_s_t& op) {
146 context.inc_pc();
147 void* _ptr = pop_memop_addr(op);
148 context.push_operand(i32_const_t{ static_cast<int32_t>( read_unaligned<int16_t>(_ptr) ) });
149 }
150 [[gnu::always_inline]] inline void operator()(const i32_load8_u_t& op) {
151 context.inc_pc();
152 void* _ptr = pop_memop_addr(op);
153 context.push_operand(i32_const_t{ static_cast<uint32_t>( read_unaligned<uint8_t>(_ptr) ) });
154 }
155 [[gnu::always_inline]] inline void operator()(const i32_load16_u_t& op) {
156 context.inc_pc();
157 void* _ptr = pop_memop_addr(op);
158 context.push_operand(i32_const_t{ static_cast<uint32_t>( read_unaligned<uint16_t>(_ptr) ) });
159 }
160 [[gnu::always_inline]] inline void operator()(const i64_load_t& op) {
161 context.inc_pc();
162 void* _ptr = pop_memop_addr(op);
163 context.push_operand(i64_const_t{ static_cast<uint64_t>( read_unaligned<uint64_t>(_ptr) ) });
164 }
165 [[gnu::always_inline]] inline void operator()(const i64_load8_s_t& op) {
166 context.inc_pc();
167 void* _ptr = pop_memop_addr(op);
168 context.push_operand(i64_const_t{ static_cast<int64_t>( read_unaligned<int8_t>(_ptr) ) });
169 }
170 [[gnu::always_inline]] inline void operator()(const i64_load16_s_t& op) {
171 context.inc_pc();
172 void* _ptr = pop_memop_addr(op);
173 context.push_operand(i64_const_t{ static_cast<int64_t>( read_unaligned<int16_t>(_ptr) ) });
174 }
175 [[gnu::always_inline]] inline void operator()(const i64_load32_s_t& op) {
176 context.inc_pc();
177 void* _ptr = pop_memop_addr(op);
178 context.push_operand(i64_const_t{ static_cast<int64_t>( read_unaligned<int32_t>(_ptr) ) });
179 }
180 [[gnu::always_inline]] inline void operator()(const i64_load8_u_t& op) {
181 context.inc_pc();
182 void* _ptr = pop_memop_addr(op);
183 context.push_operand(i64_const_t{ static_cast<uint64_t>( read_unaligned<uint8_t>(_ptr) ) });
184 }
185 [[gnu::always_inline]] inline void operator()(const i64_load16_u_t& op) {
186 context.inc_pc();
187 void* _ptr = pop_memop_addr(op);
188 context.push_operand(i64_const_t{ static_cast<uint64_t>( read_unaligned<uint16_t>(_ptr) ) });
189 }
190 [[gnu::always_inline]] inline void operator()(const i64_load32_u_t& op) {
191 context.inc_pc();
192 void* _ptr = pop_memop_addr(op);
193 context.push_operand(i64_const_t{ static_cast<uint64_t>( read_unaligned<uint32_t>(_ptr) ) });
194 }
195 [[gnu::always_inline]] inline void operator()(const f32_load_t& op) {
196 context.inc_pc();
197 void* _ptr = pop_memop_addr(op);
198 context.push_operand(f32_const_t{ read_unaligned<uint32_t>(_ptr) });
199 }
200 [[gnu::always_inline]] inline void operator()(const f64_load_t& op) {
201 context.inc_pc();
202 void* _ptr = pop_memop_addr(op);
203 context.push_operand(f64_const_t{ read_unaligned<uint64_t>(_ptr) });
204 }
205 [[gnu::always_inline]] inline void operator()(const i32_store_t& op) {
206 context.inc_pc();
207 const auto& val = context.pop_operand();
208 void* store_loc = pop_memop_addr(op);
209 write_unaligned(store_loc, val.to_ui32());
210 }
211 [[gnu::always_inline]] inline void operator()(const i32_store8_t& op) {
212 context.inc_pc();
213 const auto& val = context.pop_operand();
214 void* store_loc = pop_memop_addr(op);
215 write_unaligned(store_loc, static_cast<uint8_t>(val.to_ui32()));
216 }
217 [[gnu::always_inline]] inline void operator()(const i32_store16_t& op) {
218 context.inc_pc();
219 const auto& val = context.pop_operand();
220 void* store_loc = pop_memop_addr(op);
221 write_unaligned(store_loc, static_cast<uint16_t>(val.to_ui32()));
222 }
223 [[gnu::always_inline]] inline void operator()(const i64_store_t& op) {
224 context.inc_pc();
225 const auto& val = context.pop_operand();
226 void* store_loc = pop_memop_addr(op);
227 write_unaligned(store_loc, static_cast<uint64_t>(val.to_ui64()));
228 }
229 [[gnu::always_inline]] inline void operator()(const i64_store8_t& op) {
230 context.inc_pc();
231 const auto& val = context.pop_operand();
232 void* store_loc = pop_memop_addr(op);
233 write_unaligned(store_loc, static_cast<uint8_t>(val.to_ui64()));
234 }
235 [[gnu::always_inline]] inline void operator()(const i64_store16_t& op) {
236 context.inc_pc();
237 const auto& val = context.pop_operand();
238 void* store_loc = pop_memop_addr(op);
239 write_unaligned(store_loc, static_cast<uint16_t>(val.to_ui64()));
240 }
241 [[gnu::always_inline]] inline void operator()(const i64_store32_t& op) {
242 context.inc_pc();
243 const auto& val = context.pop_operand();
244 void* store_loc = pop_memop_addr(op);
245 write_unaligned(store_loc, static_cast<uint32_t>(val.to_ui64()));
246 }
247 [[gnu::always_inline]] inline void operator()(const f32_store_t& op) {
248 context.inc_pc();
249 const auto& val = context.pop_operand();
250 void* store_loc = pop_memop_addr(op);
251 write_unaligned(store_loc, static_cast<uint32_t>(val.to_fui32()));
252 }
253 [[gnu::always_inline]] inline void operator()(const f64_store_t& op) {
254 context.inc_pc();
255 const auto& val = context.pop_operand();
256 void* store_loc = pop_memop_addr(op);
257 write_unaligned(store_loc, static_cast<uint64_t>(val.to_fui64()));
258 }
259 [[gnu::always_inline]] inline void operator()(const current_memory_t& op) {
260 context.inc_pc();
261 context.push_operand(i32_const_t{ context.current_linear_memory() });
262 }
263 [[gnu::always_inline]] inline void operator()(const grow_memory_t& op) {
264 context.inc_pc();
265 auto& oper = context.peek_operand().to_ui32();
266 oper = context.grow_linear_memory(oper);
267 }
268 [[gnu::always_inline]] inline void operator()(const i32_const_t& op) {
269 context.inc_pc();
270 context.push_operand(op);
271 }
272 [[gnu::always_inline]] inline void operator()(const i64_const_t& op) {
273 context.inc_pc();
274 context.push_operand(op);
275 }
276 [[gnu::always_inline]] inline void operator()(const f32_const_t& op) {
277 context.inc_pc();
278 context.push_operand(op);
279 }
280 [[gnu::always_inline]] inline void operator()(const f64_const_t& op) {
281 context.inc_pc();
282 context.push_operand(op);
283 }
284 [[gnu::always_inline]] inline void operator()(const i32_eqz_t& op) {
285 context.inc_pc();
286 auto& t = context.peek_operand().to_ui32();
287 t = t == 0;
288 }
289 [[gnu::always_inline]] inline void operator()(const i32_eq_t& op) {
290 context.inc_pc();
291 const auto& rhs = context.pop_operand().to_ui32();
292 auto& lhs = context.peek_operand().to_ui32();
293 lhs = lhs == rhs;
294 }
295 [[gnu::always_inline]] inline void operator()(const i32_ne_t& op) {
296 context.inc_pc();
297 const auto& rhs = context.pop_operand().to_ui32();
298 auto& lhs = context.peek_operand().to_ui32();
299 lhs = lhs != rhs;
300 }
301 [[gnu::always_inline]] inline void operator()(const i32_lt_s_t& op) {
302 context.inc_pc();
303 const auto& rhs = context.pop_operand().to_i32();
304 auto& lhs = context.peek_operand().to_i32();
305 lhs = lhs < rhs;
306 }
307 [[gnu::always_inline]] inline void operator()(const i32_lt_u_t& op) {
308 context.inc_pc();
309 const auto& rhs = context.pop_operand().to_ui32();
310 auto& lhs = context.peek_operand().to_ui32();
311 lhs = lhs < rhs;
312 }
313 [[gnu::always_inline]] inline void operator()(const i32_le_s_t& op) {
314 context.inc_pc();
315 const auto& rhs = context.pop_operand().to_i32();
316 auto& lhs = context.peek_operand().to_i32();
317 lhs = lhs <= rhs;
318 }
319 [[gnu::always_inline]] inline void operator()(const i32_le_u_t& op) {
320 context.inc_pc();
321 const auto& rhs = context.pop_operand().to_ui32();
322 auto& lhs = context.peek_operand().to_ui32();
323 lhs = lhs <= rhs;
324 }
325 [[gnu::always_inline]] inline void operator()(const i32_gt_s_t& op) {
326 context.inc_pc();
327 const auto& rhs = context.pop_operand().to_i32();
328 auto& lhs = context.peek_operand().to_i32();
329 lhs = lhs > rhs;
330 }
331 [[gnu::always_inline]] inline void operator()(const i32_gt_u_t& op) {
332 context.inc_pc();
333 const auto& rhs = context.pop_operand().to_ui32();
334 auto& lhs = context.peek_operand().to_ui32();
335 lhs = lhs > rhs;
336 }
337 [[gnu::always_inline]] inline void operator()(const i32_ge_s_t& op) {
338 context.inc_pc();
339 const auto& rhs = context.pop_operand().to_i32();
340 auto& lhs = context.peek_operand().to_i32();
341 lhs = lhs >= rhs;
342 }
343 [[gnu::always_inline]] inline void operator()(const i32_ge_u_t& op) {
344 context.inc_pc();
345 const auto& rhs = context.pop_operand().to_ui32();
346 auto& lhs = context.peek_operand().to_ui32();
347 lhs = lhs >= rhs;
348 }
349 [[gnu::always_inline]] inline void operator()(const i64_eqz_t& op) {
350 context.inc_pc();
351 auto& oper = context.peek_operand();
352 oper = i32_const_t{ oper.to_ui64() == 0 };
353 }
354 [[gnu::always_inline]] inline void operator()(const i64_eq_t& op) {
355 context.inc_pc();
356 const auto& rhs = context.pop_operand().to_ui64();
357 auto& lhs = context.peek_operand();
358 lhs = i32_const_t{ lhs.to_ui64() == rhs };
359 }
360 [[gnu::always_inline]] inline void operator()(const i64_ne_t& op) {
361 context.inc_pc();
362 const auto& rhs = context.pop_operand().to_ui64();
363 auto& lhs = context.peek_operand();
364 lhs = i32_const_t{ lhs.to_ui64() != rhs };
365 }
366 [[gnu::always_inline]] inline void operator()(const i64_lt_s_t& op) {
367 context.inc_pc();
368 const auto& rhs = context.pop_operand().to_i64();
369 auto& lhs = context.peek_operand();
370 lhs = i32_const_t{ lhs.to_i64() < rhs };
371 }
372 [[gnu::always_inline]] inline void operator()(const i64_lt_u_t& op) {
373 context.inc_pc();
374 const auto& rhs = context.pop_operand().to_ui64();
375 auto& lhs = context.peek_operand();
376 lhs = i32_const_t{ lhs.to_ui64() < rhs };
377 }
378 [[gnu::always_inline]] inline void operator()(const i64_le_s_t& op) {
379 context.inc_pc();
380 const auto& rhs = context.pop_operand().to_i64();
381 auto& lhs = context.peek_operand();
382 lhs = i32_const_t{ lhs.to_i64() <= rhs };
383 }
384 [[gnu::always_inline]] inline void operator()(const i64_le_u_t& op) {
385 context.inc_pc();
386 const auto& rhs = context.pop_operand().to_ui64();
387 auto& lhs = context.peek_operand();
388 lhs = i32_const_t{ lhs.to_ui64() <= rhs };
389 }
390 [[gnu::always_inline]] inline void operator()(const i64_gt_s_t& op) {
391 context.inc_pc();
392 const auto& rhs = context.pop_operand().to_i64();
393 auto& lhs = context.peek_operand();
394 lhs = i32_const_t{ lhs.to_i64() > rhs };
395 }
396 [[gnu::always_inline]] inline void operator()(const i64_gt_u_t& op) {
397 context.inc_pc();
398 const auto& rhs = context.pop_operand().to_ui64();
399 auto& lhs = context.peek_operand();
400 lhs = i32_const_t{ lhs.to_ui64() > rhs };
401 }
402 [[gnu::always_inline]] inline void operator()(const i64_ge_s_t& op) {
403 context.inc_pc();
404 const auto& rhs = context.pop_operand().to_i64();
405 auto& lhs = context.peek_operand();
406 lhs = i32_const_t{ lhs.to_i64() >= rhs };
407 }
408 [[gnu::always_inline]] inline void operator()(const i64_ge_u_t& op) {
409 context.inc_pc();
410 const auto& rhs = context.pop_operand().to_ui64();
411 auto& lhs = context.peek_operand();
412 lhs = i32_const_t{ lhs.to_ui64() >= rhs };
413 }
414 [[gnu::always_inline]] inline void operator()(const f32_eq_t& op) {
415 context.inc_pc();
416 const auto& rhs = context.pop_operand().to_f32();
417 auto& lhs = context.peek_operand();
418 if constexpr (use_softfloat)
419 lhs = i32_const_t{ (uint32_t)_sysio_f32_eq(lhs.to_f32(), rhs) };
420 else
421 lhs = i32_const_t{ (uint32_t)(lhs.to_f32() == rhs) };
422 }
423 [[gnu::always_inline]] inline void operator()(const f32_ne_t& op) {
424 context.inc_pc();
425 const auto& rhs = context.pop_operand().to_f32();
426 auto& lhs = context.peek_operand();
427 if constexpr (use_softfloat)
428 lhs = i32_const_t{ (uint32_t)_sysio_f32_ne(lhs.to_f32(), rhs) };
429 else
430 lhs = i32_const_t{ (uint32_t)(lhs.to_f32() != rhs) };
431 }
432 [[gnu::always_inline]] inline void operator()(const f32_lt_t& op) {
433 context.inc_pc();
434 const auto& rhs = context.pop_operand().to_f32();
435 auto& lhs = context.peek_operand();
436 if constexpr (use_softfloat)
437 lhs = i32_const_t{ (uint32_t)_sysio_f32_lt(lhs.to_f32(), rhs) };
438 else
439 lhs = i32_const_t{ (uint32_t)(lhs.to_f32() < rhs) };
440 }
441 [[gnu::always_inline]] inline void operator()(const f32_gt_t& op) {
442 context.inc_pc();
443 const auto& rhs = context.pop_operand().to_f32();
444 auto& lhs = context.peek_operand();
445 if constexpr (use_softfloat)
446 lhs = i32_const_t{ (uint32_t)_sysio_f32_gt(lhs.to_f32(), rhs) };
447 else
448 lhs = i32_const_t{ (uint32_t)(lhs.to_f32() > rhs) };
449 }
450 [[gnu::always_inline]] inline void operator()(const f32_le_t& op) {
451 context.inc_pc();
452 const auto& rhs = context.pop_operand().to_f32();
453 auto& lhs = context.peek_operand();
454 if constexpr (use_softfloat)
455 lhs = i32_const_t{ (uint32_t)_sysio_f32_le(lhs.to_f32(), rhs) };
456 else
457 lhs = i32_const_t{ (uint32_t)(lhs.to_f32() <= rhs) };
458 }
459 [[gnu::always_inline]] inline void operator()(const f32_ge_t& op) {
460 context.inc_pc();
461 const auto& rhs = context.pop_operand().to_f32();
462 auto& lhs = context.peek_operand();
463 if constexpr (use_softfloat)
464 lhs = i32_const_t{ (uint32_t)_sysio_f32_ge(lhs.to_f32(), rhs) };
465 else
466 lhs = i32_const_t{ (uint32_t)(lhs.to_f32() >= rhs) };
467 }
468 [[gnu::always_inline]] inline void operator()(const f64_eq_t& op) {
469 context.inc_pc();
470 const auto& rhs = context.pop_operand().to_f64();
471 auto& lhs = context.peek_operand();
472 if constexpr (use_softfloat)
473 lhs = i32_const_t{ (uint32_t)_sysio_f64_eq(lhs.to_f64(), rhs) };
474 else
475 lhs = i32_const_t{ (uint32_t)(lhs.to_f64() == rhs) };
476 }
477 [[gnu::always_inline]] inline void operator()(const f64_ne_t& op) {
478 context.inc_pc();
479 const auto& rhs = context.pop_operand().to_f64();
480 auto& lhs = context.peek_operand();
481 if constexpr (use_softfloat)
482 lhs = i32_const_t{ (uint32_t)_sysio_f64_ne(lhs.to_f64(), rhs) };
483 else
484 lhs = i32_const_t{ (uint32_t)(lhs.to_f64() != rhs) };
485 }
486 [[gnu::always_inline]] inline void operator()(const f64_lt_t& op) {
487 context.inc_pc();
488 const auto& rhs = context.pop_operand().to_f64();
489 auto& lhs = context.peek_operand();
490 if constexpr (use_softfloat)
491 lhs = i32_const_t{ (uint32_t)_sysio_f64_lt(lhs.to_f64(), rhs) };
492 else
493 lhs = i32_const_t{ (uint32_t)(lhs.to_f64() < rhs) };
494 }
495 [[gnu::always_inline]] inline void operator()(const f64_gt_t& op) {
496 context.inc_pc();
497 const auto& rhs = context.pop_operand().to_f64();
498 auto& lhs = context.peek_operand();
499 if constexpr (use_softfloat)
500 lhs = i32_const_t{ (uint32_t)_sysio_f64_gt(lhs.to_f64(), rhs) };
501 else
502 lhs = i32_const_t{ (uint32_t)(lhs.to_f64() > rhs) };
503 }
504 [[gnu::always_inline]] inline void operator()(const f64_le_t& op) {
505 context.inc_pc();
506 const auto& rhs = context.pop_operand().to_f64();
507 auto& lhs = context.peek_operand();
508 if constexpr (use_softfloat)
509 lhs = i32_const_t{ (uint32_t)_sysio_f64_le(lhs.to_f64(), rhs) };
510 else
511 lhs = i32_const_t{ (uint32_t)(lhs.to_f64() <= rhs) };
512 }
513 [[gnu::always_inline]] inline void operator()(const f64_ge_t& op) {
514 context.inc_pc();
515 const auto& rhs = context.pop_operand().to_f64();
516 auto& lhs = context.peek_operand();
517 if constexpr (use_softfloat)
518 lhs = i32_const_t{ (uint32_t)_sysio_f64_ge(lhs.to_f64(), rhs) };
519 else
520 lhs = i32_const_t{ (uint32_t)(lhs.to_f64() >= rhs) };
521 }
522 [[gnu::always_inline]] inline void operator()(const i32_clz_t& op) {
523 context.inc_pc();
524 auto& oper = context.peek_operand().to_ui32();
525 // __builtin_clz(0) is undefined
526 oper = oper == 0 ? 32 : __builtin_clz(oper);
527 }
528 [[gnu::always_inline]] inline void operator()(const i32_ctz_t& op) {
529 context.inc_pc();
530 auto& oper = context.peek_operand().to_ui32();
531
532 // __builtin_ctz(0) is undefined
533 oper = oper == 0 ? 32 : __builtin_ctz(oper);
534 }
535 [[gnu::always_inline]] inline void operator()(const i32_popcnt_t& op) {
536 context.inc_pc();
537 auto& oper = context.peek_operand().to_ui32();
538 oper = __builtin_popcount(oper);
539 }
540 [[gnu::always_inline]] inline void operator()(const i32_add_t& op) {
541 context.inc_pc();
542 const auto& rhs = context.pop_operand().to_ui32();
543 auto& lhs = context.peek_operand().to_ui32();
544 lhs += rhs;
545 }
546 [[gnu::always_inline]] inline void operator()(const i32_sub_t& op) {
547 context.inc_pc();
548 const auto& rhs = context.pop_operand().to_ui32();
549 auto& lhs = context.peek_operand().to_ui32();
550 lhs -= rhs;
551 }
552 [[gnu::always_inline]] inline void operator()(const i32_mul_t& op) {
553 context.inc_pc();
554 const auto& rhs = context.pop_operand().to_ui32();
555 auto& lhs = context.peek_operand().to_ui32();
556 lhs *= rhs;
557 }
558 [[gnu::always_inline]] inline void operator()(const i32_div_s_t& op) {
559 context.inc_pc();
560 const auto& rhs = context.pop_operand().to_i32();
561 auto& lhs = context.peek_operand().to_i32();
562 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception, "i32.div_s divide by zero");
563 SYS_VM_ASSERT(!(lhs == std::numeric_limits<int32_t>::min() && rhs == -1), wasm_interpreter_exception,
564 "i32.div_s traps when I32_MAX/-1");
565 lhs /= rhs;
566 }
567 [[gnu::always_inline]] inline void operator()(const i32_div_u_t& op) {
568 context.inc_pc();
569 const auto& rhs = context.pop_operand().to_ui32();
570 auto& lhs = context.peek_operand().to_ui32();
571 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception, "i32.div_u divide by zero");
572 lhs /= rhs;
573 }
574 [[gnu::always_inline]] inline void operator()(const i32_rem_s_t& op) {
575 context.inc_pc();
576 const auto& rhs = context.pop_operand().to_i32();
577 auto& lhs = context.peek_operand().to_i32();
578 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception, "i32.rem_s divide by zero");
579 if (UNLIKELY(lhs == std::numeric_limits<int32_t>::min() && rhs == -1))
580 lhs = 0;
581 else
582 lhs %= rhs;
583 }
584 [[gnu::always_inline]] inline void operator()(const i32_rem_u_t& op) {
585 context.inc_pc();
586 const auto& rhs = context.pop_operand().to_ui32();
587 auto& lhs = context.peek_operand().to_ui32();
588 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception, "i32.rem_u divide by zero");
589 lhs %= rhs;
590 }
591 [[gnu::always_inline]] inline void operator()(const i32_and_t& op) {
592 context.inc_pc();
593 const auto& rhs = context.pop_operand().to_ui32();
594 auto& lhs = context.peek_operand().to_ui32();
595 lhs &= rhs;
596 }
597 [[gnu::always_inline]] inline void operator()(const i32_or_t& op) {
598 context.inc_pc();
599 const auto& rhs = context.pop_operand().to_ui32();
600 auto& lhs = context.peek_operand().to_ui32();
601 lhs |= rhs;
602 }
603 [[gnu::always_inline]] inline void operator()(const i32_xor_t& op) {
604 context.inc_pc();
605 const auto& rhs = context.pop_operand().to_ui32();
606 auto& lhs = context.peek_operand().to_ui32();
607 lhs ^= rhs;
608 }
609 [[gnu::always_inline]] inline void operator()(const i32_shl_t& op) {
610 context.inc_pc();
611 static constexpr uint32_t mask = (8 * sizeof(uint32_t) - 1);
612 const auto& rhs = context.pop_operand().to_ui32();
613 auto& lhs = context.peek_operand().to_ui32();
614 lhs <<= (rhs & mask);
615 }
616 [[gnu::always_inline]] inline void operator()(const i32_shr_s_t& op) {
617 context.inc_pc();
618 static constexpr uint32_t mask = (8 * sizeof(uint32_t) - 1);
619 const auto& rhs = context.pop_operand().to_ui32();
620 auto& lhs = context.peek_operand().to_i32();
621 lhs >>= (rhs & mask);
622 }
623 [[gnu::always_inline]] inline void operator()(const i32_shr_u_t& op) {
624 context.inc_pc();
625 static constexpr uint32_t mask = (8 * sizeof(uint32_t) - 1);
626 const auto& rhs = context.pop_operand().to_ui32();
627 auto& lhs = context.peek_operand().to_ui32();
628 lhs >>= (rhs & mask);
629 }
630 [[gnu::always_inline]] inline void operator()(const i32_rotl_t& op) {
631
632 context.inc_pc();
633 static constexpr uint32_t mask = (8 * sizeof(uint32_t) - 1);
634 const auto& rhs = context.pop_operand().to_ui32();
635 auto& lhs = context.peek_operand().to_ui32();
636 uint32_t c = rhs;
637 c &= mask;
638 lhs = (lhs << c) | (lhs >> ((-c) & mask));
639 }
640 [[gnu::always_inline]] inline void operator()(const i32_rotr_t& op) {
641 context.inc_pc();
642 static constexpr uint32_t mask = (8 * sizeof(uint32_t) - 1);
643 const auto& rhs = context.pop_operand().to_ui32();
644 auto& lhs = context.peek_operand().to_ui32();
645 uint32_t c = rhs;
646 c &= mask;
647 lhs = (lhs >> c) | (lhs << ((-c) & mask));
648 }
649 [[gnu::always_inline]] inline void operator()(const i64_clz_t& op) {
650 context.inc_pc();
651 auto& oper = context.peek_operand().to_ui64();
652 // __builtin_clzll(0) is undefined
653 oper = oper == 0 ? 64 : __builtin_clzll(oper);
654 }
655 [[gnu::always_inline]] inline void operator()(const i64_ctz_t& op) {
656 context.inc_pc();
657 auto& oper = context.peek_operand().to_ui64();
658 // __builtin_clzll(0) is undefined
659 oper = oper == 0 ? 64 : __builtin_ctzll(oper);
660 }
661 [[gnu::always_inline]] inline void operator()(const i64_popcnt_t& op) {
662 context.inc_pc();
663 auto& oper = context.peek_operand().to_ui64();
664 oper = __builtin_popcountll(oper);
665 }
666 [[gnu::always_inline]] inline void operator()(const i64_add_t& op) {
667 context.inc_pc();
668 const auto& rhs = context.pop_operand().to_ui64();
669 auto& lhs = context.peek_operand().to_ui64();
670 lhs += rhs;
671 }
672 [[gnu::always_inline]] inline void operator()(const i64_sub_t& op) {
673 context.inc_pc();
674 const auto& rhs = context.pop_operand().to_ui64();
675 auto& lhs = context.peek_operand().to_ui64();
676 lhs -= rhs;
677 }
678 [[gnu::always_inline]] inline void operator()(const i64_mul_t& op) {
679 context.inc_pc();
680 const auto& rhs = context.pop_operand().to_ui64();
681 auto& lhs = context.peek_operand().to_ui64();
682 lhs *= rhs;
683 }
684 [[gnu::always_inline]] inline void operator()(const i64_div_s_t& op) {
685 context.inc_pc();
686 const auto& rhs = context.pop_operand().to_i64();
687 auto& lhs = context.peek_operand().to_i64();
688 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception, "i64.div_s divide by zero");
689 SYS_VM_ASSERT(!(lhs == std::numeric_limits<int64_t>::min() && rhs == -1), wasm_interpreter_exception,
690 "i64.div_s traps when I64_MAX/-1");
691 lhs /= rhs;
692 }
693 [[gnu::always_inline]] inline void operator()(const i64_div_u_t& op) {
694 context.inc_pc();
695 const auto& rhs = context.pop_operand().to_ui64();
696 auto& lhs = context.peek_operand().to_ui64();
697 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception, "i64.div_u divide by zero");
698 lhs /= rhs;
699 }
700 [[gnu::always_inline]] inline void operator()(const i64_rem_s_t& op) {
701 context.inc_pc();
702 const auto& rhs = context.pop_operand().to_i64();
703 auto& lhs = context.peek_operand().to_i64();
704 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception, "i64.rem_s divide by zero");
705 if (UNLIKELY(lhs == std::numeric_limits<int64_t>::min() && rhs == -1))
706 lhs = 0;
707 else
708 lhs %= rhs;
709 }
710 [[gnu::always_inline]] inline void operator()(const i64_rem_u_t& op) {
711 context.inc_pc();
712 const auto& rhs = context.pop_operand().to_ui64();
713 auto& lhs = context.peek_operand().to_ui64();
714 SYS_VM_ASSERT(rhs != 0, wasm_interpreter_exception, "i64.rem_s divide by zero");
715 lhs %= rhs;
716 }
717 [[gnu::always_inline]] inline void operator()(const i64_and_t& op) {
718 context.inc_pc();
719 const auto& rhs = context.pop_operand().to_ui64();
720 auto& lhs = context.peek_operand().to_ui64();
721 lhs &= rhs;
722 }
723 [[gnu::always_inline]] inline void operator()(const i64_or_t& op) {
724 context.inc_pc();
725 const auto& rhs = context.pop_operand().to_ui64();
726 auto& lhs = context.peek_operand().to_ui64();
727 lhs |= rhs;
728 }
729 [[gnu::always_inline]] inline void operator()(const i64_xor_t& op) {
730 context.inc_pc();
731 const auto& rhs = context.pop_operand().to_ui64();
732 auto& lhs = context.peek_operand().to_ui64();
733 lhs ^= rhs;
734 }
735 [[gnu::always_inline]] inline void operator()(const i64_shl_t& op) {
736 context.inc_pc();
737 static constexpr uint64_t mask = (8 * sizeof(uint64_t) - 1);
738 const auto& rhs = context.pop_operand().to_ui64();
739 auto& lhs = context.peek_operand().to_ui64();
740 lhs <<= (rhs & mask);
741 }
742 [[gnu::always_inline]] inline void operator()(const i64_shr_s_t& op) {
743 context.inc_pc();
744 static constexpr uint64_t mask = (8 * sizeof(uint64_t) - 1);
745 const auto& rhs = context.pop_operand().to_ui64();
746 auto& lhs = context.peek_operand().to_i64();
747 lhs >>= (rhs & mask);
748 }
749 [[gnu::always_inline]] inline void operator()(const i64_shr_u_t& op) {
750 context.inc_pc();
751 static constexpr uint64_t mask = (8 * sizeof(uint64_t) - 1);
752 const auto& rhs = context.pop_operand().to_ui64();
753 auto& lhs = context.peek_operand().to_ui64();
754 lhs >>= (rhs & mask);
755 }
756 [[gnu::always_inline]] inline void operator()(const i64_rotl_t& op) {
757 context.inc_pc();
758 static constexpr uint64_t mask = (8 * sizeof(uint64_t) - 1);
759 const auto& rhs = context.pop_operand().to_ui64();
760 auto& lhs = context.peek_operand().to_ui64();
761 uint32_t c = rhs;
762 c &= mask;
763 lhs = (lhs << c) | (lhs >> (-c & mask));
764 }
765 [[gnu::always_inline]] inline void operator()(const i64_rotr_t& op) {
766 context.inc_pc();
767 static constexpr uint64_t mask = (8 * sizeof(uint64_t) - 1);
768 const auto& rhs = context.pop_operand().to_ui64();
769 auto& lhs = context.peek_operand().to_ui64();
770 uint32_t c = rhs;
771 c &= mask;
772 lhs = (lhs >> c) | (lhs << (-c & mask));
773 }
774 [[gnu::always_inline]] inline void operator()(const f32_abs_t& op) {
775 context.inc_pc();
776 auto& oper = context.peek_operand().to_f32();
777 if constexpr (use_softfloat)
778 oper = _sysio_f32_abs(oper);
779 else
780 oper = __builtin_fabsf(oper);
781 }
782 [[gnu::always_inline]] inline void operator()(const f32_neg_t& op) {
783 context.inc_pc();
784 auto& oper = context.peek_operand().to_f32();
785 if constexpr (use_softfloat)
786 oper = _sysio_f32_neg(oper);
787 else
788 oper = -oper;
789 }
790 [[gnu::always_inline]] inline void operator()(const f32_ceil_t& op) {
791 context.inc_pc();
792 auto& oper = context.peek_operand().to_f32();
793 if constexpr (use_softfloat)
794 oper = _sysio_f32_ceil(oper);
795 else
796 oper = __builtin_ceilf(oper);
797 }
798 [[gnu::always_inline]] inline void operator()(const f32_floor_t& op) {
799 context.inc_pc();
800 auto& oper = context.peek_operand().to_f32();
801 if constexpr (use_softfloat)
802 oper = _sysio_f32_floor(oper);
803 else
804 oper = __builtin_floorf(oper);
805 }
806 [[gnu::always_inline]] inline void operator()(const f32_trunc_t& op) {
807 context.inc_pc();
808 auto& oper = context.peek_operand().to_f32();
809 if constexpr (use_softfloat)
810 oper = _sysio_f32_trunc(oper);
811 else
812 oper = __builtin_trunc(oper);
813 }
814 [[gnu::always_inline]] inline void operator()(const f32_nearest_t& op) {
815 context.inc_pc();
816 auto& oper = context.peek_operand().to_f32();
817 if constexpr (use_softfloat)
818 oper = _sysio_f32_nearest(oper);
819 else
820 oper = __builtin_nearbyintf(oper);
821 }
822 [[gnu::always_inline]] inline void operator()(const f32_sqrt_t& op) {
823 context.inc_pc();
824 auto& oper = context.peek_operand().to_f32();
825 if constexpr (use_softfloat)
826 oper = _sysio_f32_sqrt(oper);
827 else
828 oper = __builtin_sqrtf(oper);
829 }
830 [[gnu::always_inline]] inline void operator()(const f32_add_t& op) {
831 context.inc_pc();
832 const auto& rhs = context.pop_operand();
833 auto& lhs = context.peek_operand().to_f32();
834 if constexpr (use_softfloat)
835 lhs = _sysio_f32_add(lhs, rhs.to_f32());
836 else
837 lhs += rhs.to_f32();
838 }
839 [[gnu::always_inline]] inline void operator()(const f32_sub_t& op) {
840 context.inc_pc();
841 const auto& rhs = context.pop_operand();
842 auto& lhs = context.peek_operand().to_f32();
843 if constexpr (use_softfloat)
844 lhs = _sysio_f32_sub(lhs, rhs.to_f32());
845 else
846 lhs -= rhs.to_f32();
847 }
848 [[gnu::always_inline]] inline void operator()(const f32_mul_t& op) {
849 context.inc_pc();
850 const auto& rhs = context.pop_operand();
851 auto& lhs = context.peek_operand().to_f32();
852 if constexpr (use_softfloat) {
853 lhs = _sysio_f32_mul(lhs, rhs.to_f32());
854 } else
855 lhs *= rhs.to_f32();
856 }
857 [[gnu::always_inline]] inline void operator()(const f32_div_t& op) {
858 context.inc_pc();
859 const auto& rhs = context.pop_operand();
860 auto& lhs = context.peek_operand().to_f32();
861 if constexpr (use_softfloat)
862 lhs = _sysio_f32_div(lhs, rhs.to_f32());
863 else
864 lhs /= rhs.to_f32();
865 }
866 [[gnu::always_inline]] inline void operator()(const f32_min_t& op) {
867 context.inc_pc();
868 const auto& rhs = context.pop_operand();
869 auto& lhs = context.peek_operand().to_f32();
870 if constexpr (use_softfloat)
871 lhs = _sysio_f32_min(lhs, rhs.to_f32());
872 else
873 lhs = __builtin_fminf(lhs, rhs.to_f32());
874 }
875 [[gnu::always_inline]] inline void operator()(const f32_max_t& op) {
876 context.inc_pc();
877 const auto& rhs = context.pop_operand();
878 auto& lhs = context.peek_operand().to_f32();
879 if constexpr (use_softfloat)
880 lhs = _sysio_f32_max(lhs, rhs.to_f32());
881 else
882 lhs = __builtin_fmaxf(lhs, rhs.to_f32());
883 }
884 [[gnu::always_inline]] inline void operator()(const f32_copysign_t& op) {
885 context.inc_pc();
886 const auto& rhs = context.pop_operand();
887 auto& lhs = context.peek_operand().to_f32();
888 if constexpr (use_softfloat)
889 lhs = _sysio_f32_copysign(lhs, rhs.to_f32());
890 else
891 lhs = __builtin_copysignf(lhs, rhs.to_f32());
892 }
893 [[gnu::always_inline]] inline void operator()(const f64_abs_t& op) {
894 context.inc_pc();
895 auto& oper = context.peek_operand().to_f64();
896 if constexpr (use_softfloat)
897 oper = _sysio_f64_abs(oper);
898 else
899 oper = __builtin_fabs(oper);
900 }
901 [[gnu::always_inline]] inline void operator()(const f64_neg_t& op) {
902 context.inc_pc();
903 auto& oper = context.peek_operand().to_f64();
904 if constexpr (use_softfloat)
905 oper = _sysio_f64_neg(oper);
906 else
907 oper = -oper;
908 }
909 [[gnu::always_inline]] inline void operator()(const f64_ceil_t& op) {
910
911 context.inc_pc();
912 auto& oper = context.peek_operand().to_f64();
913 if constexpr (use_softfloat)
914 oper = _sysio_f64_ceil(oper);
915 else
916 oper = __builtin_ceil(oper);
917 }
918 [[gnu::always_inline]] inline void operator()(const f64_floor_t& op) {
919 context.inc_pc();
920 auto& oper = context.peek_operand().to_f64();
921 if constexpr (use_softfloat)
922 oper = _sysio_f64_floor(oper);
923 else
924 oper = __builtin_floor(oper);
925 }
926 [[gnu::always_inline]] inline void operator()(const f64_trunc_t& op) {
927 context.inc_pc();
928 auto& oper = context.peek_operand().to_f64();
929 if constexpr (use_softfloat)
930 oper = _sysio_f64_trunc(oper);
931 else
932 oper = __builtin_trunc(oper);
933 }
934 [[gnu::always_inline]] inline void operator()(const f64_nearest_t& op) {
935 context.inc_pc();
936 auto& oper = context.peek_operand().to_f64();
937 if constexpr (use_softfloat)
938 oper = _sysio_f64_nearest(oper);
939 else
940 oper = __builtin_nearbyint(oper);
941 }
942 [[gnu::always_inline]] inline void operator()(const f64_sqrt_t& op) {
943 context.inc_pc();
944 auto& oper = context.peek_operand().to_f64();
945 if constexpr (use_softfloat)
946 oper = _sysio_f64_sqrt(oper);
947 else
948 oper = __builtin_sqrt(oper);
949 }
950 [[gnu::always_inline]] inline void operator()(const f64_add_t& op) {
951 context.inc_pc();
952 const auto& rhs = context.pop_operand();
953 auto& lhs = context.peek_operand().to_f64();
954 if constexpr (use_softfloat)
955 lhs = _sysio_f64_add(lhs, rhs.to_f64());
956 else
957 lhs += rhs.to_f64();
958 }
959 [[gnu::always_inline]] inline void operator()(const f64_sub_t& op) {
960 context.inc_pc();
961 const auto& rhs = context.pop_operand();
962 auto& lhs = context.peek_operand().to_f64();
963 if constexpr (use_softfloat)
964 lhs = _sysio_f64_sub(lhs, rhs.to_f64());
965 else
966 lhs -= rhs.to_f64();
967 }
968 [[gnu::always_inline]] inline void operator()(const f64_mul_t& op) {
969 context.inc_pc();
970 const auto& rhs = context.pop_operand();
971 auto& lhs = context.peek_operand().to_f64();
972 if constexpr (use_softfloat)
973 lhs = _sysio_f64_mul(lhs, rhs.to_f64());
974 else
975 lhs *= rhs.to_f64();
976 }
977 [[gnu::always_inline]] inline void operator()(const f64_div_t& op) {
978 context.inc_pc();
979 const auto& rhs = context.pop_operand();
980 auto& lhs = context.peek_operand().to_f64();
981 if constexpr (use_softfloat)
982 lhs = _sysio_f64_div(lhs, rhs.to_f64());
983 else
984 lhs /= rhs.to_f64();
985 }
986 [[gnu::always_inline]] inline void operator()(const f64_min_t& op) {
987 context.inc_pc();
988 const auto& rhs = context.pop_operand();
989 auto& lhs = context.peek_operand().to_f64();
990 if constexpr (use_softfloat)
991 lhs = _sysio_f64_min(lhs, rhs.to_f64());
992 else
993 lhs = __builtin_fmin(lhs, rhs.to_f64());
994 }
995 [[gnu::always_inline]] inline void operator()(const f64_max_t& op) {
996 context.inc_pc();
997 const auto& rhs = context.pop_operand();
998 auto& lhs = context.peek_operand().to_f64();
999 if constexpr (use_softfloat)
1000 lhs = _sysio_f64_max(lhs, rhs.to_f64());
1001 else
1002 lhs = __builtin_fmax(lhs, rhs.to_f64());
1003 }
1004 [[gnu::always_inline]] inline void operator()(const f64_copysign_t& op) {
1005 context.inc_pc();
1006 const auto& rhs = context.pop_operand();
1007 auto& lhs = context.peek_operand().to_f64();
1008 if constexpr (use_softfloat)
1009 lhs = _sysio_f64_copysign(lhs, rhs.to_f64());
1010 else
1011 lhs = __builtin_copysign(lhs, rhs.to_f64());
1012 }
1013 [[gnu::always_inline]] inline void operator()(const i32_wrap_i64_t& op) {
1014 context.inc_pc();
1015 auto& oper = context.peek_operand();
1016 oper = i32_const_t{ static_cast<int32_t>(oper.to_i64()) };
1017 }
1018 [[gnu::always_inline]] inline void operator()(const i32_trunc_s_f32_t& op) {
1019 context.inc_pc();
1020 auto& oper = context.peek_operand();
1021 if constexpr (use_softfloat) {
1022 oper = i32_const_t{ _sysio_f32_trunc_i32s(oper.to_f32()) };
1023 } else {
1024 float af = oper.to_f32();
1025 SYS_VM_ASSERT(!((af >= 2147483648.0f) || (af < -2147483648.0f)), wasm_interpreter_exception, "Error, f32.trunc_s/i32 overflow" );
1026 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception, "Error, f32.trunc_s/i32 unrepresentable");
1027 oper = i32_const_t{ static_cast<int32_t>(af) };
1028 }
1029 }
1030 [[gnu::always_inline]] inline void operator()(const i32_trunc_u_f32_t& op) {
1031 context.inc_pc();
1032 auto& oper = context.peek_operand();
1033 if constexpr (use_softfloat) {
1034 oper = i32_const_t{ _sysio_f32_trunc_i32u(oper.to_f32()) };
1035 } else {
1036 float af = oper.to_f32();
1037 SYS_VM_ASSERT(!((af >= 4294967296.0f) || (af <= -1.0f)),wasm_interpreter_exception, "Error, f32.trunc_u/i32 overflow");
1038 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception, "Error, f32.trunc_u/i32 unrepresentable");
1039 oper = i32_const_t{ static_cast<uint32_t>(af) };
1040 }
1041 }
1042 [[gnu::always_inline]] inline void operator()(const i32_trunc_s_f64_t& op) {
1043 context.inc_pc();
1044 auto& oper = context.peek_operand();
1045 if constexpr (use_softfloat) {
1046 oper = i32_const_t{ _sysio_f64_trunc_i32s(oper.to_f64()) };
1047 } else {
1048 double af = oper.to_f64();
1049 SYS_VM_ASSERT(!((af >= 2147483648.0) || (af < -2147483648.0)), wasm_interpreter_exception, "Error, f64.trunc_s/i32 overflow");
1050 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception, "Error, f64.trunc_s/i32 unrepresentable");
1051 oper = i32_const_t{ static_cast<int32_t>(af) };
1052 }
1053 }
1054 [[gnu::always_inline]] inline void operator()(const i32_trunc_u_f64_t& op) {
1055 context.inc_pc();
1056 auto& oper = context.peek_operand();
1057 if constexpr (use_softfloat) {
1058 oper = i32_const_t{ _sysio_f64_trunc_i32u(oper.to_f64()) };
1059 } else {
1060 double af = oper.to_f64();
1061 SYS_VM_ASSERT(!((af >= 4294967296.0) || (af <= -1.0)), wasm_interpreter_exception, "Error, f64.trunc_u/i32 overflow");
1062 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception, "Error, f64.trunc_u/i32 unrepresentable");
1063 oper = i32_const_t{ static_cast<uint32_t>(af) };
1064 }
1065 }
1066 [[gnu::always_inline]] inline void operator()(const i64_extend_s_i32_t& op) {
1067 context.inc_pc();
1068 auto& oper = context.peek_operand();
1069 oper = i64_const_t{ static_cast<int64_t>(oper.to_i32()) };
1070 }
1071 [[gnu::always_inline]] inline void operator()(const i64_extend_u_i32_t& op) {
1072 context.inc_pc();
1073 auto& oper = context.peek_operand();
1074 oper = i64_const_t{ static_cast<uint64_t>(oper.to_ui32()) };
1075 }
1076 [[gnu::always_inline]] inline void operator()(const i64_trunc_s_f32_t& op) {
1077 context.inc_pc();
1078 auto& oper = context.peek_operand();
1079 if constexpr (use_softfloat) {
1080 oper = i64_const_t{ _sysio_f32_trunc_i64s(oper.to_f32()) };
1081 } else {
1082 float af = oper.to_f32();
1083 SYS_VM_ASSERT(!((af >= 9223372036854775808.0f) || (af < -9223372036854775808.0f)), wasm_interpreter_exception, "Error, f32.trunc_s/i64 overflow");
1084 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception, "Error, f32.trunc_s/i64 unrepresentable");
1085 oper = i64_const_t{ static_cast<int64_t>(af) };
1086 }
1087 }
1088 [[gnu::always_inline]] inline void operator()(const i64_trunc_u_f32_t& op) {
1089 context.inc_pc();
1090 auto& oper = context.peek_operand();
1091 if constexpr (use_softfloat) {
1092 oper = i64_const_t{ _sysio_f32_trunc_i64u(oper.to_f32()) };
1093 } else {
1094 float af = oper.to_f32();
1095 SYS_VM_ASSERT(!((af >= 18446744073709551616.0f) || (af <= -1.0f)), wasm_interpreter_exception, "Error, f32.trunc_u/i64 overflow");
1096 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception, "Error, f32.trunc_u/i64 unrepresentable");
1097 oper = i64_const_t{ static_cast<uint64_t>(af) };
1098 }
1099 }
1100 [[gnu::always_inline]] inline void operator()(const i64_trunc_s_f64_t& op) {
1101 context.inc_pc();
1102 auto& oper = context.peek_operand();
1103 if constexpr (use_softfloat) {
1104 oper = i64_const_t{ _sysio_f64_trunc_i64s(oper.to_f64()) };
1105 } else {
1106 double af = oper.to_f64();
1107 SYS_VM_ASSERT(!((af >= 9223372036854775808.0) || (af < -9223372036854775808.0)), wasm_interpreter_exception, "Error, f64.trunc_s/i64 overflow");
1108 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception, "Error, f64.trunc_s/i64 unrepresentable");
1109 oper = i64_const_t{ static_cast<int64_t>(af) };
1110 }
1111 }
1112 [[gnu::always_inline]] inline void operator()(const i64_trunc_u_f64_t& op) {
1113 context.inc_pc();
1114 auto& oper = context.peek_operand();
1115 if constexpr (use_softfloat) {
1116 oper = i64_const_t{ _sysio_f64_trunc_i64u(oper.to_f64()) };
1117 } else {
1118 double af = oper.to_f64();
1119 SYS_VM_ASSERT(!((af >= 18446744073709551616.0) || (af <= -1.0)), wasm_interpreter_exception, "Error, f64.trunc_u/i64 overflow");
1120 SYS_VM_ASSERT(!__builtin_isnan(af), wasm_interpreter_exception, "Error, f64.trunc_u/i64 unrepresentable");
1121 oper = i64_const_t{ static_cast<uint64_t>(af) };
1122 }
1123 }
1124 [[gnu::always_inline]] inline void operator()(const f32_convert_s_i32_t& op) {
1125 context.inc_pc();
1126 auto& oper = context.peek_operand();
1127 if constexpr (use_softfloat) {
1128 oper = f32_const_t{ _sysio_i32_to_f32(oper.to_i32()) };
1129 } else {
1130 oper = f32_const_t{ static_cast<float>(oper.to_i32()) };
1131 }
1132 }
1133 [[gnu::always_inline]] inline void operator()(const f32_convert_u_i32_t& op) {
1134 context.inc_pc();
1135 auto& oper = context.peek_operand();
1136 if constexpr (use_softfloat) {
1137 oper = f32_const_t{ _sysio_ui32_to_f32(oper.to_ui32()) };
1138 } else {
1139 oper = f32_const_t{ static_cast<float>(oper.to_ui32()) };
1140 }
1141 }
1142 [[gnu::always_inline]] inline void operator()(const f32_convert_s_i64_t& op) {
1143 context.inc_pc();
1144 auto& oper = context.peek_operand();
1145 if constexpr (use_softfloat) {
1146 oper = f32_const_t{ _sysio_i64_to_f32(oper.to_i64()) };
1147 } else {
1148 oper = f32_const_t{ static_cast<float>(oper.to_i64()) };
1149 }
1150 }
1151 [[gnu::always_inline]] inline void operator()(const f32_convert_u_i64_t& op) {
1152 context.inc_pc();
1153 auto& oper = context.peek_operand();
1154 if constexpr (use_softfloat) {
1155 oper = f32_const_t{ _sysio_ui64_to_f32(oper.to_ui64()) };
1156 } else {
1157 oper = f32_const_t{ static_cast<float>(oper.to_ui64()) };
1158 }
1159 }
1160 [[gnu::always_inline]] inline void operator()(const f32_demote_f64_t& op) {
1161 context.inc_pc();
1162 auto& oper = context.peek_operand();
1163 if constexpr (use_softfloat) {
1164 oper = f32_const_t{ _sysio_f64_demote(oper.to_f64()) };
1165 } else {
1166 oper = f32_const_t{ static_cast<float>(oper.to_f64()) };
1167 }
1168 }
1169 [[gnu::always_inline]] inline void operator()(const f64_convert_s_i32_t& op) {
1170 context.inc_pc();
1171 auto& oper = context.peek_operand();
1172 if constexpr (use_softfloat) {
1173 oper = f64_const_t{ _sysio_i32_to_f64(oper.to_i32()) };
1174 } else {
1175 oper = f64_const_t{ static_cast<double>(oper.to_i32()) };
1176 }
1177 }
1178 [[gnu::always_inline]] inline void operator()(const f64_convert_u_i32_t& op) {
1179 context.inc_pc();
1180 auto& oper = context.peek_operand();
1181 if constexpr (use_softfloat) {
1182 oper = f64_const_t{ _sysio_ui32_to_f64(oper.to_ui32()) };
1183 } else {
1184 oper = f64_const_t{ static_cast<double>(oper.to_ui32()) };
1185 }
1186 }
1187 [[gnu::always_inline]] inline void operator()(const f64_convert_s_i64_t& op) {
1188 context.inc_pc();
1189 auto& oper = context.peek_operand();
1190 if constexpr (use_softfloat) {
1191 oper = f64_const_t{ _sysio_i64_to_f64(oper.to_i64()) };
1192 } else {
1193 oper = f64_const_t{ static_cast<double>(oper.to_i64()) };
1194 }
1195 }
1196 [[gnu::always_inline]] inline void operator()(const f64_convert_u_i64_t& op) {
1197 context.inc_pc();
1198 auto& oper = context.peek_operand();
1199 if constexpr (use_softfloat) {
1200 oper = f64_const_t{ _sysio_ui64_to_f64(oper.to_ui64()) };
1201 } else {
1202 oper = f64_const_t{ static_cast<double>(oper.to_ui64()) };
1203 }
1204 }
1205 [[gnu::always_inline]] inline void operator()(const f64_promote_f32_t& op) {
1206 context.inc_pc();
1207 auto& oper = context.peek_operand();
1208 if constexpr (use_softfloat) {
1209 oper = f64_const_t{ _sysio_f32_promote(oper.to_f32()) };
1210 } else {
1211 oper = f64_const_t{ static_cast<double>(oper.to_f32()) };
1212 }
1213 }
1214 [[gnu::always_inline]] inline void operator()(const i32_reinterpret_f32_t& op) {
1215 context.inc_pc();
1216 auto& oper = context.peek_operand();
1217 oper = i32_const_t{ oper.to_fui32() };
1218 }
1219 [[gnu::always_inline]] inline void operator()(const i64_reinterpret_f64_t& op) {
1220 context.inc_pc();
1221 auto& oper = context.peek_operand();
1222 oper = i64_const_t{ oper.to_fui64() };
1223 }
1224 [[gnu::always_inline]] inline void operator()(const f32_reinterpret_i32_t& op) {
1225 context.inc_pc();
1226 auto& oper = context.peek_operand();
1227 oper = f32_const_t{ oper.to_ui32() };
1228 }
1229 [[gnu::always_inline]] inline void operator()(const f64_reinterpret_i64_t& op) {
1230 context.inc_pc();
1231 auto& oper = context.peek_operand();
1232 oper = f64_const_t{ oper.to_ui64() };
1233 }
1234 };
1235
1236}} // namespace sysio::vm
#define UNLIKELY(x)
constexpr bool should_align_memory_ops
Definition config.hpp:9
constexpr bool use_softfloat
Definition config.hpp:16
#define value
Definition pkcs11.h:157
#define T(meth, val, expected)
unsigned short uint16_t
Definition stdint.h:125
_W64 unsigned int uintptr_t
Definition stdint.h:165
signed __int64 int64_t
Definition stdint.h:135
unsigned int uint32_t
Definition stdint.h:126
signed int int32_t
Definition stdint.h:123
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
void operator()(const f64_ne_t &op)
void operator()(const i32_gt_u_t &op)
void operator()(const f32_trunc_t &op)
void operator()(const i64_reinterpret_f64_t &op)
void operator()(const f32_copysign_t &op)
void operator()(const i64_ge_u_t &op)
void operator()(const call_t &op)
void operator()(const f64_load_t &op)
void operator()(const i64_rem_s_t &op)
void operator()(const f32_eq_t &op)
void operator()(const i64_extend_u_i32_t &op)
void operator()(const nop_t &op)
void operator()(const i32_eqz_t &op)
void operator()(const i64_trunc_u_f32_t &op)
void operator()(const f32_store_t &op)
void operator()(const i32_load8_s_t &op)
void operator()(const i32_const_t &op)
void operator()(const i32_load16_u_t &op)
void operator()(const i64_eqz_t &op)
void operator()(const loop_t &op)
void operator()(const end_t &op)
void operator()(const i64_load16_s_t &op)
void operator()(const f64_div_t &op)
void operator()(const i64_load32_s_t &op)
void operator()(const f64_trunc_t &op)
void operator()(const i64_load32_u_t &op)
void operator()(const f64_abs_t &op)
void operator()(const f32_ne_t &op)
void operator()(const i64_xor_t &op)
void operator()(const i64_load16_u_t &op)
void operator()(const i64_popcnt_t &op)
interpret_visitor(ExecutionContext &ec)
void operator()(const f64_max_t &op)
void operator()(const f64_add_t &op)
void operator()(const i32_store_t &op)
void operator()(const i64_const_t &op)
void operator()(const i64_store_t &op)
void operator()(const i64_div_u_t &op)
static constexpr void * align_address(void *addr, size_t align_amt)
void operator()(const f64_nearest_t &op)
void operator()(const current_memory_t &op)
void operator()(const i32_trunc_s_f64_t &op)
void operator()(const i32_ge_s_t &op)
void operator()(const br_table_t &op)
void operator()(const else_t &op)
void operator()(const i64_shl_t &op)
void operator()(const i64_rotr_t &op)
void operator()(const f32_div_t &op)
void operator()(const i32_wrap_i64_t &op)
void operator()(const i64_gt_u_t &op)
void operator()(const f64_lt_t &op)
void operator()(const i64_le_s_t &op)
void operator()(const tee_local_t &op)
void operator()(const f64_eq_t &op)
void operator()(const i32_load8_u_t &op)
void operator()(const grow_memory_t &op)
void operator()(const f32_max_t &op)
void operator()(const i64_eq_t &op)
void operator()(const f64_promote_f32_t &op)
void operator()(const f32_demote_f64_t &op)
void operator()(const i32_or_t &op)
static T read_unaligned(const void *addr)
void operator()(const i32_div_u_t &op)
static void write_unaligned(void *addr, T value)
void operator()(const f64_sub_t &op)
void operator()(const f64_reinterpret_i64_t &op)
void operator()(const f32_ceil_t &op)
void operator()(const i32_shr_u_t &op)
void operator()(const f64_store_t &op)
void operator()(const i64_trunc_s_f64_t &op)
void operator()(const f64_const_t &op)
void operator()(const i32_reinterpret_f32_t &op)
void operator()(const i32_sub_t &op)
void operator()(const i32_ne_t &op)
void operator()(const f64_copysign_t &op)
void operator()(const f32_min_t &op)
void operator()(const f64_convert_u_i64_t &op)
void operator()(const i32_gt_s_t &op)
void operator()(const f32_le_t &op)
void operator()(const i64_lt_u_t &op)
void operator()(const return_t &op)
void operator()(const i32_trunc_s_f32_t &op)
void operator()(const i32_le_u_t &op)
void operator()(const i64_and_t &op)
void operator()(const i32_rem_s_t &op)
void operator()(const f32_sub_t &op)
void operator()(const i32_add_t &op)
void operator()(const f64_neg_t &op)
void operator()(const f64_floor_t &op)
void operator()(const i32_load16_s_t &op)
void operator()(const i64_load_t &op)
void operator()(const i64_rem_u_t &op)
void operator()(const i64_lt_s_t &op)
void operator()(const i32_rotr_t &op)
void operator()(const i64_add_t &op)
void operator()(const f32_convert_s_i32_t &op)
void operator()(const i64_store8_t &op)
void operator()(const f32_convert_u_i64_t &op)
void operator()(const select_t &op)
void operator()(const i32_and_t &op)
void operator()(const i32_load_t &op)
void operator()(const i64_load8_u_t &op)
void operator()(const call_indirect_t &op)
void operator()(const f32_ge_t &op)
void operator()(const i32_rotl_t &op)
void operator()(const f64_mul_t &op)
void * pop_memop_addr(const Op &op)
void operator()(const i64_or_t &op)
void operator()(const i64_shr_u_t &op)
void operator()(const i64_store16_t &op)
void operator()(const set_local_t &op)
void operator()(const get_global_t &op)
void operator()(const f64_sqrt_t &op)
void operator()(const i64_shr_s_t &op)
void operator()(const f32_abs_t &op)
void operator()(const i64_trunc_s_f32_t &op)
void operator()(const i32_mul_t &op)
void operator()(const i32_popcnt_t &op)
void operator()(const i32_store8_t &op)
void operator()(const i32_rem_u_t &op)
void operator()(const i32_store16_t &op)
void operator()(const f32_const_t &op)
void operator()(const f64_convert_u_i32_t &op)
void operator()(const f64_gt_t &op)
void operator()(const i64_sub_t &op)
void operator()(const i64_div_s_t &op)
void operator()(const f32_nearest_t &op)
void operator()(const unreachable_t &op)
void operator()(const i32_div_s_t &op)
void operator()(const get_local_t &op)
void operator()(const i64_ctz_t &op)
void operator()(const i32_shl_t &op)
void operator()(const i32_clz_t &op)
void operator()(const f64_convert_s_i64_t &op)
void operator()(const f32_floor_t &op)
void operator()(const f64_convert_s_i32_t &op)
void operator()(const f32_gt_t &op)
void operator()(const i32_le_s_t &op)
void operator()(const f64_le_t &op)
void operator()(const br_if_t &op)
void operator()(const set_global_t &op)
void operator()(const drop_t &op)
void operator()(const i32_shr_s_t &op)
void operator()(const i64_rotl_t &op)
void operator()(const i64_le_u_t &op)
void operator()(const i64_gt_s_t &op)
void operator()(const i64_trunc_u_f64_t &op)
void operator()(const block_t &op)
void operator()(const i32_trunc_u_f64_t &op)
void operator()(const i32_ctz_t &op)
void operator()(const f32_load_t &op)
void operator()(const i32_ge_u_t &op)
void operator()(const i32_trunc_u_f32_t &op)
void operator()(const i64_store32_t &op)
void operator()(const i64_ge_s_t &op)
void operator()(const f32_reinterpret_i32_t &op)
void operator()(const f64_ceil_t &op)
void operator()(const f32_convert_u_i32_t &op)
void operator()(const i64_clz_t &op)
void operator()(const i64_extend_s_i32_t &op)
void operator()(const f32_mul_t &op)
void operator()(const i32_lt_s_t &op)
void operator()(const f64_ge_t &op)
void operator()(const i64_mul_t &op)
void operator()(const f32_sqrt_t &op)
void operator()(const br_table_data_t &op)
void operator()(const f64_min_t &op)
void operator()(const i32_lt_u_t &op)
void operator()(const i32_xor_t &op)
void operator()(const f32_lt_t &op)
void operator()(const i64_ne_t &op)
void operator()(const i32_eq_t &op)
void operator()(const i64_load8_s_t &op)
void operator()(const f32_neg_t &op)
void operator()(const f32_convert_s_i64_t &op)
void operator()(const f32_add_t &op)
#define SYS_VM_ASSERT(expr, exc_type, msg)
Definition exceptions.hpp:8