Skip to content

Add support for relaxed-simd instructions #4320

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 10 commits into from
Nov 15, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
19 changes: 19 additions & 0 deletions scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,25 @@
("f32x4.demote_f64x2_zero", "makeUnary(s, UnaryOp::DemoteZeroVecF64x2ToVecF32x4)"),
("f64x2.promote_low_f32x4", "makeUnary(s, UnaryOp::PromoteLowVecF32x4ToVecF64x2)"),

# relaxed SIMD ops
("i8x16.relaxed_swizzle", "makeBinary(s, BinaryOp::RelaxedSwizzleVec8x16)"),
("i32x4.relaxed_trunc_f32x4_s", "makeUnary(s, UnaryOp::RelaxedTruncSVecF32x4ToVecI32x4)"),
("i32x4.relaxed_trunc_f32x4_u", "makeUnary(s, UnaryOp::RelaxedTruncUVecF32x4ToVecI32x4)"),
("i32x4.relaxed_trunc_f64x2_s_zero", "makeUnary(s, UnaryOp::RelaxedTruncZeroSVecF64x2ToVecI32x4)"),
("i32x4.relaxed_trunc_f64x2_u_zero", "makeUnary(s, UnaryOp::RelaxedTruncZeroUVecF64x2ToVecI32x4)"),
("f32x4.relaxed_fma", "makeSIMDTernary(s, SIMDTernaryOp::RelaxedFmaVecF32x4)"),
("f32x4.relaxed_fms", "makeSIMDTernary(s, SIMDTernaryOp::RelaxedFmsVecF32x4)"),
("f64x2.relaxed_fma", "makeSIMDTernary(s, SIMDTernaryOp::RelaxedFmaVecF64x2)"),
("f64x2.relaxed_fms", "makeSIMDTernary(s, SIMDTernaryOp::RelaxedFmsVecF64x2)"),
("i8x16.laneselect", "makeSIMDTernary(s, SIMDTernaryOp::LaneselectI8x16)"),
("i16x8.laneselect", "makeSIMDTernary(s, SIMDTernaryOp::LaneselectI16x8)"),
("i32x4.laneselect", "makeSIMDTernary(s, SIMDTernaryOp::LaneselectI32x4)"),
("i64x2.laneselect", "makeSIMDTernary(s, SIMDTernaryOp::LaneselectI64x2)"),
("f32x4.relaxed_min", "makeBinary(s, BinaryOp::RelaxedMinVecF32x4)"),
("f32x4.relaxed_max", "makeBinary(s, BinaryOp::RelaxedMaxVecF32x4)"),
("f64x2.relaxed_min", "makeBinary(s, BinaryOp::RelaxedMinVecF64x2)"),
("f64x2.relaxed_max", "makeBinary(s, BinaryOp::RelaxedMaxVecF64x2)"),

# reference types instructions
("ref.null", "makeRefNull(s)"),
("ref.is_null", "makeRefIs(s, RefIsNull)"),
Expand Down
144 changes: 130 additions & 14 deletions src/gen-s-parser.inc
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

#ifdef INSTRUCTION_PARSER
#undef INSTRUCTION_PARSER
char op[30] = {'\0'};
strncpy(op, s[0]->c_str(), 29);
char op[33] = {'\0'};
strncpy(op, s[0]->c_str(), 32);
switch (op[0]) {
case 'a': {
switch (op[1]) {
Expand Down Expand Up @@ -491,9 +491,41 @@ switch (op[0]) {
default: goto parse_error;
}
}
case 'r':
if (strcmp(op, "f32x4.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecF32x4, 4); }
goto parse_error;
case 'r': {
switch (op[8]) {
case 'l': {
switch (op[14]) {
case 'f': {
switch (op[16]) {
case 'a':
if (strcmp(op, "f32x4.relaxed_fma") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::RelaxedFmaVecF32x4); }
goto parse_error;
case 's':
if (strcmp(op, "f32x4.relaxed_fms") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::RelaxedFmsVecF32x4); }
goto parse_error;
default: goto parse_error;
}
}
case 'm': {
switch (op[15]) {
case 'a':
if (strcmp(op, "f32x4.relaxed_max") == 0) { return makeBinary(s, BinaryOp::RelaxedMaxVecF32x4); }
goto parse_error;
case 'i':
if (strcmp(op, "f32x4.relaxed_min") == 0) { return makeBinary(s, BinaryOp::RelaxedMinVecF32x4); }
goto parse_error;
default: goto parse_error;
}
}
default: goto parse_error;
}
}
case 'p':
if (strcmp(op, "f32x4.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecF32x4, 4); }
goto parse_error;
default: goto parse_error;
}
}
case 's': {
switch (op[7]) {
case 'p':
Expand Down Expand Up @@ -789,9 +821,41 @@ switch (op[0]) {
default: goto parse_error;
}
}
case 'r':
if (strcmp(op, "f64x2.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecF64x2, 2); }
goto parse_error;
case 'r': {
switch (op[8]) {
case 'l': {
switch (op[14]) {
case 'f': {
switch (op[16]) {
case 'a':
if (strcmp(op, "f64x2.relaxed_fma") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::RelaxedFmaVecF64x2); }
goto parse_error;
case 's':
if (strcmp(op, "f64x2.relaxed_fms") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::RelaxedFmsVecF64x2); }
goto parse_error;
default: goto parse_error;
}
}
case 'm': {
switch (op[15]) {
case 'a':
if (strcmp(op, "f64x2.relaxed_max") == 0) { return makeBinary(s, BinaryOp::RelaxedMaxVecF64x2); }
goto parse_error;
case 'i':
if (strcmp(op, "f64x2.relaxed_min") == 0) { return makeBinary(s, BinaryOp::RelaxedMinVecF64x2); }
goto parse_error;
default: goto parse_error;
}
}
default: goto parse_error;
}
}
case 'p':
if (strcmp(op, "f64x2.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecF64x2, 2); }
goto parse_error;
default: goto parse_error;
}
}
case 's': {
switch (op[7]) {
case 'p':
Expand Down Expand Up @@ -987,6 +1051,9 @@ switch (op[0]) {
}
case 'l': {
switch (op[7]) {
case 'a':
if (strcmp(op, "i16x8.laneselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::LaneselectI16x8); }
goto parse_error;
case 'e': {
switch (op[9]) {
case 's':
Expand Down Expand Up @@ -1730,6 +1797,9 @@ switch (op[0]) {
}
case 'l': {
switch (op[7]) {
case 'a':
if (strcmp(op, "i32x4.laneselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::LaneselectI32x4); }
goto parse_error;
case 'e': {
switch (op[9]) {
case 's':
Expand Down Expand Up @@ -1796,9 +1866,41 @@ switch (op[0]) {
default: goto parse_error;
}
}
case 'r':
if (strcmp(op, "i32x4.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI32x4, 4); }
goto parse_error;
case 'r': {
switch (op[8]) {
case 'l': {
switch (op[21]) {
case '3': {
switch (op[26]) {
case 's':
if (strcmp(op, "i32x4.relaxed_trunc_f32x4_s") == 0) { return makeUnary(s, UnaryOp::RelaxedTruncSVecF32x4ToVecI32x4); }
goto parse_error;
case 'u':
if (strcmp(op, "i32x4.relaxed_trunc_f32x4_u") == 0) { return makeUnary(s, UnaryOp::RelaxedTruncUVecF32x4ToVecI32x4); }
goto parse_error;
default: goto parse_error;
}
}
case '6': {
switch (op[26]) {
case 's':
if (strcmp(op, "i32x4.relaxed_trunc_f64x2_s_zero") == 0) { return makeUnary(s, UnaryOp::RelaxedTruncZeroSVecF64x2ToVecI32x4); }
goto parse_error;
case 'u':
if (strcmp(op, "i32x4.relaxed_trunc_f64x2_u_zero") == 0) { return makeUnary(s, UnaryOp::RelaxedTruncZeroUVecF64x2ToVecI32x4); }
goto parse_error;
default: goto parse_error;
}
}
default: goto parse_error;
}
}
case 'p':
if (strcmp(op, "i32x4.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI32x4, 4); }
goto parse_error;
default: goto parse_error;
}
}
case 's': {
switch (op[7]) {
case 'h': {
Expand Down Expand Up @@ -2487,6 +2589,9 @@ switch (op[0]) {
}
case 'l': {
switch (op[7]) {
case 'a':
if (strcmp(op, "i64x2.laneselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::LaneselectI64x2); }
goto parse_error;
case 'e':
if (strcmp(op, "i64x2.le_s") == 0) { return makeBinary(s, BinaryOp::LeSVecI64x2); }
goto parse_error;
Expand Down Expand Up @@ -2635,6 +2740,9 @@ switch (op[0]) {
}
case 'l': {
switch (op[7]) {
case 'a':
if (strcmp(op, "i8x16.laneselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::LaneselectI8x16); }
goto parse_error;
case 'e': {
switch (op[9]) {
case 's':
Expand Down Expand Up @@ -2717,9 +2825,17 @@ switch (op[0]) {
case 'p':
if (strcmp(op, "i8x16.popcnt") == 0) { return makeUnary(s, UnaryOp::PopcntVecI8x16); }
goto parse_error;
case 'r':
if (strcmp(op, "i8x16.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI8x16, 16); }
goto parse_error;
case 'r': {
switch (op[8]) {
case 'l':
if (strcmp(op, "i8x16.relaxed_swizzle") == 0) { return makeBinary(s, BinaryOp::RelaxedSwizzleVec8x16); }
goto parse_error;
case 'p':
if (strcmp(op, "i8x16.replace_lane") == 0) { return makeSIMDReplace(s, SIMDReplaceOp::ReplaceLaneVecI8x16, 16); }
goto parse_error;
default: goto parse_error;
}
}
case 's': {
switch (op[7]) {
case 'h': {
Expand Down
17 changes: 17 additions & 0 deletions src/ir/cost.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,10 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
case TruncSatZeroUVecF64x2ToVecI32x4:
case DemoteZeroVecF64x2ToVecF32x4:
case PromoteLowVecF32x4ToVecF64x2:
case RelaxedTruncSVecF32x4ToVecI32x4:
case RelaxedTruncUVecF32x4ToVecI32x4:
case RelaxedTruncZeroSVecF64x2ToVecI32x4:
case RelaxedTruncZeroUVecF64x2ToVecI32x4:
ret = 1;
break;
case InvalidUnary:
Expand Down Expand Up @@ -465,6 +469,8 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
case MaxVecF32x4:
case PMinVecF32x4:
case PMaxVecF32x4:
case RelaxedMinVecF32x4:
case RelaxedMaxVecF32x4:
case AddVecF64x2:
case SubVecF64x2:
ret = 1;
Expand All @@ -479,11 +485,14 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
case MaxVecF64x2:
case PMinVecF64x2:
case PMaxVecF64x2:
case RelaxedMinVecF64x2:
case RelaxedMaxVecF64x2:
case NarrowSVecI16x8ToVecI8x16:
case NarrowUVecI16x8ToVecI8x16:
case NarrowSVecI32x4ToVecI16x8:
case NarrowUVecI32x4ToVecI16x8:
case SwizzleVec8x16:
case RelaxedSwizzleVec8x16:
ret = 1;
break;
case InvalidBinary:
Expand Down Expand Up @@ -523,6 +532,14 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
CostType ret = 0;
switch (curr->op) {
case Bitselect:
case LaneselectI8x16:
case LaneselectI16x8:
case LaneselectI32x4:
case LaneselectI64x2:
case RelaxedFmaVecF32x4:
case RelaxedFmsVecF32x4:
case RelaxedFmaVecF64x2:
case RelaxedFmsVecF64x2:
ret = 1;
break;
}
Expand Down
9 changes: 9 additions & 0 deletions src/literal.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,11 @@ class Literal {
Literal pmax(const Literal& other) const;
Literal copysign(const Literal& other) const;

// Fused multiply add and subtract.
// Computes this + (left * right) to infinite precision then round once.
Literal fma(const Literal& left, const Literal& right) const;
Literal fms(const Literal& left, const Literal& right) const;

std::array<Literal, 16> getLanesSI8x16() const;
std::array<Literal, 16> getLanesUI8x16() const;
std::array<Literal, 8> getLanesSI16x8() const;
Expand Down Expand Up @@ -647,6 +652,10 @@ class Literal {
Literal demoteZeroToF32x4() const;
Literal promoteLowToF64x2() const;
Literal swizzleI8x16(const Literal& other) const;
Literal relaxedFmaF32x4(const Literal& left, const Literal& right) const;
Literal relaxedFmsF32x4(const Literal& left, const Literal& right) const;
Literal relaxedFmaF64x2(const Literal& left, const Literal& right) const;
Literal relaxedFmsF64x2(const Literal& left, const Literal& right) const;

// Checks if an RTT value is a sub-rtt of another, that is, whether GC data
// with this object's RTT can be successfuly cast using the other RTT
Expand Down
52 changes: 52 additions & 0 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,30 @@ struct PrintExpressionContents
case Bitselect:
o << "v128.bitselect";
break;
case LaneselectI8x16:
o << "i8x16.laneselect";
break;
case LaneselectI16x8:
o << "i16x8.laneselect";
break;
case LaneselectI32x4:
o << "i32x4.laneselect";
break;
case LaneselectI64x2:
o << "i64x2.laneselect";
break;
case RelaxedFmaVecF32x4:
o << "f32x4.relaxed_fma";
break;
case RelaxedFmsVecF32x4:
o << "f32x4.relaxed_fms";
break;
case RelaxedFmaVecF64x2:
o << "f64x2.relaxed_fma";
break;
case RelaxedFmsVecF64x2:
o << "f64x2.relaxed_fms";
break;
}
restoreNormalColor(o);
}
Expand Down Expand Up @@ -1192,6 +1216,18 @@ struct PrintExpressionContents
case PromoteLowVecF32x4ToVecF64x2:
o << "f64x2.promote_low_f32x4";
break;
case RelaxedTruncSVecF32x4ToVecI32x4:
o << "i32x4.relaxed_trunc_f32x4_s";
break;
case RelaxedTruncUVecF32x4ToVecI32x4:
o << "i32x4.relaxed_trunc_f32x4_u";
break;
case RelaxedTruncZeroSVecF64x2ToVecI32x4:
o << "i32x4.relaxed_trunc_f64x2_s_zero";
break;
case RelaxedTruncZeroUVecF64x2ToVecI32x4:
o << "i32x4.relaxed_trunc_f64x2_u_zero";
break;
case InvalidUnary:
WASM_UNREACHABLE("unvalid unary operator");
}
Expand Down Expand Up @@ -1800,6 +1836,22 @@ struct PrintExpressionContents
o << "i8x16.swizzle";
break;

case RelaxedMinVecF32x4:
o << "f32x4.relaxed_min";
break;
case RelaxedMaxVecF32x4:
o << "f32x4.relaxed_max";
break;
case RelaxedMinVecF64x2:
o << "f64x2.relaxed_min";
break;
case RelaxedMaxVecF64x2:
o << "f64x2.relaxed_max";
break;
case RelaxedSwizzleVec8x16:
o << "i8x16.relaxed_swizzle";
break;

case InvalidBinary:
WASM_UNREACHABLE("unvalid binary operator");
}
Expand Down
Loading