From 45752608405e75cd167615abd0afc5b4a902232d Mon Sep 17 00:00:00 2001 From: Ubaid Date: Thu, 10 Nov 2022 18:17:48 +0530 Subject: [PATCH 1/9] WASM_X86: Define emit_exit2() --- src/libasr/codegen/x86_assembler.cpp | 9 +++++++++ src/libasr/codegen/x86_assembler.h | 1 + 2 files changed, 10 insertions(+) diff --git a/src/libasr/codegen/x86_assembler.cpp b/src/libasr/codegen/x86_assembler.cpp index d246bda27d..f8a3d7d8d0 100644 --- a/src/libasr/codegen/x86_assembler.cpp +++ b/src/libasr/codegen/x86_assembler.cpp @@ -94,6 +94,15 @@ void emit_exit(X86Assembler &a, const std::string &name, a.asm_int_imm8(0x80); // syscall } +void emit_exit2(X86Assembler &a, const std::string &name) +{ + a.add_label(name); + // void exit(); + a.asm_mov_r32_imm32(LFortran::X86Reg::eax, 1); // sys_exit + a.asm_pop_r32(X86Reg::ebx); // exit code on stack, move to register + a.asm_int_imm8(0x80); // syscall +} + void emit_data_string(X86Assembler &a, const std::string &label, const std::string &s) { diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index aba882c45a..2aadd02877 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -815,6 +815,7 @@ void emit_elf32_footer(X86Assembler &a); void emit_exit(X86Assembler &a, const std::string &name, uint32_t exit_code); +void emit_exit2(X86Assembler &a, const std::string &name); void emit_data_string(X86Assembler &a, const std::string &label, const std::string &s); void emit_print(X86Assembler &a, const std::string &msg_label, From 4fe4c69209ce57d544b246a3de939158886814b1 Mon Sep 17 00:00:00 2001 From: Ubaid Date: Thu, 10 Nov 2022 18:18:48 +0530 Subject: [PATCH 2/9] Commit white space removals --- src/libasr/codegen/x86_assembler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libasr/codegen/x86_assembler.cpp b/src/libasr/codegen/x86_assembler.cpp index f8a3d7d8d0..12373385c7 100644 --- a/src/libasr/codegen/x86_assembler.cpp +++ b/src/libasr/codegen/x86_assembler.cpp @@ -154,11 +154,11 @@ void emit_print_int(X86Assembler &a, const std::string &name) a.asm_je_label(".print"); // jmp .loop a.asm_jmp_label(".loop"); - + a.add_label(".print"); // cmp esi, 0 a.asm_cmp_r32_imm8(X86Reg::esi, 0); -// jz end +// jz end a.asm_je_label(".end"); // dec esi a.asm_dec_r32(X86Reg::esi); From bff606f428bf8ad58dfc7ac3f105b3273ebe669f Mon Sep 17 00:00:00 2001 From: Ubaid Date: Thu, 10 Nov 2022 18:19:37 +0530 Subject: [PATCH 3/9] WASM_X86: Support exit --- src/libasr/codegen/wasm_to_x86.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libasr/codegen/wasm_to_x86.cpp b/src/libasr/codegen/wasm_to_x86.cpp index cf968d5c43..36f06d6474 100644 --- a/src/libasr/codegen/wasm_to_x86.cpp +++ b/src/libasr/codegen/wasm_to_x86.cpp @@ -28,6 +28,8 @@ class X86Visitor : public WASMDecoder, wasm_bytes.from_pointer_n(code.data(), code.size()); } + void visit_Unreachable() {} + void visit_Return() {} void call_imported_function(uint32_t func_index) { @@ -238,7 +240,7 @@ class X86Visitor : public WASMDecoder, // Add runtime library functions emit_print_int(m_a, "print_i32"); - emit_exit(m_a, "exit", 0); + emit_exit2(m_a, "exit"); // declare compile-time strings for (uint32_t i = 0; i < data_segments.size(); i++) { From e7394105569f439acac0024ad1b0cb4ceb562968 Mon Sep 17 00:00:00 2001 From: Ubaid Date: Fri, 11 Nov 2022 15:36:32 +0530 Subject: [PATCH 4/9] WASM_X86: Implement visit_I32Eqz() --- src/libasr/codegen/wasm_to_x86.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libasr/codegen/wasm_to_x86.cpp b/src/libasr/codegen/wasm_to_x86.cpp index 36f06d6474..4f50a816f6 100644 --- a/src/libasr/codegen/wasm_to_x86.cpp +++ b/src/libasr/codegen/wasm_to_x86.cpp @@ -162,6 +162,11 @@ class X86Visitor : public WASMDecoder, } } + void visit_I32Eqz() { + m_a.asm_push_imm32(0U); + handle_I32Compare("Eq"); + } + void visit_I32Const(int32_t value) { m_a.asm_push_imm32(value); // if (value < 0) { From 3c677110e966806426449103c39feb7571c721ca Mon Sep 17 00:00:00 2001 From: Ubaid Date: Fri, 11 Nov 2022 15:45:51 +0530 Subject: [PATCH 5/9] TEST: WASM_X86: Enable supporting tests --- integration_tests/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 0636c3b25f..a441164b28 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -180,8 +180,8 @@ RUN(NAME bindc_02 LABELS llvm c) RUN(NAME bindc_04 LABELS llvm) RUN(NAME exit_01 LABELS cpython llvm c) RUN(NAME exit_02 FAIL LABELS cpython llvm c) -RUN(NAME exit_01b LABELS cpython llvm c wasm) -RUN(NAME exit_02b FAIL LABELS cpython llvm c wasm) +RUN(NAME exit_01b LABELS cpython llvm c wasm wasm_x86) +RUN(NAME exit_02b FAIL LABELS cpython llvm c wasm wasm_x86) RUN(NAME exit_02c FAIL LABELS cpython llvm c) # Test all four backends @@ -233,8 +233,8 @@ RUN(NAME test_dict_03 LABELS cpython llvm) RUN(NAME test_dict_04 LABELS cpython llvm) RUN(NAME test_dict_05 LABELS cpython llvm) RUN(NAME test_for_loop LABELS cpython llvm c) -RUN(NAME modules_01 LABELS cpython llvm wasm) -RUN(NAME modules_02 LABELS cpython llvm wasm) +RUN(NAME modules_01 LABELS cpython llvm wasm wasm_x86) +RUN(NAME modules_02 LABELS cpython llvm wasm wasm_x86) RUN(NAME test_import_01 LABELS cpython llvm) RUN(NAME test_import_02 LABELS cpython llvm) RUN(NAME test_math LABELS cpython llvm) From 9d3a5d7ef26a3b8186d80603aaa9dc6fc8c1d367 Mon Sep 17 00:00:00 2001 From: Ubaid Date: Fri, 11 Nov 2022 16:14:27 +0530 Subject: [PATCH 6/9] WASM_X86: Fix exit (jump to exit label instead of calling it) --- src/libasr/codegen/wasm_to_x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libasr/codegen/wasm_to_x86.cpp b/src/libasr/codegen/wasm_to_x86.cpp index 4f50a816f6..437e0b8030 100644 --- a/src/libasr/codegen/wasm_to_x86.cpp +++ b/src/libasr/codegen/wasm_to_x86.cpp @@ -72,7 +72,7 @@ class X86Visitor : public WASMDecoder, break; } case 6: { // set_exit_code - m_a.asm_call_label("exit"); + m_a.asm_jmp_label("exit"); break; } default: { From 068563a24a95311c321a99b10fbf5f95f2a76a31 Mon Sep 17 00:00:00 2001 From: Ubaid Date: Fri, 11 Nov 2022 16:18:46 +0530 Subject: [PATCH 7/9] WASM_X86: Use offset directly as label (without pushing it to unique_id) --- src/libasr/codegen/wasm_to_x86.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libasr/codegen/wasm_to_x86.cpp b/src/libasr/codegen/wasm_to_x86.cpp index 437e0b8030..2accfb124c 100644 --- a/src/libasr/codegen/wasm_to_x86.cpp +++ b/src/libasr/codegen/wasm_to_x86.cpp @@ -206,30 +206,30 @@ class X86Visitor : public WASMDecoder, } void handle_I32Compare(const std::string &compare_op) { - unique_id.push_back(std::to_string(offset)); + std::string label = std::to_string(offset); m_a.asm_pop_r32(X86Reg::ebx); m_a.asm_pop_r32(X86Reg::eax); m_a.asm_cmp_r32_r32(X86Reg::eax, X86Reg::ebx); if (compare_op == "Eq") { - m_a.asm_je_label(".compare_1" + unique_id.back()); + m_a.asm_je_label(".compare_1" + label); } else if (compare_op == "Gt") { - m_a.asm_jg_label(".compare_1" + unique_id.back()); + m_a.asm_jg_label(".compare_1" + label); } else if (compare_op == "GtE") { - m_a.asm_jge_label(".compare_1" + unique_id.back()); + m_a.asm_jge_label(".compare_1" + label); } else if (compare_op == "Lt") { - m_a.asm_jl_label(".compare_1" + unique_id.back()); + m_a.asm_jl_label(".compare_1" + label); } else if (compare_op == "LtE") { - m_a.asm_jle_label(".compare_1" + unique_id.back()); + m_a.asm_jle_label(".compare_1" + label); } else if (compare_op == "NotEq") { - m_a.asm_jne_label(".compare_1" + unique_id.back()); + m_a.asm_jne_label(".compare_1" + label); } else { throw CodeGenError("Comparison operator not implemented"); } m_a.asm_mov_r32_imm32(X86Reg::eax, 0); - m_a.asm_jmp_label(".compare.end_" + unique_id.back()); - m_a.add_label(".compare_1" + unique_id.back()); + m_a.asm_jmp_label(".compare.end_" + label); + m_a.add_label(".compare_1" + label); m_a.asm_mov_r32_imm32(X86Reg::eax, 1); - m_a.add_label(".compare.end_" + unique_id.back()); + m_a.add_label(".compare.end_" + label); m_a.asm_push_r32(X86Reg::eax); } From 15779646094f2c40110bfe06cd1dfa0041985e30 Mon Sep 17 00:00:00 2001 From: Ubaid Date: Fri, 11 Nov 2022 16:22:04 +0530 Subject: [PATCH 8/9] Refactor: WASM_X86: Directly push value onto stack --- src/libasr/codegen/wasm_to_x86.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libasr/codegen/wasm_to_x86.cpp b/src/libasr/codegen/wasm_to_x86.cpp index 2accfb124c..a170086551 100644 --- a/src/libasr/codegen/wasm_to_x86.cpp +++ b/src/libasr/codegen/wasm_to_x86.cpp @@ -225,12 +225,11 @@ class X86Visitor : public WASMDecoder, } else { throw CodeGenError("Comparison operator not implemented"); } - m_a.asm_mov_r32_imm32(X86Reg::eax, 0); + m_a.asm_push_imm8(0); m_a.asm_jmp_label(".compare.end_" + label); m_a.add_label(".compare_1" + label); - m_a.asm_mov_r32_imm32(X86Reg::eax, 1); + m_a.asm_push_imm8(1); m_a.add_label(".compare.end_" + label); - m_a.asm_push_r32(X86Reg::eax); } void visit_I32Eq() { handle_I32Compare("Eq"); } From ad6c486eb02ade6e0eb8fc1ff13a32e96fa8f4a5 Mon Sep 17 00:00:00 2001 From: Ubaid Date: Fri, 11 Nov 2022 16:40:27 +0530 Subject: [PATCH 9/9] WASM_X86: Add comments about emit_exit2() and X86Visitor stack working --- src/libasr/codegen/wasm_to_x86.cpp | 16 ++++++++++++++++ src/libasr/codegen/x86_assembler.h | 7 +++++++ 2 files changed, 23 insertions(+) diff --git a/src/libasr/codegen/wasm_to_x86.cpp b/src/libasr/codegen/wasm_to_x86.cpp index a170086551..16a31b28be 100644 --- a/src/libasr/codegen/wasm_to_x86.cpp +++ b/src/libasr/codegen/wasm_to_x86.cpp @@ -11,6 +11,22 @@ namespace LFortran { namespace wasm { +/* + +This X86Visitor uses stack to pass arguments and return values from functions. +Since in X86, instructions operate on registers (and not on stack), +for every instruction we pop elements from top of stack and store them into +registers. After operating on the registers, the result value is then +pushed back onto the stack. + +One of the reasons to use stack to pass function arguments is that, +it allows us to define and call functions with any number of parameters. +As registers are limited in number, if we use them to pass function arugments, +the number of arguments we could pass to a function would get limited by +the number of registers available with the CPU. + +*/ + class X86Visitor : public WASMDecoder, public WASM_INSTS_VISITOR::BaseWASMVisitor { public: diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index 2aadd02877..6947b1185d 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -815,7 +815,14 @@ void emit_elf32_footer(X86Assembler &a); void emit_exit(X86Assembler &a, const std::string &name, uint32_t exit_code); + +// this is similar to emit_exit() but takes the argument (i.e. exit code) +// from top of stack. To call this exit2, one needs to jump to it +// instead of call it. (Because calling pushes the instruction address and +// base pointer value (ebp) of previous function and thus makes the +// exit code parameter less reachable) void emit_exit2(X86Assembler &a, const std::string &name); + void emit_data_string(X86Assembler &a, const std::string &label, const std::string &s); void emit_print(X86Assembler &a, const std::string &msg_label,