Skip to content

Commit 75d059a

Browse files
authored
[Strings] string.eq (#4781)
1 parent 838e8ee commit 75d059a

20 files changed

+115
-8
lines changed

scripts/gen-s-parser.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@
622622
("string.encode_wtf8", "makeStringEncode(s, StringEncodeWTF8)"),
623623
("string.encode_wtf16", "makeStringEncode(s, StringEncodeWTF16)"),
624624
("string.concat", "makeStringConcat(s)"),
625+
("string.eq", "makeStringEq(s)"),
625626
]
626627

627628

src/gen-s-parser.inc

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3141,12 +3141,20 @@ switch (op[0]) {
31413141
}
31423142
}
31433143
case 'e': {
3144-
switch (op[17]) {
3145-
case '1':
3146-
if (strcmp(op, "string.encode_wtf16") == 0) { return makeStringEncode(s, StringEncodeWTF16); }
3147-
goto parse_error;
3148-
case '8':
3149-
if (strcmp(op, "string.encode_wtf8") == 0) { return makeStringEncode(s, StringEncodeWTF8); }
3144+
switch (op[8]) {
3145+
case 'n': {
3146+
switch (op[17]) {
3147+
case '1':
3148+
if (strcmp(op, "string.encode_wtf16") == 0) { return makeStringEncode(s, StringEncodeWTF16); }
3149+
goto parse_error;
3150+
case '8':
3151+
if (strcmp(op, "string.encode_wtf8") == 0) { return makeStringEncode(s, StringEncodeWTF8); }
3152+
goto parse_error;
3153+
default: goto parse_error;
3154+
}
3155+
}
3156+
case 'q':
3157+
if (strcmp(op, "string.eq") == 0) { return makeStringEq(s); }
31503158
goto parse_error;
31513159
default: goto parse_error;
31523160
}

src/ir/ReFinalize.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ void ReFinalize::visitStringConst(StringConst* curr) { curr->finalize(); }
177177
void ReFinalize::visitStringMeasure(StringMeasure* curr) { curr->finalize(); }
178178
void ReFinalize::visitStringEncode(StringEncode* curr) { curr->finalize(); }
179179
void ReFinalize::visitStringConcat(StringConcat* curr) { curr->finalize(); }
180+
void ReFinalize::visitStringEq(StringEq* curr) { curr->finalize(); }
180181

181182
void ReFinalize::visitFunction(Function* curr) {
182183
// we may have changed the body from unreachable to none, which might be bad

src/ir/cost.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,10 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
684684
CostType visitStringConcat(StringConcat* curr) {
685685
return 10 + visit(curr->left) + visit(curr->right);
686686
}
687+
CostType visitStringEq(StringEq* curr) {
688+
// "3" is chosen since strings might or might not be interned in the engine.
689+
return 3 + visit(curr->left) + visit(curr->right);
690+
}
687691

688692
private:
689693
CostType nullCheckCost(Expression* ref) {

src/ir/effects.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ class EffectAnalyzer {
746746
// traps when an input is null.
747747
parent.implicitTrap = true;
748748
}
749+
void visitStringEq(StringEq* curr) {}
749750
};
750751

751752
public:

src/ir/possible-contents.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,10 @@ struct InfoCollector
693693
// TODO: optimize when possible
694694
addRoot(curr);
695695
}
696+
void visitStringEq(StringEq* curr) {
697+
// TODO: optimize when possible
698+
addRoot(curr);
699+
}
696700

697701
// TODO: Model which throws can go to which catches. For now, anything thrown
698702
// is sent to the location of that tag, and any catch of that tag can

src/passes/Print.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2275,6 +2275,7 @@ struct PrintExpressionContents
22752275
void visitStringConcat(StringConcat* curr) {
22762276
printMedium(o, "string.concat");
22772277
}
2278+
void visitStringEq(StringEq* curr) { printMedium(o, "string.eq"); }
22782279
};
22792280

22802281
// Prints an expression in s-expr format, including both the

src/wasm-binary.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,7 @@ enum ASTNodes {
11451145
StringEncodeWTF8 = 0x86,
11461146
StringEncodeWTF16 = 0x87,
11471147
StringConcat = 0x88,
1148+
StringEq = 0x89,
11481149
};
11491150

11501151
enum MemoryAccess {
@@ -1730,6 +1731,7 @@ class WasmBinaryBuilder {
17301731
bool maybeVisitStringMeasure(Expression*& out, uint32_t code);
17311732
bool maybeVisitStringEncode(Expression*& out, uint32_t code);
17321733
bool maybeVisitStringConcat(Expression*& out, uint32_t code);
1734+
bool maybeVisitStringEq(Expression*& out, uint32_t code);
17331735
void visitSelect(Select* curr, uint8_t code);
17341736
void visitReturn(Return* curr);
17351737
void visitMemorySize(MemorySize* curr);

src/wasm-builder.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,13 @@ class Builder {
10271027
ret->finalize();
10281028
return ret;
10291029
}
1030+
StringEq* makeStringEq(Expression* left, Expression* right) {
1031+
auto* ret = wasm.allocator.alloc<StringEq>();
1032+
ret->left = left;
1033+
ret->right = right;
1034+
ret->finalize();
1035+
return ret;
1036+
}
10301037

10311038
// Additional helpers
10321039

src/wasm-delegations-fields.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,13 @@ switch (DELEGATE_ID) {
749749
DELEGATE_END(StringConcat);
750750
break;
751751
}
752+
case Expression::Id::StringEqId: {
753+
DELEGATE_START(StringEq);
754+
DELEGATE_FIELD_CHILD(StringEq, right);
755+
DELEGATE_FIELD_CHILD(StringEq, left);
756+
DELEGATE_END(StringEq);
757+
break;
758+
}
752759
}
753760

754761
#undef DELEGATE_ID

src/wasm-delegations.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,5 +90,6 @@ DELEGATE(StringConst);
9090
DELEGATE(StringMeasure);
9191
DELEGATE(StringEncode);
9292
DELEGATE(StringConcat);
93+
DELEGATE(StringEq);
9394

9495
#undef DELEGATE

src/wasm-interpreter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,6 +1970,9 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
19701970
Flow visitStringConcat(StringConcat* curr) {
19711971
WASM_UNREACHABLE("unimplemented string.concat");
19721972
}
1973+
Flow visitStringEq(StringEq* curr) {
1974+
WASM_UNREACHABLE("unimplemented string.eq");
1975+
}
19731976

19741977
virtual void trap(const char* why) { WASM_UNREACHABLE("unimp"); }
19751978

src/wasm-s-parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ class SExpressionWasmBuilder {
308308
Expression* makeStringMeasure(Element& s, StringMeasureOp op);
309309
Expression* makeStringEncode(Element& s, StringEncodeOp op);
310310
Expression* makeStringConcat(Element& s);
311+
Expression* makeStringEq(Element& s);
311312

312313
// Helper functions
313314
Type parseOptionalResultType(Element& s, Index& i);

src/wasm.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ class Expression {
702702
StringMeasureId,
703703
StringEncodeId,
704704
StringConcatId,
705+
StringEqId,
705706
NumExpressionIds
706707
};
707708
Id _id;
@@ -1725,6 +1726,16 @@ class StringConcat : public SpecificExpression<Expression::StringConcatId> {
17251726
void finalize();
17261727
};
17271728

1729+
class StringEq : public SpecificExpression<Expression::StringEqId> {
1730+
public:
1731+
StringEq(MixedArena& allocator) {}
1732+
1733+
Expression* left;
1734+
Expression* right;
1735+
1736+
void finalize();
1737+
};
1738+
17281739
// Globals
17291740

17301741
struct Named {

src/wasm/wasm-binary.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3933,6 +3933,9 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
39333933
if (maybeVisitStringConcat(curr, opcode)) {
39343934
break;
39353935
}
3936+
if (maybeVisitStringEq(curr, opcode)) {
3937+
break;
3938+
}
39363939
if (opcode == BinaryConsts::RefIsFunc ||
39373940
opcode == BinaryConsts::RefIsData ||
39383941
opcode == BinaryConsts::RefIsI31) {
@@ -7234,6 +7237,16 @@ bool WasmBinaryBuilder::maybeVisitStringConcat(Expression*& out,
72347237
return true;
72357238
}
72367239

7240+
bool WasmBinaryBuilder::maybeVisitStringEq(Expression*& out, uint32_t code) {
7241+
if (code != BinaryConsts::StringEq) {
7242+
return false;
7243+
}
7244+
auto* right = popNonVoidExpression();
7245+
auto* left = popNonVoidExpression();
7246+
out = Builder(wasm).makeStringEq(left, right);
7247+
return true;
7248+
}
7249+
72377250
void WasmBinaryBuilder::visitRefAs(RefAs* curr, uint8_t code) {
72387251
BYN_TRACE("zz node: RefAs\n");
72397252
switch (code) {

src/wasm/wasm-s-parser.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2995,6 +2995,11 @@ Expression* SExpressionWasmBuilder::makeStringConcat(Element& s) {
29952995
parseExpression(s[2]));
29962996
}
29972997

2998+
Expression* SExpressionWasmBuilder::makeStringEq(Element& s) {
2999+
return Builder(wasm).makeStringEq(parseExpression(s[1]),
3000+
parseExpression(s[2]));
3001+
}
3002+
29983003
// converts an s-expression string representing binary data into an output
29993004
// sequence of raw bytes this appends to data, which may already contain
30003005
// content.

src/wasm/wasm-stack.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2304,6 +2304,10 @@ void BinaryInstWriter::visitStringConcat(StringConcat* curr) {
23042304
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::StringConcat);
23052305
}
23062306

2307+
void BinaryInstWriter::visitStringEq(StringEq* curr) {
2308+
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::StringEq);
2309+
}
2310+
23072311
void BinaryInstWriter::emitScopeEnd(Expression* curr) {
23082312
assert(!breakStack.empty());
23092313
breakStack.pop_back();

src/wasm/wasm.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,6 +1208,14 @@ void StringConcat::finalize() {
12081208
}
12091209
}
12101210

1211+
void StringEq::finalize() {
1212+
if (left->type == Type::unreachable || right->type == Type::unreachable) {
1213+
type = Type::unreachable;
1214+
} else {
1215+
type = Type::i32;
1216+
}
1217+
}
1218+
12111219
size_t Function::getNumParams() { return getParams().size(); }
12121220

12131221
size_t Function::getNumVars() { return vars.size(); }

src/wasm2js.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2323,6 +2323,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m,
23232323
unimplemented(curr);
23242324
WASM_UNREACHABLE("unimp");
23252325
}
2326+
Ref visitStringEq(StringEq* curr) {
2327+
unimplemented(curr);
2328+
WASM_UNREACHABLE("unimp");
2329+
}
23262330
Ref visitRefAs(RefAs* curr) {
23272331
unimplemented(curr);
23282332
WASM_UNREACHABLE("unimp");

test/lit/strings.wast

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
(module
88
;; CHECK: (type $ref?|string|_=>_none (func (param stringref)))
99

10+
;; CHECK: (type $ref?|string|_ref?|string|_=>_none (func (param stringref stringref)))
11+
1012
;; CHECK: (type $ref?|string|_ref?|stringview_wtf8|_ref?|stringview_wtf16|_ref?|stringview_iter|_ref?|string|_ref?|stringview_wtf8|_ref?|stringview_wtf16|_ref?|stringview_iter|_ref|string|_ref|stringview_wtf8|_ref|stringview_wtf16|_ref|stringview_iter|_=>_none (func (param stringref stringview_wtf8 stringview_wtf16 stringview_iter stringref stringview_wtf8 stringview_wtf16 stringview_iter (ref string) (ref stringview_wtf8) (ref stringview_wtf16) (ref stringview_iter))))
1113

1214
;; CHECK: (type $none_=>_none (func))
1315

14-
;; CHECK: (type $ref?|string|_ref?|string|_=>_none (func (param stringref stringref)))
15-
1616
;; CHECK: (global $string-const stringref (string.const "string in a global"))
1717
(global $string-const stringref (string.const "string in a global"))
1818

@@ -204,4 +204,25 @@
204204
)
205205
)
206206
)
207+
208+
;; CHECK: (func $string.eq (param $a stringref) (param $b stringref)
209+
;; CHECK-NEXT: (drop
210+
;; CHECK-NEXT: (i32.eqz
211+
;; CHECK-NEXT: (string.eq
212+
;; CHECK-NEXT: (local.get $a)
213+
;; CHECK-NEXT: (local.get $b)
214+
;; CHECK-NEXT: )
215+
;; CHECK-NEXT: )
216+
;; CHECK-NEXT: )
217+
;; CHECK-NEXT: )
218+
(func $string.eq (param $a stringref) (param $b stringref)
219+
(drop
220+
(i32.eqz ;; validate the output is an i32
221+
(string.eq
222+
(local.get $a)
223+
(local.get $b)
224+
)
225+
)
226+
)
227+
)
207228
)

0 commit comments

Comments
 (0)