Skip to content

[Strings] string.eq #4781

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

Merged
merged 6 commits into from
Jul 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@
("string.encode_wtf8", "makeStringEncode(s, StringEncodeWTF8)"),
("string.encode_wtf16", "makeStringEncode(s, StringEncodeWTF16)"),
("string.concat", "makeStringConcat(s)"),
("string.eq", "makeStringEq(s)"),
]


Expand Down
20 changes: 14 additions & 6 deletions src/gen-s-parser.inc
Original file line number Diff line number Diff line change
Expand Up @@ -3141,12 +3141,20 @@ switch (op[0]) {
}
}
case 'e': {
switch (op[17]) {
case '1':
if (strcmp(op, "string.encode_wtf16") == 0) { return makeStringEncode(s, StringEncodeWTF16); }
goto parse_error;
case '8':
if (strcmp(op, "string.encode_wtf8") == 0) { return makeStringEncode(s, StringEncodeWTF8); }
switch (op[8]) {
case 'n': {
switch (op[17]) {
case '1':
if (strcmp(op, "string.encode_wtf16") == 0) { return makeStringEncode(s, StringEncodeWTF16); }
goto parse_error;
case '8':
if (strcmp(op, "string.encode_wtf8") == 0) { return makeStringEncode(s, StringEncodeWTF8); }
goto parse_error;
default: goto parse_error;
}
}
case 'q':
if (strcmp(op, "string.eq") == 0) { return makeStringEq(s); }
goto parse_error;
default: goto parse_error;
}
Expand Down
1 change: 1 addition & 0 deletions src/ir/ReFinalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ void ReFinalize::visitStringConst(StringConst* curr) { curr->finalize(); }
void ReFinalize::visitStringMeasure(StringMeasure* curr) { curr->finalize(); }
void ReFinalize::visitStringEncode(StringEncode* curr) { curr->finalize(); }
void ReFinalize::visitStringConcat(StringConcat* curr) { curr->finalize(); }
void ReFinalize::visitStringEq(StringEq* curr) { curr->finalize(); }

void ReFinalize::visitFunction(Function* curr) {
// we may have changed the body from unreachable to none, which might be bad
Expand Down
4 changes: 4 additions & 0 deletions src/ir/cost.h
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,10 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
CostType visitStringConcat(StringConcat* curr) {
return 10 + visit(curr->left) + visit(curr->right);
}
CostType visitStringEq(StringEq* curr) {
// "3" is chosen since strings might or might not be interned in the engine.
return 3 + visit(curr->left) + visit(curr->right);
}

private:
CostType nullCheckCost(Expression* ref) {
Expand Down
1 change: 1 addition & 0 deletions src/ir/effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,7 @@ class EffectAnalyzer {
// traps when an input is null.
parent.implicitTrap = true;
}
void visitStringEq(StringEq* curr) {}
};

public:
Expand Down
4 changes: 4 additions & 0 deletions src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,10 @@ struct InfoCollector
// TODO: optimize when possible
addRoot(curr);
}
void visitStringEq(StringEq* curr) {
// TODO: optimize when possible
addRoot(curr);
}

// TODO: Model which throws can go to which catches. For now, anything thrown
// is sent to the location of that tag, and any catch of that tag can
Expand Down
1 change: 1 addition & 0 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2275,6 +2275,7 @@ struct PrintExpressionContents
void visitStringConcat(StringConcat* curr) {
printMedium(o, "string.concat");
}
void visitStringEq(StringEq* curr) { printMedium(o, "string.eq"); }
};

// Prints an expression in s-expr format, including both the
Expand Down
2 changes: 2 additions & 0 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,7 @@ enum ASTNodes {
StringEncodeWTF8 = 0x86,
StringEncodeWTF16 = 0x87,
StringConcat = 0x88,
StringEq = 0x89,
};

enum MemoryAccess {
Expand Down Expand Up @@ -1730,6 +1731,7 @@ class WasmBinaryBuilder {
bool maybeVisitStringMeasure(Expression*& out, uint32_t code);
bool maybeVisitStringEncode(Expression*& out, uint32_t code);
bool maybeVisitStringConcat(Expression*& out, uint32_t code);
bool maybeVisitStringEq(Expression*& out, uint32_t code);
void visitSelect(Select* curr, uint8_t code);
void visitReturn(Return* curr);
void visitMemorySize(MemorySize* curr);
Expand Down
7 changes: 7 additions & 0 deletions src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,13 @@ class Builder {
ret->finalize();
return ret;
}
StringEq* makeStringEq(Expression* left, Expression* right) {
auto* ret = wasm.allocator.alloc<StringEq>();
ret->left = left;
ret->right = right;
ret->finalize();
return ret;
}

// Additional helpers

Expand Down
7 changes: 7 additions & 0 deletions src/wasm-delegations-fields.def
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,13 @@ switch (DELEGATE_ID) {
DELEGATE_END(StringConcat);
break;
}
case Expression::Id::StringEqId: {
DELEGATE_START(StringEq);
DELEGATE_FIELD_CHILD(StringEq, right);
DELEGATE_FIELD_CHILD(StringEq, left);
DELEGATE_END(StringEq);
break;
}
}

#undef DELEGATE_ID
Expand Down
1 change: 1 addition & 0 deletions src/wasm-delegations.def
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,6 @@ DELEGATE(StringConst);
DELEGATE(StringMeasure);
DELEGATE(StringEncode);
DELEGATE(StringConcat);
DELEGATE(StringEq);

#undef DELEGATE
3 changes: 3 additions & 0 deletions src/wasm-interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -1970,6 +1970,9 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
Flow visitStringConcat(StringConcat* curr) {
WASM_UNREACHABLE("unimplemented string.concat");
}
Flow visitStringEq(StringEq* curr) {
WASM_UNREACHABLE("unimplemented string.eq");
}

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

Expand Down
1 change: 1 addition & 0 deletions src/wasm-s-parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ class SExpressionWasmBuilder {
Expression* makeStringMeasure(Element& s, StringMeasureOp op);
Expression* makeStringEncode(Element& s, StringEncodeOp op);
Expression* makeStringConcat(Element& s);
Expression* makeStringEq(Element& s);

// Helper functions
Type parseOptionalResultType(Element& s, Index& i);
Expand Down
11 changes: 11 additions & 0 deletions src/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ class Expression {
StringMeasureId,
StringEncodeId,
StringConcatId,
StringEqId,
NumExpressionIds
};
Id _id;
Expand Down Expand Up @@ -1725,6 +1726,16 @@ class StringConcat : public SpecificExpression<Expression::StringConcatId> {
void finalize();
};

class StringEq : public SpecificExpression<Expression::StringEqId> {
public:
StringEq(MixedArena& allocator) {}

Expression* left;
Expression* right;

void finalize();
};

// Globals

struct Named {
Expand Down
13 changes: 13 additions & 0 deletions src/wasm/wasm-binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3933,6 +3933,9 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
if (maybeVisitStringConcat(curr, opcode)) {
break;
}
if (maybeVisitStringEq(curr, opcode)) {
break;
}
if (opcode == BinaryConsts::RefIsFunc ||
opcode == BinaryConsts::RefIsData ||
opcode == BinaryConsts::RefIsI31) {
Expand Down Expand Up @@ -7234,6 +7237,16 @@ bool WasmBinaryBuilder::maybeVisitStringConcat(Expression*& out,
return true;
}

bool WasmBinaryBuilder::maybeVisitStringEq(Expression*& out, uint32_t code) {
if (code != BinaryConsts::StringEq) {
return false;
}
auto* right = popNonVoidExpression();
auto* left = popNonVoidExpression();
out = Builder(wasm).makeStringEq(left, right);
return true;
}

void WasmBinaryBuilder::visitRefAs(RefAs* curr, uint8_t code) {
BYN_TRACE("zz node: RefAs\n");
switch (code) {
Expand Down
5 changes: 5 additions & 0 deletions src/wasm/wasm-s-parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2995,6 +2995,11 @@ Expression* SExpressionWasmBuilder::makeStringConcat(Element& s) {
parseExpression(s[2]));
}

Expression* SExpressionWasmBuilder::makeStringEq(Element& s) {
return Builder(wasm).makeStringEq(parseExpression(s[1]),
parseExpression(s[2]));
}

// converts an s-expression string representing binary data into an output
// sequence of raw bytes this appends to data, which may already contain
// content.
Expand Down
4 changes: 4 additions & 0 deletions src/wasm/wasm-stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2304,6 +2304,10 @@ void BinaryInstWriter::visitStringConcat(StringConcat* curr) {
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::StringConcat);
}

void BinaryInstWriter::visitStringEq(StringEq* curr) {
o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::StringEq);
}

void BinaryInstWriter::emitScopeEnd(Expression* curr) {
assert(!breakStack.empty());
breakStack.pop_back();
Expand Down
8 changes: 8 additions & 0 deletions src/wasm/wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1208,6 +1208,14 @@ void StringConcat::finalize() {
}
}

void StringEq::finalize() {
if (left->type == Type::unreachable || right->type == Type::unreachable) {
type = Type::unreachable;
} else {
type = Type::i32;
}
}

size_t Function::getNumParams() { return getParams().size(); }

size_t Function::getNumVars() { return vars.size(); }
Expand Down
4 changes: 4 additions & 0 deletions src/wasm2js.h
Original file line number Diff line number Diff line change
Expand Up @@ -2323,6 +2323,10 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m,
unimplemented(curr);
WASM_UNREACHABLE("unimp");
}
Ref visitStringEq(StringEq* curr) {
unimplemented(curr);
WASM_UNREACHABLE("unimp");
}
Ref visitRefAs(RefAs* curr) {
unimplemented(curr);
WASM_UNREACHABLE("unimp");
Expand Down
25 changes: 23 additions & 2 deletions test/lit/strings.wast
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
(module
;; CHECK: (type $ref?|string|_=>_none (func (param stringref)))

;; CHECK: (type $ref?|string|_ref?|string|_=>_none (func (param stringref stringref)))

;; 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))))

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

;; CHECK: (type $ref?|string|_ref?|string|_=>_none (func (param stringref stringref)))

;; CHECK: (global $string-const stringref (string.const "string in a global"))
(global $string-const stringref (string.const "string in a global"))

Expand Down Expand Up @@ -204,4 +204,25 @@
)
)
)

;; CHECK: (func $string.eq (param $a stringref) (param $b stringref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.eqz
;; CHECK-NEXT: (string.eq
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (local.get $b)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $string.eq (param $a stringref) (param $b stringref)
(drop
(i32.eqz ;; validate the output is an i32
(string.eq
(local.get $a)
(local.get $b)
)
)
)
)
)