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