summaryrefslogtreecommitdiff
path: root/src/wasm
diff options
context:
space:
mode:
authorBrendan Dahl <brendan.dahl@gmail.com>2024-09-26 15:35:47 -0700
committerGitHub <noreply@github.com>2024-09-26 15:35:47 -0700
commitc3a71ff46d8f38e29896c321d89b6d0c3b90fbc1 (patch)
tree04c4751da10f8e548e0ff94945d2635939b34f58 /src/wasm
parent3856a2dc909b3c713497ef311fe4051078ee74b9 (diff)
downloadbinaryen-c3a71ff46d8f38e29896c321d89b6d0c3b90fbc1.tar.gz
binaryen-c3a71ff46d8f38e29896c321d89b6d0c3b90fbc1.tar.bz2
binaryen-c3a71ff46d8f38e29896c321d89b6d0c3b90fbc1.zip
[FP16] Implement conversion operations. (#6974)
Note: FP16 is a little different from F32/F64 since it can't represent the full 2^16 integer range. 65504 is the max whole integer. This leads to some slightly strange behavior when converting integers greater than 65504 since they become infinity. Specified at https://github.com/WebAssembly/half-precision/blob/main/proposals/half-precision/Overview.md
Diffstat (limited to 'src/wasm')
-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
5 files changed, 83 insertions, 0 deletions
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: