summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gen-s-parser.inc49
-rw-r--r--src/ir/child-typer.h4
-rw-r--r--src/ir/cost.h4
-rw-r--r--src/literal.h8
-rw-r--r--src/passes/Print.cpp12
-rw-r--r--src/support/safe_integer.cpp10
-rw-r--r--src/support/safe_integer.h2
-rw-r--r--src/tools/fuzzing/fuzzing.cpp6
-rw-r--r--src/wasm-binary.h4
-rw-r--r--src/wasm-interpreter.h8
-rw-r--r--src/wasm.h4
-rw-r--r--src/wasm/literal.cpp43
-rw-r--r--src/wasm/wasm-binary.cpp16
-rw-r--r--src/wasm/wasm-stack.cpp16
-rw-r--r--src/wasm/wasm-validator.cpp4
-rw-r--r--src/wasm/wasm.cpp4
16 files changed, 188 insertions, 6 deletions
diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc
index f7d12a1be..75fda4f7a 100644
--- a/src/gen-s-parser.inc
+++ b/src/gen-s-parser.inc
@@ -326,12 +326,34 @@ switch (buf[0]) {
default: goto parse_error;
}
}
- case 'c':
- if (op == "f16x8.ceil"sv) {
- CHECK_ERR(makeUnary(ctx, pos, annotations, UnaryOp::CeilVecF16x8));
- return Ok{};
+ case 'c': {
+ switch (buf[7]) {
+ case 'e':
+ if (op == "f16x8.ceil"sv) {
+ CHECK_ERR(makeUnary(ctx, pos, annotations, UnaryOp::CeilVecF16x8));
+ return Ok{};
+ }
+ goto parse_error;
+ case 'o': {
+ switch (buf[20]) {
+ case 's':
+ if (op == "f16x8.convert_i16x8_s"sv) {
+ CHECK_ERR(makeUnary(ctx, pos, annotations, UnaryOp::ConvertSVecI16x8ToVecF16x8));
+ return Ok{};
+ }
+ goto parse_error;
+ case 'u':
+ if (op == "f16x8.convert_i16x8_u"sv) {
+ CHECK_ERR(makeUnary(ctx, pos, annotations, UnaryOp::ConvertUVecI16x8ToVecF16x8));
+ return Ok{};
+ }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
+ default: goto parse_error;
}
- goto parse_error;
+ }
case 'd':
if (op == "f16x8.div"sv) {
CHECK_ERR(makeBinary(ctx, pos, annotations, BinaryOp::DivVecF16x8));
@@ -2038,6 +2060,23 @@ switch (buf[0]) {
default: goto parse_error;
}
}
+ case 't': {
+ switch (buf[22]) {
+ case 's':
+ if (op == "i16x8.trunc_sat_f16x8_s"sv) {
+ CHECK_ERR(makeUnary(ctx, pos, annotations, UnaryOp::TruncSatSVecF16x8ToVecI16x8));
+ return Ok{};
+ }
+ goto parse_error;
+ case 'u':
+ if (op == "i16x8.trunc_sat_f16x8_u"sv) {
+ CHECK_ERR(makeUnary(ctx, pos, annotations, UnaryOp::TruncSatUVecF16x8ToVecI16x8));
+ return Ok{};
+ }
+ goto parse_error;
+ default: goto parse_error;
+ }
+ }
default: goto parse_error;
}
}
diff --git a/src/ir/child-typer.h b/src/ir/child-typer.h
index 638bb9c33..499a7e4dd 100644
--- a/src/ir/child-typer.h
+++ b/src/ir/child-typer.h
@@ -423,6 +423,10 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
case RelaxedTruncUVecF32x4ToVecI32x4:
case RelaxedTruncZeroSVecF64x2ToVecI32x4:
case RelaxedTruncZeroUVecF64x2ToVecI32x4:
+ case TruncSatSVecF16x8ToVecI16x8:
+ case TruncSatUVecF16x8ToVecI16x8:
+ case ConvertSVecI16x8ToVecF16x8:
+ case ConvertUVecI16x8ToVecF16x8:
case AnyTrueVec128:
case AllTrueVecI8x16:
case AllTrueVecI16x8:
diff --git a/src/ir/cost.h b/src/ir/cost.h
index d11a9bfac..fcee6c18e 100644
--- a/src/ir/cost.h
+++ b/src/ir/cost.h
@@ -257,6 +257,10 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
case RelaxedTruncUVecF32x4ToVecI32x4:
case RelaxedTruncZeroSVecF64x2ToVecI32x4:
case RelaxedTruncZeroUVecF64x2ToVecI32x4:
+ case TruncSatSVecF16x8ToVecI16x8:
+ case TruncSatUVecF16x8ToVecI16x8:
+ case ConvertSVecI16x8ToVecF16x8:
+ case ConvertUVecI16x8ToVecF16x8:
ret = 1;
break;
case InvalidUnary:
diff --git a/src/literal.h b/src/literal.h
index 6aa348084..50666083e 100644
--- a/src/literal.h
+++ b/src/literal.h
@@ -377,14 +377,18 @@ public:
Literal extendS32() const;
Literal wrapToI32() const;
+ Literal convertSIToF16() const;
+ Literal convertUIToF16() const;
Literal convertSIToF32() const;
Literal convertUIToF32() const;
Literal convertSIToF64() const;
Literal convertUIToF64() const;
Literal convertF32ToF16() const;
+ Literal truncSatToSI16() const;
Literal truncSatToSI32() const;
Literal truncSatToSI64() const;
+ Literal truncSatToUI16() const;
Literal truncSatToUI32() const;
Literal truncSatToUI64() const;
@@ -693,6 +697,10 @@ public:
Literal truncSatZeroUToI32x4() const;
Literal demoteZeroToF32x4() const;
Literal promoteLowToF64x2() const;
+ Literal truncSatToSI16x8() const;
+ Literal truncSatToUI16x8() const;
+ Literal convertSToF16x8() const;
+ Literal convertUToF16x8() const;
Literal swizzleI8x16(const Literal& other) const;
Literal relaxedMaddF16x8(const Literal& left, const Literal& right) const;
Literal relaxedNmaddF16x8(const Literal& left, const Literal& right) const;
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index 427bff329..854934204 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -1368,6 +1368,18 @@ struct PrintExpressionContents
case RelaxedTruncZeroUVecF64x2ToVecI32x4:
o << "i32x4.relaxed_trunc_f64x2_u_zero";
break;
+ case TruncSatSVecF16x8ToVecI16x8:
+ o << "i16x8.trunc_sat_f16x8_s";
+ break;
+ case TruncSatUVecF16x8ToVecI16x8:
+ o << "i16x8.trunc_sat_f16x8_u";
+ break;
+ case ConvertSVecI16x8ToVecF16x8:
+ o << "f16x8.convert_i16x8_s";
+ break;
+ case ConvertUVecI16x8ToVecF16x8:
+ o << "f16x8.convert_i16x8_u";
+ break;
case InvalidUnary:
WASM_UNREACHABLE("unvalid unary operator");
}
diff --git a/src/support/safe_integer.cpp b/src/support/safe_integer.cpp
index 3a50b50ea..86ba2547a 100644
--- a/src/support/safe_integer.cpp
+++ b/src/support/safe_integer.cpp
@@ -98,6 +98,11 @@ int64_t wasm::toSInteger64(double x) {
* 1 11111111 111...11 => 0xffffffff => -nan(0x7fffff)
*/
+bool wasm::isInRangeI16TruncS(int32_t i) {
+ uint32_t u = i;
+ return (u < 0x47000000U) || (u >= 0x80000000U && u <= 0xc7000000U);
+}
+
bool wasm::isInRangeI32TruncS(int32_t i) {
uint32_t u = i;
return (u < 0x4f000000U) || (u >= 0x80000000U && u <= 0xcf000000U);
@@ -108,6 +113,11 @@ bool wasm::isInRangeI64TruncS(int32_t i) {
return (u < 0x5f000000U) || (u >= 0x80000000U && u <= 0xdf000000U);
}
+bool wasm::isInRangeI16TruncU(int32_t i) {
+ uint32_t u = i;
+ return (u < 0x47800000) || (u >= 0x80000000U && u < 0xbf800000U);
+}
+
bool wasm::isInRangeI32TruncU(int32_t i) {
uint32_t u = i;
return (u < 0x4f800000U) || (u >= 0x80000000U && u < 0xbf800000U);
diff --git a/src/support/safe_integer.h b/src/support/safe_integer.h
index 031c6c323..6888ab25f 100644
--- a/src/support/safe_integer.h
+++ b/src/support/safe_integer.h
@@ -32,8 +32,10 @@ uint64_t toUInteger64(double x);
int64_t toSInteger64(double x);
// The isInRange* functions all expect to be passed the binary representation
// of a float or double.
+bool isInRangeI16TruncS(int32_t i);
bool isInRangeI32TruncS(int32_t i);
bool isInRangeI64TruncS(int32_t i);
+bool isInRangeI16TruncU(int32_t i);
bool isInRangeI32TruncU(int32_t i);
bool isInRangeI64TruncU(int32_t i);
bool isInRangeI32TruncS(int64_t i);
diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp
index a66fa6772..a8b8f7855 100644
--- a/src/tools/fuzzing/fuzzing.cpp
+++ b/src/tools/fuzzing/fuzzing.cpp
@@ -3143,7 +3143,11 @@ Expression* TranslateToFuzzReader::makeUnary(Type type) {
CeilVecF16x8,
FloorVecF16x8,
TruncVecF16x8,
- NearestVecF16x8)),
+ NearestVecF16x8,
+ TruncSatSVecF16x8ToVecI16x8,
+ TruncSatUVecF16x8ToVecI16x8,
+ ConvertSVecI16x8ToVecF16x8,
+ ConvertUVecI16x8ToVecF16x8)),
make(Type::v128)});
}
WASM_UNREACHABLE("invalid value");
diff --git a/src/wasm-binary.h b/src/wasm-binary.h
index 5021b6a29..35f131952 100644
--- a/src/wasm-binary.h
+++ b/src/wasm-binary.h
@@ -1039,6 +1039,10 @@ enum ASTNodes {
F16x8Max = 0x142,
F16x8Pmin = 0x143,
F16x8Pmax = 0x144,
+ I16x8TruncSatF16x8S = 0x145,
+ I16x8TruncSatF16x8U = 0x146,
+ F16x8ConvertI16x8S = 0x147,
+ F16x8ConvertI16x8U = 0x148,
// bulk memory opcodes
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 25303abfe..9659a5c34 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -632,6 +632,14 @@ public:
return value.demoteZeroToF32x4();
case PromoteLowVecF32x4ToVecF64x2:
return value.promoteLowToF64x2();
+ case TruncSatSVecF16x8ToVecI16x8:
+ return value.truncSatToSI16x8();
+ case TruncSatUVecF16x8ToVecI16x8:
+ return value.truncSatToUI16x8();
+ case ConvertSVecI16x8ToVecF16x8:
+ return value.convertSToF16x8();
+ case ConvertUVecI16x8ToVecF16x8:
+ return value.convertUToF16x8();
case InvalidUnary:
WASM_UNREACHABLE("invalid unary op");
}
diff --git a/src/wasm.h b/src/wasm.h
index a86f77013..e54d628bd 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -238,6 +238,10 @@ enum UnaryOp {
// Half precision SIMD
SplatVecF16x8,
+ TruncSatSVecF16x8ToVecI16x8,
+ TruncSatUVecF16x8ToVecI16x8,
+ ConvertSVecI16x8ToVecF16x8,
+ ConvertUVecI16x8ToVecF16x8,
InvalidUnary
};
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index 6aaba729a..b53378cfa 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -798,6 +798,20 @@ Literal Literal::wrapToI32() const {
return Literal((int32_t)i64);
}
+Literal Literal::convertSIToF16() const {
+ if (type == Type::i32) {
+ return Literal(fp16_ieee_from_fp32_value(float(i32)));
+ }
+ WASM_UNREACHABLE("invalid type");
+}
+
+Literal Literal::convertUIToF16() const {
+ if (type == Type::i32) {
+ return Literal(fp16_ieee_from_fp32_value(float(uint16_t(i32))));
+ }
+ WASM_UNREACHABLE("invalid type");
+}
+
Literal Literal::convertSIToF32() const {
if (type == Type::i32) {
return Literal(float(i32));
@@ -861,6 +875,14 @@ static Literal saturating_trunc(typename AsInt<F>::type val) {
return Literal(I(std::trunc(bit_cast<F>(val))));
}
+Literal Literal::truncSatToSI16() const {
+ if (type == Type::f32) {
+ return saturating_trunc<float, int16_t, isInRangeI16TruncS>(
+ Literal(*this).castToI32().geti32());
+ }
+ WASM_UNREACHABLE("invalid type");
+}
+
Literal Literal::truncSatToSI32() const {
if (type == Type::f32) {
return saturating_trunc<float, int32_t, isInRangeI32TruncS>(
@@ -885,6 +907,14 @@ Literal Literal::truncSatToSI64() const {
WASM_UNREACHABLE("invalid type");
}
+Literal Literal::truncSatToUI16() const {
+ if (type == Type::f32) {
+ return saturating_trunc<float, uint16_t, isInRangeI16TruncU>(
+ Literal(*this).castToI32().geti32());
+ }
+ WASM_UNREACHABLE("invalid type");
+}
+
Literal Literal::truncSatToUI32() const {
if (type == Type::f32) {
return saturating_trunc<float, uint32_t, isInRangeI32TruncU>(
@@ -1997,6 +2027,19 @@ Literal Literal::convertUToF32x4() const {
return unary<4, &Literal::getLanesI32x4, &Literal::convertUIToF32>(*this);
}
+Literal Literal::truncSatToSI16x8() const {
+ return unary<8, &Literal::getLanesF16x8, &Literal::truncSatToSI16>(*this);
+}
+Literal Literal::truncSatToUI16x8() const {
+ return unary<8, &Literal::getLanesF16x8, &Literal::truncSatToUI16>(*this);
+}
+Literal Literal::convertSToF16x8() const {
+ return unary<8, &Literal::getLanesSI16x8, &Literal::convertSIToF16>(*this);
+}
+Literal Literal::convertUToF16x8() const {
+ return unary<8, &Literal::getLanesSI16x8, &Literal::convertUIToF16>(*this);
+}
+
Literal Literal::anyTrueV128() const {
auto lanes = getLanesI32x4();
for (size_t i = 0; i < 4; ++i) {
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index cb9ea3731..3bb33529b 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -6522,6 +6522,22 @@ bool WasmBinaryReader::maybeVisitSIMDUnary(Expression*& out, uint32_t code) {
curr = allocator.alloc<Unary>();
curr->op = RelaxedTruncZeroUVecF64x2ToVecI32x4;
break;
+ case BinaryConsts::I16x8TruncSatF16x8S:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatSVecF16x8ToVecI16x8;
+ break;
+ case BinaryConsts::I16x8TruncSatF16x8U:
+ curr = allocator.alloc<Unary>();
+ curr->op = TruncSatUVecF16x8ToVecI16x8;
+ break;
+ case BinaryConsts::F16x8ConvertI16x8S:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertSVecI16x8ToVecF16x8;
+ break;
+ case BinaryConsts::F16x8ConvertI16x8U:
+ curr = allocator.alloc<Unary>();
+ curr->op = ConvertUVecI16x8ToVecF16x8;
+ break;
default:
return false;
}
diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp
index a1446c2de..7194229fe 100644
--- a/src/wasm/wasm-stack.cpp
+++ b/src/wasm/wasm-stack.cpp
@@ -1324,6 +1324,22 @@ void BinaryInstWriter::visitUnary(Unary* curr) {
o << int8_t(BinaryConsts::SIMDPrefix)
<< U32LEB(BinaryConsts::I32x4RelaxedTruncF64x2UZero);
break;
+ case TruncSatSVecF16x8ToVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I16x8TruncSatF16x8S);
+ break;
+ case TruncSatUVecF16x8ToVecI16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::I16x8TruncSatF16x8U);
+ break;
+ case ConvertSVecI16x8ToVecF16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::F16x8ConvertI16x8S);
+ break;
+ case ConvertUVecI16x8ToVecF16x8:
+ o << int8_t(BinaryConsts::SIMDPrefix)
+ << U32LEB(BinaryConsts::F16x8ConvertI16x8U);
+ break;
case InvalidUnary:
WASM_UNREACHABLE("invalid unary op");
}
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp
index 40726d7cd..a86187fa7 100644
--- a/src/wasm/wasm-validator.cpp
+++ b/src/wasm/wasm-validator.cpp
@@ -2160,6 +2160,10 @@ void FunctionValidator::visitUnary(Unary* curr) {
case RelaxedTruncUVecF32x4ToVecI32x4:
case RelaxedTruncZeroSVecF64x2ToVecI32x4:
case RelaxedTruncZeroUVecF64x2ToVecI32x4:
+ case TruncSatSVecF16x8ToVecI16x8:
+ case TruncSatUVecF16x8ToVecI16x8:
+ case ConvertSVecI16x8ToVecF16x8:
+ case ConvertUVecI16x8ToVecF16x8:
shouldBeEqual(curr->type, Type(Type::v128), curr, "expected v128 type");
shouldBeEqual(
curr->value->type, Type(Type::v128), curr, "expected v128 operand");
diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp
index 87ae6ac5a..84fd9a06f 100644
--- a/src/wasm/wasm.cpp
+++ b/src/wasm/wasm.cpp
@@ -703,6 +703,10 @@ void Unary::finalize() {
case RelaxedTruncUVecF32x4ToVecI32x4:
case RelaxedTruncZeroSVecF64x2ToVecI32x4:
case RelaxedTruncZeroUVecF64x2ToVecI32x4:
+ case TruncSatSVecF16x8ToVecI16x8:
+ case TruncSatUVecF16x8ToVecI16x8:
+ case ConvertSVecI16x8ToVecF16x8:
+ case ConvertUVecI16x8ToVecF16x8:
type = Type::v128;
break;
case AnyTrueVec128: