From d22f77d9852642e405adebf87d23e320e369a731 Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Sat, 1 Apr 2023 22:51:55 +0530 Subject: [PATCH 1/2] tmp --- src/libasr/codegen/asr_to_wasm.cpp | 739 ++++----- src/libasr/codegen/wasm_assembler.h | 2167 +++++++++++++++------------ 2 files changed, 1475 insertions(+), 1431 deletions(-) diff --git a/src/libasr/codegen/asr_to_wasm.cpp b/src/libasr/codegen/asr_to_wasm.cpp index 409dcf4288..394a96bca7 100644 --- a/src/libasr/codegen/asr_to_wasm.cpp +++ b/src/libasr/codegen/asr_to_wasm.cpp @@ -98,34 +98,14 @@ std::string import_fn_to_str(IMPORT_FUNC fn) { class ASRToWASMVisitor : public ASR::BaseVisitor { public: Allocator &m_al; + WASMAssembler m_wa; diag::Diagnostics &diag; SymbolFuncInfo *cur_sym_info; - uint32_t nesting_level; - uint32_t cur_loop_nesting_level; bool is_prototype_only; bool is_local_vars_only; ASR::Function_t* main_func; - Vec m_type_section; - Vec m_import_section; - Vec m_func_section; - Vec m_memory_section; - Vec m_global_section; - Vec m_export_section; - Vec m_code_section; - Vec m_data_section; - - uint32_t no_of_types; - uint32_t no_of_functions; - uint32_t no_of_memories; - uint32_t no_of_globals; - uint32_t no_of_exports; - uint32_t no_of_imports; - uint32_t no_of_data_segments; - uint32_t avail_mem_loc; - uint32_t digits_mem_loc; - uint32_t min_no_pages; uint32_t max_no_pages; @@ -147,86 +127,41 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { main_func = nullptr; nesting_level = 0; cur_loop_nesting_level = 0; - no_of_types = 0; avail_mem_loc = 0; - no_of_functions = 0; - no_of_memories = 0; - no_of_globals = 0; - no_of_exports = 0; - no_of_imports = 0; - no_of_data_segments = 0; min_no_pages = 100; // fixed 6.4 Mb memory currently max_no_pages = 100; // fixed 6.4 Mb memory currently - m_type_section.reserve(m_al, 1024 * 128); - m_import_section.reserve(m_al, 1024 * 128); - m_func_section.reserve(m_al, 1024 * 128); - m_memory_section.reserve(m_al, 1024 * 128); - m_global_section.reserve(m_al, 1024 * 128); - m_export_section.reserve(m_al, 1024 * 128); - m_code_section.reserve(m_al, 1024 * 128); - m_data_section.reserve(m_al, 1024 * 128); - m_compiler_globals.resize(global_vars_cnt); m_import_func_idx_map.resize(import_funcs_cnt); m_rt_funcs_map.resize(NO_OF_RT_FUNCS); m_rt_func_used_idx = std::vector(NO_OF_RT_FUNCS, -1); } - void get_wasm(Vec &code) { - code.reserve(m_al, 8U /* preamble size */ + - 8U /* (section id + section size) */ * - 8U /* number of sections */ - + m_type_section.size() + - m_import_section.size() + m_func_section.size() + - m_memory_section.size() + m_global_section.size() + - m_export_section.size() + m_code_section.size() + - m_data_section.size()); - - wasm::emit_header(code, m_al); // emit header and version - wasm::encode_section( - code, m_type_section, m_al, 1U, - no_of_types); // no_of_types indicates total (imported + defined) - // no of functions - wasm::encode_section(code, m_import_section, m_al, 2U, no_of_imports); - wasm::encode_section(code, m_func_section, m_al, 3U, no_of_functions); - wasm::encode_section(code, m_memory_section, m_al, 5U, no_of_memories); - wasm::encode_section(code, m_global_section, m_al, 6U, no_of_globals); - wasm::encode_section(code, m_export_section, m_al, 7U, no_of_exports); - wasm::encode_section(code, m_code_section, m_al, 10U, no_of_functions); - wasm::encode_section(code, m_data_section, m_al, 11U, - no_of_data_segments); - } - void import_function(IMPORT_FUNC fn, std::vector param_types, std::vector result_types) { int func_idx = -1; emit_func_type(param_types, result_types, func_idx); m_import_func_idx_map[fn] = func_idx; - - wasm::emit_import_fn(m_import_section, m_al, "wasi_snapshot_preview1", import_fn_to_str(fn), func_idx); - no_of_imports++; + m_wa.emit_import_fn("wasi_snapshot_preview1", import_fn_to_str(fn), func_idx); } - void import_function2(ASR::Function_t* fn) { + void import_function(ASR::Function_t* fn) { if (ASRUtils::get_FunctionType(fn)->m_abi != ASR::abiType::BindC) return; if (ASRUtils::get_FunctionType(fn)->m_deftype != ASR::deftypeType::Interface) return; if (ASRUtils::get_FunctionType(fn)->m_abi != ASR::abiType::BindC) return; if (ASRUtils::is_intrinsic_function2(fn)) return; - wasm::emit_import_fn(m_import_section, m_al, "js", fn->m_name, no_of_types); - no_of_imports++; + m_wa.emit_import_fn("js", fn->m_name, m_wa.no_of_types); emit_function_prototype(*fn); } void emit_imports(SymbolTable *global_scope) { - using namespace wasm; - avail_mem_loc += 4; /* initial 4 bytes to store return values of wasi funcs*/ - import_function(proc_exit, {i32}, {}); - import_function(fd_write, {i32, i32, i32, i32}, {i32}); + import_function(proc_exit, {WASMType::i32}, {}); + import_function(fd_write, {WASMType::i32, WASMType::i32, WASMType::i32, WASMType::i32}, + {WASMType::i32}); // In WASM: The indices of the imports precede the indices of other // definitions in the same index space. Therefore, declare the import @@ -237,206 +172,119 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { for (auto &item : p->m_symtab->get_scope()) { if (ASR::is_a(*item.second)) { ASR::Function_t *fn = ASR::down_cast(item.second); - import_function2(fn); + import_function(fn); } } } else if (ASR::is_a(*item.second)) { ASR::Function_t *fn = ASR::down_cast(item.second); - import_function2(fn); + import_function(fn); } } } - void emit_if_else(std::function test_cond, std::function if_block, std::function else_block) { - test_cond(); - wasm::emit_b8(m_code_section, m_al, 0x04); // emit if start - wasm::emit_b8(m_code_section, m_al, 0x40); // empty block type - nesting_level++; - if_block(); - wasm::emit_b8(m_code_section, m_al, 0x05); // starting of else - else_block(); - nesting_level--; - wasm::emit_expr_end(m_code_section, m_al); // emit if end - } - - void emit_loop(std::function test_cond, std::function loop_block) { - uint32_t prev_cur_loop_nesting_level = cur_loop_nesting_level; - cur_loop_nesting_level = nesting_level; - - wasm::emit_b8(m_code_section, m_al, 0x03); // emit loop start - wasm::emit_b8(m_code_section, m_al, 0x40); // empty block type - - nesting_level++; - - emit_if_else(test_cond, [&](){ - loop_block(); - // From WebAssembly Docs: - // Unlike with other index spaces, indexing of labels is relative by - // nesting depth, that is, label 0 refers to the innermost structured - // control instruction enclosing the referring branch instruction, while - // increasing indices refer to those farther out. - wasm::emit_branch(m_code_section, m_al, nesting_level - - cur_loop_nesting_level - 1); // emit_branch and label the loop - }, [&](){}); - - nesting_level--; - wasm::emit_expr_end(m_code_section, m_al); // end loop - cur_loop_nesting_level = prev_cur_loop_nesting_level; - } - - void emit_func_type(std::vector params, std::vector results, int &func_idx) { - wasm::emit_b8(m_type_section, m_al, 0x60); - wasm::emit_u32(m_type_section, m_al, params.size()); // no of params - for (auto param:params) { - wasm::emit_b8(m_type_section, m_al, param); - } - wasm::emit_u32(m_type_section, m_al, results.size()); // no of results - for (auto result:results) { - wasm::emit_b8(m_type_section, m_al, result); - } - if (func_idx == -1) { - func_idx = no_of_types++; - } - } - - void define_emit_func( - std::vector params, - std::vector results, - std::vector locals, - std::string func_name, - std::function func_body, - int func_idx = -1) { - - emit_func_type(params, results, func_idx); // type declaration - - /*** Reference Function Prototype ***/ - wasm::emit_u32(m_func_section, m_al, func_idx); - - /*** Function Body Starts Here ***/ - uint32_t len_idx_code_section_func_size = - wasm::emit_len_placeholder(m_code_section, m_al); - - wasm::emit_u32(m_code_section, m_al, locals.size()); - for (auto local:locals) { - wasm::emit_u32(m_code_section, m_al, 1u); // count of local vars of this type - wasm::emit_b8(m_code_section, m_al, local); - } - - func_body(); - - wasm::emit_b8(m_code_section, m_al, 0x0F); // emit wasm return instruction - wasm::emit_expr_end(m_code_section, m_al); - wasm::fixup_len(m_code_section, m_al, len_idx_code_section_func_size); - - /*** Export the function ***/ - wasm::emit_export_fn(m_export_section, m_al, func_name, func_idx); // add function to export - no_of_functions++; - no_of_exports++; - } - void emit_print_int(int fn_idx = -1) { - using namespace wasm; - define_emit_func({i64}, {}, {i64, i64, i64, i64}, "print_i64", [&](){ + m_wa.define_emit_func({WASMType::i64}, {}, {WASMType::i64, WASMType::i64, + WASMType::i64, WASMType::i64}, "print_i64", [&](){ // locals 0 is given parameter // locals 1 is digits_cnt // locals 2 is divisor (in powers of 10) // locals 3 is loop counter (counts upto digits_cnt (which is decreasing)) // locals 4 is extra copy of given parameter - emit_if_else([&](){ - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_i64_eq(m_code_section, m_al); + m_wa.emit_if_else([&](){ + m_wa.emit_local_get(0); + m_wa.emit_i64_const(0); + m_wa.emit_i64_eq(); }, [&](){ emit_call_fd_write(1, "0", 1, 0); - wasm::emit_b8(m_code_section, m_al, 0x0F); // emit wasm return instruction + m_wa.emit_b8(0x0F); // emit wasm return instruction }, [&](){}); - emit_if_else([&](){ - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_i64_lt_s(m_code_section, m_al); + m_wa.emit_if_else([&](){ + m_wa.emit_local_get(0); + m_wa.emit_i64_const(0); + m_wa.emit_i64_lt_s(); }, [&](){ emit_call_fd_write(1, "-", 1, 0); - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_i64_const(m_code_section, m_al, -1); - wasm::emit_i64_mul(m_code_section, m_al); - wasm::emit_local_set(m_code_section, m_al, 0); + m_wa.emit_local_get(0); + m_wa.emit_i64_const(-1); + m_wa.emit_i64_mul(); + m_wa.emit_local_set(0); }, [&](){}); - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_local_set(m_code_section, m_al, 4); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_local_set(m_code_section, m_al, 1); + m_wa.emit_local_get(0); + m_wa.emit_local_set(4); + m_wa.emit_i64_const(0); + m_wa.emit_local_set(1); - emit_loop([&](){ - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_i64_gt_s(m_code_section, m_al); + m_wa.emit_loop([&](){ + m_wa.emit_local_get(0); + m_wa.emit_i64_const(0); + m_wa.emit_i64_gt_s(); }, [&](){ - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_i64_const(m_code_section, m_al, 1); - wasm::emit_i64_add(m_code_section, m_al); - wasm::emit_local_set(m_code_section, m_al, 1); - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_i64_const(m_code_section, m_al, 10); - wasm::emit_i64_div_s(m_code_section, m_al); - wasm::emit_local_set(m_code_section, m_al, 0); + m_wa.emit_local_get(1); + m_wa.emit_i64_const(1); + m_wa.emit_i64_add(); + m_wa.emit_local_set(1); + m_wa.emit_local_get(0); + m_wa.emit_i64_const(10); + m_wa.emit_i64_div_s(); + m_wa.emit_local_set(0); }); - emit_loop([&](){ - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_i64_gt_s(m_code_section, m_al); + m_wa.emit_loop([&](){ + m_wa.emit_local_get(1); + m_wa.emit_i64_const(0); + m_wa.emit_i64_gt_s(); }, [&](){ - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_i64_const(m_code_section, m_al, 1); - wasm::emit_i64_sub(m_code_section, m_al); - wasm::emit_local_set(m_code_section, m_al, 1); + m_wa.emit_local_get(1); + m_wa.emit_i64_const(1); + m_wa.emit_i64_sub(); + m_wa.emit_local_set(1); - wasm::emit_i64_const(m_code_section, m_al, 1); - wasm::emit_local_set(m_code_section, m_al, 2); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_local_set(m_code_section, m_al, 3); + m_wa.emit_i64_const(1); + m_wa.emit_local_set(2); + m_wa.emit_i64_const(0); + m_wa.emit_local_set(3); emit_loop([&](){ - wasm::emit_local_get(m_code_section, m_al, 3); - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_i64_lt_s(m_code_section, m_al); + m_wa.emit_local_get(3); + m_wa.emit_local_get(1); + m_wa.emit_i64_lt_s(); }, [&](){ - wasm::emit_local_get(m_code_section, m_al, 3); - wasm::emit_i64_const(m_code_section, m_al, 1); - wasm::emit_i64_add(m_code_section, m_al); - wasm::emit_local_set(m_code_section, m_al, 3); - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_i64_const(m_code_section, m_al, 10); - wasm::emit_i64_mul(m_code_section, m_al); - wasm::emit_local_set(m_code_section, m_al, 2); + m_wa.emit_local_get(3); + m_wa.emit_i64_const(1); + m_wa.emit_i64_add(); + m_wa.emit_local_set(3); + m_wa.emit_local_get(2); + m_wa.emit_i64_const(10); + m_wa.emit_i64_mul(); + m_wa.emit_local_set(2); }); - wasm::emit_local_get(m_code_section, m_al, 4); - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_i64_div_s(m_code_section, m_al); - wasm::emit_i64_const(m_code_section, m_al, 10); - wasm::emit_i64_rem_s(m_code_section, m_al); + m_wa.emit_local_get(4); + m_wa.emit_local_get(2); + m_wa.emit_i64_div_s(); + m_wa.emit_i64_const(10); + m_wa.emit_i64_rem_s(); /* The digit is on stack */ - wasm::emit_i64_const(m_code_section, m_al, 12 /* 4 + 4 + 4 (iov vec + str size)*/); - wasm::emit_i64_mul(m_code_section, m_al); - wasm::emit_i64_const(m_code_section, m_al, digits_mem_loc); - wasm::emit_i64_add(m_code_section, m_al); - wasm::emit_local_set(m_code_section, m_al, 0); // temporary save + m_wa.emit_i64_const(12 /* 4 + 4 + 4 (iov vec + str size)*/); + m_wa.emit_i64_mul(); + m_wa.emit_i64_const(digits_mem_loc); + m_wa.emit_i64_add(); + m_wa.emit_local_set(0); // temporary save { - wasm::emit_i32_const(m_code_section, m_al, 1); // file type: 1 for stdout - wasm::emit_local_get(m_code_section, m_al, 0); // use stored digit - wasm::emit_i32_wrap_i64(m_code_section, m_al); - wasm::emit_i32_const(m_code_section, m_al, 1); // size of iov vector - wasm::emit_i32_const(m_code_section, m_al, 0); // mem_loction to return no. of bytes written + m_wa.emit_i32_const(1); // file type: 1 for stdout + m_wa.emit_local_get(0); // use stored digit + m_wa.emit_i32_wrap_i64(); + m_wa.emit_i32_const(1); // size of iov vector + m_wa.emit_i32_const(0); // mem_loction to return no. of bytes written // call WASI fd_write - wasm::emit_call(m_code_section, m_al, m_import_func_idx_map[fd_write]); - wasm::emit_drop(m_code_section, m_al); + m_wa.emit_call(m_import_func_idx_map[fd_write]); + m_wa.emit_drop(); } }); @@ -444,224 +292,225 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } void emit_print_float(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f64}, {}, {i64, i64, i64}, "print_f64", [&](){ - emit_if_else([&](){ - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_f64_const(m_code_section, m_al, 0); - wasm::emit_f64_lt(m_code_section, m_al); + m_wa.define_emit_func({WASMType::f64}, {}, {WASMType::i64, WASMType::i64, + WASMType::i64}, "print_f64", [&](){ + m_wa.emit_if_else([&](){ + m_wa.emit_local_get(0); + m_wa.emit_f64_const(0); + m_wa.emit_f64_lt(); }, [&](){ emit_call_fd_write(1, "-", 1, 0); - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_f64_const(m_code_section, m_al, -1); - wasm::emit_f64_mul(m_code_section, m_al); - wasm::emit_local_set(m_code_section, m_al, 0); + m_wa.emit_local_get(0); + m_wa.emit_f64_const(-1); + m_wa.emit_f64_mul(); + m_wa.emit_local_set(0); }, [&](){}); - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_i64_trunc_f64_s(m_code_section, m_al); - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[print_i64]); + m_wa.emit_local_get(0); + m_wa.emit_i64_trunc_f64_s(); + m_wa.emit_call(m_rt_func_used_idx[print_i64]); emit_call_fd_write(1, ".", 1, 0); - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_i64_trunc_f64_s(m_code_section, m_al); - wasm::emit_f64_convert_i64_s(m_code_section, m_al); - wasm::emit_f64_sub(m_code_section, m_al); - wasm::emit_f64_const(m_code_section, m_al, 1e8); - wasm::emit_f64_mul(m_code_section, m_al); - wasm::emit_i64_trunc_f64_s(m_code_section, m_al); - wasm::emit_local_set(m_code_section, m_al, 2); /* save the current fractional part value */ - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_local_set(m_code_section, m_al, 3); /* save the another copy */ - - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_local_set(m_code_section, m_al, 1); // digits_cnt - - emit_loop([&](){ - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_i64_const(m_code_section, m_al, 0); - wasm::emit_i64_gt_s(m_code_section, m_al); + m_wa.emit_local_get(0); + m_wa.emit_local_get(0); + m_wa.emit_i64_trunc_f64_s(); + m_wa.emit_f64_convert_i64_s(); + m_wa.emit_f64_sub(); + m_wa.emit_f64_const(1e8); + m_wa.emit_f64_mul(); + m_wa.emit_i64_trunc_f64_s(); + m_wa.emit_local_set(2); /* save the current fractional part value */ + m_wa.emit_local_get(2); + m_wa.emit_local_set(3); /* save the another copy */ + + m_wa.emit_i64_const(0); + m_wa.emit_local_set(1); // digits_cnt + + m_wa.emit_loop([&](){ + m_wa.emit_local_get(2); + m_wa.emit_i64_const(0); + m_wa.emit_i64_gt_s(); }, [&](){ - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_i64_const(m_code_section, m_al, 1); - wasm::emit_i64_add(m_code_section, m_al); - wasm::emit_local_set(m_code_section, m_al, 1); - - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_f64_convert_i64_s(m_code_section, m_al); - wasm::emit_i64_const(m_code_section, m_al, 10); - wasm::emit_f64_convert_i64_s(m_code_section, m_al); - wasm::emit_f64_div(m_code_section, m_al); - wasm::emit_i64_trunc_f64_s(m_code_section, m_al); - wasm::emit_local_set(m_code_section, m_al, 2); + m_wa.emit_local_get(1); + m_wa.emit_i64_const(1); + m_wa.emit_i64_add(); + m_wa.emit_local_set(1); + + m_wa.emit_local_get(2); + m_wa.emit_f64_convert_i64_s(); + m_wa.emit_i64_const(10); + m_wa.emit_f64_convert_i64_s(); + m_wa.emit_f64_div(); + m_wa.emit_i64_trunc_f64_s(); + m_wa.emit_local_set(2); }); - emit_loop([&](){ - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_i64_const(m_code_section, m_al, 8); - wasm::emit_i64_lt_s(m_code_section, m_al); + m_wa.emit_loop([&](){ + m_wa.emit_local_get(1); + m_wa.emit_i64_const(8); + m_wa.emit_i64_lt_s(); }, [&](){ - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_i64_const(m_code_section, m_al, 1); - wasm::emit_i64_add(m_code_section, m_al); - wasm::emit_local_set(m_code_section, m_al, 1); + m_wa.emit_local_get(1); + m_wa.emit_i64_const(1); + m_wa.emit_i64_add(); + m_wa.emit_local_set(1); emit_call_fd_write(1, "0", 1, 0); }); - wasm::emit_local_get(m_code_section, m_al, 3); - wasm::emit_call(m_code_section, m_al, m_rt_func_used_idx[print_i64]); + m_wa.emit_local_get(3); + m_wa.emit_call(m_rt_func_used_idx[print_i64]); }, fn_idx); } void emit_complex_add_32(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f32, f32, f32, f32}, {f32, f32}, {}, "add_c32", [&](){ - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_f32_add(m_code_section, m_al); - - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_local_get(m_code_section, m_al, 3); - wasm::emit_f32_add(m_code_section, m_al); + m_wa.define_emit_func({WASMType::f32, WASMType::f32, WASMType::f32, + WASMType::f32}, {WASMType::f32, WASMType::f32}, + {}, "add_c32", [&](){ + m_wa.emit_local_get(0); + m_wa.emit_local_get(2); + m_wa.emit_f32_add(); + + m_wa.emit_local_get(1); + m_wa.emit_local_get(3); + m_wa.emit_f32_add(); }, fn_idx); } void emit_complex_add_64(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f64, f64, f64, f64}, {f64, f64}, {}, "add_c64", [&](){ - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_f64_add(m_code_section, m_al); - - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_local_get(m_code_section, m_al, 3); - wasm::emit_f64_add(m_code_section, m_al); + m_wa.define_emit_func({WASMType::f64, WASMType::f64, WASMType::f64, + WASMType::f64}, {WASMType::f64, WASMType::f64}, {}, "add_c64", [&](){ + m_wa.emit_local_get(0); + m_wa.emit_local_get(2); + m_wa.emit_f64_add(); + + m_wa.emit_local_get(1); + m_wa.emit_local_get(3); + m_wa.emit_f64_add(); }, fn_idx); } void emit_complex_sub_32(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f32, f32, f32, f32}, {f32, f32}, {}, "sub_c32", [&](){ - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_f32_sub(m_code_section, m_al); - - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_local_get(m_code_section, m_al, 3); - wasm::emit_f32_sub(m_code_section, m_al); + m_wa.define_emit_func({WASMType::f32, WASMType::f32, WASMType::f32, + WASMType::f32}, {WASMType::f32, WASMType::f32}, {}, "sub_c32", [&](){ + m_wa.emit_local_get(0); + m_wa.emit_local_get(2); + m_wa.emit_f32_sub(); + + m_wa.emit_local_get(1); + m_wa.emit_local_get(3); + m_wa.emit_f32_sub(); }, fn_idx); } void emit_complex_sub_64(int fn_idx = -1) { using namespace wasm; - define_emit_func({f64, f64, f64, f64}, {f64, f64}, {}, "sub_c64", [&](){ - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_f64_sub(m_code_section, m_al); - - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_local_get(m_code_section, m_al, 3); - wasm::emit_f64_sub(m_code_section, m_al); + m_wa.define_emit_func({WASMType::f64, WASMType::f64, WASMType::f64, + WASMType::f64}, {WASMType::f64, WASMType::f64}, {}, "sub_c64", [&](){ + m_wa.emit_local_get(0); + m_wa.emit_local_get(2); + m_wa.emit_f64_sub(); + + m_wa.emit_local_get(1); + m_wa.emit_local_get(3); + m_wa.emit_f64_sub(); }, fn_idx); } void emit_complex_mul_32(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f32, f32, f32, f32}, {f32, f32}, {}, "mul_c32", [&](){ - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_f32_mul(m_code_section, m_al); + m_wa.define_emit_func({WASMType::f32, WASMType::f32, WASMType::f32, + WASMType::f32}, {WASMType::f32, WASMType::f32}, {}, "mul_c32", [&](){ + m_wa.emit_local_get(0); + m_wa.emit_local_get(2); + m_wa.emit_f32_mul(); - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_local_get(m_code_section, m_al, 3); - wasm::emit_f32_mul(m_code_section, m_al); + m_wa.emit_local_get(1); + m_wa.emit_local_get(3); + m_wa.emit_f32_mul(); - wasm::emit_f32_sub(m_code_section, m_al); + m_wa.emit_f32_sub(); - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_local_get(m_code_section, m_al, 3); - wasm::emit_f32_mul(m_code_section, m_al); + m_wa.emit_local_get(0); + m_wa.emit_local_get(3); + m_wa.emit_f32_mul(); - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_f32_mul(m_code_section, m_al); + m_wa.emit_local_get(1); + m_wa.emit_local_get(2); + m_wa.emit_f32_mul(); - wasm::emit_f32_add(m_code_section, m_al); + m_wa.emit_f32_add(); }, fn_idx); } void emit_complex_mul_64(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f64, f64, f64, f64}, {f64, f64}, {}, "mul_c64", [&](){ - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_f64_mul(m_code_section, m_al); - - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_local_get(m_code_section, m_al, 3); - wasm::emit_f64_mul(m_code_section, m_al); - - wasm::emit_f64_sub(m_code_section, m_al); - - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_local_get(m_code_section, m_al, 3); - wasm::emit_f64_mul(m_code_section, m_al); - - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_local_get(m_code_section, m_al, 2); - wasm::emit_f64_mul(m_code_section, m_al); - - wasm::emit_f64_add(m_code_section, m_al); + m_wa.define_emit_func({WASMType::f64, WASMType::f64, WASMType::f64, + WASMType::f64}, {WASMType::f64, WASMType::f64}, {}, "mul_c64", [&](){ + m_wa.emit_local_get(0); + m_wa.emit_local_get(2); + m_wa.emit_f64_mul(); + + m_wa.emit_local_get(1); + m_wa.emit_local_get(3); + m_wa.emit_f64_mul(); + + m_wa.emit_f64_sub(); + + m_wa.emit_local_get(0); + m_wa.emit_local_get(3); + m_wa.emit_f64_mul(); + + m_wa.emit_local_get(1); + m_wa.emit_local_get(2); + m_wa.emit_f64_mul(); + m_wa.emit_f64_add(); }, fn_idx); } void emit_complex_abs_32(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f32, f32}, {f32}, {}, "abs_c32", [&](){ - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_f32_mul(m_code_section, m_al); - - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_f32_mul(m_code_section, m_al); - - wasm::emit_f32_add(m_code_section, m_al); - wasm::emit_f32_sqrt(m_code_section, m_al); + m_wa.define_emit_func({WASMType::f32, WASMType::f32}, + {WASMType::f32}, {}, "abs_c32", [&](){ + m_wa.emit_local_get(0); + m_wa.emit_local_get(0); + m_wa.emit_f32_mul(); + + m_wa.emit_local_get(1); + m_wa.emit_local_get(1); + m_wa.emit_f32_mul(); + + m_wa.emit_f32_add(); + m_wa.emit_f32_sqrt(); }, fn_idx); } void emit_complex_abs_64(int fn_idx = -1) { - using namespace wasm; - define_emit_func({f64, f64}, {f64}, {}, "abs_c64", [&](){ - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_local_get(m_code_section, m_al, 0); - wasm::emit_f64_mul(m_code_section, m_al); - - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_local_get(m_code_section, m_al, 1); - wasm::emit_f64_mul(m_code_section, m_al); - - wasm::emit_f64_add(m_code_section, m_al); - wasm::emit_f64_sqrt(m_code_section, m_al); + m_wa.define_emit_func({WASMType::f64, WASMType::f64}, + {WASMType::f64}, {}, "abs_c64", [&](){ + m_wa.emit_local_get(0); + m_wa.emit_local_get(0); + m_wa.emit_f64_mul(); + + m_wa.emit_local_get(1); + m_wa.emit_local_get(1); + m_wa.emit_f64_mul(); + + m_wa.emit_f64_add(); + m_wa.emit_f64_sqrt(); }, fn_idx); } template - void declare_global_var(wasm::type var_type, GLOBAL_VAR name, T initial_value, bool isMutable) { + void declare_global_var(WASMType var_type, GLOBAL_VAR name, T initial_value, bool isMutable) { m_global_section.push_back(m_al, var_type); m_global_section.push_back(m_al, isMutable); switch (var_type) { - case wasm::type::i32: wasm::emit_i32_const(m_global_section, m_al, initial_value); break; - case wasm::type::i64: wasm::emit_i64_const(m_global_section, m_al, initial_value); break; - case wasm::type::f32: wasm::emit_f32_const(m_global_section, m_al, initial_value); break; - case wasm::type::f64: wasm::emit_f64_const(m_global_section, m_al, initial_value); break; + case WASMType::i32: m_wa.emit_i32_const(m_global_section, initial_value); break; + case WASMType::i64: m_wa.emit_i64_const(m_global_section, initial_value); break; + case WASMType::f32: m_wa.emit_f32_const(m_global_section, initial_value); break; + case WASMType::f64: m_wa.emit_f64_const(m_global_section, initial_value); break; default: throw CodeGenError("declare_global_var: Unsupport var_type"); break; } - wasm::emit_expr_end(m_global_section, m_al); // end instructions + m_wa.emit_expr_end(m_global_section); // end instructions m_compiler_globals[name] = no_of_globals; no_of_globals++; } @@ -671,9 +520,9 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { // Ignore type variables return; } - m_global_var_idx_map[get_hash((ASR::asr_t *)v)] = no_of_globals; - emit_var_type(m_global_section, v, no_of_globals, false); - m_global_section.push_back(m_al, true); // mutable + m_global_var_idx_map[get_hash((ASR::asr_t *)v)] = m_wa.no_of_globals; + emit_var_type(m_wa.m_global_section, v, m_wa.no_of_globals, false); + m_wa.m_global_section.push_back(m_al, true); // mutable int kind = ASRUtils::extract_kind_from_ttype_t(v->m_type); switch (v->m_type->type){ case ASR::ttypeType::Integer: { @@ -683,10 +532,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } switch (kind) { case 4: - wasm::emit_i32_const(m_global_section, m_al, init_val); + m_wa.emit_i32_const(m_global_section, init_val); break; case 8: - wasm::emit_i64_const(m_global_section, m_al, init_val); + m_wa.emit_i64_const(m_global_section, init_val); break; default: throw CodeGenError( @@ -701,10 +550,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } switch (kind) { case 4: - wasm::emit_f32_const(m_global_section, m_al, init_val); + m_wa.emit_f32_const(m_global_section, init_val); break; case 8: - wasm::emit_f64_const(m_global_section, m_al, init_val); + m_wa.emit_f64_const(m_global_section, init_val); break; default: throw CodeGenError( @@ -719,7 +568,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } switch (kind) { case 4: - wasm::emit_i32_const(m_global_section, m_al, init_val); + m_wa.emit_i32_const(m_global_section, init_val); break; default: throw CodeGenError( @@ -735,7 +584,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { emit_string(init_val); switch (kind) { case 1: - wasm::emit_i32_const(m_global_section, m_al, m_string_to_iov_loc_map[init_val]); + m_wa.emit_i32_const(m_global_section, m_string_to_iov_loc_map[init_val]); break; default: throw CodeGenError( @@ -749,7 +598,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { wasm::emit_i32_const(m_global_section, m_al, 0); } } - wasm::emit_expr_end(m_global_section, m_al); // end instructions + m_wa.emit_expr_end(m_global_section); // end instructions } void declare_symbols(const ASR::TranslationUnit_t &x) { @@ -783,16 +632,14 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { emit_imports(x.m_global_scope); - wasm::emit_declare_mem(m_memory_section, m_al, min_no_pages, max_no_pages); - no_of_memories++; - wasm::emit_export_mem(m_export_section, m_al, "memory", 0 /* mem_idx */); - no_of_exports++; + m_wa.emit_declare_mem(min_no_pages, max_no_pages); + m_wa.emit_export_mem("memory", 0 /* mem_idx */); - declare_global_var(wasm::type::i32, cur_mem_loc, 0, true); - declare_global_var(wasm::type::i32, tmp_reg_i32, 0, true); - declare_global_var(wasm::type::i64, tmp_reg_i64, 0, true); - declare_global_var(wasm::type::f32, tmp_reg_f32, 0, true); - declare_global_var(wasm::type::f64, tmp_reg_f64, 0, true); + declare_global_var(WASMType::i32, cur_mem_loc, 0, true); + declare_global_var(WASMType::i32, tmp_reg_i32, 0, true); + declare_global_var(WASMType::i64, tmp_reg_i64, 0, true); + declare_global_var(WASMType::f32, tmp_reg_f32, 0, true); + declare_global_var(WASMType::f64, tmp_reg_f64, 0, true); emit_string(" "); emit_string("\n"); @@ -891,7 +738,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { bool is_array = ASRUtils::is_array(v->m_type); if (emitCount) { - wasm::emit_u32(code, m_al, 1U); + m_wa.emit_u32(code, m_al, 1U); } if (ASRUtils::is_pointer(v->m_type)) { @@ -903,9 +750,9 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { "Pointers are not currently supported", {v->base.base.loc}, "emitting integer for now"); if (t->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::i32); + m_wa.emit_b8(code, m_al, WASMType::i32); } else if (t->m_kind == 8) { - wasm::emit_b8(code, m_al, wasm::type::i64); + m_wa.emit_b8(code, m_al, WASMType::i64); } else { throw CodeGenError( "Integers of kind 4 and 8 only supported"); @@ -922,12 +769,12 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::Integer_t *v_int = ASR::down_cast(v->m_type); if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); + m_wa.emit_b8(code, m_al, WASMType::i32); } else { if (v_int->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::i32); + m_wa.emit_b8(code, m_al, WASMType::i32); } else if (v_int->m_kind == 8) { - wasm::emit_b8(code, m_al, wasm::type::i64); + m_wa.emit_b8(code, m_al, WASMType::i64); } else { throw CodeGenError( "Integers of kind 4 and 8 only supported"); @@ -937,12 +784,12 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::Real_t *v_float = ASR::down_cast(v->m_type); if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); + m_wa.emit_b8(code, m_al, WASMType::i32); } else { if (v_float->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::f32); + m_wa.emit_b8(code, m_al, WASMType::f32); } else if (v_float->m_kind == 8) { - wasm::emit_b8(code, m_al, wasm::type::f64); + m_wa.emit_b8(code, m_al, WASMType::f64); } else { throw CodeGenError( "Floating Points of kind 4 and 8 only supported"); @@ -953,11 +800,11 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::down_cast(v->m_type); if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); + m_wa.emit_b8(code, m_al, WASMType::i32); } else { // All Logicals are represented as i32 in WASM if (v_logical->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::i32); + m_wa.emit_b8(code, m_al, WASMType::i32); } else { throw CodeGenError("Logicals of kind 4 only supported"); } @@ -967,13 +814,13 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::down_cast(v->m_type); if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); + m_wa.emit_b8(code, m_al, WASMType::i32); } else { if (v_int->m_kind == 1) { /* Character is stored as string in memory. The variable points to this location in memory */ - wasm::emit_b8(code, m_al, wasm::type::i32); + m_wa.emit_b8(code, m_al, WASMType::i32); } else { throw CodeGenError( "Characters of kind 1 only supported"); @@ -984,20 +831,20 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::down_cast(v->m_type); if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); + m_wa.emit_b8(code, m_al, WASMType::i32); } else { if (v_comp->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::f32); // real part + m_wa.emit_b8(code, m_al, WASMType::f32); // real part if (emitCount) { - wasm::emit_u32(code, m_al, 1U); + m_wa.emit_u32(code, m_al, 1U); } - wasm::emit_b8(code, m_al, wasm::type::f32); // imag part + m_wa.emit_b8(code, m_al, WASMType::f32); // imag part } else if (v_comp->m_kind == 8) { - wasm::emit_b8(code, m_al, wasm::type::f64); // real part + m_wa.emit_b8(code, m_al, WASMType::f64); // real part if (emitCount) { - wasm::emit_u32(code, m_al, 1U); + m_wa.emit_u32(code, m_al, 1U); } - wasm::emit_b8(code, m_al, wasm::type::f64); // imag part + m_wa.emit_b8(code, m_al, WASMType::f64); // imag part } else { throw CodeGenError( "Complex numbers of kind 4 and 8 only supported yet"); @@ -1026,7 +873,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::down_cast(item.second); if (isLocalVar(v)) { m_var_idx_map[get_hash((ASR::asr_t *)v)] = cur_sym_info->no_of_variables; - emit_var_type(m_code_section, v, cur_sym_info->no_of_variables, true); + emit_var_type(m_wa.m_code_section, v, cur_sym_info->no_of_variables, true); } } } @@ -1036,17 +883,17 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { uint64_t hash = get_hash((ASR::asr_t *)v); if (m_var_idx_map.find(hash) != m_var_idx_map.end()) { uint32_t var_idx = m_var_idx_map[hash]; - wasm::emit_local_get(m_code_section, m_al, var_idx); + m_wa.emit_local_get(var_idx); if (ASRUtils::is_complex(*v->m_type)) { // get the imaginary part - wasm::emit_local_get(m_code_section, m_al, var_idx + 1u); + m_wa.emit_local_get(var_idx + 1u); } } else if (m_global_var_idx_map.find(hash) != m_global_var_idx_map.end()) { uint32_t var_idx = m_global_var_idx_map[hash]; - wasm::emit_global_get(m_code_section, m_al, var_idx); + m_wa.emit_global_get(var_idx); if (ASRUtils::is_complex(*v->m_type)) { // get the imaginary part - wasm::emit_global_get(m_code_section, m_al, var_idx + 1u); + m_wa.emit_global_get(var_idx + 1u); } } else { throw CodeGenError("Variable " + std::string(v->m_name) + " not declared"); @@ -1059,16 +906,16 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { uint32_t var_idx = m_var_idx_map[hash]; if (ASRUtils::is_complex(*v->m_type)) { // set the imaginary part - wasm::emit_local_set(m_code_section, m_al, var_idx + 1u); + m_wa.emit_local_set(var_idx + 1u); } - wasm::emit_local_set(m_code_section, m_al, var_idx); + m_wa.emit_local_set(var_idx); } else if (m_global_var_idx_map.find(hash) != m_global_var_idx_map.end()) { uint32_t var_idx = m_global_var_idx_map[hash]; if (ASRUtils::is_complex(*v->m_type)) { // set the imaginary part - wasm::emit_global_set(m_code_section, m_al, var_idx + 1u); + m_wa.emit_global_set(var_idx + 1u); } - wasm::emit_global_set(m_code_section, m_al, var_idx); + m_wa.emit_global_set(var_idx); } else { throw CodeGenError("Variable " + std::string(v->m_name) + " not declared"); } @@ -1096,8 +943,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { total_array_size *= dim; } - wasm::emit_i32_const(m_code_section, m_al, - avail_mem_loc); + m_wa.emit_i32_const(avail_mem_loc); emit_var_set(v); avail_mem_loc += kind * total_array_size; } @@ -1116,7 +962,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { SymbolFuncInfo *s = new SymbolFuncInfo; /********************* New Type Declaration *********************/ - wasm::emit_b8(m_type_section, m_al, 0x60); + m_wa.emit_b8(m_wa.m_type_section, m_al, 0x60); /********************* Parameter Types List *********************/ s->referenced_vars.reserve(m_al, x.n_args); @@ -1890,7 +1736,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } else if (a_kind == 8) { switch (x.m_op) { case (ASR::cmpopType::Eq): { - wasm::emit_i64_eq(m_code_section, m_al); + wasm::);m_code_section, m_al); break; } case (ASR::cmpopType::Gt): { @@ -2855,13 +2701,14 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } void emit_call_fd_write(int filetype, const std::string &str, int iov_vec_len, int return_val_mem_loc) { - wasm::emit_i32_const(m_code_section, m_al, filetype); // file type: 1 for stdout - wasm::emit_i32_const(m_code_section, m_al, m_string_to_iov_loc_map[str]); // iov location - wasm::emit_i32_const(m_code_section, m_al, iov_vec_len); // size of iov vector - wasm::emit_i32_const(m_code_section, m_al, return_val_mem_loc); // mem_loction to return no. of bytes written + LCOMPILERS_ASSERT(m_string_to_iov_loc_map.find(str) != m_string_to_iov_loc_map.end()); + m_wa.emit_i32_const(filetype); // file type: 1 for stdout + m_wa.emit_i32_const(m_string_to_iov_loc_map[str]); // iov location + m_wa.emit_i32_const(iov_vec_len); // size of iov vector + m_wa.emit_i32_const(return_val_mem_loc); // mem_loction to return no. of bytes written // call WASI fd_write - wasm::emit_call(m_code_section, m_al, m_import_func_idx_map[fd_write]); - wasm::emit_drop(m_code_section, m_al); + m_wa.emit_call(m_import_func_idx_map[fd_write]); + m_wa.emit_drop(); } template diff --git a/src/libasr/codegen/wasm_assembler.h b/src/libasr/codegen/wasm_assembler.h index 2f6df20742..c673fabb8e 100644 --- a/src/libasr/codegen/wasm_assembler.h +++ b/src/libasr/codegen/wasm_assembler.h @@ -5,13 +5,21 @@ namespace LCompilers { -namespace wasm { - -enum type { i32 = 0x7F, i64 = 0x7E, f32 = 0x7D, f64 = 0x7C }; - -enum mem_align { b8 = 0, b16 = 1, b32 = 2, b64 = 3 }; - -void emit_leb128_u32(Vec &code, Allocator &al, +enum WASMType : uint8_t { + i32 = 0x7F, + i64 = 0x7E, + f32 = 0x7D, + f64 = 0x7C +}; + +enum WASMMemAlign { + b8 = 0, + b16 = 1, + b32 = 2, + b64 = 3 +}; + +static void emit_leb128_u32(Vec &code, Allocator &al, uint32_t n) { // for u32 do { uint8_t byte = n & 0x7f; @@ -23,7 +31,7 @@ void emit_leb128_u32(Vec &code, Allocator &al, } while (n != 0); } -void emit_leb128_i32(Vec &code, Allocator &al, int32_t n) { // for i32 +static static void emit_leb128_i32(Vec &code, Allocator &al, int32_t n) { // for i32 bool more = true; do { uint8_t byte = n & 0x7f; @@ -37,7 +45,7 @@ void emit_leb128_i32(Vec &code, Allocator &al, int32_t n) { // for i32 } while (more); } -void emit_leb128_i64(Vec &code, Allocator &al, int64_t n) { // for i64 +static void emit_leb128_i64(Vec &code, Allocator &al, int64_t n) { // for i64 bool more = true; do { uint8_t byte = n & 0x7f; @@ -51,7 +59,7 @@ void emit_leb128_i64(Vec &code, Allocator &al, int64_t n) { // for i64 } while (more); } -void emit_ieee754_f32(Vec &code, Allocator &al, float z) { // for f32 +static void emit_ieee754_f32(Vec &code, Allocator &al, float z) { // for f32 uint8_t encoded_float[sizeof(z)]; std::memcpy(&encoded_float, &z, sizeof(z)); for (auto &byte : encoded_float) { @@ -59,7 +67,7 @@ void emit_ieee754_f32(Vec &code, Allocator &al, float z) { // for f32 } } -void emit_ieee754_f64(Vec &code, Allocator &al, double z) { // for f64 +static void emit_ieee754_f64(Vec &code, Allocator &al, double z) { // for f64 uint8_t encoded_float[sizeof(z)]; std::memcpy(&encoded_float, &z, sizeof(z)); for (auto &byte : encoded_float) { @@ -67,1182 +75,1371 @@ void emit_ieee754_f64(Vec &code, Allocator &al, double z) { // for f64 } } -// function to emit header of Wasm Binary Format -void emit_header(Vec &code, Allocator &al) { - code.push_back(al, 0x00); - code.push_back(al, 0x61); - code.push_back(al, 0x73); - code.push_back(al, 0x6D); - code.push_back(al, 0x01); - code.push_back(al, 0x00); - code.push_back(al, 0x00); - code.push_back(al, 0x00); -} +static void emit_u32_b32_idx(Vec &code, Allocator &al, uint32_t idx, + uint32_t section_size) { + /* + Encodes the integer `i` using LEB128 and adds trailing zeros to always + occupy 4 bytes. Stores the int `i` at the index `idx` in `code`. + */ + Vec num; + num.reserve(al, 4); + emit_leb128_u32(num, al, section_size); + std::vector num_4b = {0x80, 0x80, 0x80, 0x00}; + assert(num.size() <= 4); + for (uint32_t i = 0; i < num.size(); i++) { + num_4b[i] |= num[i]; + } + for (uint32_t i = 0; i < 4u; i++) { + code.p[idx + i] = num_4b[i]; + } + } -// function to append a given bytecode to the end of the code -void emit_b8(Vec &code, Allocator &al, uint8_t x) { - code.push_back(al, x); -} +class WASMAssembler { + private: + Allocator &m_al; + + // function to emit header of Wasm Binary Format + void emit_header(Vec &code, Allocator &al) { + code.push_back(al, 0x00); + code.push_back(al, 0x61); + code.push_back(al, 0x73); + code.push_back(al, 0x6D); + code.push_back(al, 0x01); + code.push_back(al, 0x00); + code.push_back(al, 0x00); + code.push_back(al, 0x00); + } -// function to emit unsigned 32 bit integer -void emit_u32(Vec &code, Allocator &al, uint32_t x) { - emit_leb128_u32(code, al, x); -} + // function to append a given bytecode to the end of the code + void emit_b8(Vec &code, Allocator &al, uint8_t x) { + code.push_back(al, x); + } -// function to emit signed 32 bit integer -void emit_i32(Vec &code, Allocator &al, int32_t x) { - emit_leb128_i32(code, al, x); -} + // function to emit unsigned 32 bit integer + void emit_u32(Vec &code, Allocator &al, uint32_t x) { + emit_leb128_u32(code, al, x); + } -// function to emit signed 64 bit integer -void emit_i64(Vec &code, Allocator &al, int64_t x) { - emit_leb128_i64(code, al, x); -} + // function to emit signed 32 bit integer + void emit_i32(Vec &code, Allocator &al, int32_t x) { + emit_leb128_i32(code, al, x); + } -// function to emit 32 bit float -void emit_f32(Vec &code, Allocator &al, float x) { - emit_ieee754_f32(code, al, x); -} + // function to emit signed 64 bit integer + void emit_i64(Vec &code, Allocator &al, int64_t x) { + emit_leb128_i64(code, al, x); + } -// function to emit 64 bit float -void emit_f64(Vec &code, Allocator &al, double x) { - emit_ieee754_f64(code, al, x); -} + // function to emit 32 bit float + void emit_f32(Vec &code, Allocator &al, float x) { + emit_ieee754_f32(code, al, x); + } -// function to emit string -void emit_str(Vec &code, Allocator &al, std::string text) { - std::vector text_bytes(text.size()); - std::memcpy(text_bytes.data(), text.data(), text.size()); - emit_u32(code, al, text_bytes.size()); - for (auto &byte : text_bytes) emit_b8(code, al, byte); -} + // function to emit 64 bit float + void emit_f64(Vec &code, Allocator &al, double x) { + emit_ieee754_f64(code, al, x); + } -void emit_u32_b32_idx(Vec &code, Allocator &al, uint32_t idx, - uint32_t section_size) { - /* - Encodes the integer `i` using LEB128 and adds trailing zeros to always - occupy 4 bytes. Stores the int `i` at the index `idx` in `code`. - */ - Vec num; - num.reserve(al, 4); - emit_leb128_u32(num, al, section_size); - std::vector num_4b = {0x80, 0x80, 0x80, 0x00}; - assert(num.size() <= 4); - for (uint32_t i = 0; i < num.size(); i++) { - num_4b[i] |= num[i]; - } - for (uint32_t i = 0; i < 4u; i++) { - code.p[idx + i] = num_4b[i]; + // function to emit string + void emit_str(Vec &code, Allocator &al, std::string text) { + std::vector text_bytes(text.size()); + std::memcpy(text_bytes.data(), text.data(), text.size()); + emit_u32(code, al, text_bytes.size()); + for (auto &byte : text_bytes) emit_b8(code, al, byte); } -} -// function to fixup length at the given length index -void fixup_len(Vec &code, Allocator &al, uint32_t len_idx) { - uint32_t section_len = code.size() - len_idx - 4u; - emit_u32_b32_idx(code, al, len_idx, section_len); -} + void encode_section(Vec &des, Vec §ion_content, + Allocator &al, uint32_t section_id, + uint32_t no_of_elements) { + // every section in WebAssembly is encoded by adding its section id, + // followed by the content size and lastly the contents + emit_u32(des, al, section_id); + emit_u32(des, al, 4U /* size of no_of_elements */ + section_content.size()); + uint32_t len_idx = emit_len_placeholder(des, al); + emit_u32_b32_idx(des, al, len_idx, no_of_elements); + for (auto &byte : section_content) { + des.push_back(al, byte); + } + } -// function to emit length placeholder -uint32_t emit_len_placeholder(Vec &code, Allocator &al) { - uint32_t len_idx = code.size(); - code.push_back(al, 0x00); - code.push_back(al, 0x00); - code.push_back(al, 0x00); - code.push_back(al, 0x00); - return len_idx; -} + public: + Vec m_type_section; + Vec m_import_section; + Vec m_func_section; + Vec m_memory_section; + Vec m_global_section; + Vec m_export_section; + Vec m_code_section; + Vec m_data_section; + + // no_of_types indicates total (imported + defined) no of functions + uint32_t no_of_types; + uint32_t no_of_functions; + uint32_t no_of_memories; + uint32_t no_of_globals; + uint32_t no_of_exports; + uint32_t no_of_imports; + uint32_t no_of_data_segments; + uint32_t avail_mem_loc; + uint32_t digits_mem_loc; + + uint32_t nesting_level; + uint32_t cur_loop_nesting_level; + + WASMAssembler(Allocator &al, size_t reserve_mem = (1024 * 128)) { + no_of_types = 0; + no_of_functions = 0; + no_of_memories = 0; + no_of_globals = 0; + no_of_exports = 0; + no_of_imports = 0; + no_of_data_segments = 0; + + m_type_section.reserve(m_al, reserve_mem); + m_import_section.reserve(m_al, reserve_mem); + m_func_section.reserve(m_al, reserve_mem); + m_memory_section.reserve(m_al, reserve_mem); + m_global_section.reserve(m_al, reserve_mem); + m_export_section.reserve(m_al, reserve_mem); + m_code_section.reserve(m_al, reserve_mem); + m_data_section.reserve(m_al, reserve_mem); + } -void emit_export_fn(Vec &code, Allocator &al, const std::string &name, - uint32_t idx) { - emit_str(code, al, name); - emit_b8(code, al, 0x00); // for exporting function - emit_u32(code, al, idx); -} + Vec get_wasm() { + Vec code; + code.reserve(m_al, 8U /* preamble size */ + + 8U /* (section id + section size) */ * + 8U /* number of sections */ + + m_type_section.size() + + m_import_section.size() + m_func_section.size() + + m_memory_section.size() + m_global_section.size() + + m_export_section.size() + m_code_section.size() + + m_data_section.size()); + + emit_header(code, m_al); // emit header and version + + encode_section(code, m_type_section, m_al, 1U, no_of_types); + encode_section(code, m_import_section, m_al, 2U, no_of_imports); + encode_section(code, m_func_section, m_al, 3U, no_of_functions); + encode_section(code, m_memory_section, m_al, 5U, no_of_memories); + encode_section(code, m_global_section, m_al, 6U, no_of_globals); + encode_section(code, m_export_section, m_al, 7U, no_of_exports); + encode_section(code, m_code_section, m_al, 10U, no_of_functions); + encode_section(code, m_data_section, m_al, 11U, no_of_data_segments); + + return code; + } -void emit_import_fn(Vec &code, Allocator &al, - const std::string &mod_name, const std::string &fn_name, - uint32_t type_idx) { - emit_str(code, al, mod_name); - emit_str(code, al, fn_name); - emit_b8(code, al, 0x00); // for importing function - emit_u32(code, al, type_idx); -} + void emit_if_else(std::function test_cond, std::function if_block, std::function else_block) { + test_cond(); + m_code_section.push_back(m_al, 0x04); // emit if start + m_code_section.push_back(m_al, 0x40); // empty block type + nesting_level++; + if_block(); + m_code_section.push_back(m_al, 0x05); // starting of else + else_block(); + nesting_level--; + emit_expr_end(m_code_section); // emit if end + } + + void emit_loop(std::function test_cond, std::function loop_block) { + uint32_t prev_cur_loop_nesting_level = cur_loop_nesting_level; + cur_loop_nesting_level = nesting_level; + + m_code_section.push_back(m_al, 0x03); // emit loop start + m_code_section.push_back(m_al, 0x40); // empty block type + + nesting_level++; -void emit_declare_mem(Vec &code, Allocator &al, - uint32_t min_no_pages, uint32_t max_no_pages = 0) { - if (max_no_pages > 0) { - emit_b8(code, al, - 0x01); // for specifying min and max page limits of memory - emit_u32(code, al, min_no_pages); - emit_u32(code, al, max_no_pages); - } else { - emit_b8(code, al, - 0x00); // for specifying only min page limit of memory - emit_u32(code, al, min_no_pages); + emit_if_else(test_cond, [&](){ + loop_block(); + // From WebAssembly Docs: + // Unlike with other index spaces, indexing of labels is relative by + // nesting depth, that is, label 0 refers to the innermost structured + // control instruction enclosing the referring branch instruction, while + // increasing indices refer to those farther out. + + // emit_branch and label the loop + emit_branch(nesting_level - cur_loop_nesting_level - 1); + }, [&](){}); + + nesting_level--; + emit_expr_end(m_code_section); // end loop + cur_loop_nesting_level = prev_cur_loop_nesting_level; } -} -void emit_import_mem(Vec &code, Allocator &al, - const std::string &mod_name, const std::string &mem_name, - uint32_t min_no_pages, uint32_t max_no_pages = 0) { - emit_str(code, al, mod_name); - emit_str(code, al, mem_name); - emit_b8(code, al, 0x02); // for importing memory - if (max_no_pages > 0) { - emit_b8(code, al, - 0x01); // for specifying min and max page limits of memory - emit_u32(code, al, min_no_pages); - emit_u32(code, al, max_no_pages); - } else { - emit_b8(code, al, - 0x00); // for specifying only min page limit of memory - emit_u32(code, al, min_no_pages); + void emit_func_type(std::vector params, std::vector results, int &func_idx) { + emit_b8(m_type_section, m_al, 0x60); + emit_u32(m_type_section, m_al, params.size()); // no of params + for (auto param:params) { + emit_b8(m_type_section, m_al, param); + } + emit_u32(m_type_section, m_al, results.size()); // no of results + for (auto result:results) { + emit_b8(m_type_section, m_al, result); + } + if (func_idx == -1) { + func_idx = no_of_types++; + } } -} -void emit_export_mem(Vec &code, Allocator &al, const std::string &name, - uint32_t idx) { - emit_str(code, al, name); - emit_b8(code, al, 0x02); // for exporting memory - emit_u32(code, al, idx); -} + void define_emit_func( + std::vector params, + std::vector results, + std::vector locals, + std::string func_name, + std::function func_body, + int func_idx = -1) { -void encode_section(Vec &des, Vec §ion_content, - Allocator &al, uint32_t section_id, - uint32_t no_of_elements) { - // every section in WebAssembly is encoded by adding its section id, - // followed by the content size and lastly the contents - emit_u32(des, al, section_id); - emit_u32(des, al, 4U /* size of no_of_elements */ + section_content.size()); - uint32_t len_idx = emit_len_placeholder(des, al); - emit_u32_b32_idx(des, al, len_idx, no_of_elements); - for (auto &byte : section_content) { - des.push_back(al, byte); - } -} + emit_func_type(params, results, func_idx); // type declaration -// function to emit drop instruction (it throws away a single operand on stack) -void emit_drop(Vec &code, Allocator &al) { code.push_back(al, 0x1A); } + /*** Reference Function Prototype ***/ + emit_u32(m_func_section, m_al, func_idx); -// function to emit get local variable at given index -void emit_local_get(Vec &code, Allocator &al, uint32_t idx) { - code.push_back(al, 0x20); - emit_u32(code, al, idx); -} + /*** Function Body Starts Here ***/ + uint32_t len_idx_code_section_func_size = + emit_len_placeholder(m_code_section, m_al); -// function to emit set local variable at given index -void emit_local_set(Vec &code, Allocator &al, uint32_t idx) { - code.push_back(al, 0x21); - emit_u32(code, al, idx); -} + emit_u32(m_code_section, m_al, locals.size()); + for (auto local:locals) { + emit_u32(m_code_section, m_al, 1u); // count of local vars of this type + emit_b8(m_code_section, m_al, local); + } -// function to emit get global variable at given index -void emit_global_get(Vec &code, Allocator &al, uint32_t idx) { - code.push_back(al, 0x23); - emit_u32(code, al, idx); -} + func_body(); -// function to emit set global variable at given index -void emit_global_set(Vec &code, Allocator &al, uint32_t idx) { - code.push_back(al, 0x24); - emit_u32(code, al, idx); -} + emit_b8(m_code_section, m_al, 0x0F); // emit wasm return instruction + emit_expr_end(m_code_section, m_al); + fixup_len(m_code_section, m_al, len_idx_code_section_func_size); -// function to emit call instruction -void emit_call(Vec &code, Allocator &al, uint32_t idx) { - code.push_back(al, 0x10); - emit_u32(code, al, idx); -} + /*** Export the function ***/ + emit_export_fn(func_name, func_idx); // add function to export + no_of_functions++; + } -// function to emit end of wasm expression -void emit_expr_end(Vec &code, Allocator &al) { - code.push_back(al, 0x0B); -} + // function to emit length placeholder + uint32_t emit_len_placeholder(Vec &code, Allocator &al) { + uint32_t len_idx = code.size(); + code.push_back(al, 0x00); + code.push_back(al, 0x00); + code.push_back(al, 0x00); + code.push_back(al, 0x00); + return len_idx; + } -/**************************** Integer Operations ****************************/ + void store_int_at_idx(Vec &code, Allocator &al, uint32_t idx, uint32_t n) { + emit_u32_b32_idx(code, al, idx, n); + } -// function to emit a i32.const instruction -void emit_i32_const(Vec &code, Allocator &al, int32_t x) { - code.push_back(al, 0x41); - emit_i32(code, al, x); -} + // function to fixup length at the given length index + void fixup_len(Vec &code, Allocator &al, uint32_t len_idx) { + uint32_t section_len = code.size() - len_idx - 4u; + store_int_at_idx(code, al, len_idx, section_len); + } -// function to emit i32.clz instruction -void emit_i32_clz(Vec &code, Allocator &al) { - code.push_back(al, 0x67); -} -// function to emit i32.ctz instruction -void emit_i32_ctz(Vec &code, Allocator &al) { - code.push_back(al, 0x68); -} + void emit_export_fn(const std::string &name, uint32_t idx) { + emit_str(m_export_section, m_al, name); + emit_b8(m_export_section, m_al, 0x00); // for exporting function + emit_u32(m_export_section, m_al, idx); + no_of_exports++; + } -// function to emit i32.popcnt instruction -void emit_i32_popcnt(Vec &code, Allocator &al) { - code.push_back(al, 0x69); -} + void emit_import_fn(const std::string &mod_name, const std::string &fn_name, uint32_t type_idx) { + emit_str(m_import_section, m_al, mod_name); + emit_str(m_import_section, m_al, fn_name); + emit_b8(m_import_section, m_al, 0x00); // for importing function + emit_u32(m_import_section, m_al, type_idx); + no_of_imports++; + } -// function to emit i32.add instruction -void emit_i32_add(Vec &code, Allocator &al) { - code.push_back(al, 0x6A); -} + void emit_declare_mem(uint32_t min_no_pages, uint32_t max_no_pages = 0) { + if (max_no_pages > 0) { + emit_b8(m_memory_section, m_al, + 0x01); // for specifying min and max page limits of memory + emit_u32(m_memory_section, m_al, min_no_pages); + emit_u32(m_memory_section, m_al, max_no_pages); + } else { + emit_b8(m_memory_section, m_al, + 0x00); // for specifying only min page limit of memory + emit_u32(m_memory_section, m_al, min_no_pages); + } + no_of_memories++; + } -// function to emit i32.sub instruction -void emit_i32_sub(Vec &code, Allocator &al) { - code.push_back(al, 0x6B); -} + void emit_import_mem(const std::string &mod_name, const std::string &mem_name, + uint32_t min_no_pages, uint32_t max_no_pages = 0) { + emit_str(m_import_section, m_al, mod_name); + emit_str(m_import_section, m_al, mem_name); + emit_b8(m_import_section, m_al, 0x02); // for importing memory + if (max_no_pages > 0) { + emit_b8(m_import_section, m_al, + 0x01); // for specifying min and max page limits of memory + emit_u32(m_import_section, m_al, min_no_pages); + emit_u32(m_import_section, m_al, max_no_pages); + } else { + emit_b8(m_import_section, m_al, + 0x00); // for specifying only min page limit of memory + emit_u32(m_import_section, m_al, min_no_pages); + } + no_of_imports++; + } -// function to emit i32.mul instruction -void emit_i32_mul(Vec &code, Allocator &al) { - code.push_back(al, 0x6C); -} + void emit_export_mem(const std::string &name, uint32_t idx) { + emit_str(m_export_section, m_al, name); + emit_b8(m_export_section, m_al, 0x02); // for exporting memory + emit_u32(m_export_section, m_al, idx); + no_of_exports++; + } -// function to emit i32.div_s instruction -void emit_i32_div_s(Vec &code, Allocator &al) { - code.push_back(al, 0x6D); -} + // function to emit drop instruction (it throws away a single operand on stack) + void emit_drop() { + m_code_section.push_back(al, 0x1A); + } -// function to emit i32.div_u instruction -void emit_i32_div_u(Vec &code, Allocator &al) { - code.push_back(al, 0x6E); -} + // function to emit get local variable at given index + void emit_local_get(uint32_t idx) { + m_code_section.push_back(m_al, 0x20); + emit_u32(m_code_section, m_al, idx); + } -// function to emit i32.rem_s instruction -void emit_i32_rem_s(Vec &code, Allocator &al) { - code.push_back(al, 0x6F); -} + // function to emit set local variable at given index + void emit_local_set(uint32_t idx) { + m_code_section.push_back(m_al, 0x21); + emit_u32(m_code_section, m_al, idx); + } -// function to emit i32.rem_u instruction -void emit_i32_rem_u(Vec &code, Allocator &al) { - code.push_back(al, 0x70); -} + // function to emit get global variable at given index + void emit_global_get(uint32_t idx) { + m_code_section.push_back(m_al, 0x23); + emit_u32(m_code_section, m_al, idx); + } -// function to emit i32.and instruction -void emit_i32_and(Vec &code, Allocator &al) { - code.push_back(al, 0x71); -} + // function to emit set global variable at given index + void emit_global_set(uint32_t idx) { + m_code_section.push_back(m_al, 0x24); + emit_u32(m_code_section, m_al, idx); + } -// function to emit i32.or instruction -void emit_i32_or(Vec &code, Allocator &al) { - code.push_back(al, 0x72); -} + // function to emit call instruction + void emit_call(uint32_t idx) { + m_code_section.push_back(m_al, 0x10); + emit_u32(m_code_section, m_al, idx); + } -// function to emit i32.xor instruction -void emit_i32_xor(Vec &code, Allocator &al) { - code.push_back(al, 0x73); -} + // function to emit end of wasm expression + void emit_expr_end(Vec &code) { + code.push_back(m_al, 0x0B); + } -// function to emit i32.shl instruction -void emit_i32_shl(Vec &code, Allocator &al) { - code.push_back(al, 0x74); -} + /**************************** Integer Operations ****************************/ -// function to emit i32.shr_s instruction -void emit_i32_shr_s(Vec &code, Allocator &al) { - code.push_back(al, 0x75); -} + // function to emit a i32.const instruction + void emit_i32_const(int32_t x) { + m_code_section.push_back(m_al, 0x41); + emit_i32(m_code_section, m_al, x); + } -// function to emit i32.shr_u instruction -void emit_i32_shr_u(Vec &code, Allocator &al) { - code.push_back(al, 0x76); -} + // function to emit i32.clz instruction + void emit_i32_clz() { + m_code_section.push_back(m_al, 0x67); + } -// function to emit i32.rotl instruction -void emit_i32_rotl(Vec &code, Allocator &al) { - code.push_back(al, 0x77); -} + // function to emit i32.ctz instruction + void emit_i32_ctz() { + m_code_section.push_back(m_al, 0x68); + } -// function to emit i32.rotr instruction -void emit_i32_rotr(Vec &code, Allocator &al) { - code.push_back(al, 0x78); -} + // function to emit i32.popcnt instruction + void emit_i32_popcnt() { + m_code_section.push_back(m_al, 0x69); + } -// function to emit a i64.const instruction -void emit_i64_const(Vec &code, Allocator &al, int64_t x) { - code.push_back(al, 0x42); - emit_i64(code, al, x); -} + // function to emit i32.add instruction + void emit_i32_add() { + m_code_section.push_back(m_al, 0x6A); + } -// function to emit i64.clz instruction -void emit_i64_clz(Vec &code, Allocator &al) { - code.push_back(al, 0x79); -} + // function to emit i32.sub instruction + void emit_i32_sub() { + m_code_section.push_back(m_al, 0x6B); + } -// function to emit i64.ctz instruction -void emit_i64_ctz(Vec &code, Allocator &al) { - code.push_back(al, 0x7A); -} + // function to emit i32.mul instruction + void emit_i32_mul() { + m_code_section.push_back(m_al, 0x6C); + } -// function to emit i64.popcnt instruction -void emit_i64_popcnt(Vec &code, Allocator &al) { - code.push_back(al, 0x7B); -} + // function to emit i32.div_s instruction + void emit_i32_div_s() { + m_code_section.push_back(m_al, 0x6D); + } -// function to emit i64.add instruction -void emit_i64_add(Vec &code, Allocator &al) { - code.push_back(al, 0x7C); -} + // function to emit i32.div_u instruction + void emit_i32_div_u() { + m_code_section.push_back(m_al, 0x6E); + } -// function to emit i64.sub instruction -void emit_i64_sub(Vec &code, Allocator &al) { - code.push_back(al, 0x7D); -} + // function to emit i32.rem_s instruction + void emit_i32_rem_s() { + m_code_section.push_back(m_al, 0x6F); + } -// function to emit i64.mul instruction -void emit_i64_mul(Vec &code, Allocator &al) { - code.push_back(al, 0x7E); -} + // function to emit i32.rem_u instruction + void emit_i32_rem_u() { + m_code_section.push_back(m_al, 0x70); + } -// function to emit i64.div_s instruction -void emit_i64_div_s(Vec &code, Allocator &al) { - code.push_back(al, 0x7F); -} + // function to emit i32.and instruction + void emit_i32_and() { + m_code_section.push_back(m_al, 0x71); + } -// function to emit i64.div_u instruction -void emit_i64_div_u(Vec &code, Allocator &al) { - code.push_back(al, 0x80); -} + // function to emit i32.or instruction + void emit_i32_or() { + m_code_section.push_back(m_al, 0x72); + } -// function to emit i64.rem_s instruction -void emit_i64_rem_s(Vec &code, Allocator &al) { - code.push_back(al, 0x81); -} + // function to emit i32.xor instruction + void emit_i32_xor() { + m_code_section.push_back(m_al, 0x73); + } -// function to emit i64.rem_u instruction -void emit_i64_rem_u(Vec &code, Allocator &al) { - code.push_back(al, 0x82); -} + // function to emit i32.shl instruction + void emit_i32_shl() { + m_code_section.push_back(m_al, 0x74); + } -// function to emit i64.and instruction -void emit_i64_and(Vec &code, Allocator &al) { - code.push_back(al, 0x83); -} + // function to emit i32.shr_s instruction + void emit_i32_shr_s() { + m_code_section.push_back(m_al, 0x75); + } -// function to emit i64.or instruction -void emit_i64_or(Vec &code, Allocator &al) { - code.push_back(al, 0x84); -} + // function to emit i32.shr_u instruction + void emit_i32_shr_u() { + m_code_section.push_back(m_al, 0x76); + } -// function to emit i64.xor instruction -void emit_i64_xor(Vec &code, Allocator &al) { - code.push_back(al, 0x85); -} + // function to emit i32.rotl instruction + void emit_i32_rotl() { + m_code_section.push_back(m_al, 0x77); + } -// function to emit i64.shl instruction -void emit_i64_shl(Vec &code, Allocator &al) { - code.push_back(al, 0x86); -} + // function to emit i32.rotr instruction + void emit_i32_rotr() { + m_code_section.push_back(m_al, 0x78); + } -// function to emit i64.shr_s instruction -void emit_i64_shr_s(Vec &code, Allocator &al) { - code.push_back(al, 0x87); -} + // function to emit a i64.const instruction + void emit_i64_const(int64_t x) { + m_code_section.push_back(m_al, 0x42); + emit_i64(m_code_section, m_al, x); + } -// function to emit i64.shr_u instruction -void emit_i64_shr_u(Vec &code, Allocator &al) { - code.push_back(al, 0x88); -} + // function to emit i64.clz instruction + void emit_i64_clz() { + m_code_section.push_back(m_al, 0x79); + } -// function to emit i64.rotl instruction -void emit_i64_rotl(Vec &code, Allocator &al) { - code.push_back(al, 0x89); -} + // function to emit i64.ctz instruction + void emit_i64_ctz() { + m_code_section.push_back(m_al, 0x7A); + } -// function to emit i64.rotr instruction -void emit_i64_rotr(Vec &code, Allocator &al) { - code.push_back(al, 0x8A); -} + // function to emit i64.popcnt instruction + void emit_i64_popcnt() { + m_code_section.push_back(m_al, 0x7B); + } -/******** Integer Relational Operations ********/ + // function to emit i64.add instruction + void emit_i64_add() { + m_code_section.push_back(m_al, 0x7C); + } -// function to emit i32.eqz instruction -void emit_i32_eqz(Vec &code, Allocator &al) { - code.push_back(al, 0x45); -} + // function to emit i64.sub instruction + void emit_i64_sub() { + m_code_section.push_back(m_al, 0x7D); + } -// function to emit i32.eq instruction -void emit_i32_eq(Vec &code, Allocator &al) { - code.push_back(al, 0x46); -} + // function to emit i64.mul instruction + void emit_i64_mul() { + m_code_section.push_back(m_al, 0x7E); + } -// function to emit i32.ne instruction -void emit_i32_ne(Vec &code, Allocator &al) { - code.push_back(al, 0x47); -} + // function to emit i64.div_s instruction + void emit_i64_div_s() { + m_code_section.push_back(m_al, 0x7F); + } -// function to emit i32.lt_s instruction -void emit_i32_lt_s(Vec &code, Allocator &al) { - code.push_back(al, 0x48); -} + // function to emit i64.div_u instruction + void emit_i64_div_u() { + m_code_section.push_back(m_al, 0x80); + } -// function to emit i32.lt_u instruction -void emit_i32_lt_u(Vec &code, Allocator &al) { - code.push_back(al, 0x49); -} + // function to emit i64.rem_s instruction + void emit_i64_rem_s() { + m_code_section.push_back(m_al, 0x81); + } -// function to emit i32.gt_s instruction -void emit_i32_gt_s(Vec &code, Allocator &al) { - code.push_back(al, 0x4A); -} + // function to emit i64.rem_u instruction + void emit_i64_rem_u() { + m_code_section.push_back(m_al, 0x82); + } -// function to emit i32.gt_u instruction -void emit_i32_gt_u(Vec &code, Allocator &al) { - code.push_back(al, 0x4B); -} + // function to emit i64.and instruction + void emit_i64_and() { + m_code_section.push_back(m_al, 0x83); + } -// function to emit i32.le_s instruction -void emit_i32_le_s(Vec &code, Allocator &al) { - code.push_back(al, 0x4C); -} + // function to emit i64.or instruction + void emit_i64_or() { + m_code_section.push_back(m_al, 0x84); + } -// function to emit i32.le_u instruction -void emit_i32_le_u(Vec &code, Allocator &al) { - code.push_back(al, 0x4D); -} + // function to emit i64.xor instruction + void emit_i64_xor() { + m_code_section.push_back(m_al, 0x85); + } -// function to emit i32.ge_s instruction -void emit_i32_ge_s(Vec &code, Allocator &al) { - code.push_back(al, 0x4E); -} + // function to emit i64.shl instruction + void emit_i64_shl() { + m_code_section.push_back(m_al, 0x86); + } -// function to emit i32.ge_u instruction -void emit_i32_ge_u(Vec &code, Allocator &al) { - code.push_back(al, 0x4F); -} + // function to emit i64.shr_s instruction + void emit_i64_shr_s() { + m_code_section.push_back(m_al, 0x87); + } -// function to emit i64.eqz instruction -void emit_i64_eqz(Vec &code, Allocator &al) { - code.push_back(al, 0x50); -} + // function to emit i64.shr_u instruction + void emit_i64_shr_u() { + m_code_section.push_back(m_al, 0x88); + } -// function to emit i64.eq instruction -void emit_i64_eq(Vec &code, Allocator &al) { - code.push_back(al, 0x51); -} + // function to emit i64.rotl instruction + void emit_i64_rotl() { + m_code_section.push_back(m_al, 0x89); + } -// function to emit i64.ne instruction -void emit_i64_ne(Vec &code, Allocator &al) { - code.push_back(al, 0x52); -} + // function to emit i64.rotr instruction + void emit_i64_rotr() { + m_code_section.push_back(m_al, 0x8A); + } -// function to emit i64.lt_s instruction -void emit_i64_lt_s(Vec &code, Allocator &al) { - code.push_back(al, 0x53); -} + /******** Integer Relational Operations ********/ -// function to emit i64.lt_u instruction -void emit_i64_lt_u(Vec &code, Allocator &al) { - code.push_back(al, 0x54); -} + // function to emit i32.eqz instruction + void emit_i32_eqz() { + m_code_section.push_back(m_al, 0x45); + } -// function to emit i64.gt_s instruction -void emit_i64_gt_s(Vec &code, Allocator &al) { - code.push_back(al, 0x55); -} + // function to emit i32.eq instruction + void emit_i32_eq() { + m_code_section.push_back(m_al, 0x46); + } -// function to emit i64.gt_u instruction -void emit_i64_gt_u(Vec &code, Allocator &al) { - code.push_back(al, 0x56); -} + // function to emit i32.ne instruction + void emit_i32_ne() { + m_code_section.push_back(m_al, 0x47); + } -// function to emit i64.le_s instruction -void emit_i64_le_s(Vec &code, Allocator &al) { - code.push_back(al, 0x57); -} + // function to emit i32.lt_s instruction + void emit_i32_lt_s() { + m_code_section.push_back(m_al, 0x48); + } -// function to emit i64.le_u instruction -void emit_i64_le_u(Vec &code, Allocator &al) { - code.push_back(al, 0x58); -} + // function to emit i32.lt_u instruction + void emit_i32_lt_u() { + m_code_section.push_back(m_al, 0x49); + } -// function to emit i64.ge_s instruction -void emit_i64_ge_s(Vec &code, Allocator &al) { - code.push_back(al, 0x59); -} + // function to emit i32.gt_s instruction + void emit_i32_gt_s() { + m_code_section.push_back(m_al, 0x4A); + } -// function to emit i64.ge_u instruction -void emit_i64_ge_u(Vec &code, Allocator &al) { - code.push_back(al, 0x5A); -} + // function to emit i32.gt_u instruction + void emit_i32_gt_u() { + m_code_section.push_back(m_al, 0x4B); + } -/**************************** Floating Point Operations - * ****************************/ + // function to emit i32.le_s instruction + void emit_i32_le_s() { + m_code_section.push_back(m_al, 0x4C); + } -// function to emit a f32.const instruction -void emit_f32_const(Vec &code, Allocator &al, float x) { - code.push_back(al, 0x43); - emit_f32(code, al, x); -} + // function to emit i32.le_u instruction + void emit_i32_le_u() { + m_code_section.push_back(m_al, 0x4D); + } -// function to emit f32.abs instruction -void emit_f32_abs(Vec &code, Allocator &al) { - code.push_back(al, 0x8B); -} + // function to emit i32.ge_s instruction + void emit_i32_ge_s() { + m_code_section.push_back(m_al, 0x4E); + } -// function to emit f32.neg instruction -void emit_f32_neg(Vec &code, Allocator &al) { - code.push_back(al, 0x8C); -} + // function to emit i32.ge_u instruction + void emit_i32_ge_u() { + m_code_section.push_back(m_al, 0x4F); + } -// function to emit f32.ceil instruction -void emit_f32_ceil(Vec &code, Allocator &al) { - code.push_back(al, 0x8D); -} + // function to emit i64.eqz instruction + void emit_i64_eqz() { + m_code_section.push_back(m_al, 0x50); + } -// function to emit f32.floor instruction -void emit_f32_floor(Vec &code, Allocator &al) { - code.push_back(al, 0x8E); -} + // function to emit i64.eq instruction + void emit_i64_eq() { + m_code_section.push_back(m_al, 0x51); + } -// function to emit f32.trunc instruction -void emit_f32_trunc(Vec &code, Allocator &al) { - code.push_back(al, 0x8F); -} + // function to emit i64.ne instruction + void emit_i64_ne() { + m_code_section.push_back(m_al, 0x52); + } -// function to emit f32.nearest instruction -void emit_f32_nearest(Vec &code, Allocator &al) { - code.push_back(al, 0x90); -} + // function to emit i64.lt_s instruction + void emit_i64_lt_s() { + m_code_section.push_back(m_al, 0x53); + } -// function to emit f32.sqrt instruction -void emit_f32_sqrt(Vec &code, Allocator &al) { - code.push_back(al, 0x91); -} + // function to emit i64.lt_u instruction + void emit_i64_lt_u() { + m_code_section.push_back(m_al, 0x54); + } -// function to emit f32.add instruction -void emit_f32_add(Vec &code, Allocator &al) { - code.push_back(al, 0x92); -} + // function to emit i64.gt_s instruction + void emit_i64_gt_s() { + m_code_section.push_back(m_al, 0x55); + } -// function to emit f32.sub instruction -void emit_f32_sub(Vec &code, Allocator &al) { - code.push_back(al, 0x93); -} + // function to emit i64.gt_u instruction + void emit_i64_gt_u() { + m_code_section.push_back(m_al, 0x56); + } -// function to emit f32.mul instruction -void emit_f32_mul(Vec &code, Allocator &al) { - code.push_back(al, 0x94); -} + // function to emit i64.le_s instruction + void emit_i64_le_s() { + m_code_section.push_back(m_al, 0x57); + } -// function to emit f32.div instruction -void emit_f32_div(Vec &code, Allocator &al) { - code.push_back(al, 0x95); -} + // function to emit i64.le_u instruction + void emit_i64_le_u() { + m_code_section.push_back(m_al, 0x58); + } -// function to emit f32.min instruction -void emit_f32_min(Vec &code, Allocator &al) { - code.push_back(al, 0x96); -} + // function to emit i64.ge_s instruction + void emit_i64_ge_s() { + m_code_section.push_back(m_al, 0x59); + } -// function to emit f32.max instruction -void emit_f32_max(Vec &code, Allocator &al) { - code.push_back(al, 0x97); -} + // function to emit i64.ge_u instruction + void emit_i64_ge_u() { + m_code_section.push_back(m_al, 0x5A); + } -// function to emit f32.copysign instruction -void emit_f32_copysign(Vec &code, Allocator &al) { - code.push_back(al, 0x98); -} + /**************************** Floating Point Operations + * ****************************/ -// function to emit a f64.const instruction -void emit_f64_const(Vec &code, Allocator &al, double x) { - code.push_back(al, 0x44); - emit_f64(code, al, x); -} + // function to emit a f32.const instruction + void emit_f32_const(float x) { + m_code_section.push_back(m_al, 0x43); + emit_f32(m_code_section, m_al, x); + } -// function to emit f64.abs instruction -void emit_f64_abs(Vec &code, Allocator &al) { - code.push_back(al, 0x99); -} + // function to emit f32.abs instruction + void emit_f32_abs() { + m_code_section.push_back(m_al, 0x8B); + } -// function to emit f64.neg instruction -void emit_f64_neg(Vec &code, Allocator &al) { - code.push_back(al, 0x9A); -} + // function to emit f32.neg instruction + void emit_f32_neg() { + m_code_section.push_back(m_al, 0x8C); + } -// function to emit f64.ceil instruction -void emit_f64_ceil(Vec &code, Allocator &al) { - code.push_back(al, 0x9B); -} + // function to emit f32.ceil instruction + void emit_f32_ceil() { + m_code_section.push_back(m_al, 0x8D); + } -// function to emit f64.floor instruction -void emit_f64_floor(Vec &code, Allocator &al) { - code.push_back(al, 0x9C); -} + // function to emit f32.floor instruction + void emit_f32_floor() { + m_code_section.push_back(m_al, 0x8E); + } -// function to emit f64.trunc instruction -void emit_f64_trunc(Vec &code, Allocator &al) { - code.push_back(al, 0x9D); -} + // function to emit f32.trunc instruction + void emit_f32_trunc() { + m_code_section.push_back(m_al, 0x8F); + } -// function to emit f64.nearest instruction -void emit_f64_nearest(Vec &code, Allocator &al) { - code.push_back(al, 0x9E); -} + // function to emit f32.nearest instruction + void emit_f32_nearest() { + m_code_section.push_back(m_al, 0x90); + } -// function to emit f64.sqrt instruction -void emit_f64_sqrt(Vec &code, Allocator &al) { - code.push_back(al, 0x9F); -} + // function to emit f32.sqrt instruction + void emit_f32_sqrt() { + m_code_section.push_back(m_al, 0x91); + } -// function to emit f64.add instruction -void emit_f64_add(Vec &code, Allocator &al) { - code.push_back(al, 0xA0); -} + // function to emit f32.add instruction + void emit_f32_add() { + m_code_section.push_back(m_al, 0x92); + } -// function to emit f64.sub instruction -void emit_f64_sub(Vec &code, Allocator &al) { - code.push_back(al, 0xA1); -} + // function to emit f32.sub instruction + void emit_f32_sub() { + m_code_section.push_back(m_al, 0x93); + } -// function to emit f64.mul instruction -void emit_f64_mul(Vec &code, Allocator &al) { - code.push_back(al, 0xA2); -} + // function to emit f32.mul instruction + void emit_f32_mul() { + m_code_section.push_back(m_al, 0x94); + } -// function to emit f64.div instruction -void emit_f64_div(Vec &code, Allocator &al) { - code.push_back(al, 0xA3); -} + // function to emit f32.div instruction + void emit_f32_div() { + m_code_section.push_back(m_al, 0x95); + } -// function to emit f64.min instruction -void emit_f64_min(Vec &code, Allocator &al) { - code.push_back(al, 0xA4); -} + // function to emit f32.min instruction + void emit_f32_min() { + m_code_section.push_back(m_al, 0x96); + } -// function to emit f64.max instruction -void emit_f64_max(Vec &code, Allocator &al) { - code.push_back(al, 0xA5); -} + // function to emit f32.max instruction + void emit_f32_max() { + m_code_section.push_back(m_al, 0x97); + } -// function to emit f64.copysign instruction -void emit_f64_copysign(Vec &code, Allocator &al) { - code.push_back(al, 0xA6); -} + // function to emit f32.copysign instruction + void emit_f32_copysign() { + m_code_section.push_back(m_al, 0x98); + } -/******** Float Relational Operations ********/ + // function to emit a f64.const instruction + void emit_f64_const(double x) { + m_code_section.push_back(m_al, 0x44); + emit_f64(m_code_section, m_al, x); + } -// function to emit f32.eq instruction -void emit_f32_eq(Vec &code, Allocator &al) { - code.push_back(al, 0x5B); -} + // function to emit f64.abs instruction + void emit_f64_abs() { + m_code_section.push_back(m_al, 0x99); + } -// function to emit f32.ne instruction -void emit_f32_ne(Vec &code, Allocator &al) { - code.push_back(al, 0x5C); -} + // function to emit f64.neg instruction + void emit_f64_neg() { + m_code_section.push_back(m_al, 0x9A); + } -// function to emit f32.lt instruction -void emit_f32_lt(Vec &code, Allocator &al) { - code.push_back(al, 0x5D); -} + // function to emit f64.ceil instruction + void emit_f64_ceil() { + m_code_section.push_back(m_al, 0x9B); + } -// function to emit f32.gt instruction -void emit_f32_gt(Vec &code, Allocator &al) { - code.push_back(al, 0x5E); -} + // function to emit f64.floor instruction + void emit_f64_floor() { + m_code_section.push_back(m_al, 0x9C); + } -// function to emit f32.le instruction -void emit_f32_le(Vec &code, Allocator &al) { - code.push_back(al, 0x5F); -} + // function to emit f64.trunc instruction + void emit_f64_trunc() { + m_code_section.push_back(m_al, 0x9D); + } -// function to emit f32.ge instruction -void emit_f32_ge(Vec &code, Allocator &al) { - code.push_back(al, 0x60); -} + // function to emit f64.nearest instruction + void emit_f64_nearest() { + m_code_section.push_back(m_al, 0x9E); + } -// function to emit f64.eq instruction -void emit_f64_eq(Vec &code, Allocator &al) { - code.push_back(al, 0x61); -} + // function to emit f64.sqrt instruction + void emit_f64_sqrt() { + m_code_section.push_back(m_al, 0x9F); + } -// function to emit f64.ne instruction -void emit_f64_ne(Vec &code, Allocator &al) { - code.push_back(al, 0x62); -} + // function to emit f64.add instruction + void emit_f64_add() { + m_code_section.push_back(m_al, 0xA0); + } -// function to emit f64.lt instruction -void emit_f64_lt(Vec &code, Allocator &al) { - code.push_back(al, 0x63); -} + // function to emit f64.sub instruction + void emit_f64_sub() { + m_code_section.push_back(m_al, 0xA1); + } -// function to emit f64.gt instruction -void emit_f64_gt(Vec &code, Allocator &al) { - code.push_back(al, 0x64); -} + // function to emit f64.mul instruction + void emit_f64_mul() { + m_code_section.push_back(m_al, 0xA2); + } -// function to emit f64.le instruction -void emit_f64_le(Vec &code, Allocator &al) { - code.push_back(al, 0x65); -} + // function to emit f64.div instruction + void emit_f64_div() { + m_code_section.push_back(m_al, 0xA3); + } -// function to emit f64.ge instruction -void emit_f64_ge(Vec &code, Allocator &al) { - code.push_back(al, 0x66); -} + // function to emit f64.min instruction + void emit_f64_min() { + m_code_section.push_back(m_al, 0xA4); + } -// function to emit string -void emit_str_const(Vec &code, Allocator &al, uint32_t mem_idx, - const std::string &text) { - emit_u32(code, al, - 0U); // for active mode of memory with default mem_idx of 0 - emit_i32_const( - code, al, - (int32_t)mem_idx); // specifying memory location as instructions - emit_expr_end(code, al); // end instructions - emit_str(code, al, text); -} + // function to emit f64.max instruction + void emit_f64_max() { + m_code_section.push_back(m_al, 0xA5); + } -void emit_unreachable(Vec &code, Allocator &al) { - code.push_back(al, 0x00); -} + // function to emit f64.copysign instruction + void emit_f64_copysign() { + m_code_section.push_back(m_al, 0xA6); + } -void emit_branch(Vec &code, Allocator &al, uint32_t label_idx) { - code.push_back(al, 0x0C); - emit_u32(code, al, label_idx); -} + /******** Float Relational Operations ********/ -void emit_branch_if(Vec &code, Allocator &al, uint32_t label_idx) { - code.push_back(al, 0x0D); - emit_u32(code, al, label_idx); -} + // function to emit f32.eq instruction + void emit_f32_eq() { + m_code_section.push_back(m_al, 0x5B); + } -void save_js_glue(std::string filename) { - std::string js_glue = - R"(function define_imports(memory, outputBuffer, exit_code, stdout_print) { - const printNum = (num) => outputBuffer.push(num.toString()); - const printStr = (startIdx, strSize) => outputBuffer.push( - new TextDecoder("utf8").decode(new Uint8Array(memory.buffer, startIdx, strSize))); - const flushBuffer = () => { - stdout_print(outputBuffer.join(" ") + "\n"); - outputBuffer.length = 0; - } - const set_exit_code = (exit_code_val) => exit_code.val = exit_code_val; - const cpu_time = (time) => (Date.now() / 1000); // Date.now() returns milliseconds, so divide by 1000 - var imports = { - js: { - memory: memory, - /* functions */ - print_i32: printNum, - print_i64: printNum, - print_f32: printNum, - print_f64: printNum, - print_str: printStr, - flush_buf: flushBuffer, - set_exit_code: set_exit_code, - cpu_time: cpu_time - }, - }; - return imports; -} + // function to emit f32.ne instruction + void emit_f32_ne() { + m_code_section.push_back(m_al, 0x5C); + } -async function run_wasm(bytes, imports) { - try { - var res = await WebAssembly.instantiate(bytes, imports); - const { _lcompilers_main } = res.instance.exports; - _lcompilers_main(); - } catch(e) { console.log(e); } -} + // function to emit f32.lt instruction + void emit_f32_lt() { + m_code_section.push_back(m_al, 0x5D); + } -async function execute_code(bytes, stdout_print) { - var exit_code = {val: 1}; /* non-zero exit code */ - var outputBuffer = []; - var memory = new WebAssembly.Memory({ initial: 100, maximum: 100 }); // fixed 6.4 Mb memory currently - var imports = define_imports(memory, outputBuffer, exit_code, stdout_print); - await run_wasm(bytes, imports); - return exit_code.val; -} + // function to emit f32.gt instruction + void emit_f32_gt() { + m_code_section.push_back(m_al, 0x5E); + } -function main() { - const fs = require("fs"); - const wasmBuffer = fs.readFileSync(")" + - filename + R"("); - execute_code(wasmBuffer, (text) => process.stdout.write(text)) - .then((exit_code) => { - process.exit(exit_code); - }) - .catch((e) => console.log(e)) -} + // function to emit f32.le instruction + void emit_f32_le() { + m_code_section.push_back(m_al, 0x5F); + } -main(); -)"; - filename += ".js"; - std::ofstream out(filename); - out << js_glue; - out.close(); -} + // function to emit f32.ge instruction + void emit_f32_ge() { + m_code_section.push_back(m_al, 0x60); + } -void save_js_glue_wasi(std::string filename) { - std::string js_glue = -R"(async function main() { - const fs = require("fs"); - const { WASI } = require("wasi"); - const wasi = new WASI(); - const importObject = { - wasi_snapshot_preview1: wasi.wasiImport, - js: { - cpu_time: (time) => (Date.now() / 1000) // Date.now() returns milliseconds, so divide by 1000 - } - }; - const wasm = await WebAssembly.compile(fs.readFileSync(")" + filename + R"(")); - const instance = await WebAssembly.instantiate(wasm, importObject); - wasi.start(instance); -} -main(); -)"; - filename += ".js"; - std::ofstream out(filename); - out << js_glue; - out.close(); -} + // function to emit f64.eq instruction + void emit_f64_eq() { + m_code_section.push_back(m_al, 0x61); + } -void save_bin(Vec &code, std::string filename) { - std::ofstream out(filename); - out.write((const char *)code.p, code.size()); - out.close(); - save_js_glue_wasi(filename); -} + // function to emit f64.ne instruction + void emit_f64_ne() { + m_code_section.push_back(m_al, 0x62); + } -/**************************** Type Conversion Operations - * ****************************/ + // function to emit f64.lt instruction + void emit_f64_lt() { + m_code_section.push_back(m_al, 0x63); + } -// function to emit i32.wrap_i64 instruction -void emit_i32_wrap_i64(Vec &code, Allocator &al) { - code.push_back(al, 0xA7); -} + // function to emit f64.gt instruction + void emit_f64_gt() { + m_code_section.push_back(m_al, 0x64); + } -// function to emit i32.trunc_f32_s instruction -void emit_i32_trunc_f32_s(Vec &code, Allocator &al) { - code.push_back(al, 0xA8); -} + // function to emit f64.le instruction + void emit_f64_le() { + m_code_section.push_back(m_al, 0x65); + } -// function to emit i32.trunc_f32_u instruction -void emit_i32_trunc_f32_u(Vec &code, Allocator &al) { - code.push_back(al, 0xA9); -} + // function to emit f64.ge instruction + void emit_f64_ge() { + m_code_section.push_back(m_al, 0x66); + } -// function to emit i32.trunc_f64_s instruction -void emit_i32_trunc_f64_s(Vec &code, Allocator &al) { - code.push_back(al, 0xAA); -} + void emit_unreachable() { + m_code_section.push_back(m_al, 0x00); + } -// function to emit i32.trunc_f64_u instruction -void emit_i32_trunc_f64_u(Vec &code, Allocator &al) { - code.push_back(al, 0xAB); -} + void emit_branch(uint32_t label_idx) { + m_code_section.push_back(m_al, 0x0C); + emit_u32(m_code_section, m_al, label_idx); + } -// function to emit i64.extend_i32_s instruction -void emit_i64_extend_i32_s(Vec &code, Allocator &al) { - code.push_back(al, 0xAC); -} + void emit_branch_if(uint32_t label_idx) { + m_code_section.push_back(m_al, 0x0D); + emit_u32(m_code_section, m_al, label_idx); + } -// function to emit i64.extend_i32_u instruction -void emit_i64_extend_i32_u(Vec &code, Allocator &al) { - code.push_back(al, 0xAD); -} + // function to emit string + void emit_str_const(uint32_t mem_idx, + const std::string &text) { + emit_u32(m_data_section, m_al, + 0U); // for active mode of memory with default mem_idx of 0 + emit_i32_const( + m_data_section, m_al, + (int32_t)mem_idx); // specifying memory location as instructions + emit_expr_end(m_data_section, al); // end instructions + emit_str(m_data_section, m_al, text); + } -// function to emit i64.trunc_f32_s instruction -void emit_i64_trunc_f32_s(Vec &code, Allocator &al) { - code.push_back(al, 0xAE); -} + void save_js_glue(std::string filename) { + std::string js_glue = + R"(function define_imports(memory, outputBuffer, exit_code, stdout_print) { + const printNum = (num) => outputBuffer.push(num.toString()); + const printStr = (startIdx, strSize) => outputBuffer.push( + new TextDecoder("utf8").decode(new Uint8Array(memory.buffer, startIdx, strSize))); + const flushBuffer = () => { + stdout_print(outputBuffer.join(" ") + "\n"); + outputBuffer.length = 0; + } + const set_exit_code = (exit_code_val) => exit_code.val = exit_code_val; + const cpu_time = (time) => (Date.now() / 1000); // Date.now() returns milliseconds, so divide by 1000 + var imports = { + js: { + memory: memory, + /* functions */ + print_i32: printNum, + print_i64: printNum, + print_f32: printNum, + print_f64: printNum, + print_str: printStr, + flush_buf: flushBuffer, + set_exit_code: set_exit_code, + cpu_time: cpu_time + }, + }; + return imports; + } -// function to emit i64.trunc_f32_u instruction -void emit_i64_trunc_f32_u(Vec &code, Allocator &al) { - code.push_back(al, 0xAF); -} + async function run_wasm(bytes, imports) { + try { + var res = await WebAssembly.instantiate(bytes, imports); + const { _lcompilers_main } = res.instance.exports; + _lcompilers_main(); + } catch(e) { console.log(e); } + } -// function to emit i64.trunc_f64_s instruction -void emit_i64_trunc_f64_s(Vec &code, Allocator &al) { - code.push_back(al, 0xB0); -} + async function execute_code(bytes, stdout_print) { + var exit_code = {val: 1}; /* non-zero exit code */ + var outputBuffer = []; + var memory = new WebAssembly.Memory({ initial: 100, maximum: 100 }); // fixed 6.4 Mb memory currently + var imports = define_imports(memory, outputBuffer, exit_code, stdout_print); + await run_wasm(bytes, imports); + return exit_code.val; + } -// function to emit i64.trunc_f64_u instruction -void emit_i64_trunc_f64_u(Vec &code, Allocator &al) { - code.push_back(al, 0xB1); -} + function main() { + const fs = require("fs"); + const wasmBuffer = fs.readFileSync(")" + + filename + R"("); + execute_code(wasmBuffer, (text) => process.stdout.write(text)) + .then((exit_code) => { + process.exit(exit_code); + }) + .catch((e) => console.log(e)) + } -// function to emit f32.convert_i32_s instruction -void emit_f32_convert_i32_s(Vec &code, Allocator &al) { - code.push_back(al, 0xB2); -} + main(); + )"; + filename += ".js"; + std::ofstream out(filename); + out << js_glue; + out.close(); + } -// function to emit f32.convert_i32_u instruction -void emit_f32_convert_i32_u(Vec &code, Allocator &al) { - code.push_back(al, 0xB3); -} + void save_js_glue_wasi(std::string filename) { + std::string js_glue = + R"(async function main() { + const fs = require("fs"); + const { WASI } = require("wasi"); + const wasi = new WASI(); + const importObject = { + wasi_snapshot_preview1: wasi.wasiImport, + js: { + cpu_time: (time) => (Date.now() / 1000) // Date.now() returns milliseconds, so divide by 1000 + } + }; + const wasm = await WebAssembly.compile(fs.readFileSync(")" + filename + R"(")); + const instance = await WebAssembly.instantiate(wasm, importObject); + wasi.start(instance); + } + main(); + )"; + filename += ".js"; + std::ofstream out(filename); + out << js_glue; + out.close(); + } -// function to emit f32.convert_i64_s instruction -void emit_f32_convert_i64_s(Vec &code, Allocator &al) { - code.push_back(al, 0xB4); -} + void save_bin(Vec &code, std::string filename) { + std::ofstream out(filename); + out.write((const char *)code.p, code.size()); + out.close(); + save_js_glue_wasi(filename); + } -// function to emit f32.convert_i64_u instruction -void emit_f32_convert_i64_u(Vec &code, Allocator &al) { - code.push_back(al, 0xB5); -} + /**************************** Type Conversion Operations + * ****************************/ -// function to emit f32.demote_f64 instruction -void emit_f32_demote_f64(Vec &code, Allocator &al) { - code.push_back(al, 0xB6); -} + // function to emit i32.wrap_i64 instruction + void emit_i32_wrap_i64() { + m_code_section.push_back(m_al, 0xA7); + } -// function to emit f64.convert_i32_s instruction -void emit_f64_convert_i32_s(Vec &code, Allocator &al) { - code.push_back(al, 0xB7); -} + // function to emit i32.trunc_f32_s instruction + void emit_i32_trunc_f32_s() { + m_code_section.push_back(m_al, 0xA8); + } -// function to emit f64.convert_i32_u instruction -void emit_f64_convert_i32_u(Vec &code, Allocator &al) { - code.push_back(al, 0xB8); -} + // function to emit i32.trunc_f32_u instruction + void emit_i32_trunc_f32_u() { + m_code_section.push_back(m_al, 0xA9); + } -// function to emit f64.convert_i64_s instruction -void emit_f64_convert_i64_s(Vec &code, Allocator &al) { - code.push_back(al, 0xB9); -} + // function to emit i32.trunc_f64_s instruction + void emit_i32_trunc_f64_s() { + m_code_section.push_back(m_al, 0xAA); + } -// function to emit f64.convert_i64_u instruction -void emit_f64_convert_i64_u(Vec &code, Allocator &al) { - code.push_back(al, 0xBA); -} + // function to emit i32.trunc_f64_u instruction + void emit_i32_trunc_f64_u() { + m_code_section.push_back(m_al, 0xAB); + } -// function to emit f64.promote_f32 instruction -void emit_f64_promote_f32(Vec &code, Allocator &al) { - code.push_back(al, 0xBB); -} + // function to emit i64.extend_i32_s instruction + void emit_i64_extend_i32_s() { + m_code_section.push_back(m_al, 0xAC); + } -// function to emit i32.reinterpret_f32 instruction -void emit_i32_reinterpret_f32(Vec &code, Allocator &al) { - code.push_back(al, 0xBC); -} + // function to emit i64.extend_i32_u instruction + void emit_i64_extend_i32_u() { + m_code_section.push_back(m_al, 0xAD); + } -// function to emit i64.reinterpret_f64 instruction -void emit_i64_reinterpret_f64(Vec &code, Allocator &al) { - code.push_back(al, 0xBD); -} + // function to emit i64.trunc_f32_s instruction + void emit_i64_trunc_f32_s() { + m_code_section.push_back(m_al, 0xAE); + } -// function to emit f32.reinterpret_i32 instruction -void emit_f32_reinterpret_i32(Vec &code, Allocator &al) { - code.push_back(al, 0xBE); -} + // function to emit i64.trunc_f32_u instruction + void emit_i64_trunc_f32_u() { + m_code_section.push_back(m_al, 0xAF); + } -// function to emit f64.reinterpret_i64 instruction -void emit_f64_reinterpret_i64(Vec &code, Allocator &al) { - code.push_back(al, 0xBF); -} + // function to emit i64.trunc_f64_s instruction + void emit_i64_trunc_f64_s() { + m_code_section.push_back(m_al, 0xB0); + } -// function to emit i32.extend8_s instruction -void emit_i32_extend8_s(Vec &code, Allocator &al) { - code.push_back(al, 0xC0); -} + // function to emit i64.trunc_f64_u instruction + void emit_i64_trunc_f64_u() { + m_code_section.push_back(m_al, 0xB1); + } -// function to emit i32.extend16_s instruction -void emit_i32_extend16_s(Vec &code, Allocator &al) { - code.push_back(al, 0xC1); -} + // function to emit f32.convert_i32_s instruction + void emit_f32_convert_i32_s() { + m_code_section.push_back(m_al, 0xB2); + } -// function to emit i64.extend8_s instruction -void emit_i64_extend8_s(Vec &code, Allocator &al) { - code.push_back(al, 0xC2); -} + // function to emit f32.convert_i32_u instruction + void emit_f32_convert_i32_u() { + m_code_section.push_back(m_al, 0xB3); + } -// function to emit i64.extend16_s instruction -void emit_i64_extend16_s(Vec &code, Allocator &al) { - code.push_back(al, 0xC3); -} + // function to emit f32.convert_i64_s instruction + void emit_f32_convert_i64_s() { + m_code_section.push_back(m_al, 0xB4); + } -// function to emit i64.extend32_s instruction -void emit_i64_extend32_s(Vec &code, Allocator &al) { - code.push_back(al, 0xC4); -} + // function to emit f32.convert_i64_u instruction + void emit_f32_convert_i64_u() { + m_code_section.push_back(m_al, 0xB5); + } -/**************************** Memory Instructions ****************************/ + // function to emit f32.demote_f64 instruction + void emit_f32_demote_f64() { + m_code_section.push_back(m_al, 0xB6); + } -// function to emit i32.load instruction -void emit_i32_load(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x28); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit f64.convert_i32_s instruction + void emit_f64_convert_i32_s() { + m_code_section.push_back(m_al, 0xB7); + } -// function to emit i64.load instruction -void emit_i64_load(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x29); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit f64.convert_i32_u instruction + void emit_f64_convert_i32_u() { + m_code_section.push_back(m_al, 0xB8); + } -// function to emit f32.load instruction -void emit_f32_load(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x2A); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit f64.convert_i64_s instruction + void emit_f64_convert_i64_s() { + m_code_section.push_back(m_al, 0xB9); + } -// function to emit f64.load instruction -void emit_f64_load(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x2B); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit f64.convert_i64_u instruction + void emit_f64_convert_i64_u() { + m_code_section.push_back(m_al, 0xBA); + } -// function to emit i32.load8_s instruction -void emit_i32_load8_s(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x2C); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit f64.promote_f32 instruction + void emit_f64_promote_f32() { + m_code_section.push_back(m_al, 0xBB); + } -// function to emit i32.load8_u instruction -void emit_i32_load8_u(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x2D); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit i32.reinterpret_f32 instruction + void emit_i32_reinterpret_f32() { + m_code_section.push_back(m_al, 0xBC); + } -// function to emit i32.load16_s instruction -void emit_i32_load16_s(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x2E); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit i64.reinterpret_f64 instruction + void emit_i64_reinterpret_f64() { + m_code_section.push_back(m_al, 0xBD); + } -// function to emit i32.load16_u instruction -void emit_i32_load16_u(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x2F); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit f32.reinterpret_i32 instruction + void emit_f32_reinterpret_i32() { + m_code_section.push_back(m_al, 0xBE); + } -// function to emit i64.load8_s instruction -void emit_i64_load8_s(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x30); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit f64.reinterpret_i64 instruction + void emit_f64_reinterpret_i64() { + m_code_section.push_back(m_al, 0xBF); + } -// function to emit i64.load8_u instruction -void emit_i64_load8_u(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x31); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit i32.extend8_s instruction + void emit_i32_extend8_s() { + m_code_section.push_back(m_al, 0xC0); + } -// function to emit i64.load16_s instruction -void emit_i64_load16_s(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x32); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit i32.extend16_s instruction + void emit_i32_extend16_s() { + m_code_section.push_back(m_al, 0xC1); + } -// function to emit i64.load16_u instruction -void emit_i64_load16_u(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x33); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit i64.extend8_s instruction + void emit_i64_extend8_s() { + m_code_section.push_back(m_al, 0xC2); + } -// function to emit i64.load32_s instruction -void emit_i64_load32_s(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x34); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit i64.extend16_s instruction + void emit_i64_extend16_s() { + m_code_section.push_back(m_al, 0xC3); + } -// function to emit i64.load32_u instruction -void emit_i64_load32_u(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x35); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit i64.extend32_s instruction + void emit_i64_extend32_s() { + m_code_section.push_back(m_al, 0xC4); + } + + /**************************** Memory Instructions ****************************/ -// function to emit i32.store instruction -void emit_i32_store(Vec &code, Allocator &al, uint32_t mem_align, + // function to emit i32.load instruction + void emit_i32_load(uint32_t mem_align, uint32_t mem_offset) { - emit_b8(code, al, 0x36); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + emit_b8(m_code_section, m_al, 0x28); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } -// function to emit i64.store instruction -void emit_i64_store(Vec &code, Allocator &al, uint32_t mem_align, + // function to emit i64.load instruction + void emit_i64_load(uint32_t mem_align, uint32_t mem_offset) { - emit_b8(code, al, 0x37); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + emit_b8(m_code_section, m_al, 0x29); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } -// function to emit f32.store instruction -void emit_f32_store(Vec &code, Allocator &al, uint32_t mem_align, + // function to emit f32.load instruction + void emit_f32_load(uint32_t mem_align, uint32_t mem_offset) { - emit_b8(code, al, 0x38); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + emit_b8(m_code_section, m_al, 0x2A); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } -// function to emit f64.store instruction -void emit_f64_store(Vec &code, Allocator &al, uint32_t mem_align, + // function to emit f64.load instruction + void emit_f64_load(uint32_t mem_align, uint32_t mem_offset) { - emit_b8(code, al, 0x39); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + emit_b8(m_code_section, m_al, 0x2B); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } -// function to emit i32.store8 instruction -void emit_i32_store8(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x3A); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit i32.load8_s instruction + void emit_i32_load8_s(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x2C); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } -// function to emit i32.store16 instruction -void emit_i32_store16(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x3B); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit i32.load8_u instruction + void emit_i32_load8_u(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x2D); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } -// function to emit i64.store8 instruction -void emit_i64_store8(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x3C); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit i32.load16_s instruction + void emit_i32_load16_s(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x2E); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } -// function to emit i64.store16 instruction -void emit_i64_store16(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x3D); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit i32.load16_u instruction + void emit_i32_load16_u(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x2F); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } -// function to emit i64.store32 instruction -void emit_i64_store32(Vec &code, Allocator &al, uint32_t mem_align, - uint32_t mem_offset) { - emit_b8(code, al, 0x3E); - emit_u32(code, al, mem_align); - emit_u32(code, al, mem_offset); -} + // function to emit i64.load8_s instruction + void emit_i64_load8_s(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x30); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit i64.load8_u instruction + void emit_i64_load8_u(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x31); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit i64.load16_s instruction + void emit_i64_load16_s(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x32); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit i64.load16_u instruction + void emit_i64_load16_u(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x33); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit i64.load32_s instruction + void emit_i64_load32_s(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x34); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit i64.load32_u instruction + void emit_i64_load32_u(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x35); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit i32.store instruction + void emit_i32_store(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x36); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit i64.store instruction + void emit_i64_store(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x37); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit f32.store instruction + void emit_f32_store(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x38); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit f64.store instruction + void emit_f64_store(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x39); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit i32.store8 instruction + void emit_i32_store8(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x3A); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit i32.store16 instruction + void emit_i32_store16(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x3B); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit i64.store8 instruction + void emit_i64_store8(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x3C); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit i64.store16 instruction + void emit_i64_store16(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x3D); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit i64.store32 instruction + void emit_i64_store32(uint32_t mem_align, + uint32_t mem_offset) { + emit_b8(m_code_section, m_al, 0x3E); + emit_u32(m_code_section, m_al, mem_align); + emit_u32(m_code_section, m_al, mem_offset); + } + + // function to emit a i32.const instruction given a section reference + void emit_i32_const(Vec &code, int32_t x) { + code.push_back(m_al, 0x41); + emit_i32(code, m_al, x); + } + + // function to emit a i64.const instruction given a section reference + void emit_i64_const(Vec &code, int32_t x) { + code.push_back(m_al, 0x42); + emit_i32(code, m_al, x); + } + + // function to emit a f32.const instruction given a section reference + void emit_f32_const(Vec &code, int32_t x) { + code.push_back(m_al, 0x43); + emit_i32(code, m_al, x); + } + + // function to emit a f64.const instruction given a section reference + void emit_f64_const(Vec &code, int32_t x) { + code.push_back(m_al, 0x44); + emit_i32(code, m_al, x); + } -} // namespace wasm +} // class WASMAssembler } // namespace LCompilers From 3fbc9af4571929e5ebfd6ae1fe8e7fc50ef53f9d Mon Sep 17 00:00:00 2001 From: Shaikh Ubaid Date: Sat, 1 Apr 2023 23:02:39 +0530 Subject: [PATCH 2/2] tmp --- src/libasr/codegen/asr_to_wasm.cpp | 29 ++++++++++++++--------------- src/libasr/codegen/wasm_assembler.h | 4 ++-- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/libasr/codegen/asr_to_wasm.cpp b/src/libasr/codegen/asr_to_wasm.cpp index 394a96bca7..95fa47c76c 100644 --- a/src/libasr/codegen/asr_to_wasm.cpp +++ b/src/libasr/codegen/asr_to_wasm.cpp @@ -98,7 +98,7 @@ std::string import_fn_to_str(IMPORT_FUNC fn) { class ASRToWASMVisitor : public ASR::BaseVisitor { public: Allocator &m_al; - WASMAssembler m_wa; + WASMAssembler &m_wa; diag::Diagnostics &diag; SymbolFuncInfo *cur_sym_info; @@ -120,8 +120,8 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { std::vector m_rt_func_used_idx; public: - ASRToWASMVisitor(Allocator &al, diag::Diagnostics &diagnostics) - : m_al(al), diag(diagnostics) { + ASRToWASMVisitor(WASMAssembler &wa, Allocator &al, diag::Diagnostics &diagnostics) + : m_wa(wa), m_al(al), diag(diagnostics) { is_prototype_only = false; is_local_vars_only = false; main_func = nullptr; @@ -967,37 +967,37 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { /********************* Parameter Types List *********************/ s->referenced_vars.reserve(m_al, x.n_args); uint32_t len_idx_type_section_param_types_list = - wasm::emit_len_placeholder(m_type_section, m_al); + m_wa.emit_len_placeholder(m_wa.m_type_section, m_al); for (size_t i = 0; i < x.n_args; i++) { ASR::Variable_t *arg = ASRUtils::EXPR2VAR(x.m_args[i]); LCOMPILERS_ASSERT(ASRUtils::is_arg_dummy(arg->m_intent)); m_var_idx_map[get_hash((ASR::asr_t *)arg)] = s->no_of_variables; - emit_var_type(m_type_section, arg, s->no_of_variables, false); + emit_var_type(m_wa.m_type_section, arg, s->no_of_variables, false); if (isRefVar(arg)) { s->referenced_vars.push_back(m_al, arg); } } - wasm::fixup_len(m_type_section, m_al, + m_wa.fixup_len(m_wa.m_type_section, m_al, len_idx_type_section_param_types_list); /********************* Result Types List *********************/ - uint32_t len_idx_type_section_return_types_list = wasm::emit_len_placeholder(m_type_section, m_al); + uint32_t len_idx_type_section_return_types_list = m_wa.emit_len_placeholder(m_wa.m_type_section, m_al); uint32_t no_of_return_vars = 0; if (x.m_return_var) { // It is a function s->return_var = ASRUtils::EXPR2VAR(x.m_return_var); - emit_var_type(m_type_section, s->return_var, no_of_return_vars, false); + emit_var_type(m_wa.m_type_section, s->return_var, no_of_return_vars, false); } else { // It is a subroutine for (size_t i = 0; i < x.n_args; i++) { ASR::Variable_t *arg = ASRUtils::EXPR2VAR(x.m_args[i]); if (isRefVar(arg)) { - emit_var_type(m_type_section, arg, no_of_return_vars, false); + emit_var_type(m_wa.m_type_section, arg, no_of_return_vars, false); } } } - wasm::fixup_len(m_type_section, m_al, len_idx_type_section_return_types_list); + wasm::fixup_len(m_wa.m_type_section, m_al, len_idx_type_section_return_types_list); /********************* Add Type to Map *********************/ - s->index = no_of_types++; + s->index = m_wa.no_of_types++; m_func_name_idx_map[get_hash((ASR::asr_t *)&x)] = s; // add function to map } @@ -2995,8 +2995,8 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { Result> asr_to_wasm_bytes_stream(ASR::TranslationUnit_t &asr, Allocator &al, diag::Diagnostics &diagnostics) { - ASRToWASMVisitor v(al, diagnostics); - Vec wasm_bytes; + WASMAssembler wa(al); + ASRToWASMVisitor v(wa, al, diagnostics); LCompilers::PassOptions pass_options; pass_array_by_data(al, asr, pass_options); @@ -3017,8 +3017,7 @@ Result> asr_to_wasm_bytes_stream(ASR::TranslationUnit_t &asr, return Error(); } - v.get_wasm(wasm_bytes); - + Vec wasm_bytes = wa.get_wasm(); return wasm_bytes; } diff --git a/src/libasr/codegen/wasm_assembler.h b/src/libasr/codegen/wasm_assembler.h index c673fabb8e..60f1a4065e 100644 --- a/src/libasr/codegen/wasm_assembler.h +++ b/src/libasr/codegen/wasm_assembler.h @@ -94,7 +94,7 @@ static void emit_u32_b32_idx(Vec &code, Allocator &al, uint32_t idx, } } -class WASMAssembler { +class zWASMAssembler { private: Allocator &m_al; @@ -186,7 +186,7 @@ class WASMAssembler { uint32_t nesting_level; uint32_t cur_loop_nesting_level; - WASMAssembler(Allocator &al, size_t reserve_mem = (1024 * 128)) { + WASMAssembler(Allocator &al, size_t reserve_mem = (1024 * 128)): m_al(al) { no_of_types = 0; no_of_functions = 0; no_of_memories = 0;