summaryrefslogtreecommitdiff
path: root/src/wasm/literal.cpp
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2018-04-13 09:17:21 -0700
committerGitHub <noreply@github.com>2018-04-13 09:17:21 -0700
commitfd3b3e54bd97abbf8269b33d937ad2f44ba4bb60 (patch)
treef36ce91f19944f00460035105758f61606a42bdd /src/wasm/literal.cpp
parent7a8273ae2c1854b9840fc56a952e572f673bb10f (diff)
downloadbinaryen-fd3b3e54bd97abbf8269b33d937ad2f44ba4bb60.tar.gz
binaryen-fd3b3e54bd97abbf8269b33d937ad2f44ba4bb60.tar.bz2
binaryen-fd3b3e54bd97abbf8269b33d937ad2f44ba4bb60.zip
Refactor interpreter (#1508)
* Move more logic to the Literal class. We now leave all the work to there, except for handling traps. * Avoid switching on the type, then the opcode, then Literal method usually switches on the type again - instead, do one big switch for the opcodes (then the Literal method is unchanged) which is shorter and clearer, and avoids that first switching.
Diffstat (limited to 'src/wasm/literal.cpp')
-rw-r--r--src/wasm/literal.cpp56
1 files changed, 50 insertions, 6 deletions
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index a6dcd17f0..e68dd5d5f 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -22,6 +22,8 @@
#include "emscripten-optimizer/simple_ast.h"
#include "pretty_printing.h"
#include "support/bits.h"
+#include "ir/bits.h"
+
namespace wasm {
@@ -213,6 +215,23 @@ Literal Literal::extendToF64() const {
return Literal(double(getf32()));
}
+Literal Literal::extendS8() const {
+ if (type == Type::i32) return Literal(int32_t(int8_t(geti32() & 0xFF)));
+ if (type == Type::i64) return Literal(int64_t(int8_t(geti64() & 0xFF)));
+ WASM_UNREACHABLE();
+}
+
+Literal Literal::extendS16() const {
+ if (type == Type::i32) return Literal(int32_t(int16_t(geti32() & 0xFFFF)));
+ if (type == Type::i64) return Literal(int64_t(int16_t(geti64() & 0xFFFF)));
+ WASM_UNREACHABLE();
+}
+
+Literal Literal::extendS32() const {
+ if (type == Type::i64) return Literal(int64_t(int32_t(geti64() & 0xFFFFFFFF)));
+ WASM_UNREACHABLE();
+}
+
Literal Literal::truncateToI32() const {
assert(type == Type::i64);
return Literal((int32_t)i64);
@@ -247,6 +266,16 @@ Literal Literal::convertUToF64() const {
WASM_UNREACHABLE();
}
+Literal Literal::eqz() const {
+ switch (type) {
+ case Type::i32: return eq(Literal(int32_t(0)));
+ case Type::i64: return eq(Literal(int64_t(0)));
+ case Type::f32: return eq(Literal(float(0)));
+ case Type::f64: return eq(Literal(double(0)));
+ default: WASM_UNREACHABLE();
+ }
+}
+
Literal Literal::neg() const {
switch (type) {
case Type::i32: return Literal(-uint32_t(i32));
@@ -307,6 +336,21 @@ Literal Literal::sqrt() const {
}
}
+Literal Literal::demote() const {
+ auto f64 = getf64();
+ if (std::isnan(f64)) return Literal(float(f64));
+ if (std::isinf(f64)) return Literal(float(f64));
+ // when close to the limit, but still truncatable to a valid value, do that
+ // see https://github.com/WebAssembly/sexpr-wasm-prototype/blob/2d375e8d502327e814d62a08f22da9d9b6b675dc/src/wasm-interpreter.c#L247
+ uint64_t bits = reinterpreti64();
+ if (bits > 0x47efffffe0000000ULL && bits < 0x47effffff0000000ULL) return Literal(std::numeric_limits<float>::max());
+ if (bits > 0xc7efffffe0000000ULL && bits < 0xc7effffff0000000ULL) return Literal(-std::numeric_limits<float>::max());
+ // when we must convert to infinity, do that
+ if (f64 < -std::numeric_limits<float>::max()) return Literal(-std::numeric_limits<float>::infinity());
+ if (f64 > std::numeric_limits<float>::max()) return Literal(std::numeric_limits<float>::infinity());
+ return truncateToF32();
+}
+
Literal Literal::add(const Literal& other) const {
switch (type) {
case Type::i32: return Literal(uint32_t(i32) + uint32_t(other.i32));
@@ -441,24 +485,24 @@ Literal Literal::xor_(const Literal& other) const {
Literal Literal::shl(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) << shiftMask(other.i32));
- case Type::i64: return Literal(uint64_t(i64) << shiftMask(other.i64));
+ case Type::i32: return Literal(uint32_t(i32) << Bits::getEffectiveShifts(other.i32, Type::i32));
+ case Type::i64: return Literal(uint64_t(i64) << Bits::getEffectiveShifts(other.i64, Type::i64));
default: WASM_UNREACHABLE();
}
}
Literal Literal::shrS(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(i32 >> shiftMask(other.i32));
- case Type::i64: return Literal(i64 >> shiftMask(other.i64));
+ case Type::i32: return Literal(i32 >> Bits::getEffectiveShifts(other.i32, Type::i32));
+ case Type::i64: return Literal(i64 >> Bits::getEffectiveShifts(other.i64, Type::i64));
default: WASM_UNREACHABLE();
}
}
Literal Literal::shrU(const Literal& other) const {
switch (type) {
- case Type::i32: return Literal(uint32_t(i32) >> shiftMask(other.i32));
- case Type::i64: return Literal(uint64_t(i64) >> shiftMask(other.i64));
+ case Type::i32: return Literal(uint32_t(i32) >> Bits::getEffectiveShifts(other.i32, Type::i32));
+ case Type::i64: return Literal(uint64_t(i64) >> Bits::getEffectiveShifts(other.i64, Type::i64));
default: WASM_UNREACHABLE();
}
}