blob: c58dbb35c756f7fcc51ff92800717033711aca4d [file] [log] [blame]
/*
* Copyright 2017 WebAssembly Community Group participants
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef wasm_literal_h
#define wasm_literal_h
#include <array>
#include <iostream>
#include "compiler-support.h"
#include "support/hash.h"
#include "support/name.h"
#include "support/small_vector.h"
#include "support/utilities.h"
#include "wasm-type.h"
namespace wasm {
class Literals;
struct ExceptionPackage;
class Literal {
// store only integers, whose bits are deterministic. floats
// can have their signalling bit set, for example.
union {
int32_t i32;
int64_t i64;
uint8_t v128[16];
Name func; // function name for funcref
std::unique_ptr<ExceptionPackage> exn;
};
public:
Type type;
public:
Literal() : v128(), type(Type::none) {}
explicit Literal(Type type) : v128(), type(type) {
assert(type != Type::unreachable);
}
explicit Literal(int32_t init) : i32(init), type(Type::i32) {}
explicit Literal(uint32_t init) : i32(init), type(Type::i32) {}
explicit Literal(int64_t init) : i64(init), type(Type::i64) {}
explicit Literal(uint64_t init) : i64(init), type(Type::i64) {}
explicit Literal(float init)
: i32(bit_cast<int32_t>(init)), type(Type::f32) {}
explicit Literal(double init)
: i64(bit_cast<int64_t>(init)), type(Type::f64) {}
// v128 literal from bytes
explicit Literal(const uint8_t init[16]);
// v128 literal from lane value literals
explicit Literal(const std::array<Literal, 16>&);
explicit Literal(const std::array<Literal, 8>&);
explicit Literal(const std::array<Literal, 4>&);
explicit Literal(const std::array<Literal, 2>&);
explicit Literal(Name func) : func(func), type(Type::funcref) {}
explicit Literal(std::unique_ptr<ExceptionPackage> exn)
: exn(std::move(exn)), type(Type::exnref) {}
Literal(const Literal& other);
Literal& operator=(const Literal& other);
~Literal() {
if (type == Type::exnref) {
exn.~unique_ptr();
}
}
bool isConcrete() const { return type != Type::none; }
bool isNone() const { return type == Type::none; }
static Literal makeFromInt32(int32_t x, Type type) {
switch (type.getSingle()) {
case Type::i32:
return Literal(int32_t(x));
break;
case Type::i64:
return Literal(int64_t(x));
break;
case Type::f32:
return Literal(float(x));
break;
case Type::f64:
return Literal(double(x));
break;
case Type::v128:
return Literal(std::array<Literal, 4>{{Literal(x),
Literal(int32_t(0)),
Literal(int32_t(0)),
Literal(int32_t(0))}});
case Type::funcref:
case Type::externref:
case Type::nullref:
case Type::exnref:
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unexpected type");
}
WASM_UNREACHABLE("unexpected type");
}
static Literals makeZero(Type type);
static Literal makeSingleZero(Type type);
static Literal makeNullref() { return Literal(Type(Type::nullref)); }
static Literal makeFuncref(Name func) { return Literal(func.c_str()); }
static Literal makeExnref(std::unique_ptr<ExceptionPackage> exn) {
return Literal(std::move(exn));
}
Literal castToF32();
Literal castToF64();
Literal castToI32();
Literal castToI64();
int32_t geti32() const {
assert(type == Type::i32);
return i32;
}
int64_t geti64() const {
assert(type == Type::i64);
return i64;
}
float getf32() const {
assert(type == Type::f32);
return bit_cast<float>(i32);
}
double getf64() const {
assert(type == Type::f64);
return bit_cast<double>(i64);
}
std::array<uint8_t, 16> getv128() const;
Name getFunc() const {
assert(type == Type::funcref);
return func;
}
const ExceptionPackage& getExceptionPackage() const {
assert(type == Type::exnref);
return *exn.get();
}
// careful!
int32_t* geti32Ptr() {
assert(type == Type::i32);
return &i32;
}
uint8_t* getv128Ptr() {
assert(type == Type::v128);
return v128;
}
const uint8_t* getv128Ptr() const {
assert(type == Type::v128);
return v128;
}
int32_t reinterpreti32() const {
assert(type == Type::f32);
return i32;
}
int64_t reinterpreti64() const {
assert(type == Type::f64);
return i64;
}
float reinterpretf32() const {
assert(type == Type::i32);
return bit_cast<float>(i32);
}
double reinterpretf64() const {
assert(type == Type::i64);
return bit_cast<double>(i64);
}
int64_t getInteger() const;
double getFloat() const;
void getBits(uint8_t (&buf)[16]) const;
// Equality checks for the type and the bits, so a nan float would
// be compared bitwise (which means that a Literal containing a nan
// would be equal to itself, if the bits are equal).
bool operator==(const Literal& other) const;
bool operator!=(const Literal& other) const;
bool isNaN();
static uint32_t NaNPayload(float f);
static uint64_t NaNPayload(double f);
static float setQuietNaN(float f);
static double setQuietNaN(double f);
static void printFloat(std::ostream& o, float f);
static void printDouble(std::ostream& o, double d);
static void printVec128(std::ostream& o, const std::array<uint8_t, 16>& v);
Literal countLeadingZeroes() const;
Literal countTrailingZeroes() const;
Literal popCount() const;
Literal extendToSI64() const;
Literal extendToUI64() const;
Literal extendToF64() const;
Literal extendS8() const;
Literal extendS16() const;
Literal extendS32() const;
Literal wrapToI32() const;
Literal convertSIToF32() const;
Literal convertUIToF32() const;
Literal convertSIToF64() const;
Literal convertUIToF64() const;
Literal truncSatToSI32() const;
Literal truncSatToSI64() const;
Literal truncSatToUI32() const;
Literal truncSatToUI64() const;
Literal eqz() const;
Literal neg() const;
Literal abs() const;
Literal ceil() const;
Literal floor() const;
Literal trunc() const;
Literal nearbyint() const;
Literal sqrt() const;
Literal demote() const;
Literal add(const Literal& other) const;
Literal sub(const Literal& other) const;
Literal mul(const Literal& other) const;
Literal div(const Literal& other) const;
Literal divS(const Literal& other) const;
Literal divU(const Literal& other) const;
Literal remS(const Literal& other) const;
Literal remU(const Literal& other) const;
Literal and_(const Literal& other) const;
Literal or_(const Literal& other) const;
Literal xor_(const Literal& other) const;
Literal shl(const Literal& other) const;
Literal shrS(const Literal& other) const;
Literal shrU(const Literal& other) const;
Literal rotL(const Literal& other) const;
Literal rotR(const Literal& other) const;
// Note that these functions perform equality checks based
// on the type of the literal, so that (unlike the == operator)
// a float nan would not be identical to itself.
Literal eq(const Literal& other) const;
Literal ne(const Literal& other) const;
Literal ltS(const Literal& other) const;
Literal ltU(const Literal& other) const;
Literal lt(const Literal& other) const;
Literal leS(const Literal& other) const;
Literal leU(const Literal& other) const;
Literal le(const Literal& other) const;
Literal gtS(const Literal& other) const;
Literal gtU(const Literal& other) const;
Literal gt(const Literal& other) const;
Literal geS(const Literal& other) const;
Literal geU(const Literal& other) const;
Literal ge(const Literal& other) const;
Literal min(const Literal& other) const;
Literal max(const Literal& other) const;
Literal pmin(const Literal& other) const;
Literal pmax(const Literal& other) const;
Literal copysign(const Literal& other) const;
std::array<Literal, 16> getLanesSI8x16() const;
std::array<Literal, 16> getLanesUI8x16() const;
std::array<Literal, 8> getLanesSI16x8() const;
std::array<Literal, 8> getLanesUI16x8() const;
std::array<Literal, 4> getLanesI32x4() const;
std::array<Literal, 2> getLanesI64x2() const;
std::array<Literal, 4> getLanesF32x4() const;
std::array<Literal, 2> getLanesF64x2() const;
Literal shuffleV8x16(const Literal& other,
const std::array<uint8_t, 16>& mask) const;
Literal splatI8x16() const;
Literal extractLaneSI8x16(uint8_t index) const;
Literal extractLaneUI8x16(uint8_t index) const;
Literal replaceLaneI8x16(const Literal& other, uint8_t index) const;
Literal splatI16x8() const;
Literal extractLaneSI16x8(uint8_t index) const;
Literal extractLaneUI16x8(uint8_t index) const;
Literal replaceLaneI16x8(const Literal& other, uint8_t index) const;
Literal splatI32x4() const;
Literal extractLaneI32x4(uint8_t index) const;
Literal replaceLaneI32x4(const Literal& other, uint8_t index) const;
Literal splatI64x2() const;
Literal extractLaneI64x2(uint8_t index) const;
Literal replaceLaneI64x2(const Literal& other, uint8_t index) const;
Literal splatF32x4() const;
Literal extractLaneF32x4(uint8_t index) const;
Literal replaceLaneF32x4(const Literal& other, uint8_t index) const;
Literal splatF64x2() const;
Literal extractLaneF64x2(uint8_t index) const;
Literal replaceLaneF64x2(const Literal& other, uint8_t index) const;
Literal eqI8x16(const Literal& other) const;
Literal neI8x16(const Literal& other) const;
Literal ltSI8x16(const Literal& other) const;
Literal ltUI8x16(const Literal& other) const;
Literal gtSI8x16(const Literal& other) const;
Literal gtUI8x16(const Literal& other) const;
Literal leSI8x16(const Literal& other) const;
Literal leUI8x16(const Literal& other) const;
Literal geSI8x16(const Literal& other) const;
Literal geUI8x16(const Literal& other) const;
Literal eqI16x8(const Literal& other) const;
Literal neI16x8(const Literal& other) const;
Literal ltSI16x8(const Literal& other) const;
Literal ltUI16x8(const Literal& other) const;
Literal gtSI16x8(const Literal& other) const;
Literal gtUI16x8(const Literal& other) const;
Literal leSI16x8(const Literal& other) const;
Literal leUI16x8(const Literal& other) const;
Literal geSI16x8(const Literal& other) const;
Literal geUI16x8(const Literal& other) const;
Literal eqI32x4(const Literal& other) const;
Literal neI32x4(const Literal& other) const;
Literal ltSI32x4(const Literal& other) const;
Literal ltUI32x4(const Literal& other) const;
Literal gtSI32x4(const Literal& other) const;
Literal gtUI32x4(const Literal& other) const;
Literal leSI32x4(const Literal& other) const;
Literal leUI32x4(const Literal& other) const;
Literal geSI32x4(const Literal& other) const;
Literal geUI32x4(const Literal& other) const;
Literal eqF32x4(const Literal& other) const;
Literal neF32x4(const Literal& other) const;
Literal ltF32x4(const Literal& other) const;
Literal gtF32x4(const Literal& other) const;
Literal leF32x4(const Literal& other) const;
Literal geF32x4(const Literal& other) const;
Literal eqF64x2(const Literal& other) const;
Literal neF64x2(const Literal& other) const;
Literal ltF64x2(const Literal& other) const;
Literal gtF64x2(const Literal& other) const;
Literal leF64x2(const Literal& other) const;
Literal geF64x2(const Literal& other) const;
Literal notV128() const;
Literal andV128(const Literal& other) const;
Literal orV128(const Literal& other) const;
Literal xorV128(const Literal& other) const;
Literal bitselectV128(const Literal& left, const Literal& right) const;
Literal absI8x16() const;
Literal negI8x16() const;
Literal anyTrueI8x16() const;
Literal allTrueI8x16() const;
Literal bitmaskI8x16() const;
Literal shlI8x16(const Literal& other) const;
Literal shrSI8x16(const Literal& other) const;
Literal shrUI8x16(const Literal& other) const;
Literal addI8x16(const Literal& other) const;
Literal addSaturateSI8x16(const Literal& other) const;
Literal addSaturateUI8x16(const Literal& other) const;
Literal subI8x16(const Literal& other) const;
Literal subSaturateSI8x16(const Literal& other) const;
Literal subSaturateUI8x16(const Literal& other) const;
Literal mulI8x16(const Literal& other) const;
Literal minSI8x16(const Literal& other) const;
Literal minUI8x16(const Literal& other) const;
Literal maxSI8x16(const Literal& other) const;
Literal maxUI8x16(const Literal& other) const;
Literal avgrUI8x16(const Literal& other) const;
Literal absI16x8() const;
Literal negI16x8() const;
Literal anyTrueI16x8() const;
Literal allTrueI16x8() const;
Literal bitmaskI16x8() const;
Literal shlI16x8(const Literal& other) const;
Literal shrSI16x8(const Literal& other) const;
Literal shrUI16x8(const Literal& other) const;
Literal addI16x8(const Literal& other) const;
Literal addSaturateSI16x8(const Literal& other) const;
Literal addSaturateUI16x8(const Literal& other) const;
Literal subI16x8(const Literal& other) const;
Literal subSaturateSI16x8(const Literal& other) const;
Literal subSaturateUI16x8(const Literal& other) const;
Literal mulI16x8(const Literal& other) const;
Literal minSI16x8(const Literal& other) const;
Literal minUI16x8(const Literal& other) const;
Literal maxSI16x8(const Literal& other) const;
Literal maxUI16x8(const Literal& other) const;
Literal avgrUI16x8(const Literal& other) const;
Literal absI32x4() const;
Literal negI32x4() const;
Literal anyTrueI32x4() const;
Literal allTrueI32x4() const;
Literal bitmaskI32x4() const;
Literal shlI32x4(const Literal& other) const;
Literal shrSI32x4(const Literal& other) const;
Literal shrUI32x4(const Literal& other) const;
Literal addI32x4(const Literal& other) const;
Literal subI32x4(const Literal& other) const;
Literal mulI32x4(const Literal& other) const;
Literal minSI32x4(const Literal& other) const;
Literal minUI32x4(const Literal& other) const;
Literal maxSI32x4(const Literal& other) const;
Literal maxUI32x4(const Literal& other) const;
Literal dotSI16x8toI32x4(const Literal& other) const;
Literal negI64x2() const;
Literal anyTrueI64x2() const;
Literal allTrueI64x2() const;
Literal shlI64x2(const Literal& other) const;
Literal shrSI64x2(const Literal& other) const;
Literal shrUI64x2(const Literal& other) const;
Literal addI64x2(const Literal& other) const;
Literal subI64x2(const Literal& other) const;
Literal mulI64x2(const Literal& other) const;
Literal absF32x4() const;
Literal negF32x4() const;
Literal sqrtF32x4() const;
Literal addF32x4(const Literal& other) const;
Literal subF32x4(const Literal& other) const;
Literal mulF32x4(const Literal& other) const;
Literal divF32x4(const Literal& other) const;
Literal minF32x4(const Literal& other) const;
Literal maxF32x4(const Literal& other) const;
Literal pminF32x4(const Literal& other) const;
Literal pmaxF32x4(const Literal& other) const;
Literal ceilF32x4() const;
Literal floorF32x4() const;
Literal truncF32x4() const;
Literal nearestF32x4() const;
Literal absF64x2() const;
Literal negF64x2() const;
Literal sqrtF64x2() const;
Literal addF64x2(const Literal& other) const;
Literal subF64x2(const Literal& other) const;
Literal mulF64x2(const Literal& other) const;
Literal divF64x2(const Literal& other) const;
Literal minF64x2(const Literal& other) const;
Literal maxF64x2(const Literal& other) const;
Literal pminF64x2(const Literal& other) const;
Literal pmaxF64x2(const Literal& other) const;
Literal ceilF64x2() const;
Literal floorF64x2() const;
Literal truncF64x2() const;
Literal nearestF64x2() const;
Literal truncSatToSI32x4() const;
Literal truncSatToUI32x4() const;
Literal truncSatToSI64x2() const;
Literal truncSatToUI64x2() const;
Literal convertSToF32x4() const;
Literal convertUToF32x4() const;
Literal convertSToF64x2() const;
Literal convertUToF64x2() const;
Literal narrowSToVecI8x16(const Literal& other) const;
Literal narrowUToVecI8x16(const Literal& other) const;
Literal narrowSToVecI16x8(const Literal& other) const;
Literal narrowUToVecI16x8(const Literal& other) const;
Literal widenLowSToVecI16x8() const;
Literal widenHighSToVecI16x8() const;
Literal widenLowUToVecI16x8() const;
Literal widenHighUToVecI16x8() const;
Literal widenLowSToVecI32x4() const;
Literal widenHighSToVecI32x4() const;
Literal widenLowUToVecI32x4() const;
Literal widenHighUToVecI32x4() const;
Literal swizzleVec8x16(const Literal& other) const;
private:
Literal addSatSI8(const Literal& other) const;
Literal addSatUI8(const Literal& other) const;
Literal addSatSI16(const Literal& other) const;
Literal addSatUI16(const Literal& other) const;
Literal subSatSI8(const Literal& other) const;
Literal subSatUI8(const Literal& other) const;
Literal subSatSI16(const Literal& other) const;
Literal subSatUI16(const Literal& other) const;
Literal minInt(const Literal& other) const;
Literal maxInt(const Literal& other) const;
Literal minUInt(const Literal& other) const;
Literal maxUInt(const Literal& other) const;
Literal avgrUInt(const Literal& other) const;
};
class Literals : public SmallVector<Literal, 1> {
public:
Literals() = default;
Literals(std::initializer_list<Literal> init)
: SmallVector<Literal, 1>(init) {
#ifndef NDEBUG
for (auto& lit : init) {
assert(lit.isConcrete());
}
#endif
};
Type getType() {
std::vector<Type> types;
for (auto& val : *this) {
types.push_back(val.type);
}
return Type(types);
}
bool isNone() { return size() == 0; }
bool isConcrete() { return size() != 0; }
};
// A struct for a thrown exception, which includes a tag (event) and thrown
// values
struct ExceptionPackage {
Name event;
Literals values;
};
std::ostream& operator<<(std::ostream& o, wasm::Literal literal);
std::ostream& operator<<(std::ostream& o, wasm::Literals literals);
std::ostream& operator<<(std::ostream& o, const ExceptionPackage& exn);
} // namespace wasm
namespace std {
template<> struct hash<wasm::Literal> {
size_t operator()(const wasm::Literal& a) const {
uint8_t bytes[16];
a.getBits(bytes);
int64_t chunks[2];
memcpy(chunks, bytes, sizeof(chunks));
auto digest = wasm::hash(a.type.getID());
wasm::rehash(digest, chunks[0]);
wasm::rehash(digest, chunks[1]);
return digest;
}
};
template<> struct hash<wasm::Literals> {
size_t operator()(const wasm::Literals& a) const {
auto digest = wasm::hash(a.size());
for (const auto& lit : a) {
wasm::rehash(digest, lit);
}
return digest;
}
};
template<> struct less<wasm::Literal> {
bool operator()(const wasm::Literal& a, const wasm::Literal& b) const {
if (a.type < b.type) {
return true;
}
if (b.type < a.type) {
return false;
}
switch (a.type.getSingle()) {
case wasm::Type::i32:
return a.geti32() < b.geti32();
case wasm::Type::f32:
return a.reinterpreti32() < b.reinterpreti32();
case wasm::Type::i64:
return a.geti64() < b.geti64();
case wasm::Type::f64:
return a.reinterpreti64() < b.reinterpreti64();
case wasm::Type::v128:
return memcmp(a.getv128Ptr(), b.getv128Ptr(), 16) < 0;
case wasm::Type::funcref:
case wasm::Type::externref:
case wasm::Type::nullref:
case wasm::Type::exnref:
case wasm::Type::none:
case wasm::Type::unreachable:
return false;
}
WASM_UNREACHABLE("unexpected type");
}
};
} // namespace std
#endif // wasm_literal_h