• 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/intrinsic_table.h"
16 
17 #include "gmock/gmock.h"
18 #include "src/program_builder.h"
19 #include "src/sem/atomic_type.h"
20 #include "src/sem/depth_multisampled_texture_type.h"
21 #include "src/sem/depth_texture_type.h"
22 #include "src/sem/external_texture_type.h"
23 #include "src/sem/multisampled_texture_type.h"
24 #include "src/sem/reference_type.h"
25 #include "src/sem/sampled_texture_type.h"
26 #include "src/sem/storage_texture_type.h"
27 
28 namespace tint {
29 namespace {
30 
31 using ::testing::HasSubstr;
32 
33 using IntrinsicType = sem::IntrinsicType;
34 using Parameter = sem::Parameter;
35 using ParameterUsage = sem::ParameterUsage;
36 
37 class IntrinsicTableTest : public testing::Test, public ProgramBuilder {
38  public:
39   std::unique_ptr<IntrinsicTable> table = IntrinsicTable::Create(*this);
40 };
41 
TEST_F(IntrinsicTableTest,MatchF32)42 TEST_F(IntrinsicTableTest, MatchF32) {
43   auto* f32 = create<sem::F32>();
44   auto* result = table->Lookup(IntrinsicType::kCos, {f32}, Source{});
45   ASSERT_NE(result, nullptr) << Diagnostics().str();
46   ASSERT_EQ(Diagnostics().str(), "");
47   EXPECT_EQ(result->Type(), IntrinsicType::kCos);
48   EXPECT_EQ(result->ReturnType(), f32);
49   ASSERT_EQ(result->Parameters().size(), 1u);
50   EXPECT_EQ(result->Parameters()[0]->Type(), f32);
51 }
52 
TEST_F(IntrinsicTableTest,MismatchF32)53 TEST_F(IntrinsicTableTest, MismatchF32) {
54   auto* i32 = create<sem::I32>();
55   auto* result = table->Lookup(IntrinsicType::kCos, {i32}, Source{});
56   ASSERT_EQ(result, nullptr);
57   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
58 }
59 
TEST_F(IntrinsicTableTest,MatchU32)60 TEST_F(IntrinsicTableTest, MatchU32) {
61   auto* f32 = create<sem::F32>();
62   auto* u32 = create<sem::U32>();
63   auto* vec2_f32 = create<sem::Vector>(f32, 2);
64   auto* result =
65       table->Lookup(IntrinsicType::kUnpack2x16float, {u32}, Source{});
66   ASSERT_NE(result, nullptr) << Diagnostics().str();
67   ASSERT_EQ(Diagnostics().str(), "");
68   EXPECT_EQ(result->Type(), IntrinsicType::kUnpack2x16float);
69   EXPECT_EQ(result->ReturnType(), vec2_f32);
70   ASSERT_EQ(result->Parameters().size(), 1u);
71   EXPECT_EQ(result->Parameters()[0]->Type(), u32);
72 }
73 
TEST_F(IntrinsicTableTest,MismatchU32)74 TEST_F(IntrinsicTableTest, MismatchU32) {
75   auto* f32 = create<sem::F32>();
76   auto* result =
77       table->Lookup(IntrinsicType::kUnpack2x16float, {f32}, Source{});
78   ASSERT_EQ(result, nullptr);
79   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
80 }
81 
TEST_F(IntrinsicTableTest,MatchI32)82 TEST_F(IntrinsicTableTest, MatchI32) {
83   auto* f32 = create<sem::F32>();
84   auto* i32 = create<sem::I32>();
85   auto* vec4_f32 = create<sem::Vector>(f32, 4);
86   auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
87   auto* result =
88       table->Lookup(IntrinsicType::kTextureLoad, {tex, i32, i32}, Source{});
89   ASSERT_NE(result, nullptr) << Diagnostics().str();
90   ASSERT_EQ(Diagnostics().str(), "");
91   EXPECT_EQ(result->Type(), IntrinsicType::kTextureLoad);
92   EXPECT_EQ(result->ReturnType(), vec4_f32);
93   ASSERT_EQ(result->Parameters().size(), 3u);
94   EXPECT_EQ(result->Parameters()[0]->Type(), tex);
95   EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
96   EXPECT_EQ(result->Parameters()[1]->Type(), i32);
97   EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
98   EXPECT_EQ(result->Parameters()[2]->Type(), i32);
99   EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kLevel);
100 }
101 
TEST_F(IntrinsicTableTest,MismatchI32)102 TEST_F(IntrinsicTableTest, MismatchI32) {
103   auto* f32 = create<sem::F32>();
104   auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
105   auto* result =
106       table->Lookup(IntrinsicType::kTextureLoad, {tex, f32}, Source{});
107   ASSERT_EQ(result, nullptr);
108   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
109 }
110 
TEST_F(IntrinsicTableTest,MatchIU32AsI32)111 TEST_F(IntrinsicTableTest, MatchIU32AsI32) {
112   auto* i32 = create<sem::I32>();
113   auto* result = table->Lookup(IntrinsicType::kCountOneBits, {i32}, Source{});
114   ASSERT_NE(result, nullptr) << Diagnostics().str();
115   ASSERT_EQ(Diagnostics().str(), "");
116   EXPECT_EQ(result->Type(), IntrinsicType::kCountOneBits);
117   EXPECT_EQ(result->ReturnType(), i32);
118   ASSERT_EQ(result->Parameters().size(), 1u);
119   EXPECT_EQ(result->Parameters()[0]->Type(), i32);
120 }
121 
TEST_F(IntrinsicTableTest,MatchIU32AsU32)122 TEST_F(IntrinsicTableTest, MatchIU32AsU32) {
123   auto* u32 = create<sem::U32>();
124   auto* result = table->Lookup(IntrinsicType::kCountOneBits, {u32}, Source{});
125   ASSERT_NE(result, nullptr) << Diagnostics().str();
126   ASSERT_EQ(Diagnostics().str(), "");
127   EXPECT_EQ(result->Type(), IntrinsicType::kCountOneBits);
128   EXPECT_EQ(result->ReturnType(), u32);
129   ASSERT_EQ(result->Parameters().size(), 1u);
130   EXPECT_EQ(result->Parameters()[0]->Type(), u32);
131 }
132 
TEST_F(IntrinsicTableTest,MismatchIU32)133 TEST_F(IntrinsicTableTest, MismatchIU32) {
134   auto* f32 = create<sem::F32>();
135   auto* result = table->Lookup(IntrinsicType::kCountOneBits, {f32}, Source{});
136   ASSERT_EQ(result, nullptr);
137   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
138 }
139 
TEST_F(IntrinsicTableTest,MatchFIU32AsI32)140 TEST_F(IntrinsicTableTest, MatchFIU32AsI32) {
141   auto* i32 = create<sem::I32>();
142   auto* result =
143       table->Lookup(IntrinsicType::kClamp, {i32, i32, i32}, Source{});
144   ASSERT_NE(result, nullptr) << Diagnostics().str();
145   ASSERT_EQ(Diagnostics().str(), "");
146   EXPECT_EQ(result->Type(), IntrinsicType::kClamp);
147   EXPECT_EQ(result->ReturnType(), i32);
148   ASSERT_EQ(result->Parameters().size(), 3u);
149   EXPECT_EQ(result->Parameters()[0]->Type(), i32);
150   EXPECT_EQ(result->Parameters()[1]->Type(), i32);
151   EXPECT_EQ(result->Parameters()[2]->Type(), i32);
152 }
153 
TEST_F(IntrinsicTableTest,MatchFIU32AsU32)154 TEST_F(IntrinsicTableTest, MatchFIU32AsU32) {
155   auto* u32 = create<sem::U32>();
156   auto* result =
157       table->Lookup(IntrinsicType::kClamp, {u32, u32, u32}, Source{});
158   ASSERT_NE(result, nullptr) << Diagnostics().str();
159   ASSERT_EQ(Diagnostics().str(), "");
160   EXPECT_EQ(result->Type(), IntrinsicType::kClamp);
161   EXPECT_EQ(result->ReturnType(), u32);
162   ASSERT_EQ(result->Parameters().size(), 3u);
163   EXPECT_EQ(result->Parameters()[0]->Type(), u32);
164   EXPECT_EQ(result->Parameters()[1]->Type(), u32);
165   EXPECT_EQ(result->Parameters()[2]->Type(), u32);
166 }
167 
TEST_F(IntrinsicTableTest,MatchFIU32AsF32)168 TEST_F(IntrinsicTableTest, MatchFIU32AsF32) {
169   auto* f32 = create<sem::F32>();
170   auto* result =
171       table->Lookup(IntrinsicType::kClamp, {f32, f32, f32}, Source{});
172   ASSERT_NE(result, nullptr) << Diagnostics().str();
173   ASSERT_EQ(Diagnostics().str(), "");
174   EXPECT_EQ(result->Type(), IntrinsicType::kClamp);
175   EXPECT_EQ(result->ReturnType(), f32);
176   ASSERT_EQ(result->Parameters().size(), 3u);
177   EXPECT_EQ(result->Parameters()[0]->Type(), f32);
178   EXPECT_EQ(result->Parameters()[1]->Type(), f32);
179   EXPECT_EQ(result->Parameters()[2]->Type(), f32);
180 }
181 
TEST_F(IntrinsicTableTest,MismatchFIU32)182 TEST_F(IntrinsicTableTest, MismatchFIU32) {
183   auto* bool_ = create<sem::Bool>();
184   auto* result =
185       table->Lookup(IntrinsicType::kClamp, {bool_, bool_, bool_}, Source{});
186   ASSERT_EQ(result, nullptr);
187   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
188 }
189 
TEST_F(IntrinsicTableTest,MatchBool)190 TEST_F(IntrinsicTableTest, MatchBool) {
191   auto* f32 = create<sem::F32>();
192   auto* bool_ = create<sem::Bool>();
193   auto* result =
194       table->Lookup(IntrinsicType::kSelect, {f32, f32, bool_}, Source{});
195   ASSERT_NE(result, nullptr) << Diagnostics().str();
196   ASSERT_EQ(Diagnostics().str(), "");
197   EXPECT_EQ(result->Type(), IntrinsicType::kSelect);
198   EXPECT_EQ(result->ReturnType(), f32);
199   ASSERT_EQ(result->Parameters().size(), 3u);
200   EXPECT_EQ(result->Parameters()[0]->Type(), f32);
201   EXPECT_EQ(result->Parameters()[1]->Type(), f32);
202   EXPECT_EQ(result->Parameters()[2]->Type(), bool_);
203 }
204 
TEST_F(IntrinsicTableTest,MismatchBool)205 TEST_F(IntrinsicTableTest, MismatchBool) {
206   auto* f32 = create<sem::F32>();
207   auto* result =
208       table->Lookup(IntrinsicType::kSelect, {f32, f32, f32}, Source{});
209   ASSERT_EQ(result, nullptr);
210   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
211 }
212 
TEST_F(IntrinsicTableTest,MatchPointer)213 TEST_F(IntrinsicTableTest, MatchPointer) {
214   auto* i32 = create<sem::I32>();
215   auto* atomicI32 = create<sem::Atomic>(i32);
216   auto* ptr = create<sem::Pointer>(atomicI32, ast::StorageClass::kWorkgroup,
217                                    ast::Access::kReadWrite);
218   auto* result = table->Lookup(IntrinsicType::kAtomicLoad, {ptr}, Source{});
219   ASSERT_NE(result, nullptr) << Diagnostics().str();
220   ASSERT_EQ(Diagnostics().str(), "");
221   EXPECT_EQ(result->Type(), IntrinsicType::kAtomicLoad);
222   EXPECT_EQ(result->ReturnType(), i32);
223   ASSERT_EQ(result->Parameters().size(), 1u);
224   EXPECT_EQ(result->Parameters()[0]->Type(), ptr);
225 }
226 
TEST_F(IntrinsicTableTest,MismatchPointer)227 TEST_F(IntrinsicTableTest, MismatchPointer) {
228   auto* i32 = create<sem::I32>();
229   auto* atomicI32 = create<sem::Atomic>(i32);
230   auto* result =
231       table->Lookup(IntrinsicType::kAtomicLoad, {atomicI32}, Source{});
232   ASSERT_EQ(result, nullptr);
233   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
234 }
235 
TEST_F(IntrinsicTableTest,MatchArray)236 TEST_F(IntrinsicTableTest, MatchArray) {
237   auto* arr = create<sem::Array>(create<sem::U32>(), 0, 4, 4, 4, 4);
238   auto* arr_ptr = create<sem::Pointer>(arr, ast::StorageClass::kStorage,
239                                        ast::Access::kReadWrite);
240   auto* result =
241       table->Lookup(IntrinsicType::kArrayLength, {arr_ptr}, Source{});
242   ASSERT_NE(result, nullptr) << Diagnostics().str();
243   ASSERT_EQ(Diagnostics().str(), "");
244   EXPECT_EQ(result->Type(), IntrinsicType::kArrayLength);
245   EXPECT_TRUE(result->ReturnType()->Is<sem::U32>());
246   ASSERT_EQ(result->Parameters().size(), 1u);
247   auto* param_type = result->Parameters()[0]->Type();
248   ASSERT_TRUE(param_type->Is<sem::Pointer>());
249   EXPECT_TRUE(param_type->As<sem::Pointer>()->StoreType()->Is<sem::Array>());
250 }
251 
TEST_F(IntrinsicTableTest,MismatchArray)252 TEST_F(IntrinsicTableTest, MismatchArray) {
253   auto* f32 = create<sem::F32>();
254   auto* result = table->Lookup(IntrinsicType::kArrayLength, {f32}, Source{});
255   ASSERT_EQ(result, nullptr);
256   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
257 }
258 
TEST_F(IntrinsicTableTest,MatchSampler)259 TEST_F(IntrinsicTableTest, MatchSampler) {
260   auto* f32 = create<sem::F32>();
261   auto* vec2_f32 = create<sem::Vector>(f32, 2);
262   auto* vec4_f32 = create<sem::Vector>(f32, 4);
263   auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
264   auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
265   auto* result = table->Lookup(IntrinsicType::kTextureSample,
266                                {tex, sampler, vec2_f32}, Source{});
267   ASSERT_NE(result, nullptr) << Diagnostics().str();
268   ASSERT_EQ(Diagnostics().str(), "");
269   EXPECT_EQ(result->Type(), IntrinsicType::kTextureSample);
270   EXPECT_EQ(result->ReturnType(), vec4_f32);
271   ASSERT_EQ(result->Parameters().size(), 3u);
272   EXPECT_EQ(result->Parameters()[0]->Type(), tex);
273   EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
274   EXPECT_EQ(result->Parameters()[1]->Type(), sampler);
275   EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kSampler);
276   EXPECT_EQ(result->Parameters()[2]->Type(), vec2_f32);
277   EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kCoords);
278 }
279 
TEST_F(IntrinsicTableTest,MismatchSampler)280 TEST_F(IntrinsicTableTest, MismatchSampler) {
281   auto* f32 = create<sem::F32>();
282   auto* vec2_f32 = create<sem::Vector>(f32, 2);
283   auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
284   auto* result = table->Lookup(IntrinsicType::kTextureSample,
285                                {tex, f32, vec2_f32}, Source{});
286   ASSERT_EQ(result, nullptr);
287   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
288 }
289 
TEST_F(IntrinsicTableTest,MatchSampledTexture)290 TEST_F(IntrinsicTableTest, MatchSampledTexture) {
291   auto* i32 = create<sem::I32>();
292   auto* f32 = create<sem::F32>();
293   auto* vec2_i32 = create<sem::Vector>(i32, 2);
294   auto* vec4_f32 = create<sem::Vector>(f32, 4);
295   auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
296   auto* result = table->Lookup(IntrinsicType::kTextureLoad,
297                                {tex, vec2_i32, i32}, Source{});
298   ASSERT_NE(result, nullptr) << Diagnostics().str();
299   ASSERT_EQ(Diagnostics().str(), "");
300   EXPECT_EQ(result->Type(), IntrinsicType::kTextureLoad);
301   EXPECT_EQ(result->ReturnType(), vec4_f32);
302   ASSERT_EQ(result->Parameters().size(), 3u);
303   EXPECT_EQ(result->Parameters()[0]->Type(), tex);
304   EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
305   EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
306   EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
307   EXPECT_EQ(result->Parameters()[2]->Type(), i32);
308   EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kLevel);
309 }
310 
TEST_F(IntrinsicTableTest,MatchMultisampledTexture)311 TEST_F(IntrinsicTableTest, MatchMultisampledTexture) {
312   auto* i32 = create<sem::I32>();
313   auto* f32 = create<sem::F32>();
314   auto* vec2_i32 = create<sem::Vector>(i32, 2);
315   auto* vec4_f32 = create<sem::Vector>(f32, 4);
316   auto* tex = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
317   auto* result = table->Lookup(IntrinsicType::kTextureLoad,
318                                {tex, vec2_i32, i32}, Source{});
319   ASSERT_NE(result, nullptr) << Diagnostics().str();
320   ASSERT_EQ(Diagnostics().str(), "");
321   EXPECT_EQ(result->Type(), IntrinsicType::kTextureLoad);
322   EXPECT_EQ(result->ReturnType(), vec4_f32);
323   ASSERT_EQ(result->Parameters().size(), 3u);
324   EXPECT_EQ(result->Parameters()[0]->Type(), tex);
325   EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
326   EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
327   EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
328   EXPECT_EQ(result->Parameters()[2]->Type(), i32);
329   EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kSampleIndex);
330 }
331 
TEST_F(IntrinsicTableTest,MatchDepthTexture)332 TEST_F(IntrinsicTableTest, MatchDepthTexture) {
333   auto* f32 = create<sem::F32>();
334   auto* i32 = create<sem::I32>();
335   auto* vec2_i32 = create<sem::Vector>(i32, 2);
336   auto* tex = create<sem::DepthTexture>(ast::TextureDimension::k2d);
337   auto* result = table->Lookup(IntrinsicType::kTextureLoad,
338                                {tex, vec2_i32, i32}, Source{});
339   ASSERT_NE(result, nullptr) << Diagnostics().str();
340   ASSERT_EQ(Diagnostics().str(), "");
341   EXPECT_EQ(result->Type(), IntrinsicType::kTextureLoad);
342   EXPECT_EQ(result->ReturnType(), f32);
343   ASSERT_EQ(result->Parameters().size(), 3u);
344   EXPECT_EQ(result->Parameters()[0]->Type(), tex);
345   EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
346   EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
347   EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
348   EXPECT_EQ(result->Parameters()[2]->Type(), i32);
349   EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kLevel);
350 }
351 
TEST_F(IntrinsicTableTest,MatchDepthMultisampledTexture)352 TEST_F(IntrinsicTableTest, MatchDepthMultisampledTexture) {
353   auto* f32 = create<sem::F32>();
354   auto* i32 = create<sem::I32>();
355   auto* vec2_i32 = create<sem::Vector>(i32, 2);
356   auto* tex = create<sem::DepthMultisampledTexture>(ast::TextureDimension::k2d);
357   auto* result = table->Lookup(IntrinsicType::kTextureLoad,
358                                {tex, vec2_i32, i32}, Source{});
359   ASSERT_NE(result, nullptr) << Diagnostics().str();
360   ASSERT_EQ(Diagnostics().str(), "");
361   EXPECT_EQ(result->Type(), IntrinsicType::kTextureLoad);
362   EXPECT_EQ(result->ReturnType(), f32);
363   ASSERT_EQ(result->Parameters().size(), 3u);
364   EXPECT_EQ(result->Parameters()[0]->Type(), tex);
365   EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
366   EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
367   EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
368   EXPECT_EQ(result->Parameters()[2]->Type(), i32);
369   EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kSampleIndex);
370 }
371 
TEST_F(IntrinsicTableTest,MatchExternalTexture)372 TEST_F(IntrinsicTableTest, MatchExternalTexture) {
373   auto* f32 = create<sem::F32>();
374   auto* i32 = create<sem::I32>();
375   auto* vec2_i32 = create<sem::Vector>(i32, 2);
376   auto* vec4_f32 = create<sem::Vector>(f32, 4);
377   auto* tex = create<sem::ExternalTexture>();
378   auto* result =
379       table->Lookup(IntrinsicType::kTextureLoad, {tex, vec2_i32}, Source{});
380   ASSERT_NE(result, nullptr) << Diagnostics().str();
381   ASSERT_EQ(Diagnostics().str(), "");
382   EXPECT_EQ(result->Type(), IntrinsicType::kTextureLoad);
383   EXPECT_EQ(result->ReturnType(), vec4_f32);
384   ASSERT_EQ(result->Parameters().size(), 2u);
385   EXPECT_EQ(result->Parameters()[0]->Type(), tex);
386   EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
387   EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
388   EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
389 }
390 
TEST_F(IntrinsicTableTest,MatchWOStorageTexture)391 TEST_F(IntrinsicTableTest, MatchWOStorageTexture) {
392   auto* f32 = create<sem::F32>();
393   auto* i32 = create<sem::I32>();
394   auto* vec2_i32 = create<sem::Vector>(i32, 2);
395   auto* vec4_f32 = create<sem::Vector>(f32, 4);
396   auto* subtype =
397       sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR32Float, Types());
398   auto* tex = create<sem::StorageTexture>(ast::TextureDimension::k2d,
399                                           ast::ImageFormat::kR32Float,
400                                           ast::Access::kWrite, subtype);
401 
402   auto* result = table->Lookup(IntrinsicType::kTextureStore,
403                                {tex, vec2_i32, vec4_f32}, Source{});
404   ASSERT_NE(result, nullptr) << Diagnostics().str();
405   ASSERT_EQ(Diagnostics().str(), "");
406   EXPECT_EQ(result->Type(), IntrinsicType::kTextureStore);
407   EXPECT_TRUE(result->ReturnType()->Is<sem::Void>());
408   ASSERT_EQ(result->Parameters().size(), 3u);
409   EXPECT_EQ(result->Parameters()[0]->Type(), tex);
410   EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
411   EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
412   EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
413   EXPECT_EQ(result->Parameters()[2]->Type(), vec4_f32);
414   EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kValue);
415 }
416 
TEST_F(IntrinsicTableTest,MismatchTexture)417 TEST_F(IntrinsicTableTest, MismatchTexture) {
418   auto* f32 = create<sem::F32>();
419   auto* i32 = create<sem::I32>();
420   auto* vec2_i32 = create<sem::Vector>(i32, 2);
421   auto* result =
422       table->Lookup(IntrinsicType::kTextureLoad, {f32, vec2_i32}, Source{});
423   ASSERT_EQ(result, nullptr);
424   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
425 }
426 
TEST_F(IntrinsicTableTest,ImplicitLoadOnReference)427 TEST_F(IntrinsicTableTest, ImplicitLoadOnReference) {
428   auto* f32 = create<sem::F32>();
429   auto* result =
430       table->Lookup(IntrinsicType::kCos,
431                     {create<sem::Reference>(f32, ast::StorageClass::kFunction,
432                                             ast::Access::kReadWrite)},
433                     Source{});
434   ASSERT_NE(result, nullptr) << Diagnostics().str();
435   ASSERT_EQ(Diagnostics().str(), "");
436   EXPECT_EQ(result->Type(), IntrinsicType::kCos);
437   EXPECT_EQ(result->ReturnType(), f32);
438   ASSERT_EQ(result->Parameters().size(), 1u);
439   EXPECT_EQ(result->Parameters()[0]->Type(), f32);
440 }
441 
TEST_F(IntrinsicTableTest,MatchOpenType)442 TEST_F(IntrinsicTableTest, MatchOpenType) {
443   auto* f32 = create<sem::F32>();
444   auto* result =
445       table->Lookup(IntrinsicType::kClamp, {f32, f32, f32}, Source{});
446   ASSERT_NE(result, nullptr) << Diagnostics().str();
447   ASSERT_EQ(Diagnostics().str(), "");
448   EXPECT_EQ(result->Type(), IntrinsicType::kClamp);
449   EXPECT_EQ(result->ReturnType(), f32);
450   EXPECT_EQ(result->Parameters()[0]->Type(), f32);
451   EXPECT_EQ(result->Parameters()[1]->Type(), f32);
452   EXPECT_EQ(result->Parameters()[2]->Type(), f32);
453 }
454 
TEST_F(IntrinsicTableTest,MismatchOpenType)455 TEST_F(IntrinsicTableTest, MismatchOpenType) {
456   auto* f32 = create<sem::F32>();
457   auto* u32 = create<sem::U32>();
458   auto* result =
459       table->Lookup(IntrinsicType::kClamp, {f32, u32, f32}, Source{});
460   ASSERT_EQ(result, nullptr);
461   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
462 }
463 
TEST_F(IntrinsicTableTest,MatchOpenSizeVector)464 TEST_F(IntrinsicTableTest, MatchOpenSizeVector) {
465   auto* f32 = create<sem::F32>();
466   auto* vec2_f32 = create<sem::Vector>(f32, 2);
467   auto* result = table->Lookup(IntrinsicType::kClamp,
468                                {vec2_f32, vec2_f32, vec2_f32}, Source{});
469   ASSERT_NE(result, nullptr) << Diagnostics().str();
470   ASSERT_EQ(Diagnostics().str(), "");
471   EXPECT_EQ(result->Type(), IntrinsicType::kClamp);
472   EXPECT_EQ(result->ReturnType(), vec2_f32);
473   ASSERT_EQ(result->Parameters().size(), 3u);
474   EXPECT_EQ(result->Parameters()[0]->Type(), vec2_f32);
475   EXPECT_EQ(result->Parameters()[1]->Type(), vec2_f32);
476   EXPECT_EQ(result->Parameters()[2]->Type(), vec2_f32);
477 }
478 
TEST_F(IntrinsicTableTest,MismatchOpenSizeVector)479 TEST_F(IntrinsicTableTest, MismatchOpenSizeVector) {
480   auto* f32 = create<sem::F32>();
481   auto* u32 = create<sem::U32>();
482   auto* vec2_f32 = create<sem::Vector>(f32, 2);
483   auto* result =
484       table->Lookup(IntrinsicType::kClamp, {vec2_f32, u32, vec2_f32}, Source{});
485   ASSERT_EQ(result, nullptr);
486   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
487 }
488 
TEST_F(IntrinsicTableTest,MatchOpenSizeMatrix)489 TEST_F(IntrinsicTableTest, MatchOpenSizeMatrix) {
490   auto* f32 = create<sem::F32>();
491   auto* vec3_f32 = create<sem::Vector>(f32, 3);
492   auto* mat3_f32 = create<sem::Matrix>(vec3_f32, 3);
493   auto* result =
494       table->Lookup(IntrinsicType::kDeterminant, {mat3_f32}, Source{});
495   ASSERT_NE(result, nullptr) << Diagnostics().str();
496   ASSERT_EQ(Diagnostics().str(), "");
497   EXPECT_EQ(result->Type(), IntrinsicType::kDeterminant);
498   EXPECT_EQ(result->ReturnType(), f32);
499   ASSERT_EQ(result->Parameters().size(), 1u);
500   EXPECT_EQ(result->Parameters()[0]->Type(), mat3_f32);
501 }
502 
TEST_F(IntrinsicTableTest,MismatchOpenSizeMatrix)503 TEST_F(IntrinsicTableTest, MismatchOpenSizeMatrix) {
504   auto* f32 = create<sem::F32>();
505   auto* vec2_f32 = create<sem::Vector>(f32, 2);
506   auto* mat3x2_f32 = create<sem::Matrix>(vec2_f32, 3);
507   auto* result =
508       table->Lookup(IntrinsicType::kDeterminant, {mat3x2_f32}, Source{});
509   ASSERT_EQ(result, nullptr);
510   ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
511 }
512 
TEST_F(IntrinsicTableTest,OverloadOrderByNumberOfParameters)513 TEST_F(IntrinsicTableTest, OverloadOrderByNumberOfParameters) {
514   // None of the arguments match, so expect the overloads with 2 parameters to
515   // come first
516   auto* bool_ = create<sem::Bool>();
517   table->Lookup(IntrinsicType::kTextureDimensions, {bool_, bool_}, Source{});
518   ASSERT_EQ(Diagnostics().str(),
519             R"(error: no matching call to textureDimensions(bool, bool)
520 
521 27 candidate functions:
522   textureDimensions(texture: texture_1d<T>, level: i32) -> i32  where: T is f32, i32 or u32
523   textureDimensions(texture: texture_2d<T>, level: i32) -> vec2<i32>  where: T is f32, i32 or u32
524   textureDimensions(texture: texture_2d_array<T>, level: i32) -> vec2<i32>  where: T is f32, i32 or u32
525   textureDimensions(texture: texture_3d<T>, level: i32) -> vec3<i32>  where: T is f32, i32 or u32
526   textureDimensions(texture: texture_cube<T>, level: i32) -> vec2<i32>  where: T is f32, i32 or u32
527   textureDimensions(texture: texture_cube_array<T>, level: i32) -> vec2<i32>  where: T is f32, i32 or u32
528   textureDimensions(texture: texture_depth_2d, level: i32) -> vec2<i32>
529   textureDimensions(texture: texture_depth_2d_array, level: i32) -> vec2<i32>
530   textureDimensions(texture: texture_depth_cube, level: i32) -> vec2<i32>
531   textureDimensions(texture: texture_depth_cube_array, level: i32) -> vec2<i32>
532   textureDimensions(texture: texture_1d<T>) -> i32  where: T is f32, i32 or u32
533   textureDimensions(texture: texture_2d<T>) -> vec2<i32>  where: T is f32, i32 or u32
534   textureDimensions(texture: texture_2d_array<T>) -> vec2<i32>  where: T is f32, i32 or u32
535   textureDimensions(texture: texture_3d<T>) -> vec3<i32>  where: T is f32, i32 or u32
536   textureDimensions(texture: texture_cube<T>) -> vec2<i32>  where: T is f32, i32 or u32
537   textureDimensions(texture: texture_cube_array<T>) -> vec2<i32>  where: T is f32, i32 or u32
538   textureDimensions(texture: texture_multisampled_2d<T>) -> vec2<i32>  where: T is f32, i32 or u32
539   textureDimensions(texture: texture_depth_2d) -> vec2<i32>
540   textureDimensions(texture: texture_depth_2d_array) -> vec2<i32>
541   textureDimensions(texture: texture_depth_cube) -> vec2<i32>
542   textureDimensions(texture: texture_depth_cube_array) -> vec2<i32>
543   textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<i32>
544   textureDimensions(texture: texture_storage_1d<F, A>) -> i32  where: A is write
545   textureDimensions(texture: texture_storage_2d<F, A>) -> vec2<i32>  where: A is write
546   textureDimensions(texture: texture_storage_2d_array<F, A>) -> vec2<i32>  where: A is write
547   textureDimensions(texture: texture_storage_3d<F, A>) -> vec3<i32>  where: A is write
548   textureDimensions(texture: texture_external) -> vec2<i32>
549 )");
550 }
551 
TEST_F(IntrinsicTableTest,OverloadOrderByMatchingParameter)552 TEST_F(IntrinsicTableTest, OverloadOrderByMatchingParameter) {
553   auto* tex = create<sem::DepthTexture>(ast::TextureDimension::k2d);
554   auto* bool_ = create<sem::Bool>();
555   table->Lookup(IntrinsicType::kTextureDimensions, {tex, bool_}, Source{});
556   ASSERT_EQ(
557       Diagnostics().str(),
558       R"(error: no matching call to textureDimensions(texture_depth_2d, bool)
559 
560 27 candidate functions:
561   textureDimensions(texture: texture_depth_2d, level: i32) -> vec2<i32>
562   textureDimensions(texture: texture_depth_2d) -> vec2<i32>
563   textureDimensions(texture: texture_1d<T>, level: i32) -> i32  where: T is f32, i32 or u32
564   textureDimensions(texture: texture_2d<T>, level: i32) -> vec2<i32>  where: T is f32, i32 or u32
565   textureDimensions(texture: texture_2d_array<T>, level: i32) -> vec2<i32>  where: T is f32, i32 or u32
566   textureDimensions(texture: texture_3d<T>, level: i32) -> vec3<i32>  where: T is f32, i32 or u32
567   textureDimensions(texture: texture_cube<T>, level: i32) -> vec2<i32>  where: T is f32, i32 or u32
568   textureDimensions(texture: texture_cube_array<T>, level: i32) -> vec2<i32>  where: T is f32, i32 or u32
569   textureDimensions(texture: texture_depth_2d_array, level: i32) -> vec2<i32>
570   textureDimensions(texture: texture_depth_cube, level: i32) -> vec2<i32>
571   textureDimensions(texture: texture_depth_cube_array, level: i32) -> vec2<i32>
572   textureDimensions(texture: texture_1d<T>) -> i32  where: T is f32, i32 or u32
573   textureDimensions(texture: texture_2d<T>) -> vec2<i32>  where: T is f32, i32 or u32
574   textureDimensions(texture: texture_2d_array<T>) -> vec2<i32>  where: T is f32, i32 or u32
575   textureDimensions(texture: texture_3d<T>) -> vec3<i32>  where: T is f32, i32 or u32
576   textureDimensions(texture: texture_cube<T>) -> vec2<i32>  where: T is f32, i32 or u32
577   textureDimensions(texture: texture_cube_array<T>) -> vec2<i32>  where: T is f32, i32 or u32
578   textureDimensions(texture: texture_multisampled_2d<T>) -> vec2<i32>  where: T is f32, i32 or u32
579   textureDimensions(texture: texture_depth_2d_array) -> vec2<i32>
580   textureDimensions(texture: texture_depth_cube) -> vec2<i32>
581   textureDimensions(texture: texture_depth_cube_array) -> vec2<i32>
582   textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<i32>
583   textureDimensions(texture: texture_storage_1d<F, A>) -> i32  where: A is write
584   textureDimensions(texture: texture_storage_2d<F, A>) -> vec2<i32>  where: A is write
585   textureDimensions(texture: texture_storage_2d_array<F, A>) -> vec2<i32>  where: A is write
586   textureDimensions(texture: texture_storage_3d<F, A>) -> vec3<i32>  where: A is write
587   textureDimensions(texture: texture_external) -> vec2<i32>
588 )");
589 }
590 
TEST_F(IntrinsicTableTest,SameOverloadReturnsSameIntrinsicPointer)591 TEST_F(IntrinsicTableTest, SameOverloadReturnsSameIntrinsicPointer) {
592   auto* f32 = create<sem::F32>();
593   auto* vec2_f32 = create<sem::Vector>(create<sem::F32>(), 2);
594   auto* bool_ = create<sem::Bool>();
595   auto* a = table->Lookup(IntrinsicType::kSelect, {f32, f32, bool_}, Source{});
596   ASSERT_NE(a, nullptr) << Diagnostics().str();
597 
598   auto* b = table->Lookup(IntrinsicType::kSelect, {f32, f32, bool_}, Source{});
599   ASSERT_NE(b, nullptr) << Diagnostics().str();
600   ASSERT_EQ(Diagnostics().str(), "");
601 
602   auto* c = table->Lookup(IntrinsicType::kSelect, {vec2_f32, vec2_f32, bool_},
603                           Source{});
604   ASSERT_NE(c, nullptr) << Diagnostics().str();
605   ASSERT_EQ(Diagnostics().str(), "");
606 
607   EXPECT_EQ(a, b);
608   EXPECT_NE(a, c);
609   EXPECT_NE(b, c);
610 }
611 
612 }  // namespace
613 }  // namespace tint
614