// Copyright 2021 The Tint Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "src/tint/resolver/intrinsic_table.h" #include #include "gmock/gmock.h" #include "src/tint/program_builder.h" #include "src/tint/resolver/resolver_test_helper.h" #include "src/tint/sem/atomic.h" #include "src/tint/sem/depth_multisampled_texture.h" #include "src/tint/sem/depth_texture.h" #include "src/tint/sem/external_texture.h" #include "src/tint/sem/multisampled_texture.h" #include "src/tint/sem/reference.h" #include "src/tint/sem/sampled_texture.h" #include "src/tint/sem/storage_texture.h" #include "src/tint/sem/test_helper.h" #include "src/tint/sem/type_constructor.h" #include "src/tint/sem/type_conversion.h" namespace tint::resolver { namespace { using ::testing::HasSubstr; using BuiltinType = sem::BuiltinType; using Parameter = sem::Parameter; using ParameterUsage = sem::ParameterUsage; using AFloatV = builder::vec<3, AFloat>; using AIntV = builder::vec<3, AInt>; using f32V = builder::vec<3, f32>; using i32V = builder::vec<3, i32>; using u32V = builder::vec<3, u32>; class IntrinsicTableTest : public testing::Test, public ProgramBuilder { public: std::unique_ptr table = IntrinsicTable::Create(*this); }; TEST_F(IntrinsicTableTest, MatchF32) { auto* f32 = create(); auto result = table->Lookup(BuiltinType::kCos, {f32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kCos); EXPECT_EQ(result.sem->ReturnType(), f32); ASSERT_EQ(result.sem->Parameters().size(), 1u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32); } TEST_F(IntrinsicTableTest, MismatchF32) { auto* i32 = create(); auto result = table->Lookup(BuiltinType::kCos, {i32}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, MatchU32) { auto* f32 = create(); auto* u32 = create(); auto* vec2_f32 = create(f32, 2u); auto result = table->Lookup(BuiltinType::kUnpack2x16float, {u32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kUnpack2x16float); EXPECT_EQ(result.sem->ReturnType(), vec2_f32); ASSERT_EQ(result.sem->Parameters().size(), 1u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), u32); } TEST_F(IntrinsicTableTest, MismatchU32) { auto* f32 = create(); auto result = table->Lookup(BuiltinType::kUnpack2x16float, {f32}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, MatchI32) { auto* f32 = create(); auto* i32 = create(); auto* vec4_f32 = create(f32, 4u); auto* tex = create(ast::TextureDimension::k1d, f32); auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, i32, i32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad); EXPECT_EQ(result.sem->ReturnType(), vec4_f32); ASSERT_EQ(result.sem->Parameters().size(), 3u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex); EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture); EXPECT_EQ(result.sem->Parameters()[1]->Type(), i32); EXPECT_EQ(result.sem->Parameters()[1]->Usage(), ParameterUsage::kCoords); EXPECT_EQ(result.sem->Parameters()[2]->Type(), i32); EXPECT_EQ(result.sem->Parameters()[2]->Usage(), ParameterUsage::kLevel); } TEST_F(IntrinsicTableTest, MismatchI32) { auto* f32 = create(); auto* tex = create(ast::TextureDimension::k1d, f32); auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, f32}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, MatchIU32AsI32) { auto* i32 = create(); auto result = table->Lookup(BuiltinType::kCountOneBits, {i32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kCountOneBits); EXPECT_EQ(result.sem->ReturnType(), i32); ASSERT_EQ(result.sem->Parameters().size(), 1u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), i32); } TEST_F(IntrinsicTableTest, MatchIU32AsU32) { auto* u32 = create(); auto result = table->Lookup(BuiltinType::kCountOneBits, {u32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kCountOneBits); EXPECT_EQ(result.sem->ReturnType(), u32); ASSERT_EQ(result.sem->Parameters().size(), 1u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), u32); } TEST_F(IntrinsicTableTest, MismatchIU32) { auto* f32 = create(); auto result = table->Lookup(BuiltinType::kCountOneBits, {f32}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, MatchFIU32AsI32) { auto* i32 = create(); auto result = table->Lookup(BuiltinType::kClamp, {i32, i32, i32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp); EXPECT_EQ(result.sem->ReturnType(), i32); ASSERT_EQ(result.sem->Parameters().size(), 3u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), i32); EXPECT_EQ(result.sem->Parameters()[1]->Type(), i32); EXPECT_EQ(result.sem->Parameters()[2]->Type(), i32); } TEST_F(IntrinsicTableTest, MatchFIU32AsU32) { auto* u32 = create(); auto result = table->Lookup(BuiltinType::kClamp, {u32, u32, u32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp); EXPECT_EQ(result.sem->ReturnType(), u32); ASSERT_EQ(result.sem->Parameters().size(), 3u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), u32); EXPECT_EQ(result.sem->Parameters()[1]->Type(), u32); EXPECT_EQ(result.sem->Parameters()[2]->Type(), u32); } TEST_F(IntrinsicTableTest, MatchFIU32AsF32) { auto* f32 = create(); auto result = table->Lookup(BuiltinType::kClamp, {f32, f32, f32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp); EXPECT_EQ(result.sem->ReturnType(), f32); ASSERT_EQ(result.sem->Parameters().size(), 3u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32); EXPECT_EQ(result.sem->Parameters()[1]->Type(), f32); EXPECT_EQ(result.sem->Parameters()[2]->Type(), f32); } TEST_F(IntrinsicTableTest, MismatchFIU32) { auto* bool_ = create(); auto result = table->Lookup(BuiltinType::kClamp, {bool_, bool_, bool_}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, MatchBool) { auto* f32 = create(); auto* bool_ = create(); auto result = table->Lookup(BuiltinType::kSelect, {f32, f32, bool_}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect); EXPECT_EQ(result.sem->ReturnType(), f32); ASSERT_EQ(result.sem->Parameters().size(), 3u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32); EXPECT_EQ(result.sem->Parameters()[1]->Type(), f32); EXPECT_EQ(result.sem->Parameters()[2]->Type(), bool_); } TEST_F(IntrinsicTableTest, MismatchBool) { auto* f32 = create(); auto result = table->Lookup(BuiltinType::kSelect, {f32, f32, f32}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, MatchPointer) { auto* i32 = create(); auto* atomicI32 = create(i32); auto* ptr = create(atomicI32, ast::StorageClass::kWorkgroup, ast::Access::kReadWrite); auto result = table->Lookup(BuiltinType::kAtomicLoad, {ptr}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kAtomicLoad); EXPECT_EQ(result.sem->ReturnType(), i32); ASSERT_EQ(result.sem->Parameters().size(), 1u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), ptr); } TEST_F(IntrinsicTableTest, MismatchPointer) { auto* i32 = create(); auto* atomicI32 = create(i32); auto result = table->Lookup(BuiltinType::kAtomicLoad, {atomicI32}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, MatchArray) { auto* arr = create(create(), 0u, 4u, 4u, 4u, 4u); auto* arr_ptr = create(arr, ast::StorageClass::kStorage, ast::Access::kReadWrite); auto result = table->Lookup(BuiltinType::kArrayLength, {arr_ptr}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kArrayLength); EXPECT_TRUE(result.sem->ReturnType()->Is()); ASSERT_EQ(result.sem->Parameters().size(), 1u); auto* param_type = result.sem->Parameters()[0]->Type(); ASSERT_TRUE(param_type->Is()); EXPECT_TRUE(param_type->As()->StoreType()->Is()); } TEST_F(IntrinsicTableTest, MismatchArray) { auto* f32 = create(); auto result = table->Lookup(BuiltinType::kArrayLength, {f32}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, MatchSampler) { auto* f32 = create(); auto* vec2_f32 = create(f32, 2u); auto* vec4_f32 = create(f32, 4u); auto* tex = create(ast::TextureDimension::k2d, f32); auto* sampler = create(ast::SamplerKind::kSampler); auto result = table->Lookup(BuiltinType::kTextureSample, {tex, sampler, vec2_f32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureSample); EXPECT_EQ(result.sem->ReturnType(), vec4_f32); ASSERT_EQ(result.sem->Parameters().size(), 3u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex); EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture); EXPECT_EQ(result.sem->Parameters()[1]->Type(), sampler); EXPECT_EQ(result.sem->Parameters()[1]->Usage(), ParameterUsage::kSampler); EXPECT_EQ(result.sem->Parameters()[2]->Type(), vec2_f32); EXPECT_EQ(result.sem->Parameters()[2]->Usage(), ParameterUsage::kCoords); } TEST_F(IntrinsicTableTest, MismatchSampler) { auto* f32 = create(); auto* vec2_f32 = create(f32, 2u); auto* tex = create(ast::TextureDimension::k2d, f32); auto result = table->Lookup(BuiltinType::kTextureSample, {tex, f32, vec2_f32}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, MatchSampledTexture) { auto* i32 = create(); auto* f32 = create(); auto* vec2_i32 = create(i32, 2u); auto* vec4_f32 = create(f32, 4u); auto* tex = create(ast::TextureDimension::k2d, f32); auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad); EXPECT_EQ(result.sem->ReturnType(), vec4_f32); ASSERT_EQ(result.sem->Parameters().size(), 3u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex); EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture); EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_i32); EXPECT_EQ(result.sem->Parameters()[1]->Usage(), ParameterUsage::kCoords); EXPECT_EQ(result.sem->Parameters()[2]->Type(), i32); EXPECT_EQ(result.sem->Parameters()[2]->Usage(), ParameterUsage::kLevel); } TEST_F(IntrinsicTableTest, MatchMultisampledTexture) { auto* i32 = create(); auto* f32 = create(); auto* vec2_i32 = create(i32, 2u); auto* vec4_f32 = create(f32, 4u); auto* tex = create(ast::TextureDimension::k2d, f32); auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad); EXPECT_EQ(result.sem->ReturnType(), vec4_f32); ASSERT_EQ(result.sem->Parameters().size(), 3u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex); EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture); EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_i32); EXPECT_EQ(result.sem->Parameters()[1]->Usage(), ParameterUsage::kCoords); EXPECT_EQ(result.sem->Parameters()[2]->Type(), i32); EXPECT_EQ(result.sem->Parameters()[2]->Usage(), ParameterUsage::kSampleIndex); } TEST_F(IntrinsicTableTest, MatchDepthTexture) { auto* f32 = create(); auto* i32 = create(); auto* vec2_i32 = create(i32, 2u); auto* tex = create(ast::TextureDimension::k2d); auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad); EXPECT_EQ(result.sem->ReturnType(), f32); ASSERT_EQ(result.sem->Parameters().size(), 3u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex); EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture); EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_i32); EXPECT_EQ(result.sem->Parameters()[1]->Usage(), ParameterUsage::kCoords); EXPECT_EQ(result.sem->Parameters()[2]->Type(), i32); EXPECT_EQ(result.sem->Parameters()[2]->Usage(), ParameterUsage::kLevel); } TEST_F(IntrinsicTableTest, MatchDepthMultisampledTexture) { auto* f32 = create(); auto* i32 = create(); auto* vec2_i32 = create(i32, 2u); auto* tex = create(ast::TextureDimension::k2d); auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad); EXPECT_EQ(result.sem->ReturnType(), f32); ASSERT_EQ(result.sem->Parameters().size(), 3u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex); EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture); EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_i32); EXPECT_EQ(result.sem->Parameters()[1]->Usage(), ParameterUsage::kCoords); EXPECT_EQ(result.sem->Parameters()[2]->Type(), i32); EXPECT_EQ(result.sem->Parameters()[2]->Usage(), ParameterUsage::kSampleIndex); } TEST_F(IntrinsicTableTest, MatchExternalTexture) { auto* f32 = create(); auto* i32 = create(); auto* vec2_i32 = create(i32, 2u); auto* vec4_f32 = create(f32, 4u); auto* tex = create(); auto result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad); EXPECT_EQ(result.sem->ReturnType(), vec4_f32); ASSERT_EQ(result.sem->Parameters().size(), 2u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex); EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture); EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_i32); EXPECT_EQ(result.sem->Parameters()[1]->Usage(), ParameterUsage::kCoords); } TEST_F(IntrinsicTableTest, MatchWOStorageTexture) { auto* f32 = create(); auto* i32 = create(); auto* vec2_i32 = create(i32, 2u); auto* vec4_f32 = create(f32, 4u); auto* subtype = sem::StorageTexture::SubtypeFor(ast::TexelFormat::kR32Float, Types()); auto* tex = create(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float, ast::Access::kWrite, subtype); auto result = table->Lookup(BuiltinType::kTextureStore, {tex, vec2_i32, vec4_f32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureStore); EXPECT_TRUE(result.sem->ReturnType()->Is()); ASSERT_EQ(result.sem->Parameters().size(), 3u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex); EXPECT_EQ(result.sem->Parameters()[0]->Usage(), ParameterUsage::kTexture); EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_i32); EXPECT_EQ(result.sem->Parameters()[1]->Usage(), ParameterUsage::kCoords); EXPECT_EQ(result.sem->Parameters()[2]->Type(), vec4_f32); EXPECT_EQ(result.sem->Parameters()[2]->Usage(), ParameterUsage::kValue); } TEST_F(IntrinsicTableTest, MismatchTexture) { auto* f32 = create(); auto* i32 = create(); auto* vec2_i32 = create(i32, 2u); auto result = table->Lookup(BuiltinType::kTextureLoad, {f32, vec2_i32}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, ImplicitLoadOnReference) { auto* f32 = create(); auto result = table->Lookup( BuiltinType::kCos, {create(f32, ast::StorageClass::kFunction, ast::Access::kReadWrite)}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kCos); EXPECT_EQ(result.sem->ReturnType(), f32); ASSERT_EQ(result.sem->Parameters().size(), 1u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32); } TEST_F(IntrinsicTableTest, MatchTemplateType) { auto* f32 = create(); auto result = table->Lookup(BuiltinType::kClamp, {f32, f32, f32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp); EXPECT_EQ(result.sem->ReturnType(), f32); EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32); EXPECT_EQ(result.sem->Parameters()[1]->Type(), f32); EXPECT_EQ(result.sem->Parameters()[2]->Type(), f32); } TEST_F(IntrinsicTableTest, MismatchTemplateType) { auto* f32 = create(); auto* u32 = create(); auto result = table->Lookup(BuiltinType::kClamp, {f32, u32, f32}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, MatchOpenSizeVector) { auto* f32 = create(); auto* vec2_f32 = create(f32, 2u); auto result = table->Lookup(BuiltinType::kClamp, {vec2_f32, vec2_f32, vec2_f32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp); EXPECT_EQ(result.sem->ReturnType(), vec2_f32); ASSERT_EQ(result.sem->Parameters().size(), 3u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), vec2_f32); EXPECT_EQ(result.sem->Parameters()[1]->Type(), vec2_f32); EXPECT_EQ(result.sem->Parameters()[2]->Type(), vec2_f32); } TEST_F(IntrinsicTableTest, MismatchOpenSizeVector) { auto* f32 = create(); auto* u32 = create(); auto* vec2_f32 = create(f32, 2u); auto result = table->Lookup(BuiltinType::kClamp, {vec2_f32, u32, vec2_f32}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, MatchOpenSizeMatrix) { auto* f32 = create(); auto* vec3_f32 = create(f32, 3u); auto* mat3_f32 = create(vec3_f32, 3u); auto result = table->Lookup(BuiltinType::kDeterminant, {mat3_f32}, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(result.sem->Type(), BuiltinType::kDeterminant); EXPECT_EQ(result.sem->ReturnType(), f32); ASSERT_EQ(result.sem->Parameters().size(), 1u); EXPECT_EQ(result.sem->Parameters()[0]->Type(), mat3_f32); } TEST_F(IntrinsicTableTest, MismatchOpenSizeMatrix) { auto* f32 = create(); auto* vec2_f32 = create(f32, 2u); auto* mat3x2_f32 = create(vec2_f32, 3u); auto result = table->Lookup(BuiltinType::kDeterminant, {mat3x2_f32}, Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, OverloadOrderByNumberOfParameters) { // None of the arguments match, so expect the overloads with 2 parameters to // come first auto* bool_ = create(); table->Lookup(BuiltinType::kTextureDimensions, {bool_, bool_}, Source{}); ASSERT_EQ(Diagnostics().str(), R"(error: no matching call to textureDimensions(bool, bool) 27 candidate functions: textureDimensions(texture: texture_1d, level: i32) -> i32 where: T is f32, i32 or u32 textureDimensions(texture: texture_2d, level: i32) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_2d_array, level: i32) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_3d, level: i32) -> vec3 where: T is f32, i32 or u32 textureDimensions(texture: texture_cube, level: i32) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_cube_array, level: i32) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_depth_2d, level: i32) -> vec2 textureDimensions(texture: texture_depth_2d_array, level: i32) -> vec2 textureDimensions(texture: texture_depth_cube, level: i32) -> vec2 textureDimensions(texture: texture_depth_cube_array, level: i32) -> vec2 textureDimensions(texture: texture_1d) -> i32 where: T is f32, i32 or u32 textureDimensions(texture: texture_2d) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_2d_array) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_3d) -> vec3 where: T is f32, i32 or u32 textureDimensions(texture: texture_cube) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_cube_array) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_multisampled_2d) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_depth_2d) -> vec2 textureDimensions(texture: texture_depth_2d_array) -> vec2 textureDimensions(texture: texture_depth_cube) -> vec2 textureDimensions(texture: texture_depth_cube_array) -> vec2 textureDimensions(texture: texture_depth_multisampled_2d) -> vec2 textureDimensions(texture: texture_storage_1d) -> i32 where: A is write textureDimensions(texture: texture_storage_2d) -> vec2 where: A is write textureDimensions(texture: texture_storage_2d_array) -> vec2 where: A is write textureDimensions(texture: texture_storage_3d) -> vec3 where: A is write textureDimensions(texture: texture_external) -> vec2 )"); } TEST_F(IntrinsicTableTest, OverloadOrderByMatchingParameter) { auto* tex = create(ast::TextureDimension::k2d); auto* bool_ = create(); table->Lookup(BuiltinType::kTextureDimensions, {tex, bool_}, Source{}); ASSERT_EQ(Diagnostics().str(), R"(error: no matching call to textureDimensions(texture_depth_2d, bool) 27 candidate functions: textureDimensions(texture: texture_depth_2d, level: i32) -> vec2 textureDimensions(texture: texture_depth_2d) -> vec2 textureDimensions(texture: texture_1d, level: i32) -> i32 where: T is f32, i32 or u32 textureDimensions(texture: texture_2d, level: i32) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_2d_array, level: i32) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_3d, level: i32) -> vec3 where: T is f32, i32 or u32 textureDimensions(texture: texture_cube, level: i32) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_cube_array, level: i32) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_depth_2d_array, level: i32) -> vec2 textureDimensions(texture: texture_depth_cube, level: i32) -> vec2 textureDimensions(texture: texture_depth_cube_array, level: i32) -> vec2 textureDimensions(texture: texture_1d) -> i32 where: T is f32, i32 or u32 textureDimensions(texture: texture_2d) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_2d_array) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_3d) -> vec3 where: T is f32, i32 or u32 textureDimensions(texture: texture_cube) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_cube_array) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_multisampled_2d) -> vec2 where: T is f32, i32 or u32 textureDimensions(texture: texture_depth_2d_array) -> vec2 textureDimensions(texture: texture_depth_cube) -> vec2 textureDimensions(texture: texture_depth_cube_array) -> vec2 textureDimensions(texture: texture_depth_multisampled_2d) -> vec2 textureDimensions(texture: texture_storage_1d) -> i32 where: A is write textureDimensions(texture: texture_storage_2d) -> vec2 where: A is write textureDimensions(texture: texture_storage_2d_array) -> vec2 where: A is write textureDimensions(texture: texture_storage_3d) -> vec3 where: A is write textureDimensions(texture: texture_external) -> vec2 )"); } TEST_F(IntrinsicTableTest, SameOverloadReturnsSameBuiltinPointer) { auto* f32 = create(); auto* vec2_f32 = create(create(), 2u); auto* bool_ = create(); auto a = table->Lookup(BuiltinType::kSelect, {f32, f32, bool_}, Source{}); ASSERT_NE(a.sem, nullptr) << Diagnostics().str(); auto b = table->Lookup(BuiltinType::kSelect, {f32, f32, bool_}, Source{}); ASSERT_NE(b.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); auto c = table->Lookup(BuiltinType::kSelect, {vec2_f32, vec2_f32, bool_}, Source{}); ASSERT_NE(c.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); EXPECT_EQ(a.sem, b.sem); EXPECT_NE(a.sem, c.sem); EXPECT_NE(b.sem, c.sem); } TEST_F(IntrinsicTableTest, MatchUnaryOp) { auto* i32 = create(); auto* vec3_i32 = create(i32, 3u); auto result = table->Lookup(ast::UnaryOp::kNegation, vec3_i32, Source{{12, 34}}); EXPECT_EQ(result.result, vec3_i32); EXPECT_EQ(result.result, vec3_i32); EXPECT_EQ(Diagnostics().str(), ""); } TEST_F(IntrinsicTableTest, MismatchUnaryOp) { auto* bool_ = create(); auto result = table->Lookup(ast::UnaryOp::kNegation, bool_, Source{{12, 34}}); ASSERT_EQ(result.result, nullptr); EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator - (bool) 2 candidate operators: operator - (T) -> T where: T is abstract-float, abstract-int, f32, i32 or f16 operator - (vecN) -> vecN where: T is abstract-float, abstract-int, f32, i32 or f16 )"); } TEST_F(IntrinsicTableTest, MatchBinaryOp) { auto* i32 = create(); auto* vec3_i32 = create(i32, 3u); auto result = table->Lookup(ast::BinaryOp::kMultiply, i32, vec3_i32, Source{{12, 34}}, /* is_compound */ false); EXPECT_EQ(result.result, vec3_i32); EXPECT_EQ(result.lhs, i32); EXPECT_EQ(result.rhs, vec3_i32); EXPECT_EQ(Diagnostics().str(), ""); } TEST_F(IntrinsicTableTest, MismatchBinaryOp) { auto* f32 = create(); auto* bool_ = create(); auto result = table->Lookup(ast::BinaryOp::kMultiply, f32, bool_, Source{{12, 34}}, /* is_compound */ false); ASSERT_EQ(result.result, nullptr); EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator * (f32, bool) 9 candidate operators: operator * (T, T) -> T where: T is f32, i32, u32 or f16 operator * (vecN, T) -> vecN where: T is f32, i32, u32 or f16 operator * (T, vecN) -> vecN where: T is f32, i32, u32 or f16 operator * (T, matNxM) -> matNxM where: T is f32 or f16 operator * (matNxM, T) -> matNxM where: T is f32 or f16 operator * (vecN, vecN) -> vecN where: T is f32, i32, u32 or f16 operator * (matCxR, vecC) -> vecR where: T is f32 or f16 operator * (vecR, matCxR) -> vecC where: T is f32 or f16 operator * (matKxR, matCxK) -> matCxR where: T is f32 or f16 )"); } TEST_F(IntrinsicTableTest, MatchCompoundOp) { auto* i32 = create(); auto* vec3_i32 = create(i32, 3u); auto result = table->Lookup(ast::BinaryOp::kMultiply, i32, vec3_i32, Source{{12, 34}}, /* is_compound */ true); EXPECT_EQ(result.result, vec3_i32); EXPECT_EQ(result.lhs, i32); EXPECT_EQ(result.rhs, vec3_i32); EXPECT_EQ(Diagnostics().str(), ""); } TEST_F(IntrinsicTableTest, MismatchCompoundOp) { auto* f32 = create(); auto* bool_ = create(); auto result = table->Lookup(ast::BinaryOp::kMultiply, f32, bool_, Source{{12, 34}}, /* is_compound */ true); ASSERT_EQ(result.result, nullptr); EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator *= (f32, bool) 9 candidate operators: operator *= (T, T) -> T where: T is f32, i32, u32 or f16 operator *= (vecN, T) -> vecN where: T is f32, i32, u32 or f16 operator *= (T, vecN) -> vecN where: T is f32, i32, u32 or f16 operator *= (T, matNxM) -> matNxM where: T is f32 or f16 operator *= (matNxM, T) -> matNxM where: T is f32 or f16 operator *= (vecN, vecN) -> vecN where: T is f32, i32, u32 or f16 operator *= (matCxR, vecC) -> vecR where: T is f32 or f16 operator *= (vecR, matCxR) -> vecC where: T is f32 or f16 operator *= (matKxR, matCxK) -> matCxR where: T is f32 or f16 )"); } TEST_F(IntrinsicTableTest, MatchTypeConstructorImplicit) { auto* i32 = create(); auto* vec3_i32 = create(i32, 3u); auto result = table->Lookup(CtorConvIntrinsic::kVec3, nullptr, {i32, i32, i32}, Source{{12, 34}}); ASSERT_NE(result.target, nullptr); EXPECT_EQ(result.target->ReturnType(), vec3_i32); EXPECT_TRUE(result.target->Is()); ASSERT_EQ(result.target->Parameters().size(), 3u); EXPECT_EQ(result.target->Parameters()[0]->Type(), i32); EXPECT_EQ(result.target->Parameters()[1]->Type(), i32); EXPECT_EQ(result.target->Parameters()[2]->Type(), i32); EXPECT_NE(result.const_eval_fn, nullptr); } TEST_F(IntrinsicTableTest, MatchTypeConstructorExplicit) { auto* i32 = create(); auto* vec3_i32 = create(i32, 3u); auto result = table->Lookup(CtorConvIntrinsic::kVec3, i32, {i32, i32, i32}, Source{{12, 34}}); ASSERT_NE(result.target, nullptr); EXPECT_EQ(result.target->ReturnType(), vec3_i32); EXPECT_TRUE(result.target->Is()); ASSERT_EQ(result.target->Parameters().size(), 3u); EXPECT_EQ(result.target->Parameters()[0]->Type(), i32); EXPECT_EQ(result.target->Parameters()[1]->Type(), i32); EXPECT_EQ(result.target->Parameters()[2]->Type(), i32); EXPECT_NE(result.const_eval_fn, nullptr); } TEST_F(IntrinsicTableTest, MismatchTypeConstructorImplicit) { auto* i32 = create(); auto* f32 = create(); auto result = table->Lookup(CtorConvIntrinsic::kVec3, nullptr, {i32, f32, i32}, Source{{12, 34}}); ASSERT_EQ(result.target, nullptr); EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching constructor for vec3(i32, f32, i32) 6 candidate constructors: vec3(x: T, y: T, z: T) -> vec3 where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool vec3(xy: vec2, z: T) -> vec3 where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool vec3(x: T, yz: vec2) -> vec3 where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool vec3(T) -> vec3 where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool vec3(vec3) -> vec3 where: T is f32, f16, i32, u32 or bool vec3() -> vec3 where: T is f32, f16, i32, u32 or bool 5 candidate conversions: vec3(vec3) -> vec3 where: T is f32, U is i32, f16, u32 or bool vec3(vec3) -> vec3 where: T is f16, U is f32, i32, u32 or bool vec3(vec3) -> vec3 where: T is i32, U is f32, f16, u32 or bool vec3(vec3) -> vec3 where: T is u32, U is f32, f16, i32 or bool vec3(vec3) -> vec3 where: T is bool, U is f32, f16, i32 or u32 )"); } TEST_F(IntrinsicTableTest, MismatchTypeConstructorExplicit) { auto* i32 = create(); auto* f32 = create(); auto result = table->Lookup(CtorConvIntrinsic::kVec3, i32, {i32, f32, i32}, Source{{12, 34}}); ASSERT_EQ(result.target, nullptr); EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching constructor for vec3(i32, f32, i32) 6 candidate constructors: vec3(x: T, y: T, z: T) -> vec3 where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool vec3(x: T, yz: vec2) -> vec3 where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool vec3(T) -> vec3 where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool vec3(xy: vec2, z: T) -> vec3 where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool vec3(vec3) -> vec3 where: T is f32, f16, i32, u32 or bool vec3() -> vec3 where: T is f32, f16, i32, u32 or bool 5 candidate conversions: vec3(vec3) -> vec3 where: T is f32, U is i32, f16, u32 or bool vec3(vec3) -> vec3 where: T is f16, U is f32, i32, u32 or bool vec3(vec3) -> vec3 where: T is i32, U is f32, f16, u32 or bool vec3(vec3) -> vec3 where: T is u32, U is f32, f16, i32 or bool vec3(vec3) -> vec3 where: T is bool, U is f32, f16, i32 or u32 )"); } TEST_F(IntrinsicTableTest, MatchTypeConversion) { auto* i32 = create(); auto* vec3_i32 = create(i32, 3u); auto* f32 = create(); auto* vec3_f32 = create(f32, 3u); auto result = table->Lookup(CtorConvIntrinsic::kVec3, i32, {vec3_f32}, Source{{12, 34}}); ASSERT_NE(result.target, nullptr); EXPECT_EQ(result.target->ReturnType(), vec3_i32); EXPECT_TRUE(result.target->Is()); ASSERT_EQ(result.target->Parameters().size(), 1u); EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_f32); } TEST_F(IntrinsicTableTest, MismatchTypeConversion) { auto* arr = create(create(), 0u, 4u, 4u, 4u, 4u); auto* f32 = create(); auto result = table->Lookup(CtorConvIntrinsic::kVec3, f32, {arr}, Source{{12, 34}}); ASSERT_EQ(result.target, nullptr); EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching constructor for vec3(array) 6 candidate constructors: vec3(vec3) -> vec3 where: T is f32, f16, i32, u32 or bool vec3(T) -> vec3 where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool vec3() -> vec3 where: T is f32, f16, i32, u32 or bool vec3(xy: vec2, z: T) -> vec3 where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool vec3(x: T, yz: vec2) -> vec3 where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool vec3(x: T, y: T, z: T) -> vec3 where: T is abstract-int, abstract-float, f32, f16, i32, u32 or bool 5 candidate conversions: vec3(vec3) -> vec3 where: T is f32, U is i32, f16, u32 or bool vec3(vec3) -> vec3 where: T is f16, U is f32, i32, u32 or bool vec3(vec3) -> vec3 where: T is i32, U is f32, f16, u32 or bool vec3(vec3) -> vec3 where: T is u32, U is f32, f16, i32 or bool vec3(vec3) -> vec3 where: T is bool, U is f32, f16, i32 or u32 )"); } TEST_F(IntrinsicTableTest, Err257Arguments) { // crbug.com/1323605 auto* f32 = create(); std::vector arg_tys(257, f32); auto result = table->Lookup(BuiltinType::kAbs, std::move(arg_tys), Source{}); ASSERT_EQ(result.sem, nullptr); ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } TEST_F(IntrinsicTableTest, OverloadResolution) { // i32(abstract-int) produces candidates for both: // ctor i32(i32) -> i32 // conv i32(T) -> i32 // The first should win overload resolution. auto* ai = create(); auto* i32 = create(); auto result = table->Lookup(CtorConvIntrinsic::kI32, nullptr, {ai}, Source{}); ASSERT_NE(result.target, nullptr); EXPECT_EQ(result.target->ReturnType(), i32); EXPECT_EQ(result.target->Parameters().size(), 1u); EXPECT_EQ(result.target->Parameters()[0]->Type(), i32); } //////////////////////////////////////////////////////////////////////////////// // AbstractBinaryTests //////////////////////////////////////////////////////////////////////////////// namespace AbstractBinaryTests { struct Case { template static Case Create(bool match = true) { return { match, // builder::DataType::Sem, // builder::DataType::Sem, // builder::DataType::Sem, // builder::DataType::Sem, // builder::DataType::Sem, // }; } bool expected_match; builder::sem_type_func_ptr expected_result; builder::sem_type_func_ptr expected_param_lhs; builder::sem_type_func_ptr expected_param_rhs; builder::sem_type_func_ptr arg_lhs; builder::sem_type_func_ptr arg_rhs; }; struct IntrinsicTableAbstractBinaryTest : public ResolverTestWithParam { std::unique_ptr table = IntrinsicTable::Create(*this); }; TEST_P(IntrinsicTableAbstractBinaryTest, MatchAdd) { auto* arg_lhs = GetParam().arg_lhs(*this); auto* arg_rhs = GetParam().arg_rhs(*this); auto result = table->Lookup(ast::BinaryOp::kAdd, arg_lhs, arg_rhs, Source{{12, 34}}, /* is_compound */ false); bool matched = result.result != nullptr; bool expected_match = GetParam().expected_match; EXPECT_EQ(matched, expected_match) << Diagnostics().str(); auto* expected_result = GetParam().expected_result(*this); EXPECT_TYPE(result.result, expected_result); auto* expected_param_lhs = GetParam().expected_param_lhs(*this); EXPECT_TYPE(result.lhs, expected_param_lhs); auto* expected_param_rhs = GetParam().expected_param_rhs(*this); EXPECT_TYPE(result.rhs, expected_param_rhs); } INSTANTIATE_TEST_SUITE_P(AFloat_AInt, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(), Case::Create(), Case::Create(), Case::Create() )); // clang-format on INSTANTIATE_TEST_SUITE_P(VecAFloat_VecAInt, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(), Case::Create(), Case::Create(), Case::Create() )); // clang-format on INSTANTIATE_TEST_SUITE_P(AFloat_f32, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(), Case::Create() )); // clang-format on INSTANTIATE_TEST_SUITE_P(VecAFloat_Vecf32, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(), Case::Create() )); // clang-format on INSTANTIATE_TEST_SUITE_P( AFloat_i32, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(false), Case::Create(false) )); // clang-format on INSTANTIATE_TEST_SUITE_P( VecAFloat_Veci32, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(false), Case::Create(false) )); // clang-format on INSTANTIATE_TEST_SUITE_P( AFloat_u32, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(false), Case::Create(false) )); // clang-format on INSTANTIATE_TEST_SUITE_P( VecAFloat_Vecu32, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(false), Case::Create(false) )); // clang-format on INSTANTIATE_TEST_SUITE_P(AInt_f32, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(), Case::Create() )); // clang-format on INSTANTIATE_TEST_SUITE_P(VecAInt_Vecf32, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(), Case::Create() )); // clang-format on INSTANTIATE_TEST_SUITE_P(AInt_i32, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(), Case::Create() )); // clang-format on INSTANTIATE_TEST_SUITE_P(VecAInt_Veci32, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(), Case::Create() )); // clang-format on INSTANTIATE_TEST_SUITE_P(AInt_u32, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(), Case::Create() )); // clang-format on INSTANTIATE_TEST_SUITE_P(VecAInt_Vecu32, IntrinsicTableAbstractBinaryTest, testing::Values( // clang-format off // result | param lhs | param rhs | arg lhs | arg rhs Case::Create(), Case::Create() )); // clang-format on } // namespace AbstractBinaryTests //////////////////////////////////////////////////////////////////////////////// // AbstractTernaryTests //////////////////////////////////////////////////////////////////////////////// namespace AbstractTernaryTests { struct Case { template static Case Create(bool match = true) { return { match, builder::DataType::Sem, // builder::DataType::Sem, // builder::DataType::Sem, // builder::DataType::Sem, // builder::DataType::Sem, // builder::DataType::Sem, // builder::DataType::Sem, // }; } bool expected_match; builder::sem_type_func_ptr expected_result; builder::sem_type_func_ptr expected_param_a; builder::sem_type_func_ptr expected_param_b; builder::sem_type_func_ptr expected_param_c; builder::sem_type_func_ptr arg_a; builder::sem_type_func_ptr arg_b; builder::sem_type_func_ptr arg_c; }; struct IntrinsicTableAbstractTernaryTest : public ResolverTestWithParam { std::unique_ptr table = IntrinsicTable::Create(*this); }; TEST_P(IntrinsicTableAbstractTernaryTest, MatchClamp) { auto* arg_a = GetParam().arg_a(*this); auto* arg_b = GetParam().arg_b(*this); auto* arg_c = GetParam().arg_c(*this); auto builtin = table->Lookup(sem::BuiltinType::kClamp, {arg_a, arg_b, arg_c}, Source{{12, 34}}); bool matched = builtin.sem != nullptr; bool expected_match = GetParam().expected_match; EXPECT_EQ(matched, expected_match) << Diagnostics().str(); auto* result = builtin.sem ? builtin.sem->ReturnType() : nullptr; auto* expected_result = GetParam().expected_result(*this); EXPECT_TYPE(result, expected_result); auto* param_a = builtin.sem ? builtin.sem->Parameters()[0]->Type() : nullptr; auto* expected_param_a = GetParam().expected_param_a(*this); EXPECT_TYPE(param_a, expected_param_a); auto* param_b = builtin.sem ? builtin.sem->Parameters()[1]->Type() : nullptr; auto* expected_param_b = GetParam().expected_param_b(*this); EXPECT_TYPE(param_b, expected_param_b); auto* param_c = builtin.sem ? builtin.sem->Parameters()[2]->Type() : nullptr; auto* expected_param_c = GetParam().expected_param_c(*this); EXPECT_TYPE(param_c, expected_param_c); } INSTANTIATE_TEST_SUITE_P( AFloat_AInt, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create() // clang-format on )); INSTANTIATE_TEST_SUITE_P( VecAFloat_VecAInt, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create() // clang-format on )); INSTANTIATE_TEST_SUITE_P( AFloat_f32, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create() // clang-format on )); INSTANTIATE_TEST_SUITE_P( VecAFloat_Vecf32, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create () // clang-format on )); INSTANTIATE_TEST_SUITE_P( AFloat_i32, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(false), Case::Create(false), Case::Create(false), Case::Create(false), Case::Create(false), Case::Create(false) // clang-format on )); INSTANTIATE_TEST_SUITE_P( VecAFloat_Veci32, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(false), Case::Create(false), Case::Create(false), Case::Create(false), Case::Create(false), Case::Create(false) // clang-format on )); INSTANTIATE_TEST_SUITE_P( AFloat_u32, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(false), Case::Create(false), Case::Create(false), Case::Create(false), Case::Create(false), Case::Create(false) // clang-format on )); INSTANTIATE_TEST_SUITE_P( VecAFloat_Vecu32, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(false), Case::Create(false), Case::Create(false), Case::Create(false), Case::Create(false), Case::Create(false) // clang-format on )); INSTANTIATE_TEST_SUITE_P( AInt_f32, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create() // clang-format on )); INSTANTIATE_TEST_SUITE_P( VecAInt_Vecf32, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create() // clang-format on )); INSTANTIATE_TEST_SUITE_P( AInt_i32, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create() // clang-format on )); INSTANTIATE_TEST_SUITE_P( VecAInt_Veci32, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create() // clang-format on )); INSTANTIATE_TEST_SUITE_P( AInt_u32, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create() // clang-format on )); INSTANTIATE_TEST_SUITE_P( VecAInt_Vecu32, IntrinsicTableAbstractTernaryTest, testing::Values( // clang-format off // result | param a | param b | param c | arg a | arg b | arg c Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create(), Case::Create() // clang-format on )); } // namespace AbstractTernaryTests } // namespace } // namespace tint::resolver