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