Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
bitcode_writer.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <sysio/vm/allocator.hpp>
4#include <sysio/vm/opcodes.hpp>
5#include <sysio/vm/types.hpp>
6#include <sysio/vm/vector.hpp>
7
8#include <cstddef>
9#include <cstdint>
10#include <type_traits>
11
12namespace sysio { namespace vm {
13
15
16 template<class I>
17 decltype(auto) append_instr(I&& instr) {
18 return (fb[op_index++] = instr).template get<std::decay_t<I>>();
19 }
20
21 public:
22 explicit bitcode_writer(growable_allocator& alloc, std::size_t source_bytes, module& mod) :
23 _allocator(alloc),
24 _code_segment_base(alloc.start_code()),
25 fb(alloc, source_bytes),
26 _mod(&mod) {}
27 ~bitcode_writer() { _allocator.end_code<false>(_code_segment_base); }
28 void emit_unreachable() { fb[op_index++] = unreachable_t{}; };
29 void emit_nop() { fb[op_index++] = nop_t{}; }
30 uint32_t emit_end() { return op_index; }
31 uint32_t* emit_return(uint32_t depth_change) {
32 return emit_br(depth_change);
33 }
34 void emit_block() {}
35 uint32_t emit_loop() { return op_index; }
37 if_t& instr = append_instr(if_t{});
38 return &instr.pc;
39 }
41 auto& else_ = append_instr(else_t{});
42 *if_loc = _base_offset + op_index;
43 return &else_.pc;
44 }
45 uint32_t * emit_br(uint32_t depth_change) {
46 auto& instr = append_instr(br_t{});
47 instr.data = depth_change;
48 return &instr.pc;
49 }
50 uint32_t * emit_br_if(uint32_t depth_change) {
51 auto& instr = append_instr(br_if_t{});
52 instr.data = depth_change;
53 return &instr.pc;
54 }
55
56 struct br_table_parser;
57 friend struct br_table_parser;
60 _this{ &base },
61 _i{ 0 } {
62 br_table_t& bt = _this->append_instr(br_table_t{});
63 bt.offset = static_cast<uint32_t>(((table_size * sizeof(br_table_t::elem_t))/sizeof(opcode))+2);
64
65 // point the branch table data to after the br_table instruction
66 _br_tab = bt.table = reinterpret_cast<br_table_t::elem_t*>(&_this->fb[_this->op_index]);
67
68 _this->op_index += bt.offset;
69
70 // canary to throw if we have overbounded our allocated memory
71 _this->fb[_this->op_index] = error_t{};
72 bt.size = table_size;
73 }
74 uint32_t * emit_case(uint32_t depth_change) {
75 auto& elem = _br_tab[_i++];
76 elem.stack_pop = depth_change;
77 return &elem.pc;
78 }
79 // Must be called after all cases
81 auto result = emit_case(depth_change);
82 SYS_VM_ASSERT(_this->fb[_this->op_index].is_a<error_t>(), wasm_parse_exception, "overwrote br_table data");
83 return result;
84 }
85 br_table_t::elem_t* _br_tab;
87 std::size_t _i;
90 };
91 auto emit_br_table(uint32_t table_size) { return br_table_parser{ *this, table_size }; }
92 void emit_call(const func_type& ft, uint32_t funcnum) { fb[op_index++] = call_t{ funcnum }; }
93 void emit_call_indirect(const func_type& ft, uint32_t functypeidx) { fb[op_index++] = call_indirect_t{ functypeidx }; }
94
95
96 void emit_drop() { fb[op_index++] = drop_t{}; }
97 void emit_select() { fb[op_index++] = select_t{}; }
98 void emit_get_local(uint32_t localidx) { fb[op_index++] = get_local_t{localidx}; }
99 void emit_set_local(uint32_t localidx) { fb[op_index++] = set_local_t{localidx}; }
100 void emit_tee_local(uint32_t localidx) { fb[op_index++] = tee_local_t{localidx}; }
101 void emit_get_global(uint32_t localidx) { fb[op_index++] = get_global_t{localidx}; }
102 void emit_set_global(uint32_t localidx) { fb[op_index++] = set_global_t{localidx}; }
103
104#define MEM_OP(op_name) \
105 void emit_ ## op_name(uint32_t offset, uint32_t alignment) { fb[op_index++] = op_name ## _t{ offset, alignment }; }
106#define LOAD_OP MEM_OP
107#define STORE_OP MEM_OP
108 LOAD_OP(i32_load)
109 LOAD_OP(i64_load)
110 LOAD_OP(f32_load)
111 LOAD_OP(f64_load)
112 LOAD_OP(i32_load8_s)
113 LOAD_OP(i32_load16_s)
114 LOAD_OP(i32_load8_u)
115 LOAD_OP(i32_load16_u)
116 LOAD_OP(i64_load8_s)
117 LOAD_OP(i64_load16_s)
118 LOAD_OP(i64_load32_s)
119 LOAD_OP(i64_load8_u)
120 LOAD_OP(i64_load16_u)
121 LOAD_OP(i64_load32_u)
122 STORE_OP(i32_store)
123 STORE_OP(i64_store)
124 STORE_OP(f32_store)
125 STORE_OP(f64_store)
126 STORE_OP(i32_store8)
127 STORE_OP(i32_store16)
128 STORE_OP(i64_store8)
129 STORE_OP(i64_store16)
130 STORE_OP(i64_store32)
131#undef LOAD_OP
132#undef STORE_OP
133#undef MEM_OP
134
135 void emit_current_memory() { fb[op_index++] = current_memory_t{}; }
136 void emit_grow_memory() { fb[op_index++] = grow_memory_t{}; }
137
138 void emit_i32_const(uint32_t value) { fb[op_index++] = i32_const_t{ value }; }
139 void emit_i64_const(uint64_t value) { fb[op_index++] = i64_const_t{ value }; }
140 void emit_f32_const(float value) { fb[op_index++] = f32_const_t{ value }; }
141 void emit_f64_const(double value) { fb[op_index++] = f64_const_t{ value }; }
142
143#define OP(opname) \
144 void emit_ ## opname() { fb[op_index++] = opname ## _t{}; }
145#define UNOP OP
146#define BINOP OP
147
148
149 UNOP(i32_eqz)
150 BINOP(i32_eq)
151 BINOP(i32_ne)
152 BINOP(i32_lt_s)
153 BINOP(i32_lt_u)
154 BINOP(i32_gt_s)
155 BINOP(i32_gt_u)
156 BINOP(i32_le_s)
157 BINOP(i32_le_u)
158 BINOP(i32_ge_s)
159 BINOP(i32_ge_u)
160 UNOP(i64_eqz)
161 BINOP(i64_eq)
162 BINOP(i64_ne)
163 BINOP(i64_lt_s)
164 BINOP(i64_lt_u)
165 BINOP(i64_gt_s)
166 BINOP(i64_gt_u)
167 BINOP(i64_le_s)
168 BINOP(i64_le_u)
169 BINOP(i64_ge_s)
170 BINOP(i64_ge_u)
172 BINOP(f32_ne)
174 BINOP(f32_gt)
176 BINOP(f32_ge)
178 BINOP(f64_ne)
180 BINOP(f64_gt)
182 BINOP(f64_ge)
183
184 UNOP(i32_clz)
185 UNOP(i32_ctz)
186 UNOP(i32_popcnt)
187 BINOP(i32_add)
188 BINOP(i32_sub)
189 BINOP(i32_mul)
190 BINOP(i32_div_s)
191 BINOP(i32_div_u)
192 BINOP(i32_rem_s)
193 BINOP(i32_rem_u)
194 BINOP(i32_and)
195 BINOP(i32_or)
196 BINOP(i32_xor)
197 BINOP(i32_shl)
198 BINOP(i32_shr_s)
199 BINOP(i32_shr_u)
200 BINOP(i32_rotl)
201 BINOP(i32_rotr)
202 UNOP(i64_clz)
203 UNOP(i64_ctz)
204 UNOP(i64_popcnt)
205 BINOP(i64_add)
206 BINOP(i64_sub)
207 BINOP(i64_mul)
208 BINOP(i64_div_s)
209 BINOP(i64_div_u)
210 BINOP(i64_rem_s)
211 BINOP(i64_rem_u)
212 BINOP(i64_and)
213 BINOP(i64_or)
214 BINOP(i64_xor)
215 BINOP(i64_shl)
216 BINOP(i64_shr_s)
217 BINOP(i64_shr_u)
218 BINOP(i64_rotl)
219 BINOP(i64_rotr)
220
221 UNOP(f32_abs)
222 UNOP(f32_neg)
223 UNOP(f32_ceil)
224 UNOP(f32_floor)
225 UNOP(f32_trunc)
226 UNOP(f32_nearest)
232 BINOP(f32_min)
233 BINOP(f32_max)
234 BINOP(f32_copysign)
235 UNOP(f64_abs)
236 UNOP(f64_neg)
237 UNOP(f64_ceil)
238 UNOP(f64_floor)
239 UNOP(f64_trunc)
240 UNOP(f64_nearest)
246 BINOP(f64_min)
247 BINOP(f64_max)
248 BINOP(f64_copysign)
249
250 UNOP(i32_wrap_i64)
251 UNOP(i32_trunc_s_f32)
252 UNOP(i32_trunc_u_f32)
253 UNOP(i32_trunc_s_f64)
254 UNOP(i32_trunc_u_f64)
255 UNOP(i64_extend_s_i32)
256 UNOP(i64_extend_u_i32)
257 UNOP(i64_trunc_s_f32)
258 UNOP(i64_trunc_u_f32)
259 UNOP(i64_trunc_s_f64)
260 UNOP(i64_trunc_u_f64)
261 UNOP(f32_convert_s_i32)
262 UNOP(f32_convert_u_i32)
263 UNOP(f32_convert_s_i64)
264 UNOP(f32_convert_u_i64)
265 UNOP(f32_demote_f64)
266 UNOP(f64_convert_s_i32)
267 UNOP(f64_convert_u_i32)
268 UNOP(f64_convert_s_i64)
269 UNOP(f64_convert_u_i64)
270 UNOP(f64_promote_f32)
271 UNOP(i32_reinterpret_f32)
272 UNOP(i64_reinterpret_f64)
273 UNOP(f32_reinterpret_i32)
274 UNOP(f64_reinterpret_i64)
275
276#undef BINOP
277#undef UNOP
278#undef OP
279
280 void emit_error() { fb[op_index++] = error_t{}; }
281
282 void fix_branch(uint32_t* branch, uint32_t target) { if(branch) *branch = _base_offset + target; }
284 op_index = 0;
285 // pre-allocate for the function body code, so we have a big blob of memory to work with during function code parsing
286 fb = guarded_vector<opcode>{_allocator, _mod->code[idx].size };
287 }
289 fb.resize(op_index + 1);
290 uint32_t locals_count = 0;
291 for(uint32_t i = 0; i < locals.size(); ++i) {
292 locals_count += locals[i].count;
293 }
294 fb[fb.size() - 1] = return_t{ static_cast<uint32_t>(locals_count + ft.param_types.size()), ft.return_count, 0, 0 };
295 }
296
298 op_index++;
299 fb.resize(op_index);
300 body.code = fb.raw();
301 body.size = op_index;
302 _base_offset += body.size;
303 }
304
305 const void* get_addr() const { return fb.raw() + op_index; }
306 const void* get_base_addr() const { return _code_segment_base; }
307
308 private:
309
310 growable_allocator& _allocator;
311 void * _code_segment_base;
312 std::size_t op_index = 0;
314 module* _mod;
315 std::size_t _base_offset = 0;
316 };
317
318}}
void emit_prologue(const func_type &ft, const guarded_vector< local_entry > &, uint32_t idx)
const void * get_base_addr() const
void emit_get_local(uint32_t localidx)
void emit_set_global(uint32_t localidx)
void emit_tee_local(uint32_t localidx)
void emit_i32_const(uint32_t value)
void emit_f32_const(float value)
void emit_call(const func_type &ft, uint32_t funcnum)
void emit_call_indirect(const func_type &ft, uint32_t functypeidx)
void emit_set_local(uint32_t localidx)
const void * get_addr() const
void fix_branch(uint32_t *branch, uint32_t target)
uint32_t * emit_br(uint32_t depth_change)
auto emit_br_table(uint32_t table_size)
uint32_t * emit_else(uint32_t *if_loc)
void emit_i64_const(uint64_t value)
uint32_t * emit_br_if(uint32_t depth_change)
void emit_get_global(uint32_t localidx)
void finalize(function_body &body)
uint32_t * emit_return(uint32_t depth_change)
void emit_epilogue(const func_type &ft, const guarded_vector< local_entry > &locals, uint32_t idx)
void emit_f64_const(double value)
bitcode_writer(growable_allocator &alloc, std::size_t source_bytes, module &mod)
void end_code(void *code_base)
variant< > opcode
Definition opcodes.hpp:79
#define value
Definition pkcs11.h:157
float32_t f32_add(float32_t a, float32_t b)
Definition f32_add.c:43
float32_t f32_div(float32_t a, float32_t b)
Definition f32_div.c:44
bool f32_eq(float32_t a, float32_t b)
Definition f32_eq.c:44
bool f32_le(float32_t a, float32_t b)
Definition f32_le.c:43
bool f32_lt(float32_t a, float32_t b)
Definition f32_lt.c:43
float32_t f32_mul(float32_t a, float32_t b)
Definition f32_mul.c:44
float32_t f32_sqrt(float32_t a)
Definition f32_sqrt.c:44
float32_t f32_sub(float32_t a, float32_t b)
Definition f32_sub.c:43
float64_t f64_add(float64_t a, float64_t b)
Definition f64_add.c:43
float64_t f64_div(float64_t a, float64_t b)
Definition f64_div.c:44
bool f64_eq(float64_t a, float64_t b)
Definition f64_eq.c:44
bool f64_le(float64_t a, float64_t b)
Definition f64_le.c:43
bool f64_lt(float64_t a, float64_t b)
Definition f64_lt.c:43
float64_t f64_mul(float64_t a, float64_t b)
Definition f64_mul.c:44
float64_t f64_sqrt(float64_t a)
Definition f64_sqrt.c:44
float64_t f64_sub(float64_t a, float64_t b)
Definition f64_sub.c:43
unsigned int uint32_t
Definition stdint.h:126
unsigned __int64 uint64_t
Definition stdint.h:136
br_table_parser(const br_table_parser &)=delete
uint32_t * emit_default(uint32_t depth_change)
uint32_t * emit_case(uint32_t depth_change)
br_table_parser(bitcode_writer &base, uint32_t table_size)
br_table_parser & operator=(const br_table_parser &)=delete
uint8_t return_count
Definition types.hpp:45
guarded_vector< value_type > param_types
Definition types.hpp:44
guarded_vector< function_body > code
Definition types.hpp:177
#define SYS_VM_ASSERT(expr, exc_type, msg)
Definition exceptions.hpp:8
#define UNOP
#define LOAD_OP
#define STORE_OP
#define BINOP
void bt(const Operand &op, const Reg &reg)