Skip to content

Commit aca3a87

Browse files
committed
WASM: Support string comparison
1 parent c3314f7 commit aca3a87

File tree

1 file changed

+133
-3
lines changed

1 file changed

+133
-3
lines changed

src/libasr/codegen/asr_to_wasm.cpp

Lines changed: 133 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ enum RT_FUNCS {
7777
abs_c64 = 10,
7878
equal_c32 = 11,
7979
equal_c64 = 12,
80-
NO_OF_RT_FUNCS = 13,
80+
string_cmp = 13,
81+
NO_OF_RT_FUNCS = 14,
8182
};
8283

8384
enum GLOBAL_VAR {
@@ -552,6 +553,93 @@ class ASRToWASMVisitor : public ASR::BaseVisitor<ASRToWASMVisitor> {
552553
});
553554
}
554555

556+
void emit_string_cmp() {
557+
using namespace wasm;
558+
m_wa.define_func({i32, i32}, {i32}, {i32, i32, i32, i32, i32, i32}, "string_cmp", [&](){
559+
/*
560+
local 0 (param 0): string 1 (s1)
561+
local 1 (param 1): string 2 (s2)
562+
local 2: len(s1)
563+
local 3: len(s2)
564+
local 4: min(len(s1), len(s2))
565+
local 5: loop variable
566+
local 6: temp variable to store s1[i] - s2[i]
567+
local 7: return variable
568+
*/
569+
570+
m_wa.emit_local_get(0);
571+
m_wa.emit_i32_load(mem_align::b8, 4);
572+
m_wa.emit_local_set(2);
573+
574+
m_wa.emit_local_get(1);
575+
m_wa.emit_i32_load(mem_align::b8, 4);
576+
m_wa.emit_local_set(3);
577+
578+
m_wa.emit_if_else([&](){
579+
m_wa.emit_local_get(2);
580+
m_wa.emit_local_get(3);
581+
m_wa.emit_i32_le_s();
582+
}, [&](){
583+
m_wa.emit_local_get(2);
584+
m_wa.emit_local_set(4);
585+
}, [&](){
586+
m_wa.emit_local_get(3);
587+
m_wa.emit_local_set(4);
588+
});
589+
590+
m_wa.emit_i32_const(0);
591+
m_wa.emit_local_set(5);
592+
593+
m_wa.emit_loop([&](){
594+
m_wa.emit_local_get(5);
595+
m_wa.emit_local_get(4);
596+
m_wa.emit_i32_lt_s();
597+
}, [&](){
598+
m_wa.emit_local_get(0);
599+
m_wa.emit_local_get(5);
600+
m_wa.emit_i32_add();
601+
m_wa.emit_i32_load8_u(mem_align::b8, 8);
602+
603+
m_wa.emit_local_get(1);
604+
m_wa.emit_local_get(5);
605+
m_wa.emit_i32_add();
606+
m_wa.emit_i32_load8_u(mem_align::b8, 8);
607+
608+
m_wa.emit_i32_sub();
609+
m_wa.emit_local_set(6);
610+
611+
m_wa.emit_local_get(6);
612+
m_wa.emit_i32_const(0);
613+
m_wa.emit_i32_ne();
614+
615+
// branch to end of if, if char diff not equal to 0
616+
m_wa.emit_br_if(m_wa.nest_lvl - m_wa.cur_loop_nest_lvl - 2U);
617+
618+
m_wa.emit_local_get(5);
619+
m_wa.emit_i32_const(1);
620+
m_wa.emit_i32_add();
621+
m_wa.emit_local_set(5);
622+
});
623+
624+
m_wa.emit_if_else([&](){
625+
m_wa.emit_local_get(5);
626+
m_wa.emit_local_get(4);
627+
m_wa.emit_i32_lt_s();
628+
}, [&](){
629+
m_wa.emit_local_get(6);
630+
m_wa.emit_local_set(7);
631+
}, [&](){
632+
m_wa.emit_local_get(2);
633+
m_wa.emit_local_get(3);
634+
m_wa.emit_i32_sub();
635+
m_wa.emit_local_set(7);
636+
});
637+
638+
m_wa.emit_local_get(7);
639+
m_wa.emit_return();
640+
});
641+
}
642+
555643
void declare_global_var(ASR::Variable_t* v) {
556644
if (v->m_type->type == ASR::ttypeType::TypeParameter) {
557645
// Ignore type variables
@@ -688,6 +776,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor<ASRToWASMVisitor> {
688776
m_rt_funcs_map[abs_c64] = &ASRToWASMVisitor::emit_complex_abs_64;
689777
m_rt_funcs_map[equal_c32] = &ASRToWASMVisitor::emit_complex_equal_32;
690778
m_rt_funcs_map[equal_c64] = &ASRToWASMVisitor::emit_complex_equal_64;
779+
m_rt_funcs_map[string_cmp] = &ASRToWASMVisitor::emit_string_cmp;
691780

692781
{
693782
// Pre-declare all functions first, then generate code
@@ -1915,6 +2004,47 @@ class ASRToWASMVisitor : public ASR::BaseVisitor<ASRToWASMVisitor> {
19152004
}
19162005
}
19172006

2007+
void handle_string_compare(const ASR::StringCompare_t &x) {
2008+
if (x.m_value) {
2009+
visit_expr(*x.m_value);
2010+
return;
2011+
}
2012+
INCLUDE_RUNTIME_FUNC(string_cmp);
2013+
this->visit_expr(*x.m_left);
2014+
this->visit_expr(*x.m_right);
2015+
m_wa.emit_call(m_rt_func_used_idx[string_cmp]);
2016+
m_wa.emit_i32_const(0);
2017+
switch (x.m_op) {
2018+
case (ASR::cmpopType::Eq): {
2019+
m_wa.emit_i32_eq();
2020+
break;
2021+
}
2022+
case (ASR::cmpopType::Gt): {
2023+
m_wa.emit_i32_gt_s();
2024+
break;
2025+
}
2026+
case (ASR::cmpopType::GtE): {
2027+
m_wa.emit_i32_ge_s();
2028+
break;
2029+
}
2030+
case (ASR::cmpopType::Lt): {
2031+
m_wa.emit_i32_lt_s();
2032+
break;
2033+
}
2034+
case (ASR::cmpopType::LtE): {
2035+
m_wa.emit_i32_le_s();
2036+
break;
2037+
}
2038+
case (ASR::cmpopType::NotEq): {
2039+
m_wa.emit_i32_ne();
2040+
break;
2041+
}
2042+
default:
2043+
throw CodeGenError(
2044+
"handle_string_compare: ICE: Unknown string comparison operator");
2045+
}
2046+
}
2047+
19182048
void visit_IntegerCompare(const ASR::IntegerCompare_t &x) {
19192049
handle_integer_compare(x);
19202050
}
@@ -1931,8 +2061,8 @@ class ASRToWASMVisitor : public ASR::BaseVisitor<ASRToWASMVisitor> {
19312061
handle_integer_compare(x);
19322062
}
19332063

1934-
void visit_StringCompare(const ASR::StringCompare_t & /*x*/) {
1935-
throw CodeGenError("String Types not yet supported");
2064+
void visit_StringCompare(const ASR::StringCompare_t &x) {
2065+
handle_string_compare(x);
19362066
}
19372067

19382068
void visit_StringLen(const ASR::StringLen_t & x) {

0 commit comments

Comments
 (0)