Skip to content
Merged
42 changes: 42 additions & 0 deletions integration_tests/if_02.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from ltypes import bool, i32

def test_if_01():
x: bool = True
y: i32 = 10
z: i32 = 0

if x:
x = False
if x:
z += 1
else:
z += 1

if y > 5:
z += 1
if y < 12:
z += 1
if y == 10:
z += 1
if y != 10:
z += 1
else:
z += 1
if y <= 10:
z += 1

y = 5
if y <= 10:
z += 1
if y >= 5:
z += 1
if y >= 2:
z += 1

# TODO: replace this an assert statement
print(z)

def verify():
test_if_01()

verify()
51 changes: 43 additions & 8 deletions src/libasr/codegen/wasm_to_x86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class X86Visitor : public WASMDecoder<X86Visitor>,
public:
X86Assembler &m_a;
uint32_t cur_func_idx;
std::vector<uint32_t> unique_id;
std::vector<std::string> unique_id;

X86Visitor(X86Assembler &m_a, Allocator &al,
diag::Diagnostics &diagonostics, Vec<uint8_t> &code)
Expand Down Expand Up @@ -72,22 +72,22 @@ class X86Visitor : public WASMDecoder<X86Visitor>,
void visit_EmtpyBlockType() {}

void visit_If() {
unique_id.push_back(offset);
unique_id.push_back(std::to_string(offset));
m_a.asm_pop_r32(X86Reg::eax);
m_a.asm_cmp_r32_imm8(LFortran::X86Reg::eax, 1);
m_a.asm_je_label(".then_" + std::to_string(unique_id.back()));
m_a.asm_jmp_label(".else_" + std::to_string(unique_id.back()));
m_a.add_label(".then_" + std::to_string(unique_id.back()));
m_a.asm_je_label(".then_" + unique_id.back());
m_a.asm_jmp_label(".else_" + unique_id.back());
m_a.add_label(".then_" + unique_id.back());
{
decode_instructions();
}
m_a.add_label(".endif_" + std::to_string(unique_id.back()));
m_a.add_label(".endif_" + unique_id.back());
unique_id.pop_back();
}

void visit_Else() {
m_a.asm_jmp_label(".endif_" + std::to_string(unique_id.back()));
m_a.add_label(".else_" + std::to_string(unique_id.back()));
m_a.asm_jmp_label(".endif_" + unique_id.back());
m_a.add_label(".else_" + unique_id.back());
}

void visit_LocalGet(uint32_t localidx) {
Expand Down Expand Up @@ -154,6 +154,41 @@ class X86Visitor : public WASMDecoder<X86Visitor>,
m_a.asm_push_r32(X86Reg::eax);
}

void handle_I32Compare(const std::string &compare_op) {
unique_id.push_back(std::to_string(offset));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Thirumalai-Shaktivel, please, could you possibly share why we need to store the offset in unique_id? Are we using it later outside the handleI32Compare() function?

If it is not used later, we need/should not store it, I think.

Copy link
Copy Markdown
Collaborator Author

@Thirumalai-Shaktivel Thirumalai-Shaktivel Nov 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, I forgot to pop the uniqu_id!
Now, If I think of it, we have options:
1.

diff --git a/src/libasr/codegen/wasm_to_x86.cpp b/src/libasr/codegen/wasm_to_x86.cpp
index cf968d5c4..12ea3b156 100644
--- a/src/libasr/codegen/wasm_to_x86.cpp
+++ b/src/libasr/codegen/wasm_to_x86.cpp
@@ -199,30 +199,29 @@ class X86Visitor : public WASMDecoder<X86Visitor>,
     }
 
     void handle_I32Compare(const std::string &compare_op) {
-        unique_id.push_back(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" + std::to_string(offset));
...
diff --git a/src/libasr/codegen/wasm_to_x86.cpp b/src/libasr/codegen/wasm_to_x86.cpp
index cf968d5c4..2e23d7230 100644
--- a/src/libasr/codegen/wasm_to_x86.cpp
+++ b/src/libasr/codegen/wasm_to_x86.cpp
@@ -224,6 +224,7 @@ class X86Visitor : public WASMDecoder<X86Visitor>,
         m_a.asm_mov_r32_imm32(X86Reg::eax, 1);
         m_a.add_label(".compare.end_" + unique_id.back());
         m_a.asm_push_r32(X86Reg::eax);
+        unique_id.pop_back();
     }
 
     void visit_I32Eq() { handle_I32Compare("Eq"); }

which do you prefer the most?

Copy link
Copy Markdown
Collaborator Author

@Thirumalai-Shaktivel Thirumalai-Shaktivel Nov 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you said, yup, it is not used later on. So, Instead of storing the unique_id, we can just use std::to_string(offset). I think option 1 would be good to go.

Copy link
Copy Markdown
Collaborator Author

@Thirumalai-Shaktivel Thirumalai-Shaktivel Nov 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the reason why I used the unique_id is that: I thought the offset value would be incremented inside the handle_compareI32() function. I checked and it seems the offset is not modified. So, we can use std::to_string(offset).
I will make the able change with the loop stmt. Thanks for noticing it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, Instead of storing the unique_id, we can just use std::to_string(offset)

Yup, we can just use offset as a label.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I incorporated this change into this commit WASM_X86: Use offset directly as label

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());
} else if (compare_op == "Gt") {
m_a.asm_jg_label(".compare_1" + unique_id.back());
} else if (compare_op == "GtE") {
m_a.asm_jge_label(".compare_1" + unique_id.back());
} else if (compare_op == "Lt") {
m_a.asm_jl_label(".compare_1" + unique_id.back());
} else if (compare_op == "LtE") {
m_a.asm_jle_label(".compare_1" + unique_id.back());
} else if (compare_op == "NotEq") {
m_a.asm_jne_label(".compare_1" + unique_id.back());
} 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_mov_r32_imm32(X86Reg::eax, 1);
m_a.add_label(".compare.end_" + unique_id.back());
m_a.asm_push_r32(X86Reg::eax);
Comment on lines +177 to +182
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the last discussion, you said we can push value directly into the stack.
Here why not we just push the result value into the stack instead of moving it into the eax?
Also, I have another doubt:
How do we access the pushed value in the stack?

Copy link
Copy Markdown
Collaborator Author

@Thirumalai-Shaktivel Thirumalai-Shaktivel Nov 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the other instructions that follow use it. For example, After the I32Const, there could be an instruction I32Neg (hypothetical example) which would use the value on top of stack (it pops it to use it), negate it and then push back onto stack.
#1222 (comment)

How would we use the value on top of stack?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushing the value directly into the stack works:

m_a.asm_push_imm8(0);
m_a.asm_jmp_label(".compare.end_" + std::to_string(offset));
m_a.add_label(".compare_1" + std::to_string(offset));
m_a.asm_push_imm8(1);
m_a.add_label(".compare.end_" + std::to_string(offset));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do we access the pushed value in the stack?

It can be accessed during run-time only.

How would we use the value on top of stack?

Other instructions can use it during run-time time. They perform some operation(s) on it and store the result back onto stack.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushing the value directly into the stack works:

If it works, we can use this way. (I think it could be better as it could use (slightly) lesser instructions)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this change/improvement into this commit
Refactor: WASM_X86: Directly push value onto stack.

}

void visit_I32Eq() { handle_I32Compare("Eq"); }
void visit_I32GtS() { handle_I32Compare("Gt"); }
void visit_I32GeS() { handle_I32Compare("GtE"); }
void visit_I32LtS() { handle_I32Compare("Lt"); }
void visit_I32LeS() { handle_I32Compare("LtE"); }
void visit_I32Ne() { handle_I32Compare("NotEq"); }

void gen_x86_bytes() {
emit_elf32_header(m_a);

Expand Down