blob: fd9880680b4c42f94703749e38ecca2795612285 [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 "source/opt/types.h"
#include <memory>
#include <utility>
#include <vector>
#include "gtest/gtest.h"
#include "source/util/make_unique.h"
namespace spvtools {
namespace opt {
namespace analysis {
namespace {
// Fixture class providing some element types.
class SameTypeTest : public ::testing::Test {
protected:
void SetUp() override {
void_t_ = MakeUnique<Void>();
u32_t_ = MakeUnique<Integer>(32, false);
f64_t_ = MakeUnique<Float>(64);
v3u32_t_ = MakeUnique<Vector>(u32_t_.get(), 3);
image_t_ =
MakeUnique<Image>(f64_t_.get(), SpvDim2D, 1, 1, 0, 0, SpvImageFormatR16,
SpvAccessQualifierReadWrite);
}
// Element types to be used for constructing other types for testing.
std::unique_ptr<Type> void_t_;
std::unique_ptr<Type> u32_t_;
std::unique_ptr<Type> f64_t_;
std::unique_ptr<Type> v3u32_t_;
std::unique_ptr<Type> image_t_;
};
#define TestMultipleInstancesOfTheSameTypeQualified(ty, name, ...) \
TEST_F(SameTypeTest, MultiSame##ty##name) { \
std::vector<std::unique_ptr<Type>> types; \
for (int i = 0; i < 10; ++i) types.emplace_back(new ty(__VA_ARGS__)); \
for (size_t i = 0; i < types.size(); ++i) { \
for (size_t j = 0; j < types.size(); ++j) { \
EXPECT_TRUE(types[i]->IsSame(types[j].get())) \
<< "expected '" << types[i]->str() << "' is the same as '" \
<< types[j]->str() << "'"; \
EXPECT_TRUE(*types[i] == *types[j]) \
<< "expected '" << types[i]->str() << "' is the same as '" \
<< types[j]->str() << "'"; \
} \
} \
}
#define TestMultipleInstancesOfTheSameType(ty, ...) \
TestMultipleInstancesOfTheSameTypeQualified(ty, Simple, __VA_ARGS__)
TestMultipleInstancesOfTheSameType(Void);
TestMultipleInstancesOfTheSameType(Bool);
TestMultipleInstancesOfTheSameType(Integer, 32, true);
TestMultipleInstancesOfTheSameType(Float, 64);
TestMultipleInstancesOfTheSameType(Vector, u32_t_.get(), 3);
TestMultipleInstancesOfTheSameType(Matrix, v3u32_t_.get(), 4);
TestMultipleInstancesOfTheSameType(Image, f64_t_.get(), SpvDimCube, 0, 0, 1, 1,
SpvImageFormatRgb10A2,
SpvAccessQualifierWriteOnly);
TestMultipleInstancesOfTheSameType(Sampler);
TestMultipleInstancesOfTheSameType(SampledImage, image_t_.get());
// There are three classes of arrays, based on the kinds of length information
// they have.
// 1. Array length is a constant or spec constant without spec ID, with literals
// for the constant value.
TestMultipleInstancesOfTheSameTypeQualified(Array, LenConstant, u32_t_.get(),
Array::LengthInfo{42,
{
0,
9999,
}});
// 2. Array length is a spec constant with a given spec id.
TestMultipleInstancesOfTheSameTypeQualified(Array, LenSpecId, u32_t_.get(),
Array::LengthInfo{42, {1, 99}});
// 3. Array length is an OpSpecConstantOp expression
TestMultipleInstancesOfTheSameTypeQualified(Array, LenDefiningId, u32_t_.get(),
Array::LengthInfo{42, {2, 42}});
TestMultipleInstancesOfTheSameType(RuntimeArray, u32_t_.get());
TestMultipleInstancesOfTheSameType(Struct, std::vector<const Type*>{
u32_t_.get(), f64_t_.get()});
TestMultipleInstancesOfTheSameType(Opaque, "testing rocks");
TestMultipleInstancesOfTheSameType(Pointer, u32_t_.get(), SpvStorageClassInput);
TestMultipleInstancesOfTheSameType(Function, u32_t_.get(),
{f64_t_.get(), f64_t_.get()});
TestMultipleInstancesOfTheSameType(Event);
TestMultipleInstancesOfTheSameType(DeviceEvent);
TestMultipleInstancesOfTheSameType(ReserveId);
TestMultipleInstancesOfTheSameType(Queue);
TestMultipleInstancesOfTheSameType(Pipe, SpvAccessQualifierReadWrite);
TestMultipleInstancesOfTheSameType(ForwardPointer, 10, SpvStorageClassUniform);
TestMultipleInstancesOfTheSameType(PipeStorage);
TestMultipleInstancesOfTheSameType(NamedBarrier);
TestMultipleInstancesOfTheSameType(AccelerationStructureNV);
#undef TestMultipleInstanceOfTheSameType
#undef TestMultipleInstanceOfTheSameTypeQual
std::vector<std::unique_ptr<Type>> GenerateAllTypes() {
// Types in this test case are only equal to themselves, nothing else.
std::vector<std::unique_ptr<Type>> types;
// Forward Pointer
types.emplace_back(new ForwardPointer(10000, SpvStorageClassInput));
types.emplace_back(new ForwardPointer(20000, SpvStorageClassInput));
// Void, Bool
types.emplace_back(new Void());
auto* voidt = types.back().get();
types.emplace_back(new Bool());
auto* boolt = types.back().get();
// Integer
types.emplace_back(new Integer(32, true));
auto* s32 = types.back().get();
types.emplace_back(new Integer(32, false));
types.emplace_back(new Integer(64, true));
types.emplace_back(new Integer(64, false));
auto* u64 = types.back().get();
// Float
types.emplace_back(new Float(32));
auto* f32 = types.back().get();
types.emplace_back(new Float(64));
// Vector
types.emplace_back(new Vector(s32, 2));
types.emplace_back(new Vector(s32, 3));
auto* v3s32 = types.back().get();
types.emplace_back(new Vector(u64, 4));
types.emplace_back(new Vector(f32, 3));
auto* v3f32 = types.back().get();
// Matrix
types.emplace_back(new Matrix(v3s32, 3));
types.emplace_back(new Matrix(v3s32, 4));
types.emplace_back(new Matrix(v3f32, 4));
// Images
types.emplace_back(new Image(s32, SpvDim2D, 0, 0, 0, 0, SpvImageFormatRg8,
SpvAccessQualifierReadOnly));
auto* image1 = types.back().get();
types.emplace_back(new Image(s32, SpvDim2D, 0, 1, 0, 0, SpvImageFormatRg8,
SpvAccessQualifierReadOnly));
types.emplace_back(new Image(s32, SpvDim3D, 0, 1, 0, 0, SpvImageFormatRg8,
SpvAccessQualifierReadOnly));
types.emplace_back(new Image(voidt, SpvDim3D, 0, 1, 0, 1, SpvImageFormatRg8,
SpvAccessQualifierReadWrite));
auto* image2 = types.back().get();
// Sampler
types.emplace_back(new Sampler());
// Sampled Image
types.emplace_back(new SampledImage(image1));
types.emplace_back(new SampledImage(image2));
// Array
// Length is constant with integer bit representation of 42.
types.emplace_back(new Array(f32, Array::LengthInfo{99u, {0, 42u}}));
auto* a42f32 = types.back().get();
// Differs from previous in length value only.
types.emplace_back(new Array(f32, Array::LengthInfo{99u, {0, 44u}}));
// Length is 64-bit constant integer value 42.
types.emplace_back(new Array(u64, Array::LengthInfo{100u, {0, 42u, 0u}}));
// Differs from previous in length value only.
types.emplace_back(new Array(u64, Array::LengthInfo{100u, {0, 44u, 0u}}));
// Length is spec constant with spec id 18 and default value 44.
types.emplace_back(new Array(f32, Array::LengthInfo{99u,
{
1,
18u,
44u,
}}));
// Differs from previous in spec id only.
types.emplace_back(new Array(f32, Array::LengthInfo{99u, {1, 19u, 44u}}));
// Differs from previous in literal value only.
types.emplace_back(new Array(f32, Array::LengthInfo{99u, {1, 19u, 48u}}));
// Length is spec constant op with id 42.
types.emplace_back(new Array(f32, Array::LengthInfo{42u, {2, 42}}));
// Differs from previous in result id only.
types.emplace_back(new Array(f32, Array::LengthInfo{43u, {2, 43}}));
// RuntimeArray
types.emplace_back(new RuntimeArray(v3f32));
types.emplace_back(new RuntimeArray(v3s32));
auto* rav3s32 = types.back().get();
// Struct
types.emplace_back(new Struct(std::vector<const Type*>{s32}));
types.emplace_back(new Struct(std::vector<const Type*>{s32, f32}));
auto* sts32f32 = types.back().get();
types.emplace_back(
new Struct(std::vector<const Type*>{u64, a42f32, rav3s32}));
// Opaque
types.emplace_back(new Opaque(""));
types.emplace_back(new Opaque("hello"));
types.emplace_back(new Opaque("world"));
// Pointer
types.emplace_back(new Pointer(f32, SpvStorageClassInput));
types.emplace_back(new Pointer(sts32f32, SpvStorageClassFunction));
types.emplace_back(new Pointer(a42f32, SpvStorageClassFunction));
types.emplace_back(new Pointer(voidt, SpvStorageClassFunction));
// Function
types.emplace_back(new Function(voidt, {}));
types.emplace_back(new Function(voidt, {boolt}));
types.emplace_back(new Function(voidt, {boolt, s32}));
types.emplace_back(new Function(s32, {boolt, s32}));
// Event, Device Event, Reserve Id, Queue,
types.emplace_back(new Event());
types.emplace_back(new DeviceEvent());
types.emplace_back(new ReserveId());
types.emplace_back(new Queue());
// Pipe, Forward Pointer, PipeStorage, NamedBarrier
types.emplace_back(new Pipe(SpvAccessQualifierReadWrite));
types.emplace_back(new Pipe(SpvAccessQualifierReadOnly));
types.emplace_back(new ForwardPointer(1, SpvStorageClassInput));
types.emplace_back(new ForwardPointer(2, SpvStorageClassInput));
types.emplace_back(new ForwardPointer(2, SpvStorageClassUniform));
types.emplace_back(new PipeStorage());
types.emplace_back(new NamedBarrier());
return types;
}
TEST(Types, AllTypes) {
// Types in this test case are only equal to themselves, nothing else.
std::vector<std::unique_ptr<Type>> types = GenerateAllTypes();
for (size_t i = 0; i < types.size(); ++i) {
for (size_t j = 0; j < types.size(); ++j) {
if (i == j) {
EXPECT_TRUE(types[i]->IsSame(types[j].get()))
<< "expected '" << types[i]->str() << "' is the same as '"
<< types[j]->str() << "'";
} else {
EXPECT_FALSE(types[i]->IsSame(types[j].get()))
<< "entry (" << i << "," << j << ") expected '" << types[i]->str()
<< "' is different to '" << types[j]->str() << "'";
}
}
}
}
TEST(Types, IntSignedness) {
std::vector<bool> signednesses = {true, false, false, true};
std::vector<std::unique_ptr<Integer>> types;
for (bool s : signednesses) {
types.emplace_back(new Integer(32, s));
}
for (size_t i = 0; i < signednesses.size(); i++) {
EXPECT_EQ(signednesses[i], types[i]->IsSigned());
}
}
TEST(Types, IntWidth) {
std::vector<uint32_t> widths = {1, 2, 4, 8, 16, 32, 48, 64, 128};
std::vector<std::unique_ptr<Integer>> types;
for (uint32_t w : widths) {
types.emplace_back(new Integer(w, true));
}
for (size_t i = 0; i < widths.size(); i++) {
EXPECT_EQ(widths[i], types[i]->width());
}
}
TEST(Types, FloatWidth) {
std::vector<uint32_t> widths = {1, 2, 4, 8, 16, 32, 48, 64, 128};
std::vector<std::unique_ptr<Float>> types;
for (uint32_t w : widths) {
types.emplace_back(new Float(w));
}
for (size_t i = 0; i < widths.size(); i++) {
EXPECT_EQ(widths[i], types[i]->width());
}
}
TEST(Types, VectorElementCount) {
auto s32 = MakeUnique<Integer>(32, true);
for (uint32_t c : {2, 3, 4}) {
auto s32v = MakeUnique<Vector>(s32.get(), c);
EXPECT_EQ(c, s32v->element_count());
}
}
TEST(Types, MatrixElementCount) {
auto s32 = MakeUnique<Integer>(32, true);
auto s32v4 = MakeUnique<Vector>(s32.get(), 4);
for (uint32_t c : {1, 2, 3, 4, 10, 100}) {
auto s32m = MakeUnique<Matrix>(s32v4.get(), c);
EXPECT_EQ(c, s32m->element_count());
}
}
TEST(Types, IsUniqueType) {
std::vector<std::unique_ptr<Type>> types = GenerateAllTypes();
for (auto& t : types) {
bool expectation = true;
// Disallowing variable pointers.
switch (t->kind()) {
case Type::kArray:
case Type::kRuntimeArray:
case Type::kStruct:
expectation = false;
break;
default:
break;
}
EXPECT_EQ(t->IsUniqueType(false), expectation)
<< "expected '" << t->str() << "' to be a "
<< (expectation ? "" : "non-") << "unique type";
// Allowing variables pointers.
if (t->AsPointer()) expectation = false;
EXPECT_EQ(t->IsUniqueType(true), expectation)
<< "expected '" << t->str() << "' to be a "
<< (expectation ? "" : "non-") << "unique type";
}
}
std::vector<std::unique_ptr<Type>> GenerateAllTypesWithDecorations() {
std::vector<std::unique_ptr<Type>> types = GenerateAllTypes();
uint32_t elems = 1;
uint32_t decs = 1;
for (auto& t : types) {
for (uint32_t i = 0; i < (decs % 10); ++i) {
std::vector<uint32_t> decoration;
for (uint32_t j = 0; j < (elems % 4) + 1; ++j) {
decoration.push_back(j);
}
t->AddDecoration(std::move(decoration));
++elems;
++decs;
}
}
return types;
}
TEST(Types, Clone) {
std::vector<std::unique_ptr<Type>> types = GenerateAllTypesWithDecorations();
for (auto& t : types) {
auto clone = t->Clone();
EXPECT_TRUE(*t == *clone);
EXPECT_TRUE(t->HasSameDecorations(clone.get()));
EXPECT_NE(clone.get(), t.get());
}
}
TEST(Types, RemoveDecorations) {
std::vector<std::unique_ptr<Type>> types = GenerateAllTypesWithDecorations();
for (auto& t : types) {
auto decorationless = t->RemoveDecorations();
EXPECT_EQ(*t == *decorationless, t->decoration_empty());
EXPECT_EQ(t->HasSameDecorations(decorationless.get()),
t->decoration_empty());
EXPECT_NE(t.get(), decorationless.get());
}
}
} // namespace
} // namespace analysis
} // namespace opt
} // namespace spvtools