Thanks to visit codestin.com
Credit goes to github.com

Skip to content

WASM_X64: Support local variables #1361

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 99 additions & 0 deletions src/libasr/codegen/wasm_to_x64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,80 @@ class X64Visitor : public WASMDecoder<X64Visitor>,

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) {
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) {
Expand All @@ -106,6 +180,31 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
m_a.asm_push_r64(X64Reg::rax);
}

void visit_I32Add() {
m_a.asm_pop_r64(X64Reg::rbx);
m_a.asm_pop_r64(X64Reg::rax);
m_a.asm_add_r64_r64(X64Reg::rax, X64Reg::rbx);
m_a.asm_push_r64(X64Reg::rax);
}
void visit_I32Sub() {
m_a.asm_pop_r64(X64Reg::rbx);
m_a.asm_pop_r64(X64Reg::rax);
m_a.asm_sub_r64_r64(X64Reg::rax, X64Reg::rbx);
m_a.asm_push_r64(X64Reg::rax);
}
void visit_I32Mul() {
m_a.asm_pop_r64(X64Reg::rbx);
m_a.asm_pop_r64(X64Reg::rax);
m_a.asm_mul_r64(X64Reg::rbx);
m_a.asm_push_r64(X64Reg::rax);
}
void visit_I32DivS() {
m_a.asm_pop_r64(X64Reg::rbx);
m_a.asm_pop_r64(X64Reg::rax);
m_a.asm_div_r64(X64Reg::rbx);
m_a.asm_push_r64(X64Reg::rax);
}

void gen_x64_bytes() {
{ // Initialize/Modify values of entities for code simplicity later

Expand Down
105 changes: 100 additions & 5 deletions src/libasr/codegen/x86_assembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "[";
Expand Down Expand Up @@ -473,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));
}
Expand All @@ -491,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));
}
Expand Down Expand Up @@ -664,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));
}
Expand All @@ -679,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);
Expand All @@ -693,6 +714,25 @@ 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);
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,
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) {
Expand All @@ -707,6 +747,25 @@ 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);
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);
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) {
Expand Down Expand Up @@ -736,6 +795,15 @@ class X86Assembler {
EMIT("sub " + r2s(r32) + ", " + i2s(imm8));
}

void asm_sub_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, 0x29);
modrm_sib_disp(m_code, m_al,
s32, &r32, nullptr, 1, 0, false);
EMIT("sub " + r2s(r64) + ", " + r2s(s64));
}

void asm_sub_r32_r32(X86Reg r32, X86Reg s32) {
m_code.push_back(m_al, 0x29);
modrm_sib_disp(m_code, m_al,
Expand Down Expand Up @@ -865,6 +933,15 @@ class X86Assembler {
EMIT("add " + m2s(base, index, scale, disp) + ", " + r2s(r32));
}

void asm_add_r64_r64(X64Reg s64, X64Reg r64) {
X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7);
m_code.push_back(m_al, rex(1, s64 >> 3, 0, r64 >> 3));
m_code.push_back(m_al, 0x01);
modrm_sib_disp(m_code, m_al,
r32, &s32, nullptr, 1, 0, false);
EMIT("add " + r2s(s64) + ", " + r2s(r64));
}

void asm_add_r32_r32(X86Reg s32, X86Reg r32) {
m_code.push_back(m_al, 0x01);
modrm_sib_disp(m_code, m_al,
Expand All @@ -888,13 +965,31 @@ class X86Assembler {
EMIT("add " + r2s(r32) + ", " + i2s(imm32));
}

void asm_mul_r64(X64Reg r64) {
X86Reg r32 = X86Reg(r64 & 7);
m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3));
m_code.push_back(m_al, 0xF7);
modrm_sib_disp(m_code, m_al,
X86Reg::esp, &r32, nullptr, 1, 0, false);
EMIT("mul " + r2s(r64));
}

void asm_mul_r32(X86Reg r32) {
m_code.push_back(m_al, 0xF7);
modrm_sib_disp(m_code, m_al,
X86Reg::esp, &r32, nullptr, 1, 0, false);
EMIT("mul " + r2s(r32));
}

void asm_div_r64(X64Reg r64) {
X86Reg r32 = X86Reg(r64 & 7);
m_code.push_back(m_al, rex(1, 0, 0, r64 >> 3));
m_code.push_back(m_al, 0xF7);
modrm_sib_disp(m_code, m_al,
X86Reg::esi, &r32, nullptr, 1, 0, false);
EMIT("div " + r2s(r64));
}

void asm_div_r32(X86Reg r32) {
m_code.push_back(m_al, 0xF7);
modrm_sib_disp(m_code, m_al,
Expand Down