Skip to content

Commit a0fc10f

Browse files
authored
Merge pull request #1338 from Shaikh-Ubaid/wasm_x64_func_calls
WASM_X64: Basic support for function calls
2 parents 00ed228 + 8b75a63 commit a0fc10f

File tree

3 files changed

+122
-8
lines changed

3 files changed

+122
-8
lines changed

src/libasr/codegen/wasm_to_x64.cpp

Lines changed: 95 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
3131
public WASM_INSTS_VISITOR::BaseWASMVisitor<X64Visitor> {
3232
public:
3333
X86Assembler &m_a;
34+
uint32_t cur_func_idx;
3435

3536
X64Visitor(X86Assembler &m_a, Allocator &al,
3637
diag::Diagnostics &diagonostics, Vec<uint8_t> &code)
@@ -40,19 +41,105 @@ class X64Visitor : public WASMDecoder<X64Visitor>,
4041
wasm_bytes.from_pointer_n(code.data(), code.size());
4142
}
4243

44+
void visit_Return() {}
45+
46+
void call_imported_function(uint32_t func_idx) {
47+
switch (func_idx) {
48+
case 0: { // print_i32
49+
std::cerr << "Call to print_i32() will be printed as exit code\n";
50+
51+
// Currently, for print we are setting the value to be printed
52+
// as the exit code. Later we can access/view this value from console
53+
// using: echo $?
54+
m_a.asm_pop_r64(X64Reg::rdi); // get exit code from stack top
55+
m_a.asm_mov_r64_imm64(X64Reg::rax, 60); // sys_exit
56+
m_a.asm_syscall(); // syscall
57+
break;
58+
}
59+
case 1: { // print_i64
60+
std::cerr << "Call to print_i64() is not yet supported\n";
61+
break;
62+
}
63+
case 2: { // print_f32
64+
std::cerr << "Call to print_f32() is not yet supported\n";
65+
break;
66+
}
67+
case 3: { // print_f64
68+
std::cerr << "Call to print_f64() is not yet supported\n";
69+
break;
70+
}
71+
case 4: { // print_str
72+
std::cerr << "Call to print_str() is not yet supported\n";
73+
break;
74+
}
75+
case 5: { // flush_buf
76+
std::cerr << "Call to flush_buf() is not yet supported\n";
77+
break;
78+
}
79+
case 6: { // set_exit_code
80+
m_a.asm_pop_r64(X64Reg::rdi); // get exit code from stack top
81+
m_a.asm_mov_r64_imm64(X64Reg::rax, 60); // sys_exit
82+
m_a.asm_syscall(); // syscall
83+
break;
84+
}
85+
default: {
86+
std::cerr << "Unsupported func_idx";
87+
}
88+
}
89+
}
90+
91+
void visit_Call(uint32_t func_idx) {
92+
if (func_idx <= 6U) {
93+
call_imported_function(func_idx);
94+
return;
95+
}
96+
97+
func_idx -= 7u; // adjust function index as per imports
98+
m_a.asm_call_label(exports[func_idx].name);
99+
}
100+
101+
void visit_I32Const(int32_t value) {
102+
// direct addition of imm64 to stack is not available with us yet
103+
// so temporarily using a combination of instructions
104+
// TODO: Update this once we have support for push_imm64()
105+
m_a.asm_mov_r64_imm64(X64Reg::rax, value);
106+
m_a.asm_push_r64(X64Reg::rax);
107+
}
108+
43109
void gen_x64_bytes() {
44-
// update the initial value of asm text as per X64 text format
45-
m_a.update_asm("BITS 64\n\n");
110+
{ // Initialize/Modify values of entities for code simplicity later
111+
112+
m_a.update_asm("BITS 64\n\n"); // Update initial value of asm text as per X64 text format
113+
exports.back().name = "_start"; // Update _lcompilers_main() to _start
114+
}
46115

47116
emit_elf64_header(m_a);
48117

49-
{
50-
m_a.add_label("_start");
118+
for (uint32_t idx = 0; idx < type_indices.size(); idx++) {
119+
m_a.add_label(exports[idx].name);
120+
{
121+
// Initialize the stack
122+
m_a.asm_push_r64(X64Reg::rbp);
123+
m_a.asm_mov_r64_r64(X64Reg::rbp, X64Reg::rsp);
124+
125+
// Initialize local variables to zero and thus allocate space
126+
m_a.asm_mov_r64_imm64(X64Reg::rax, 0u);
127+
for (auto &local_var_info:codes[idx].locals) {
128+
for (uint32_t cnt = 0u; cnt < local_var_info.count; cnt++) {
129+
m_a.asm_push_r64(X64Reg::rax);
130+
}
131+
}
132+
133+
offset = codes[idx].insts_start_index;
134+
cur_func_idx = idx;
135+
decode_instructions();
136+
137+
// Restore stack
138+
m_a.asm_mov_r64_r64(X64Reg::rsp, X64Reg::rbp);
139+
m_a.asm_pop_r64(X64Reg::rbp);
140+
m_a.asm_ret();
141+
}
51142

52-
// exit with a fixed non-zero exit code
53-
m_a.asm_mov_r64_imm64(LFortran::X64Reg::rax, 60); // sys_exit
54-
m_a.asm_mov_r64_imm64(LFortran::X64Reg::rdi, 24 /* exit_code */); // exit code
55-
m_a.asm_syscall(); // syscall
56143
}
57144

58145
emit_elf64_footer(m_a);

src/libasr/codegen/x86_assembler.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,13 @@ class X86Assembler {
471471
// Saves the generated machine code into a binary file
472472
void save_binary(const std::string &filename);
473473

474+
void asm_pop_r64(X64Reg r64) {
475+
X86Reg r32 = X86Reg(r64 & 7);
476+
m_code.push_back(m_al, rex(1, r64 >> 3, 0, 0));
477+
m_code.push_back(m_al, 0x58 + r32);
478+
EMIT("pop " + r2s(r64));
479+
}
480+
474481
void asm_pop_r32(X86Reg r32) {
475482
m_code.push_back(m_al, 0x58 + r32);
476483
EMIT("pop " + r2s(r32));
@@ -482,6 +489,13 @@ class X86Assembler {
482489
EMIT("popl " + r2s(r16));
483490
}
484491

492+
void asm_push_r64(X64Reg r64) {
493+
X86Reg r32 = X86Reg(r64 & 7);
494+
m_code.push_back(m_al, rex(1, r64 >> 3, 0, 0));
495+
m_code.push_back(m_al, 0x50 + r32);
496+
EMIT("push " + r2s(r64));
497+
}
498+
485499
void asm_push_r32(X86Reg r32) {
486500
m_code.push_back(m_al, 0x50 + r32);
487501
EMIT("push " + r2s(r32));
@@ -663,6 +677,15 @@ class X86Assembler {
663677
EMIT("mov " + r2s(r32) + ", " + label);
664678
}
665679

680+
void asm_mov_r64_r64(X64Reg r64, X64Reg s64) {
681+
X86Reg r32 = X86Reg(r64 & 7), s32 = X86Reg(s64 & 7);
682+
m_code.push_back(m_al, rex(1, r64 >> 3, 0, s64 >> 3));
683+
m_code.push_back(m_al, 0x89);
684+
modrm_sib_disp(m_code, m_al,
685+
s32, &r32, nullptr, 1, 0, false);
686+
EMIT("mov " + r2s(r64) + ", " + r2s(s64));
687+
}
688+
666689
void asm_mov_r32_r32(X86Reg r32, X86Reg s32) {
667690
m_code.push_back(m_al, 0x89);
668691
modrm_sib_disp(m_code, m_al,

src/libasr/containers.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ struct Vec {
9595
return p;
9696
}
9797

98+
T& back() const {
99+
return p[n - 1];
100+
}
101+
98102
const T& operator[](size_t pos) const {
99103
return p[pos];
100104
}

0 commit comments

Comments
 (0)