Implement if-else in wasm_to_x86 backend - #1264
Conversation
| while (cur_byte != 0x0B) { | ||
| if (cur_byte == 0x05) { | ||
| cur_byte = wasm::read_b8(code, offset_); | ||
| if (cur_byte == 0x0B || cur_byte == 0x41) { |
There was a problem hiding this comment.
I have a doubt:
Does wasm always have an else block (even though else is empty) in the if statement?

@Shaikh-Ubaid
If so, how Assert is handled in asr_to_wasm?
There was a problem hiding this comment.
I asked this because, the else block is not empty in the visit_assert(), it has 0x41
There was a problem hiding this comment.
Does wasm always have an else block (even though else is empty) in the if statement?
Currently, if there is no else block, then in the wat generated, we would just have if <some instructions> end.
There was a problem hiding this comment.
I asked this because, the else block is not empty in the visit_assert(), it has 0x41
Do you mean visit_Assert() in ASR->WASM backend?
There was a problem hiding this comment.
Nah, After the wasm code is generated and captured in the wasm->x86
| while (cur_byte != 0x0B) { | ||
| if (cur_byte == 0x05) { | ||
| cur_byte = wasm::read_b8(code, offset_); | ||
| if (cur_byte == 0x0B || cur_byte == 0x41) { | ||
| return false; | ||
| } else { | ||
| return true; | ||
| } | ||
| } | ||
| cur_byte = wasm::read_b8(code, offset_); | ||
| } |
There was a problem hiding this comment.
But this logic, detects the else block, even for the following syntax!!
if True:
pass
There was a problem hiding this comment.
That is the reason, I check the next byte of the visit_else to be 0x0B (which checks the end of the if stmt).
There was a problem hiding this comment.
At present, if there is no else block, then visit_Else() should not be visited. I guess, we might be missing something.
d494fb3 to
7b8e83f
Compare
|
I looked into the If an |
|
I will rebase this on top of #1262 (so that we can print some value inside the |
|
This looks great! Thanks for updating. |
|
Let's implement visit_Assert() in this PR itself. def Main0():
assert 1 == 1
Main0()Output: $ lpython examples/expr2.py --backend wasm_x86 && ./a.out
AssertionErrordef Main0():
assert 0 == 1
Main0()$ lpython examples/expr2.py --backend wasm_x86 && ./a.out |
| void visit_Assert(const ASR::Assert_t &x) { | ||
| this->visit_expr(*x.m_test); | ||
| wasm::emit_i32_eqz(m_code_section, m_al); | ||
| wasm::emit_b8(m_code_section, m_al, 0x04); // emit if start | ||
| wasm::emit_b8(m_code_section, m_al, 0x40); // empty block type | ||
| wasm::emit_b8(m_code_section, m_al, 0x05); // starting of else | ||
| if (x.m_msg) { | ||
| std::string msg = | ||
| ASR::down_cast<ASR::StringConstant_t>(x.m_msg)->m_s; |
There was a problem hiding this comment.
The previous version was more correct, right? The previous version would say -> If Assert condition failed, raise an error (which is what assert does, I think).
There was a problem hiding this comment.
The main motive for these changes was that visit_I32Eqz() in the wasm_to_x86 is not working correctly.
Here, the changes imply:
If True:
// Do nothing
else:
print("AssertionError")
quit(1)which is similar to assert False
There was a problem hiding this comment.
The same approach as we do in the LLVM backend:
lpython/src/libasr/codegen/asr_to_llvm.cpp
Lines 4845 to 4862 in d4a6d53
| } | ||
| wasm::emit_i32_const(m_code_section, m_al, 1); // non-zero exit code | ||
| exit(); | ||
| wasm::emit_b8(m_code_section, m_al, 0x05); // starting of else | ||
| wasm::emit_expr_end(m_code_section, m_al); // emit if end | ||
| } | ||
| }; |
There was a problem hiding this comment.
The else portion was empty in the previous version.
There was a problem hiding this comment.
The right way to support Assert would instead be to implement the visit_I32Eqz in the WASM->X86 backend.
void visit_I32Eqz() {
m_a.asm_pop_r32(X86Reg::eax);
m_a.asm_mov_r32_imm32(X86Reg::ebx, 0U);
m_a.asm_cmp_r32_r32(X86Reg::eax, X86Reg::ebx);
m_a.asm_push_r32(X86Reg::eax);
}|
Thanks @Thirumalai-Shaktivel for working on this, very helpful. Thanks @Shaikh-Ubaid for the review. |
This seems not working in the wasm_x86 backend. |
|
What does I32Eqz do? isn't it a NOT operator? |
It checks if the stack top is equal to zero. Yes, it works similar to a not operator.
If it is similar to the
It should (hopefully) work. I tested it locally on my system before sharing here. If we are following the |
Were you able to get "AssertionError" for |
|
For the code: def Test_assert_01():
if True:
assert True
assert 1 != 1, "One is equal to one."
def Verify():
Test_assert_01()
Verify()I get: $ lpython examples/expr2.py --backend wasm_x86 && ./a.out
Call to imported function with index 4 not yet supported
Call to imported function with index 4 not yet supported |
|
Sorry my bad, |
Let's wait for the |
|
Yup! Now, I feel the same. |
6e47f8e to
4093db1
Compare
|
Thank you for your approval and guidance! |
| public: | ||
| X86Assembler &m_a; | ||
| uint32_t cur_func_idx; | ||
| std::vector<uint32_t> unique_id; |
There was a problem hiding this comment.
Later:
| std::vector<uint32_t> unique_id; | |
| uint32_t unique_id; |
| void visit_EmtpyBlockType() {} | ||
|
|
||
| void visit_If() { | ||
| unique_id.push_back(offset); |
There was a problem hiding this comment.
| unique_id.push_back(offset); | |
| unique_id++; | |
| uint32_t label = unique_id; |
| 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())); |
There was a problem hiding this comment.
For later (but probably quite soon): we should not be using strings for labels, but just unique integers. The unique integer can just be a counter in this visitor, just an integer, see above.
There was a problem hiding this comment.
(we might need to have a stack of unique ids...)
certik
left a comment
There was a problem hiding this comment.
Looks good to me, thanks!
Related #1222