blob: c5a1597e2f669ba7d38a164f57423a77e09326c2 [file] [log] [blame]
Ben Clayton313e6182021-06-17 19:56:14 +00001// 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
22namespace tint {
23namespace resolver {
24namespace {
25
26struct ResolverAtomicValidationTest : public resolver::TestHelper,
27 public testing::Test {};
28
Sarah4038fa72021-08-05 15:18:29 +000029TEST_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
36TEST_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
45TEST_F(ResolverAtomicValidationTest, InvalidType) {
Ben Clayton313e6182021-06-17 19:56:14 +000046 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
Sarah4038fa72021-08-05 15:18:29 +000053TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Simple) {
Ben Clayton313e6182021-06-17 19:56:14 +000054 Global("a", ty.atomic(Source{{12, 34}}, ty.i32()),
55 ast::StorageClass::kPrivate);
56
57 EXPECT_FALSE(r()->Resolve());
Sarah4038fa72021-08-05 15:18:29 +000058 EXPECT_EQ(r()->error(),
59 "12:34 error: atomic variables must have <storage> or <workgroup> "
60 "storage class");
Ben Clayton313e6182021-06-17 19:56:14 +000061}
62
Sarah4038fa72021-08-05 15:18:29 +000063TEST_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
73TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Struct) {
Ben Clayton313e6182021-06-17 19:56:14 +000074 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(),
Sarah4038fa72021-08-05 15:18:29 +000080 "error: atomic variables must have <storage> or <workgroup> "
81 "storage class\n"
82 "note: atomic sub-type of 's' is declared here");
Ben Clayton313e6182021-06-17 19:56:14 +000083}
84
Sarah4038fa72021-08-05 15:18:29 +000085TEST_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
102TEST_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
120TEST_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
135TEST_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
152TEST_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
172TEST_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
213TEST_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
227TEST_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
241TEST_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
261TEST_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
280TEST_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}
Ben Clayton313e6182021-06-17 19:56:14 +0000321
322TEST_F(ResolverAtomicValidationTest, Local) {
323 WrapInFunction(Var("a", ty.atomic(Source{{12, 34}}, ty.i32())));
324
325 EXPECT_FALSE(r()->Resolve());
Sarah72494042021-07-28 22:43:36 +0000326 EXPECT_EQ(r()->error(),
327 "12:34 error: function variable must have a constructible type");
Ben Clayton313e6182021-06-17 19:56:14 +0000328}
329
Ben Clayton313e6182021-06-17 19:56:14 +0000330} // namespace
331} // namespace resolver
332} // namespace tint