Skip to content

Commit 7f2048e

Browse files
authored
Merge pull request #2245 from Shaikh-Ubaid/wasm_string_cmp
WASM: Support string comparison
2 parents 9aefff4 + 45668c2 commit 7f2048e

File tree

3 files changed

+142
-10
lines changed

3 files changed

+142
-10
lines changed

integration_tests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,7 @@ RUN(NAME test_vars_01 LABELS cpython llvm)
708708
RUN(NAME test_version LABELS cpython llvm)
709709
RUN(NAME logical_binop1 LABELS cpython llvm)
710710
RUN(NAME vec_01 LABELS cpython llvm c NOFAST)
711-
RUN(NAME test_str_comparison LABELS cpython llvm c)
711+
RUN(NAME test_str_comparison LABELS cpython llvm c wasm)
712712
RUN(NAME test_bit_length LABELS cpython llvm c)
713713
RUN(NAME str_to_list_cast LABELS cpython llvm c)
714714
RUN(NAME cast_01 LABELS cpython llvm c)

integration_tests/test_str_comparison.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ def f():
55
assert s1 <= s2
66
assert s1 >= s2
77
s1 = "abcde"
8-
assert s1 >= s2
8+
assert s1 >= s2
99
assert s1 > s2
1010
s1 = "abc"
11-
assert s1 < s2
11+
assert s1 < s2
1212
assert s1 <= s2
1313
s1 = "Abcd"
1414
s2 = "abcd"
15-
assert s1 < s2
15+
assert s1 < s2
1616
s1 = "orange"
1717
s2 = "apple"
18-
assert s1 >= s2
19-
assert s1 > s2
18+
assert s1 >= s2
19+
assert s1 > s2
2020
s1 = "albatross"
2121
s2 = "albany"
2222
assert s1 >= s2
@@ -28,9 +28,11 @@ def f():
2828
assert s1 < s2
2929
assert s1 != s2
3030
s1 = "Zebra"
31-
s2 = "ant"
31+
s2 = "ant"
3232
assert s1 <= s2
3333
assert s1 < s2
3434
assert s1 != s2
3535

36+
print("Ok")
37+
3638
f()

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)