1 // Copyright (c) 2016 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <memory> 16 #include <utility> 17 #include <vector> 18 19 #include "gtest/gtest.h" 20 #include "source/opt/types.h" 21 #include "source/util/make_unique.h" 22 23 namespace spvtools { 24 namespace opt { 25 namespace analysis { 26 namespace { 27 28 // Fixture class providing some element types. 29 class SameTypeTest : public ::testing::Test { 30 protected: 31 void SetUp() override { 32 void_t_ = MakeUnique<Void>(); 33 u32_t_ = MakeUnique<Integer>(32, false); 34 f64_t_ = MakeUnique<Float>(64); 35 v3u32_t_ = MakeUnique<Vector>(u32_t_.get(), 3); 36 image_t_ = 37 MakeUnique<Image>(f64_t_.get(), SpvDim2D, 1, 1, 0, 0, SpvImageFormatR16, 38 SpvAccessQualifierReadWrite); 39 } 40 41 // Element types to be used for constructing other types for testing. 42 std::unique_ptr<Type> void_t_; 43 std::unique_ptr<Type> u32_t_; 44 std::unique_ptr<Type> f64_t_; 45 std::unique_ptr<Type> v3u32_t_; 46 std::unique_ptr<Type> image_t_; 47 }; 48 49 #define TestMultipleInstancesOfTheSameType(ty, ...) \ 50 TEST_F(SameTypeTest, MultiSame##ty) { \ 51 std::vector<std::unique_ptr<Type>> types; \ 52 for (int i = 0; i < 10; ++i) types.emplace_back(new ty(__VA_ARGS__)); \ 53 for (size_t i = 0; i < types.size(); ++i) { \ 54 for (size_t j = 0; j < types.size(); ++j) { \ 55 EXPECT_TRUE(types[i]->IsSame(types[j].get())) \ 56 << "expected '" << types[i]->str() << "' is the same as '" \ 57 << types[j]->str() << "'"; \ 58 EXPECT_TRUE(*types[i] == *types[j]) \ 59 << "expected '" << types[i]->str() << "' is the same as '" \ 60 << types[j]->str() << "'"; \ 61 } \ 62 } \ 63 } 64 TestMultipleInstancesOfTheSameType(Void); 65 TestMultipleInstancesOfTheSameType(Bool); 66 TestMultipleInstancesOfTheSameType(Integer, 32, true); 67 TestMultipleInstancesOfTheSameType(Float, 64); 68 TestMultipleInstancesOfTheSameType(Vector, u32_t_.get(), 3); 69 TestMultipleInstancesOfTheSameType(Matrix, v3u32_t_.get(), 4); 70 TestMultipleInstancesOfTheSameType(Image, f64_t_.get(), SpvDimCube, 0, 0, 1, 1, 71 SpvImageFormatRgb10A2, 72 SpvAccessQualifierWriteOnly); 73 TestMultipleInstancesOfTheSameType(Sampler); 74 TestMultipleInstancesOfTheSameType(SampledImage, image_t_.get()); 75 TestMultipleInstancesOfTheSameType(Array, u32_t_.get(), 10); 76 TestMultipleInstancesOfTheSameType(RuntimeArray, u32_t_.get()); 77 TestMultipleInstancesOfTheSameType(Struct, std::vector<const Type*>{ 78 u32_t_.get(), f64_t_.get()}); 79 TestMultipleInstancesOfTheSameType(Opaque, "testing rocks"); 80 TestMultipleInstancesOfTheSameType(Pointer, u32_t_.get(), SpvStorageClassInput); 81 TestMultipleInstancesOfTheSameType(Function, u32_t_.get(), 82 {f64_t_.get(), f64_t_.get()}); 83 TestMultipleInstancesOfTheSameType(Event); 84 TestMultipleInstancesOfTheSameType(DeviceEvent); 85 TestMultipleInstancesOfTheSameType(ReserveId); 86 TestMultipleInstancesOfTheSameType(Queue); 87 TestMultipleInstancesOfTheSameType(Pipe, SpvAccessQualifierReadWrite); 88 TestMultipleInstancesOfTheSameType(ForwardPointer, 10, SpvStorageClassUniform); 89 TestMultipleInstancesOfTheSameType(PipeStorage); 90 TestMultipleInstancesOfTheSameType(NamedBarrier); 91 TestMultipleInstancesOfTheSameType(AccelerationStructureNV); 92 #undef TestMultipleInstanceOfTheSameType 93 94 std::vector<std::unique_ptr<Type>> GenerateAllTypes() { 95 // Types in this test case are only equal to themselves, nothing else. 96 std::vector<std::unique_ptr<Type>> types; 97 98 // Forward Pointer 99 types.emplace_back(new ForwardPointer(10000, SpvStorageClassInput)); 100 types.emplace_back(new ForwardPointer(20000, SpvStorageClassInput)); 101 102 // Void, Bool 103 types.emplace_back(new Void()); 104 auto* voidt = types.back().get(); 105 types.emplace_back(new Bool()); 106 auto* boolt = types.back().get(); 107 108 // Integer 109 types.emplace_back(new Integer(32, true)); 110 auto* s32 = types.back().get(); 111 types.emplace_back(new Integer(32, false)); 112 types.emplace_back(new Integer(64, true)); 113 types.emplace_back(new Integer(64, false)); 114 auto* u64 = types.back().get(); 115 116 // Float 117 types.emplace_back(new Float(32)); 118 auto* f32 = types.back().get(); 119 types.emplace_back(new Float(64)); 120 121 // Vector 122 types.emplace_back(new Vector(s32, 2)); 123 types.emplace_back(new Vector(s32, 3)); 124 auto* v3s32 = types.back().get(); 125 types.emplace_back(new Vector(u64, 4)); 126 types.emplace_back(new Vector(f32, 3)); 127 auto* v3f32 = types.back().get(); 128 129 // Matrix 130 types.emplace_back(new Matrix(v3s32, 3)); 131 types.emplace_back(new Matrix(v3s32, 4)); 132 types.emplace_back(new Matrix(v3f32, 4)); 133 134 // Images 135 types.emplace_back(new Image(s32, SpvDim2D, 0, 0, 0, 0, SpvImageFormatRg8, 136 SpvAccessQualifierReadOnly)); 137 auto* image1 = types.back().get(); 138 types.emplace_back(new Image(s32, SpvDim2D, 0, 1, 0, 0, SpvImageFormatRg8, 139 SpvAccessQualifierReadOnly)); 140 types.emplace_back(new Image(s32, SpvDim3D, 0, 1, 0, 0, SpvImageFormatRg8, 141 SpvAccessQualifierReadOnly)); 142 types.emplace_back(new Image(voidt, SpvDim3D, 0, 1, 0, 1, SpvImageFormatRg8, 143 SpvAccessQualifierReadWrite)); 144 auto* image2 = types.back().get(); 145 146 // Sampler 147 types.emplace_back(new Sampler()); 148 149 // Sampled Image 150 types.emplace_back(new SampledImage(image1)); 151 types.emplace_back(new SampledImage(image2)); 152 153 // Array 154 types.emplace_back(new Array(f32, 100)); 155 types.emplace_back(new Array(f32, 42)); 156 auto* a42f32 = types.back().get(); 157 types.emplace_back(new Array(u64, 24)); 158 159 // RuntimeArray 160 types.emplace_back(new RuntimeArray(v3f32)); 161 types.emplace_back(new RuntimeArray(v3s32)); 162 auto* rav3s32 = types.back().get(); 163 164 // Struct 165 types.emplace_back(new Struct(std::vector<const Type*>{s32})); 166 types.emplace_back(new Struct(std::vector<const Type*>{s32, f32})); 167 auto* sts32f32 = types.back().get(); 168 types.emplace_back( 169 new Struct(std::vector<const Type*>{u64, a42f32, rav3s32})); 170 171 // Opaque 172 types.emplace_back(new Opaque("")); 173 types.emplace_back(new Opaque("hello")); 174 types.emplace_back(new Opaque("world")); 175 176 // Pointer 177 types.emplace_back(new Pointer(f32, SpvStorageClassInput)); 178 types.emplace_back(new Pointer(sts32f32, SpvStorageClassFunction)); 179 types.emplace_back(new Pointer(a42f32, SpvStorageClassFunction)); 180 types.emplace_back(new Pointer(voidt, SpvStorageClassFunction)); 181 182 // Function 183 types.emplace_back(new Function(voidt, {})); 184 types.emplace_back(new Function(voidt, {boolt})); 185 types.emplace_back(new Function(voidt, {boolt, s32})); 186 types.emplace_back(new Function(s32, {boolt, s32})); 187 188 // Event, Device Event, Reserve Id, Queue, 189 types.emplace_back(new Event()); 190 types.emplace_back(new DeviceEvent()); 191 types.emplace_back(new ReserveId()); 192 types.emplace_back(new Queue()); 193 194 // Pipe, Forward Pointer, PipeStorage, NamedBarrier 195 types.emplace_back(new Pipe(SpvAccessQualifierReadWrite)); 196 types.emplace_back(new Pipe(SpvAccessQualifierReadOnly)); 197 types.emplace_back(new ForwardPointer(1, SpvStorageClassInput)); 198 types.emplace_back(new ForwardPointer(2, SpvStorageClassInput)); 199 types.emplace_back(new ForwardPointer(2, SpvStorageClassUniform)); 200 types.emplace_back(new PipeStorage()); 201 types.emplace_back(new NamedBarrier()); 202 203 return types; 204 } 205 206 TEST(Types, AllTypes) { 207 // Types in this test case are only equal to themselves, nothing else. 208 std::vector<std::unique_ptr<Type>> types = GenerateAllTypes(); 209 210 for (size_t i = 0; i < types.size(); ++i) { 211 for (size_t j = 0; j < types.size(); ++j) { 212 if (i == j) { 213 EXPECT_TRUE(types[i]->IsSame(types[j].get())) 214 << "expected '" << types[i]->str() << "' is the same as '" 215 << types[j]->str() << "'"; 216 } else { 217 EXPECT_FALSE(types[i]->IsSame(types[j].get())) 218 << "expected '" << types[i]->str() << "' is different to '" 219 << types[j]->str() << "'"; 220 } 221 } 222 } 223 } 224 225 TEST(Types, IntSignedness) { 226 std::vector<bool> signednesses = {true, false, false, true}; 227 std::vector<std::unique_ptr<Integer>> types; 228 for (bool s : signednesses) { 229 types.emplace_back(new Integer(32, s)); 230 } 231 for (size_t i = 0; i < signednesses.size(); i++) { 232 EXPECT_EQ(signednesses[i], types[i]->IsSigned()); 233 } 234 } 235 236 TEST(Types, IntWidth) { 237 std::vector<uint32_t> widths = {1, 2, 4, 8, 16, 32, 48, 64, 128}; 238 std::vector<std::unique_ptr<Integer>> types; 239 for (uint32_t w : widths) { 240 types.emplace_back(new Integer(w, true)); 241 } 242 for (size_t i = 0; i < widths.size(); i++) { 243 EXPECT_EQ(widths[i], types[i]->width()); 244 } 245 } 246 247 TEST(Types, FloatWidth) { 248 std::vector<uint32_t> widths = {1, 2, 4, 8, 16, 32, 48, 64, 128}; 249 std::vector<std::unique_ptr<Float>> types; 250 for (uint32_t w : widths) { 251 types.emplace_back(new Float(w)); 252 } 253 for (size_t i = 0; i < widths.size(); i++) { 254 EXPECT_EQ(widths[i], types[i]->width()); 255 } 256 } 257 258 TEST(Types, VectorElementCount) { 259 auto s32 = MakeUnique<Integer>(32, true); 260 for (uint32_t c : {2, 3, 4}) { 261 auto s32v = MakeUnique<Vector>(s32.get(), c); 262 EXPECT_EQ(c, s32v->element_count()); 263 } 264 } 265 266 TEST(Types, MatrixElementCount) { 267 auto s32 = MakeUnique<Integer>(32, true); 268 auto s32v4 = MakeUnique<Vector>(s32.get(), 4); 269 for (uint32_t c : {1, 2, 3, 4, 10, 100}) { 270 auto s32m = MakeUnique<Matrix>(s32v4.get(), c); 271 EXPECT_EQ(c, s32m->element_count()); 272 } 273 } 274 275 TEST(Types, IsUniqueType) { 276 std::vector<std::unique_ptr<Type>> types = GenerateAllTypes(); 277 278 for (auto& t : types) { 279 bool expectation = true; 280 // Disallowing variable pointers. 281 switch (t->kind()) { 282 case Type::kArray: 283 case Type::kRuntimeArray: 284 case Type::kStruct: 285 expectation = false; 286 break; 287 default: 288 break; 289 } 290 EXPECT_EQ(t->IsUniqueType(false), expectation) 291 << "expected '" << t->str() << "' to be a " 292 << (expectation ? "" : "non-") << "unique type"; 293 294 // Allowing variables pointers. 295 if (t->AsPointer()) expectation = false; 296 EXPECT_EQ(t->IsUniqueType(true), expectation) 297 << "expected '" << t->str() << "' to be a " 298 << (expectation ? "" : "non-") << "unique type"; 299 } 300 } 301 302 std::vector<std::unique_ptr<Type>> GenerateAllTypesWithDecorations() { 303 std::vector<std::unique_ptr<Type>> types = GenerateAllTypes(); 304 uint32_t elems = 1; 305 uint32_t decs = 1; 306 for (auto& t : types) { 307 for (uint32_t i = 0; i < (decs % 10); ++i) { 308 std::vector<uint32_t> decoration; 309 for (uint32_t j = 0; j < (elems % 4) + 1; ++j) { 310 decoration.push_back(j); 311 } 312 t->AddDecoration(std::move(decoration)); 313 ++elems; 314 ++decs; 315 } 316 } 317 318 return types; 319 } 320 321 TEST(Types, Clone) { 322 std::vector<std::unique_ptr<Type>> types = GenerateAllTypesWithDecorations(); 323 for (auto& t : types) { 324 auto clone = t->Clone(); 325 EXPECT_TRUE(*t == *clone); 326 EXPECT_TRUE(t->HasSameDecorations(clone.get())); 327 EXPECT_NE(clone.get(), t.get()); 328 } 329 } 330 331 TEST(Types, RemoveDecorations) { 332 std::vector<std::unique_ptr<Type>> types = GenerateAllTypesWithDecorations(); 333 for (auto& t : types) { 334 auto decorationless = t->RemoveDecorations(); 335 EXPECT_EQ(*t == *decorationless, t->decoration_empty()); 336 EXPECT_EQ(t->HasSameDecorations(decorationless.get()), 337 t->decoration_empty()); 338 EXPECT_NE(t.get(), decorationless.get()); 339 } 340 } 341 342 } // namespace 343 } // namespace analysis 344 } // namespace opt 345 } // namespace spvtools 346