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 "source/opt/types.h"
16 
17 #include <memory>
18 #include <utility>
19 #include <vector>
20 
21 #include "gtest/gtest.h"
22 #include "source/util/make_unique.h"
23 
24 namespace spvtools {
25 namespace opt {
26 namespace analysis {
27 namespace {
28 
29 // Fixture class providing some element types.
30 class SameTypeTest : public ::testing::Test {
31  protected:
SetUp()32   void SetUp() override {
33     void_t_ = MakeUnique<Void>();
34     u32_t_ = MakeUnique<Integer>(32, false);
35     f64_t_ = MakeUnique<Float>(64);
36     v3u32_t_ = MakeUnique<Vector>(u32_t_.get(), 3);
37     image_t_ =
38         MakeUnique<Image>(f64_t_.get(), SpvDim2D, 1, 1, 0, 0, SpvImageFormatR16,
39                           SpvAccessQualifierReadWrite);
40   }
41 
42   // Element types to be used for constructing other types for testing.
43   std::unique_ptr<Type> void_t_;
44   std::unique_ptr<Type> u32_t_;
45   std::unique_ptr<Type> f64_t_;
46   std::unique_ptr<Type> v3u32_t_;
47   std::unique_ptr<Type> image_t_;
48 };
49 
50 #define TestMultipleInstancesOfTheSameTypeQualified(ty, name, ...)        \
51   TEST_F(SameTypeTest, MultiSame##ty##name) {                             \
52     std::vector<std::unique_ptr<Type>> types;                             \
53     for (int i = 0; i < 10; ++i) types.emplace_back(new ty(__VA_ARGS__)); \
54     for (size_t i = 0; i < types.size(); ++i) {                           \
55       for (size_t j = 0; j < types.size(); ++j) {                         \
56         EXPECT_TRUE(types[i]->IsSame(types[j].get()))                     \
57             << "expected '" << types[i]->str() << "' is the same as '"    \
58             << types[j]->str() << "'";                                    \
59         EXPECT_TRUE(*types[i] == *types[j])                               \
60             << "expected '" << types[i]->str() << "' is the same as '"    \
61             << types[j]->str() << "'";                                    \
62       }                                                                   \
63     }                                                                     \
64   }
65 #define TestMultipleInstancesOfTheSameType(ty, ...) \
66   TestMultipleInstancesOfTheSameTypeQualified(ty, Simple, __VA_ARGS__)
67 
68 // clang-format off
69 TestMultipleInstancesOfTheSameType(Void)
TestMultipleInstancesOfTheSameType(Bool)70 TestMultipleInstancesOfTheSameType(Bool)
71 TestMultipleInstancesOfTheSameType(Integer, 32, true)
72 TestMultipleInstancesOfTheSameType(Float, 64)
73 TestMultipleInstancesOfTheSameType(Vector, u32_t_.get(), 3)
74 TestMultipleInstancesOfTheSameType(Matrix, v3u32_t_.get(), 4)
75 TestMultipleInstancesOfTheSameType(Image, f64_t_.get(), SpvDimCube, 0, 0, 1, 1,
76                                    SpvImageFormatRgb10A2,
77                                    SpvAccessQualifierWriteOnly)
78 TestMultipleInstancesOfTheSameType(Sampler)
79 TestMultipleInstancesOfTheSameType(SampledImage, image_t_.get())
80 // There are three classes of arrays, based on the kinds of length information
81 // they have.
82 // 1. Array length is a constant or spec constant without spec ID, with literals
83 // for the constant value.
84 TestMultipleInstancesOfTheSameTypeQualified(Array, LenConstant, u32_t_.get(),
85                                             Array::LengthInfo{42,
86                                                               {
87                                                                   0,
88                                                                   9999,
89                                                               }})
90 // 2. Array length is a spec constant with a given spec id.
91 TestMultipleInstancesOfTheSameTypeQualified(Array, LenSpecId, u32_t_.get(),
92                                             Array::LengthInfo{42, {1, 99}})
93 // 3. Array length is an OpSpecConstantOp expression
94 TestMultipleInstancesOfTheSameTypeQualified(Array, LenDefiningId, u32_t_.get(),
95                                             Array::LengthInfo{42, {2, 42}})
96 
97 TestMultipleInstancesOfTheSameType(RuntimeArray, u32_t_.get())
98 TestMultipleInstancesOfTheSameType(Struct, std::vector<const Type*>{
99                                                u32_t_.get(), f64_t_.get()})
100 TestMultipleInstancesOfTheSameType(Opaque, "testing rocks")
101 TestMultipleInstancesOfTheSameType(Pointer, u32_t_.get(), SpvStorageClassInput)
102 TestMultipleInstancesOfTheSameType(Function, u32_t_.get(),
103                                    {f64_t_.get(), f64_t_.get()})
104 TestMultipleInstancesOfTheSameType(Event)
105 TestMultipleInstancesOfTheSameType(DeviceEvent)
106 TestMultipleInstancesOfTheSameType(ReserveId)
107 TestMultipleInstancesOfTheSameType(Queue)
108 TestMultipleInstancesOfTheSameType(Pipe, SpvAccessQualifierReadWrite)
109 TestMultipleInstancesOfTheSameType(ForwardPointer, 10, SpvStorageClassUniform)
110 TestMultipleInstancesOfTheSameType(PipeStorage)
111 TestMultipleInstancesOfTheSameType(NamedBarrier)
112 TestMultipleInstancesOfTheSameType(AccelerationStructureNV)
113 #undef TestMultipleInstanceOfTheSameType
114 #undef TestMultipleInstanceOfTheSameTypeQual
115 
116 std::vector<std::unique_ptr<Type>> GenerateAllTypes() {
117   // clang-format on
118   // Types in this test case are only equal to themselves, nothing else.
119   std::vector<std::unique_ptr<Type>> types;
120 
121   // Forward Pointer
122   types.emplace_back(new ForwardPointer(10000, SpvStorageClassInput));
123   types.emplace_back(new ForwardPointer(20000, SpvStorageClassInput));
124 
125   // Void, Bool
126   types.emplace_back(new Void());
127   auto* voidt = types.back().get();
128   types.emplace_back(new Bool());
129   auto* boolt = types.back().get();
130 
131   // Integer
132   types.emplace_back(new Integer(32, true));
133   auto* s32 = types.back().get();
134   types.emplace_back(new Integer(32, false));
135   types.emplace_back(new Integer(64, true));
136   types.emplace_back(new Integer(64, false));
137   auto* u64 = types.back().get();
138 
139   // Float
140   types.emplace_back(new Float(32));
141   auto* f32 = types.back().get();
142   types.emplace_back(new Float(64));
143 
144   // Vector
145   types.emplace_back(new Vector(s32, 2));
146   types.emplace_back(new Vector(s32, 3));
147   auto* v3s32 = types.back().get();
148   types.emplace_back(new Vector(u64, 4));
149   types.emplace_back(new Vector(f32, 3));
150   auto* v3f32 = types.back().get();
151 
152   // Matrix
153   types.emplace_back(new Matrix(v3s32, 3));
154   types.emplace_back(new Matrix(v3s32, 4));
155   types.emplace_back(new Matrix(v3f32, 4));
156 
157   // Images
158   types.emplace_back(new Image(s32, SpvDim2D, 0, 0, 0, 0, SpvImageFormatRg8,
159                                SpvAccessQualifierReadOnly));
160   auto* image1 = types.back().get();
161   types.emplace_back(new Image(s32, SpvDim2D, 0, 1, 0, 0, SpvImageFormatRg8,
162                                SpvAccessQualifierReadOnly));
163   types.emplace_back(new Image(s32, SpvDim3D, 0, 1, 0, 0, SpvImageFormatRg8,
164                                SpvAccessQualifierReadOnly));
165   types.emplace_back(new Image(voidt, SpvDim3D, 0, 1, 0, 1, SpvImageFormatRg8,
166                                SpvAccessQualifierReadWrite));
167   auto* image2 = types.back().get();
168 
169   // Sampler
170   types.emplace_back(new Sampler());
171 
172   // Sampled Image
173   types.emplace_back(new SampledImage(image1));
174   types.emplace_back(new SampledImage(image2));
175 
176   // Array
177   // Length is constant with integer bit representation of 42.
178   types.emplace_back(new Array(f32, Array::LengthInfo{99u, {0, 42u}}));
179   auto* a42f32 = types.back().get();
180   // Differs from previous in length value only.
181   types.emplace_back(new Array(f32, Array::LengthInfo{99u, {0, 44u}}));
182   // Length is 64-bit constant integer value 42.
183   types.emplace_back(new Array(u64, Array::LengthInfo{100u, {0, 42u, 0u}}));
184   // Differs from previous in length value only.
185   types.emplace_back(new Array(u64, Array::LengthInfo{100u, {0, 44u, 0u}}));
186 
187   // Length is spec constant with spec id 18 and default value 44.
188   types.emplace_back(new Array(f32, Array::LengthInfo{99u,
189                                                       {
190                                                           1,
191                                                           18u,
192                                                           44u,
193                                                       }}));
194   // Differs from previous in spec id only.
195   types.emplace_back(new Array(f32, Array::LengthInfo{99u, {1, 19u, 44u}}));
196   // Differs from previous in literal value only.
197   types.emplace_back(new Array(f32, Array::LengthInfo{99u, {1, 19u, 48u}}));
198   // Length is spec constant op with id 42.
199   types.emplace_back(new Array(f32, Array::LengthInfo{42u, {2, 42}}));
200   // Differs from previous in result id only.
201   types.emplace_back(new Array(f32, Array::LengthInfo{43u, {2, 43}}));
202 
203   // RuntimeArray
204   types.emplace_back(new RuntimeArray(v3f32));
205   types.emplace_back(new RuntimeArray(v3s32));
206   auto* rav3s32 = types.back().get();
207 
208   // Struct
209   types.emplace_back(new Struct(std::vector<const Type*>{s32}));
210   types.emplace_back(new Struct(std::vector<const Type*>{s32, f32}));
211   auto* sts32f32 = types.back().get();
212   types.emplace_back(
213       new Struct(std::vector<const Type*>{u64, a42f32, rav3s32}));
214 
215   // Opaque
216   types.emplace_back(new Opaque(""));
217   types.emplace_back(new Opaque("hello"));
218   types.emplace_back(new Opaque("world"));
219 
220   // Pointer
221   types.emplace_back(new Pointer(f32, SpvStorageClassInput));
222   types.emplace_back(new Pointer(sts32f32, SpvStorageClassFunction));
223   types.emplace_back(new Pointer(a42f32, SpvStorageClassFunction));
224   types.emplace_back(new Pointer(voidt, SpvStorageClassFunction));
225 
226   // Function
227   types.emplace_back(new Function(voidt, {}));
228   types.emplace_back(new Function(voidt, {boolt}));
229   types.emplace_back(new Function(voidt, {boolt, s32}));
230   types.emplace_back(new Function(s32, {boolt, s32}));
231 
232   // Event, Device Event, Reserve Id, Queue,
233   types.emplace_back(new Event());
234   types.emplace_back(new DeviceEvent());
235   types.emplace_back(new ReserveId());
236   types.emplace_back(new Queue());
237 
238   // Pipe, Forward Pointer, PipeStorage, NamedBarrier
239   types.emplace_back(new Pipe(SpvAccessQualifierReadWrite));
240   types.emplace_back(new Pipe(SpvAccessQualifierReadOnly));
241   types.emplace_back(new ForwardPointer(1, SpvStorageClassInput));
242   types.emplace_back(new ForwardPointer(2, SpvStorageClassInput));
243   types.emplace_back(new ForwardPointer(2, SpvStorageClassUniform));
244   types.emplace_back(new PipeStorage());
245   types.emplace_back(new NamedBarrier());
246 
247   return types;
248 }
249 
TEST(Types,AllTypes)250 TEST(Types, AllTypes) {
251   // Types in this test case are only equal to themselves, nothing else.
252   std::vector<std::unique_ptr<Type>> types = GenerateAllTypes();
253 
254   for (size_t i = 0; i < types.size(); ++i) {
255     for (size_t j = 0; j < types.size(); ++j) {
256       if (i == j) {
257         EXPECT_TRUE(types[i]->IsSame(types[j].get()))
258             << "expected '" << types[i]->str() << "' is the same as '"
259             << types[j]->str() << "'";
260       } else {
261         EXPECT_FALSE(types[i]->IsSame(types[j].get()))
262             << "entry (" << i << "," << j << ")  expected '" << types[i]->str()
263             << "' is different to '" << types[j]->str() << "'";
264       }
265     }
266   }
267 }
268 
TEST(Types,IntSignedness)269 TEST(Types, IntSignedness) {
270   std::vector<bool> signednesses = {true, false, false, true};
271   std::vector<std::unique_ptr<Integer>> types;
272   for (bool s : signednesses) {
273     types.emplace_back(new Integer(32, s));
274   }
275   for (size_t i = 0; i < signednesses.size(); i++) {
276     EXPECT_EQ(signednesses[i], types[i]->IsSigned());
277   }
278 }
279 
TEST(Types,IntWidth)280 TEST(Types, IntWidth) {
281   std::vector<uint32_t> widths = {1, 2, 4, 8, 16, 32, 48, 64, 128};
282   std::vector<std::unique_ptr<Integer>> types;
283   for (uint32_t w : widths) {
284     types.emplace_back(new Integer(w, true));
285   }
286   for (size_t i = 0; i < widths.size(); i++) {
287     EXPECT_EQ(widths[i], types[i]->width());
288   }
289 }
290 
TEST(Types,FloatWidth)291 TEST(Types, FloatWidth) {
292   std::vector<uint32_t> widths = {1, 2, 4, 8, 16, 32, 48, 64, 128};
293   std::vector<std::unique_ptr<Float>> types;
294   for (uint32_t w : widths) {
295     types.emplace_back(new Float(w));
296   }
297   for (size_t i = 0; i < widths.size(); i++) {
298     EXPECT_EQ(widths[i], types[i]->width());
299   }
300 }
301 
TEST(Types,VectorElementCount)302 TEST(Types, VectorElementCount) {
303   auto s32 = MakeUnique<Integer>(32, true);
304   for (uint32_t c : {2, 3, 4}) {
305     auto s32v = MakeUnique<Vector>(s32.get(), c);
306     EXPECT_EQ(c, s32v->element_count());
307   }
308 }
309 
TEST(Types,MatrixElementCount)310 TEST(Types, MatrixElementCount) {
311   auto s32 = MakeUnique<Integer>(32, true);
312   auto s32v4 = MakeUnique<Vector>(s32.get(), 4);
313   for (uint32_t c : {1, 2, 3, 4, 10, 100}) {
314     auto s32m = MakeUnique<Matrix>(s32v4.get(), c);
315     EXPECT_EQ(c, s32m->element_count());
316   }
317 }
318 
TEST(Types,IsUniqueType)319 TEST(Types, IsUniqueType) {
320   std::vector<std::unique_ptr<Type>> types = GenerateAllTypes();
321 
322   for (auto& t : types) {
323     bool expectation = true;
324     // Disallowing variable pointers.
325     switch (t->kind()) {
326       case Type::kArray:
327       case Type::kRuntimeArray:
328       case Type::kStruct:
329         expectation = false;
330         break;
331       default:
332         break;
333     }
334     EXPECT_EQ(t->IsUniqueType(false), expectation)
335         << "expected '" << t->str() << "' to be a "
336         << (expectation ? "" : "non-") << "unique type";
337 
338     // Allowing variables pointers.
339     if (t->AsPointer()) expectation = false;
340     EXPECT_EQ(t->IsUniqueType(true), expectation)
341         << "expected '" << t->str() << "' to be a "
342         << (expectation ? "" : "non-") << "unique type";
343   }
344 }
345 
GenerateAllTypesWithDecorations()346 std::vector<std::unique_ptr<Type>> GenerateAllTypesWithDecorations() {
347   std::vector<std::unique_ptr<Type>> types = GenerateAllTypes();
348   uint32_t elems = 1;
349   uint32_t decs = 1;
350   for (auto& t : types) {
351     for (uint32_t i = 0; i < (decs % 10); ++i) {
352       std::vector<uint32_t> decoration;
353       for (uint32_t j = 0; j < (elems % 4) + 1; ++j) {
354         decoration.push_back(j);
355       }
356       t->AddDecoration(std::move(decoration));
357       ++elems;
358       ++decs;
359     }
360   }
361 
362   return types;
363 }
364 
TEST(Types,Clone)365 TEST(Types, Clone) {
366   std::vector<std::unique_ptr<Type>> types = GenerateAllTypesWithDecorations();
367   for (auto& t : types) {
368     auto clone = t->Clone();
369     EXPECT_TRUE(*t == *clone);
370     EXPECT_TRUE(t->HasSameDecorations(clone.get()));
371     EXPECT_NE(clone.get(), t.get());
372   }
373 }
374 
TEST(Types,RemoveDecorations)375 TEST(Types, RemoveDecorations) {
376   std::vector<std::unique_ptr<Type>> types = GenerateAllTypesWithDecorations();
377   for (auto& t : types) {
378     auto decorationless = t->RemoveDecorations();
379     EXPECT_EQ(*t == *decorationless, t->decoration_empty());
380     EXPECT_EQ(t->HasSameDecorations(decorationless.get()),
381               t->decoration_empty());
382     EXPECT_NE(t.get(), decorationless.get());
383   }
384 }
385 
386 }  // namespace
387 }  // namespace analysis
388 }  // namespace opt
389 }  // namespace spvtools
390