diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index 6691c8654c..f4c38840c0 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -810,6 +810,7 @@ if(TINT_BUILD_TESTS) sem/sem_struct_test.cc sem/storage_texture_test.cc sem/texture_test.cc + sem/type_test.cc sem/type_manager_test.cc sem/u32_test.cc sem/vector_test.cc diff --git a/src/tint/sem/type.cc b/src/tint/sem/type.cc index 0ee138da9c..06f2a8d11d 100644 --- a/src/tint/sem/type.cc +++ b/src/tint/sem/type.cc @@ -14,6 +14,8 @@ #include "src/tint/sem/type.h" +#include "src/tint/sem/abstract_float.h" +#include "src/tint/sem/abstract_int.h" #include "src/tint/sem/bool.h" #include "src/tint/sem/f16.h" #include "src/tint/sem/f32.h" @@ -153,4 +155,47 @@ bool Type::is_handle() const { return IsAnyOf(); } +uint32_t Type::ConversionRank(const Type* from, const Type* to) { + if (from->UnwrapRef() == to) { + return 0; + } + return Switch( + from, + [&](const AbstractFloat*) { + return Switch( + to, // + [&](const F32*) { return 1; }, // + [&](const F16*) { return 2; }, // + [&](Default) { return kNoConversion; }); + }, + [&](const AbstractInt*) { + return Switch( + to, // + [&](const I32*) { return 3; }, // + [&](const U32*) { return 4; }, // + [&](const AbstractFloat*) { return 5; }, // + [&](const F32*) { return 6; }, // + [&](const F16*) { return 7; }, // + [&](Default) { return kNoConversion; }); + }, + [&](const Vector* from_vec) { + if (auto* to_vec = to->As()) { + if (from_vec->Width() == to_vec->Width()) { + return ConversionRank(from_vec->type(), to_vec->type()); + } + } + return kNoConversion; + }, + [&](const Matrix* from_mat) { + if (auto* to_mat = to->As()) { + if (from_mat->columns() == to_mat->columns() && + from_mat->rows() == to_mat->rows()) { + return ConversionRank(from_mat->type(), to_mat->type()); + } + } + return kNoConversion; + }, + [&](Default) { return kNoConversion; }); +} + } // namespace tint::sem diff --git a/src/tint/sem/type.h b/src/tint/sem/type.h index 271e1d7fca..56ec64b463 100644 --- a/src/tint/sem/type.h +++ b/src/tint/sem/type.h @@ -114,6 +114,19 @@ class Type : public Castable { /// @returns true if this type is a handle type bool is_handle() const; + /// kNoConversion is returned from ConversionRank() when the implicit conversion is not + /// permitted. + static constexpr uint32_t kNoConversion = 0xffffffffu; + + /// ConversionRank returns the implicit conversion rank when attempting to convert `from` to + /// `to`. Lower ranks are preferred over higher ranks. + /// @param from the source type + /// @param to the destination type + /// @returns the rank value for converting from type `from` to type `to`, or #kNoConversion if + /// the implicit conversion is not allowed. + /// @see https://www.w3.org/TR/WGSL/#conversion-rank + static uint32_t ConversionRank(const Type* from, const Type* to); + protected: Type(); }; diff --git a/src/tint/sem/type_test.cc b/src/tint/sem/type_test.cc new file mode 100644 index 0000000000..149ecc7c40 --- /dev/null +++ b/src/tint/sem/type_test.cc @@ -0,0 +1,95 @@ +// Copyright 2022 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/sem/abstract_float.h" +#include "src/tint/sem/abstract_int.h" +#include "src/tint/sem/reference.h" +#include "src/tint/sem/test_helper.h" + +namespace tint::sem { +namespace { + +using TypeTest = TestHelper; + +TEST_F(TypeTest, ConversionRank) { + auto* af = create(); + auto* ai = create(); + auto* f32 = create(); + auto* f16 = create(); + auto* i32 = create(); + auto* u32 = create(); + auto* vec3_f32 = create(f32, 3u); + auto* vec3_f16 = create(f16, 3u); + auto* vec4_f32 = create(f32, 4u); + auto* vec3_u32 = create(u32, 3u); + auto* vec3_i32 = create(i32, 3u); + auto* vec3_af = create(af, 3u); + auto* vec3_ai = create(ai, 3u); + auto* mat3x4_f32 = create(vec4_f32, 3u); + auto* mat4x3_f32 = create(vec3_f32, 4u); + auto* mat4x3_f16 = create(vec3_f16, 4u); + auto* mat4x3_af = create(vec3_af, 4u); + auto* ref_u32 = create(u32, ast::StorageClass::kPrivate, ast::Access::kReadWrite); + + EXPECT_EQ(Type::ConversionRank(i32, i32), 0u); + EXPECT_EQ(Type::ConversionRank(f32, f32), 0u); + EXPECT_EQ(Type::ConversionRank(u32, u32), 0u); + EXPECT_EQ(Type::ConversionRank(vec3_f32, vec3_f32), 0u); + EXPECT_EQ(Type::ConversionRank(vec3_f16, vec3_f16), 0u); + EXPECT_EQ(Type::ConversionRank(vec4_f32, vec4_f32), 0u); + EXPECT_EQ(Type::ConversionRank(vec3_u32, vec3_u32), 0u); + EXPECT_EQ(Type::ConversionRank(vec3_i32, vec3_i32), 0u); + EXPECT_EQ(Type::ConversionRank(vec3_af, vec3_af), 0u); + EXPECT_EQ(Type::ConversionRank(vec3_ai, vec3_ai), 0u); + EXPECT_EQ(Type::ConversionRank(mat3x4_f32, mat3x4_f32), 0u); + EXPECT_EQ(Type::ConversionRank(mat4x3_f32, mat4x3_f32), 0u); + EXPECT_EQ(Type::ConversionRank(mat4x3_f16, mat4x3_f16), 0u); + EXPECT_EQ(Type::ConversionRank(mat4x3_af, mat4x3_af), 0u); + EXPECT_EQ(Type::ConversionRank(ref_u32, u32), 0u); + + EXPECT_EQ(Type::ConversionRank(af, f32), 1u); + EXPECT_EQ(Type::ConversionRank(vec3_af, vec3_f32), 1u); + EXPECT_EQ(Type::ConversionRank(mat4x3_af, mat4x3_f32), 1u); + EXPECT_EQ(Type::ConversionRank(af, f16), 2u); + EXPECT_EQ(Type::ConversionRank(vec3_af, vec3_f16), 2u); + EXPECT_EQ(Type::ConversionRank(mat4x3_af, mat4x3_f16), 2u); + EXPECT_EQ(Type::ConversionRank(ai, i32), 3u); + EXPECT_EQ(Type::ConversionRank(vec3_ai, vec3_i32), 3u); + EXPECT_EQ(Type::ConversionRank(ai, u32), 4u); + EXPECT_EQ(Type::ConversionRank(vec3_ai, vec3_u32), 4u); + EXPECT_EQ(Type::ConversionRank(ai, af), 5u); + EXPECT_EQ(Type::ConversionRank(ai, f32), 6u); + EXPECT_EQ(Type::ConversionRank(ai, f16), 7u); + + EXPECT_EQ(Type::ConversionRank(i32, f32), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(f32, u32), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(u32, i32), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(vec3_u32, vec3_f32), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(vec3_f32, vec4_f32), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(mat3x4_f32, mat4x3_f32), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(mat4x3_f32, mat3x4_f32), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(mat4x3_f32, mat4x3_af), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(f32, af), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(f16, af), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(vec3_f16, vec3_af), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(mat4x3_f16, mat4x3_af), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(i32, af), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(u32, af), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(af, ai), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(f32, ai), Type::kNoConversion); + EXPECT_EQ(Type::ConversionRank(f16, ai), Type::kNoConversion); +} + +} // namespace +} // namespace tint::sem diff --git a/test/tint/BUILD.gn b/test/tint/BUILD.gn index 87e26f2538..a66428b540 100644 --- a/test/tint/BUILD.gn +++ b/test/tint/BUILD.gn @@ -303,6 +303,7 @@ tint_unittests_source_set("tint_unittests_sem_src") { "../../src/tint/sem/sem_struct_test.cc", "../../src/tint/sem/storage_texture_test.cc", "../../src/tint/sem/texture_test.cc", + "../../src/tint/sem/type_test.cc", "../../src/tint/sem/type_manager_test.cc", "../../src/tint/sem/u32_test.cc", "../../src/tint/sem/vector_test.cc",