blob: 8e6d32ab561cf9a945ba98fee8d9634f8ed54d24 [file] [log] [blame]
// Copyright (c) 2016 Google Inc.
//
// 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.
#include <algorithm>
#include <cassert>
#include <sstream>
#include "types.h"
namespace spvtools {
namespace opt {
namespace analysis {
using U32VecVec = std::vector<std::vector<uint32_t>>;
namespace {
// Returns true if the two vector of vectors are identical.
bool CompareTwoVectors(const U32VecVec a, const U32VecVec b) {
const auto size = a.size();
if (size != b.size()) return false;
if (size == 0) return true;
if (size == 1) return a.front() == b.front();
std::vector<const std::vector<uint32_t> *> a_ptrs, b_ptrs;
a_ptrs.reserve(size);
a_ptrs.reserve(size);
for (uint32_t i = 0; i < size; ++i) {
a_ptrs.push_back(&a[i]);
b_ptrs.push_back(&b[i]);
}
const auto cmp = [](const std::vector<uint32_t>* m,
const std::vector<uint32_t>* n) {
return m->front() < n->front();
};
std::sort(a_ptrs.begin(), a_ptrs.end(), cmp);
std::sort(b_ptrs.begin(), b_ptrs.end(), cmp);
for (uint32_t i = 0; i < size; ++i) {
if (*a_ptrs[i] != *b_ptrs[i]) return false;
}
return true;
}
} // anonymous namespace
std::string Type::GetDecorationStr() const {
std::ostringstream oss;
oss << "[[";
for (const auto& decoration : decorations_) {
oss << "(";
for (size_t i = 0; i < decoration.size(); ++i) {
oss << (i > 0 ? ", " : "");
oss << decoration.at(i);
}
oss << ")";
}
oss << "]]";
return oss.str();
}
bool Type::HasSameDecorations(const Type* that) const {
return CompareTwoVectors(decorations_, that->decorations_);
}
bool Integer::IsSame(Type* that) const {
const Integer* it = that->AsInteger();
return it && width_ == it->width_ && signed_ == it->signed_ &&
HasSameDecorations(that);
}
std::string Integer::str() const {
std::ostringstream oss;
oss << (signed_ ? "s" : "u") << "int" << width_;
return oss.str();
}
bool Float::IsSame(Type* that) const {
const Float* ft = that->AsFloat();
return ft && width_ == ft->width_ && HasSameDecorations(that);
}
std::string Float::str() const {
std::ostringstream oss;
oss << "float" << width_;
return oss.str();
}
Vector::Vector(Type* type, uint32_t count)
: element_type_(type), count_(count) {
assert(type->AsBool() || type->AsInteger() || type->AsFloat());
}
bool Vector::IsSame(Type* that) const {
const Vector* vt = that->AsVector();
if (!vt) return false;
return count_ == vt->count_ && element_type_->IsSame(vt->element_type_) &&
HasSameDecorations(that);
}
std::string Vector::str() const {
std::ostringstream oss;
oss << "<" << element_type_->str() << ", " << count_ << ">";
return oss.str();
}
Matrix::Matrix(Type* type, uint32_t count)
: element_type_(type), count_(count) {
assert(type->AsVector());
}
bool Matrix::IsSame(Type* that) const {
const Matrix* mt = that->AsMatrix();
if (!mt) return false;
return count_ == mt->count_ && element_type_->IsSame(mt->element_type_) &&
HasSameDecorations(that);
}
std::string Matrix::str() const {
std::ostringstream oss;
oss << "<" << element_type_->str() << ", " << count_ << ">";
return oss.str();
}
Image::Image(Type* sampled_type, SpvDim dim, uint32_t depth, uint32_t arrayed,
uint32_t ms, uint32_t sampled, SpvImageFormat format,
SpvAccessQualifier access_qualifier)
: sampled_type_(sampled_type),
dim_(dim),
depth_(depth),
arrayed_(arrayed),
ms_(ms),
sampled_(sampled),
format_(format),
access_qualifier_(access_qualifier) {
// TODO(antiagainst): check sampled_type
}
bool Image::IsSame(Type* that) const {
const Image* it = that->AsImage();
if (!it) return false;
return dim_ == it->dim_ && depth_ == it->depth_ && arrayed_ == it->arrayed_ &&
ms_ == it->ms_ && sampled_ == it->sampled_ && format_ == it->format_ &&
access_qualifier_ == it->access_qualifier_ &&
sampled_type_->IsSame(it->sampled_type_) && HasSameDecorations(that);
}
std::string Image::str() const {
std::ostringstream oss;
oss << "image(" << sampled_type_->str() << ", " << dim_ << ", " << depth_
<< ", " << arrayed_ << ", " << ms_ << ", " << sampled_ << ", " << format_
<< ", " << access_qualifier_ << ")";
return oss.str();
}
bool SampledImage::IsSame(Type* that) const {
const SampledImage* sit = that->AsSampledImage();
if (!sit) return false;
return image_type_->IsSame(sit->image_type_) && HasSameDecorations(that);
}
std::string SampledImage::str() const {
std::ostringstream oss;
oss << "sampled_image(" << image_type_->str() << ")";
return oss.str();
}
Array::Array(Type* type, uint32_t length_id)
: element_type_(type), length_id_(length_id) {
assert(!type->AsVoid());
}
bool Array::IsSame(Type* that) const {
const Array* at = that->AsArray();
if (!at) return false;
return length_id_ == at->length_id_ &&
element_type_->IsSame(at->element_type_) && HasSameDecorations(that);
}
std::string Array::str() const {
std::ostringstream oss;
oss << "[" << element_type_->str() << ", id(" << length_id_ << ")]";
return oss.str();
}
RuntimeArray::RuntimeArray(Type* type) : element_type_(type) {
assert(!type->AsVoid());
}
bool RuntimeArray::IsSame(Type* that) const {
const RuntimeArray* rat = that->AsRuntimeArray();
if (!rat) return false;
return element_type_->IsSame(rat->element_type_) && HasSameDecorations(that);
}
std::string RuntimeArray::str() const {
std::ostringstream oss;
oss << "[" << element_type_->str() << "]";
return oss.str();
}
Struct::Struct(const std::vector<Type*>& types) : element_types_(types) {
for (auto* t : types) {
(void)t;
assert(!t->AsVoid());
}
}
void Struct::AddMemeberDecoration(uint32_t index,
std::vector<uint32_t>&& decoration) {
if (index >= element_types_.size()) {
assert(0 && "index out of bound");
return;
}
element_decorations_[index].push_back(std::move(decoration));
}
bool Struct::IsSame(Type* that) const {
const Struct* st = that->AsStruct();
if (!st) return false;
if (element_types_.size() != st->element_types_.size()) return false;
const auto size = element_decorations_.size();
if (size != st->element_decorations_.size()) return false;
if (!HasSameDecorations(that)) return false;
for (size_t i = 0; i < element_types_.size(); ++i) {
if (!element_types_[i]->IsSame(st->element_types_[i])) return false;
}
for (const auto& p : element_decorations_) {
if (st->element_decorations_.count(p.first) == 0) return false;
if (!CompareTwoVectors(p.second, st->element_decorations_.at(p.first)))
return false;
}
return true;
}
std::string Struct::str() const {
std::ostringstream oss;
oss << "{";
const size_t count = element_types_.size();
for (size_t i = 0; i < count; ++i) {
oss << element_types_[i]->str();
if (i + 1 != count) oss << ", ";
}
oss << "}";
return oss.str();
}
bool Opaque::IsSame(Type* that) const {
const Opaque* ot = that->AsOpaque();
if (!ot) return false;
return name_ == ot->name_ && HasSameDecorations(that);
}
std::string Opaque::str() const {
std::ostringstream oss;
oss << "opaque('" << name_ << "')";
return oss.str();
}
Pointer::Pointer(Type* type, SpvStorageClass storage_class)
: pointee_type_(type), storage_class_(storage_class) {
assert(!type->AsVoid());
}
bool Pointer::IsSame(Type* that) const {
const Pointer* pt = that->AsPointer();
if (!pt) return false;
if (storage_class_ != pt->storage_class_) return false;
if (!pointee_type_->IsSame(pt->pointee_type_)) return false;
return HasSameDecorations(that);
}
std::string Pointer::str() const { return pointee_type_->str() + "*"; }
Function::Function(Type* return_type, const std::vector<Type*>& param_types)
: return_type_(return_type), param_types_(param_types) {
for (auto* t : param_types) {
(void)t;
assert(!t->AsVoid());
}
}
bool Function::IsSame(Type* that) const {
const Function* ft = that->AsFunction();
if (!ft) return false;
if (!return_type_->IsSame(ft->return_type_)) return false;
if (param_types_.size() != ft->param_types_.size()) return false;
for (size_t i = 0; i < param_types_.size(); ++i) {
if (!param_types_[i]->IsSame(ft->param_types_[i])) return false;
}
return HasSameDecorations(that);
}
std::string Function::str() const {
std::ostringstream oss;
const size_t count = param_types_.size();
oss << "(";
for (size_t i = 0; i < count; ++i) {
oss << param_types_[i]->str();
if (i + 1 != count) oss << ", ";
}
oss << ") -> " << return_type_->str();
return oss.str();
}
bool Pipe::IsSame(Type* that) const {
const Pipe* pt = that->AsPipe();
if (!pt) return false;
return access_qualifier_ == pt->access_qualifier_ && HasSameDecorations(that);
}
std::string Pipe::str() const {
std::ostringstream oss;
oss << "pipe(" << access_qualifier_ << ")";
return oss.str();
}
bool ForwardPointer::IsSame(Type* that) const {
const ForwardPointer* fpt = that->AsForwardPointer();
if (!fpt) return false;
return target_id_ == fpt->target_id_ &&
storage_class_ == fpt->storage_class_ && HasSameDecorations(that);
}
std::string ForwardPointer::str() const {
std::ostringstream oss;
oss << "forward_pointer(";
if (pointer_ != nullptr) {
oss << pointer_->str();
} else {
oss << target_id_;
}
oss << ")";
return oss.str();
}
} // namespace analysis
} // namespace opt
} // namespace spvtools