summaryrefslogtreecommitdiff
path: root/src/wasm/literal.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/literal.cpp')
-rw-r--r--src/wasm/literal.cpp684
1 files changed, 676 insertions, 8 deletions
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp
index 7b9e64e43..8d44b9b73 100644
--- a/src/wasm/literal.cpp
+++ b/src/wasm/literal.cpp
@@ -28,6 +28,52 @@
namespace wasm {
+template<int N>
+using LaneArray = std::array<Literal, N>;
+
+Literal::Literal(const uint8_t init[16]) : type(Type::v128) {
+ memcpy(&v128, init, 16);
+}
+
+template<typename LaneT, int Lanes>
+static void extractBytes(uint8_t (&dest)[16], const LaneArray<Lanes>& lanes) {
+ std::array<uint8_t, 16> bytes;
+ const size_t lane_width = 16 / Lanes;
+ for (size_t lane_idx = 0; lane_idx < Lanes; ++lane_idx) {
+ uint8_t bits[16];
+ lanes[lane_idx].getBits(bits);
+ LaneT lane;
+ memcpy(&lane, bits, sizeof(lane));
+ for (size_t offset = 0; offset < lane_width; ++offset) {
+ bytes.at(lane_idx * lane_width + offset) = uint8_t(lane >> (8 * offset));
+ }
+ }
+ memcpy(&dest, bytes.data(), sizeof(bytes));
+}
+
+Literal::Literal(const LaneArray<16>& lanes) : type(Type::v128) {
+ extractBytes<uint8_t, 16>(v128, lanes);
+}
+
+Literal::Literal(const LaneArray<8>& lanes) : type(Type::v128) {
+ extractBytes<uint16_t, 8>(v128, lanes);
+}
+
+Literal::Literal(const LaneArray<4>& lanes) : type(Type::v128) {
+ extractBytes<uint32_t, 4>(v128, lanes);
+}
+
+Literal::Literal(const LaneArray<2>& lanes) : type(Type::v128) {
+ extractBytes<uint64_t, 2>(v128, lanes);
+}
+
+std::array<uint8_t, 16> Literal::getv128() const {
+ assert(type == Type::v128);
+ std::array<uint8_t, 16> ret;
+ memcpy(ret.data(), v128, sizeof(ret));
+ return ret;
+}
+
Literal Literal::castToF32() {
assert(type == Type::i32);
Literal ret(i32);
@@ -72,20 +118,26 @@ double Literal::getFloat() const {
}
}
-int64_t Literal::getBits() const {
+void Literal::getBits(uint8_t (&buf)[16]) const {
+ memset(buf, 0, 16);
switch (type) {
- case Type::i32: case Type::f32: return i32;
- case Type::i64: case Type::f64: return i64;
- case Type::v128: assert(false && "v128 not implemented");
- case Type::none: case Type::unreachable: WASM_UNREACHABLE();
+ case Type::i32:
+ case Type::f32: memcpy(buf, &i32, sizeof(i32)); break;
+ case Type::i64:
+ case Type::f64: memcpy(buf, &i64, sizeof(i64)); break;
+ case Type::v128: memcpy(buf, &v128, sizeof(v128)); break;
+ case Type::none:
+ case Type::unreachable: WASM_UNREACHABLE();
}
- WASM_UNREACHABLE();
}
bool Literal::operator==(const Literal& other) const {
if (type != other.type) return false;
if (type == none) return true;
- return getBits() == other.getBits();
+ uint8_t bits[16], other_bits[16];
+ getBits(bits);
+ other.getBits(other_bits);
+ return memcmp(bits, other_bits, 16) == 0;
}
bool Literal::operator!=(const Literal& other) const {
@@ -158,6 +210,15 @@ void Literal::printDouble(std::ostream& o, double d) {
o << text;
}
+void Literal::printVec128(std::ostream& o, const std::array<uint8_t, 16>& v) {
+ o << std::hex;
+ for (auto i = 0; i < 16; ++i) {
+ o << "0x" << uint32_t(v[i]);
+ if (i < 15) o << " ";
+ }
+ o << std::dec;
+}
+
std::ostream& operator<<(std::ostream& o, Literal literal) {
prepareMinorColor(o) << printType(literal.type) << ".const ";
switch (literal.type) {
@@ -166,7 +227,7 @@ std::ostream& operator<<(std::ostream& o, Literal literal) {
case Type::i64: o << literal.i64; break;
case Type::f32: literal.printFloat(o, literal.getf32()); break;
case Type::f64: literal.printDouble(o, literal.getf64()); break;
- case Type::v128: assert(false && "v128 not implemented yet");
+ case Type::v128: o << "i32 "; literal.printVec128(o, literal.getv128()); break;
case Type::unreachable: WASM_UNREACHABLE();
}
restoreNormalColor(o);
@@ -450,6 +511,79 @@ Literal Literal::sub(const Literal& other) const {
WASM_UNREACHABLE();
}
+template<typename T>
+static T add_sat_s(T a, T b) {
+ static_assert(std::is_signed<T>::value, "Trying to instantiate add_sat_s with unsigned type");
+ using UT = typename std::make_unsigned<T>::type;
+ UT ua = static_cast<UT>(a);
+ UT ub = static_cast<UT>(b);
+ UT ures = ua + ub;
+ // overflow if sign of result is different from sign of a and b
+ if (static_cast<T>((ures ^ ua) & (ures ^ ub)) < 0) {
+ return (a < 0)
+ ? std::numeric_limits<T>::min()
+ : std::numeric_limits<T>::max();
+ }
+ return static_cast<T>(ures);
+}
+
+template<typename T>
+static T sub_sat_s(T a, T b) {
+ static_assert(std::is_signed<T>::value, "Trying to instantiate sub_sat_s with unsigned type");
+ using UT = typename std::make_unsigned<T>::type;
+ UT ua = static_cast<UT>(a);
+ UT ub = static_cast<UT>(b);
+ UT ures = ua - ub;
+ // overflow if a and b have different signs and result and a differ in sign
+ if (static_cast<T>((ua ^ ub) & (ures ^ ua)) < 0) {
+ return (a < 0)
+ ? std::numeric_limits<T>::min()
+ : std::numeric_limits<T>::max();
+ }
+ return static_cast<T>(ures);
+}
+
+template<typename T>
+static T add_sat_u(T a, T b) {
+ static_assert(std::is_unsigned<T>::value, "Trying to instantiate add_sat_u with signed type");
+ T res = a + b;
+ // overflow if result is less than arguments
+ return (res < a) ? std::numeric_limits<T>::max() : res;
+}
+
+template<typename T>
+static T sub_sat_u(T a, T b) {
+ static_assert(std::is_unsigned<T>::value, "Trying to instantiate sub_sat_u with signed type");
+ T res = a - b;
+ // overflow if result is greater than a
+ return (res > a) ? 0 : res;
+}
+
+Literal Literal::addSatSI8(const Literal& other) const {
+ return Literal(add_sat_s<int8_t>(geti32(), other.geti32()));
+}
+Literal Literal::addSatUI8(const Literal& other) const {
+ return Literal(add_sat_u<uint8_t>(geti32(), other.geti32()));
+}
+Literal Literal::addSatSI16(const Literal& other) const {
+ return Literal(add_sat_s<int16_t>(geti32(), other.geti32()));
+}
+Literal Literal::addSatUI16(const Literal& other) const {
+ return Literal(add_sat_u<uint16_t>(geti32(), other.geti32()));
+}
+Literal Literal::subSatSI8(const Literal& other) const {
+ return Literal(sub_sat_s<int8_t>(geti32(), other.geti32()));
+}
+Literal Literal::subSatUI8(const Literal& other) const {
+ return Literal(sub_sat_u<uint8_t>(geti32(), other.geti32()));
+}
+Literal Literal::subSatSI16(const Literal& other) const {
+ return Literal(sub_sat_s<int16_t>(geti32(), other.geti32()));
+}
+Literal Literal::subSatUI16(const Literal& other) const {
+ return Literal(sub_sat_u<uint16_t>(geti32(), other.geti32()));
+}
+
Literal Literal::mul(const Literal& other) const {
switch (type) {
case Type::i32: return Literal(uint32_t(i32) * uint32_t(other.i32));
@@ -784,4 +918,538 @@ Literal Literal::copysign(const Literal& other) const {
}
}
+template<typename LaneT, int Lanes>
+static LaneArray<Lanes> getLanes(const Literal& val) {
+ assert(val.type == Type::v128);
+ const size_t lane_width = 16 / Lanes;
+ std::array<uint8_t, 16> bytes = val.getv128();
+ LaneArray<Lanes> lanes;
+ for (size_t lane_idx = 0; lane_idx < Lanes; ++lane_idx) {
+ LaneT lane(0);
+ for (size_t offset = 0; offset < lane_width; ++offset) {
+ lane |= LaneT(bytes.at(lane_idx * lane_width + offset)) << LaneT(8 * offset);
+ }
+ lanes.at(lane_idx) = Literal(lane);
+ }
+ return lanes;
+}
+
+LaneArray<16> Literal::getLanesSI8x16() const {
+ return getLanes<int8_t, 16>(*this);
+}
+LaneArray<16> Literal::getLanesUI8x16() const {
+ return getLanes<uint8_t, 16>(*this);
+}
+LaneArray<8> Literal::getLanesSI16x8() const {
+ return getLanes<int16_t, 8>(*this);
+}
+LaneArray<8> Literal::getLanesUI16x8() const {
+ return getLanes<uint16_t, 8>(*this);
+}
+LaneArray<4> Literal::getLanesI32x4() const {
+ return getLanes<int32_t, 4>(*this);
+}
+LaneArray<2> Literal::getLanesI64x2() const {
+ return getLanes<int64_t, 2>(*this);
+}
+LaneArray<4> Literal::getLanesF32x4() const {
+ auto lanes = getLanesI32x4();
+ for (size_t i = 0; i < lanes.size(); ++i) {
+ lanes[i] = lanes[i].castToF32();
+ }
+ return lanes;
+}
+LaneArray<2> Literal::getLanesF64x2() const {
+ auto lanes = getLanesI64x2();
+ for (size_t i = 0; i < lanes.size(); ++i) {
+ lanes[i] = lanes[i].castToF64();
+ }
+ return lanes;
+}
+
+Literal Literal::shuffleV8x16(const Literal& other, const std::array<uint8_t, 16>& mask) const {
+ assert(type == Type::v128);
+ uint8_t bytes[16];
+ for (size_t i = 0; i < mask.size(); ++i) {
+ bytes[i] = (mask[i] < 16) ? v128[mask[i]] : other.v128[mask[i] - 16];
+ }
+ return Literal(bytes);
+}
+
+template<Type Ty, int Lanes>
+static Literal splat(const Literal& val) {
+ assert(val.type == Ty);
+ LaneArray<Lanes> lanes;
+ lanes.fill(val);
+ return Literal(lanes);
+}
+
+Literal Literal::splatI8x16() const { return splat<Type::i32, 16>(*this); }
+Literal Literal::splatI16x8() const { return splat<Type::i32, 8>(*this); }
+Literal Literal::splatI32x4() const { return splat<Type::i32, 4>(*this); }
+Literal Literal::splatI64x2() const { return splat<Type::i64, 2>(*this); }
+Literal Literal::splatF32x4() const { return splat<Type::f32, 4>(*this); }
+Literal Literal::splatF64x2() const { return splat<Type::f64, 2>(*this); }
+
+Literal Literal::extractLaneSI8x16(uint8_t idx) const { return getLanesSI8x16().at(idx); }
+Literal Literal::extractLaneUI8x16(uint8_t idx) const { return getLanesUI8x16().at(idx); }
+Literal Literal::extractLaneSI16x8(uint8_t idx) const { return getLanesSI16x8().at(idx); }
+Literal Literal::extractLaneUI16x8(uint8_t idx) const { return getLanesUI16x8().at(idx); }
+Literal Literal::extractLaneI32x4(uint8_t idx) const { return getLanesI32x4().at(idx); }
+Literal Literal::extractLaneI64x2(uint8_t idx) const { return getLanesI64x2().at(idx); }
+Literal Literal::extractLaneF32x4(uint8_t idx) const { return getLanesF32x4().at(idx); }
+Literal Literal::extractLaneF64x2(uint8_t idx) const { return getLanesF64x2().at(idx); }
+
+template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const>
+static Literal replace(const Literal& val, const Literal& other, uint8_t idx) {
+ LaneArray<Lanes> lanes = (val.*IntoLanes)();
+ lanes.at(idx) = other;
+ auto ret = Literal(lanes);
+ return ret;
+}
+
+Literal Literal::replaceLaneI8x16(const Literal& other, uint8_t idx) const {
+ return replace<16, &Literal::getLanesUI8x16>(*this, other, idx);
+}
+Literal Literal::replaceLaneI16x8(const Literal& other, uint8_t idx) const {
+ return replace<8, &Literal::getLanesUI16x8>(*this, other, idx);
+}
+Literal Literal::replaceLaneI32x4(const Literal& other, uint8_t idx) const {
+ return replace<4, &Literal::getLanesI32x4>(*this, other, idx);
+}
+Literal Literal::replaceLaneI64x2(const Literal& other, uint8_t idx) const {
+ return replace<2, &Literal::getLanesI64x2>(*this, other, idx);
+}
+Literal Literal::replaceLaneF32x4(const Literal& other, uint8_t idx) const {
+ return replace<4, &Literal::getLanesF32x4>(*this, other, idx);
+}
+Literal Literal::replaceLaneF64x2(const Literal& other, uint8_t idx) const {
+ return replace<2, &Literal::getLanesF64x2>(*this, other, idx);
+}
+
+template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const,
+ Literal (Literal::*UnaryOp)(void) const>
+static Literal unary(const Literal& val) {
+ LaneArray<Lanes> lanes = (val.*IntoLanes)();
+ for (size_t i = 0; i < Lanes; ++i) {
+ lanes[i] = (lanes[i].*UnaryOp)();
+ }
+ return Literal(lanes);
+}
+
+Literal Literal::notV128() const {
+ std::array<uint8_t, 16> ones;
+ ones.fill(0xff);
+ return xorV128(Literal(ones.data()));
+}
+Literal Literal::negI8x16() const {
+ return unary<16, &Literal::getLanesUI8x16, &Literal::neg>(*this);
+}
+Literal Literal::negI16x8() const {
+ return unary<8, &Literal::getLanesUI16x8, &Literal::neg>(*this);
+}
+Literal Literal::negI32x4() const {
+ return unary<4, &Literal::getLanesI32x4, &Literal::neg>(*this);
+}
+Literal Literal::negI64x2() const {
+ return unary<2, &Literal::getLanesI64x2, &Literal::neg>(*this);
+}
+Literal Literal::absF32x4() const {
+ return unary<4, &Literal::getLanesF32x4, &Literal::abs>(*this);
+}
+Literal Literal::negF32x4() const {
+ return unary<4, &Literal::getLanesF32x4, &Literal::neg>(*this);
+}
+Literal Literal::sqrtF32x4() const {
+ return unary<4, &Literal::getLanesF32x4, &Literal::sqrt>(*this);
+}
+Literal Literal::absF64x2() const {
+ return unary<2, &Literal::getLanesF64x2, &Literal::abs>(*this);
+}
+Literal Literal::negF64x2() const {
+ return unary<2, &Literal::getLanesF64x2, &Literal::neg>(*this);
+}
+Literal Literal::sqrtF64x2() const {
+ return unary<2, &Literal::getLanesF64x2, &Literal::sqrt>(*this);
+}
+Literal Literal::truncSatToSI32x4() const {
+ return unary<4, &Literal::getLanesF32x4, &Literal::truncSatToSI32>(*this);
+}
+Literal Literal::truncSatToUI32x4() const {
+ return unary<4, &Literal::getLanesF32x4, &Literal::truncSatToUI32>(*this);
+}
+Literal Literal::truncSatToSI64x2() const {
+ return unary<2, &Literal::getLanesF64x2, &Literal::truncSatToSI64>(*this);
+}
+Literal Literal::truncSatToUI64x2() const {
+ return unary<2, &Literal::getLanesF64x2, &Literal::truncSatToUI64>(*this);
+}
+Literal Literal::convertSToF32x4() const {
+ return unary<4, &Literal::getLanesI32x4, &Literal::convertSIToF32>(*this);
+}
+Literal Literal::convertUToF32x4() const {
+ return unary<4, &Literal::getLanesI32x4, &Literal::convertUIToF32>(*this);
+}
+Literal Literal::convertSToF64x2() const {
+ return unary<2, &Literal::getLanesI64x2, &Literal::convertSIToF64>(*this);
+}
+Literal Literal::convertUToF64x2() const {
+ return unary<2, &Literal::getLanesI64x2, &Literal::convertUIToF64>(*this);
+}
+
+template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const>
+static Literal any_true(const Literal& val) {
+ LaneArray<Lanes> lanes = (val.*IntoLanes)();
+ for (size_t i = 0; i < Lanes; ++i) {
+ if (lanes[i] != Literal::makeZero(lanes[i].type)) {
+ return Literal(int32_t(1));
+ }
+ }
+ return Literal(int32_t(0));
+}
+
+template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const>
+static Literal all_true(const Literal& val) {
+ LaneArray<Lanes> lanes = (val.*IntoLanes)();
+ for (size_t i = 0; i < Lanes; ++i) {
+ if (lanes[i] == Literal::makeZero(lanes[i].type)) {
+ return Literal(int32_t(0));
+ }
+ }
+ return Literal(int32_t(1));
+}
+
+Literal Literal::anyTrueI8x16() const {
+ return any_true<16, &Literal::getLanesUI8x16>(*this);
+}
+Literal Literal::allTrueI8x16() const {
+ return all_true<16, &Literal::getLanesUI8x16>(*this);
+}
+Literal Literal::anyTrueI16x8() const {
+ return any_true<8, &Literal::getLanesUI16x8>(*this);
+}
+Literal Literal::allTrueI16x8() const {
+ return all_true<8, &Literal::getLanesUI16x8>(*this);
+}
+Literal Literal::anyTrueI32x4() const {
+ return any_true<4, &Literal::getLanesI32x4>(*this);
+}
+Literal Literal::allTrueI32x4() const {
+ return all_true<4, &Literal::getLanesI32x4>(*this);
+}
+Literal Literal::anyTrueI64x2() const {
+ return any_true<2, &Literal::getLanesI64x2>(*this);
+}
+Literal Literal::allTrueI64x2() const {
+ return all_true<2, &Literal::getLanesI64x2>(*this);
+}
+
+template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const,
+ Literal (Literal::*ShiftOp)(const Literal&) const>
+static Literal shift(const Literal& vec, const Literal& shift) {
+ assert(shift.type == Type::i32);
+ size_t lane_bits = 128 / Lanes;
+ LaneArray<Lanes> lanes = (vec.*IntoLanes)();
+ for (size_t i = 0; i < Lanes; ++i) {
+ lanes[i] = (lanes[i].*ShiftOp)(Literal(int32_t(shift.geti32() % lane_bits)));
+ }
+ return Literal(lanes);
+}
+
+Literal Literal::shlI8x16(const Literal& other) const {
+ return shift<16, &Literal::getLanesUI8x16, &Literal::shl>(*this, other);
+}
+Literal Literal::shrSI8x16(const Literal& other) const {
+ return shift<16, &Literal::getLanesSI8x16, &Literal::shrS>(*this, other);
+}
+Literal Literal::shrUI8x16(const Literal& other) const {
+ return shift<16, &Literal::getLanesUI8x16, &Literal::shrU>(*this, other);
+}
+Literal Literal::shlI16x8(const Literal& other) const {
+ return shift<8, &Literal::getLanesUI16x8, &Literal::shl>(*this, other);
+}
+Literal Literal::shrSI16x8(const Literal& other) const {
+ return shift<8, &Literal::getLanesSI16x8, &Literal::shrS>(*this, other);
+}
+Literal Literal::shrUI16x8(const Literal& other) const {
+ return shift<8, &Literal::getLanesUI16x8, &Literal::shrU>(*this, other);
+}
+Literal Literal::shlI32x4(const Literal& other) const {
+ return shift<4, &Literal::getLanesI32x4, &Literal::shl>(*this, other);
+}
+Literal Literal::shrSI32x4(const Literal& other) const {
+ return shift<4, &Literal::getLanesI32x4, &Literal::shrS>(*this, other);
+}
+Literal Literal::shrUI32x4(const Literal& other) const {
+ return shift<4, &Literal::getLanesI32x4, &Literal::shrU>(*this, other);
+}
+Literal Literal::shlI64x2(const Literal& other) const {
+ return shift<2, &Literal::getLanesI64x2, &Literal::shl>(*this, other);
+}
+Literal Literal::shrSI64x2(const Literal& other) const {
+ return shift<2, &Literal::getLanesI64x2, &Literal::shrS>(*this, other);
+}
+Literal Literal::shrUI64x2(const Literal& other) const {
+ return shift<2, &Literal::getLanesI64x2, &Literal::shrU>(*this, other);
+}
+
+template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const,
+ Literal (Literal::*CompareOp)(const Literal&) const,
+ typename LaneT = int32_t>
+static Literal compare(const Literal& val, const Literal& other) {
+ LaneArray<Lanes> lanes = (val.*IntoLanes)();
+ LaneArray<Lanes> other_lanes = (other.*IntoLanes)();
+ for (size_t i = 0; i < Lanes; ++i) {
+ lanes[i] = (lanes[i].*CompareOp)(other_lanes[i]) == Literal(int32_t(1))
+ ? Literal(LaneT(-1))
+ : Literal(LaneT(0));
+ }
+ return Literal(lanes);
+}
+
+Literal Literal::eqI8x16(const Literal& other) const {
+ return compare<16, &Literal::getLanesUI8x16, &Literal::eq>(*this, other);
+}
+Literal Literal::neI8x16(const Literal& other) const {
+ return compare<16, &Literal::getLanesUI8x16, &Literal::ne>(*this, other);
+}
+Literal Literal::ltSI8x16(const Literal& other) const {
+ return compare<16, &Literal::getLanesSI8x16, &Literal::ltS>(*this, other);
+}
+Literal Literal::ltUI8x16(const Literal& other) const {
+ return compare<16, &Literal::getLanesUI8x16, &Literal::ltU>(*this, other);
+}
+Literal Literal::gtSI8x16(const Literal& other) const {
+ return compare<16, &Literal::getLanesSI8x16, &Literal::gtS>(*this, other);
+}
+Literal Literal::gtUI8x16(const Literal& other) const {
+ return compare<16, &Literal::getLanesUI8x16, &Literal::gtU>(*this, other);
+}
+Literal Literal::leSI8x16(const Literal& other) const {
+ return compare<16, &Literal::getLanesSI8x16, &Literal::leS>(*this, other);
+}
+Literal Literal::leUI8x16(const Literal& other) const {
+ return compare<16, &Literal::getLanesUI8x16, &Literal::leU>(*this, other);
+}
+Literal Literal::geSI8x16(const Literal& other) const {
+ return compare<16, &Literal::getLanesSI8x16, &Literal::geS>(*this, other);
+}
+Literal Literal::geUI8x16(const Literal& other) const {
+ return compare<16, &Literal::getLanesUI8x16, &Literal::geU>(*this, other);
+}
+Literal Literal::eqI16x8(const Literal& other) const {
+ return compare<8, &Literal::getLanesUI16x8, &Literal::eq>(*this, other);
+}
+Literal Literal::neI16x8(const Literal& other) const {
+ return compare<8, &Literal::getLanesUI16x8, &Literal::ne>(*this, other);
+}
+Literal Literal::ltSI16x8(const Literal& other) const {
+ return compare<8, &Literal::getLanesSI16x8, &Literal::ltS>(*this, other);
+}
+Literal Literal::ltUI16x8(const Literal& other) const {
+ return compare<8, &Literal::getLanesUI16x8, &Literal::ltU>(*this, other);
+}
+Literal Literal::gtSI16x8(const Literal& other) const {
+ return compare<8, &Literal::getLanesSI16x8, &Literal::gtS>(*this, other);
+}
+Literal Literal::gtUI16x8(const Literal& other) const {
+ return compare<8, &Literal::getLanesUI16x8, &Literal::gtU>(*this, other);
+}
+Literal Literal::leSI16x8(const Literal& other) const {
+ return compare<8, &Literal::getLanesSI16x8, &Literal::leS>(*this, other);
+}
+Literal Literal::leUI16x8(const Literal& other) const {
+ return compare<8, &Literal::getLanesUI16x8, &Literal::leU>(*this, other);
+}
+Literal Literal::geSI16x8(const Literal& other) const {
+ return compare<8, &Literal::getLanesSI16x8, &Literal::geS>(*this, other);
+}
+Literal Literal::geUI16x8(const Literal& other) const {
+ return compare<8, &Literal::getLanesUI16x8, &Literal::geU>(*this, other);
+}
+Literal Literal::eqI32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesI32x4, &Literal::eq>(*this, other);
+}
+Literal Literal::neI32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesI32x4, &Literal::ne>(*this, other);
+}
+Literal Literal::ltSI32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesI32x4, &Literal::ltS>(*this, other);
+}
+Literal Literal::ltUI32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesI32x4, &Literal::ltU>(*this, other);
+}
+Literal Literal::gtSI32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesI32x4, &Literal::gtS>(*this, other);
+}
+Literal Literal::gtUI32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesI32x4, &Literal::gtU>(*this, other);
+}
+Literal Literal::leSI32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesI32x4, &Literal::leS>(*this, other);
+}
+Literal Literal::leUI32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesI32x4, &Literal::leU>(*this, other);
+}
+Literal Literal::geSI32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesI32x4, &Literal::geS>(*this, other);
+}
+Literal Literal::geUI32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesI32x4, &Literal::geU>(*this, other);
+}
+Literal Literal::eqF32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesF32x4, &Literal::eq>(*this, other);
+}
+Literal Literal::neF32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesF32x4, &Literal::ne>(*this, other);
+}
+Literal Literal::ltF32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesF32x4, &Literal::lt>(*this, other);
+}
+Literal Literal::gtF32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesF32x4, &Literal::gt>(*this, other);
+}
+Literal Literal::leF32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesF32x4, &Literal::le>(*this, other);
+}
+Literal Literal::geF32x4(const Literal& other) const {
+ return compare<4, &Literal::getLanesF32x4, &Literal::ge>(*this, other);
+}
+Literal Literal::eqF64x2(const Literal& other) const {
+ return compare<2, &Literal::getLanesF64x2, &Literal::eq, int64_t>(*this, other);
+}
+Literal Literal::neF64x2(const Literal& other) const {
+ return compare<2, &Literal::getLanesF64x2, &Literal::ne, int64_t>(*this, other);
+}
+Literal Literal::ltF64x2(const Literal& other) const {
+ return compare<2, &Literal::getLanesF64x2, &Literal::lt, int64_t>(*this, other);
+}
+Literal Literal::gtF64x2(const Literal& other) const {
+ return compare<2, &Literal::getLanesF64x2, &Literal::gt, int64_t>(*this, other);
+}
+Literal Literal::leF64x2(const Literal& other) const {
+ return compare<2, &Literal::getLanesF64x2, &Literal::le, int64_t>(*this, other);
+}
+Literal Literal::geF64x2(const Literal& other) const {
+ return compare<2, &Literal::getLanesF64x2, &Literal::ge, int64_t>(*this, other);
+}
+
+template<int Lanes, LaneArray<Lanes> (Literal::*IntoLanes)() const,
+ Literal (Literal::*BinaryOp)(const Literal&) const>
+static Literal binary(const Literal& val, const Literal& other) {
+ LaneArray<Lanes> lanes = (val.*IntoLanes)();
+ LaneArray<Lanes> other_lanes = (other.*IntoLanes)();
+ for (size_t i = 0; i < Lanes; ++i) {
+ lanes[i] = (lanes[i].*BinaryOp)(other_lanes[i]);
+ }
+ return Literal(lanes);
+}
+
+Literal Literal::andV128(const Literal& other) const {
+ return binary<4, &Literal::getLanesI32x4, &Literal::and_>(*this, other);
+}
+Literal Literal::orV128(const Literal& other) const {
+ return binary<4, &Literal::getLanesI32x4, &Literal::or_>(*this, other);
+}
+Literal Literal::xorV128(const Literal& other) const {
+ return binary<4, &Literal::getLanesI32x4, &Literal::xor_>(*this, other);
+}
+Literal Literal::addI8x16(const Literal& other) const {
+ return binary<16, &Literal::getLanesUI8x16, &Literal::add>(*this, other);
+}
+Literal Literal::addSaturateSI8x16(const Literal& other) const {
+ return binary<16, &Literal::getLanesUI8x16, &Literal::addSatSI8>(*this, other);
+}
+Literal Literal::addSaturateUI8x16(const Literal& other) const {
+ return binary<16, &Literal::getLanesSI8x16, &Literal::addSatUI8>(*this, other);
+}
+Literal Literal::subI8x16(const Literal& other) const {
+ return binary<16, &Literal::getLanesUI8x16, &Literal::sub>(*this, other);
+}
+Literal Literal::subSaturateSI8x16(const Literal& other) const {
+ return binary<16, &Literal::getLanesUI8x16, &Literal::subSatSI8>(*this, other);
+}
+Literal Literal::subSaturateUI8x16(const Literal& other) const {
+ return binary<16, &Literal::getLanesSI8x16, &Literal::subSatUI8>(*this, other);
+}
+Literal Literal::mulI8x16(const Literal& other) const {
+ return binary<16, &Literal::getLanesUI8x16, &Literal::mul>(*this, other);
+}
+Literal Literal::addI16x8(const Literal& other) const {
+ return binary<8, &Literal::getLanesUI16x8, &Literal::add>(*this, other);
+}
+Literal Literal::addSaturateSI16x8(const Literal& other) const {
+ return binary<8, &Literal::getLanesUI16x8, &Literal::addSatSI16>(*this, other);
+}
+Literal Literal::addSaturateUI16x8(const Literal& other) const {
+ return binary<8, &Literal::getLanesSI16x8, &Literal::addSatUI16>(*this, other);
+}
+Literal Literal::subI16x8(const Literal& other) const {
+ return binary<8, &Literal::getLanesUI16x8, &Literal::sub>(*this, other);
+}
+Literal Literal::subSaturateSI16x8(const Literal& other) const {
+ return binary<8, &Literal::getLanesUI16x8, &Literal::subSatSI16>(*this, other);
+}
+Literal Literal::subSaturateUI16x8(const Literal& other) const {
+ return binary<8, &Literal::getLanesSI16x8, &Literal::subSatUI16>(*this, other);
+}
+Literal Literal::mulI16x8(const Literal& other) const {
+ return binary<8, &Literal::getLanesUI16x8, &Literal::mul>(*this, other);
+}
+Literal Literal::addI32x4(const Literal& other) const {
+ return binary<4, &Literal::getLanesI32x4, &Literal::add>(*this, other);
+}
+Literal Literal::subI32x4(const Literal& other) const {
+ return binary<4, &Literal::getLanesI32x4, &Literal::sub>(*this, other);
+}
+Literal Literal::mulI32x4(const Literal& other) const {
+ return binary<4, &Literal::getLanesI32x4, &Literal::mul>(*this, other);
+}
+Literal Literal::addI64x2(const Literal& other) const {
+ return binary<2, &Literal::getLanesI64x2, &Literal::add>(*this, other);
+}
+Literal Literal::subI64x2(const Literal& other) const {
+ return binary<2, &Literal::getLanesI64x2, &Literal::sub>(*this, other);
+}
+Literal Literal::addF32x4(const Literal& other) const {
+ return binary<4, &Literal::getLanesF32x4, &Literal::add>(*this, other);
+}
+Literal Literal::subF32x4(const Literal& other) const {
+ return binary<4, &Literal::getLanesF32x4, &Literal::sub>(*this, other);
+}
+Literal Literal::mulF32x4(const Literal& other) const {
+ return binary<4, &Literal::getLanesF32x4, &Literal::mul>(*this, other);
+}
+Literal Literal::divF32x4(const Literal& other) const {
+ return binary<4, &Literal::getLanesF32x4, &Literal::div>(*this, other);
+}
+Literal Literal::minF32x4(const Literal& other) const {
+ return binary<4, &Literal::getLanesF32x4, &Literal::min>(*this, other);
+}
+Literal Literal::maxF32x4(const Literal& other) const {
+ return binary<4, &Literal::getLanesF32x4, &Literal::max>(*this, other);
+}
+Literal Literal::addF64x2(const Literal& other) const {
+ return binary<2, &Literal::getLanesF64x2, &Literal::add>(*this, other);
+}
+Literal Literal::subF64x2(const Literal& other) const {
+ return binary<2, &Literal::getLanesF64x2, &Literal::sub>(*this, other);
+}
+Literal Literal::mulF64x2(const Literal& other) const {
+ return binary<2, &Literal::getLanesF64x2, &Literal::mul>(*this, other);
+}
+Literal Literal::divF64x2(const Literal& other) const {
+ return binary<2, &Literal::getLanesF64x2, &Literal::div>(*this, other);
+}
+Literal Literal::minF64x2(const Literal& other) const {
+ return binary<2, &Literal::getLanesF64x2, &Literal::min>(*this, other);
+}
+Literal Literal::maxF64x2(const Literal& other) const {
+ return binary<2, &Literal::getLanesF64x2, &Literal::max>(*this, other);
+}
+
+Literal Literal::bitselectV128(const Literal& left, const Literal& right) const {
+ return andV128(left).orV128(notV128().andV128(right));
+}
+
} // namespace wasm