-
Notifications
You must be signed in to change notification settings - Fork 171
WASM: Initial support for complex numbers #1527
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
Conversation
We were hoping to use Array approach to store a complex number. In the Array approach, we had to reset the memory at the end of the function. To maintain where a function started (from which memory location), we are needing to store the memory offset in a (new/extra) local variable. Also, we currently have support only for memory allocation at compile-time. With these constraints, supporting the array approach seems tricky. For the moment, to have something which just works I currently used two local variables to store a |
Some concerns:
|
src/libasr/codegen/asr_to_wasm.cpp
Outdated
} else if (t->type == ASR::ttypeType::Complex) { | ||
emit_call_fd_write(1, "(", 1, 0); | ||
this->visit_expr(*x.m_values[i]); | ||
wasm::emit_drop(m_code_section, m_al); // drop imag part | ||
if (a_kind == 4) { | ||
wasm::emit_f64_promote_f32(m_code_section, m_al); | ||
} | ||
wasm::emit_call(m_code_section, m_al, 3 /* print_f64 */); | ||
emit_call_fd_write(1, ",", 1, 0); | ||
this->visit_expr(*x.m_values[i]); | ||
if (a_kind == 4) { | ||
wasm::emit_f64_promote_f32(m_code_section, m_al); | ||
} | ||
wasm::emit_call(m_code_section, m_al, 3 /* print_f64 */); | ||
emit_call_fd_write(1, ")", 1, 0); | ||
wasm::emit_drop(m_code_section, m_al); // drop real part |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concern:
Line 2814 & Line 2826: When printing a complex number we print the real part and then the imaginary part. It currently happens that, when we fetch a complex number on stack top, the imaginary part of the complex is at the stack top followed by the real part. Thus, we are needing to drop the top stack so that we can print the appropriate real/imag part of the complex number.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This concern is now solved/fixed in WASM: handle_print(): Use globals and fix revisiting expr.
1239af6
to
4dd3bff
Compare
From #1527 (comment),
This is now solved/fixed in WASM: Refactor: Define and use m_self_func_name_idx_map. |
src/libasr/codegen/asr_to_wasm.cpp
Outdated
emit_complex_add_32(); | ||
emit_complex_add_64(); | ||
emit_complex_sub_32(); | ||
emit_complex_sub_64(); | ||
emit_complex_mul_32(); | ||
emit_complex_mul_64(); | ||
emit_complex_abs_32(); | ||
emit_complex_abs_64(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, these should be emitted into wasm
code only when the particular operations are being used in the source code.
Concern/Challenge: If we do not define theses functions initally and add them at the very end (that is after defining all the other functions), then we do not have any function index to refer to these functions when they are called during a call (while defining the other functions).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would keep a running index of all functions and just appending these at the end as needed; then once we are done, we convert the index to the function index at the start of the WASM binary file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I attempted to support it in WASM: Support emitting functions based on requirement, and I'd love to get your feedback on it. Specifically, I'm wondering if this is what you had in mind, and if there are any changes you would like me to make. I'm open to any suggestions you have and would love to discuss this further with you.
226c278
to
24b943a
Compare
This is ready. Please review and share feedback. |
Can we somehow convert, void emit_complex_add_32(int fn_idx = -1) {
using namespace wasm;
define_emit_func({f32, f32, f32, f32}, {f32, f32}, {}, "add_c32", [&](){
wasm::emit_get_local(m_code_section, m_al, 0);
wasm::emit_get_local(m_code_section, m_al, 2);
wasm::emit_f32_add(m_code_section, m_al);
wasm::emit_get_local(m_code_section, m_al, 1);
wasm::emit_get_local(m_code_section, m_al, 3);
wasm::emit_f32_add(m_code_section, m_al);
}, fn_idx);
} to (assuming type of void emit_complex_op_util(wasm::type& ftype, std::string op_name, callback_type callback, int fn_idx = -1) {
using namespace wasm;
define_emit_func({ftype, ftype, ftype, ftype}, {ftype, ftype}, {}, op_name, [&](){
wasm::emit_get_local(m_code_section, m_al, 0);
wasm::emit_get_local(m_code_section, m_al, 2);
callback(m_code_section, m_al);
wasm::emit_get_local(m_code_section, m_al, 1);
wasm::emit_get_local(m_code_section, m_al, 3);
callback(m_code_section, m_al);
}, fn_idx);
} and call it whereever needed. |
The @czgdp1807 how do we use the similar void emit_complex_mul_32(int fn_idx = -1) {
using namespace wasm;
define_emit_func({f32, f32, f32, f32}, {f32, f32}, {}, "mul_c32", [&](){
wasm::emit_get_local(m_code_section, m_al, 0);
wasm::emit_get_local(m_code_section, m_al, 2);
wasm::emit_f32_mul(m_code_section, m_al);
wasm::emit_get_local(m_code_section, m_al, 1);
wasm::emit_get_local(m_code_section, m_al, 3);
wasm::emit_f32_mul(m_code_section, m_al);
wasm::emit_f32_sub(m_code_section, m_al);
wasm::emit_get_local(m_code_section, m_al, 0);
wasm::emit_get_local(m_code_section, m_al, 3);
wasm::emit_f32_mul(m_code_section, m_al);
wasm::emit_get_local(m_code_section, m_al, 1);
wasm::emit_get_local(m_code_section, m_al, 2);
wasm::emit_f32_mul(m_code_section, m_al);
wasm::emit_f32_add(m_code_section, m_al);
}, fn_idx);
} |
I guess we also need to support division of complex numbers. So some similar refactoring can be done for |
@czgdp1807 Refactoring As a later change, I wonder if we can/should keep the functions |
If you need it urgently then no need to refactor anything because that can be done later. If you have time to merge this, then may be figure out the patterns and create utility functions. The boilerplate code is high but that's okay. Just add TODOs before merging. I am approving it in its current state. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve conflicts then it should be good to go. Add TODOs for refactoring whevever you think refactoring can be done to reduce the boilerplate code. Thanks. cc: @certik
Yes, these functions would later be implemented as |
m_self_funcs_map["mul_c32"] = &ASRToWASMVisitor::emit_complex_mul_32; | ||
m_self_funcs_map["mul_c64"] = &ASRToWASMVisitor::emit_complex_mul_64; | ||
m_self_funcs_map["abs_c32"] = &ASRToWASMVisitor::emit_complex_abs_32; | ||
m_self_funcs_map["abs_c64"] = &ASRToWASMVisitor::emit_complex_abs_64; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use enums here for performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also then just use std::vector<bool>
for all the enumerators, so it will be a very quick (constant) check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be done in a subsequent PR.
if (a_kind == 4) { | ||
if (m_self_func_name_idx_map.find("add_c32") == m_self_func_name_idx_map.end()) { | ||
m_self_func_name_idx_map["add_c32"] = no_of_types++; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This just becomes a quick check, like if (m_self_complex_fn_present[wasm_add_c32])
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is good to merge as is, after resolving conflicts / polishing history as needed.
In subsequent PRs we can refine.
WASM: Remove unused functions for ComplexIm
Also improve how global variables are declared
9e04fd3
to
573d806
Compare
This PR adds support for complex numbers and operations on them in the
wasm
backend.Fixes #1519.