• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/resolver/resolver.h"
16 
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