blob: 5ad53f237cd15df9be5454d570eaaa5c7d90b097 [file] [log] [blame]
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/asmjs/asm-types.h"
#include <cinttypes>
#include "src/init/v8.h"
#include "src/utils/utils.h"
namespace v8 {
namespace internal {
namespace wasm {
AsmCallableType* AsmType::AsCallableType() {
if (AsValueType() != nullptr) {
return nullptr;
}
return reinterpret_cast<AsmCallableType*>(this);
}
std::string AsmType::Name() {
AsmValueType* avt = this->AsValueType();
if (avt != nullptr) {
switch (avt->Bitset()) {
#define RETURN_TYPE_NAME(CamelName, string_name, number, parent_types) \
case AsmValueType::kAsm##CamelName: \
return string_name;
FOR_EACH_ASM_VALUE_TYPE_LIST(RETURN_TYPE_NAME)
#undef RETURN_TYPE_NAME
default:
UNREACHABLE();
}
}
return this->AsCallableType()->Name();
}
bool AsmType::IsExactly(AsmType* x, AsmType* y) {
// TODO(jpp): maybe this can become x == y.
if (x == nullptr) return y == nullptr;
AsmValueType* avt = x->AsValueType();
if (avt != nullptr) {
AsmValueType* tavt = y->AsValueType();
if (tavt == nullptr) {
return false;
}
return avt->Bitset() == tavt->Bitset();
}
// TODO(jpp): is it useful to allow non-value types to be tested with
// IsExactly?
return x == y;
}
bool AsmType::IsA(AsmType* that) {
// IsA is used for querying inheritance relationships. Therefore it is only
// meaningful for basic types.
if (auto* avt = this->AsValueType()) {
if (auto* tavt = that->AsValueType()) {
return (avt->Bitset() & tavt->Bitset()) == tavt->Bitset();
}
return false;
}
if (auto* as_callable = this->AsCallableType()) {
return as_callable->IsA(that);
}
UNREACHABLE();
}
int32_t AsmType::ElementSizeInBytes() {
auto* value = AsValueType();
if (value == nullptr) {
return AsmType::kNotHeapType;
}
switch (value->Bitset()) {
case AsmValueType::kAsmInt8Array:
case AsmValueType::kAsmUint8Array:
return 1;
case AsmValueType::kAsmInt16Array:
case AsmValueType::kAsmUint16Array:
return 2;
case AsmValueType::kAsmInt32Array:
case AsmValueType::kAsmUint32Array:
case AsmValueType::kAsmFloat32Array:
return 4;
case AsmValueType::kAsmFloat64Array:
return 8;
default:
return AsmType::kNotHeapType;
}
}
AsmType* AsmType::LoadType() {
auto* value = AsValueType();
if (value == nullptr) {
return AsmType::None();
}
switch (value->Bitset()) {
case AsmValueType::kAsmInt8Array:
case AsmValueType::kAsmUint8Array:
case AsmValueType::kAsmInt16Array:
case AsmValueType::kAsmUint16Array:
case AsmValueType::kAsmInt32Array:
case AsmValueType::kAsmUint32Array:
return AsmType::Intish();
case AsmValueType::kAsmFloat32Array:
return AsmType::FloatQ();
case AsmValueType::kAsmFloat64Array:
return AsmType::DoubleQ();
default:
return AsmType::None();
}
}
AsmType* AsmType::StoreType() {
auto* value = AsValueType();
if (value == nullptr) {
return AsmType::None();
}
switch (value->Bitset()) {
case AsmValueType::kAsmInt8Array:
case AsmValueType::kAsmUint8Array:
case AsmValueType::kAsmInt16Array:
case AsmValueType::kAsmUint16Array:
case AsmValueType::kAsmInt32Array:
case AsmValueType::kAsmUint32Array:
return AsmType::Intish();
case AsmValueType::kAsmFloat32Array:
return AsmType::FloatishDoubleQ();
case AsmValueType::kAsmFloat64Array:
return AsmType::FloatQDoubleQ();
default:
return AsmType::None();
}
}
bool AsmCallableType::IsA(AsmType* other) {
return other->AsCallableType() == this;
}
std::string AsmFunctionType::Name() {
std::string ret;
ret += "(";
for (size_t ii = 0; ii < args_.size(); ++ii) {
ret += args_[ii]->Name();
if (ii != args_.size() - 1) {
ret += ", ";
}
}
ret += ") -> ";
ret += return_type_->Name();
return ret;
}
namespace {
class AsmFroundType final : public AsmCallableType {
public:
friend AsmType;
AsmFroundType() : AsmCallableType() {}
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override;
std::string Name() override { return "fround"; }
};
} // namespace
AsmType* AsmType::FroundType(Zone* zone) {
auto* Fround = zone->New<AsmFroundType>();
return reinterpret_cast<AsmType*>(Fround);
}
bool AsmFroundType::CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) {
if (args.size() != 1) {
return false;
}
auto* arg = args[0];
if (!arg->IsA(AsmType::Floatish()) && !arg->IsA(AsmType::DoubleQ()) &&
!arg->IsA(AsmType::Signed()) && !arg->IsA(AsmType::Unsigned())) {
return false;
}
return true;
}
namespace {
class AsmMinMaxType final : public AsmCallableType {
private:
friend AsmType;
friend Zone;
AsmMinMaxType(AsmType* dest, AsmType* src)
: AsmCallableType(), return_type_(dest), arg_(src) {}
bool CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) override {
if (!AsmType::IsExactly(return_type_, return_type)) {
return false;
}
if (args.size() < 2) {
return false;
}
for (size_t ii = 0; ii < args.size(); ++ii) {
if (!args[ii]->IsA(arg_)) {
return false;
}
}
return true;
}
std::string Name() override {
return "(" + arg_->Name() + ", " + arg_->Name() + "...) -> " +
return_type_->Name();
}
AsmType* return_type_;
AsmType* arg_;
};
} // namespace
AsmType* AsmType::MinMaxType(Zone* zone, AsmType* dest, AsmType* src) {
DCHECK_NOT_NULL(dest->AsValueType());
DCHECK_NOT_NULL(src->AsValueType());
auto* MinMax = zone->New<AsmMinMaxType>(dest, src);
return reinterpret_cast<AsmType*>(MinMax);
}
bool AsmFunctionType::IsA(AsmType* other) {
auto* that = other->AsFunctionType();
if (that == nullptr) {
return false;
}
if (!AsmType::IsExactly(return_type_, that->return_type_)) {
return false;
}
if (args_.size() != that->args_.size()) {
return false;
}
for (size_t ii = 0; ii < args_.size(); ++ii) {
if (!AsmType::IsExactly(args_[ii], that->args_[ii])) {
return false;
}
}
return true;
}
bool AsmFunctionType::CanBeInvokedWith(AsmType* return_type,
const ZoneVector<AsmType*>& args) {
if (!AsmType::IsExactly(return_type_, return_type)) {
return false;
}
if (args_.size() != args.size()) {
return false;
}
for (size_t ii = 0; ii < args_.size(); ++ii) {
if (!args[ii]->IsA(args_[ii])) {
return false;
}
}
return true;
}
std::string AsmOverloadedFunctionType::Name() {
std::string ret;
for (size_t ii = 0; ii < overloads_.size(); ++ii) {
if (ii != 0) {
ret += " /\\ ";
}
ret += overloads_[ii]->Name();
}
return ret;
}
bool AsmOverloadedFunctionType::CanBeInvokedWith(
AsmType* return_type, const ZoneVector<AsmType*>& args) {
for (size_t ii = 0; ii < overloads_.size(); ++ii) {
if (overloads_[ii]->AsCallableType()->CanBeInvokedWith(return_type, args)) {
return true;
}
}
return false;
}
void AsmOverloadedFunctionType::AddOverload(AsmType* overload) {
DCHECK_NOT_NULL(overload->AsCallableType());
overloads_.push_back(overload);
}
} // namespace wasm
} // namespace internal
} // namespace v8