diff --git a/src/libasr/codegen/asr_to_wasm.cpp b/src/libasr/codegen/asr_to_wasm.cpp index be632c335b..5f39757010 100644 --- a/src/libasr/codegen/asr_to_wasm.cpp +++ b/src/libasr/codegen/asr_to_wasm.cpp @@ -21,7 +21,7 @@ #define INCLUDE_RUNTIME_FUNC(fn) \ if (m_rt_func_used_idx[fn] == -1) { \ - m_rt_func_used_idx[fn] = no_of_types++; \ + m_rt_func_used_idx[fn] = rt_funcs_seq_order++; \ } \ // #define SHOW_ASR @@ -61,7 +61,7 @@ struct SymbolFuncInfo { bool needs_declaration = true; bool intrinsic_function = false; uint32_t index = 0; - uint32_t no_of_variables = 0; + uint32_t no_of_params = 0; ASR::Variable_t *return_var = nullptr; Vec referenced_vars; }; @@ -77,9 +77,8 @@ enum RT_FUNCS { mul_c64 = 7, abs_c32 = 9, abs_c64 = 10, - rt_funcs_last = 11, // keep this as the last enumerator + NO_OF_RT_FUNCS = 11, // keep this as the last enumerator }; -const int NO_OF_RT_FUNCS = rt_funcs_last; enum GLOBAL_VAR { cur_mem_loc = 0, @@ -87,13 +86,13 @@ enum GLOBAL_VAR { tmp_reg_i64 = 2, tmp_reg_f32 = 3, tmp_reg_f64 = 4, - global_vars_cnt = 5 + GLOBAL_VARS_CNT = 5 }; enum IMPORT_FUNC { proc_exit = 0, fd_write = 1, - import_funcs_cnt = 2 + IMPORT_FUNCS_CNT = 2 }; std::string import_fn_to_str(IMPORT_FUNC fn) { @@ -110,34 +109,17 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { 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; - WASM_INSTS_VISITOR::WASMInstsAssembler wia; - - 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; + WASMAssembler m_wa; + std::vector local_vars; + uint32_t avail_mem_loc; uint32_t digits_mem_loc; - uint32_t min_no_pages; uint32_t max_no_pages; + uint32_t rt_funcs_seq_order; std::map m_var_idx_map; std::map m_global_var_idx_map; @@ -146,89 +128,43 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { std::vector m_compiler_globals; std::vector m_import_func_idx_map; - std::vector m_rt_funcs_map; + std::vector m_rt_funcs_map; std::vector m_rt_func_used_idx; public: ASRToWASMVisitor(Allocator &al, diag::Diagnostics &diagnostics) - : m_al(al), diag(diagnostics), wia(al, m_code_section) { + : m_al(al), diag(diagnostics), m_wa(al) { is_prototype_only = false; is_local_vars_only = false; 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_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); + std::vector param_types, + std::vector result_types) { + int func_idx = m_wa.emit_func_type(param_types, result_types); 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++; emit_function_prototype(*fn); + m_wa.emit_import_fn("js", fn->m_name, + m_func_name_idx_map[get_hash((ASR::asr_t*) fn)]->index); } void emit_imports(SymbolTable *global_scope) { @@ -247,451 +183,339 @@ 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); - } - - 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. - wia.emit_br(nesting_level - cur_loop_nesting_level - 1); // emit_branch and label the loop - }, [&](){}); - - nesting_level--; - wasm::emit_expr_end(m_code_section, m_al); - 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) { + void emit_print_int() { using namespace wasm; - define_emit_func({i64}, {}, {i64, i64, i64, i64}, "print_i64", [&](){ + m_wa.define_func({i64}, {}, {i64, i64, i64, 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([&](){ - wia.emit_local_get(0); - wia.emit_i64_const(0); - wia.emit_i64_eq(); + 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); - wia.emit_return(); + m_wa.emit_return(); }, [&](){}); - emit_if_else([&](){ - wia.emit_local_get(0); - wia.emit_i64_const(0); - wia.emit_i64_lt_s(); + 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); - wia.emit_local_get(0); - wia.emit_i64_const(-1); - wia.emit_i64_mul(); - wia.emit_local_set(0); + m_wa.emit_local_get(0); + m_wa.emit_i64_const(-1); + m_wa.emit_i64_mul(); + m_wa.emit_local_set(0); }, [&](){}); - wia.emit_local_get(0); - wia.emit_local_set(4); - wia.emit_i64_const(0); - wia.emit_local_set(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([&](){ - wia.emit_local_get(0); - wia.emit_i64_const(0); - wia.emit_i64_gt_s(); + m_wa.emit_loop([&](){ + m_wa.emit_local_get(0); + m_wa.emit_i64_const(0); + m_wa.emit_i64_gt_s(); }, [&](){ - wia.emit_local_get(1); - wia.emit_i64_const(1); - wia.emit_i64_add(); - wia.emit_local_set(1); - wia.emit_local_get(0); - wia.emit_i64_const(10); - wia.emit_i64_div_s(); - wia.emit_local_set(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([&](){ - wia.emit_local_get(1); - wia.emit_i64_const(0); - wia.emit_i64_gt_s(); + m_wa.emit_loop([&](){ + m_wa.emit_local_get(1); + m_wa.emit_i64_const(0); + m_wa.emit_i64_gt_s(); }, [&](){ - wia.emit_local_get(1); - wia.emit_i64_const(1); - wia.emit_i64_sub(); - wia.emit_local_set(1); - - wia.emit_i64_const(1); - wia.emit_local_set(2); - wia.emit_i64_const(0); - wia.emit_local_set(3); - - emit_loop([&](){ - wia.emit_local_get(3); - wia.emit_local_get(1); - wia.emit_i64_lt_s(); + m_wa.emit_local_get(1); + m_wa.emit_i64_const(1); + m_wa.emit_i64_sub(); + m_wa.emit_local_set(1); + + m_wa.emit_i64_const(1); + m_wa.emit_local_set(2); + m_wa.emit_i64_const(0); + m_wa.emit_local_set(3); + + m_wa.emit_loop([&](){ + m_wa.emit_local_get(3); + m_wa.emit_local_get(1); + m_wa.emit_i64_lt_s(); }, [&](){ - wia.emit_local_get(3); - wia.emit_i64_const(1); - wia.emit_i64_add(); - wia.emit_local_set(3); - wia.emit_local_get(2); - wia.emit_i64_const(10); - wia.emit_i64_mul(); - wia.emit_local_set(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); }); - wia.emit_local_get(4); - wia.emit_local_get(2); - wia.emit_i64_div_s(); - wia.emit_i64_const(10); - wia.emit_i64_rem_s(); + 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 */ - wia.emit_i64_const(12 /* 4 + 4 + 4 (iov vec + str size)*/); - wia.emit_i64_mul(); - wia.emit_i64_const(digits_mem_loc); - wia.emit_i64_add(); - wia.emit_local_set(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 { - wia.emit_i32_const(1); // file type: 1 for stdout - wia.emit_local_get(0); // use stored digit - wia.emit_i32_wrap_i64(); - wia.emit_i32_const(1); // size of iov vector - wia.emit_i32_const(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 - wia.emit_call(m_import_func_idx_map[fd_write]); - wia.emit_drop(); + m_wa.emit_call(m_import_func_idx_map[fd_write]); + m_wa.emit_drop(); } }); - }, fn_idx); + m_wa.emit_return(); + }); } - void emit_print_float(int fn_idx = -1) { + void emit_print_float() { using namespace wasm; - define_emit_func({f64}, {}, {i64, i64, i64}, "print_f64", [&](){ - emit_if_else([&](){ - wia.emit_local_get(0); - wia.emit_f64_const(0); - wia.emit_f64_lt(); + m_wa.define_func({f64}, {}, {i64, i64, 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); - wia.emit_local_get(0); - wia.emit_f64_const(-1); - wia.emit_f64_mul(); - wia.emit_local_set(0); + m_wa.emit_local_get(0); + m_wa.emit_f64_const(-1); + m_wa.emit_f64_mul(); + m_wa.emit_local_set(0); }, [&](){}); - wia.emit_local_get(0); - wia.emit_i64_trunc_f64_s(); - wia.emit_call(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); - wia.emit_local_get(0); - wia.emit_local_get(0); - wia.emit_i64_trunc_f64_s(); - wia.emit_f64_convert_i64_s(); - wia.emit_f64_sub(); - wia.emit_f64_const(1e8); - wia.emit_f64_mul(); - wia.emit_i64_trunc_f64_s(); - wia.emit_local_set(2); /* save the current fractional part value */ - wia.emit_local_get(2); - wia.emit_local_set(3); /* save the another copy */ - - wia.emit_i64_const(0); - wia.emit_local_set(1); // digits_cnt - - emit_loop([&](){ - wia.emit_local_get(2); - wia.emit_i64_const(0); - wia.emit_i64_gt_s(); + 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(); }, [&](){ - wia.emit_local_get(1); - wia.emit_i64_const(1); - wia.emit_i64_add(); - wia.emit_local_set(1); - - wia.emit_local_get(2); - wia.emit_f64_convert_i64_s(); - wia.emit_i64_const(10); - wia.emit_f64_convert_i64_s(); - wia.emit_f64_div(); - wia.emit_i64_trunc_f64_s(); - wia.emit_local_set(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([&](){ - wia.emit_local_get(1); - wia.emit_i64_const(8); - wia.emit_i64_lt_s(); + m_wa.emit_loop([&](){ + m_wa.emit_local_get(1); + m_wa.emit_i64_const(8); + m_wa.emit_i64_lt_s(); }, [&](){ - wia.emit_local_get(1); - wia.emit_i64_const(1); - wia.emit_i64_add(); - wia.emit_local_set(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); }); - wia.emit_local_get(3); - wia.emit_call(m_rt_func_used_idx[print_i64]); - }, fn_idx); + m_wa.emit_local_get(3); + m_wa.emit_call(m_rt_func_used_idx[print_i64]); + m_wa.emit_return(); + }); } - void emit_complex_add_32(int fn_idx = -1) { + void emit_complex_add_32() { using namespace wasm; - define_emit_func({f32, f32, f32, f32}, {f32, f32}, {}, "add_c32", [&](){ - wia.emit_local_get(0); - wia.emit_local_get(2); - wia.emit_f32_add(); - - wia.emit_local_get(1); - wia.emit_local_get(3); - wia.emit_f32_add(); - }, fn_idx); + m_wa.define_func({f32, f32, f32, f32}, {f32, 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(); + m_wa.emit_return(); + }); } - void emit_complex_add_64(int fn_idx = -1) { + void emit_complex_add_64() { using namespace wasm; - define_emit_func({f64, f64, f64, f64}, {f64, f64}, {}, "add_c64", [&](){ - wia.emit_local_get(0); - wia.emit_local_get(2); - wia.emit_f64_add(); - - wia.emit_local_get(1); - wia.emit_local_get(3); - wia.emit_f64_add(); - }, fn_idx); + m_wa.define_func({f64, f64, f64, f64}, {f64, 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(); + m_wa.emit_return(); + }); } - void emit_complex_sub_32(int fn_idx = -1) { + void emit_complex_sub_32() { using namespace wasm; - define_emit_func({f32, f32, f32, f32}, {f32, f32}, {}, "sub_c32", [&](){ - wia.emit_local_get(0); - wia.emit_local_get(2); - wia.emit_f32_sub(); - - wia.emit_local_get(1); - wia.emit_local_get(3); - wia.emit_f32_sub(); - }, fn_idx); + m_wa.define_func({f32, f32, f32, f32}, {f32, 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(); + m_wa.emit_return(); + }); } - void emit_complex_sub_64(int fn_idx = -1) { + void emit_complex_sub_64() { using namespace wasm; - define_emit_func({f64, f64, f64, f64}, {f64, f64}, {}, "sub_c64", [&](){ - wia.emit_local_get(0); - wia.emit_local_get(2); - wia.emit_f64_sub(); - - wia.emit_local_get(1); - wia.emit_local_get(3); - wia.emit_f64_sub(); - }, fn_idx); + m_wa.define_func({f64, f64, f64, f64}, {f64, 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(); + m_wa.emit_return(); + }); } - void emit_complex_mul_32(int fn_idx = -1) { + void emit_complex_mul_32() { using namespace wasm; - define_emit_func({f32, f32, f32, f32}, {f32, f32}, {}, "mul_c32", [&](){ - wia.emit_local_get(0); - wia.emit_local_get(2); - wia.emit_f32_mul(); + m_wa.define_func({f32, f32, f32, f32}, {f32, f32}, {}, "mul_c32", [&](){ + m_wa.emit_local_get(0); + m_wa.emit_local_get(2); + m_wa.emit_f32_mul(); - wia.emit_local_get(1); - wia.emit_local_get(3); - wia.emit_f32_mul(); + m_wa.emit_local_get(1); + m_wa.emit_local_get(3); + m_wa.emit_f32_mul(); - wia.emit_f32_sub(); + m_wa.emit_f32_sub(); - wia.emit_local_get(0); - wia.emit_local_get(3); - wia.emit_f32_mul(); + m_wa.emit_local_get(0); + m_wa.emit_local_get(3); + m_wa.emit_f32_mul(); - wia.emit_local_get(1); - wia.emit_local_get(2); - wia.emit_f32_mul(); + m_wa.emit_local_get(1); + m_wa.emit_local_get(2); + m_wa.emit_f32_mul(); - wia.emit_f32_add(); - }, fn_idx); + m_wa.emit_f32_add(); + m_wa.emit_return(); + }); } - void emit_complex_mul_64(int fn_idx = -1) { + void emit_complex_mul_64() { using namespace wasm; - define_emit_func({f64, f64, f64, f64}, {f64, f64}, {}, "mul_c64", [&](){ - wia.emit_local_get(0); - wia.emit_local_get(2); - wia.emit_f64_mul(); + m_wa.define_func({f64, f64, f64, f64}, {f64, f64}, {}, "mul_c64", [&](){ + m_wa.emit_local_get(0); + m_wa.emit_local_get(2); + m_wa.emit_f64_mul(); - wia.emit_local_get(1); - wia.emit_local_get(3); - wia.emit_f64_mul(); + m_wa.emit_local_get(1); + m_wa.emit_local_get(3); + m_wa.emit_f64_mul(); - wia.emit_f64_sub(); + m_wa.emit_f64_sub(); - wia.emit_local_get(0); - wia.emit_local_get(3); - wia.emit_f64_mul(); + m_wa.emit_local_get(0); + m_wa.emit_local_get(3); + m_wa.emit_f64_mul(); - wia.emit_local_get(1); - wia.emit_local_get(2); - wia.emit_f64_mul(); + m_wa.emit_local_get(1); + m_wa.emit_local_get(2); + m_wa.emit_f64_mul(); - wia.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", [&](){ - wia.emit_local_get(0); - wia.emit_local_get(0); - wia.emit_f32_mul(); - - wia.emit_local_get(1); - wia.emit_local_get(1); - wia.emit_f32_mul(); - - wia.emit_f32_add(); - wia.emit_f32_sqrt(); - }, fn_idx); + m_wa.emit_f64_add(); + m_wa.emit_return(); + }); } - void emit_complex_abs_64(int fn_idx = -1) { + void emit_complex_abs_32() { using namespace wasm; - define_emit_func({f64, f64}, {f64}, {}, "abs_c64", [&](){ - wia.emit_local_get(0); - wia.emit_local_get(0); - wia.emit_f64_mul(); - - wia.emit_local_get(1); - wia.emit_local_get(1); - wia.emit_f64_mul(); - - wia.emit_f64_add(); - wia.emit_f64_sqrt(); - }, fn_idx); - } - - template - void declare_global_var(wasm::type 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); - emit_const(m_global_section, var_type, initial_value); - wasm::emit_expr_end(m_global_section, m_al); - m_compiler_globals[name] = no_of_globals; - no_of_globals++; + m_wa.define_func({f32, f32}, {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(); + m_wa.emit_return(); + }); } - template - void emit_const(Vec &m_code, wasm::type typ, T init_val) { + void emit_complex_abs_64() { using namespace wasm; - switch (typ) - { - case i32: - wasm::emit_b8(m_code, m_al, 0x41); // emit instruction - wasm::emit_i32(m_code, m_al, init_val); // emit val - break; - case i64: - wasm::emit_b8(m_code, m_al, 0x42); // emit instruction - wasm::emit_i64(m_code, m_al, init_val); // emit val - break; - case f32: - wasm::emit_b8(m_code, m_al, 0x43); // emit instruction - wasm::emit_f32(m_code, m_al, init_val); // emit val - break; - case f64: - wasm::emit_b8(m_code, m_al, 0x44); // emit instruction - wasm::emit_f64(m_code, m_al, init_val); // emit val - break; - default: - throw CodeGenError("emit_global_const: Unsupported type"); - } + m_wa.define_func({f64, f64}, {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(); + m_wa.emit_return(); + }); } void declare_global_var(ASR::Variable_t* v) { @@ -699,12 +523,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { // Ignore type variables return; } - using namespace wasm; - 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 + using namespace wasm; int kind = ASRUtils::extract_kind_from_ttype_t(v->m_type); + uint32_t global_var_idx = -1; switch (v->m_type->type){ case ASR::ttypeType::Integer: { uint64_t init_val = 0; @@ -712,8 +534,8 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { init_val = ASR::down_cast(v->m_value)->m_n; } switch (kind) { - case 4: emit_const(m_global_section, i32, init_val); break; - case 8: emit_const(m_global_section, i64, init_val); break; + case 4: global_var_idx = m_wa.declare_global_var(i32, init_val); break; + case 8: global_var_idx = m_wa.declare_global_var(i64, init_val); break; default: throw CodeGenError("Declare Global: Unsupported Integer kind"); } break; @@ -724,8 +546,8 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { init_val = ASR::down_cast(v->m_value)->m_r; } switch (kind) { - case 4: emit_const(m_global_section, f32, init_val); break; - case 8: emit_const(m_global_section, f64, init_val); break; + case 4: global_var_idx = m_wa.declare_global_var(f32, init_val); break; + case 8: global_var_idx = m_wa.declare_global_var(f64, init_val); break; default: throw CodeGenError("Declare Global: Unsupported Real kind"); } break; @@ -736,7 +558,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { init_val = ASR::down_cast(v->m_value)->m_value; } switch (kind) { - case 4: emit_const(m_global_section, i32, init_val); break; + case 4: global_var_idx = m_wa.declare_global_var(i32, init_val); break; default: throw CodeGenError("Declare Global: Unsupported Logical kind"); } break; @@ -749,7 +571,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { emit_string(init_val); switch (kind) { case 1: - emit_const(m_global_section, i32, m_string_to_iov_loc_map[init_val]); + global_var_idx = m_wa.declare_global_var(i32, m_string_to_iov_loc_map[init_val]); break; default: throw CodeGenError("Declare Global: Unsupported Character kind"); } @@ -758,10 +580,11 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { default: { diag.codegen_warning_label("Declare Global: Type " + ASRUtils::type_to_str(v->m_type) + " not yet supported", {v->base.base.loc}, ""); - emit_const(m_global_section, i32, 0); + global_var_idx = m_wa.declare_global_var(i32, 0); } } - wasm::emit_expr_end(m_global_section, m_al); + LCOMPILERS_ASSERT(global_var_idx >= 0); + m_global_var_idx_map[get_hash((ASR::asr_t *)v)] = global_var_idx; } void declare_symbols(const ASR::TranslationUnit_t &x) { @@ -795,16 +618,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); + m_compiler_globals[cur_mem_loc] = m_wa.declare_global_var(wasm::var_type::i32, 0); + m_compiler_globals[tmp_reg_i32] = m_wa.declare_global_var(wasm::var_type::i32, 0); + m_compiler_globals[tmp_reg_i64] = m_wa.declare_global_var(wasm::var_type::i64, 0); + m_compiler_globals[tmp_reg_f32] = m_wa.declare_global_var(wasm::var_type::f32, 0); + m_compiler_globals[tmp_reg_f64] = m_wa.declare_global_var(wasm::var_type::f64, 0); emit_string(" "); emit_string("\n"); @@ -835,6 +656,8 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { is_prototype_only = true; declare_symbols(x); is_prototype_only = false; + + rt_funcs_seq_order = m_wa.get_no_of_types(); } declare_symbols(x); @@ -849,7 +672,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { sort(ordered_rt_funcs_type_idx.begin(), ordered_rt_funcs_type_idx.end()); for (auto rt_func:ordered_rt_funcs_type_idx) { - (this->*m_rt_funcs_map[rt_func.second])(rt_func.first); + (this->*m_rt_funcs_map[rt_func.second])(); } } @@ -899,12 +722,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { this->visit_Function(*main_func); } - void emit_var_type(Vec &code, ASR::Variable_t *v, uint32_t &no_of_vars, bool emitCount) { - bool is_array = ASRUtils::is_array(v->m_type); + void get_var_type(ASR::Variable_t *v, std::vector &type_vec) { + using namespace wasm; - if (emitCount) { - wasm::emit_u32(code, m_al, 1U); - } + bool is_array = ASRUtils::is_array(v->m_type); if (ASRUtils::is_pointer(v->m_type)) { ASR::ttype_t *t2 = @@ -915,9 +736,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); + type_vec.push_back(i32); } else if (t->m_kind == 8) { - wasm::emit_b8(code, m_al, wasm::type::i64); + type_vec.push_back(i64); } else { throw CodeGenError( "Integers of kind 4 and 8 only supported"); @@ -934,12 +755,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); + type_vec.push_back(i32); } else { if (v_int->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::i32); + type_vec.push_back(i32); } else if (v_int->m_kind == 8) { - wasm::emit_b8(code, m_al, wasm::type::i64); + type_vec.push_back(i64); } else { throw CodeGenError( "Integers of kind 4 and 8 only supported"); @@ -949,12 +770,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); + type_vec.push_back(i32); } else { if (v_float->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::f32); + type_vec.push_back(f32); } else if (v_float->m_kind == 8) { - wasm::emit_b8(code, m_al, wasm::type::f64); + type_vec.push_back(f64); } else { throw CodeGenError( "Floating Points of kind 4 and 8 only supported"); @@ -965,11 +786,11 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::down_cast(v->m_type); if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); + type_vec.push_back(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); + type_vec.push_back(i32); } else { throw CodeGenError("Logicals of kind 4 only supported"); } @@ -979,13 +800,13 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::down_cast(v->m_type); if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); + type_vec.push_back(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); + type_vec.push_back(i32); } else { throw CodeGenError( "Characters of kind 1 only supported"); @@ -996,34 +817,26 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::down_cast(v->m_type); if (is_array) { - wasm::emit_b8(code, m_al, wasm::type::i32); + type_vec.push_back(i32); } else { if (v_comp->m_kind == 4) { - wasm::emit_b8(code, m_al, wasm::type::f32); // real part - if (emitCount) { - wasm::emit_u32(code, m_al, 1U); - } - wasm::emit_b8(code, m_al, wasm::type::f32); // imag part + type_vec.push_back(f32); + type_vec.push_back(f32); } else if (v_comp->m_kind == 8) { - wasm::emit_b8(code, m_al, wasm::type::f64); // real part - if (emitCount) { - wasm::emit_u32(code, m_al, 1U); - } - wasm::emit_b8(code, m_al, wasm::type::f64); // imag part + type_vec.push_back(f64); + type_vec.push_back(f64); } else { throw CodeGenError( "Complex numbers of kind 4 and 8 only supported yet"); } - no_of_vars++; } } else { diag.codegen_warning_label("Unsupported variable type: " + ASRUtils::type_to_str(v->m_type), {v->base.base.loc}, "Only integer, floats, logical and complex supported currently"); - wasm::emit_b8(code, m_al, wasm::type::i32); + type_vec.push_back(i32); } } - no_of_vars++; } bool isLocalVar(ASR::Variable_t *v) { @@ -1031,14 +844,14 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { v->m_intent == ASRUtils::intent_return_var); } - void emit_local_vars(SymbolTable* symtab) { + void get_local_vars(SymbolTable* symtab) { for (auto &item : symtab->get_scope()) { if (ASR::is_a(*item.second)) { ASR::Variable_t *v = 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); + m_var_idx_map[get_hash((ASR::asr_t *)v)] = cur_sym_info->no_of_params + local_vars.size(); + get_var_type(v, local_vars); } } } @@ -1048,17 +861,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]; - wia.emit_local_get(var_idx); + m_wa.emit_local_get(var_idx); if (ASRUtils::is_complex(*v->m_type)) { // get the imaginary part - wia.emit_local_get(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]; - wia.emit_global_get(var_idx); + m_wa.emit_global_get(var_idx); if (ASRUtils::is_complex(*v->m_type)) { // get the imaginary part - wia.emit_global_get(var_idx + 1u); + m_wa.emit_global_get(var_idx + 1u); } } else { throw CodeGenError("Variable " + std::string(v->m_name) + " not declared"); @@ -1071,16 +884,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 - wia.emit_local_set(var_idx + 1u); + m_wa.emit_local_set(var_idx + 1u); } - wia.emit_local_set(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 - wia.emit_global_set(var_idx + 1u); + m_wa.emit_global_set(var_idx + 1u); } - wia.emit_global_set(var_idx); + m_wa.emit_global_set(var_idx); } else { throw CodeGenError("Variable " + std::string(v->m_name) + " not declared"); } @@ -1108,7 +921,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { total_array_size *= dim; } - wia.emit_i32_const(avail_mem_loc); + m_wa.emit_i32_const(avail_mem_loc); emit_var_set(v); avail_mem_loc += kind * total_array_size; } @@ -1126,45 +939,35 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { void emit_function_prototype(const ASR::Function_t &x) { SymbolFuncInfo *s = new SymbolFuncInfo; - /********************* New Type Declaration *********************/ - wasm::emit_b8(m_type_section, m_al, 0x60); + std::vector params, results; - /********************* 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); 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); + + get_var_type(arg, params); + m_var_idx_map[get_hash((ASR::asr_t *)arg)] = s->no_of_params++; + if (isRefVar(arg)) { s->referenced_vars.push_back(m_al, arg); } } - wasm::fixup_len(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 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); + get_var_type(s->return_var, results); } 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); + get_var_type(arg, results); } } } - wasm::fixup_len(m_type_section, m_al, len_idx_type_section_return_types_list); - /********************* Add Type to Map *********************/ - s->index = no_of_types++; - m_func_name_idx_map[get_hash((ASR::asr_t *)&x)] = - s; // add function to map + s->index = m_wa.emit_func_type(params, results); + m_func_name_idx_map[get_hash((ASR::asr_t *)&x)] = s; } template @@ -1182,54 +985,29 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { cur_sym_info = m_func_name_idx_map[get_hash((ASR::asr_t *)&x)]; - /********************* Reference Function Prototype - * *********************/ - wasm::emit_u32(m_func_section, m_al, cur_sym_info->index); - - /********************* Function Body Starts Here *********************/ - uint32_t len_idx_code_section_func_size = - wasm::emit_len_placeholder(m_code_section, m_al); - { + local_vars.clear(); is_local_vars_only = true; - int params_cnt = cur_sym_info->no_of_variables; - /********************* Local Vars Types List *********************/ - uint32_t len_idx_code_section_local_vars_list = - wasm::emit_len_placeholder(m_code_section, m_al); - emit_local_vars(x.m_symtab); + get_local_vars(x.m_symtab); visit_BlockStatements(x); - // fixup length of local vars list - wasm::emit_u32_b32_idx(m_code_section, m_al, - len_idx_code_section_local_vars_list, - cur_sym_info->no_of_variables - params_cnt); is_local_vars_only = false; } - initialize_local_vars(x.m_symtab); - - for (size_t i = 0; i < x.n_body; i++) { - this->visit_stmt(*x.m_body[i]); - } - - if (strcmp(x.m_name, "_start") == 0) { - wia.emit_i32_const(0 /* zero exit code */); - wia.emit_call(m_import_func_idx_map[proc_exit]); - } - - if (x.n_body == 0 || !ASR::is_a(*x.m_body[x.n_body - 1])) { - handle_return(); - } - 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, x.m_name, - cur_sym_info->index); // add function to export - no_of_functions++; - no_of_exports++; + m_wa.emit_func_body(cur_sym_info->index, x.m_name, local_vars, [&](){ + initialize_local_vars(x.m_symtab); + for (size_t i = 0; i < x.n_body; i++) { + this->visit_stmt(*x.m_body[i]); + } + if (strcmp(x.m_name, "_start") == 0) { + m_wa.emit_i32_const(0 /* zero exit code */); + m_wa.emit_call(m_import_func_idx_map[proc_exit]); + } + if (x.n_body == 0 || !ASR::is_a(*x.m_body[x.n_body - 1])) { + handle_return(); + } + }); } bool is_unsupported_function(const ASR::Function_t &x) { @@ -1282,7 +1060,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { LCOMPILERS_ASSERT(ASR::is_a(*x.m_m)); ASR::Block_t* block = ASR::down_cast(x.m_m); if (is_local_vars_only) { - emit_local_vars(block->m_symtab); + get_local_vars(block->m_symtab); visit_BlockStatements(*block); } else { initialize_local_vars(block->m_symtab); @@ -1299,10 +1077,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { case ASR::ttypeType::Integer: { switch (kind) { case 4: - wia.emit_i32_store(wasm::mem_align::b8, 0); + m_wa.emit_i32_store(wasm::mem_align::b8, 0); break; case 8: - wia.emit_i64_store(wasm::mem_align::b8, 0); + m_wa.emit_i64_store(wasm::mem_align::b8, 0); break; default: throw CodeGenError( @@ -1313,10 +1091,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { case ASR::ttypeType::Real: { switch (kind) { case 4: - wia.emit_f32_store(wasm::mem_align::b8, 0); + m_wa.emit_f32_store(wasm::mem_align::b8, 0); break; case 8: - wia.emit_f64_store(wasm::mem_align::b8, 0); + m_wa.emit_f64_store(wasm::mem_align::b8, 0); break; default: throw CodeGenError( @@ -1327,7 +1105,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { case ASR::ttypeType::Logical: { switch (kind) { case 4: - wia.emit_i32_store(wasm::mem_align::b8, 0); + m_wa.emit_i32_store(wasm::mem_align::b8, 0); break; default: throw CodeGenError( @@ -1338,10 +1116,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { case ASR::ttypeType::Character: { switch (kind) { case 4: - wia.emit_i32_store(wasm::mem_align::b8, 0); + m_wa.emit_i32_store(wasm::mem_align::b8, 0); break; case 8: - wia.emit_i64_store(wasm::mem_align::b8, 0); + m_wa.emit_i64_store(wasm::mem_align::b8, 0); break; default: throw CodeGenError( @@ -1365,10 +1143,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { case ASR::ttypeType::Integer: { switch (kind) { case 4: - wia.emit_i32_load(wasm::mem_align::b8, 0); + m_wa.emit_i32_load(wasm::mem_align::b8, 0); break; case 8: - wia.emit_i64_load(wasm::mem_align::b8, 0); + m_wa.emit_i64_load(wasm::mem_align::b8, 0); break; default: throw CodeGenError( @@ -1379,10 +1157,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { case ASR::ttypeType::Real: { switch (kind) { case 4: - wia.emit_f32_load(wasm::mem_align::b8, 0); + m_wa.emit_f32_load(wasm::mem_align::b8, 0); break; case 8: - wia.emit_f64_load(wasm::mem_align::b8, 0); + m_wa.emit_f64_load(wasm::mem_align::b8, 0); break; default: throw CodeGenError("MemoryLoad: Unsupported Real kind"); @@ -1392,7 +1170,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { case ASR::ttypeType::Logical: { switch (kind) { case 4: - wia.emit_i32_load(wasm::mem_align::b8, 0); + m_wa.emit_i32_load(wasm::mem_align::b8, 0); break; default: throw CodeGenError( @@ -1403,10 +1181,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { case ASR::ttypeType::Character: { switch (kind) { case 4: - wia.emit_i32_load(wasm::mem_align::b8, 0); + m_wa.emit_i32_load(wasm::mem_align::b8, 0); break; case 8: - wia.emit_i64_load(wasm::mem_align::b8, 0); + m_wa.emit_i64_load(wasm::mem_align::b8, 0); break; default: throw CodeGenError( @@ -1449,19 +1227,19 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { if (i->m_kind == 4) { switch (x.m_op) { case ASR::binopType::Add: { - wia.emit_i32_add(); + m_wa.emit_i32_add(); break; }; case ASR::binopType::Sub: { - wia.emit_i32_sub(); + m_wa.emit_i32_sub(); break; }; case ASR::binopType::Mul: { - wia.emit_i32_mul(); + m_wa.emit_i32_mul(); break; }; case ASR::binopType::Div: { - wia.emit_i32_div_s(); + m_wa.emit_i32_div_s(); break; }; case ASR::binopType::Pow: { @@ -1471,9 +1249,9 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::down_cast(val); if (c->m_n == 2) { // drop the last stack item in the wasm stack - wia.emit_drop(); + m_wa.emit_drop(); this->visit_expr(*x.m_left); - wia.emit_i32_mul(); + m_wa.emit_i32_mul(); } else { throw CodeGenError( "IntegerBinop kind 4: only x**2 implemented so " @@ -1487,23 +1265,23 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { break; }; case ASR::binopType::BitAnd: { - wia.emit_i32_and(); + m_wa.emit_i32_and(); break; }; case ASR::binopType::BitOr: { - wia.emit_i32_or(); + m_wa.emit_i32_or(); break; }; case ASR::binopType::BitXor: { - wia.emit_i32_xor(); + m_wa.emit_i32_xor(); break; }; case ASR::binopType::BitLShift: { - wia.emit_i32_shl(); + m_wa.emit_i32_shl(); break; }; case ASR::binopType::BitRShift: { - wia.emit_i32_shr_s(); + m_wa.emit_i32_shr_s(); break; }; default: { @@ -1514,19 +1292,19 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } else if (i->m_kind == 8) { switch (x.m_op) { case ASR::binopType::Add: { - wia.emit_i64_add(); + m_wa.emit_i64_add(); break; }; case ASR::binopType::Sub: { - wia.emit_i64_sub(); + m_wa.emit_i64_sub(); break; }; case ASR::binopType::Mul: { - wia.emit_i64_mul(); + m_wa.emit_i64_mul(); break; }; case ASR::binopType::Div: { - wia.emit_i64_div_s(); + m_wa.emit_i64_div_s(); break; }; case ASR::binopType::Pow: { @@ -1536,9 +1314,9 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::down_cast(val); if (c->m_n == 2) { // drop the last stack item in the wasm stack - wia.emit_drop(); + m_wa.emit_drop(); this->visit_expr(*x.m_left); - wia.emit_i64_mul(); + m_wa.emit_i64_mul(); } else { throw CodeGenError( "IntegerBinop kind 8: only x**2 implemented so " @@ -1552,23 +1330,23 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { break; }; case ASR::binopType::BitAnd: { - wia.emit_i64_and(); + m_wa.emit_i64_and(); break; }; case ASR::binopType::BitOr: { - wia.emit_i64_or(); + m_wa.emit_i64_or(); break; }; case ASR::binopType::BitXor: { - wia.emit_i64_xor(); + m_wa.emit_i64_xor(); break; }; case ASR::binopType::BitLShift: { - wia.emit_i64_shl(); + m_wa.emit_i64_shl(); break; }; case ASR::binopType::BitRShift: { - wia.emit_i64_shr_s(); + m_wa.emit_i64_shr_s(); break; }; default: { @@ -1591,12 +1369,12 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { // there is no direct bit-invert inst in wasm, // so xor-ing with -1 (sequence of 32/64 1s) if(i->m_kind == 4){ - wia.emit_i32_const(-1); - wia.emit_i32_xor(); + m_wa.emit_i32_const(-1); + m_wa.emit_i32_xor(); } else if(i->m_kind == 8){ - wia.emit_i64_const(-1LL); - wia.emit_i64_xor(); + m_wa.emit_i64_const(-1LL); + m_wa.emit_i64_xor(); } else{ throw CodeGenError("IntegerBitNot: Only kind 4 and 8 supported"); @@ -1614,19 +1392,19 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { if (f->m_kind == 4) { switch (x.m_op) { case ASR::binopType::Add: { - wia.emit_f32_add(); + m_wa.emit_f32_add(); break; }; case ASR::binopType::Sub: { - wia.emit_f32_sub(); + m_wa.emit_f32_sub(); break; }; case ASR::binopType::Mul: { - wia.emit_f32_mul(); + m_wa.emit_f32_mul(); break; }; case ASR::binopType::Div: { - wia.emit_f32_div(); + m_wa.emit_f32_div(); break; }; case ASR::binopType::Pow: { @@ -1636,9 +1414,9 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::down_cast(val); if (c->m_r == 2.0) { // drop the last stack item in the wasm stack - wia.emit_drop(); + m_wa.emit_drop(); this->visit_expr(*x.m_left); - wia.emit_f32_mul(); + m_wa.emit_f32_mul(); } else { throw CodeGenError( "RealBinop: only x**2 implemented so far for " @@ -1659,19 +1437,19 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } else if (f->m_kind == 8) { switch (x.m_op) { case ASR::binopType::Add: { - wia.emit_f64_add(); + m_wa.emit_f64_add(); break; }; case ASR::binopType::Sub: { - wia.emit_f64_sub(); + m_wa.emit_f64_sub(); break; }; case ASR::binopType::Mul: { - wia.emit_f64_mul(); + m_wa.emit_f64_mul(); break; }; case ASR::binopType::Div: { - wia.emit_f64_div(); + m_wa.emit_f64_div(); break; }; case ASR::binopType::Pow: { @@ -1681,9 +1459,9 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::down_cast(val); if (c->m_r == 2.0) { // drop the last stack item in the wasm stack - wia.emit_drop(); + m_wa.emit_drop(); this->visit_expr(*x.m_left); - wia.emit_f64_mul(); + m_wa.emit_f64_mul(); } else { throw CodeGenError( "RealBinop: only x**2 implemented so far for " @@ -1718,30 +1496,30 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { case ASR::binopType::Add: { if (a_kind == 4) { INCLUDE_RUNTIME_FUNC(add_c32); - wia.emit_call(m_rt_func_used_idx[add_c32]); + m_wa.emit_call(m_rt_func_used_idx[add_c32]); } else { INCLUDE_RUNTIME_FUNC(add_c64); - wia.emit_call(m_rt_func_used_idx[add_c64]); + m_wa.emit_call(m_rt_func_used_idx[add_c64]); } break; }; case ASR::binopType::Sub: { if (a_kind == 4) { INCLUDE_RUNTIME_FUNC(sub_c32); - wia.emit_call(m_rt_func_used_idx[sub_c32]); + m_wa.emit_call(m_rt_func_used_idx[sub_c32]); } else { INCLUDE_RUNTIME_FUNC(sub_c64); - wia.emit_call(m_rt_func_used_idx[sub_c64]); + m_wa.emit_call(m_rt_func_used_idx[sub_c64]); } break; }; case ASR::binopType::Mul: { if (a_kind == 4) { INCLUDE_RUNTIME_FUNC(mul_c32); - wia.emit_call(m_rt_func_used_idx[mul_c32]); + m_wa.emit_call(m_rt_func_used_idx[mul_c32]); } else { INCLUDE_RUNTIME_FUNC(mul_c64); - wia.emit_call(m_rt_func_used_idx[mul_c64]); + m_wa.emit_call(m_rt_func_used_idx[mul_c64]); } break; }; @@ -1760,13 +1538,13 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::Integer_t *i = ASR::down_cast(x.m_type); // there seems no direct unary-minus inst in wasm, so subtracting from 0 if (i->m_kind == 4) { - wia.emit_i32_const(0); + m_wa.emit_i32_const(0); this->visit_expr(*x.m_arg); - wia.emit_i32_sub(); + m_wa.emit_i32_sub(); } else if (i->m_kind == 8) { - wia.emit_i64_const(0LL); + m_wa.emit_i64_const(0LL); this->visit_expr(*x.m_arg); - wia.emit_i64_sub(); + m_wa.emit_i64_sub(); } else { throw CodeGenError( "IntegerUnaryMinus: Only kind 4 and 8 supported"); @@ -1781,10 +1559,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::Real_t *f = ASR::down_cast(x.m_type); if (f->m_kind == 4) { this->visit_expr(*x.m_arg); - wia.emit_f32_neg(); + m_wa.emit_f32_neg(); } else if (f->m_kind == 8) { this->visit_expr(*x.m_arg); - wia.emit_f64_neg(); + m_wa.emit_f64_neg(); } else { throw CodeGenError("RealUnaryMinus: Only kind 4 and 8 supported"); } @@ -1798,16 +1576,16 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::Complex_t *f = ASR::down_cast(x.m_type); if (f->m_kind == 4) { this->visit_expr(*x.m_arg); - wia.emit_f32_neg(); - wia.emit_global_set(m_compiler_globals[tmp_reg_f32]); - wia.emit_f32_neg(); - wia.emit_global_get(m_compiler_globals[tmp_reg_f32]); + m_wa.emit_f32_neg(); + m_wa.emit_global_set(m_compiler_globals[tmp_reg_f32]); + m_wa.emit_f32_neg(); + m_wa.emit_global_get(m_compiler_globals[tmp_reg_f32]); } else if (f->m_kind == 8) { this->visit_expr(*x.m_arg); - wia.emit_f64_neg(); - wia.emit_global_set(m_compiler_globals[tmp_reg_f64]); - wia.emit_f64_neg(); - wia.emit_global_get(m_compiler_globals[tmp_reg_f64]); + m_wa.emit_f64_neg(); + m_wa.emit_global_set(m_compiler_globals[tmp_reg_f64]); + m_wa.emit_f64_neg(); + m_wa.emit_global_get(m_compiler_globals[tmp_reg_f64]); } else { throw CodeGenError("ComplexUnaryMinus: Only kind 4 and 8 supported"); } @@ -1844,27 +1622,27 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { if (a_kind == 4) { switch (x.m_op) { case (ASR::cmpopType::Eq): { - wia.emit_i32_eq(); + m_wa.emit_i32_eq(); break; } case (ASR::cmpopType::Gt): { - wia.emit_i32_gt_s(); + m_wa.emit_i32_gt_s(); break; } case (ASR::cmpopType::GtE): { - wia.emit_i32_ge_s(); + m_wa.emit_i32_ge_s(); break; } case (ASR::cmpopType::Lt): { - wia.emit_i32_lt_s(); + m_wa.emit_i32_lt_s(); break; } case (ASR::cmpopType::LtE): { - wia.emit_i32_le_s(); + m_wa.emit_i32_le_s(); break; } case (ASR::cmpopType::NotEq): { - wia.emit_i32_ne(); + m_wa.emit_i32_ne(); break; } default: @@ -1875,27 +1653,27 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } else if (a_kind == 8) { switch (x.m_op) { case (ASR::cmpopType::Eq): { - wia.emit_i64_eq(); + m_wa.emit_i64_eq(); break; } case (ASR::cmpopType::Gt): { - wia.emit_i64_gt_s(); + m_wa.emit_i64_gt_s(); break; } case (ASR::cmpopType::GtE): { - wia.emit_i64_ge_s(); + m_wa.emit_i64_ge_s(); break; } case (ASR::cmpopType::Lt): { - wia.emit_i64_lt_s(); + m_wa.emit_i64_lt_s(); break; } case (ASR::cmpopType::LtE): { - wia.emit_i64_le_s(); + m_wa.emit_i64_le_s(); break; } case (ASR::cmpopType::NotEq): { - wia.emit_i64_ne(); + m_wa.emit_i64_ne(); break; } default: @@ -1920,27 +1698,27 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { if (a_kind == 4) { switch (x.m_op) { case (ASR::cmpopType::Eq): { - wia.emit_f32_eq(); + m_wa.emit_f32_eq(); break; } case (ASR::cmpopType::Gt): { - wia.emit_f32_gt(); + m_wa.emit_f32_gt(); break; } case (ASR::cmpopType::GtE): { - wia.emit_f32_ge(); + m_wa.emit_f32_ge(); break; } case (ASR::cmpopType::Lt): { - wia.emit_f32_lt(); + m_wa.emit_f32_lt(); break; } case (ASR::cmpopType::LtE): { - wia.emit_f32_le(); + m_wa.emit_f32_le(); break; } case (ASR::cmpopType::NotEq): { - wia.emit_f32_ne(); + m_wa.emit_f32_ne(); break; } default: @@ -1950,27 +1728,27 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } else if (a_kind == 8) { switch (x.m_op) { case (ASR::cmpopType::Eq): { - wia.emit_f64_eq(); + m_wa.emit_f64_eq(); break; } case (ASR::cmpopType::Gt): { - wia.emit_f64_gt(); + m_wa.emit_f64_gt(); break; } case (ASR::cmpopType::GtE): { - wia.emit_f64_ge(); + m_wa.emit_f64_ge(); break; } case (ASR::cmpopType::Lt): { - wia.emit_f64_lt(); + m_wa.emit_f64_lt(); break; } case (ASR::cmpopType::LtE): { - wia.emit_f64_le(); + m_wa.emit_f64_le(); break; } case (ASR::cmpopType::NotEq): { - wia.emit_f64_ne(); + m_wa.emit_f64_ne(); break; } default: @@ -2013,23 +1791,23 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { if (a_kind == 4) { switch (x.m_op) { case (ASR::logicalbinopType::And): { - wia.emit_i32_and(); + m_wa.emit_i32_and(); break; } case (ASR::logicalbinopType::Or): { - wia.emit_i32_or(); + m_wa.emit_i32_or(); break; } case ASR::logicalbinopType::Xor: { - wia.emit_i32_xor(); + m_wa.emit_i32_xor(); break; } case (ASR::logicalbinopType::NEqv): { - wia.emit_i32_xor(); + m_wa.emit_i32_xor(); break; } case (ASR::logicalbinopType::Eqv): { - wia.emit_i32_eq(); + m_wa.emit_i32_eq(); break; } default: @@ -2049,9 +1827,9 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { this->visit_expr(*x.m_arg); int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); if (a_kind == 4) { - wia.emit_i32_eqz(); + m_wa.emit_i32_eqz(); } else if (a_kind == 8) { - wia.emit_i64_eqz(); + m_wa.emit_i64_eqz(); } else { throw CodeGenError("LogicalNot: kind 4 and 8 supported only"); } @@ -2097,12 +1875,12 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASR::dimension_t *m_dims; ASRUtils::extract_dimensions_from_ttype(ttype, m_dims); - wia.emit_i32_const(0); + m_wa.emit_i32_const(0); for (uint32_t i = 0; i < x.n_args; i++) { if (x.m_args[i].m_right) { this->visit_expr(*x.m_args[i].m_right); this->visit_expr(*m_dims[i].m_start); - wia.emit_i32_sub(); + m_wa.emit_i32_sub(); size_t jmin, jmax; if (x.m_storage_format == ASR::arraystorageType::ColMajor) { @@ -2117,18 +1895,18 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { for (size_t j = jmin; j < jmax; j++) { this->visit_expr(*m_dims[j].m_length); - wia.emit_i32_mul(); + m_wa.emit_i32_mul(); } - wia.emit_i32_add(); + m_wa.emit_i32_add(); } else { diag.codegen_warning_label("/* FIXME right index */", {x.base.base.loc}, ""); } } - wia.emit_i32_const(kind); - wia.emit_i32_mul(); - wia.emit_i32_add(); + m_wa.emit_i32_const(kind); + m_wa.emit_i32_mul(); + m_wa.emit_i32_add(); } void visit_ArrayItem(const ASR::ArrayItem_t &x) { @@ -2163,13 +1941,13 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { this->visit_expr(*(m_dims[0].m_length)); for (int i = 1; i < n_dims; i++) { this->visit_expr(*m_dims[i].m_length); - wia.emit_i32_mul(); + m_wa.emit_i32_mul(); } } int kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); if (kind == 8) { - wia.emit_i64_extend_i32_s(); + m_wa.emit_i64_extend_i32_s(); } } @@ -2181,7 +1959,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { emit_var_get(return_var); } } - wia.emit_return(); // wasm return + m_wa.emit_return(); } void visit_Return(const ASR::Return_t & /* x */) { handle_return(); } @@ -2191,11 +1969,11 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { int a_kind = ((ASR::Integer_t *)(&(x.m_type->base)))->m_kind; switch (a_kind) { case 4: { - wia.emit_i32_const(val); + m_wa.emit_i32_const(val); break; } case 8: { - wia.emit_i64_const(val); + m_wa.emit_i64_const(val); break; } default: { @@ -2210,11 +1988,11 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { int a_kind = ((ASR::Real_t *)(&(x.m_type->base)))->m_kind; switch (a_kind) { case 4: { - wia.emit_f32_const(val); + m_wa.emit_f32_const(val); break; } case 8: { - wia.emit_f64_const(val); + m_wa.emit_f64_const(val); break; } default: { @@ -2229,7 +2007,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { int a_kind = ((ASR::Logical_t *)(&(x.m_type->base)))->m_kind; switch (a_kind) { case 4: { - wia.emit_i32_const(val); + m_wa.emit_i32_const(val); break; } default: { @@ -2251,13 +2029,13 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); switch( a_kind ) { case 4: { - wia.emit_f32_const(x.m_re); - wia.emit_f32_const(x.m_im); + m_wa.emit_f32_const(x.m_re); + m_wa.emit_f32_const(x.m_im); break; } case 8: { - wia.emit_f64_const(x.m_re); - wia.emit_f64_const(x.m_im); + m_wa.emit_f64_const(x.m_re); + m_wa.emit_f64_const(x.m_im); break; } default: { @@ -2296,19 +2074,17 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { uint32_t string_loc = avail_mem_loc + 8U /* IOV_SIZE */; std::string iov = convert_int_to_bytes_string(string_loc) + convert_int_to_bytes_string(str.length()); - wasm::emit_str_const(m_data_section, m_al, avail_mem_loc, iov); + m_wa.emit_data_str(avail_mem_loc, iov); avail_mem_loc += iov.length(); - no_of_data_segments++; align_str_by_4_bytes(str); - wasm::emit_str_const(m_data_section, m_al, avail_mem_loc, str); + m_wa.emit_data_str(avail_mem_loc, str); avail_mem_loc += str.length(); - no_of_data_segments++; } void visit_StringConstant(const ASR::StringConstant_t &x) { emit_string(x.m_s); - wia.emit_i32_const(m_string_to_iov_loc_map[x.m_s]); + m_wa.emit_i32_const(m_string_to_iov_loc_map[x.m_s]); } void visit_ArrayConstant(const ASR::ArrayConstant_t &x) { @@ -2317,14 +2093,14 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { uint32_t cur_mem_loc = avail_mem_loc; for (size_t i = 0; i < x.n_args; i++) { // emit memory location to store array element - wia.emit_i32_const(avail_mem_loc); + m_wa.emit_i32_const(avail_mem_loc); this->visit_expr(*x.m_args[i]); int element_size_in_bytes = emit_memory_store(x.m_args[i]); avail_mem_loc += element_size_in_bytes; } // leave array location in memory on the stack - wia.emit_i32_const(cur_mem_loc); + m_wa.emit_i32_const(cur_mem_loc); } void visit_FunctionCall(const ASR::FunctionCall_t &x) { @@ -2342,17 +2118,17 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { uint64_t hash = get_hash((ASR::asr_t *)fn); if (m_func_name_idx_map.find(hash) != m_func_name_idx_map.end()) { - wia.emit_call(m_func_name_idx_map[hash]->index); + m_wa.emit_call(m_func_name_idx_map[hash]->index); } else { if (strcmp(fn->m_name, "c_caimag") == 0) { LCOMPILERS_ASSERT(x.n_args == 1); - wia.emit_global_set(m_compiler_globals[tmp_reg_f32]); - wia.emit_drop(); - wia.emit_global_get(m_compiler_globals[tmp_reg_f32]); + m_wa.emit_global_set(m_compiler_globals[tmp_reg_f32]); + m_wa.emit_drop(); + m_wa.emit_global_get(m_compiler_globals[tmp_reg_f32]); } else if (strcmp(fn->m_name, "c_zaimag") == 0) { - wia.emit_global_set(m_compiler_globals[tmp_reg_f64]); - wia.emit_drop(); - wia.emit_global_get(m_compiler_globals[tmp_reg_f64]); + m_wa.emit_global_set(m_compiler_globals[tmp_reg_f64]); + m_wa.emit_drop(); + m_wa.emit_global_get(m_compiler_globals[tmp_reg_f64]); } else { throw CodeGenError("FunctionCall: Function " + std::string(fn->m_name) + " not found"); } @@ -2405,7 +2181,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { " not yet supported"); } } - wia.emit_global_set(m_compiler_globals[global_var]); + m_wa.emit_global_set(m_compiler_globals[global_var]); } void temp_value_get(ASR::expr_t* expr) { @@ -2454,7 +2230,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { " not yet supported"); } } - wia.emit_global_get(m_compiler_globals[global_var]); + m_wa.emit_global_get(m_compiler_globals[global_var]); } void visit_SubroutineCall(const ASR::SubroutineCall_t &x) { @@ -2481,7 +2257,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { uint64_t hash = get_hash((ASR::asr_t *)s); if (m_func_name_idx_map.find(hash) != m_func_name_idx_map.end()) { - wia.emit_call(m_func_name_idx_map[hash]->index); + m_wa.emit_call(m_func_name_idx_map[hash]->index); } else { throw CodeGenError("SubroutineCall: Function " + std::string(s->m_name) + " not found"); } @@ -2524,13 +2300,13 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { extract_kinds(x, arg_kind, dest_kind); if (arg_kind > 0 && dest_kind > 0) { if (arg_kind == 4 && dest_kind == 4) { - wia.emit_f32_convert_i32_s(); + m_wa.emit_f32_convert_i32_s(); } else if (arg_kind == 8 && dest_kind == 8) { - wia.emit_f64_convert_i64_s(); + m_wa.emit_f64_convert_i64_s(); } else if (arg_kind == 4 && dest_kind == 8) { - wia.emit_f64_convert_i32_s(); + m_wa.emit_f64_convert_i32_s(); } else if (arg_kind == 8 && dest_kind == 4) { - wia.emit_f32_convert_i64_s(); + m_wa.emit_f32_convert_i64_s(); } else { std::string msg = "Conversion from " + std::to_string(arg_kind) + " to " + @@ -2546,13 +2322,13 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { extract_kinds(x, arg_kind, dest_kind); if (arg_kind > 0 && dest_kind > 0) { if (arg_kind == 4 && dest_kind == 4) { - wia.emit_i32_trunc_f32_s(); + m_wa.emit_i32_trunc_f32_s(); } else if (arg_kind == 8 && dest_kind == 8) { - wia.emit_i64_trunc_f64_s(); + m_wa.emit_i64_trunc_f64_s(); } else if (arg_kind == 4 && dest_kind == 8) { - wia.emit_i64_trunc_f32_s(); + m_wa.emit_i64_trunc_f32_s(); } else if (arg_kind == 8 && dest_kind == 4) { - wia.emit_i32_trunc_f64_s(); + m_wa.emit_i32_trunc_f64_s(); } else { std::string msg = "Conversion from " + std::to_string(arg_kind) + " to " + @@ -2569,9 +2345,9 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { if (arg_kind == dest_kind) { } else if (arg_kind == 4 && dest_kind == 8) { - wia.emit_f64_promote_f32(); + m_wa.emit_f64_promote_f32(); } else if (arg_kind == 8 && dest_kind == 4) { - wia.emit_f32_demote_f64(); + m_wa.emit_f32_demote_f64(); } else { std::string msg = "RealToComplex: Conversion from " + std::to_string(arg_kind) + " to " + @@ -2582,10 +2358,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { switch(dest_kind) { case 4: - wia.emit_f32_const(0.0); + m_wa.emit_f32_const(0.0); break; case 8: - wia.emit_f64_const(0.0); + m_wa.emit_f64_const(0.0); break; default: throw CodeGenError("RealToComplex: Only 32 and 64 bits real kinds are supported."); @@ -2597,13 +2373,13 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { extract_kinds(x, arg_kind, dest_kind); if (arg_kind > 0 && dest_kind > 0) { if (arg_kind == 4 && dest_kind == 4) { - wia.emit_f32_convert_i32_s(); + m_wa.emit_f32_convert_i32_s(); } else if (arg_kind == 8 && dest_kind == 8) { - wia.emit_f64_convert_i64_s(); + m_wa.emit_f64_convert_i64_s(); } else if (arg_kind == 4 && dest_kind == 8) { - wia.emit_f64_convert_i32_s(); + m_wa.emit_f64_convert_i32_s(); } else if (arg_kind == 8 && dest_kind == 4) { - wia.emit_f32_convert_i64_s(); + m_wa.emit_f32_convert_i64_s(); } else { std::string msg = "IntegerToComplex: Conversion from " + std::to_string(arg_kind) + " to " + @@ -2615,10 +2391,10 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { switch(dest_kind) { case 4: - wia.emit_f32_const(0.0); + m_wa.emit_f32_const(0.0); break; case 8: - wia.emit_f64_const(0.0); + m_wa.emit_f64_const(0.0); break; default: throw CodeGenError("RealToComplex: Only 32 and 64 bits real kinds are supported."); @@ -2630,12 +2406,12 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { extract_kinds(x, arg_kind, dest_kind); if (arg_kind > 0 && dest_kind > 0) { if (arg_kind == 4 && dest_kind == 4) { - wia.emit_i32_eqz(); - wia.emit_i32_eqz(); + m_wa.emit_i32_eqz(); + m_wa.emit_i32_eqz(); } else if (arg_kind == 8 && dest_kind == 4) { - wia.emit_i64_eqz(); - wia.emit_i64_eqz(); - wia.emit_i32_wrap_i64(); + m_wa.emit_i64_eqz(); + m_wa.emit_i64_eqz(); + m_wa.emit_i32_wrap_i64(); } else { std::string msg = "Conversion from kinds " + std::to_string(arg_kind) + " to " + @@ -2651,14 +2427,14 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { extract_kinds(x, arg_kind, dest_kind); if (arg_kind > 0 && dest_kind > 0) { if (arg_kind == 4 && dest_kind == 4) { - wia.emit_f32_const(0.0); - wia.emit_f32_eq(); - wia.emit_i32_eqz(); + m_wa.emit_f32_const(0.0); + m_wa.emit_f32_eq(); + m_wa.emit_i32_eqz(); } else if (arg_kind == 8 && dest_kind == 4) { - wia.emit_f64_const(0.0); - wia.emit_f64_eq(); - wia.emit_i64_eqz(); - wia.emit_i32_wrap_i64(); + m_wa.emit_f64_const(0.0); + m_wa.emit_f64_eq(); + m_wa.emit_i64_eqz(); + m_wa.emit_i32_wrap_i64(); } else { std::string msg = "Conversion from kinds " + std::to_string(arg_kind) + " to " + @@ -2679,14 +2455,14 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { extract_kinds(x, arg_kind, dest_kind); if (arg_kind == 4) { INCLUDE_RUNTIME_FUNC(abs_c32); - wia.emit_call(m_rt_func_used_idx[abs_c32]); - wia.emit_f32_const(0.0); - wia.emit_f32_gt(); + m_wa.emit_call(m_rt_func_used_idx[abs_c32]); + m_wa.emit_f32_const(0.0); + m_wa.emit_f32_gt(); } else if (arg_kind == 8) { INCLUDE_RUNTIME_FUNC(abs_c64); - wia.emit_call(m_rt_func_used_idx[abs_c64]); - wia.emit_f64_const(0.0); - wia.emit_f64_gt(); + m_wa.emit_call(m_rt_func_used_idx[abs_c64]); + m_wa.emit_f64_const(0.0); + m_wa.emit_f64_gt(); } else { std::string msg = "ComplexToLogical: Conversion from kinds " + std::to_string(arg_kind) + " to " + @@ -2701,7 +2477,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { extract_kinds(x, arg_kind, dest_kind); if (arg_kind > 0 && dest_kind > 0) { if (arg_kind == 4 && dest_kind == 8) { - wia.emit_i64_extend_i32_s(); + m_wa.emit_i64_extend_i32_s(); } else if (arg_kind == 4 && dest_kind == 4) { } else { std::string msg = "Conversion from kinds " + @@ -2718,9 +2494,9 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { extract_kinds(x, arg_kind, dest_kind); if (arg_kind > 0 && dest_kind > 0) { if (arg_kind == 4 && dest_kind == 4) { - wia.emit_f32_convert_i32_s(); + m_wa.emit_f32_convert_i32_s(); } else if (arg_kind == 4 && dest_kind == 8) { - wia.emit_f64_convert_i32_s(); + m_wa.emit_f64_convert_i32_s(); } else { std::string msg = "Conversion from kinds " + std::to_string(arg_kind) + " to " + @@ -2736,9 +2512,9 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { extract_kinds(x, arg_kind, dest_kind); if (arg_kind > 0 && dest_kind > 0 && arg_kind != dest_kind) { if (arg_kind == 4 && dest_kind == 8) { - wia.emit_i64_extend_i32_s(); + m_wa.emit_i64_extend_i32_s(); } else if (arg_kind == 8 && dest_kind == 4) { - wia.emit_i32_wrap_i64(); + m_wa.emit_i32_wrap_i64(); } else { std::string msg = "Conversion from " + std::to_string(arg_kind) + " to " + @@ -2754,9 +2530,9 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { extract_kinds(x, arg_kind, dest_kind); if (arg_kind > 0 && dest_kind > 0 && arg_kind != dest_kind) { if (arg_kind == 4 && dest_kind == 8) { - wia.emit_f64_promote_f32(); + m_wa.emit_f64_promote_f32(); } else if (arg_kind == 8 && dest_kind == 4) { - wia.emit_f32_demote_f64(); + m_wa.emit_f32_demote_f64(); } else { std::string msg = "Conversion from " + std::to_string(arg_kind) + " to " + @@ -2772,15 +2548,15 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { extract_kinds(x, arg_kind, dest_kind); if (arg_kind > 0 && dest_kind > 0 && arg_kind != dest_kind) { if (arg_kind == 4 && dest_kind == 8) { - wia.emit_f64_promote_f32(); - wia.emit_global_set(m_compiler_globals[tmp_reg_f64]); - wia.emit_f64_promote_f32(); - wia.emit_global_get(m_compiler_globals[tmp_reg_f64]); + m_wa.emit_f64_promote_f32(); + m_wa.emit_global_set(m_compiler_globals[tmp_reg_f64]); + m_wa.emit_f64_promote_f32(); + m_wa.emit_global_get(m_compiler_globals[tmp_reg_f64]); } else if (arg_kind == 8 && dest_kind == 4) { - wia.emit_f32_demote_f64(); - wia.emit_global_set(m_compiler_globals[tmp_reg_f32]); - wia.emit_f32_demote_f64(); - wia.emit_global_get(m_compiler_globals[tmp_reg_f32]); + m_wa.emit_f32_demote_f64(); + m_wa.emit_global_set(m_compiler_globals[tmp_reg_f32]); + m_wa.emit_f32_demote_f64(); + m_wa.emit_global_get(m_compiler_globals[tmp_reg_f32]); } else { std::string msg = "ComplexToComplex: Conversion from " + std::to_string(arg_kind) + " to " + @@ -2792,14 +2568,14 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { break; } case (ASR::cast_kindType::ComplexToReal): { - wia.emit_drop(); // drop imag part + m_wa.emit_drop(); // drop imag part int arg_kind = -1, dest_kind = -1; extract_kinds(x, arg_kind, dest_kind); if (arg_kind > 0 && dest_kind > 0 && arg_kind != dest_kind) { if (arg_kind == 4 && dest_kind == 8) { - wia.emit_f64_promote_f32(); + m_wa.emit_f64_promote_f32(); } else if (arg_kind == 8 && dest_kind == 4) { - wia.emit_f32_demote_f64(); + m_wa.emit_f32_demote_f64(); } else { std::string msg = "ComplexToReal: Conversion from " + std::to_string(arg_kind) + " to " + @@ -2817,28 +2593,28 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { void visit_ComplexRe(const ASR::ComplexRe_t &x) { this->visit_expr(*x.m_arg); - wia.emit_drop(); + m_wa.emit_drop(); } void visit_ComplexIm(const ASR::ComplexIm_t &x) { this->visit_expr(*x.m_arg); int a_kind = ASRUtils::extract_kind_from_ttype_t(ASRUtils::expr_type(x.m_arg)); - wia.emit_global_set((a_kind == 4) ? m_compiler_globals[tmp_reg_f32] + m_wa.emit_global_set((a_kind == 4) ? m_compiler_globals[tmp_reg_f32] : m_compiler_globals[tmp_reg_f64]); - wia.emit_drop(); - wia.emit_global_get((a_kind == 4) ? m_compiler_globals[tmp_reg_f32] + m_wa.emit_drop(); + m_wa.emit_global_get((a_kind == 4) ? m_compiler_globals[tmp_reg_f32] : m_compiler_globals[tmp_reg_f64]); } void emit_call_fd_write(int filetype, const std::string &str, int iov_vec_len, int return_val_mem_loc) { - wia.emit_i32_const(filetype); // file type: 1 for stdout - wia.emit_i32_const(m_string_to_iov_loc_map[str]); // iov location - wia.emit_i32_const(iov_vec_len); // size of iov vector - wia.emit_i32_const(return_val_mem_loc); // mem_loction to return no. of bytes written + 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 - wia.emit_call(m_import_func_idx_map[fd_write]); - wia.emit_drop(); + m_wa.emit_call(m_import_func_idx_map[fd_write]); + m_wa.emit_drop(); } template @@ -2846,14 +2622,14 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { for (size_t i = 0; i < x.n_values; i++) { if (i > 0) { if (x.m_separator) { - wia.emit_i32_const(1); // file type: 1 for stdout + m_wa.emit_i32_const(1); // file type: 1 for stdout this->visit_expr(*x.m_separator); // iov location - wia.emit_i32_const(1); // size of iov vector - wia.emit_i32_const(0); // mem_loction to return no. of bytes written + 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 - wia.emit_call(m_import_func_idx_map[fd_write]); - wia.emit_drop(); + m_wa.emit_call(m_import_func_idx_map[fd_write]); + m_wa.emit_drop(); } else { emit_call_fd_write(1, " ", 1, 0); } @@ -2867,12 +2643,12 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { this->visit_expr(*x.m_values[i]); switch (a_kind) { case 4: { - wia.emit_i64_extend_i32_s(); - wia.emit_call(m_rt_func_used_idx[print_i64]); + m_wa.emit_i64_extend_i32_s(); + m_wa.emit_call(m_rt_func_used_idx[print_i64]); break; } case 8: { - wia.emit_call(m_rt_func_used_idx[print_i64]); + m_wa.emit_call(m_rt_func_used_idx[print_i64]); break; } default: { @@ -2887,12 +2663,12 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { this->visit_expr(*x.m_values[i]); switch (a_kind) { case 4: { - wia.emit_f64_promote_f32(); - wia.emit_call(m_rt_func_used_idx[print_f64]); + m_wa.emit_f64_promote_f32(); + m_wa.emit_call(m_rt_func_used_idx[print_f64]); break; } case 8: { - wia.emit_call(m_rt_func_used_idx[print_f64]); + m_wa.emit_call(m_rt_func_used_idx[print_f64]); break; } default: { @@ -2902,44 +2678,44 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } } } else if (t->type == ASR::ttypeType::Character) { - wia.emit_i32_const(1); // file type: 1 for stdout + m_wa.emit_i32_const(1); // file type: 1 for stdout this->visit_expr(*x.m_values[i]); // iov location - wia.emit_i32_const(1); // size of iov vector - wia.emit_i32_const(0); // mem_loction to return no. of bytes written + 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 - wia.emit_call(m_import_func_idx_map[fd_write]); - wia.emit_drop(); + m_wa.emit_call(m_import_func_idx_map[fd_write]); + m_wa.emit_drop(); } else if (t->type == ASR::ttypeType::Complex) { INCLUDE_RUNTIME_FUNC(print_i64); INCLUDE_RUNTIME_FUNC(print_f64); emit_call_fd_write(1, "(", 1, 0); this->visit_expr(*x.m_values[i]); if (a_kind == 4) { - wia.emit_f64_promote_f32(); - wia.emit_global_set(m_compiler_globals[tmp_reg_f64]); - wia.emit_f64_promote_f32(); + m_wa.emit_f64_promote_f32(); + m_wa.emit_global_set(m_compiler_globals[tmp_reg_f64]); + m_wa.emit_f64_promote_f32(); } else { - wia.emit_global_set(m_compiler_globals[tmp_reg_f64]); + m_wa.emit_global_set(m_compiler_globals[tmp_reg_f64]); } - wia.emit_call(m_rt_func_used_idx[print_f64]); + m_wa.emit_call(m_rt_func_used_idx[print_f64]); emit_call_fd_write(1, ",", 1, 0); - wia.emit_global_get(m_compiler_globals[tmp_reg_f64]); - wia.emit_call(m_rt_func_used_idx[print_f64]); + m_wa.emit_global_get(m_compiler_globals[tmp_reg_f64]); + m_wa.emit_call(m_rt_func_used_idx[print_f64]); emit_call_fd_write(1, ")", 1, 0); } } // print "\n" newline character if (x.m_end) { - wia.emit_i32_const(1); // file type: 1 for stdout + m_wa.emit_i32_const(1); // file type: 1 for stdout this->visit_expr(*x.m_end); // iov location - wia.emit_i32_const(1); // size of iov vector - wia.emit_i32_const(0); // mem_loction to return no. of bytes written + 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 - wia.emit_call(m_import_func_idx_map[fd_write]); - wia.emit_drop(); + m_wa.emit_call(m_import_func_idx_map[fd_write]); + m_wa.emit_drop(); } else { emit_call_fd_write(1, "\n", 1, 0); } @@ -2995,11 +2771,11 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { emit_call_fd_write(1, msg, 1, 0); } - void exit() { + void wasm_exit() { // exit_code would be on stack, so set this exit code using // proc_exit(). this exit code would be read by JavaScript glue code - wia.emit_call(m_import_func_idx_map[proc_exit]); - wia.emit_unreachable(); // raise trap/exception + m_wa.emit_call(m_import_func_idx_map[proc_exit]); + m_wa.emit_unreachable(); // raise trap/exception } void visit_ArrayBound(const ASR::ArrayBound_t& x) { @@ -3023,13 +2799,13 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } else { this->visit_expr(*m_dims[dimDir->m_n - 1].m_start); this->visit_expr(*m_dims[dimDir->m_n - 1].m_length); - wia.emit_i32_add(); - wia.emit_i32_const(1); - wia.emit_i32_sub(); + m_wa.emit_i32_add(); + m_wa.emit_i32_const(1); + m_wa.emit_i32_sub(); } } else { if (x.m_bound == ASR::arrayboundType::LBound) { - wia.emit_i32_const(1); + m_wa.emit_i32_const(1); } else { // emit the whole array size if (!m_dims[0].m_length) { @@ -3039,7 +2815,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { this->visit_expr(*(m_dims[0].m_length)); for (int i = 1; i < n_dims; i++) { this->visit_expr(*m_dims[i].m_length); - wia.emit_i32_mul(); + m_wa.emit_i32_mul(); } } } @@ -3051,19 +2827,19 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { ASRUtils::expr_type(x.m_code)->type == ASR::ttypeType::Integer) { this->visit_expr(*x.m_code); } else { - wia.emit_i32_const(0); // zero exit code + m_wa.emit_i32_const(0); // zero exit code } - exit(); + wasm_exit(); } void visit_ErrorStop(const ASR::ErrorStop_t & /* x */) { print_msg("ERROR STOP"); - wia.emit_i32_const(1); // non-zero exit code - exit(); + m_wa.emit_i32_const(1); // non-zero exit code + wasm_exit(); } void visit_If(const ASR::If_t &x) { - emit_if_else([&](){ this->visit_expr(*x.m_test); }, [&](){ + m_wa.emit_if_else([&](){ this->visit_expr(*x.m_test); }, [&](){ for (size_t i = 0; i < x.n_body; i++) { this->visit_stmt(*x.m_body[i]); } @@ -3075,7 +2851,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } void visit_WhileLoop(const ASR::WhileLoop_t &x) { - emit_loop([&](){ this->visit_expr(*x.m_test); }, [&](){ + m_wa.emit_loop([&](){ this->visit_expr(*x.m_test); }, [&](){ for (size_t i = 0; i < x.n_body; i++) { this->visit_stmt(*x.m_body[i]); } @@ -3083,28 +2859,27 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } void visit_Exit(const ASR::Exit_t & /* x */) { - wia.emit_br(nesting_level - cur_loop_nesting_level - 2U); // branch to end of if + m_wa.emit_br(m_wa.nest_lvl - m_wa.cur_loop_nest_lvl - 2U); // branch to end of if } void visit_Cycle(const ASR::Cycle_t & /* x */) { - wia.emit_br(nesting_level - cur_loop_nesting_level - 1U); // branch to start of loop + m_wa.emit_br(m_wa.nest_lvl - m_wa.cur_loop_nest_lvl - 1U); // branch to start of loop } void visit_Assert(const ASR::Assert_t &x) { - this->visit_expr(*x.m_test); - wasm::emit_b8(m_code_section, m_al, 0x04); // emit if start - wasm::emit_b8(m_code_section, m_al, 0x40); // empty block type - wasm::emit_b8(m_code_section, m_al, 0x05); // starting of else - if (x.m_msg) { - std::string msg = - ASR::down_cast(x.m_msg)->m_s; - print_msg("AssertionError: " + msg); - } else { - print_msg("AssertionError"); - } - wia.emit_i32_const(1); // non-zero exit code - exit(); - wasm::emit_expr_end(m_code_section, m_al); + m_wa.emit_if_else([&](){ + this->visit_expr(*x.m_test); + }, [&](){}, [&](){ + if (x.m_msg) { + std::string msg = + ASR::down_cast(x.m_msg)->m_s; + print_msg("AssertionError: " + msg); + } else { + print_msg("AssertionError"); + } + m_wa.emit_i32_const(1); // non-zero exit code + wasm_exit(); + }); } }; @@ -3112,7 +2887,6 @@ Result> asr_to_wasm_bytes_stream(ASR::TranslationUnit_t &asr, Allocator &al, diag::Diagnostics &diagnostics) { ASRToWASMVisitor v(al, diagnostics); - Vec wasm_bytes; LCompilers::PassOptions pass_options; pass_array_by_data(al, asr, pass_options); @@ -3134,9 +2908,7 @@ Result> asr_to_wasm_bytes_stream(ASR::TranslationUnit_t &asr, return Error(); } - v.get_wasm(wasm_bytes); - - return wasm_bytes; + return v.m_wa.get_wasm(); } Result asr_to_wasm(ASR::TranslationUnit_t &asr, Allocator &al, diff --git a/src/libasr/codegen/wasm_assembler.h b/src/libasr/codegen/wasm_assembler.h index 8d949f8f86..bc5f40bab2 100644 --- a/src/libasr/codegen/wasm_assembler.h +++ b/src/libasr/codegen/wasm_assembler.h @@ -1,30 +1,15 @@ #include #include +#include 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_expr_end(Vec &code, Allocator &al) { code.push_back(al, 0x0B); } -// 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 string void emit_str(Vec &code, Allocator &al, std::string text) { std::vector text_bytes(text.size()); @@ -33,13 +18,14 @@ void emit_str(Vec &code, Allocator &al, std::string text) { for (auto &byte : text_bytes) emit_b8(code, al, byte); } -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_b8(code, al, 0x41); // i32.const - emit_i32(code, al, (int32_t)mem_idx); // specifying memory location - emit_expr_end(code, al); // end instructions - emit_str(code, al, text); +// 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; } void emit_u32_b32_idx(Vec &code, Allocator &al, uint32_t idx, @@ -67,150 +53,6 @@ void fixup_len(Vec &code, Allocator &al, uint32_t len_idx) { emit_u32_b32_idx(code, al, len_idx, section_len); } -// 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; -} - -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); -} - -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_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); - } -} - -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_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 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); - } -} - -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; -} - -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); } -} - -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 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)) -} - -main(); -)"; - filename += ".js"; - std::ofstream out(filename); - out << js_glue; - out.close(); -} - void save_js_glue_wasi(std::string filename) { std::string js_glue = R"(async function main() { @@ -244,4 +86,302 @@ void save_bin(Vec &code, std::string filename) { } // namespace wasm +class WASMAssembler: public WASM_INSTS_VISITOR::WASMInstsAssembler { + private: + Allocator &m_al; + + 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_segs; + + public: + + int nest_lvl; + int cur_loop_nest_lvl; + + WASMAssembler(Allocator &al) : WASMInstsAssembler(al, m_code_section), m_al(al) { + nest_lvl = 0; + cur_loop_nest_lvl = 0; + + 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_segs = 0; + + 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); + } + + uint32_t get_no_of_types() { + return no_of_types; + } + + // function to emit header of Wasm Binary Format + void emit_header(Vec &code) { + code.push_back(m_al, 0x00); + code.push_back(m_al, 0x61); + code.push_back(m_al, 0x73); + code.push_back(m_al, 0x6D); + code.push_back(m_al, 0x01); + code.push_back(m_al, 0x00); + code.push_back(m_al, 0x00); + code.push_back(m_al, 0x00); + } + + 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); // emit header and version + encode_section(code, m_type_section, 1U, no_of_types); + encode_section(code, m_import_section, 2U, no_of_imports); + encode_section(code, m_func_section, 3U, no_of_functions); + encode_section(code, m_memory_section, 5U, no_of_memories); + encode_section(code, m_global_section, 6U, no_of_globals); + encode_section(code, m_export_section, 7U, no_of_exports); + encode_section(code, m_code_section, 10U, no_of_functions); + encode_section(code, m_data_section, 11U, no_of_data_segs); + return code; + } + + 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 + nest_lvl++; + if_block(); + wasm::emit_b8(m_code_section, m_al, 0x05); // starting of else + else_block(); + nest_lvl--; + wasm::emit_expr_end(m_code_section, m_al); // instructions end + } + + void emit_loop(std::function test_cond, std::function loop_block) { + uint32_t prev_cur_loop_nest_lvl = cur_loop_nest_lvl; + cur_loop_nest_lvl = nest_lvl; + + wasm::emit_b8(m_code_section, m_al, 0x03); // emit loop start + wasm::emit_b8(m_code_section, m_al, 0x40); // empty block type + + nest_lvl++; + + 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_br(nest_lvl - cur_loop_nest_lvl - 1); // emit_branch and label the loop + }, [&](){}); + + nest_lvl--; + wasm::emit_expr_end(m_code_section, m_al); // instructions end + cur_loop_nest_lvl = prev_cur_loop_nest_lvl; + } + + uint32_t emit_func_type(std::vector ¶ms, std::vector &results) { + wasm::emit_b8(m_type_section, m_al, 0x60); + + wasm::emit_u32(m_type_section, m_al, params.size()); + for (auto param:params) { + wasm::emit_b8(m_type_section, m_al, param); + } + + wasm::emit_u32(m_type_section, m_al, results.size()); + for (auto result:results) { + wasm::emit_b8(m_type_section, m_al, result); + } + + return no_of_types++; + } + + void emit_import_fn(const std::string &mod_name, const std::string &fn_name, + uint32_t type_idx) { + wasm::emit_str(m_import_section, m_al, mod_name); + wasm::emit_str(m_import_section, m_al, fn_name); + wasm::emit_b8(m_import_section, m_al, 0x00); // for importing function + wasm::emit_u32(m_import_section, m_al, type_idx); + no_of_imports++; + } + + void emit_export_fn(const std::string &name, uint32_t idx) { + wasm::emit_str(m_export_section, m_al, name); + wasm::emit_b8(m_export_section, m_al, 0x00); // for exporting function + wasm::emit_u32(m_export_section, m_al, idx); + no_of_exports++; + } + + void emit_declare_mem(uint32_t min_no_pages, uint32_t max_no_pages = 0) { + if (max_no_pages > 0) { + wasm::emit_b8(m_memory_section, m_al, + 0x01); // for specifying min and max page limits of memory + wasm::emit_u32(m_memory_section, m_al, min_no_pages); + wasm::emit_u32(m_memory_section, m_al, max_no_pages); + } else { + wasm::emit_b8(m_memory_section, m_al, + 0x00); // for specifying only min page limit of memory + wasm::emit_u32(m_memory_section, m_al, min_no_pages); + } + no_of_memories++; + } + + 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) { + wasm::emit_str(m_import_section, m_al, mod_name); + wasm::emit_str(m_import_section, m_al, mem_name); + wasm::emit_b8(m_import_section, m_al, 0x02); // for importing memory + if (max_no_pages > 0) { + wasm::emit_b8(m_import_section, m_al, + 0x01); // for specifying min and max page limits of memory + wasm::emit_u32(m_import_section, m_al, min_no_pages); + wasm::emit_u32(m_import_section, m_al, max_no_pages); + } else { + wasm::emit_b8(m_import_section, m_al, + 0x00); // for specifying only min page limit of memory + wasm::emit_u32(m_import_section, m_al, min_no_pages); + } + no_of_imports++; + } + + void emit_export_mem(const std::string &name, + uint32_t idx) { + wasm::emit_str(m_export_section, m_al, name); + wasm::emit_b8(m_export_section, m_al, 0x02); // for exporting memory + wasm::emit_u32(m_export_section, m_al, idx); + no_of_exports++; + } + + void encode_section(Vec &des, Vec §ion_content, + 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 + wasm::emit_u32(des, m_al, section_id); + wasm::emit_u32(des, m_al, 4U /* size of no_of_elements */ + section_content.size()); + uint32_t len_idx = wasm::emit_len_placeholder(des, m_al); + wasm::emit_u32_b32_idx(des, m_al, len_idx, no_of_elements); + for (auto &byte : section_content) { + des.push_back(m_al, byte); + } + } + + void emit_func_body(uint32_t func_idx, std::string func_name, std::vector &locals, std::function func_body) { + /*** 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); + + + { + uint32_t len_idx_code_section_no_of_locals = + wasm::emit_len_placeholder(m_code_section, m_al); + uint32_t no_of_locals = emit_local_vars(locals); + wasm::emit_u32_b32_idx(m_code_section, m_al, + len_idx_code_section_no_of_locals, no_of_locals); + } + + func_body(); + + 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 ***/ + emit_export_fn(func_name, func_idx); + no_of_functions++; + } + + void define_func( + std::vector params, + std::vector results, + std::vector locals, + std::string func_name, + std::function func_body) { + + uint32_t func_idx = emit_func_type(params, results); + emit_func_body(func_idx, func_name, locals, func_body); + } + + template + uint32_t declare_global_var(wasm::var_type var_type, T init_val) { + m_global_section.push_back(m_al, var_type); + m_global_section.push_back(m_al, true /* mutable */); + switch (var_type) + { + case wasm::i32: + wasm::emit_b8(m_global_section, m_al, 0x41); // emit instruction + wasm::emit_i32(m_global_section, m_al, init_val); // emit val + break; + case wasm::i64: + wasm::emit_b8(m_global_section, m_al, 0x42); // emit instruction + wasm::emit_i64(m_global_section, m_al, init_val); // emit val + break; + case wasm::f32: + wasm::emit_b8(m_global_section, m_al, 0x43); // emit instruction + wasm::emit_f32(m_global_section, m_al, init_val); // emit val + break; + case wasm::f64: + wasm::emit_b8(m_global_section, m_al, 0x44); // emit instruction + wasm::emit_f64(m_global_section, m_al, init_val); // emit val + break; + default: + std::cerr << "declare_global_var: Unsupported type" << std::endl; + LCOMPILERS_ASSERT(false); + } + wasm::emit_expr_end(m_global_section, m_al); + return no_of_globals++; + } + + uint32_t emit_local_vars(std::vector locals) { + uint32_t no_of_locals = 0; + for (auto v:locals) { + wasm::emit_u32(m_code_section, m_al, 1); + wasm::emit_b8(m_code_section, m_al, v); + no_of_locals++; + } + return no_of_locals; + } + + void emit_data_str(uint32_t mem_idx, const std::string &text) { + wasm::emit_u32(m_data_section, m_al, 0U); // for active mode of memory with default mem_idx of 0 + wasm::emit_b8(m_data_section, m_al, 0x41); // i32.const + wasm::emit_i32(m_data_section, m_al, (int32_t)mem_idx); // specifying memory location + wasm::emit_expr_end(m_data_section, m_al); // end instructions + wasm::emit_str(m_data_section, m_al, text); + no_of_data_segs++; + } +}; + } // namespace LCompilers diff --git a/src/libasr/codegen/wasm_decoder.h b/src/libasr/codegen/wasm_decoder.h index d2a7fdebef..c42405ad16 100644 --- a/src/libasr/codegen/wasm_decoder.h +++ b/src/libasr/codegen/wasm_decoder.h @@ -4,8 +4,6 @@ #include #include -#include -#include #include // #define WAT_DEBUG @@ -48,9 +46,6 @@ class WASMDecoder { Struct &self() { return static_cast(*this); } public: - std::unordered_map var_type_to_string; - std::unordered_map kind_to_string; - Allocator &al; diag::Diagnostics &diag; Vec wasm_bytes; @@ -67,10 +62,6 @@ class WASMDecoder { WASMDecoder(Allocator &al, diag::Diagnostics &diagonostics) : al(al), diag(diagonostics) { - var_type_to_string = { - {0x7F, "i32"}, {0x7E, "i64"}, {0x7D, "f32"}, {0x7C, "f64"}}; - kind_to_string = { - {0x00, "func"}, {0x01, "table"}, {0x02, "memory"}, {0x03, "global"}}; PREAMBLE_SIZE = 8 /* BYTES */; // wasm_bytes.reserve(al, 1024 * 128); diff --git a/src/libasr/codegen/wasm_to_wat.cpp b/src/libasr/codegen/wasm_to_wat.cpp index 25bff32dfb..2ca0e7f2d9 100644 --- a/src/libasr/codegen/wasm_to_wat.cpp +++ b/src/libasr/codegen/wasm_to_wat.cpp @@ -313,13 +313,12 @@ class WATVisitor : public WASMDecoder, result += indent + "(type (;" + std::to_string(i) + ";) (func (param"; for (uint32_t j = 0; j < func_types[i].param_types.size(); j++) { - result += - " " + var_type_to_string[func_types[i].param_types.p[j]]; + result += " " + vt2s(func_types[i].param_types.p[j]); } result += ") (result"; for (uint32_t j = 0; j < func_types[i].result_types.size(); j++) { result += - " " + var_type_to_string[func_types[i].result_types.p[j]]; + " " + vt2s(func_types[i].result_types.p[j]); } result += ")))"; } @@ -350,8 +349,8 @@ class WATVisitor : public WASMDecoder, decode_instructions(); global_initialization_insts = this->src; } - std::string global_type = ((globals[i].mut == 0x00) ? var_type_to_string[globals[i].type]: - "(mut " + var_type_to_string[globals[i].type] + ")" ); + std::string global_type = ((globals[i].mut == 0x00) ? vt2s(globals[i].type): + "(mut " + vt2s(globals[i].type) + ")" ); result += indent + "(global $" + std::to_string(i); result += " " + global_type; result += " (" + global_initialization_insts + "))"; @@ -365,20 +364,20 @@ class WATVisitor : public WASMDecoder, j++) { result += " " + - var_type_to_string[func_types[func_index].param_types.p[j]]; + vt2s(func_types[func_index].param_types.p[j]); } result += ") (result"; for (uint32_t j = 0; j < func_types[func_index].result_types.size(); j++) { - result += " " + var_type_to_string[func_types[func_index] - .result_types.p[j]]; + result += " " + vt2s(func_types[func_index] + .result_types.p[j]); } result += ")"; result += indent + " (local"; for (uint32_t j = 0; j < codes.p[i].locals.size(); j++) { for (uint32_t k = 0; k < codes.p[i].locals.p[j].count; k++) { result += - " " + var_type_to_string[codes.p[i].locals.p[j].type]; + " " + vt2s(codes.p[i].locals.p[j].type); } } result += ")"; @@ -403,7 +402,7 @@ class WATVisitor : public WASMDecoder, for (uint32_t i = 0; i < exports.size(); i++) { result += indent + "(export \"" + exports.p[i].name + "\" (" + - kind_to_string[exports.p[i].kind] + " " + + k2s(exports.p[i].kind) + " " + std::to_string(exports.p[i].index) + "))"; } diff --git a/src/libasr/codegen/wasm_to_x64.cpp b/src/libasr/codegen/wasm_to_x64.cpp index 4338b42300..af048265d2 100644 --- a/src/libasr/codegen/wasm_to_x64.cpp +++ b/src/libasr/codegen/wasm_to_x64.cpp @@ -212,7 +212,7 @@ class X64Visitor : public WASMDecoder, void visit_GlobalGet(uint32_t globalidx) { std::string loc = "global_" + std::to_string(globalidx); - std::string var_type = var_type_to_string[globals[globalidx].type]; + std::string var_type = vt2s(globals[globalidx].type); X64Reg base = X64Reg::rbx; m_a.asm_mov_r64_label(X64Reg::rbx, loc); @@ -235,7 +235,7 @@ class X64Visitor : public WASMDecoder, } std::string loc = "global_" + std::to_string(globalidx); - std::string var_type = var_type_to_string[globals[globalidx].type]; + std::string var_type = vt2s(globals[globalidx].type); X64Reg base = X64Reg::rbx; m_a.asm_mov_r64_label(X64Reg::rbx, loc); @@ -257,7 +257,7 @@ class X64Visitor : public WASMDecoder, auto cur_func_param_type = func_types[type_indices[cur_func_idx]]; int no_of_params = (int)cur_func_param_type.param_types.size(); if ((int)localidx < no_of_params) { - std::string var_type = var_type_to_string[cur_func_param_type.param_types[localidx]]; + std::string var_type = vt2s(cur_func_param_type.param_types[localidx]); if (var_type == "i32" || var_type == "i64") { m_a.asm_mov_r64_m64(X64Reg::rax, &base, nullptr, 1, 8 * (2 + no_of_params - (int)localidx - 1)); m_a.asm_push_r64(X64Reg::rax); @@ -271,7 +271,7 @@ class X64Visitor : public WASMDecoder, } } else { localidx -= no_of_params; - std::string var_type = var_type_to_string[codes[cur_func_idx].locals[localidx].type]; + std::string var_type = vt2s(codes[cur_func_idx].locals[localidx].type); if (var_type == "i32" || var_type == "i64") { m_a.asm_mov_r64_m64(X64Reg::rax, &base, nullptr, 1, -8 * (1 + (int)localidx)); m_a.asm_push_r64(X64Reg::rax); @@ -291,7 +291,7 @@ class X64Visitor : public WASMDecoder, auto cur_func_param_type = func_types[type_indices[cur_func_idx]]; int no_of_params = (int)cur_func_param_type.param_types.size(); if ((int)localidx < no_of_params) { - std::string var_type = var_type_to_string[cur_func_param_type.param_types[localidx]]; + std::string var_type = vt2s(cur_func_param_type.param_types[localidx]); if (var_type == "i32" || var_type == "i64") { m_a.asm_pop_r64(X64Reg::rax); m_a.asm_mov_m64_r64(&base, nullptr, 1, 8 * (2 + no_of_params - (int)localidx - 1), X64Reg::rax); @@ -305,7 +305,7 @@ class X64Visitor : public WASMDecoder, } } else { localidx -= no_of_params; - std::string var_type = var_type_to_string[codes[cur_func_idx].locals[localidx].type]; + std::string var_type = vt2s(codes[cur_func_idx].locals[localidx].type); if (var_type == "i32" || var_type == "i64") { m_a.asm_pop_r64(X64Reg::rax); m_a.asm_mov_m64_r64(&base, nullptr, 1, -8 * (1 + (int)localidx), X64Reg::rax); diff --git a/src/libasr/codegen/wasm_to_x86.cpp b/src/libasr/codegen/wasm_to_x86.cpp index e948b5bc09..ac3c62ca6e 100644 --- a/src/libasr/codegen/wasm_to_x86.cpp +++ b/src/libasr/codegen/wasm_to_x86.cpp @@ -209,7 +209,7 @@ class X86Visitor : public WASMDecoder, auto cur_func_param_type = func_types[type_indices[cur_func_idx]]; int no_of_params = (int)cur_func_param_type.param_types.size(); if ((int)localidx < no_of_params) { - std::string var_type = var_type_to_string[cur_func_param_type.param_types[localidx]]; + std::string var_type = vt2s(cur_func_param_type.param_types[localidx]); if (var_type == "i32") { m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, 4 * (2 + no_of_params - (int)localidx - 1)); m_a.asm_push_r32(X86Reg::eax); @@ -227,7 +227,7 @@ class X86Visitor : public WASMDecoder, } else { localidx -= no_of_params; - std::string var_type = var_type_to_string[codes[cur_func_idx].locals[localidx].type]; + std::string var_type = vt2s(codes[cur_func_idx].locals[localidx].type); if (var_type == "i32") { m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, -4 * (1 + localidx)); m_a.asm_push_r32(X86Reg::eax); @@ -249,7 +249,7 @@ class X86Visitor : public WASMDecoder, auto cur_func_param_type = func_types[type_indices[cur_func_idx]]; int no_of_params = (int)cur_func_param_type.param_types.size(); if ((int)localidx < no_of_params) { - std::string var_type = var_type_to_string[cur_func_param_type.param_types[localidx]]; + std::string var_type = vt2s(cur_func_param_type.param_types[localidx]); if (var_type == "i32") { m_a.asm_pop_r32(X86Reg::eax); m_a.asm_mov_m32_r32(&base, nullptr, 1, 4 * (2 + no_of_params - (int)localidx - 1), X86Reg::eax); @@ -267,7 +267,7 @@ class X86Visitor : public WASMDecoder, } else { localidx -= no_of_params; - std::string var_type = var_type_to_string[codes[cur_func_idx].locals[localidx].type]; + std::string var_type = vt2s(codes[cur_func_idx].locals[localidx].type); if (var_type == "i32") { m_a.asm_pop_r32(X86Reg::eax); m_a.asm_mov_m32_r32(&base, nullptr, 1, -4 * (1 + (int)localidx), X86Reg::eax); diff --git a/src/libasr/codegen/wasm_utils.h b/src/libasr/codegen/wasm_utils.h index d82f8fd42f..7745840299 100644 --- a/src/libasr/codegen/wasm_utils.h +++ b/src/libasr/codegen/wasm_utils.h @@ -11,6 +11,56 @@ namespace LCompilers { namespace wasm { +enum var_type: uint8_t { + i32 = 0x7F, + i64 = 0x7E, + f32 = 0x7D, + f64 = 0x7C +}; + +enum mem_align : uint8_t { + b8 = 0, + b16 = 1, + b32 = 2, + b64 = 3 +}; + +enum wasm_kind: uint8_t { + func = 0x00, + table = 0x01, + memory = 0x02, + global = 0x03 +}; + +template +std::string vt2s(T vt) { + switch(vt) { + case var_type::i32: return "i32"; + case var_type::i64: return "i64"; + case var_type::f32: return "f32"; + case var_type::f64: return "f64"; + default: + std::cerr << "Unsupported wasm var_type" << std::endl; + LCOMPILERS_ASSERT(false); + return ""; + + } +} + +template +std::string k2s(T k) { + switch(k) { + case wasm_kind::func: return "func"; + case wasm_kind::table: return "table"; + case wasm_kind::memory: return "memory"; + case wasm_kind::global: return "global"; + default: + std::cerr << "Unsupported wasm kind" << std::endl; + LCOMPILERS_ASSERT(false); + return ""; + } +} + struct FuncType { Vec param_types; Vec result_types; diff --git a/src/libasr/wasm_instructions_visitor.py b/src/libasr/wasm_instructions_visitor.py index 22df52eea4..614042ac48 100644 --- a/src/libasr/wasm_instructions_visitor.py +++ b/src/libasr/wasm_instructions_visitor.py @@ -105,10 +105,12 @@ def visit_BaseWASMVisitor(self, mod, *args): self.emit("};\n", 0) def visit_WASMInstsAssembler(self, mod): + self.emit("template ", 0) self.emit("class WASMInstsAssembler {", 0) self.emit("private:", 0) self.emit( "Allocator &m_al;", 1) self.emit( "Vec &m_code;\n", 1) + self.emit( "Struct &self() { return static_cast(*this); }", 1) self.emit("public:", 0) self.emit( "WASMInstsAssembler(Allocator &al, Vec &code): m_al(al), m_code(code) {}\n", 1)