summaryrefslogtreecommitdiff
path: root/src/wasm/literal.cpp
diff options
context:
space:
mode:
authorThomas Lively <7121787+tlively@users.noreply.github.com>2018-12-04 10:30:35 -0800
committerGitHub <noreply@github.com>2018-12-04 10:30:35 -0800
commitbebbeb54f177bdc2cfdff71d6a256a35f2f2057b (patch)
tree80609eb177ddab4edae30323d42152e9ab59ba9b /src/wasm/literal.cpp
parentb4badb815ec844e438a05d501eafb6bb99383bc6 (diff)
downloadbinaryen-bebbeb54f177bdc2cfdff71d6a256a35f2f2057b.tar.gz
binaryen-bebbeb54f177bdc2cfdff71d6a256a35f2f2057b.tar.bz2
binaryen-bebbeb54f177bdc2cfdff71d6a256a35f2f2057b.zip
Implement nontrapping float-to-int instructions (#1780)
Diffstat (limited to 'src/wasm/literal.cpp')
-rw-r--r--src/wasm/literal.cpp87
1 files changed, 83 insertions, 4 deletions
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index 7b248010e..ece92c6ee 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -22,6 +22,7 @@
#include "emscripten-optimizer/simple_ast.h"
#include "pretty_printing.h"
#include "support/bits.h"
+#include "support/utilities.h"
#include "ir/bits.h"
@@ -232,30 +233,108 @@ Literal Literal::truncateToF32() const {
return Literal(float(getf64()));
}
-Literal Literal::convertSToF32() const {
+Literal Literal::truncSIToF32() const {
if (type == Type::i32) return Literal(float(i32));
if (type == Type::i64) return Literal(float(i64));
WASM_UNREACHABLE();
}
-Literal Literal::convertUToF32() const {
+Literal Literal::truncUIToF32() const {
if (type == Type::i32) return Literal(float(uint32_t(i32)));
if (type == Type::i64) return Literal(float(uint64_t(i64)));
WASM_UNREACHABLE();
}
-Literal Literal::convertSToF64() const {
+Literal Literal::truncSIToF64() const {
if (type == Type::i32) return Literal(double(i32));
if (type == Type::i64) return Literal(double(i64));
WASM_UNREACHABLE();
}
-Literal Literal::convertUToF64() const {
+Literal Literal::truncUIToF64() const {
if (type == Type::i32) return Literal(double(uint32_t(i32)));
if (type == Type::i64) return Literal(double(uint64_t(i64)));
WASM_UNREACHABLE();
}
+template<typename F>
+struct AsInt {
+ using type = void;
+};
+template<> struct AsInt<float> { using type = int32_t; };
+template<> struct AsInt<double> { using type = int64_t; };
+
+template<typename F, typename I, bool (*RangeCheck)(typename AsInt<F>::type)>
+static Literal saturating_trunc(typename AsInt<F>::type val) {
+ if (std::isnan(bit_cast<F>(val))) {
+ return Literal(I(0));
+ }
+ if (!RangeCheck(val)) {
+ if (std::signbit(bit_cast<F>(val))) {
+ return Literal(std::numeric_limits<I>::min());
+ } else {
+ return Literal(std::numeric_limits<I>::max());
+ }
+ }
+ return Literal(I(std::trunc(bit_cast<F>(val))));
+}
+
+Literal Literal::truncSatToSI32() const {
+ if (type == Type::f32) {
+ return saturating_trunc<float, int32_t, isInRangeI32TruncS>(
+ Literal(*this).castToI32().geti32()
+ );
+ }
+ if (type == Type::f64) {
+ return saturating_trunc<double, int32_t, isInRangeI32TruncS>(
+ Literal(*this).castToI64().geti64()
+ );
+ }
+ WASM_UNREACHABLE();
+}
+
+Literal Literal::truncSatToSI64() const {
+ if (type == Type::f32) {
+ return saturating_trunc<float, int64_t, isInRangeI64TruncS>(
+ Literal(*this).castToI32().geti32()
+ );
+ }
+ if (type == Type::f64) {
+ return saturating_trunc<double, int64_t, isInRangeI64TruncS>(
+ Literal(*this).castToI64().geti64()
+ );
+ }
+ WASM_UNREACHABLE();
+}
+
+Literal Literal::truncSatToUI32() const {
+ if (type == Type::f32) {
+ return saturating_trunc<float, uint32_t, isInRangeI32TruncU>(
+ Literal(*this).castToI32().geti32()
+ );
+ }
+ if (type == Type::f64) {
+ return saturating_trunc<double, uint32_t, isInRangeI32TruncU>(
+ Literal(*this).castToI64().geti64()
+ );
+ }
+ WASM_UNREACHABLE();
+}
+
+Literal Literal::truncSatToUI64() const {
+ if (type == Type::f32) {
+ return saturating_trunc<float, uint64_t, isInRangeI64TruncU>(
+ Literal(*this).castToI32().geti32()
+ );
+ }
+ if (type == Type::f64) {
+ return saturating_trunc<double, uint64_t, isInRangeI64TruncU>(
+ Literal(*this).castToI64().geti64()
+ );
+ }
+ WASM_UNREACHABLE();
+}
+
Literal Literal::eqz() const {
switch (type) {
case Type::i32: return eq(Literal(int32_t(0)));