• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Tint Authors.
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 "src/resolver/resolver.h"
16 #include "src/resolver/resolver_test_helper.h"
17 #include "src/sem/atomic_type.h"
18 #include "src/sem/reference_type.h"
19 
20 #include "gmock/gmock.h"
21 
22 namespace tint {
23 namespace resolver {
24 namespace {
25 
26 struct ResolverAtomicValidationTest : public resolver::TestHelper,
27                                       public testing::Test {};
28 
TEST_F(ResolverAtomicValidationTest,StorageClass_WorkGroup)29 TEST_F(ResolverAtomicValidationTest, StorageClass_WorkGroup) {
30   Global("a", ty.atomic(Source{{12, 34}}, ty.i32()),
31          ast::StorageClass::kWorkgroup);
32 
33   EXPECT_TRUE(r()->Resolve());
34 }
35 
TEST_F(ResolverAtomicValidationTest,StorageClass_Storage)36 TEST_F(ResolverAtomicValidationTest, StorageClass_Storage) {
37   auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))},
38                       {StructBlock()});
39   Global("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
40          GroupAndBinding(0, 0));
41 
42   EXPECT_TRUE(r()->Resolve()) << r()->error();
43 }
44 
TEST_F(ResolverAtomicValidationTest,InvalidType)45 TEST_F(ResolverAtomicValidationTest, InvalidType) {
46   Global("a", ty.atomic(ty.f32(Source{{12, 34}})),
47          ast::StorageClass::kWorkgroup);
48 
49   EXPECT_FALSE(r()->Resolve());
50   EXPECT_EQ(r()->error(), "12:34 error: atomic only supports i32 or u32 types");
51 }
52 
TEST_F(ResolverAtomicValidationTest,InvalidStorageClass_Simple)53 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Simple) {
54   Global("a", ty.atomic(Source{{12, 34}}, ty.i32()),
55          ast::StorageClass::kPrivate);
56 
57   EXPECT_FALSE(r()->Resolve());
58   EXPECT_EQ(r()->error(),
59             "12:34 error: atomic variables must have <storage> or <workgroup> "
60             "storage class");
61 }
62 
TEST_F(ResolverAtomicValidationTest,InvalidStorageClass_Array)63 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Array) {
64   Global("a", ty.atomic(Source{{12, 34}}, ty.i32()),
65          ast::StorageClass::kPrivate);
66 
67   EXPECT_FALSE(r()->Resolve());
68   EXPECT_EQ(r()->error(),
69             "12:34 error: atomic variables must have <storage> or <workgroup> "
70             "storage class");
71 }
72 
TEST_F(ResolverAtomicValidationTest,InvalidStorageClass_Struct)73 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Struct) {
74   auto* s =
75       Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
76   Global("g", ty.Of(s), ast::StorageClass::kPrivate);
77 
78   EXPECT_FALSE(r()->Resolve());
79   EXPECT_EQ(r()->error(),
80             "error: atomic variables must have <storage> or <workgroup> "
81             "storage class\n"
82             "note: atomic sub-type of 's' is declared here");
83 }
84 
TEST_F(ResolverAtomicValidationTest,InvalidStorageClass_StructOfStruct)85 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_StructOfStruct) {
86   // struct Inner { m : atomic<i32>; };
87   // struct Outer { m : array<Inner, 4>; };
88   // var<private> g : Outer;
89 
90   auto* Inner =
91       Structure("Inner", {Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
92   auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
93   Global("g", ty.Of(Outer), ast::StorageClass::kPrivate);
94 
95   EXPECT_FALSE(r()->Resolve());
96   EXPECT_EQ(r()->error(),
97             "error: atomic variables must have <storage> or <workgroup> "
98             "storage class\n"
99             "note: atomic sub-type of 'Outer' is declared here");
100 }
101 
TEST_F(ResolverAtomicValidationTest,InvalidStorageClass_StructOfStructOfArray)102 TEST_F(ResolverAtomicValidationTest,
103        InvalidStorageClass_StructOfStructOfArray) {
104   // struct Inner { m : array<atomic<i32>, 4>; };
105   // struct Outer { m : array<Inner, 4>; };
106   // var<private> g : Outer;
107 
108   auto* Inner =
109       Structure("Inner", {Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
110   auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
111   Global("g", ty.Of(Outer), ast::StorageClass::kPrivate);
112 
113   EXPECT_FALSE(r()->Resolve());
114   EXPECT_EQ(r()->error(),
115             "error: atomic variables must have <storage> or <workgroup> "
116             "storage class\n"
117             "12:34 note: atomic sub-type of 'Outer' is declared here");
118 }
119 
TEST_F(ResolverAtomicValidationTest,InvalidStorageClass_ArrayOfArray)120 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfArray) {
121   // type AtomicArray = array<atomic<i32>, 5>;
122   // var<private> v: array<s, 5>;
123 
124   auto* atomic_array = Alias(Source{{12, 34}}, "AtomicArray",
125                              ty.atomic(Source{{12, 34}}, ty.i32()));
126   Global(Source{{56, 78}}, "v", ty.Of(atomic_array),
127          ast::StorageClass::kPrivate);
128 
129   EXPECT_FALSE(r()->Resolve());
130   EXPECT_EQ(r()->error(),
131             "error: atomic variables must have <storage> or <workgroup> "
132             "storage class");
133 }
134 
TEST_F(ResolverAtomicValidationTest,InvalidStorageClass_ArrayOfStruct)135 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfStruct) {
136   // struct S{
137   //   m: atomic<u32>;
138   // };
139   // var<private> v: array<S, 5>;
140 
141   auto* s = Structure("S", {Member("m", ty.atomic<u32>())});
142   Global(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5),
143          ast::StorageClass::kPrivate);
144 
145   EXPECT_FALSE(r()->Resolve());
146   EXPECT_EQ(r()->error(),
147             "error: atomic variables must have <storage> or <workgroup> "
148             "storage class\n"
149             "note: atomic sub-type of 'array<S, 5>' is declared here");
150 }
151 
TEST_F(ResolverAtomicValidationTest,InvalidStorageClass_ArrayOfStructOfArray)152 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfStructOfArray) {
153   // type AtomicArray = array<atomic<i32>, 5>;
154   // struct S{
155   //   m: AtomicArray;
156   // };
157   // var<private> v: array<S, 5>;
158 
159   auto* atomic_array = Alias(Source{{12, 34}}, "AtomicArray",
160                              ty.atomic(Source{{12, 34}}, ty.i32()));
161   auto* s = Structure("S", {Member("m", ty.Of(atomic_array))});
162   Global(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5),
163          ast::StorageClass::kPrivate);
164 
165   EXPECT_FALSE(r()->Resolve());
166   EXPECT_EQ(r()->error(),
167             "error: atomic variables must have <storage> or <workgroup> "
168             "storage class\n"
169             "note: atomic sub-type of 'array<S, 5>' is declared here");
170 }
171 
TEST_F(ResolverAtomicValidationTest,InvalidStorageClass_Complex)172 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Complex) {
173   // type AtomicArray = array<atomic<i32>, 5>;
174   // struct S6 { x: array<i32, 4>; };
175   // struct S5 { x: S6;
176   //             y: AtomicArray;
177   //             z: array<atomic<u32>, 8>; };
178   // struct S4 { x: S6;
179   //             y: S5;
180   //             z: array<atomic<i32>, 4>; };
181   // struct S3 { x: S4; };
182   // struct S2 { x: S3; };
183   // struct S1 { x: S2; };
184   // struct S0 { x: S1; };
185   // var<private> g : S0;
186 
187   auto* atomic_array = Alias(Source{{12, 34}}, "AtomicArray",
188                              ty.atomic(Source{{12, 34}}, ty.i32()));
189   auto* array_i32_4 = ty.array(ty.i32(), 4);
190   auto* array_atomic_u32_8 = ty.array(ty.atomic(ty.u32()), 8);
191   auto* array_atomic_i32_4 = ty.array(ty.atomic(ty.i32()), 4);
192 
193   auto* s6 = Structure("S6", {Member("x", array_i32_4)});
194   auto* s5 = Structure("S5", {Member("x", ty.Of(s6)),             //
195                               Member("y", ty.Of(atomic_array)),   //
196                               Member("z", array_atomic_u32_8)});  //
197   auto* s4 = Structure("S4", {Member("x", ty.Of(s6)),             //
198                               Member("y", ty.Of(s5)),             //
199                               Member("z", array_atomic_i32_4)});  //
200   auto* s3 = Structure("S3", {Member("x", ty.Of(s4))});
201   auto* s2 = Structure("S2", {Member("x", ty.Of(s3))});
202   auto* s1 = Structure("S1", {Member("x", ty.Of(s2))});
203   auto* s0 = Structure("S0", {Member("x", ty.Of(s1))});
204   Global(Source{{56, 78}}, "g", ty.Of(s0), ast::StorageClass::kPrivate);
205 
206   EXPECT_FALSE(r()->Resolve());
207   EXPECT_EQ(r()->error(),
208             "error: atomic variables must have <storage> or <workgroup> "
209             "storage class\n"
210             "note: atomic sub-type of 'S0' is declared here");
211 }
212 
TEST_F(ResolverAtomicValidationTest,Struct_AccessMode_Read)213 TEST_F(ResolverAtomicValidationTest, Struct_AccessMode_Read) {
214   auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))},
215                       {StructBlock()});
216   Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
217          ast::Access::kRead, GroupAndBinding(0, 0));
218 
219   EXPECT_FALSE(r()->Resolve());
220   EXPECT_EQ(
221       r()->error(),
222       "error: atomic variables in <storage> storage class must have read_write "
223       "access mode\n"
224       "note: atomic sub-type of 's' is declared here");
225 }
226 
TEST_F(ResolverAtomicValidationTest,InvalidAccessMode_Struct)227 TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_Struct) {
228   auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))},
229                       {StructBlock()});
230   Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
231          ast::Access::kRead, GroupAndBinding(0, 0));
232 
233   EXPECT_FALSE(r()->Resolve());
234   EXPECT_EQ(
235       r()->error(),
236       "error: atomic variables in <storage> storage class must have read_write "
237       "access mode\n"
238       "note: atomic sub-type of 's' is declared here");
239 }
240 
TEST_F(ResolverAtomicValidationTest,InvalidAccessMode_StructOfStruct)241 TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_StructOfStruct) {
242   // struct Inner { m : atomic<i32>; };
243   // struct Outer { m : array<Inner, 4>; };
244   // var<storage, read> g : Outer;
245 
246   auto* Inner =
247       Structure("Inner", {Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
248   auto* Outer =
249       Structure("Outer", {Member("m", ty.Of(Inner))}, {StructBlock()});
250   Global(Source{{56, 78}}, "g", ty.Of(Outer), ast::StorageClass::kStorage,
251          ast::Access::kRead, GroupAndBinding(0, 0));
252 
253   EXPECT_FALSE(r()->Resolve());
254   EXPECT_EQ(
255       r()->error(),
256       "error: atomic variables in <storage> storage class must have read_write "
257       "access mode\n"
258       "note: atomic sub-type of 'Outer' is declared here");
259 }
260 
TEST_F(ResolverAtomicValidationTest,InvalidAccessMode_StructOfStructOfArray)261 TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_StructOfStructOfArray) {
262   // struct Inner { m : array<atomic<i32>, 4>; };
263   // struct Outer { m : array<Inner, 4>; };
264   // var<storage, read> g : Outer;
265 
266   auto* Inner =
267       Structure("Inner", {Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
268   auto* Outer =
269       Structure("Outer", {Member("m", ty.Of(Inner))}, {StructBlock()});
270   Global(Source{{56, 78}}, "g", ty.Of(Outer), ast::StorageClass::kStorage,
271          ast::Access::kRead, GroupAndBinding(0, 0));
272 
273   EXPECT_FALSE(r()->Resolve());
274   EXPECT_EQ(r()->error(),
275             "error: atomic variables in <storage> storage class must have "
276             "read_write access mode\n"
277             "12:34 note: atomic sub-type of 'Outer' is declared here");
278 }
279 
TEST_F(ResolverAtomicValidationTest,InvalidAccessMode_Complex)280 TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_Complex) {
281   // type AtomicArray = array<atomic<i32>, 5>;
282   // struct S6 { x: array<i32, 4>; };
283   // struct S5 { x: S6;
284   //             y: AtomicArray;
285   //             z: array<atomic<u32>, 8>; };
286   // struct S4 { x: S6;
287   //             y: S5;
288   //             z: array<atomic<i32>, 4>; };
289   // struct S3 { x: S4; };
290   // struct S2 { x: S3; };
291   // struct S1 { x: S2; };
292   // struct S0 { x: S1; };
293   // var<storage, read> g : S0;
294 
295   auto* atomic_array = Alias(Source{{12, 34}}, "AtomicArray",
296                              ty.atomic(Source{{12, 34}}, ty.i32()));
297   auto* array_i32_4 = ty.array(ty.i32(), 4);
298   auto* array_atomic_u32_8 = ty.array(ty.atomic(ty.u32()), 8);
299   auto* array_atomic_i32_4 = ty.array(ty.atomic(ty.i32()), 4);
300 
301   auto* s6 = Structure("S6", {Member("x", array_i32_4)});
302   auto* s5 = Structure("S5", {Member("x", ty.Of(s6)),             //
303                               Member("y", ty.Of(atomic_array)),   //
304                               Member("z", array_atomic_u32_8)});  //
305   auto* s4 = Structure("S4", {Member("x", ty.Of(s6)),             //
306                               Member("y", ty.Of(s5)),             //
307                               Member("z", array_atomic_i32_4)});  //
308   auto* s3 = Structure("S3", {Member("x", ty.Of(s4))});
309   auto* s2 = Structure("S2", {Member("x", ty.Of(s3))});
310   auto* s1 = Structure("S1", {Member("x", ty.Of(s2))});
311   auto* s0 = Structure("S0", {Member("x", ty.Of(s1))}, {StructBlock()});
312   Global(Source{{56, 78}}, "g", ty.Of(s0), ast::StorageClass::kStorage,
313          ast::Access::kRead, GroupAndBinding(0, 0));
314 
315   EXPECT_FALSE(r()->Resolve());
316   EXPECT_EQ(r()->error(),
317             "error: atomic variables in <storage> storage class must have "
318             "read_write access mode\n"
319             "note: atomic sub-type of 'S0' is declared here");
320 }
321 
TEST_F(ResolverAtomicValidationTest,Local)322 TEST_F(ResolverAtomicValidationTest, Local) {
323   WrapInFunction(Var("a", ty.atomic(Source{{12, 34}}, ty.i32())));
324 
325   EXPECT_FALSE(r()->Resolve());
326   EXPECT_EQ(r()->error(),
327             "12:34 error: function variable must have a constructible type");
328 }
329 
330 }  // namespace
331 }  // namespace resolver
332 }  // namespace tint
333