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
17 #include "gmock/gmock.h"
18 #include "src/ast/assignment_statement.h"
19 #include "src/ast/bitcast_expression.h"
20 #include "src/ast/break_statement.h"
21 #include "src/ast/call_statement.h"
22 #include "src/ast/continue_statement.h"
23 #include "src/ast/if_statement.h"
24 #include "src/ast/intrinsic_texture_helper_test.h"
25 #include "src/ast/loop_statement.h"
26 #include "src/ast/return_statement.h"
27 #include "src/ast/stage_decoration.h"
28 #include "src/ast/struct_block_decoration.h"
29 #include "src/ast/switch_statement.h"
30 #include "src/ast/unary_op_expression.h"
31 #include "src/ast/variable_decl_statement.h"
32 #include "src/resolver/resolver_test_helper.h"
33 #include "src/sem/call.h"
34 #include "src/sem/function.h"
35 #include "src/sem/member_accessor_expression.h"
36 #include "src/sem/sampled_texture_type.h"
37 #include "src/sem/statement.h"
38 #include "src/sem/variable.h"
39
40 using ::testing::ElementsAre;
41 using ::testing::HasSubstr;
42
43 namespace tint {
44 namespace resolver {
45 namespace {
46
47 using IntrinsicType = sem::IntrinsicType;
48
49 using ResolverIntrinsicTest = ResolverTest;
50
51 using ResolverIntrinsicDerivativeTest = ResolverTestWithParam<std::string>;
TEST_P(ResolverIntrinsicDerivativeTest,Scalar)52 TEST_P(ResolverIntrinsicDerivativeTest, Scalar) {
53 auto name = GetParam();
54
55 Global("ident", ty.f32(), ast::StorageClass::kPrivate);
56
57 auto* expr = Call(name, "ident");
58 Func("func", {}, ty.void_(), {Ignore(expr)},
59 {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
60
61 EXPECT_TRUE(r()->Resolve()) << r()->error();
62
63 ASSERT_NE(TypeOf(expr), nullptr);
64 ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
65 }
66
TEST_P(ResolverIntrinsicDerivativeTest,Vector)67 TEST_P(ResolverIntrinsicDerivativeTest, Vector) {
68 auto name = GetParam();
69 Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
70
71 auto* expr = Call(name, "ident");
72 Func("func", {}, ty.void_(), {Ignore(expr)},
73 {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
74
75 EXPECT_TRUE(r()->Resolve()) << r()->error();
76
77 ASSERT_NE(TypeOf(expr), nullptr);
78 ASSERT_TRUE(TypeOf(expr)->Is<sem::Vector>());
79 EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
80 EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 4u);
81 }
82
TEST_P(ResolverIntrinsicDerivativeTest,MissingParam)83 TEST_P(ResolverIntrinsicDerivativeTest, MissingParam) {
84 auto name = GetParam();
85
86 auto* expr = Call(name);
87 WrapInFunction(expr);
88
89 EXPECT_FALSE(r()->Resolve());
90
91 EXPECT_EQ(r()->error(), "error: no matching call to " + name +
92 "()\n\n"
93 "2 candidate functions:\n " +
94 name + "(f32) -> f32\n " + name +
95 "(vecN<f32>) -> vecN<f32>\n");
96 }
97
98 INSTANTIATE_TEST_SUITE_P(ResolverTest,
99 ResolverIntrinsicDerivativeTest,
100 testing::Values("dpdx",
101 "dpdxCoarse",
102 "dpdxFine",
103 "dpdy",
104 "dpdyCoarse",
105 "dpdyFine",
106 "fwidth",
107 "fwidthCoarse",
108 "fwidthFine"));
109
110 using ResolverIntrinsicTest_BoolMethod = ResolverTestWithParam<std::string>;
TEST_P(ResolverIntrinsicTest_BoolMethod,Scalar)111 TEST_P(ResolverIntrinsicTest_BoolMethod, Scalar) {
112 auto name = GetParam();
113
114 Global("my_var", ty.bool_(), ast::StorageClass::kPrivate);
115
116 auto* expr = Call(name, "my_var");
117 WrapInFunction(expr);
118
119 EXPECT_TRUE(r()->Resolve()) << r()->error();
120
121 ASSERT_NE(TypeOf(expr), nullptr);
122 EXPECT_TRUE(TypeOf(expr)->Is<sem::Bool>());
123 }
TEST_P(ResolverIntrinsicTest_BoolMethod,Vector)124 TEST_P(ResolverIntrinsicTest_BoolMethod, Vector) {
125 auto name = GetParam();
126
127 Global("my_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
128
129 auto* expr = Call(name, "my_var");
130 WrapInFunction(expr);
131
132 EXPECT_TRUE(r()->Resolve()) << r()->error();
133
134 ASSERT_NE(TypeOf(expr), nullptr);
135 EXPECT_TRUE(TypeOf(expr)->Is<sem::Bool>());
136 }
137 INSTANTIATE_TEST_SUITE_P(ResolverTest,
138 ResolverIntrinsicTest_BoolMethod,
139 testing::Values("any", "all"));
140
141 using ResolverIntrinsicTest_FloatMethod = ResolverTestWithParam<std::string>;
TEST_P(ResolverIntrinsicTest_FloatMethod,Vector)142 TEST_P(ResolverIntrinsicTest_FloatMethod, Vector) {
143 auto name = GetParam();
144
145 Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
146
147 auto* expr = Call(name, "my_var");
148 WrapInFunction(expr);
149
150 EXPECT_TRUE(r()->Resolve()) << r()->error();
151
152 ASSERT_NE(TypeOf(expr), nullptr);
153 ASSERT_TRUE(TypeOf(expr)->Is<sem::Vector>());
154 EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::Bool>());
155 EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 3u);
156 }
157
TEST_P(ResolverIntrinsicTest_FloatMethod,Scalar)158 TEST_P(ResolverIntrinsicTest_FloatMethod, Scalar) {
159 auto name = GetParam();
160
161 Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
162
163 auto* expr = Call(name, "my_var");
164 WrapInFunction(expr);
165
166 EXPECT_TRUE(r()->Resolve()) << r()->error();
167
168 ASSERT_NE(TypeOf(expr), nullptr);
169 EXPECT_TRUE(TypeOf(expr)->Is<sem::Bool>());
170 }
171
TEST_P(ResolverIntrinsicTest_FloatMethod,MissingParam)172 TEST_P(ResolverIntrinsicTest_FloatMethod, MissingParam) {
173 auto name = GetParam();
174
175 Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
176
177 auto* expr = Call(name);
178 WrapInFunction(expr);
179
180 EXPECT_FALSE(r()->Resolve());
181
182 EXPECT_EQ(r()->error(), "error: no matching call to " + name +
183 "()\n\n"
184 "2 candidate functions:\n " +
185 name + "(f32) -> bool\n " + name +
186 "(vecN<f32>) -> vecN<bool>\n");
187 }
188
TEST_P(ResolverIntrinsicTest_FloatMethod,TooManyParams)189 TEST_P(ResolverIntrinsicTest_FloatMethod, TooManyParams) {
190 auto name = GetParam();
191
192 Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
193
194 auto* expr = Call(name, "my_var", 1.23f);
195 WrapInFunction(expr);
196
197 EXPECT_FALSE(r()->Resolve());
198
199 EXPECT_EQ(r()->error(), "error: no matching call to " + name +
200 "(f32, f32)\n\n"
201 "2 candidate functions:\n " +
202 name + "(f32) -> bool\n " + name +
203 "(vecN<f32>) -> vecN<bool>\n");
204 }
205 INSTANTIATE_TEST_SUITE_P(
206 ResolverTest,
207 ResolverIntrinsicTest_FloatMethod,
208 testing::Values("isInf", "isNan", "isFinite", "isNormal"));
209
210 enum class Texture { kF32, kI32, kU32 };
operator <<(std::ostream & out,Texture data)211 inline std::ostream& operator<<(std::ostream& out, Texture data) {
212 if (data == Texture::kF32) {
213 out << "f32";
214 } else if (data == Texture::kI32) {
215 out << "i32";
216 } else {
217 out << "u32";
218 }
219 return out;
220 }
221
222 struct TextureTestParams {
223 ast::TextureDimension dim;
224 Texture type = Texture::kF32;
225 ast::ImageFormat format = ast::ImageFormat::kR16Float;
226 };
operator <<(std::ostream & out,TextureTestParams data)227 inline std::ostream& operator<<(std::ostream& out, TextureTestParams data) {
228 out << data.dim << "_" << data.type;
229 return out;
230 }
231
232 class ResolverIntrinsicTest_TextureOperation
233 : public ResolverTestWithParam<TextureTestParams> {
234 public:
235 /// Gets an appropriate type for the coords parameter depending the the
236 /// dimensionality of the texture being sampled.
237 /// @param dim dimensionality of the texture being sampled
238 /// @param scalar the scalar type
239 /// @returns a pointer to a type appropriate for the coord param
GetCoordsType(ast::TextureDimension dim,const ast::Type * scalar)240 const ast::Type* GetCoordsType(ast::TextureDimension dim,
241 const ast::Type* scalar) {
242 switch (dim) {
243 case ast::TextureDimension::k1d:
244 return scalar;
245 case ast::TextureDimension::k2d:
246 case ast::TextureDimension::k2dArray:
247 return ty.vec(scalar, 2);
248 case ast::TextureDimension::k3d:
249 case ast::TextureDimension::kCube:
250 case ast::TextureDimension::kCubeArray:
251 return ty.vec(scalar, 3);
252 default:
253 [=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
254 }
255 return nullptr;
256 }
257
add_call_param(std::string name,const ast::Type * type,ast::ExpressionList * call_params)258 void add_call_param(std::string name,
259 const ast::Type* type,
260 ast::ExpressionList* call_params) {
261 if (type->IsAnyOf<ast::Texture, ast::Sampler>()) {
262 Global(name, type,
263 ast::DecorationList{
264 create<ast::BindingDecoration>(0),
265 create<ast::GroupDecoration>(0),
266 });
267
268 } else {
269 Global(name, type, ast::StorageClass::kPrivate);
270 }
271
272 call_params->push_back(Expr(name));
273 }
subtype(Texture type)274 const ast::Type* subtype(Texture type) {
275 if (type == Texture::kF32) {
276 return ty.f32();
277 }
278 if (type == Texture::kI32) {
279 return ty.i32();
280 }
281 return ty.u32();
282 }
283 };
284
285 using ResolverIntrinsicTest_SampledTextureOperation =
286 ResolverIntrinsicTest_TextureOperation;
TEST_P(ResolverIntrinsicTest_SampledTextureOperation,TextureLoadSampled)287 TEST_P(ResolverIntrinsicTest_SampledTextureOperation, TextureLoadSampled) {
288 auto dim = GetParam().dim;
289 auto type = GetParam().type;
290
291 auto* s = subtype(type);
292 auto* coords_type = GetCoordsType(dim, ty.i32());
293 auto* texture_type = ty.sampled_texture(dim, s);
294
295 ast::ExpressionList call_params;
296
297 add_call_param("texture", texture_type, &call_params);
298 add_call_param("coords", coords_type, &call_params);
299 if (dim == ast::TextureDimension::k2dArray) {
300 add_call_param("array_index", ty.i32(), &call_params);
301 }
302 add_call_param("level", ty.i32(), &call_params);
303
304 auto* expr = Call("textureLoad", call_params);
305 WrapInFunction(expr);
306
307 EXPECT_TRUE(r()->Resolve()) << r()->error();
308
309 ASSERT_NE(TypeOf(expr), nullptr);
310 ASSERT_TRUE(TypeOf(expr)->Is<sem::Vector>());
311 if (type == Texture::kF32) {
312 EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
313 } else if (type == Texture::kI32) {
314 EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::I32>());
315 } else {
316 EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::U32>());
317 }
318 EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 4u);
319 }
320
321 INSTANTIATE_TEST_SUITE_P(
322 ResolverTest,
323 ResolverIntrinsicTest_SampledTextureOperation,
324 testing::Values(TextureTestParams{ast::TextureDimension::k1d},
325 TextureTestParams{ast::TextureDimension::k2d},
326 TextureTestParams{ast::TextureDimension::k2dArray},
327 TextureTestParams{ast::TextureDimension::k3d}));
328
TEST_F(ResolverIntrinsicTest,Dot_Vec2)329 TEST_F(ResolverIntrinsicTest, Dot_Vec2) {
330 Global("my_var", ty.vec2<f32>(), ast::StorageClass::kPrivate);
331
332 auto* expr = Call("dot", "my_var", "my_var");
333 WrapInFunction(expr);
334
335 EXPECT_TRUE(r()->Resolve()) << r()->error();
336
337 ASSERT_NE(TypeOf(expr), nullptr);
338 EXPECT_TRUE(TypeOf(expr)->Is<sem::F32>());
339 }
340
TEST_F(ResolverIntrinsicTest,Dot_Vec3)341 TEST_F(ResolverIntrinsicTest, Dot_Vec3) {
342 Global("my_var", ty.vec3<i32>(), ast::StorageClass::kPrivate);
343
344 auto* expr = Call("dot", "my_var", "my_var");
345 WrapInFunction(expr);
346
347 EXPECT_TRUE(r()->Resolve()) << r()->error();
348
349 ASSERT_NE(TypeOf(expr), nullptr);
350 EXPECT_TRUE(TypeOf(expr)->Is<sem::I32>());
351 }
352
TEST_F(ResolverIntrinsicTest,Dot_Vec4)353 TEST_F(ResolverIntrinsicTest, Dot_Vec4) {
354 Global("my_var", ty.vec4<u32>(), ast::StorageClass::kPrivate);
355
356 auto* expr = Call("dot", "my_var", "my_var");
357 WrapInFunction(expr);
358
359 EXPECT_TRUE(r()->Resolve()) << r()->error();
360
361 ASSERT_NE(TypeOf(expr), nullptr);
362 EXPECT_TRUE(TypeOf(expr)->Is<sem::U32>());
363 }
364
TEST_F(ResolverIntrinsicTest,Dot_Error_Scalar)365 TEST_F(ResolverIntrinsicTest, Dot_Error_Scalar) {
366 auto* expr = Call("dot", 1.0f, 1.0f);
367 WrapInFunction(expr);
368
369 EXPECT_FALSE(r()->Resolve());
370
371 EXPECT_EQ(r()->error(),
372 R"(error: no matching call to dot(f32, f32)
373
374 1 candidate function:
375 dot(vecN<T>, vecN<T>) -> T where: T is f32, i32 or u32
376 )");
377 }
378
TEST_F(ResolverIntrinsicTest,Select)379 TEST_F(ResolverIntrinsicTest, Select) {
380 Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
381
382 Global("bool_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
383
384 auto* expr = Call("select", "my_var", "my_var", "bool_var");
385 WrapInFunction(expr);
386
387 EXPECT_TRUE(r()->Resolve()) << r()->error();
388
389 ASSERT_NE(TypeOf(expr), nullptr);
390 EXPECT_TRUE(TypeOf(expr)->Is<sem::Vector>());
391 EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 3u);
392 EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
393 }
394
TEST_F(ResolverIntrinsicTest,Select_Error_NoParams)395 TEST_F(ResolverIntrinsicTest, Select_Error_NoParams) {
396 auto* expr = Call("select");
397 WrapInFunction(expr);
398
399 EXPECT_FALSE(r()->Resolve());
400
401 EXPECT_EQ(r()->error(),
402 R"(error: no matching call to select()
403
404 3 candidate functions:
405 select(T, T, bool) -> T where: T is f32, i32, u32 or bool
406 select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, i32, u32 or bool
407 select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, i32, u32 or bool
408 )");
409 }
410
TEST_F(ResolverIntrinsicTest,Select_Error_SelectorInt)411 TEST_F(ResolverIntrinsicTest, Select_Error_SelectorInt) {
412 auto* expr = Call("select", 1, 1, 1);
413 WrapInFunction(expr);
414
415 EXPECT_FALSE(r()->Resolve());
416
417 EXPECT_EQ(r()->error(),
418 R"(error: no matching call to select(i32, i32, i32)
419
420 3 candidate functions:
421 select(T, T, bool) -> T where: T is f32, i32, u32 or bool
422 select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, i32, u32 or bool
423 select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, i32, u32 or bool
424 )");
425 }
426
TEST_F(ResolverIntrinsicTest,Select_Error_Matrix)427 TEST_F(ResolverIntrinsicTest, Select_Error_Matrix) {
428 auto* expr = Call(
429 "select", mat2x2<f32>(vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f)),
430 mat2x2<f32>(vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f)), Expr(true));
431 WrapInFunction(expr);
432
433 EXPECT_FALSE(r()->Resolve());
434
435 EXPECT_EQ(r()->error(),
436 R"(error: no matching call to select(mat2x2<f32>, mat2x2<f32>, bool)
437
438 3 candidate functions:
439 select(T, T, bool) -> T where: T is f32, i32, u32 or bool
440 select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, i32, u32 or bool
441 select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, i32, u32 or bool
442 )");
443 }
444
TEST_F(ResolverIntrinsicTest,Select_Error_MismatchTypes)445 TEST_F(ResolverIntrinsicTest, Select_Error_MismatchTypes) {
446 auto* expr = Call("select", 1.0f, vec2<f32>(2.0f, 3.0f), Expr(true));
447 WrapInFunction(expr);
448
449 EXPECT_FALSE(r()->Resolve());
450
451 EXPECT_EQ(r()->error(),
452 R"(error: no matching call to select(f32, vec2<f32>, bool)
453
454 3 candidate functions:
455 select(T, T, bool) -> T where: T is f32, i32, u32 or bool
456 select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, i32, u32 or bool
457 select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, i32, u32 or bool
458 )");
459 }
460
TEST_F(ResolverIntrinsicTest,Select_Error_MismatchVectorSize)461 TEST_F(ResolverIntrinsicTest, Select_Error_MismatchVectorSize) {
462 auto* expr = Call("select", vec2<f32>(1.0f, 2.0f),
463 vec3<f32>(3.0f, 4.0f, 5.0f), Expr(true));
464 WrapInFunction(expr);
465
466 EXPECT_FALSE(r()->Resolve());
467
468 EXPECT_EQ(r()->error(),
469 R"(error: no matching call to select(vec2<f32>, vec3<f32>, bool)
470
471 3 candidate functions:
472 select(T, T, bool) -> T where: T is f32, i32, u32 or bool
473 select(vecN<T>, vecN<T>, bool) -> vecN<T> where: T is f32, i32, u32 or bool
474 select(vecN<T>, vecN<T>, vecN<bool>) -> vecN<T> where: T is f32, i32, u32 or bool
475 )");
476 }
477
478 struct IntrinsicData {
479 const char* name;
480 IntrinsicType intrinsic;
481 };
482
operator <<(std::ostream & out,IntrinsicData data)483 inline std::ostream& operator<<(std::ostream& out, IntrinsicData data) {
484 out << data.name;
485 return out;
486 }
487
488 using ResolverIntrinsicTest_Barrier = ResolverTestWithParam<IntrinsicData>;
TEST_P(ResolverIntrinsicTest_Barrier,InferType)489 TEST_P(ResolverIntrinsicTest_Barrier, InferType) {
490 auto param = GetParam();
491
492 auto* call = Call(param.name);
493 WrapInFunction(CallStmt(call));
494
495 EXPECT_TRUE(r()->Resolve()) << r()->error();
496 ASSERT_NE(TypeOf(call), nullptr);
497 EXPECT_TRUE(TypeOf(call)->Is<sem::Void>());
498 }
499
TEST_P(ResolverIntrinsicTest_Barrier,Error_TooManyParams)500 TEST_P(ResolverIntrinsicTest_Barrier, Error_TooManyParams) {
501 auto param = GetParam();
502
503 auto* call = Call(param.name, vec4<f32>(1.f, 2.f, 3.f, 4.f), 1.0f);
504 WrapInFunction(CallStmt(call));
505
506 EXPECT_FALSE(r()->Resolve());
507
508 EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
509 std::string(param.name)));
510 }
511
512 INSTANTIATE_TEST_SUITE_P(
513 ResolverTest,
514 ResolverIntrinsicTest_Barrier,
515 testing::Values(
516 IntrinsicData{"storageBarrier", IntrinsicType::kStorageBarrier},
517 IntrinsicData{"workgroupBarrier", IntrinsicType::kWorkgroupBarrier}));
518
519 using ResolverIntrinsicTest_DataPacking = ResolverTestWithParam<IntrinsicData>;
TEST_P(ResolverIntrinsicTest_DataPacking,InferType)520 TEST_P(ResolverIntrinsicTest_DataPacking, InferType) {
521 auto param = GetParam();
522
523 bool pack4 = param.intrinsic == IntrinsicType::kPack4x8snorm ||
524 param.intrinsic == IntrinsicType::kPack4x8unorm;
525
526 auto* call = pack4 ? Call(param.name, vec4<f32>(1.f, 2.f, 3.f, 4.f))
527 : Call(param.name, vec2<f32>(1.f, 2.f));
528 WrapInFunction(call);
529
530 EXPECT_TRUE(r()->Resolve()) << r()->error();
531 ASSERT_NE(TypeOf(call), nullptr);
532 EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
533 }
534
TEST_P(ResolverIntrinsicTest_DataPacking,Error_IncorrectParamType)535 TEST_P(ResolverIntrinsicTest_DataPacking, Error_IncorrectParamType) {
536 auto param = GetParam();
537
538 bool pack4 = param.intrinsic == IntrinsicType::kPack4x8snorm ||
539 param.intrinsic == IntrinsicType::kPack4x8unorm;
540
541 auto* call = pack4 ? Call(param.name, vec4<i32>(1, 2, 3, 4))
542 : Call(param.name, vec2<i32>(1, 2));
543 WrapInFunction(call);
544
545 EXPECT_FALSE(r()->Resolve());
546
547 EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
548 std::string(param.name)));
549 }
550
TEST_P(ResolverIntrinsicTest_DataPacking,Error_NoParams)551 TEST_P(ResolverIntrinsicTest_DataPacking, Error_NoParams) {
552 auto param = GetParam();
553
554 auto* call = Call(param.name);
555 WrapInFunction(call);
556
557 EXPECT_FALSE(r()->Resolve());
558
559 EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
560 std::string(param.name)));
561 }
562
TEST_P(ResolverIntrinsicTest_DataPacking,Error_TooManyParams)563 TEST_P(ResolverIntrinsicTest_DataPacking, Error_TooManyParams) {
564 auto param = GetParam();
565
566 bool pack4 = param.intrinsic == IntrinsicType::kPack4x8snorm ||
567 param.intrinsic == IntrinsicType::kPack4x8unorm;
568
569 auto* call = pack4 ? Call(param.name, vec4<f32>(1.f, 2.f, 3.f, 4.f), 1.0f)
570 : Call(param.name, vec2<f32>(1.f, 2.f), 1.0f);
571 WrapInFunction(call);
572
573 EXPECT_FALSE(r()->Resolve());
574
575 EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
576 std::string(param.name)));
577 }
578
579 INSTANTIATE_TEST_SUITE_P(
580 ResolverTest,
581 ResolverIntrinsicTest_DataPacking,
582 testing::Values(
583 IntrinsicData{"pack4x8snorm", IntrinsicType::kPack4x8snorm},
584 IntrinsicData{"pack4x8unorm", IntrinsicType::kPack4x8unorm},
585 IntrinsicData{"pack2x16snorm", IntrinsicType::kPack2x16snorm},
586 IntrinsicData{"pack2x16unorm", IntrinsicType::kPack2x16unorm},
587 IntrinsicData{"pack2x16float", IntrinsicType::kPack2x16float}));
588
589 using ResolverIntrinsicTest_DataUnpacking =
590 ResolverTestWithParam<IntrinsicData>;
TEST_P(ResolverIntrinsicTest_DataUnpacking,InferType)591 TEST_P(ResolverIntrinsicTest_DataUnpacking, InferType) {
592 auto param = GetParam();
593
594 bool pack4 = param.intrinsic == IntrinsicType::kUnpack4x8snorm ||
595 param.intrinsic == IntrinsicType::kUnpack4x8unorm;
596
597 auto* call = Call(param.name, 1u);
598 WrapInFunction(call);
599
600 EXPECT_TRUE(r()->Resolve()) << r()->error();
601 ASSERT_NE(TypeOf(call), nullptr);
602 EXPECT_TRUE(TypeOf(call)->is_float_vector());
603 if (pack4) {
604 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 4u);
605 } else {
606 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 2u);
607 }
608 }
609
610 INSTANTIATE_TEST_SUITE_P(
611 ResolverTest,
612 ResolverIntrinsicTest_DataUnpacking,
613 testing::Values(
614 IntrinsicData{"unpack4x8snorm", IntrinsicType::kUnpack4x8snorm},
615 IntrinsicData{"unpack4x8unorm", IntrinsicType::kUnpack4x8unorm},
616 IntrinsicData{"unpack2x16snorm", IntrinsicType::kUnpack2x16snorm},
617 IntrinsicData{"unpack2x16unorm", IntrinsicType::kUnpack2x16unorm},
618 IntrinsicData{"unpack2x16float", IntrinsicType::kUnpack2x16float}));
619
620 using ResolverIntrinsicTest_SingleParam = ResolverTestWithParam<IntrinsicData>;
TEST_P(ResolverIntrinsicTest_SingleParam,Scalar)621 TEST_P(ResolverIntrinsicTest_SingleParam, Scalar) {
622 auto param = GetParam();
623
624 auto* call = Call(param.name, 1.f);
625 WrapInFunction(call);
626
627 EXPECT_TRUE(r()->Resolve()) << r()->error();
628
629 ASSERT_NE(TypeOf(call), nullptr);
630 EXPECT_TRUE(TypeOf(call)->is_float_scalar());
631 }
632
TEST_P(ResolverIntrinsicTest_SingleParam,Vector)633 TEST_P(ResolverIntrinsicTest_SingleParam, Vector) {
634 auto param = GetParam();
635
636 auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f));
637 WrapInFunction(call);
638
639 EXPECT_TRUE(r()->Resolve()) << r()->error();
640
641 ASSERT_NE(TypeOf(call), nullptr);
642 EXPECT_TRUE(TypeOf(call)->is_float_vector());
643 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
644 }
645
TEST_P(ResolverIntrinsicTest_SingleParam,Error_NoParams)646 TEST_P(ResolverIntrinsicTest_SingleParam, Error_NoParams) {
647 auto param = GetParam();
648
649 auto* call = Call(param.name);
650 WrapInFunction(call);
651
652 EXPECT_FALSE(r()->Resolve());
653
654 EXPECT_EQ(r()->error(),
655 "error: no matching call to " + std::string(param.name) +
656 "()\n\n"
657 "2 candidate functions:\n " +
658 std::string(param.name) + "(f32) -> f32\n " +
659 std::string(param.name) + "(vecN<f32>) -> vecN<f32>\n");
660 }
661
TEST_P(ResolverIntrinsicTest_SingleParam,Error_TooManyParams)662 TEST_P(ResolverIntrinsicTest_SingleParam, Error_TooManyParams) {
663 auto param = GetParam();
664
665 auto* call = Call(param.name, 1, 2, 3);
666 WrapInFunction(call);
667
668 EXPECT_FALSE(r()->Resolve());
669
670 EXPECT_EQ(r()->error(),
671 "error: no matching call to " + std::string(param.name) +
672 "(i32, i32, i32)\n\n"
673 "2 candidate functions:\n " +
674 std::string(param.name) + "(f32) -> f32\n " +
675 std::string(param.name) + "(vecN<f32>) -> vecN<f32>\n");
676 }
677
678 INSTANTIATE_TEST_SUITE_P(
679 ResolverTest,
680 ResolverIntrinsicTest_SingleParam,
681 testing::Values(IntrinsicData{"acos", IntrinsicType::kAcos},
682 IntrinsicData{"asin", IntrinsicType::kAsin},
683 IntrinsicData{"atan", IntrinsicType::kAtan},
684 IntrinsicData{"ceil", IntrinsicType::kCeil},
685 IntrinsicData{"cos", IntrinsicType::kCos},
686 IntrinsicData{"cosh", IntrinsicType::kCosh},
687 IntrinsicData{"exp", IntrinsicType::kExp},
688 IntrinsicData{"exp2", IntrinsicType::kExp2},
689 IntrinsicData{"floor", IntrinsicType::kFloor},
690 IntrinsicData{"fract", IntrinsicType::kFract},
691 IntrinsicData{"inverseSqrt", IntrinsicType::kInverseSqrt},
692 IntrinsicData{"log", IntrinsicType::kLog},
693 IntrinsicData{"log2", IntrinsicType::kLog2},
694 IntrinsicData{"round", IntrinsicType::kRound},
695 IntrinsicData{"sign", IntrinsicType::kSign},
696 IntrinsicData{"sin", IntrinsicType::kSin},
697 IntrinsicData{"sinh", IntrinsicType::kSinh},
698 IntrinsicData{"sqrt", IntrinsicType::kSqrt},
699 IntrinsicData{"tan", IntrinsicType::kTan},
700 IntrinsicData{"tanh", IntrinsicType::kTanh},
701 IntrinsicData{"trunc", IntrinsicType::kTrunc}));
702
703 using ResolverIntrinsicDataTest = ResolverTest;
704
TEST_F(ResolverIntrinsicDataTest,ArrayLength_Vector)705 TEST_F(ResolverIntrinsicDataTest, ArrayLength_Vector) {
706 auto* ary = ty.array<i32>();
707 auto* str = Structure("S", {Member("x", ary)},
708 {create<ast::StructBlockDecoration>()});
709 Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
710 ast::DecorationList{
711 create<ast::BindingDecoration>(0),
712 create<ast::GroupDecoration>(0),
713 });
714
715 auto* call = Call("arrayLength", AddressOf(MemberAccessor("a", "x")));
716 WrapInFunction(call);
717
718 EXPECT_TRUE(r()->Resolve()) << r()->error();
719
720 ASSERT_NE(TypeOf(call), nullptr);
721 EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
722 }
723
TEST_F(ResolverIntrinsicDataTest,ArrayLength_Error_ArraySized)724 TEST_F(ResolverIntrinsicDataTest, ArrayLength_Error_ArraySized) {
725 Global("arr", ty.array<int, 4>(), ast::StorageClass::kPrivate);
726 auto* call = Call("arrayLength", AddressOf("arr"));
727 WrapInFunction(call);
728
729 EXPECT_FALSE(r()->Resolve());
730
731 EXPECT_EQ(
732 r()->error(),
733 R"(error: no matching call to arrayLength(ptr<private, array<i32, 4>, read_write>)
734
735 1 candidate function:
736 arrayLength(ptr<storage, array<T>, A>) -> u32
737 )");
738 }
739
TEST_F(ResolverIntrinsicDataTest,Normalize_Vector)740 TEST_F(ResolverIntrinsicDataTest, Normalize_Vector) {
741 auto* call = Call("normalize", vec3<f32>(1.0f, 1.0f, 3.0f));
742 WrapInFunction(call);
743
744 EXPECT_TRUE(r()->Resolve()) << r()->error();
745
746 ASSERT_NE(TypeOf(call), nullptr);
747 EXPECT_TRUE(TypeOf(call)->is_float_vector());
748 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
749 }
750
TEST_F(ResolverIntrinsicDataTest,Normalize_Error_NoParams)751 TEST_F(ResolverIntrinsicDataTest, Normalize_Error_NoParams) {
752 auto* call = Call("normalize");
753 WrapInFunction(call);
754
755 EXPECT_FALSE(r()->Resolve());
756
757 EXPECT_EQ(r()->error(), R"(error: no matching call to normalize()
758
759 1 candidate function:
760 normalize(vecN<f32>) -> vecN<f32>
761 )");
762 }
763
TEST_F(ResolverIntrinsicDataTest,FrexpScalar)764 TEST_F(ResolverIntrinsicDataTest, FrexpScalar) {
765 auto* call = Call("frexp", 1.0f);
766 WrapInFunction(call);
767
768 EXPECT_TRUE(r()->Resolve()) << r()->error();
769
770 ASSERT_NE(TypeOf(call), nullptr);
771 auto* ty = TypeOf(call)->As<sem::Struct>();
772 ASSERT_NE(ty, nullptr);
773 ASSERT_EQ(ty->Members().size(), 2u);
774
775 auto* sig = ty->Members()[0];
776 EXPECT_TRUE(sig->Type()->Is<sem::F32>());
777 EXPECT_EQ(sig->Offset(), 0u);
778 EXPECT_EQ(sig->Size(), 4u);
779 EXPECT_EQ(sig->Align(), 4u);
780 EXPECT_EQ(sig->Name(), Sym("sig"));
781
782 auto* exp = ty->Members()[1];
783 EXPECT_TRUE(exp->Type()->Is<sem::I32>());
784 EXPECT_EQ(exp->Offset(), 4u);
785 EXPECT_EQ(exp->Size(), 4u);
786 EXPECT_EQ(exp->Align(), 4u);
787 EXPECT_EQ(exp->Name(), Sym("exp"));
788
789 EXPECT_EQ(ty->Size(), 8u);
790 EXPECT_EQ(ty->SizeNoPadding(), 8u);
791 }
792
TEST_F(ResolverIntrinsicDataTest,FrexpVector)793 TEST_F(ResolverIntrinsicDataTest, FrexpVector) {
794 auto* call = Call("frexp", vec3<f32>());
795 WrapInFunction(call);
796
797 EXPECT_TRUE(r()->Resolve()) << r()->error();
798
799 ASSERT_NE(TypeOf(call), nullptr);
800 auto* ty = TypeOf(call)->As<sem::Struct>();
801 ASSERT_NE(ty, nullptr);
802 ASSERT_EQ(ty->Members().size(), 2u);
803
804 auto* sig = ty->Members()[0];
805 ASSERT_TRUE(sig->Type()->Is<sem::Vector>());
806 EXPECT_EQ(sig->Type()->As<sem::Vector>()->Width(), 3u);
807 EXPECT_TRUE(sig->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
808 EXPECT_EQ(sig->Offset(), 0u);
809 EXPECT_EQ(sig->Size(), 12u);
810 EXPECT_EQ(sig->Align(), 16u);
811 EXPECT_EQ(sig->Name(), Sym("sig"));
812
813 auto* exp = ty->Members()[1];
814 ASSERT_TRUE(exp->Type()->Is<sem::Vector>());
815 EXPECT_EQ(exp->Type()->As<sem::Vector>()->Width(), 3u);
816 EXPECT_TRUE(exp->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
817 EXPECT_EQ(exp->Offset(), 16u);
818 EXPECT_EQ(exp->Size(), 12u);
819 EXPECT_EQ(exp->Align(), 16u);
820 EXPECT_EQ(exp->Name(), Sym("exp"));
821
822 EXPECT_EQ(ty->Size(), 32u);
823 EXPECT_EQ(ty->SizeNoPadding(), 28u);
824 }
825
TEST_F(ResolverIntrinsicDataTest,Frexp_Error_FirstParamInt)826 TEST_F(ResolverIntrinsicDataTest, Frexp_Error_FirstParamInt) {
827 Global("v", ty.i32(), ast::StorageClass::kWorkgroup);
828 auto* call = Call("frexp", 1, AddressOf("v"));
829 WrapInFunction(call);
830
831 EXPECT_FALSE(r()->Resolve());
832
833 EXPECT_EQ(
834 r()->error(),
835 R"(error: no matching call to frexp(i32, ptr<workgroup, i32, read_write>)
836
837 2 candidate functions:
838 frexp(f32) -> __frexp_result
839 frexp(vecN<f32>) -> __frexp_result_vecN
840 )");
841 }
842
TEST_F(ResolverIntrinsicDataTest,Frexp_Error_SecondParamFloatPtr)843 TEST_F(ResolverIntrinsicDataTest, Frexp_Error_SecondParamFloatPtr) {
844 Global("v", ty.f32(), ast::StorageClass::kWorkgroup);
845 auto* call = Call("frexp", 1.0f, AddressOf("v"));
846 WrapInFunction(call);
847
848 EXPECT_FALSE(r()->Resolve());
849
850 EXPECT_EQ(
851 r()->error(),
852 R"(error: no matching call to frexp(f32, ptr<workgroup, f32, read_write>)
853
854 2 candidate functions:
855 frexp(f32) -> __frexp_result
856 frexp(vecN<f32>) -> __frexp_result_vecN
857 )");
858 }
859
TEST_F(ResolverIntrinsicDataTest,Frexp_Error_SecondParamNotAPointer)860 TEST_F(ResolverIntrinsicDataTest, Frexp_Error_SecondParamNotAPointer) {
861 auto* call = Call("frexp", 1.0f, 1);
862 WrapInFunction(call);
863
864 EXPECT_FALSE(r()->Resolve());
865
866 EXPECT_EQ(r()->error(), R"(error: no matching call to frexp(f32, i32)
867
868 2 candidate functions:
869 frexp(f32) -> __frexp_result
870 frexp(vecN<f32>) -> __frexp_result_vecN
871 )");
872 }
873
TEST_F(ResolverIntrinsicDataTest,Frexp_Error_VectorSizesDontMatch)874 TEST_F(ResolverIntrinsicDataTest, Frexp_Error_VectorSizesDontMatch) {
875 Global("v", ty.vec4<i32>(), ast::StorageClass::kWorkgroup);
876 auto* call = Call("frexp", vec2<f32>(1.0f, 2.0f), AddressOf("v"));
877 WrapInFunction(call);
878
879 EXPECT_FALSE(r()->Resolve());
880
881 EXPECT_EQ(
882 r()->error(),
883 R"(error: no matching call to frexp(vec2<f32>, ptr<workgroup, vec4<i32>, read_write>)
884
885 2 candidate functions:
886 frexp(vecN<f32>) -> __frexp_result_vecN
887 frexp(f32) -> __frexp_result
888 )");
889 }
890
TEST_F(ResolverIntrinsicDataTest,ModfScalar)891 TEST_F(ResolverIntrinsicDataTest, ModfScalar) {
892 auto* call = Call("modf", 1.0f);
893 WrapInFunction(call);
894
895 EXPECT_TRUE(r()->Resolve()) << r()->error();
896
897 ASSERT_NE(TypeOf(call), nullptr);
898 auto* ty = TypeOf(call)->As<sem::Struct>();
899 ASSERT_NE(ty, nullptr);
900 ASSERT_EQ(ty->Members().size(), 2u);
901
902 auto* fract = ty->Members()[0];
903 EXPECT_TRUE(fract->Type()->Is<sem::F32>());
904 EXPECT_EQ(fract->Offset(), 0u);
905 EXPECT_EQ(fract->Size(), 4u);
906 EXPECT_EQ(fract->Align(), 4u);
907 EXPECT_EQ(fract->Name(), Sym("fract"));
908
909 auto* whole = ty->Members()[1];
910 EXPECT_TRUE(whole->Type()->Is<sem::F32>());
911 EXPECT_EQ(whole->Offset(), 4u);
912 EXPECT_EQ(whole->Size(), 4u);
913 EXPECT_EQ(whole->Align(), 4u);
914 EXPECT_EQ(whole->Name(), Sym("whole"));
915
916 EXPECT_EQ(ty->Size(), 8u);
917 EXPECT_EQ(ty->SizeNoPadding(), 8u);
918 }
919
TEST_F(ResolverIntrinsicDataTest,ModfVector)920 TEST_F(ResolverIntrinsicDataTest, ModfVector) {
921 auto* call = Call("modf", vec3<f32>());
922 WrapInFunction(call);
923
924 EXPECT_TRUE(r()->Resolve()) << r()->error();
925
926 ASSERT_NE(TypeOf(call), nullptr);
927 auto* ty = TypeOf(call)->As<sem::Struct>();
928 ASSERT_NE(ty, nullptr);
929 ASSERT_EQ(ty->Members().size(), 2u);
930
931 auto* fract = ty->Members()[0];
932 ASSERT_TRUE(fract->Type()->Is<sem::Vector>());
933 EXPECT_EQ(fract->Type()->As<sem::Vector>()->Width(), 3u);
934 EXPECT_TRUE(fract->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
935 EXPECT_EQ(fract->Offset(), 0u);
936 EXPECT_EQ(fract->Size(), 12u);
937 EXPECT_EQ(fract->Align(), 16u);
938 EXPECT_EQ(fract->Name(), Sym("fract"));
939
940 auto* whole = ty->Members()[1];
941 ASSERT_TRUE(whole->Type()->Is<sem::Vector>());
942 EXPECT_EQ(whole->Type()->As<sem::Vector>()->Width(), 3u);
943 EXPECT_TRUE(whole->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
944 EXPECT_EQ(whole->Offset(), 16u);
945 EXPECT_EQ(whole->Size(), 12u);
946 EXPECT_EQ(whole->Align(), 16u);
947 EXPECT_EQ(whole->Name(), Sym("whole"));
948
949 EXPECT_EQ(ty->Size(), 32u);
950 EXPECT_EQ(ty->SizeNoPadding(), 28u);
951 }
952
TEST_F(ResolverIntrinsicDataTest,Modf_Error_FirstParamInt)953 TEST_F(ResolverIntrinsicDataTest, Modf_Error_FirstParamInt) {
954 Global("whole", ty.f32(), ast::StorageClass::kWorkgroup);
955 auto* call = Call("modf", 1, AddressOf("whole"));
956 WrapInFunction(call);
957
958 EXPECT_FALSE(r()->Resolve());
959
960 EXPECT_EQ(
961 r()->error(),
962 R"(error: no matching call to modf(i32, ptr<workgroup, f32, read_write>)
963
964 2 candidate functions:
965 modf(f32) -> __modf_result
966 modf(vecN<f32>) -> __modf_result_vecN
967 )");
968 }
969
TEST_F(ResolverIntrinsicDataTest,Modf_Error_SecondParamIntPtr)970 TEST_F(ResolverIntrinsicDataTest, Modf_Error_SecondParamIntPtr) {
971 Global("whole", ty.i32(), ast::StorageClass::kWorkgroup);
972 auto* call = Call("modf", 1.0f, AddressOf("whole"));
973 WrapInFunction(call);
974
975 EXPECT_FALSE(r()->Resolve());
976
977 EXPECT_EQ(
978 r()->error(),
979 R"(error: no matching call to modf(f32, ptr<workgroup, i32, read_write>)
980
981 2 candidate functions:
982 modf(f32) -> __modf_result
983 modf(vecN<f32>) -> __modf_result_vecN
984 )");
985 }
986
TEST_F(ResolverIntrinsicDataTest,Modf_Error_SecondParamNotAPointer)987 TEST_F(ResolverIntrinsicDataTest, Modf_Error_SecondParamNotAPointer) {
988 auto* call = Call("modf", 1.0f, 1.0f);
989 WrapInFunction(call);
990
991 EXPECT_FALSE(r()->Resolve());
992
993 EXPECT_EQ(r()->error(), R"(error: no matching call to modf(f32, f32)
994
995 2 candidate functions:
996 modf(f32) -> __modf_result
997 modf(vecN<f32>) -> __modf_result_vecN
998 )");
999 }
1000
TEST_F(ResolverIntrinsicDataTest,Modf_Error_VectorSizesDontMatch)1001 TEST_F(ResolverIntrinsicDataTest, Modf_Error_VectorSizesDontMatch) {
1002 Global("whole", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
1003 auto* call = Call("modf", vec2<f32>(1.0f, 2.0f), AddressOf("whole"));
1004 WrapInFunction(call);
1005
1006 EXPECT_FALSE(r()->Resolve());
1007
1008 EXPECT_EQ(
1009 r()->error(),
1010 R"(error: no matching call to modf(vec2<f32>, ptr<workgroup, vec4<f32>, read_write>)
1011
1012 2 candidate functions:
1013 modf(vecN<f32>) -> __modf_result_vecN
1014 modf(f32) -> __modf_result
1015 )");
1016 }
1017
1018 using ResolverIntrinsicTest_SingleParam_FloatOrInt =
1019 ResolverTestWithParam<IntrinsicData>;
TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt,Float_Scalar)1020 TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt, Float_Scalar) {
1021 auto param = GetParam();
1022
1023 auto* call = Call(param.name, 1.f);
1024 WrapInFunction(call);
1025
1026 EXPECT_TRUE(r()->Resolve()) << r()->error();
1027
1028 ASSERT_NE(TypeOf(call), nullptr);
1029 EXPECT_TRUE(TypeOf(call)->is_float_scalar());
1030 }
1031
TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt,Float_Vector)1032 TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt, Float_Vector) {
1033 auto param = GetParam();
1034
1035 auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f));
1036 WrapInFunction(call);
1037
1038 EXPECT_TRUE(r()->Resolve()) << r()->error();
1039
1040 ASSERT_NE(TypeOf(call), nullptr);
1041 EXPECT_TRUE(TypeOf(call)->is_float_vector());
1042 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1043 }
1044
TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt,Sint_Scalar)1045 TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt, Sint_Scalar) {
1046 auto param = GetParam();
1047
1048 auto* call = Call(param.name, -1);
1049 WrapInFunction(call);
1050
1051 EXPECT_TRUE(r()->Resolve()) << r()->error();
1052
1053 ASSERT_NE(TypeOf(call), nullptr);
1054 EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
1055 }
1056
TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt,Sint_Vector)1057 TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt, Sint_Vector) {
1058 auto param = GetParam();
1059
1060 auto* call = Call(param.name, vec3<i32>(1, 1, 3));
1061 WrapInFunction(call);
1062
1063 EXPECT_TRUE(r()->Resolve()) << r()->error();
1064
1065 ASSERT_NE(TypeOf(call), nullptr);
1066 EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
1067 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1068 }
1069
TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt,Uint_Scalar)1070 TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt, Uint_Scalar) {
1071 auto param = GetParam();
1072
1073 auto* call = Call(param.name, 1u);
1074 WrapInFunction(call);
1075
1076 EXPECT_TRUE(r()->Resolve()) << r()->error();
1077
1078 ASSERT_NE(TypeOf(call), nullptr);
1079 EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
1080 }
1081
TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt,Uint_Vector)1082 TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt, Uint_Vector) {
1083 auto param = GetParam();
1084
1085 auto* call = Call(param.name, vec3<u32>(1u, 1u, 3u));
1086 WrapInFunction(call);
1087
1088 EXPECT_TRUE(r()->Resolve()) << r()->error();
1089
1090 ASSERT_NE(TypeOf(call), nullptr);
1091 EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
1092 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1093 }
1094
TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt,Error_NoParams)1095 TEST_P(ResolverIntrinsicTest_SingleParam_FloatOrInt, Error_NoParams) {
1096 auto param = GetParam();
1097
1098 auto* call = Call(param.name);
1099 WrapInFunction(call);
1100
1101 EXPECT_FALSE(r()->Resolve());
1102
1103 EXPECT_EQ(r()->error(),
1104 "error: no matching call to " + std::string(param.name) +
1105 "()\n\n"
1106 "2 candidate functions:\n " +
1107 std::string(param.name) +
1108 "(T) -> T where: T is f32, i32 or u32\n " +
1109 std::string(param.name) +
1110 "(vecN<T>) -> vecN<T> where: T is f32, i32 or u32\n");
1111 }
1112
1113 INSTANTIATE_TEST_SUITE_P(ResolverTest,
1114 ResolverIntrinsicTest_SingleParam_FloatOrInt,
1115 testing::Values(IntrinsicData{"abs",
1116 IntrinsicType::kAbs}));
1117
TEST_F(ResolverIntrinsicTest,Length_Scalar)1118 TEST_F(ResolverIntrinsicTest, Length_Scalar) {
1119 auto* call = Call("length", 1.f);
1120 WrapInFunction(call);
1121
1122 EXPECT_TRUE(r()->Resolve()) << r()->error();
1123
1124 ASSERT_NE(TypeOf(call), nullptr);
1125 EXPECT_TRUE(TypeOf(call)->is_float_scalar());
1126 }
1127
TEST_F(ResolverIntrinsicTest,Length_FloatVector)1128 TEST_F(ResolverIntrinsicTest, Length_FloatVector) {
1129 auto* call = Call("length", vec3<f32>(1.0f, 1.0f, 3.0f));
1130 WrapInFunction(call);
1131
1132 EXPECT_TRUE(r()->Resolve()) << r()->error();
1133
1134 ASSERT_NE(TypeOf(call), nullptr);
1135 EXPECT_TRUE(TypeOf(call)->is_float_scalar());
1136 }
1137
1138 using ResolverIntrinsicTest_TwoParam = ResolverTestWithParam<IntrinsicData>;
TEST_P(ResolverIntrinsicTest_TwoParam,Scalar)1139 TEST_P(ResolverIntrinsicTest_TwoParam, Scalar) {
1140 auto param = GetParam();
1141
1142 auto* call = Call(param.name, 1.f, 1.f);
1143 WrapInFunction(call);
1144
1145 EXPECT_TRUE(r()->Resolve()) << r()->error();
1146
1147 ASSERT_NE(TypeOf(call), nullptr);
1148 EXPECT_TRUE(TypeOf(call)->is_float_scalar());
1149 }
1150
TEST_P(ResolverIntrinsicTest_TwoParam,Vector)1151 TEST_P(ResolverIntrinsicTest_TwoParam, Vector) {
1152 auto param = GetParam();
1153
1154 auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f),
1155 vec3<f32>(1.0f, 1.0f, 3.0f));
1156 WrapInFunction(call);
1157
1158 EXPECT_TRUE(r()->Resolve()) << r()->error();
1159
1160 ASSERT_NE(TypeOf(call), nullptr);
1161 EXPECT_TRUE(TypeOf(call)->is_float_vector());
1162 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1163 }
1164
TEST_P(ResolverIntrinsicTest_TwoParam,Error_NoTooManyParams)1165 TEST_P(ResolverIntrinsicTest_TwoParam, Error_NoTooManyParams) {
1166 auto param = GetParam();
1167
1168 auto* call = Call(param.name, 1, 2, 3);
1169 WrapInFunction(call);
1170
1171 EXPECT_FALSE(r()->Resolve());
1172
1173 EXPECT_EQ(r()->error(),
1174 "error: no matching call to " + std::string(param.name) +
1175 "(i32, i32, i32)\n\n"
1176 "2 candidate functions:\n " +
1177 std::string(param.name) + "(f32, f32) -> f32\n " +
1178 std::string(param.name) +
1179 "(vecN<f32>, vecN<f32>) -> vecN<f32>\n");
1180 }
1181
TEST_P(ResolverIntrinsicTest_TwoParam,Error_NoParams)1182 TEST_P(ResolverIntrinsicTest_TwoParam, Error_NoParams) {
1183 auto param = GetParam();
1184
1185 auto* call = Call(param.name);
1186 WrapInFunction(call);
1187
1188 EXPECT_FALSE(r()->Resolve());
1189
1190 EXPECT_EQ(r()->error(),
1191 "error: no matching call to " + std::string(param.name) +
1192 "()\n\n"
1193 "2 candidate functions:\n " +
1194 std::string(param.name) + "(f32, f32) -> f32\n " +
1195 std::string(param.name) +
1196 "(vecN<f32>, vecN<f32>) -> vecN<f32>\n");
1197 }
1198
1199 INSTANTIATE_TEST_SUITE_P(
1200 ResolverTest,
1201 ResolverIntrinsicTest_TwoParam,
1202 testing::Values(IntrinsicData{"atan2", IntrinsicType::kAtan2},
1203 IntrinsicData{"pow", IntrinsicType::kPow},
1204 IntrinsicData{"step", IntrinsicType::kStep}));
1205
TEST_F(ResolverIntrinsicTest,Distance_Scalar)1206 TEST_F(ResolverIntrinsicTest, Distance_Scalar) {
1207 auto* call = Call("distance", 1.f, 1.f);
1208 WrapInFunction(call);
1209
1210 EXPECT_TRUE(r()->Resolve()) << r()->error();
1211
1212 ASSERT_NE(TypeOf(call), nullptr);
1213 EXPECT_TRUE(TypeOf(call)->is_float_scalar());
1214 }
1215
TEST_F(ResolverIntrinsicTest,Distance_Vector)1216 TEST_F(ResolverIntrinsicTest, Distance_Vector) {
1217 auto* call = Call("distance", vec3<f32>(1.0f, 1.0f, 3.0f),
1218 vec3<f32>(1.0f, 1.0f, 3.0f));
1219 WrapInFunction(call);
1220
1221 EXPECT_TRUE(r()->Resolve()) << r()->error();
1222
1223 ASSERT_NE(TypeOf(call), nullptr);
1224 EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
1225 }
1226
TEST_F(ResolverIntrinsicTest,Cross)1227 TEST_F(ResolverIntrinsicTest, Cross) {
1228 auto* call =
1229 Call("cross", vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(1.0f, 2.0f, 3.0f));
1230 WrapInFunction(call);
1231
1232 EXPECT_TRUE(r()->Resolve()) << r()->error();
1233
1234 ASSERT_NE(TypeOf(call), nullptr);
1235 EXPECT_TRUE(TypeOf(call)->is_float_vector());
1236 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1237 }
1238
TEST_F(ResolverIntrinsicTest,Cross_Error_NoArgs)1239 TEST_F(ResolverIntrinsicTest, Cross_Error_NoArgs) {
1240 auto* call = Call("cross");
1241 WrapInFunction(call);
1242
1243 EXPECT_FALSE(r()->Resolve());
1244
1245 EXPECT_EQ(r()->error(), R"(error: no matching call to cross()
1246
1247 1 candidate function:
1248 cross(vec3<f32>, vec3<f32>) -> vec3<f32>
1249 )");
1250 }
1251
TEST_F(ResolverIntrinsicTest,Cross_Error_Scalar)1252 TEST_F(ResolverIntrinsicTest, Cross_Error_Scalar) {
1253 auto* call = Call("cross", 1.0f, 1.0f);
1254 WrapInFunction(call);
1255
1256 EXPECT_FALSE(r()->Resolve());
1257
1258 EXPECT_EQ(r()->error(), R"(error: no matching call to cross(f32, f32)
1259
1260 1 candidate function:
1261 cross(vec3<f32>, vec3<f32>) -> vec3<f32>
1262 )");
1263 }
1264
TEST_F(ResolverIntrinsicTest,Cross_Error_Vec3Int)1265 TEST_F(ResolverIntrinsicTest, Cross_Error_Vec3Int) {
1266 auto* call = Call("cross", vec3<i32>(1, 2, 3), vec3<i32>(1, 2, 3));
1267 WrapInFunction(call);
1268
1269 EXPECT_FALSE(r()->Resolve());
1270
1271 EXPECT_EQ(r()->error(),
1272 R"(error: no matching call to cross(vec3<i32>, vec3<i32>)
1273
1274 1 candidate function:
1275 cross(vec3<f32>, vec3<f32>) -> vec3<f32>
1276 )");
1277 }
1278
TEST_F(ResolverIntrinsicTest,Cross_Error_Vec4)1279 TEST_F(ResolverIntrinsicTest, Cross_Error_Vec4) {
1280 auto* call = Call("cross", vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f),
1281 vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f));
1282
1283 WrapInFunction(call);
1284
1285 EXPECT_FALSE(r()->Resolve());
1286
1287 EXPECT_EQ(r()->error(),
1288 R"(error: no matching call to cross(vec4<f32>, vec4<f32>)
1289
1290 1 candidate function:
1291 cross(vec3<f32>, vec3<f32>) -> vec3<f32>
1292 )");
1293 }
1294
TEST_F(ResolverIntrinsicTest,Cross_Error_TooManyParams)1295 TEST_F(ResolverIntrinsicTest, Cross_Error_TooManyParams) {
1296 auto* call = Call("cross", vec3<f32>(1.0f, 2.0f, 3.0f),
1297 vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(1.0f, 2.0f, 3.0f));
1298
1299 WrapInFunction(call);
1300
1301 EXPECT_FALSE(r()->Resolve());
1302
1303 EXPECT_EQ(r()->error(),
1304 R"(error: no matching call to cross(vec3<f32>, vec3<f32>, vec3<f32>)
1305
1306 1 candidate function:
1307 cross(vec3<f32>, vec3<f32>) -> vec3<f32>
1308 )");
1309 }
TEST_F(ResolverIntrinsicTest,Normalize)1310 TEST_F(ResolverIntrinsicTest, Normalize) {
1311 auto* call = Call("normalize", vec3<f32>(1.0f, 1.0f, 3.0f));
1312 WrapInFunction(call);
1313
1314 EXPECT_TRUE(r()->Resolve()) << r()->error();
1315
1316 ASSERT_NE(TypeOf(call), nullptr);
1317 EXPECT_TRUE(TypeOf(call)->is_float_vector());
1318 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1319 }
1320
TEST_F(ResolverIntrinsicTest,Normalize_NoArgs)1321 TEST_F(ResolverIntrinsicTest, Normalize_NoArgs) {
1322 auto* call = Call("normalize");
1323 WrapInFunction(call);
1324
1325 EXPECT_FALSE(r()->Resolve());
1326
1327 EXPECT_EQ(r()->error(), R"(error: no matching call to normalize()
1328
1329 1 candidate function:
1330 normalize(vecN<f32>) -> vecN<f32>
1331 )");
1332 }
1333
1334 using ResolverIntrinsicTest_ThreeParam = ResolverTestWithParam<IntrinsicData>;
TEST_P(ResolverIntrinsicTest_ThreeParam,Scalar)1335 TEST_P(ResolverIntrinsicTest_ThreeParam, Scalar) {
1336 auto param = GetParam();
1337
1338 auto* call = Call(param.name, 1.f, 1.f, 1.f);
1339 WrapInFunction(call);
1340
1341 EXPECT_TRUE(r()->Resolve()) << r()->error();
1342
1343 ASSERT_NE(TypeOf(call), nullptr);
1344 EXPECT_TRUE(TypeOf(call)->is_float_scalar());
1345 }
1346
TEST_P(ResolverIntrinsicTest_ThreeParam,Vector)1347 TEST_P(ResolverIntrinsicTest_ThreeParam, Vector) {
1348 auto param = GetParam();
1349
1350 auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f),
1351 vec3<f32>(1.0f, 1.0f, 3.0f), vec3<f32>(1.0f, 1.0f, 3.0f));
1352 WrapInFunction(call);
1353
1354 EXPECT_TRUE(r()->Resolve()) << r()->error();
1355
1356 ASSERT_NE(TypeOf(call), nullptr);
1357 EXPECT_TRUE(TypeOf(call)->is_float_vector());
1358 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1359 }
TEST_P(ResolverIntrinsicTest_ThreeParam,Error_NoParams)1360 TEST_P(ResolverIntrinsicTest_ThreeParam, Error_NoParams) {
1361 auto param = GetParam();
1362
1363 auto* call = Call(param.name);
1364 WrapInFunction(call);
1365
1366 EXPECT_FALSE(r()->Resolve());
1367
1368 EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
1369 std::string(param.name) + "()"));
1370 }
1371
1372 INSTANTIATE_TEST_SUITE_P(
1373 ResolverTest,
1374 ResolverIntrinsicTest_ThreeParam,
1375 testing::Values(IntrinsicData{"mix", IntrinsicType::kMix},
1376 IntrinsicData{"smoothStep", IntrinsicType::kSmoothStep},
1377 IntrinsicData{"fma", IntrinsicType::kFma}));
1378
1379 using ResolverIntrinsicTest_ThreeParam_FloatOrInt =
1380 ResolverTestWithParam<IntrinsicData>;
TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt,Float_Scalar)1381 TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt, Float_Scalar) {
1382 auto param = GetParam();
1383
1384 auto* call = Call(param.name, 1.f, 1.f, 1.f);
1385 WrapInFunction(call);
1386
1387 EXPECT_TRUE(r()->Resolve()) << r()->error();
1388
1389 ASSERT_NE(TypeOf(call), nullptr);
1390 EXPECT_TRUE(TypeOf(call)->is_float_scalar());
1391 }
1392
TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt,Float_Vector)1393 TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt, Float_Vector) {
1394 auto param = GetParam();
1395
1396 auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f),
1397 vec3<f32>(1.0f, 1.0f, 3.0f), vec3<f32>(1.0f, 1.0f, 3.0f));
1398 WrapInFunction(call);
1399
1400 EXPECT_TRUE(r()->Resolve()) << r()->error();
1401
1402 ASSERT_NE(TypeOf(call), nullptr);
1403 EXPECT_TRUE(TypeOf(call)->is_float_vector());
1404 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1405 }
1406
TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt,Sint_Scalar)1407 TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt, Sint_Scalar) {
1408 auto param = GetParam();
1409
1410 auto* call = Call(param.name, 1, 1, 1);
1411 WrapInFunction(call);
1412
1413 EXPECT_TRUE(r()->Resolve()) << r()->error();
1414
1415 ASSERT_NE(TypeOf(call), nullptr);
1416 EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
1417 }
1418
TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt,Sint_Vector)1419 TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt, Sint_Vector) {
1420 auto param = GetParam();
1421
1422 auto* call = Call(param.name, vec3<i32>(1, 1, 3), vec3<i32>(1, 1, 3),
1423 vec3<i32>(1, 1, 3));
1424 WrapInFunction(call);
1425
1426 EXPECT_TRUE(r()->Resolve()) << r()->error();
1427
1428 ASSERT_NE(TypeOf(call), nullptr);
1429 EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
1430 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1431 }
1432
TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt,Uint_Scalar)1433 TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt, Uint_Scalar) {
1434 auto param = GetParam();
1435
1436 auto* call = Call(param.name, 1u, 1u, 1u);
1437 WrapInFunction(call);
1438
1439 EXPECT_TRUE(r()->Resolve()) << r()->error();
1440
1441 ASSERT_NE(TypeOf(call), nullptr);
1442 EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
1443 }
1444
TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt,Uint_Vector)1445 TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt, Uint_Vector) {
1446 auto param = GetParam();
1447
1448 auto* call = Call(param.name, vec3<u32>(1u, 1u, 3u), vec3<u32>(1u, 1u, 3u),
1449 vec3<u32>(1u, 1u, 3u));
1450 WrapInFunction(call);
1451
1452 EXPECT_TRUE(r()->Resolve()) << r()->error();
1453
1454 ASSERT_NE(TypeOf(call), nullptr);
1455 EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
1456 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1457 }
1458
TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt,Error_NoParams)1459 TEST_P(ResolverIntrinsicTest_ThreeParam_FloatOrInt, Error_NoParams) {
1460 auto param = GetParam();
1461
1462 auto* call = Call(param.name);
1463 WrapInFunction(call);
1464
1465 EXPECT_FALSE(r()->Resolve());
1466
1467 EXPECT_EQ(r()->error(),
1468 "error: no matching call to " + std::string(param.name) +
1469 "()\n\n"
1470 "2 candidate functions:\n " +
1471 std::string(param.name) +
1472 "(T, T, T) -> T where: T is f32, i32 or u32\n " +
1473 std::string(param.name) +
1474 "(vecN<T>, vecN<T>, vecN<T>) -> vecN<T> where: T is f32, i32 "
1475 "or u32\n");
1476 }
1477
1478 INSTANTIATE_TEST_SUITE_P(ResolverTest,
1479 ResolverIntrinsicTest_ThreeParam_FloatOrInt,
1480 testing::Values(IntrinsicData{"clamp",
1481 IntrinsicType::kClamp}));
1482
1483 using ResolverIntrinsicTest_Int_SingleParam =
1484 ResolverTestWithParam<IntrinsicData>;
TEST_P(ResolverIntrinsicTest_Int_SingleParam,Scalar)1485 TEST_P(ResolverIntrinsicTest_Int_SingleParam, Scalar) {
1486 auto param = GetParam();
1487
1488 auto* call = Call(param.name, 1);
1489 WrapInFunction(call);
1490
1491 EXPECT_TRUE(r()->Resolve()) << r()->error();
1492
1493 ASSERT_NE(TypeOf(call), nullptr);
1494 EXPECT_TRUE(TypeOf(call)->is_integer_scalar());
1495 }
1496
TEST_P(ResolverIntrinsicTest_Int_SingleParam,Vector)1497 TEST_P(ResolverIntrinsicTest_Int_SingleParam, Vector) {
1498 auto param = GetParam();
1499
1500 auto* call = Call(param.name, vec3<i32>(1, 1, 3));
1501 WrapInFunction(call);
1502
1503 EXPECT_TRUE(r()->Resolve()) << r()->error();
1504
1505 ASSERT_NE(TypeOf(call), nullptr);
1506 EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
1507 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1508 }
1509
TEST_P(ResolverIntrinsicTest_Int_SingleParam,Error_NoParams)1510 TEST_P(ResolverIntrinsicTest_Int_SingleParam, Error_NoParams) {
1511 auto param = GetParam();
1512
1513 auto* call = Call(param.name);
1514 WrapInFunction(call);
1515
1516 EXPECT_FALSE(r()->Resolve());
1517
1518 EXPECT_EQ(r()->error(), "error: no matching call to " +
1519 std::string(param.name) +
1520 "()\n\n"
1521 "2 candidate functions:\n " +
1522 std::string(param.name) +
1523 "(T) -> T where: T is i32 or u32\n " +
1524 std::string(param.name) +
1525 "(vecN<T>) -> vecN<T> where: T is i32 or u32\n");
1526 }
1527
1528 INSTANTIATE_TEST_SUITE_P(
1529 ResolverTest,
1530 ResolverIntrinsicTest_Int_SingleParam,
1531 testing::Values(IntrinsicData{"countOneBits", IntrinsicType::kCountOneBits},
1532 IntrinsicData{"reverseBits", IntrinsicType::kReverseBits}));
1533
1534 using ResolverIntrinsicTest_FloatOrInt_TwoParam =
1535 ResolverTestWithParam<IntrinsicData>;
TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam,Scalar_Signed)1536 TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam, Scalar_Signed) {
1537 auto param = GetParam();
1538
1539 auto* call = Call(param.name, 1, 1);
1540 WrapInFunction(call);
1541
1542 EXPECT_TRUE(r()->Resolve()) << r()->error();
1543
1544 ASSERT_NE(TypeOf(call), nullptr);
1545 EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
1546 }
1547
TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam,Scalar_Unsigned)1548 TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam, Scalar_Unsigned) {
1549 auto param = GetParam();
1550
1551 auto* call = Call(param.name, 1u, 1u);
1552 WrapInFunction(call);
1553
1554 EXPECT_TRUE(r()->Resolve()) << r()->error();
1555
1556 ASSERT_NE(TypeOf(call), nullptr);
1557 EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
1558 }
1559
TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam,Scalar_Float)1560 TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam, Scalar_Float) {
1561 auto param = GetParam();
1562
1563 auto* call = Call(param.name, 1.0f, 1.0f);
1564 WrapInFunction(call);
1565
1566 EXPECT_TRUE(r()->Resolve()) << r()->error();
1567
1568 ASSERT_NE(TypeOf(call), nullptr);
1569 EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
1570 }
1571
TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam,Vector_Signed)1572 TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam, Vector_Signed) {
1573 auto param = GetParam();
1574
1575 auto* call = Call(param.name, vec3<i32>(1, 1, 3), vec3<i32>(1, 1, 3));
1576 WrapInFunction(call);
1577
1578 EXPECT_TRUE(r()->Resolve()) << r()->error();
1579
1580 ASSERT_NE(TypeOf(call), nullptr);
1581 EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
1582 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1583 }
1584
TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam,Vector_Unsigned)1585 TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam, Vector_Unsigned) {
1586 auto param = GetParam();
1587
1588 auto* call = Call(param.name, vec3<u32>(1u, 1u, 3u), vec3<u32>(1u, 1u, 3u));
1589 WrapInFunction(call);
1590
1591 EXPECT_TRUE(r()->Resolve()) << r()->error();
1592
1593 ASSERT_NE(TypeOf(call), nullptr);
1594 EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
1595 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1596 }
1597
TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam,Vector_Float)1598 TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam, Vector_Float) {
1599 auto param = GetParam();
1600
1601 auto* call =
1602 Call(param.name, vec3<f32>(1.f, 1.f, 3.f), vec3<f32>(1.f, 1.f, 3.f));
1603 WrapInFunction(call);
1604
1605 EXPECT_TRUE(r()->Resolve()) << r()->error();
1606
1607 ASSERT_NE(TypeOf(call), nullptr);
1608 EXPECT_TRUE(TypeOf(call)->is_float_vector());
1609 EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
1610 }
1611
TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam,Error_NoParams)1612 TEST_P(ResolverIntrinsicTest_FloatOrInt_TwoParam, Error_NoParams) {
1613 auto param = GetParam();
1614
1615 auto* call = Call(param.name);
1616 WrapInFunction(call);
1617
1618 EXPECT_FALSE(r()->Resolve());
1619
1620 EXPECT_EQ(r()->error(),
1621 "error: no matching call to " + std::string(param.name) +
1622 "()\n\n"
1623 "2 candidate functions:\n " +
1624 std::string(param.name) +
1625 "(T, T) -> T where: T is f32, i32 or u32\n " +
1626 std::string(param.name) +
1627 "(vecN<T>, vecN<T>) -> vecN<T> where: T is f32, i32 or u32\n");
1628 }
1629
1630 INSTANTIATE_TEST_SUITE_P(
1631 ResolverTest,
1632 ResolverIntrinsicTest_FloatOrInt_TwoParam,
1633 testing::Values(IntrinsicData{"min", IntrinsicType::kMin},
1634 IntrinsicData{"max", IntrinsicType::kMax}));
1635
TEST_F(ResolverIntrinsicTest,Determinant_2x2)1636 TEST_F(ResolverIntrinsicTest, Determinant_2x2) {
1637 Global("var", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
1638
1639 auto* call = Call("determinant", "var");
1640 WrapInFunction(call);
1641
1642 EXPECT_TRUE(r()->Resolve()) << r()->error();
1643
1644 ASSERT_NE(TypeOf(call), nullptr);
1645 EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
1646 }
1647
TEST_F(ResolverIntrinsicTest,Determinant_3x3)1648 TEST_F(ResolverIntrinsicTest, Determinant_3x3) {
1649 Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
1650
1651 auto* call = Call("determinant", "var");
1652 WrapInFunction(call);
1653
1654 EXPECT_TRUE(r()->Resolve()) << r()->error();
1655
1656 ASSERT_NE(TypeOf(call), nullptr);
1657 EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
1658 }
1659
TEST_F(ResolverIntrinsicTest,Determinant_4x4)1660 TEST_F(ResolverIntrinsicTest, Determinant_4x4) {
1661 Global("var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
1662
1663 auto* call = Call("determinant", "var");
1664 WrapInFunction(call);
1665
1666 EXPECT_TRUE(r()->Resolve()) << r()->error();
1667
1668 ASSERT_NE(TypeOf(call), nullptr);
1669 EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
1670 }
1671
TEST_F(ResolverIntrinsicTest,Determinant_NotSquare)1672 TEST_F(ResolverIntrinsicTest, Determinant_NotSquare) {
1673 Global("var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
1674
1675 auto* call = Call("determinant", "var");
1676 WrapInFunction(call);
1677
1678 EXPECT_FALSE(r()->Resolve());
1679
1680 EXPECT_EQ(r()->error(), R"(error: no matching call to determinant(mat2x3<f32>)
1681
1682 1 candidate function:
1683 determinant(matNxN<f32>) -> f32
1684 )");
1685 }
1686
TEST_F(ResolverIntrinsicTest,Determinant_NotMatrix)1687 TEST_F(ResolverIntrinsicTest, Determinant_NotMatrix) {
1688 Global("var", ty.f32(), ast::StorageClass::kPrivate);
1689
1690 auto* call = Call("determinant", "var");
1691 WrapInFunction(call);
1692
1693 EXPECT_FALSE(r()->Resolve());
1694
1695 EXPECT_EQ(r()->error(), R"(error: no matching call to determinant(f32)
1696
1697 1 candidate function:
1698 determinant(matNxN<f32>) -> f32
1699 )");
1700 }
1701
1702 using ResolverIntrinsicTest_Texture =
1703 ResolverTestWithParam<ast::intrinsic::test::TextureOverloadCase>;
1704
1705 INSTANTIATE_TEST_SUITE_P(
1706 ResolverTest,
1707 ResolverIntrinsicTest_Texture,
1708 testing::ValuesIn(ast::intrinsic::test::TextureOverloadCase::ValidCases()));
1709
to_str(const std::string & function,const sem::ParameterList & params)1710 std::string to_str(const std::string& function,
1711 const sem::ParameterList& params) {
1712 std::stringstream out;
1713 out << function << "(";
1714 bool first = true;
1715 for (auto* param : params) {
1716 if (!first) {
1717 out << ", ";
1718 }
1719 out << sem::str(param->Usage());
1720 first = false;
1721 }
1722 out << ")";
1723 return out.str();
1724 }
1725
expected_texture_overload(ast::intrinsic::test::ValidTextureOverload overload)1726 const char* expected_texture_overload(
1727 ast::intrinsic::test::ValidTextureOverload overload) {
1728 using ValidTextureOverload = ast::intrinsic::test::ValidTextureOverload;
1729 switch (overload) {
1730 case ValidTextureOverload::kDimensions1d:
1731 case ValidTextureOverload::kDimensions2d:
1732 case ValidTextureOverload::kDimensions2dArray:
1733 case ValidTextureOverload::kDimensions3d:
1734 case ValidTextureOverload::kDimensionsCube:
1735 case ValidTextureOverload::kDimensionsCubeArray:
1736 case ValidTextureOverload::kDimensionsMultisampled2d:
1737 case ValidTextureOverload::kDimensionsDepth2d:
1738 case ValidTextureOverload::kDimensionsDepth2dArray:
1739 case ValidTextureOverload::kDimensionsDepthCube:
1740 case ValidTextureOverload::kDimensionsDepthCubeArray:
1741 case ValidTextureOverload::kDimensionsDepthMultisampled2d:
1742 case ValidTextureOverload::kDimensionsStorageWO1d:
1743 case ValidTextureOverload::kDimensionsStorageWO2d:
1744 case ValidTextureOverload::kDimensionsStorageWO2dArray:
1745 case ValidTextureOverload::kDimensionsStorageWO3d:
1746 return R"(textureDimensions(texture))";
1747 case ValidTextureOverload::kGather2dF32:
1748 return R"(textureGather(component, texture, sampler, coords))";
1749 case ValidTextureOverload::kGather2dOffsetF32:
1750 return R"(textureGather(component, texture, sampler, coords, offset))";
1751 case ValidTextureOverload::kGather2dArrayF32:
1752 return R"(textureGather(component, texture, sampler, coords, array_index))";
1753 case ValidTextureOverload::kGather2dArrayOffsetF32:
1754 return R"(textureGather(component, texture, sampler, coords, array_index, offset))";
1755 case ValidTextureOverload::kGatherCubeF32:
1756 return R"(textureGather(component, texture, sampler, coords))";
1757 case ValidTextureOverload::kGatherCubeArrayF32:
1758 return R"(textureGather(component, texture, sampler, coords, array_index))";
1759 case ValidTextureOverload::kGatherDepth2dF32:
1760 return R"(textureGather(texture, sampler, coords))";
1761 case ValidTextureOverload::kGatherDepth2dOffsetF32:
1762 return R"(textureGather(texture, sampler, coords, offset))";
1763 case ValidTextureOverload::kGatherDepth2dArrayF32:
1764 return R"(textureGather(texture, sampler, coords, array_index))";
1765 case ValidTextureOverload::kGatherDepth2dArrayOffsetF32:
1766 return R"(textureGather(texture, sampler, coords, array_index, offset))";
1767 case ValidTextureOverload::kGatherDepthCubeF32:
1768 return R"(textureGather(texture, sampler, coords))";
1769 case ValidTextureOverload::kGatherDepthCubeArrayF32:
1770 return R"(textureGather(texture, sampler, coords, array_index))";
1771 case ValidTextureOverload::kGatherCompareDepth2dF32:
1772 return R"(textureGatherCompare(texture, sampler, coords, depth_ref))";
1773 case ValidTextureOverload::kGatherCompareDepth2dOffsetF32:
1774 return R"(textureGatherCompare(texture, sampler, coords, depth_ref, offset))";
1775 case ValidTextureOverload::kGatherCompareDepth2dArrayF32:
1776 return R"(textureGatherCompare(texture, sampler, coords, array_index, depth_ref))";
1777 case ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32:
1778 return R"(textureGatherCompare(texture, sampler, coords, array_index, depth_ref, offset))";
1779 case ValidTextureOverload::kGatherCompareDepthCubeF32:
1780 return R"(textureGatherCompare(texture, sampler, coords, depth_ref))";
1781 case ValidTextureOverload::kGatherCompareDepthCubeArrayF32:
1782 return R"(textureGatherCompare(texture, sampler, coords, array_index, depth_ref))";
1783 case ValidTextureOverload::kNumLayers2dArray:
1784 case ValidTextureOverload::kNumLayersCubeArray:
1785 case ValidTextureOverload::kNumLayersDepth2dArray:
1786 case ValidTextureOverload::kNumLayersDepthCubeArray:
1787 case ValidTextureOverload::kNumLayersStorageWO2dArray:
1788 return R"(textureNumLayers(texture))";
1789 case ValidTextureOverload::kNumLevels2d:
1790 case ValidTextureOverload::kNumLevels2dArray:
1791 case ValidTextureOverload::kNumLevels3d:
1792 case ValidTextureOverload::kNumLevelsCube:
1793 case ValidTextureOverload::kNumLevelsCubeArray:
1794 case ValidTextureOverload::kNumLevelsDepth2d:
1795 case ValidTextureOverload::kNumLevelsDepth2dArray:
1796 case ValidTextureOverload::kNumLevelsDepthCube:
1797 case ValidTextureOverload::kNumLevelsDepthCubeArray:
1798 return R"(textureNumLevels(texture))";
1799 case ValidTextureOverload::kNumSamplesDepthMultisampled2d:
1800 case ValidTextureOverload::kNumSamplesMultisampled2d:
1801 return R"(textureNumSamples(texture))";
1802 case ValidTextureOverload::kDimensions2dLevel:
1803 case ValidTextureOverload::kDimensions2dArrayLevel:
1804 case ValidTextureOverload::kDimensions3dLevel:
1805 case ValidTextureOverload::kDimensionsCubeLevel:
1806 case ValidTextureOverload::kDimensionsCubeArrayLevel:
1807 case ValidTextureOverload::kDimensionsDepth2dLevel:
1808 case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
1809 case ValidTextureOverload::kDimensionsDepthCubeLevel:
1810 case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
1811 return R"(textureDimensions(texture, level))";
1812 case ValidTextureOverload::kSample1dF32:
1813 return R"(textureSample(texture, sampler, coords))";
1814 case ValidTextureOverload::kSample2dF32:
1815 return R"(textureSample(texture, sampler, coords))";
1816 case ValidTextureOverload::kSample2dOffsetF32:
1817 return R"(textureSample(texture, sampler, coords, offset))";
1818 case ValidTextureOverload::kSample2dArrayF32:
1819 return R"(textureSample(texture, sampler, coords, array_index))";
1820 case ValidTextureOverload::kSample2dArrayOffsetF32:
1821 return R"(textureSample(texture, sampler, coords, array_index, offset))";
1822 case ValidTextureOverload::kSample3dF32:
1823 return R"(textureSample(texture, sampler, coords))";
1824 case ValidTextureOverload::kSample3dOffsetF32:
1825 return R"(textureSample(texture, sampler, coords, offset))";
1826 case ValidTextureOverload::kSampleCubeF32:
1827 return R"(textureSample(texture, sampler, coords))";
1828 case ValidTextureOverload::kSampleCubeArrayF32:
1829 return R"(textureSample(texture, sampler, coords, array_index))";
1830 case ValidTextureOverload::kSampleDepth2dF32:
1831 return R"(textureSample(texture, sampler, coords))";
1832 case ValidTextureOverload::kSampleDepth2dOffsetF32:
1833 return R"(textureSample(texture, sampler, coords, offset))";
1834 case ValidTextureOverload::kSampleDepth2dArrayF32:
1835 return R"(textureSample(texture, sampler, coords, array_index))";
1836 case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
1837 return R"(textureSample(texture, sampler, coords, array_index, offset))";
1838 case ValidTextureOverload::kSampleDepthCubeF32:
1839 return R"(textureSample(texture, sampler, coords))";
1840 case ValidTextureOverload::kSampleDepthCubeArrayF32:
1841 return R"(textureSample(texture, sampler, coords, array_index))";
1842 case ValidTextureOverload::kSampleBias2dF32:
1843 return R"(textureSampleBias(texture, sampler, coords, bias))";
1844 case ValidTextureOverload::kSampleBias2dOffsetF32:
1845 return R"(textureSampleBias(texture, sampler, coords, bias, offset))";
1846 case ValidTextureOverload::kSampleBias2dArrayF32:
1847 return R"(textureSampleBias(texture, sampler, coords, array_index, bias))";
1848 case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
1849 return R"(textureSampleBias(texture, sampler, coords, array_index, bias, offset))";
1850 case ValidTextureOverload::kSampleBias3dF32:
1851 return R"(textureSampleBias(texture, sampler, coords, bias))";
1852 case ValidTextureOverload::kSampleBias3dOffsetF32:
1853 return R"(textureSampleBias(texture, sampler, coords, bias, offset))";
1854 case ValidTextureOverload::kSampleBiasCubeF32:
1855 return R"(textureSampleBias(texture, sampler, coords, bias))";
1856 case ValidTextureOverload::kSampleBiasCubeArrayF32:
1857 return R"(textureSampleBias(texture, sampler, coords, array_index, bias))";
1858 case ValidTextureOverload::kSampleLevel2dF32:
1859 return R"(textureSampleLevel(texture, sampler, coords, level))";
1860 case ValidTextureOverload::kSampleLevel2dOffsetF32:
1861 return R"(textureSampleLevel(texture, sampler, coords, level, offset))";
1862 case ValidTextureOverload::kSampleLevel2dArrayF32:
1863 return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
1864 case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
1865 return R"(textureSampleLevel(texture, sampler, coords, array_index, level, offset))";
1866 case ValidTextureOverload::kSampleLevel3dF32:
1867 return R"(textureSampleLevel(texture, sampler, coords, level))";
1868 case ValidTextureOverload::kSampleLevel3dOffsetF32:
1869 return R"(textureSampleLevel(texture, sampler, coords, level, offset))";
1870 case ValidTextureOverload::kSampleLevelCubeF32:
1871 return R"(textureSampleLevel(texture, sampler, coords, level))";
1872 case ValidTextureOverload::kSampleLevelCubeArrayF32:
1873 return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
1874 case ValidTextureOverload::kSampleLevelDepth2dF32:
1875 return R"(textureSampleLevel(texture, sampler, coords, level))";
1876 case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
1877 return R"(textureSampleLevel(texture, sampler, coords, level, offset))";
1878 case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
1879 return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
1880 case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
1881 return R"(textureSampleLevel(texture, sampler, coords, array_index, level, offset))";
1882 case ValidTextureOverload::kSampleLevelDepthCubeF32:
1883 return R"(textureSampleLevel(texture, sampler, coords, level))";
1884 case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
1885 return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
1886 case ValidTextureOverload::kSampleGrad2dF32:
1887 return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy))";
1888 case ValidTextureOverload::kSampleGrad2dOffsetF32:
1889 return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy, offset))";
1890 case ValidTextureOverload::kSampleGrad2dArrayF32:
1891 return R"(textureSampleGrad(texture, sampler, coords, array_index, ddx, ddy))";
1892 case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
1893 return R"(textureSampleGrad(texture, sampler, coords, array_index, ddx, ddy, offset))";
1894 case ValidTextureOverload::kSampleGrad3dF32:
1895 return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy))";
1896 case ValidTextureOverload::kSampleGrad3dOffsetF32:
1897 return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy, offset))";
1898 case ValidTextureOverload::kSampleGradCubeF32:
1899 return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy))";
1900 case ValidTextureOverload::kSampleGradCubeArrayF32:
1901 return R"(textureSampleGrad(texture, sampler, coords, array_index, ddx, ddy))";
1902 case ValidTextureOverload::kSampleCompareDepth2dF32:
1903 return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
1904 case ValidTextureOverload::kSampleCompareDepth2dOffsetF32:
1905 return R"(textureSampleCompare(texture, sampler, coords, depth_ref, offset))";
1906 case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
1907 return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
1908 case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
1909 return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref, offset))";
1910 case ValidTextureOverload::kSampleCompareDepthCubeF32:
1911 return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
1912 case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
1913 return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
1914 case ValidTextureOverload::kSampleCompareLevelDepth2dF32:
1915 return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
1916 case ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32:
1917 return R"(textureSampleCompare(texture, sampler, coords, depth_ref, offset))";
1918 case ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32:
1919 return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
1920 case ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32:
1921 return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref, offset))";
1922 case ValidTextureOverload::kSampleCompareLevelDepthCubeF32:
1923 return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
1924 case ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32:
1925 return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
1926 case ValidTextureOverload::kLoad1dLevelF32:
1927 case ValidTextureOverload::kLoad1dLevelU32:
1928 case ValidTextureOverload::kLoad1dLevelI32:
1929 case ValidTextureOverload::kLoad2dLevelF32:
1930 case ValidTextureOverload::kLoad2dLevelU32:
1931 case ValidTextureOverload::kLoad2dLevelI32:
1932 return R"(textureLoad(texture, coords, level))";
1933 case ValidTextureOverload::kLoad2dArrayLevelF32:
1934 case ValidTextureOverload::kLoad2dArrayLevelU32:
1935 case ValidTextureOverload::kLoad2dArrayLevelI32:
1936 return R"(textureLoad(texture, coords, array_index, level))";
1937 case ValidTextureOverload::kLoad3dLevelF32:
1938 case ValidTextureOverload::kLoad3dLevelU32:
1939 case ValidTextureOverload::kLoad3dLevelI32:
1940 case ValidTextureOverload::kLoadDepth2dLevelF32:
1941 return R"(textureLoad(texture, coords, level))";
1942 case ValidTextureOverload::kLoadDepthMultisampled2dF32:
1943 case ValidTextureOverload::kLoadMultisampled2dF32:
1944 case ValidTextureOverload::kLoadMultisampled2dU32:
1945 case ValidTextureOverload::kLoadMultisampled2dI32:
1946 return R"(textureLoad(texture, coords, sample_index))";
1947 case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
1948 return R"(textureLoad(texture, coords, array_index, level))";
1949 case ValidTextureOverload::kStoreWO1dRgba32float:
1950 case ValidTextureOverload::kStoreWO2dRgba32float:
1951 case ValidTextureOverload::kStoreWO3dRgba32float:
1952 return R"(textureStore(texture, coords, value))";
1953 case ValidTextureOverload::kStoreWO2dArrayRgba32float:
1954 return R"(textureStore(texture, coords, array_index, value))";
1955 }
1956 return "<unmatched texture overload>";
1957 }
1958
TEST_P(ResolverIntrinsicTest_Texture,Call)1959 TEST_P(ResolverIntrinsicTest_Texture, Call) {
1960 auto param = GetParam();
1961
1962 param.BuildTextureVariable(this);
1963 param.BuildSamplerVariable(this);
1964
1965 auto* call = Call(param.function, param.args(this));
1966 auto* stmt = CallStmt(call);
1967 Func("func", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
1968
1969 ASSERT_TRUE(r()->Resolve()) << r()->error();
1970
1971 if (std::string(param.function) == "textureDimensions") {
1972 switch (param.texture_dimension) {
1973 default:
1974 FAIL() << "invalid texture dimensions: " << param.texture_dimension;
1975 case ast::TextureDimension::k1d:
1976 EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
1977 break;
1978 case ast::TextureDimension::k2d:
1979 case ast::TextureDimension::k2dArray:
1980 case ast::TextureDimension::kCube:
1981 case ast::TextureDimension::kCubeArray: {
1982 auto* vec = As<sem::Vector>(TypeOf(call));
1983 ASSERT_NE(vec, nullptr);
1984 EXPECT_EQ(vec->Width(), 2u);
1985 EXPECT_TRUE(vec->type()->Is<sem::I32>());
1986 break;
1987 }
1988 case ast::TextureDimension::k3d: {
1989 auto* vec = As<sem::Vector>(TypeOf(call));
1990 ASSERT_NE(vec, nullptr);
1991 EXPECT_EQ(vec->Width(), 3u);
1992 EXPECT_TRUE(vec->type()->Is<sem::I32>());
1993 break;
1994 }
1995 }
1996 } else if (std::string(param.function) == "textureNumLayers") {
1997 EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
1998 } else if (std::string(param.function) == "textureNumLevels") {
1999 EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
2000 } else if (std::string(param.function) == "textureNumSamples") {
2001 EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
2002 } else if (std::string(param.function) == "textureStore") {
2003 EXPECT_TRUE(TypeOf(call)->Is<sem::Void>());
2004 } else if (std::string(param.function) == "textureGather") {
2005 auto* vec = As<sem::Vector>(TypeOf(call));
2006 ASSERT_NE(vec, nullptr);
2007 EXPECT_EQ(vec->Width(), 4u);
2008 switch (param.texture_data_type) {
2009 case ast::intrinsic::test::TextureDataType::kF32:
2010 EXPECT_TRUE(vec->type()->Is<sem::F32>());
2011 break;
2012 case ast::intrinsic::test::TextureDataType::kU32:
2013 EXPECT_TRUE(vec->type()->Is<sem::U32>());
2014 break;
2015 case ast::intrinsic::test::TextureDataType::kI32:
2016 EXPECT_TRUE(vec->type()->Is<sem::I32>());
2017 break;
2018 }
2019 } else if (std::string(param.function) == "textureGatherCompare") {
2020 auto* vec = As<sem::Vector>(TypeOf(call));
2021 ASSERT_NE(vec, nullptr);
2022 EXPECT_EQ(vec->Width(), 4u);
2023 EXPECT_TRUE(vec->type()->Is<sem::F32>());
2024 } else {
2025 switch (param.texture_kind) {
2026 case ast::intrinsic::test::TextureKind::kRegular:
2027 case ast::intrinsic::test::TextureKind::kMultisampled:
2028 case ast::intrinsic::test::TextureKind::kStorage: {
2029 auto* vec = TypeOf(call)->As<sem::Vector>();
2030 ASSERT_NE(vec, nullptr);
2031 switch (param.texture_data_type) {
2032 case ast::intrinsic::test::TextureDataType::kF32:
2033 EXPECT_TRUE(vec->type()->Is<sem::F32>());
2034 break;
2035 case ast::intrinsic::test::TextureDataType::kU32:
2036 EXPECT_TRUE(vec->type()->Is<sem::U32>());
2037 break;
2038 case ast::intrinsic::test::TextureDataType::kI32:
2039 EXPECT_TRUE(vec->type()->Is<sem::I32>());
2040 break;
2041 }
2042 break;
2043 }
2044 case ast::intrinsic::test::TextureKind::kDepth:
2045 case ast::intrinsic::test::TextureKind::kDepthMultisampled: {
2046 EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
2047 break;
2048 }
2049 }
2050 }
2051
2052 auto* call_sem = Sem().Get(call);
2053 ASSERT_NE(call_sem, nullptr);
2054 auto* target = call_sem->Target();
2055 ASSERT_NE(target, nullptr);
2056
2057 auto got = resolver::to_str(param.function, target->Parameters());
2058 auto* expected = expected_texture_overload(param.overload);
2059 EXPECT_EQ(got, expected);
2060 }
2061
2062 } // namespace
2063 } // namespace resolver
2064 } // namespace tint
2065