From 135831ee7c0930adbda1ab3554c2b3cedcdcb8e6 Mon Sep 17 00:00:00 2001 From: Ubaid Date: Thu, 15 Dec 2022 07:02:14 +0530 Subject: [PATCH 1/5] WASM_X64: Implement mov reg to mem and mem to reg --- src/libasr/codegen/x86_assembler.h | 40 ++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index 904bd2318f..accd871bdd 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -115,6 +115,26 @@ static std::string r2s(X86Reg r32) { } } +static std::string m2s(X64Reg *base, X64Reg *index, uint8_t scale, int64_t disp) { + std::string r; + r = "["; + if (base) r += r2s(*base); + if (index) { + if (base) r += "+"; + if (scale == 1) { + r += r2s(*index); + } else { + r += std::to_string(scale) + "*" + r2s(*index); + } + } + if (disp) { + if ((base || index) && (disp > 0)) r += "+"; + r += std::to_string(disp); + } + r += "]"; + return r; +} + static std::string m2s(X86Reg *base, X86Reg *index, uint8_t scale, int32_t disp) { std::string r; r = "["; @@ -693,6 +713,16 @@ class X86Assembler { EMIT("mov " + r2s(r32) + ", " + r2s(s32)); } + void asm_mov_r64_m64(X64Reg r64, X64Reg *base, X64Reg *index, + uint8_t scale, int64_t disp) { + X86Reg r32 = X86Reg(r64 & 7), base32 = X86Reg(base & 7), index32 = X86Reg(index & 7); + m_code.push_back(m_al, rex(1, r64 >> 3, index32 >> 3, base32 >> 3)); + m_code.push_back(m_al, 0x8b); + modrm_sib_disp(m_code, m_al, + r32, base32, index32, scale, (int32_t)disp, true); + EMIT("mov " + r2s(r64) + ", " + m2s(base, index, scale, disp)); + } + void asm_mov_r32_m32(X86Reg r32, X86Reg *base, X86Reg *index, uint8_t scale, int32_t disp) { if (r32 == X86Reg::eax && !base && !index) { @@ -707,6 +737,16 @@ class X86Assembler { EMIT("mov " + r2s(r32) + ", " + m2s(base, index, scale, disp)); } + void asm_mov_m64_r64(X64Reg *base, X64Reg *index, + uint8_t scale, int64_t disp, X64Reg r64) { + X86Reg r32 = X86Reg(r64 & 7), base32 = X86Reg(base & 7), index32 = X86Reg(index & 7); + m_code.push_back(m_al, rex(1, r64 >> 3, index32 >> 3, base32 >> 3)); + m_code.push_back(m_al, 0x89); + modrm_sib_disp(m_code, m_al, + r32, base32, index32, scale, (int32_t)disp, true); + EMIT("mov " + m2s(base, index, scale, disp) + ", " + r2s(r64)); + } + void asm_mov_m32_r32(X86Reg *base, X86Reg *index, uint8_t scale, int32_t disp, X86Reg r32) { if (r32 == X86Reg::eax && !base && !index) { From 407a4b952b9475cf192a859ad9fe17a3c0d5a696 Mon Sep 17 00:00:00 2001 From: Ubaid Date: Thu, 15 Dec 2022 07:12:15 +0530 Subject: [PATCH 2/5] X86Assembler: Fix rex byte for X64 instructions --- src/libasr/codegen/x86_assembler.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index accd871bdd..1cbc5a3378 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -493,7 +493,7 @@ class X86Assembler { void asm_pop_r64(X64Reg r64) { X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, 0)); + m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); m_code.push_back(m_al, 0x58 + r32); EMIT("pop " + r2s(r64)); } @@ -511,7 +511,7 @@ class X86Assembler { void asm_push_r64(X64Reg r64) { X86Reg r32 = X86Reg(r64 & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, 0)); + m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); m_code.push_back(m_al, 0x50 + r32); EMIT("push " + r2s(r64)); } @@ -684,8 +684,9 @@ class X86Assembler { } void asm_mov_r64_imm64(X64Reg r64, uint64_t imm64) { - m_code.push_back(m_al, rex(1, 0, 0, 0)); - m_code.push_back(m_al, 0xb8 + r64); + X86Reg r32 = X86Reg(r64 & 7); + m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3)); + m_code.push_back(m_al, 0xb8 + r32); push_back_uint64(m_code, m_al, imm64); EMIT("mov " + r2s(r64) + ", " + i2s(imm64)); } @@ -699,7 +700,7 @@ class X86Assembler { void asm_mov_r64_r64(X64Reg r64, X64Reg s64) { X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3)); + m_code.push_back(m_al, rex(1, s64 >> 3, 0, r64 >> 3)); m_code.push_back(m_al, 0x89); modrm_sib_disp(m_code, m_al, s32, &r32, nullptr, 1, 0, false); From 682bc796dcacb1af803e0377de59973b5bc27ca8 Mon Sep 17 00:00:00 2001 From: Ubaid Date: Thu, 15 Dec 2022 07:25:37 +0530 Subject: [PATCH 3/5] WASM_X64: Support local get and set --- src/libasr/codegen/wasm_to_x64.cpp | 56 ++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/libasr/codegen/wasm_to_x64.cpp b/src/libasr/codegen/wasm_to_x64.cpp index 808f5ebcf3..40addad0cb 100644 --- a/src/libasr/codegen/wasm_to_x64.cpp +++ b/src/libasr/codegen/wasm_to_x64.cpp @@ -98,6 +98,62 @@ class X64Visitor : public WASMDecoder, m_a.asm_call_label(exports[func_idx].name); } + void visit_LocalGet(uint32_t localidx) { + X64Reg base = X64Reg::rbp; + 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]]; + if (var_type == "i32") { + m_a.asm_mov_r64_m64(X64Reg::rax, &base, nullptr, 1, 8 * (2 + localidx)); + m_a.asm_push_r64(X64Reg::rax); + } else if (var_type == "f64") { + std::cerr << "Floats are not yet supported" << std::endl; + } else { + throw CodeGenError("WASM_X64: Var type not supported"); + } + } else { + localidx -= no_of_params; + std::string var_type = var_type_to_string[codes[cur_func_idx].locals[localidx].type]; + if (var_type == "i32") { + m_a.asm_mov_r64_m64(X64Reg::rax, &base, nullptr, 1, -8 * (1 + localidx)); + m_a.asm_push_r64(X64Reg::rax); + } else if (var_type == "f64") { + std::cerr << "Floats are not yet supported" << std::endl; + } else { + throw CodeGenError("WASM_X64: Var type not supported"); + } + } + } + + void visit_LocalSet(uint32_t localidx) { + X64Reg base = X64Reg::rbp; + 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]]; + if (var_type == "i32") { + m_a.asm_pop_r64(X64Reg::rax); + m_a.asm_mov_m64_r64(&base, nullptr, 1, 8 * (2 + localidx), X64Reg::rax); + } else if (var_type == "f64") { + std::cerr << "Floats are not yet supported" << std::endl; + } else { + throw CodeGenError("WASM_X64: Var type not supported"); + } + } else { + localidx -= no_of_params; + std::string var_type = var_type_to_string[codes[cur_func_idx].locals[localidx].type]; + if (var_type == "i32") { + m_a.asm_pop_r64(X64Reg::rax); + m_a.asm_mov_m64_r64(&base, nullptr, 1, -8 * (1 + localidx), X64Reg::rax); + } else if (var_type == "f64") { + std::cerr << "Floats are not yet supported" << std::endl; + } else { + throw CodeGenError("WASM_X64: Var type not supported"); + } + } + } + void visit_I32Const(int32_t value) { // direct addition of imm64 to stack is not available with us yet // so temporarily using a combination of instructions From 924dc53c7a6153d3ac26925dc256786b10bc49f6 Mon Sep 17 00:00:00 2001 From: Ubaid Date: Thu, 15 Dec 2022 07:59:01 +0530 Subject: [PATCH 4/5] WASM_X64: Support return values from func calls --- src/libasr/codegen/wasm_to_x64.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libasr/codegen/wasm_to_x64.cpp b/src/libasr/codegen/wasm_to_x64.cpp index 40addad0cb..f51fb57763 100644 --- a/src/libasr/codegen/wasm_to_x64.cpp +++ b/src/libasr/codegen/wasm_to_x64.cpp @@ -96,6 +96,24 @@ class X64Visitor : public WASMDecoder, func_idx -= 7u; // adjust function index as per imports m_a.asm_call_label(exports[func_idx].name); + + // Pop the passed function arguments + wasm::FuncType func_type = func_types[type_indices[func_idx]]; + for (uint32_t i = 0; i < func_type.param_types.size(); i++) { + m_a.asm_pop_r64(X64Reg::rax); + } + + // Adjust the return values of the called function + X64Reg base = X64Reg::rsp; + for (uint32_t i = 0; i < func_type.result_types.size(); i++) { + // take value into eax + m_a.asm_mov_r64_m64(X64Reg::rax, &base, nullptr, 1, + -8 * (func_type.param_types.size() + 2 + + codes[func_idx].locals.size() + 1)); + + // push eax value onto stack + m_a.asm_push_r64(X64Reg::rax); + } } void visit_LocalGet(uint32_t localidx) { From 356b3cad859772f4d2ed0c5c01b5a3e7d0b7875c Mon Sep 17 00:00:00 2001 From: Ubaid Date: Thu, 15 Dec 2022 08:02:20 +0530 Subject: [PATCH 5/5] WASM_X64: Fix nullptr handling in base and index registers --- src/libasr/codegen/x86_assembler.h | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index 1cbc5a3378..5905c5b04a 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -716,10 +716,19 @@ class X86Assembler { void asm_mov_r64_m64(X64Reg r64, X64Reg *base, X64Reg *index, uint8_t scale, int64_t disp) { - X86Reg r32 = X86Reg(r64 & 7), base32 = X86Reg(base & 7), index32 = X86Reg(index & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, index32 >> 3, base32 >> 3)); + X86Reg r32 = X86Reg(r64 & 7); + X86Reg* base32 = nullptr, *index32 = nullptr; + if (base) { + base32 = new X86Reg; + *base32 = X86Reg(*base & 7); + } + if (index) { + index32 = new X86Reg; + *index32 = X86Reg(*index & 7); + } + m_code.push_back(m_al, rex(1, r64 >> 3, (index32 ? (*index32 >> 3) : 0), (base32 ? (*base32 >> 3) : 0))); m_code.push_back(m_al, 0x8b); - modrm_sib_disp(m_code, m_al, + modrm_sib_disp(m_code, m_al, r32, base32, index32, scale, (int32_t)disp, true); EMIT("mov " + r2s(r64) + ", " + m2s(base, index, scale, disp)); } @@ -740,8 +749,17 @@ class X86Assembler { void asm_mov_m64_r64(X64Reg *base, X64Reg *index, uint8_t scale, int64_t disp, X64Reg r64) { - X86Reg r32 = X86Reg(r64 & 7), base32 = X86Reg(base & 7), index32 = X86Reg(index & 7); - m_code.push_back(m_al, rex(1, r64 >> 3, index32 >> 3, base32 >> 3)); + X86Reg r32 = X86Reg(r64 & 7); + X86Reg* base32 = nullptr, *index32 = nullptr; + if (base) { + base32 = new X86Reg; + *base32 = X86Reg(*base & 7); + } + if (index) { + index32 = new X86Reg; + *index32 = X86Reg(*index & 7); + } + m_code.push_back(m_al, rex(1, r64 >> 3, (index32 ? (*index32 >> 3) : 0), (base32 ? (*base32 >> 3) : 0))); m_code.push_back(m_al, 0x89); modrm_sib_disp(m_code, m_al, r32, base32, index32, scale, (int32_t)disp, true);