blob: f914447b4505c3255e0c6c6bc6891d3bc753124e [file] [log] [blame]
Ben Clayton2f9a9882022-12-17 02:20:04 +00001// Copyright 2022 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
dan sinclaird3b13692023-07-20 01:14:15 +000015#include "src/tint/lang/wgsl/sem/load.h"
dan sinclair3cbf3fc2023-01-21 19:16:15 +000016#include "gmock/gmock.h"
dan sinclaire7a88d22023-07-20 09:21:10 +000017#include "src/tint/lang/base/type/reference.h"
18#include "src/tint/lang/base/type/texture_dimension.h"
dan sinclaird3b13692023-07-20 01:14:15 +000019#include "src/tint/lang/wgsl/sem/test_helper.h"
Ben Clayton2f9a9882022-12-17 02:20:04 +000020#include "src/tint/resolver/resolver.h"
21#include "src/tint/resolver/resolver_test_helper.h"
Ben Clayton2f9a9882022-12-17 02:20:04 +000022
Ben Clayton2f9a9882022-12-17 02:20:04 +000023namespace tint::resolver {
24namespace {
25
Ben Clayton66805b02023-06-14 22:00:01 +000026using namespace tint::builtin::fluent_types; // NOLINT
27using namespace tint::number_suffixes; // NOLINT
28
Ben Clayton2f9a9882022-12-17 02:20:04 +000029using ResolverLoadTest = ResolverTest;
30
31TEST_F(ResolverLoadTest, VarInitializer) {
32 // var ref = 1i;
33 // var v = ref;
34 auto* ident = Expr("ref");
35 WrapInFunction(Var("ref", Expr(1_i)), //
36 Var("v", ident));
37
38 ASSERT_TRUE(r()->Resolve()) << r()->error();
39 auto* load = Sem().Get<sem::Load>(ident);
40 ASSERT_NE(load, nullptr);
41 EXPECT_TRUE(load->Type()->Is<type::I32>());
42 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
43 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::I32>());
44}
45
46TEST_F(ResolverLoadTest, LetInitializer) {
47 // var ref = 1i;
48 // let l = ref;
49 auto* ident = Expr("ref");
50 WrapInFunction(Var("ref", Expr(1_i)), //
51 Let("l", ident));
52
53 ASSERT_TRUE(r()->Resolve()) << r()->error();
54 auto* load = Sem().Get<sem::Load>(ident);
55 ASSERT_NE(load, nullptr);
56 EXPECT_TRUE(load->Type()->Is<type::I32>());
57 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
58 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::I32>());
59}
60
61TEST_F(ResolverLoadTest, Assignment) {
62 // var ref = 1i;
63 // var v : i32;
64 // v = ref;
65 auto* ident = Expr("ref");
66 WrapInFunction(Var("ref", Expr(1_i)), //
67 Var("v", ty.i32()), //
68 Assign("v", ident));
69
70 ASSERT_TRUE(r()->Resolve()) << r()->error();
71 auto* load = Sem().Get<sem::Load>(ident);
72 ASSERT_NE(load, nullptr);
73 EXPECT_TRUE(load->Type()->Is<type::I32>());
74 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
75 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::I32>());
76}
77
78TEST_F(ResolverLoadTest, CompoundAssignment) {
79 // var ref = 1i;
80 // var v : i32;
81 // v += ref;
82 auto* ident = Expr("ref");
83 WrapInFunction(Var("ref", Expr(1_i)), //
84 Var("v", ty.i32()), //
85 CompoundAssign("v", ident, ast::BinaryOp::kAdd));
86
87 ASSERT_TRUE(r()->Resolve()) << r()->error();
88 auto* load = Sem().Get<sem::Load>(ident);
89 ASSERT_NE(load, nullptr);
90 EXPECT_TRUE(load->Type()->Is<type::I32>());
91 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
92 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::I32>());
93}
94
95TEST_F(ResolverLoadTest, UnaryOp) {
96 // var ref = 1i;
97 // var v = -ref;
98 auto* ident = Expr("ref");
99 WrapInFunction(Var("ref", Expr(1_i)), //
100 Var("v", Negation(ident)));
101
102 ASSERT_TRUE(r()->Resolve()) << r()->error();
103 auto* load = Sem().Get<sem::Load>(ident);
104 ASSERT_NE(load, nullptr);
105 EXPECT_TRUE(load->Type()->Is<type::I32>());
106 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
107 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::I32>());
108}
109
110TEST_F(ResolverLoadTest, UnaryOp_NoLoad) {
111 // var ref = 1i;
112 // let v = &ref;
113 auto* ident = Expr("ref");
114 WrapInFunction(Var("ref", Expr(1_i)), //
115 Let("v", AddressOf(ident)));
116
117 ASSERT_TRUE(r()->Resolve()) << r()->error();
118 auto* var_user = Sem().Get<sem::VariableUser>(ident);
119 ASSERT_NE(var_user, nullptr);
120 EXPECT_TRUE(var_user->Type()->Is<type::Reference>());
121 EXPECT_TRUE(var_user->Type()->UnwrapRef()->Is<type::I32>());
122}
123
124TEST_F(ResolverLoadTest, BinaryOp) {
125 // var ref = 1i;
126 // var v = ref * 1i;
127 auto* ident = Expr("ref");
128 WrapInFunction(Var("ref", Expr(1_i)), //
129 Var("v", Mul(ident, 1_i)));
130
131 ASSERT_TRUE(r()->Resolve()) << r()->error();
132 auto* load = Sem().Get<sem::Load>(ident);
133 ASSERT_NE(load, nullptr);
134 EXPECT_TRUE(load->Type()->Is<type::I32>());
135 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
136 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::I32>());
137}
138
139TEST_F(ResolverLoadTest, Index) {
140 // var ref = 1i;
141 // var v = array<i32, 3>(1i, 2i, 3i)[ref];
142 auto* ident = Expr("ref");
143 WrapInFunction(Var("ref", Expr(1_i)), //
Ben Clayton66805b02023-06-14 22:00:01 +0000144 IndexAccessor(Call<array<i32, 3>>(1_i, 2_i, 3_i), ident));
Ben Clayton2f9a9882022-12-17 02:20:04 +0000145
146 ASSERT_TRUE(r()->Resolve()) << r()->error();
147 auto* load = Sem().Get<sem::Load>(ident);
148 ASSERT_NE(load, nullptr);
149 EXPECT_TRUE(load->Type()->Is<type::I32>());
150 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
151 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::I32>());
152}
153
154TEST_F(ResolverLoadTest, MultiComponentSwizzle) {
155 // var ref = vec4(1);
156 // var v = ref.xyz;
157 auto* ident = Expr("ref");
Ben Clayton66805b02023-06-14 22:00:01 +0000158 WrapInFunction(Var("ref", Call<vec4<i32>>(1_i)), //
Ben Clayton2f9a9882022-12-17 02:20:04 +0000159 Var("v", MemberAccessor(ident, "xyz")));
160
161 ASSERT_TRUE(r()->Resolve()) << r()->error();
162 auto* load = Sem().Get<sem::Load>(ident);
163 ASSERT_NE(load, nullptr);
164 EXPECT_TRUE(load->Type()->Is<type::Vector>());
165 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
166 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::Vector>());
167}
168
169TEST_F(ResolverLoadTest, Bitcast) {
170 // var ref = 1f;
171 // var v = bitcast<i32>(ref);
172 auto* ident = Expr("ref");
173 WrapInFunction(Var("ref", Expr(1_f)), //
174 Bitcast<i32>(ident));
175
176 ASSERT_TRUE(r()->Resolve()) << r()->error();
177 auto* load = Sem().Get<sem::Load>(ident);
178 ASSERT_NE(load, nullptr);
179 EXPECT_TRUE(load->Type()->Is<type::F32>());
180 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
181 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::F32>());
182}
183
184TEST_F(ResolverLoadTest, BuiltinArg) {
185 // var ref = 1f;
186 // var v = abs(ref);
187 auto* ident = Expr("ref");
188 WrapInFunction(Var("ref", Expr(1_f)), //
189 Call("abs", ident));
190
191 ASSERT_TRUE(r()->Resolve()) << r()->error();
192 auto* load = Sem().Get<sem::Load>(ident);
193 ASSERT_NE(load, nullptr);
194 EXPECT_TRUE(load->Type()->Is<type::F32>());
195 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
196 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::F32>());
197}
198
199TEST_F(ResolverLoadTest, FunctionArg) {
200 // fn f(x : f32) {}
201 // var ref = 1f;
202 // f(ref);
203 Func("f", utils::Vector{Param("x", ty.f32())}, ty.void_(), utils::Empty);
204 auto* ident = Expr("ref");
205 WrapInFunction(Var("ref", Expr(1_f)), //
206 CallStmt(Call("f", ident)));
207
208 ASSERT_TRUE(r()->Resolve()) << r()->error();
209 auto* load = Sem().Get<sem::Load>(ident);
210 ASSERT_NE(load, nullptr);
211 EXPECT_TRUE(load->Type()->Is<type::F32>());
212 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
213 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::F32>());
214}
215
216TEST_F(ResolverLoadTest, FunctionArg_Handles) {
217 // @group(0) @binding(0) var t : texture_2d<f32>;
218 // @group(0) @binding(1) var s : sampler;
219 // fn f(tp : texture_2d<f32>, sp : sampler) -> vec4<f32> {
220 // return textureSampleLevel(tp, sp, vec2(), 0);
221 // }
222 // f(t, s);
dan sinclair3cbf3fc2023-01-21 19:16:15 +0000223 GlobalVar("t", ty.sampled_texture(type::TextureDimension::k2d, ty.f32()),
Ben Clayton2f9a9882022-12-17 02:20:04 +0000224 utils::Vector{Group(0_a), Binding(0_a)});
dan sinclair3085e232023-01-23 16:24:12 +0000225 GlobalVar("s", ty.sampler(type::SamplerKind::kSampler),
226 utils::Vector{Group(0_a), Binding(1_a)});
Ben Clayton2f9a9882022-12-17 02:20:04 +0000227 Func("f",
228 utils::Vector{
dan sinclair3cbf3fc2023-01-21 19:16:15 +0000229 Param("tp", ty.sampled_texture(type::TextureDimension::k2d, ty.f32())),
dan sinclair3085e232023-01-23 16:24:12 +0000230 Param("sp", ty.sampler(type::SamplerKind::kSampler)),
Ben Clayton2f9a9882022-12-17 02:20:04 +0000231 },
232 ty.vec4<f32>(),
233 utils::Vector{
Ben Clayton66805b02023-06-14 22:00:01 +0000234 Return(Call("textureSampleLevel", "tp", "sp", Call<vec2<f32>>(), 0_a)),
Ben Clayton2f9a9882022-12-17 02:20:04 +0000235 });
236 auto* t_ident = Expr("t");
237 auto* s_ident = Expr("s");
238 WrapInFunction(CallStmt(Call("f", t_ident, s_ident)));
239
240 ASSERT_TRUE(r()->Resolve()) << r()->error();
241
242 {
243 auto* load = Sem().Get<sem::Load>(t_ident);
244 ASSERT_NE(load, nullptr);
245 EXPECT_TRUE(load->Type()->Is<type::SampledTexture>());
246 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
247 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::SampledTexture>());
248 }
249 {
250 auto* load = Sem().Get<sem::Load>(s_ident);
251 ASSERT_NE(load, nullptr);
252 EXPECT_TRUE(load->Type()->Is<type::Sampler>());
253 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
254 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::Sampler>());
255 }
256}
257
258TEST_F(ResolverLoadTest, FunctionReturn) {
259 // var ref = 1f;
260 // return ref;
261 auto* ident = Expr("ref");
262 Func("f", utils::Empty, ty.f32(),
263 utils::Vector{
264 Decl(Var("ref", Expr(1_f))),
265 Return(ident),
266 });
267
268 ASSERT_TRUE(r()->Resolve()) << r()->error();
269 auto* load = Sem().Get<sem::Load>(ident);
270 ASSERT_NE(load, nullptr);
271 EXPECT_TRUE(load->Type()->Is<type::F32>());
272 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
273 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::F32>());
274}
275
276TEST_F(ResolverLoadTest, IfCond) {
277 // var ref = false;
278 // if (ref) {}
279 auto* ident = Expr("ref");
280 WrapInFunction(Var("ref", Expr(false)), //
281 If(ident, Block()));
282
283 ASSERT_TRUE(r()->Resolve()) << r()->error();
284 auto* load = Sem().Get<sem::Load>(ident);
285 ASSERT_NE(load, nullptr);
286 EXPECT_TRUE(load->Type()->Is<type::Bool>());
287 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
288 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::Bool>());
289}
290
291TEST_F(ResolverLoadTest, Switch) {
292 // var ref = 1i;
293 // switch (ref) {
294 // default:
295 // }
296 auto* ident = Expr("ref");
297 WrapInFunction(Var("ref", Expr(1_i)), //
298 Switch(ident, DefaultCase()));
299
300 ASSERT_TRUE(r()->Resolve()) << r()->error();
301 auto* load = Sem().Get<sem::Load>(ident);
302 ASSERT_NE(load, nullptr);
303 EXPECT_TRUE(load->Type()->Is<type::I32>());
304 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
305 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::I32>());
306}
307
308TEST_F(ResolverLoadTest, BreakIfCond) {
309 // var ref = false;
310 // loop {
311 // continuing {
312 // break if (ref);
313 // }
314 // }
315 auto* ident = Expr("ref");
316 WrapInFunction(Var("ref", Expr(false)), //
317 Loop(Block(), Block(BreakIf(ident))));
318
319 ASSERT_TRUE(r()->Resolve()) << r()->error();
320 auto* load = Sem().Get<sem::Load>(ident);
321 ASSERT_NE(load, nullptr);
322 EXPECT_TRUE(load->Type()->Is<type::Bool>());
323 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
324 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::Bool>());
325}
326
327TEST_F(ResolverLoadTest, ForCond) {
328 // var ref = false;
329 // for (; ref; ) {}
330 auto* ident = Expr("ref");
331 WrapInFunction(Var("ref", Expr(false)), //
332 For(nullptr, ident, nullptr, Block()));
333
334 ASSERT_TRUE(r()->Resolve()) << r()->error();
335 auto* load = Sem().Get<sem::Load>(ident);
336 ASSERT_NE(load, nullptr);
337 EXPECT_TRUE(load->Type()->Is<type::Bool>());
338 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
339 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::Bool>());
340}
341
342TEST_F(ResolverLoadTest, WhileCond) {
343 // var ref = false;
344 // while (ref) {}
345 auto* ident = Expr("ref");
346 WrapInFunction(Var("ref", Expr(false)), //
347 While(ident, Block()));
348
349 ASSERT_TRUE(r()->Resolve()) << r()->error();
350 auto* load = Sem().Get<sem::Load>(ident);
351 ASSERT_NE(load, nullptr);
352 EXPECT_TRUE(load->Type()->Is<type::Bool>());
353 EXPECT_TRUE(load->Reference()->Type()->Is<type::Reference>());
354 EXPECT_TRUE(load->Reference()->Type()->UnwrapRef()->Is<type::Bool>());
355}
356
357TEST_F(ResolverLoadTest, AddressOf) {
358 // var ref = 1i;
359 // let l = &ref;
360 auto* ident = Expr("ref");
361 WrapInFunction(Var("ref", Expr(1_i)), //
362 Let("l", AddressOf(ident)));
363
364 ASSERT_TRUE(r()->Resolve()) << r()->error();
Ben Clayton0b4a2f12023-02-05 22:59:40 +0000365 auto* no_load = Sem().GetVal(ident);
Ben Clayton2f9a9882022-12-17 02:20:04 +0000366 ASSERT_NE(no_load, nullptr);
367 EXPECT_TRUE(no_load->Type()->Is<type::Reference>()); // No load
368}
369
370} // namespace
371} // namespace tint::resolver