[tint] Finish decoupling of intrinsic table from WGSL
The intrinsic table is now reusable for other langauges.
This required moving the WGSL-specifics into the WGSL resolver.
Change-Id: I0e625fabc83b3e47b32bfc5cd1fd8cd67afbd28c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/145262
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index b1e6daa..18e6532 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -289,12 +289,13 @@
sources = [
"lang/core/constant/eval.cc",
"lang/core/constant/eval.h",
- "lang/core/intrinsic/core_table_data.cc",
- "lang/core/intrinsic/core_table_data.h",
"lang/core/intrinsic/ctor_conv.cc",
"lang/core/intrinsic/ctor_conv.h",
"lang/core/intrinsic/table.cc",
"lang/core/intrinsic/table.h",
+ "lang/core/intrinsic_data.cc",
+ "lang/core/intrinsic_data.h",
+ "lang/core/intrinsic_type_matchers.h",
"lang/wgsl/program/clone_context.cc",
"lang/wgsl/program/program.cc",
"lang/wgsl/program/program_builder.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 157a51e..b1e2402 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -516,14 +516,15 @@
lang/wgsl/sem/while_statement.h
lang/core/constant/eval.cc
lang/core/constant/eval.h
- lang/wgsl/resolver/dependency_graph.cc
- lang/wgsl/resolver/dependency_graph.h
- lang/core/intrinsic/core_table_data.cc
- lang/core/intrinsic/core_table_data.h
lang/core/intrinsic/ctor_conv.cc
lang/core/intrinsic/ctor_conv.h
lang/core/intrinsic/table.cc
lang/core/intrinsic/table.h
+ lang/core/intrinsic_data.cc
+ lang/core/intrinsic_data.h
+ lang/core/intrinsic_type_matchers.h
+ lang/wgsl/resolver/dependency_graph.cc
+ lang/wgsl/resolver/dependency_graph.h
lang/wgsl/resolver/resolve.cc
lang/wgsl/resolver/resolve.h
lang/wgsl/resolver/resolver.cc
diff --git a/src/tint/lang/core/intrinsic/core_type_matchers.h b/src/tint/lang/core/intrinsic/core_type_matchers.h
deleted file mode 100644
index b061443..0000000
--- a/src/tint/lang/core/intrinsic/core_type_matchers.h
+++ /dev/null
@@ -1,570 +0,0 @@
-// Copyright 2023 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.
-
-#ifndef SRC_TINT_LANG_CORE_INTRINSIC_CORE_TYPE_MATCHERS_H_
-#define SRC_TINT_LANG_CORE_INTRINSIC_CORE_TYPE_MATCHERS_H_
-
-#include "src/tint/lang/core/evaluation_stage.h"
-#include "src/tint/lang/core/intrinsic/table_data.h"
-#include "src/tint/lang/core/type/abstract_float.h"
-#include "src/tint/lang/core/type/abstract_int.h"
-#include "src/tint/lang/core/type/abstract_numeric.h"
-#include "src/tint/lang/core/type/array.h"
-#include "src/tint/lang/core/type/atomic.h"
-#include "src/tint/lang/core/type/bool.h"
-#include "src/tint/lang/core/type/builtin_structs.h"
-#include "src/tint/lang/core/type/depth_multisampled_texture.h"
-#include "src/tint/lang/core/type/depth_texture.h"
-#include "src/tint/lang/core/type/external_texture.h"
-#include "src/tint/lang/core/type/f16.h"
-#include "src/tint/lang/core/type/f32.h"
-#include "src/tint/lang/core/type/i32.h"
-#include "src/tint/lang/core/type/manager.h"
-#include "src/tint/lang/core/type/matrix.h"
-#include "src/tint/lang/core/type/multisampled_texture.h"
-#include "src/tint/lang/core/type/pointer.h"
-#include "src/tint/lang/core/type/sampled_texture.h"
-#include "src/tint/lang/core/type/storage_texture.h"
-#include "src/tint/lang/core/type/texture_dimension.h"
-#include "src/tint/lang/core/type/u32.h"
-#include "src/tint/lang/core/type/vector.h"
-
-namespace tint::core::intrinsic {
-
-inline bool match_bool(TableData::MatchState&, const type::Type* ty) {
- return ty->IsAnyOf<TableData::Any, type::Bool>();
-}
-
-inline const type::AbstractFloat* build_fa(TableData::MatchState& state) {
- return state.types.AFloat();
-}
-
-inline bool match_fa(TableData::MatchState& state, const type::Type* ty) {
- return (state.earliest_eval_stage <= EvaluationStage::kConstant) &&
- ty->IsAnyOf<TableData::Any, type::AbstractNumeric>();
-}
-
-inline const type::AbstractInt* build_ia(TableData::MatchState& state) {
- return state.types.AInt();
-}
-
-inline bool match_ia(TableData::MatchState& state, const type::Type* ty) {
- return (state.earliest_eval_stage <= EvaluationStage::kConstant) &&
- ty->IsAnyOf<TableData::Any, type::AbstractInt>();
-}
-
-inline const type::Bool* build_bool(TableData::MatchState& state) {
- return state.types.bool_();
-}
-
-inline const type::F16* build_f16(TableData::MatchState& state) {
- return state.types.f16();
-}
-
-inline bool match_f16(TableData::MatchState&, const type::Type* ty) {
- return ty->IsAnyOf<TableData::Any, type::F16, type::AbstractNumeric>();
-}
-
-inline const type::F32* build_f32(TableData::MatchState& state) {
- return state.types.f32();
-}
-
-inline bool match_f32(TableData::MatchState&, const type::Type* ty) {
- return ty->IsAnyOf<TableData::Any, type::F32, type::AbstractNumeric>();
-}
-
-inline const type::I32* build_i32(TableData::MatchState& state) {
- return state.types.i32();
-}
-
-inline bool match_i32(TableData::MatchState&, const type::Type* ty) {
- return ty->IsAnyOf<TableData::Any, type::I32, type::AbstractInt>();
-}
-
-inline const type::U32* build_u32(TableData::MatchState& state) {
- return state.types.u32();
-}
-
-inline bool match_u32(TableData::MatchState&, const type::Type* ty) {
- return ty->IsAnyOf<TableData::Any, type::U32, type::AbstractInt>();
-}
-
-inline bool match_vec(TableData::MatchState&,
- const type::Type* ty,
- TableData::Number& N,
- const type::Type*& T) {
- if (ty->Is<TableData::Any>()) {
- N = TableData::Number::any;
- T = ty;
- return true;
- }
-
- if (auto* v = ty->As<type::Vector>()) {
- N = v->Width();
- T = v->type();
- return true;
- }
- return false;
-}
-
-template <uint32_t N>
-inline bool match_vec(TableData::MatchState&, const type::Type* ty, const type::Type*& T) {
- if (ty->Is<TableData::Any>()) {
- T = ty;
- return true;
- }
-
- if (auto* v = ty->As<type::Vector>()) {
- if (v->Width() == N) {
- T = v->type();
- return true;
- }
- }
- return false;
-}
-
-inline const type::Vector* build_vec(TableData::MatchState& state,
- TableData::Number N,
- const type::Type* el) {
- return state.types.vec(el, N.Value());
-}
-
-template <uint32_t N>
-inline const type::Vector* build_vec(TableData::MatchState& state, const type::Type* el) {
- return state.types.vec(el, N);
-}
-
-constexpr auto match_vec2 = match_vec<2>;
-constexpr auto match_vec3 = match_vec<3>;
-constexpr auto match_vec4 = match_vec<4>;
-
-constexpr auto build_vec2 = build_vec<2>;
-constexpr auto build_vec3 = build_vec<3>;
-constexpr auto build_vec4 = build_vec<4>;
-
-inline bool match_packedVec3(TableData::MatchState&, const type::Type* ty, const type::Type*& T) {
- if (ty->Is<TableData::Any>()) {
- T = ty;
- return true;
- }
-
- if (auto* v = ty->As<type::Vector>()) {
- if (v->Packed()) {
- T = v->type();
- return true;
- }
- }
- return false;
-}
-
-inline const type::Vector* build_packedVec3(TableData::MatchState& state, const type::Type* el) {
- return state.types.Get<type::Vector>(el, 3u, /* packed */ true);
-}
-
-inline bool match_mat(TableData::MatchState&,
- const type::Type* ty,
- TableData::Number& M,
- TableData::Number& N,
- const type::Type*& T) {
- if (ty->Is<TableData::Any>()) {
- M = TableData::Number::any;
- N = TableData::Number::any;
- T = ty;
- return true;
- }
- if (auto* m = ty->As<type::Matrix>()) {
- M = m->columns();
- N = m->ColumnType()->Width();
- T = m->type();
- return true;
- }
- return false;
-}
-
-template <uint32_t C, uint32_t R>
-inline bool match_mat(TableData::MatchState&, const type::Type* ty, const type::Type*& T) {
- if (ty->Is<TableData::Any>()) {
- T = ty;
- return true;
- }
- if (auto* m = ty->As<type::Matrix>()) {
- if (m->columns() == C && m->rows() == R) {
- T = m->type();
- return true;
- }
- }
- return false;
-}
-
-inline const type::Matrix* build_mat(TableData::MatchState& state,
- TableData::Number C,
- TableData::Number R,
- const type::Type* T) {
- auto* column_type = state.types.vec(T, R.Value());
- return state.types.mat(column_type, C.Value());
-}
-
-template <uint32_t C, uint32_t R>
-inline const type::Matrix* build_mat(TableData::MatchState& state, const type::Type* T) {
- auto* column_type = state.types.vec(T, R);
- return state.types.mat(column_type, C);
-}
-
-constexpr auto build_mat2x2 = build_mat<2, 2>;
-constexpr auto build_mat2x3 = build_mat<2, 3>;
-constexpr auto build_mat2x4 = build_mat<2, 4>;
-constexpr auto build_mat3x2 = build_mat<3, 2>;
-constexpr auto build_mat3x3 = build_mat<3, 3>;
-constexpr auto build_mat3x4 = build_mat<3, 4>;
-constexpr auto build_mat4x2 = build_mat<4, 2>;
-constexpr auto build_mat4x3 = build_mat<4, 3>;
-constexpr auto build_mat4x4 = build_mat<4, 4>;
-
-constexpr auto match_mat2x2 = match_mat<2, 2>;
-constexpr auto match_mat2x3 = match_mat<2, 3>;
-constexpr auto match_mat2x4 = match_mat<2, 4>;
-constexpr auto match_mat3x2 = match_mat<3, 2>;
-constexpr auto match_mat3x3 = match_mat<3, 3>;
-constexpr auto match_mat3x4 = match_mat<3, 4>;
-constexpr auto match_mat4x2 = match_mat<4, 2>;
-constexpr auto match_mat4x3 = match_mat<4, 3>;
-constexpr auto match_mat4x4 = match_mat<4, 4>;
-
-inline bool match_array(TableData::MatchState&, const type::Type* ty, const type::Type*& T) {
- if (ty->Is<TableData::Any>()) {
- T = ty;
- return true;
- }
-
- if (auto* a = ty->As<type::Array>()) {
- if (a->Count()->Is<type::RuntimeArrayCount>()) {
- T = a->ElemType();
- return true;
- }
- }
- return false;
-}
-
-inline const type::Array* build_array(TableData::MatchState& state, const type::Type* el) {
- return state.types.Get<type::Array>(el,
- /* count */ state.types.Get<type::RuntimeArrayCount>(),
- /* align */ 0u,
- /* size */ 0u,
- /* stride */ 0u,
- /* stride_implicit */ 0u);
-}
-
-inline bool match_ptr(TableData::MatchState&,
- const type::Type* ty,
- TableData::Number& S,
- const type::Type*& T,
- TableData::Number& A) {
- if (ty->Is<TableData::Any>()) {
- S = TableData::Number::any;
- T = ty;
- A = TableData::Number::any;
- return true;
- }
-
- if (auto* p = ty->As<type::Pointer>()) {
- S = TableData::Number(static_cast<uint32_t>(p->AddressSpace()));
- T = p->StoreType();
- A = TableData::Number(static_cast<uint32_t>(p->Access()));
- return true;
- }
- return false;
-}
-
-inline const type::Pointer* build_ptr(TableData::MatchState& state,
- TableData::Number S,
- const type::Type* T,
- TableData::Number& A) {
- return state.types.ptr(static_cast<core::AddressSpace>(S.Value()), T,
- static_cast<core::Access>(A.Value()));
-}
-
-inline bool match_atomic(TableData::MatchState&, const type::Type* ty, const type::Type*& T) {
- if (ty->Is<TableData::Any>()) {
- T = ty;
- return true;
- }
-
- if (auto* a = ty->As<type::Atomic>()) {
- T = a->Type();
- return true;
- }
- return false;
-}
-
-inline const type::Atomic* build_atomic(TableData::MatchState& state, const type::Type* T) {
- return state.types.atomic(T);
-}
-
-inline bool match_sampler(TableData::MatchState&, const type::Type* ty) {
- if (ty->Is<TableData::Any>()) {
- return true;
- }
- return ty->Is([](const type::Sampler* s) { return s->kind() == type::SamplerKind::kSampler; });
-}
-
-inline const type::Sampler* build_sampler(TableData::MatchState& state) {
- return state.types.sampler();
-}
-
-inline bool match_sampler_comparison(TableData::MatchState&, const type::Type* ty) {
- if (ty->Is<TableData::Any>()) {
- return true;
- }
- return ty->Is(
- [](const type::Sampler* s) { return s->kind() == type::SamplerKind::kComparisonSampler; });
-}
-
-inline const type::Sampler* build_sampler_comparison(TableData::MatchState& state) {
- return state.types.comparison_sampler();
-}
-
-inline bool match_texture(TableData::MatchState&,
- const type::Type* ty,
- type::TextureDimension dim,
- const type::Type*& T) {
- if (ty->Is<TableData::Any>()) {
- T = ty;
- return true;
- }
- if (auto* v = ty->As<type::SampledTexture>()) {
- if (v->dim() == dim) {
- T = v->type();
- return true;
- }
- }
- return false;
-}
-
-#define JOIN(a, b) a##b
-
-#define DECLARE_SAMPLED_TEXTURE(suffix, dim) \
- inline bool JOIN(match_texture_, suffix)(TableData::MatchState & state, const type::Type* ty, \
- const type::Type*& T) { \
- return match_texture(state, ty, dim, T); \
- } \
- inline const type::SampledTexture* JOIN(build_texture_, suffix)(TableData::MatchState & state, \
- const type::Type* T) { \
- return state.types.Get<type::SampledTexture>(dim, T); \
- }
-
-DECLARE_SAMPLED_TEXTURE(1d, type::TextureDimension::k1d)
-DECLARE_SAMPLED_TEXTURE(2d, type::TextureDimension::k2d)
-DECLARE_SAMPLED_TEXTURE(2d_array, type::TextureDimension::k2dArray)
-DECLARE_SAMPLED_TEXTURE(3d, type::TextureDimension::k3d)
-DECLARE_SAMPLED_TEXTURE(cube, type::TextureDimension::kCube)
-DECLARE_SAMPLED_TEXTURE(cube_array, type::TextureDimension::kCubeArray)
-#undef DECLARE_SAMPLED_TEXTURE
-
-inline bool match_texture_multisampled(TableData::MatchState&,
- const type::Type* ty,
- type::TextureDimension dim,
- const type::Type*& T) {
- if (ty->Is<TableData::Any>()) {
- T = ty;
- return true;
- }
- if (auto* v = ty->As<type::MultisampledTexture>()) {
- if (v->dim() == dim) {
- T = v->type();
- return true;
- }
- }
- return false;
-}
-
-#define DECLARE_MULTISAMPLED_TEXTURE(suffix, dim) \
- inline bool JOIN(match_texture_multisampled_, suffix)( \
- TableData::MatchState & state, const type::Type* ty, const type::Type*& T) { \
- return match_texture_multisampled(state, ty, dim, T); \
- } \
- inline const type::MultisampledTexture* JOIN(build_texture_multisampled_, suffix)( \
- TableData::MatchState & state, const type::Type* T) { \
- return state.types.Get<type::MultisampledTexture>(dim, T); \
- }
-
-DECLARE_MULTISAMPLED_TEXTURE(2d, type::TextureDimension::k2d)
-#undef DECLARE_MULTISAMPLED_TEXTURE
-
-inline bool match_texture_depth(TableData::MatchState&,
- const type::Type* ty,
- type::TextureDimension dim) {
- if (ty->Is<TableData::Any>()) {
- return true;
- }
- return ty->Is([&](const type::DepthTexture* t) { return t->dim() == dim; });
-}
-
-#define DECLARE_DEPTH_TEXTURE(suffix, dim) \
- inline bool JOIN(match_texture_depth_, suffix)(TableData::MatchState & state, \
- const type::Type* ty) { \
- return match_texture_depth(state, ty, dim); \
- } \
- inline const type::DepthTexture* JOIN(build_texture_depth_, \
- suffix)(TableData::MatchState & state) { \
- return state.types.Get<type::DepthTexture>(dim); \
- }
-
-DECLARE_DEPTH_TEXTURE(2d, type::TextureDimension::k2d)
-DECLARE_DEPTH_TEXTURE(2d_array, type::TextureDimension::k2dArray)
-DECLARE_DEPTH_TEXTURE(cube, type::TextureDimension::kCube)
-DECLARE_DEPTH_TEXTURE(cube_array, type::TextureDimension::kCubeArray)
-#undef DECLARE_DEPTH_TEXTURE
-
-inline bool match_texture_depth_multisampled_2d(TableData::MatchState&, const type::Type* ty) {
- if (ty->Is<TableData::Any>()) {
- return true;
- }
- return ty->Is([&](const type::DepthMultisampledTexture* t) {
- return t->dim() == type::TextureDimension::k2d;
- });
-}
-
-inline type::DepthMultisampledTexture* build_texture_depth_multisampled_2d(
- TableData::MatchState& state) {
- return state.types.Get<type::DepthMultisampledTexture>(type::TextureDimension::k2d);
-}
-
-inline bool match_texture_storage(TableData::MatchState&,
- const type::Type* ty,
- type::TextureDimension dim,
- TableData::Number& F,
- TableData::Number& A) {
- if (ty->Is<TableData::Any>()) {
- F = TableData::Number::any;
- A = TableData::Number::any;
- return true;
- }
- if (auto* v = ty->As<type::StorageTexture>()) {
- if (v->dim() == dim) {
- F = TableData::Number(static_cast<uint32_t>(v->texel_format()));
- A = TableData::Number(static_cast<uint32_t>(v->access()));
- return true;
- }
- }
- return false;
-}
-
-#define DECLARE_STORAGE_TEXTURE(suffix, dim) \
- inline bool JOIN(match_texture_storage_, suffix)(TableData::MatchState & state, \
- const type::Type* ty, TableData::Number& F, \
- TableData::Number& A) { \
- return match_texture_storage(state, ty, dim, F, A); \
- } \
- inline const type::StorageTexture* JOIN(build_texture_storage_, suffix)( \
- TableData::MatchState & state, TableData::Number F, TableData::Number A) { \
- auto format = static_cast<TexelFormat>(F.Value()); \
- auto access = static_cast<Access>(A.Value()); \
- auto* T = type::StorageTexture::SubtypeFor(format, state.types); \
- return state.types.Get<type::StorageTexture>(dim, format, access, T); \
- }
-
-DECLARE_STORAGE_TEXTURE(1d, type::TextureDimension::k1d)
-DECLARE_STORAGE_TEXTURE(2d, type::TextureDimension::k2d)
-DECLARE_STORAGE_TEXTURE(2d_array, type::TextureDimension::k2dArray)
-DECLARE_STORAGE_TEXTURE(3d, type::TextureDimension::k3d)
-#undef DECLARE_STORAGE_TEXTURE
-
-inline bool match_texture_external(TableData::MatchState&, const type::Type* ty) {
- return ty->IsAnyOf<TableData::Any, type::ExternalTexture>();
-}
-
-inline const type::ExternalTexture* build_texture_external(TableData::MatchState& state) {
- return state.types.Get<type::ExternalTexture>();
-}
-
-// Builtin types starting with a _ prefix cannot be declared in WGSL, so they
-// can only be used as return types. Because of this, they must only match Any,
-// which is used as the return type matcher.
-inline bool match_modf_result(TableData::MatchState&, const type::Type* ty, const type::Type*& T) {
- if (!ty->Is<TableData::Any>()) {
- return false;
- }
- T = ty;
- return true;
-}
-inline bool match_modf_result_vec(TableData::MatchState&,
- const type::Type* ty,
- TableData::Number& N,
- const type::Type*& T) {
- if (!ty->Is<TableData::Any>()) {
- return false;
- }
- N = TableData::Number::any;
- T = ty;
- return true;
-}
-inline bool match_frexp_result(TableData::MatchState&, const type::Type* ty, const type::Type*& T) {
- if (!ty->Is<TableData::Any>()) {
- return false;
- }
- T = ty;
- return true;
-}
-inline bool match_frexp_result_vec(TableData::MatchState&,
- const type::Type* ty,
- TableData::Number& N,
- const type::Type*& T) {
- if (!ty->Is<TableData::Any>()) {
- return false;
- }
- N = TableData::Number::any;
- T = ty;
- return true;
-}
-
-inline bool match_atomic_compare_exchange_result(TableData::MatchState&,
- const type::Type* ty,
- const type::Type*& T) {
- if (ty->Is<TableData::Any>()) {
- T = ty;
- return true;
- }
- return false;
-}
-
-inline const type::Struct* build_modf_result(TableData::MatchState& state, const type::Type* el) {
- return type::CreateModfResult(state.types, state.symbols, el);
-}
-
-inline const type::Struct* build_modf_result_vec(TableData::MatchState& state,
- TableData::Number& n,
- const type::Type* el) {
- auto* vec = state.types.vec(el, n.Value());
- return type::CreateModfResult(state.types, state.symbols, vec);
-}
-
-inline const type::Struct* build_frexp_result(TableData::MatchState& state, const type::Type* el) {
- return type::CreateFrexpResult(state.types, state.symbols, el);
-}
-
-inline const type::Struct* build_frexp_result_vec(TableData::MatchState& state,
- TableData::Number& n,
- const type::Type* el) {
- auto* vec = state.types.vec(el, n.Value());
- return type::CreateFrexpResult(state.types, state.symbols, vec);
-}
-
-inline const type::Struct* build_atomic_compare_exchange_result(TableData::MatchState& state,
- const type::Type* ty) {
- return type::CreateAtomicCompareExchangeResult(state.types, state.symbols, ty);
-}
-
-} // namespace tint::core::intrinsic
-
-#endif // SRC_TINT_LANG_CORE_INTRINSIC_CORE_TYPE_MATCHERS_H_
diff --git a/src/tint/lang/core/intrinsic/table.cc b/src/tint/lang/core/intrinsic/table.cc
index b9dbcc8..2fa6bb9 100644
--- a/src/tint/lang/core/intrinsic/table.cc
+++ b/src/tint/lang/core/intrinsic/table.cc
@@ -19,14 +19,11 @@
#include <utility>
#include "src/tint/lang/core/evaluation_stage.h"
-#include "src/tint/lang/core/intrinsic/core_table_data.h"
#include "src/tint/lang/core/intrinsic/table_data.h"
-#include "src/tint/lang/wgsl/ast/binary_expression.h"
-#include "src/tint/lang/wgsl/program/program_builder.h"
-#include "src/tint/lang/wgsl/sem/pipeline_stage_set.h"
-#include "src/tint/lang/wgsl/sem/value_constructor.h"
-#include "src/tint/lang/wgsl/sem/value_conversion.h"
+#include "src/tint/lang/core/type/manager.h"
+#include "src/tint/lang/core/type/void.h"
#include "src/tint/utils/containers/hashmap.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
#include "src/tint/utils/macros/scoped_assignment.h"
#include "src/tint/utils/math/hash.h"
#include "src/tint/utils/math/math.h"
@@ -73,89 +70,38 @@
constexpr const auto kNoMatcher = TableData::kNoMatcher;
/// The Vector `N` template argument value for arrays of parameters.
-constexpr const size_t kNumFixedParams = 8;
+constexpr const size_t kNumFixedParams = decltype(Table::Overload{}.parameters)::static_length;
/// The Vector `N` template argument value for arrays of overload candidates.
constexpr const size_t kNumFixedCandidates = 8;
-////////////////////////////////////////////////////////////////////////////////
-// Binding functions for use in the generated builtin_table.inl
-// TODO(bclayton): See if we can move more of this hand-rolled code to the
-// template
-////////////////////////////////////////////////////////////////////////////////
-using PipelineStage = ast::PipelineStage;
-
-/// IntrinsicPrototype describes a fully matched intrinsic.
-struct IntrinsicPrototype {
- /// Parameter describes a single parameter
- struct Parameter {
- /// Parameter type
- const type::Type* const type;
- /// Parameter usage
- ParameterUsage const usage = ParameterUsage::kNone;
- };
-
- /// Hasher provides a hash function for the IntrinsicPrototype
- struct Hasher {
- /// @param i the IntrinsicPrototype to create a hash for
- /// @return the hash value
- inline std::size_t operator()(const IntrinsicPrototype& i) const {
- size_t hash = Hash(i.parameters.Length());
- for (auto& p : i.parameters) {
- hash = HashCombine(hash, p.type, p.usage);
- }
- return Hash(hash, i.overload, i.return_type);
- }
- };
-
- const TableData::OverloadInfo* overload = nullptr;
- type::Type const* return_type = nullptr;
- Vector<Parameter, kNumFixedParams> parameters;
-};
-
-/// Equality operator for IntrinsicPrototype
-bool operator==(const IntrinsicPrototype& a, const IntrinsicPrototype& b) {
- if (a.overload != b.overload || a.return_type != b.return_type ||
- a.parameters.Length() != b.parameters.Length()) {
- return false;
- }
- for (size_t i = 0; i < a.parameters.Length(); i++) {
- auto& pa = a.parameters[i];
- auto& pb = b.parameters[i];
- if (pa.type != pb.type || pa.usage != pb.usage) {
- return false;
- }
- }
- return true;
-}
-
/// Impl is the private implementation of the Table interface.
class Impl : public Table {
public:
- Impl(ProgramBuilder& b, const TableData& d);
+ Impl(const TableData& td, type::Manager& tys, SymbolTable& syms, diag::List& d);
- Builtin Lookup(core::Function builtin_type,
- VectorRef<const type::Type*> args,
- EvaluationStage earliest_eval_stage,
- const Source& source) override;
+ Result<Overload> Lookup(core::Function builtin_type,
+ VectorRef<const type::Type*> args,
+ EvaluationStage earliest_eval_stage,
+ const Source& source) override;
- UnaryOperator Lookup(core::UnaryOp op,
- const type::Type* arg,
- EvaluationStage earliest_eval_stage,
- const Source& source) override;
+ Result<Overload> Lookup(core::UnaryOp op,
+ const type::Type* arg,
+ EvaluationStage earliest_eval_stage,
+ const Source& source) override;
- BinaryOperator Lookup(core::BinaryOp op,
- const type::Type* lhs,
- const type::Type* rhs,
- EvaluationStage earliest_eval_stage,
- const Source& source,
- bool is_compound) override;
+ Result<Overload> Lookup(core::BinaryOp op,
+ const type::Type* lhs,
+ const type::Type* rhs,
+ EvaluationStage earliest_eval_stage,
+ const Source& source,
+ bool is_compound) override;
- CtorOrConv Lookup(CtorConv type,
- const type::Type* template_arg,
- VectorRef<const type::Type*> args,
- EvaluationStage earliest_eval_stage,
- const Source& source) override;
+ Result<Overload> Lookup(CtorConv type,
+ const type::Type* template_arg,
+ VectorRef<const type::Type*> args,
+ EvaluationStage earliest_eval_stage,
+ const Source& source) override;
private:
/// Candidate holds information about an overload evaluated for resolution.
@@ -165,7 +111,7 @@
/// The template types and numbers
TemplateState templates;
/// The parameter types for the candidate overload
- Vector<IntrinsicPrototype::Parameter, kNumFixedParams> parameters;
+ Vector<Table::Overload::Parameter, kNumFixedParams> parameters;
/// The match-score of the candidate overload.
/// A score of zero indicates an exact match.
/// Non-zero scores are used for diagnostics when no overload matches.
@@ -194,15 +140,13 @@
/// defined as `f32`.
/// @param on_no_match an error callback when no intrinsic overloads matched the provided
/// arguments.
- /// @returns the matched intrinsic. If no intrinsic could be matched then IntrinsicPrototype
- /// will hold nullptrs for IntrinsicPrototype::overload and
- /// IntrinsicPrototype::return_type.
- IntrinsicPrototype MatchIntrinsic(const IntrinsicInfo& intrinsic,
- const char* intrinsic_name,
- VectorRef<const type::Type*> args,
- EvaluationStage earliest_eval_stage,
- TemplateState templates,
- const OnNoMatch& on_no_match) const;
+ /// @returns the matched intrinsic
+ Result<Table::Overload> MatchIntrinsic(const IntrinsicInfo& intrinsic,
+ const char* intrinsic_name,
+ VectorRef<const type::Type*> args,
+ EvaluationStage earliest_eval_stage,
+ TemplateState templates,
+ const OnNoMatch& on_no_match) const;
/// Evaluates the single overload for the provided argument types.
/// @param overload the overload being considered
@@ -256,12 +200,10 @@
TemplateState templates,
VectorRef<Candidate> candidates) const;
- ProgramBuilder& builder;
const TableData& data;
- Hashmap<IntrinsicPrototype, sem::Builtin*, 64, IntrinsicPrototype::Hasher> builtins;
- Hashmap<IntrinsicPrototype, sem::ValueConstructor*, 16, IntrinsicPrototype::Hasher>
- constructors;
- Hashmap<IntrinsicPrototype, sem::ValueConversion*, 16, IntrinsicPrototype::Hasher> converters;
+ type::Manager& types;
+ SymbolTable& symbols;
+ diag::List& diags;
};
/// @return a string representing a call to a builtin with the given argument
@@ -290,12 +232,13 @@
return ss.str();
}
-Impl::Impl(ProgramBuilder& b, const TableData& d) : builder(b), data(d) {}
+Impl::Impl(const TableData& td, type::Manager& tys, SymbolTable& syms, diag::List& d)
+ : data(td), types(tys), symbols(syms), diags(d) {}
-Impl::Builtin Impl::Lookup(core::Function builtin_type,
- VectorRef<const type::Type*> args,
- EvaluationStage earliest_eval_stage,
- const Source& source) {
+Result<Table::Overload> Impl::Lookup(core::Function builtin_type,
+ VectorRef<const type::Type*> args,
+ EvaluationStage earliest_eval_stage,
+ const Source& source) {
const char* intrinsic_name = core::str(builtin_type);
// Generates an error when no overloads match the provided arguments
@@ -308,66 +251,36 @@
<< (candidates.Length() > 1 ? "s:" : ":") << std::endl;
PrintCandidates(ss, candidates, intrinsic_name);
}
- builder.Diagnostics().add_error(diag::System::Resolver, ss.str(), source);
+ diags.add_error(diag::System::Intrinsics, ss.str(), source);
};
// Resolve the intrinsic overload
- auto match = MatchIntrinsic(data.builtins[static_cast<size_t>(builtin_type)], intrinsic_name,
- args, earliest_eval_stage, TemplateState{}, on_no_match);
- if (!match.overload) {
- return {};
- }
-
- // De-duplicate builtins that are identical.
- auto* sem = builtins.GetOrCreate(match, [&] {
- Vector<sem::Parameter*, kNumFixedParams> params;
- params.Reserve(match.parameters.Length());
- for (auto& p : match.parameters) {
- params.Push(builder.create<sem::Parameter>(
- nullptr, static_cast<uint32_t>(params.Length()), p.type,
- core::AddressSpace::kUndefined, core::Access::kUndefined, p.usage));
- }
- sem::PipelineStageSet supported_stages;
- auto& overload = *match.overload;
- if (overload.flags.Contains(OverloadFlag::kSupportsVertexPipeline)) {
- supported_stages.Add(ast::PipelineStage::kVertex);
- }
- if (overload.flags.Contains(OverloadFlag::kSupportsFragmentPipeline)) {
- supported_stages.Add(ast::PipelineStage::kFragment);
- }
- if (overload.flags.Contains(OverloadFlag::kSupportsComputePipeline)) {
- supported_stages.Add(ast::PipelineStage::kCompute);
- }
- auto eval_stage =
- overload.const_eval_fn ? EvaluationStage::kConstant : EvaluationStage::kRuntime;
- return builder.create<sem::Builtin>(builtin_type, match.return_type, std::move(params),
- eval_stage, supported_stages,
- overload.flags.Contains(OverloadFlag::kIsDeprecated),
- overload.flags.Contains(OverloadFlag::kMustUse));
- });
- return Builtin{sem, match.overload->const_eval_fn};
+ return MatchIntrinsic(data.builtins[static_cast<size_t>(builtin_type)], intrinsic_name, args,
+ earliest_eval_stage, TemplateState{}, on_no_match);
}
-Table::UnaryOperator Impl::Lookup(core::UnaryOp op,
- const type::Type* arg,
- EvaluationStage earliest_eval_stage,
- const Source& source) {
- auto [intrinsic_info, intrinsic_name] = [&]() -> std::pair<const IntrinsicInfo*, const char*> {
- switch (op) {
- case core::UnaryOp::kComplement:
- return {&data.unary_complement, "operator ~ "};
- case core::UnaryOp::kNegation:
- return {&data.unary_minus, "operator - "};
- case core::UnaryOp::kNot:
- return {&data.unary_not, "operator ! "};
- default:
- break;
- }
- TINT_UNREACHABLE() << "invalid unary op: " << op;
- return {};
- }();
- if (!intrinsic_info) {
- return {};
+Result<Table::Overload> Impl::Lookup(core::UnaryOp op,
+ const type::Type* arg,
+ EvaluationStage earliest_eval_stage,
+ const Source& source) {
+ const IntrinsicInfo* intrinsic_info = nullptr;
+ const char* intrinsic_name = nullptr;
+ switch (op) {
+ case core::UnaryOp::kComplement:
+ intrinsic_info = &data.unary_complement;
+ intrinsic_name = "operator ~ ";
+ break;
+ case core::UnaryOp::kNegation:
+ intrinsic_info = &data.unary_minus;
+ intrinsic_name = "operator - ";
+ break;
+ case core::UnaryOp::kNot:
+ intrinsic_info = &data.unary_not;
+ intrinsic_name = "operator ! ";
+ break;
+ default:
+ TINT_UNREACHABLE() << "invalid unary op: " << op;
+ return Failure;
}
Vector args{arg};
@@ -382,73 +295,95 @@
<< (candidates.Length() > 1 ? "s:" : ":") << std::endl;
PrintCandidates(ss, candidates, name);
}
- builder.Diagnostics().add_error(diag::System::Resolver, ss.str(), source);
+ diags.add_error(diag::System::Intrinsics, ss.str(), source);
};
// Resolve the intrinsic overload
- auto match = MatchIntrinsic(*intrinsic_info, intrinsic_name, args, earliest_eval_stage,
- TemplateState{}, on_no_match);
- if (!match.overload) {
- return {};
- }
-
- return UnaryOperator{
- match.return_type,
- match.parameters[0].type,
- match.overload->const_eval_fn,
- };
+ return MatchIntrinsic(*intrinsic_info, intrinsic_name, args, earliest_eval_stage,
+ TemplateState{}, on_no_match);
}
-Table::BinaryOperator Impl::Lookup(core::BinaryOp op,
- const type::Type* lhs,
- const type::Type* rhs,
- EvaluationStage earliest_eval_stage,
- const Source& source,
- bool is_compound) {
- auto [intrinsic_info, intrinsic_name] = [&]() -> std::pair<const IntrinsicInfo*, const char*> {
- switch (op) {
- case core::BinaryOp::kAnd:
- return {&data.binary_and, is_compound ? "operator &= " : "operator & "};
- case core::BinaryOp::kOr:
- return {&data.binary_or, is_compound ? "operator |= " : "operator | "};
- case core::BinaryOp::kXor:
- return {&data.binary_xor, is_compound ? "operator ^= " : "operator ^ "};
- case core::BinaryOp::kLogicalAnd:
- return {&data.binary_logical_and, "operator && "};
- case core::BinaryOp::kLogicalOr:
- return {&data.binary_logical_or, "operator || "};
- case core::BinaryOp::kEqual:
- return {&data.binary_equal, "operator == "};
- case core::BinaryOp::kNotEqual:
- return {&data.binary_not_equal, "operator != "};
- case core::BinaryOp::kLessThan:
- return {&data.binary_less_than, "operator < "};
- case core::BinaryOp::kGreaterThan:
- return {&data.binary_greater_than, "operator > "};
- case core::BinaryOp::kLessThanEqual:
- return {&data.binary_less_than_equal, "operator <= "};
- case core::BinaryOp::kGreaterThanEqual:
- return {&data.binary_greater_than_equal, "operator >= "};
- case core::BinaryOp::kShiftLeft:
- return {&data.binary_shift_left, is_compound ? "operator <<= " : "operator << "};
- case core::BinaryOp::kShiftRight:
- return {&data.binary_shift_right, is_compound ? "operator >>= " : "operator >> "};
- case core::BinaryOp::kAdd:
- return {&data.binary_plus, is_compound ? "operator += " : "operator + "};
- case core::BinaryOp::kSubtract:
- return {&data.binary_minus, is_compound ? "operator -= " : "operator - "};
- case core::BinaryOp::kMultiply:
- return {&data.binary_star, is_compound ? "operator *= " : "operator * "};
- case core::BinaryOp::kDivide:
- return {&data.binary_divide, is_compound ? "operator /= " : "operator / "};
- case core::BinaryOp::kModulo:
- return {&data.binary_modulo, is_compound ? "operator %= " : "operator % "};
- }
- TINT_UNREACHABLE() << "unhandled BinaryOp: " << op;
- return {};
- }();
- if (!intrinsic_info) {
- return {};
+Result<Table::Overload> Impl::Lookup(core::BinaryOp op,
+ const type::Type* lhs,
+ const type::Type* rhs,
+ EvaluationStage earliest_eval_stage,
+ const Source& source,
+ bool is_compound) {
+ const IntrinsicInfo* intrinsic_info = nullptr;
+ const char* intrinsic_name = nullptr;
+ switch (op) {
+ case core::BinaryOp::kAnd:
+ intrinsic_info = &data.binary_and;
+ intrinsic_name = is_compound ? "operator &= " : "operator & ";
+ break;
+ case core::BinaryOp::kOr:
+ intrinsic_info = &data.binary_or;
+ intrinsic_name = is_compound ? "operator |= " : "operator | ";
+ break;
+ case core::BinaryOp::kXor:
+ intrinsic_info = &data.binary_xor;
+ intrinsic_name = is_compound ? "operator ^= " : "operator ^ ";
+ break;
+ case core::BinaryOp::kLogicalAnd:
+ intrinsic_info = &data.binary_logical_and;
+ intrinsic_name = "operator && ";
+ break;
+ case core::BinaryOp::kLogicalOr:
+ intrinsic_info = &data.binary_logical_or;
+ intrinsic_name = "operator || ";
+ break;
+ case core::BinaryOp::kEqual:
+ intrinsic_info = &data.binary_equal;
+ intrinsic_name = "operator == ";
+ break;
+ case core::BinaryOp::kNotEqual:
+ intrinsic_info = &data.binary_not_equal;
+ intrinsic_name = "operator != ";
+ break;
+ case core::BinaryOp::kLessThan:
+ intrinsic_info = &data.binary_less_than;
+ intrinsic_name = "operator < ";
+ break;
+ case core::BinaryOp::kGreaterThan:
+ intrinsic_info = &data.binary_greater_than;
+ intrinsic_name = "operator > ";
+ break;
+ case core::BinaryOp::kLessThanEqual:
+ intrinsic_info = &data.binary_less_than_equal;
+ intrinsic_name = "operator <= ";
+ break;
+ case core::BinaryOp::kGreaterThanEqual:
+ intrinsic_info = &data.binary_greater_than_equal;
+ intrinsic_name = "operator >= ";
+ break;
+ case core::BinaryOp::kShiftLeft:
+ intrinsic_info = &data.binary_shift_left;
+ intrinsic_name = is_compound ? "operator <<= " : "operator << ";
+ break;
+ case core::BinaryOp::kShiftRight:
+ intrinsic_info = &data.binary_shift_right;
+ intrinsic_name = is_compound ? "operator >>= " : "operator >> ";
+ break;
+ case core::BinaryOp::kAdd:
+ intrinsic_info = &data.binary_plus;
+ intrinsic_name = is_compound ? "operator += " : "operator + ";
+ break;
+ case core::BinaryOp::kSubtract:
+ intrinsic_info = &data.binary_minus;
+ intrinsic_name = is_compound ? "operator -= " : "operator - ";
+ break;
+ case core::BinaryOp::kMultiply:
+ intrinsic_info = &data.binary_star;
+ intrinsic_name = is_compound ? "operator *= " : "operator * ";
+ break;
+ case core::BinaryOp::kDivide:
+ intrinsic_info = &data.binary_divide;
+ intrinsic_name = is_compound ? "operator /= " : "operator / ";
+ break;
+ case core::BinaryOp::kModulo:
+ intrinsic_info = &data.binary_modulo;
+ intrinsic_name = is_compound ? "operator %= " : "operator % ";
+ break;
}
Vector args{lhs, rhs};
@@ -463,29 +398,19 @@
<< (candidates.Length() > 1 ? "s:" : ":") << std::endl;
PrintCandidates(ss, candidates, name);
}
- builder.Diagnostics().add_error(diag::System::Resolver, ss.str(), source);
+ diags.add_error(diag::System::Intrinsics, ss.str(), source);
};
// Resolve the intrinsic overload
- auto match = MatchIntrinsic(*intrinsic_info, intrinsic_name, args, earliest_eval_stage,
- TemplateState{}, on_no_match);
- if (!match.overload) {
- return {};
- }
-
- return BinaryOperator{
- match.return_type,
- match.parameters[0].type,
- match.parameters[1].type,
- match.overload->const_eval_fn,
- };
+ return MatchIntrinsic(*intrinsic_info, intrinsic_name, args, earliest_eval_stage,
+ TemplateState{}, on_no_match);
}
-Table::CtorOrConv Impl::Lookup(CtorConv type,
- const type::Type* template_arg,
- VectorRef<const type::Type*> args,
- EvaluationStage earliest_eval_stage,
- const Source& source) {
+Result<Table::Overload> Impl::Lookup(CtorConv type,
+ const type::Type* template_arg,
+ VectorRef<const type::Type*> args,
+ EvaluationStage earliest_eval_stage,
+ const Source& source) {
auto name = str(type);
// Generates an error when no overloads match the provided arguments
@@ -513,7 +438,7 @@
<< std::endl;
PrintCandidates(ss, conv, name);
}
- builder.Diagnostics().add_error(diag::System::Resolver, ss.str(), source);
+ diags.add_error(diag::System::Intrinsics, ss.str(), source);
};
// If a template type was provided, then close the 0'th type with this.
@@ -523,48 +448,16 @@
}
// Resolve the intrinsic overload
- auto match = MatchIntrinsic(data.ctor_conv[static_cast<size_t>(type)], name, args,
- earliest_eval_stage, templates, on_no_match);
- if (!match.overload) {
- return {};
- }
-
- // Was this overload a constructor or conversion?
- if (match.overload->flags.Contains(OverloadFlag::kIsConstructor)) {
- Vector<sem::Parameter*, 8> params;
- params.Reserve(match.parameters.Length());
- for (auto& p : match.parameters) {
- params.Push(builder.create<sem::Parameter>(
- nullptr, static_cast<uint32_t>(params.Length()), p.type,
- core::AddressSpace::kUndefined, core::Access::kUndefined, p.usage));
- }
- auto eval_stage =
- match.overload->const_eval_fn ? EvaluationStage::kConstant : EvaluationStage::kRuntime;
- auto* target = constructors.GetOrCreate(match, [&] {
- return builder.create<sem::ValueConstructor>(match.return_type, std::move(params),
- eval_stage);
- });
- return CtorOrConv{target, match.overload->const_eval_fn};
- }
-
- // Conversion.
- auto* target = converters.GetOrCreate(match, [&] {
- auto param = builder.create<sem::Parameter>(
- nullptr, 0u, match.parameters[0].type, core::AddressSpace::kUndefined,
- core::Access::kUndefined, match.parameters[0].usage);
- auto eval_stage =
- match.overload->const_eval_fn ? EvaluationStage::kConstant : EvaluationStage::kRuntime;
- return builder.create<sem::ValueConversion>(match.return_type, param, eval_stage);
- });
- return CtorOrConv{target, match.overload->const_eval_fn};
+ return MatchIntrinsic(data.ctor_conv[static_cast<size_t>(type)], name, args,
+ earliest_eval_stage, templates, on_no_match);
}
-IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
- const char* intrinsic_name,
- VectorRef<const type::Type*> args,
- EvaluationStage earliest_eval_stage,
- TemplateState templates,
- const OnNoMatch& on_no_match) const {
+Result<Table::Overload> Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
+ const char* intrinsic_name,
+ VectorRef<const type::Type*> args,
+ EvaluationStage earliest_eval_stage,
+ TemplateState templates,
+ const OnNoMatch& on_no_match) const {
size_t num_matched = 0;
size_t match_idx = 0;
Vector<Candidate, kNumFixedCandidates> candidates;
@@ -585,7 +478,7 @@
// Sort the candidates with the most promising first
SortCandidates(candidates);
on_no_match(std::move(candidates));
- return {};
+ return Failure;
}
Candidate match;
@@ -596,7 +489,7 @@
match = ResolveCandidate(std::move(candidates), intrinsic_name, args, std::move(templates));
if (!match.overload) {
// Ambiguous overload. ResolveCandidate() will have already raised an error diagnostic.
- return {};
+ return Failure;
}
}
@@ -608,13 +501,13 @@
Match(match.templates, match.overload, indices, earliest_eval_stage).Type(&any);
if (TINT_UNLIKELY(!return_type)) {
TINT_ICE() << "MatchState.Match() returned null";
- return {};
+ return Failure;
}
} else {
- return_type = builder.create<type::Void>();
+ return_type = types.void_();
}
- return IntrinsicPrototype{match.overload, return_type, std::move(match.parameters)};
+ return Table::Overload{match.overload, return_type, std::move(match.parameters)};
}
Impl::Candidate Impl::ScoreOverload(const TableData::OverloadInfo* overload,
@@ -715,7 +608,7 @@
}
// Now that all the template types have been finalized, we can construct the parameters.
- Vector<IntrinsicPrototype::Parameter, kNumFixedParams> parameters;
+ Vector<Table::Overload::Parameter, kNumFixedParams> parameters;
if (score == 0) {
parameters.Reserve(num_params);
for (size_t p = 0; p < num_params; p++) {
@@ -799,8 +692,8 @@
const TableData::OverloadInfo* overload,
MatcherIndex const* matcher_indices,
EvaluationStage earliest_eval_stage) const {
- return MatchState{builder.Types(), builder.Symbols(), templates, data,
- overload, matcher_indices, earliest_eval_stage};
+ return MatchState{types, symbols, templates, data,
+ overload, matcher_indices, earliest_eval_stage};
}
void Impl::PrintOverload(StringStream& ss,
@@ -923,8 +816,11 @@
} // namespace
-std::unique_ptr<Table> Table::Create(ProgramBuilder& builder) {
- return std::make_unique<Impl>(builder, CoreTableData());
+std::unique_ptr<Table> Table::Create(const TableData& data,
+ type::Manager& types,
+ SymbolTable& symbols,
+ diag::List& diags) {
+ return std::make_unique<Impl>(data, types, symbols, diags);
}
Table::~Table() = default;
diff --git a/src/tint/lang/core/intrinsic/table.h b/src/tint/lang/core/intrinsic/table.h
index f5a5d1e..cd5cbe8 100644
--- a/src/tint/lang/core/intrinsic/table.h
+++ b/src/tint/lang/core/intrinsic/table.h
@@ -19,65 +19,82 @@
#include <string>
#include "src/tint/lang/core/binary_op.h"
-#include "src/tint/lang/core/constant/eval.h"
+#include "src/tint/lang/core/function.h"
#include "src/tint/lang/core/intrinsic/ctor_conv.h"
+#include "src/tint/lang/core/intrinsic/table_data.h"
+#include "src/tint/lang/core/parameter_usage.h"
#include "src/tint/lang/core/unary_op.h"
-#include "src/tint/lang/wgsl/sem/builtin.h"
#include "src/tint/utils/containers/vector.h"
// Forward declarations
-namespace tint {
-class ProgramBuilder;
-} // namespace tint
+namespace tint::diag {
+class List;
+} // namespace tint::diag
+namespace tint::type {
+class Manager;
+} // namespace tint::type
namespace tint::core::intrinsic {
/// Table is a lookup table of all the WGSL builtin functions and intrinsic operators
class Table {
public:
- /// @param builder the program builder
+ /// @param data the intrinsic table data
+ /// @param types the type manager
+ /// @param symbols the symbol table
+ /// @param diags the diagnostic list to append errors to
/// @return a pointer to a newly created Table
- static std::unique_ptr<Table> Create(ProgramBuilder& builder);
+ static std::unique_ptr<Table> Create(const TableData& data,
+ type::Manager& types,
+ SymbolTable& symbols,
+ diag::List& diags);
/// Destructor
virtual ~Table();
- /// Builtin describes a resolved builtin function
- struct Builtin {
- /// The semantic info for the builtin
- const sem::Builtin* sem = nullptr;
- /// The constant evaluation function
- constant::Eval::Function const_eval_fn = nullptr;
- };
+ /// Overload describes a fully matched builtin function overload
+ struct Overload {
+ /// Parameter describes a single parameter
+ struct Parameter {
+ /// Parameter type
+ const type::Type* const type;
+ /// Parameter usage
+ core::ParameterUsage const usage = core::ParameterUsage::kNone;
- /// UnaryOperator describes a resolved unary operator
- struct UnaryOperator {
- /// The result type of the unary operator
- const type::Type* result = nullptr;
- /// The type of the parameter of the unary operator
- const type::Type* parameter = nullptr;
- /// The constant evaluation function
- constant::Eval::Function const_eval_fn = nullptr;
- };
+ /// Equality operator
+ /// @param other the parameter to compare against
+ /// @returns true if this parameter and @p other are the same
+ bool operator==(const Parameter& other) const {
+ return type == other.type && usage == other.usage;
+ }
- /// BinaryOperator describes a resolved binary operator
- struct BinaryOperator {
- /// The result type of the binary operator
- const type::Type* result = nullptr;
- /// The type of LHS parameter of the binary operator
- const type::Type* lhs = nullptr;
- /// The type of RHS parameter of the binary operator
- const type::Type* rhs = nullptr;
- /// The constant evaluation function
- constant::Eval::Function const_eval_fn = nullptr;
- };
+ /// Inequality operator
+ /// @param other the parameter to compare against
+ /// @returns false if this parameter and @p other are the same
+ bool operator!=(const Parameter& other) const { return !(*this == other); }
+ };
- /// CtorOrConv describes a resolved value constructor or conversion
- struct CtorOrConv {
- /// The result type of the value constructor or conversion
- const sem::CallTarget* target = nullptr;
- /// The constant evaluation function
- constant::Eval::Function const_eval_fn = nullptr;
+ /// The overload information
+ const TableData::OverloadInfo* info = nullptr;
+
+ /// The resolved overload return type
+ type::Type const* return_type = nullptr;
+
+ /// The resolved overload parameters
+ Vector<Parameter, 8> parameters;
+
+ /// Equality operator
+ /// @param other the overload to compare against
+ /// @returns true if this overload and @p other are the same
+ bool operator==(const Overload& other) const {
+ return info == other.info && return_type == other.return_type &&
+ parameters == other.parameters;
+ }
+
+ /// Inequality operator
+ /// @param other the overload to compare against
+ /// @returns false if this overload and @p other are the same
+ bool operator!=(const Overload& other) const { return !(*this == other); }
};
/// Lookup looks for the builtin overload with the given signature, raising an error diagnostic
@@ -91,11 +108,11 @@
/// abstract-numerics will have been materialized after shader creation time
/// (EvaluationStage::kConstant).
/// @param source the source of the builtin call
- /// @return the semantic builtin if found, otherwise nullptr
- virtual Builtin Lookup(core::Function type,
- VectorRef<const type::Type*> args,
- EvaluationStage earliest_eval_stage,
- const Source& source) = 0;
+ /// @return the resolved builtin function overload
+ virtual Result<Overload> Lookup(core::Function type,
+ VectorRef<const type::Type*> args,
+ EvaluationStage earliest_eval_stage,
+ const Source& source) = 0;
/// Lookup looks for the unary op overload with the given signature, raising an error
/// diagnostic if the operator was not found.
@@ -108,12 +125,11 @@
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (EvaluationStage::kConstant).
/// @param source the source of the operator call
- /// @return the operator call target signature. If the operator was not found
- /// UnaryOperator::result will be nullptr.
- virtual UnaryOperator Lookup(core::UnaryOp op,
- const type::Type* arg,
- EvaluationStage earliest_eval_stage,
- const Source& source) = 0;
+ /// @return the resolved unary operator overload
+ virtual Result<Overload> Lookup(core::UnaryOp op,
+ const type::Type* arg,
+ EvaluationStage earliest_eval_stage,
+ const Source& source) = 0;
/// Lookup looks for the binary op overload with the given signature, raising an error
/// diagnostic if the operator was not found.
@@ -128,14 +144,13 @@
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (EvaluationStage::kConstant).
/// @param is_compound true if the binary operator is being used as a compound assignment
- /// @return the operator call target signature. If the operator was not found
- /// BinaryOperator::result will be nullptr.
- virtual BinaryOperator Lookup(core::BinaryOp op,
- const type::Type* lhs,
- const type::Type* rhs,
- EvaluationStage earliest_eval_stage,
- const Source& source,
- bool is_compound) = 0;
+ /// @return the resolved binary operator overload
+ virtual Result<Overload> Lookup(core::BinaryOp op,
+ const type::Type* lhs,
+ const type::Type* rhs,
+ EvaluationStage earliest_eval_stage,
+ const Source& source,
+ bool is_compound) = 0;
/// Lookup looks for the value constructor or conversion overload for the given CtorConv.
/// @param type the type being constructed or converted
@@ -148,14 +163,32 @@
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (EvaluationStage::kConstant).
/// @param source the source of the call
- /// @return a sem::ValueConstructor, sem::ValueConversion or nullptr if nothing matched
- virtual CtorOrConv Lookup(CtorConv type,
- const type::Type* template_arg,
- VectorRef<const type::Type*> args,
- EvaluationStage earliest_eval_stage,
- const Source& source) = 0;
+ /// @return the resolved type constructor or conversion function overload
+ virtual Result<Overload> Lookup(CtorConv type,
+ const type::Type* template_arg,
+ VectorRef<const type::Type*> args,
+ EvaluationStage earliest_eval_stage,
+ const Source& source) = 0;
};
} // namespace tint::core::intrinsic
+namespace tint {
+
+/// Hasher specialization for core::intrinsic::Table::Overload
+template <>
+struct Hasher<core::intrinsic::Table::Overload> {
+ /// @param i the core::intrinsic::Table::Overload to create a hash for
+ /// @return the hash value
+ inline std::size_t operator()(const core::intrinsic::Table::Overload& i) const {
+ size_t hash = Hash(i.parameters.Length());
+ for (auto& p : i.parameters) {
+ hash = HashCombine(hash, p.type, p.usage);
+ }
+ return Hash(hash, i.info, i.return_type);
+ }
+};
+
+} // namespace tint
+
#endif // SRC_TINT_LANG_CORE_INTRINSIC_TABLE_H_
diff --git a/src/tint/lang/core/intrinsic/table_test.cc b/src/tint/lang/core/intrinsic/table_test.cc
index 3bf47da..05d084b 100644
--- a/src/tint/lang/core/intrinsic/table_test.cc
+++ b/src/tint/lang/core/intrinsic/table_test.cc
@@ -17,6 +17,8 @@
#include <utility>
#include "gmock/gmock.h"
+#include "src/tint/lang/core/intrinsic/table_data.h"
+#include "src/tint/lang/core/intrinsic_data.h"
#include "src/tint/lang/core/type/atomic.h"
#include "src/tint/lang/core/type/depth_multisampled_texture.h"
#include "src/tint/lang/core/type/depth_texture.h"
@@ -27,7 +29,6 @@
#include "src/tint/lang/core/type/sampled_texture.h"
#include "src/tint/lang/core/type/storage_texture.h"
#include "src/tint/lang/core/type/texture_dimension.h"
-#include "src/tint/lang/wgsl/program/program_builder.h"
#include "src/tint/lang/wgsl/resolver/resolver_helper_test.h"
#include "src/tint/lang/wgsl/sem/value_constructor.h"
#include "src/tint/lang/wgsl/sem/value_conversion.h"
@@ -49,26 +50,26 @@
class IntrinsicTableTest : public testing::Test, public ProgramBuilder {
public:
- std::unique_ptr<Table> table = Table::Create(*this);
+ std::unique_ptr<Table> table =
+ Table::Create(core::kIntrinsicData, Types(), Symbols(), Diagnostics());
};
TEST_F(IntrinsicTableTest, MatchF32) {
auto* f32 = create<type::F32>();
auto result =
table->Lookup(core::Function::kCos, Vector{f32}, EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kCos);
- EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 1u);
- EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32);
+ EXPECT_EQ(result->return_type, f32);
+ ASSERT_EQ(result->parameters.Length(), 1u);
+ EXPECT_EQ(result->parameters[0].type, f32);
}
TEST_F(IntrinsicTableTest, MismatchF32) {
auto* i32 = create<type::I32>();
auto result =
table->Lookup(core::Function::kCos, Vector{i32}, EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -78,19 +79,18 @@
auto* vec2_f32 = create<type::Vector>(f32, 2u);
auto result = table->Lookup(core::Function::kUnpack2X16Float, Vector{u32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kUnpack2X16Float);
- EXPECT_EQ(result.sem->ReturnType(), vec2_f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 1u);
- EXPECT_EQ(result.sem->Parameters()[0]->Type(), u32);
+ EXPECT_EQ(result->return_type, vec2_f32);
+ ASSERT_EQ(result->parameters.Length(), 1u);
+ EXPECT_EQ(result->parameters[0].type, u32);
}
TEST_F(IntrinsicTableTest, MismatchU32) {
auto* f32 = create<type::F32>();
auto result = table->Lookup(core::Function::kUnpack2X16Float, Vector{f32},
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -101,17 +101,16 @@
auto* tex = create<type::SampledTexture>(type::TextureDimension::k1d, f32);
auto result = table->Lookup(core::Function::kTextureLoad, Vector{tex, i32, i32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kTextureLoad);
- EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 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);
+ EXPECT_EQ(result->return_type, vec4_f32);
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, tex);
+ EXPECT_EQ(result->parameters[0].usage, ParameterUsage::kTexture);
+ EXPECT_EQ(result->parameters[1].type, i32);
+ EXPECT_EQ(result->parameters[1].usage, ParameterUsage::kCoords);
+ EXPECT_EQ(result->parameters[2].type, i32);
+ EXPECT_EQ(result->parameters[2].usage, ParameterUsage::kLevel);
}
TEST_F(IntrinsicTableTest, MismatchI32) {
@@ -119,7 +118,7 @@
auto* tex = create<type::SampledTexture>(type::TextureDimension::k1d, f32);
auto result = table->Lookup(core::Function::kTextureLoad, Vector{tex, f32},
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -127,31 +126,29 @@
auto* i32 = create<type::I32>();
auto result = table->Lookup(core::Function::kCountOneBits, Vector{i32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kCountOneBits);
- EXPECT_EQ(result.sem->ReturnType(), i32);
- ASSERT_EQ(result.sem->Parameters().Length(), 1u);
- EXPECT_EQ(result.sem->Parameters()[0]->Type(), i32);
+ EXPECT_EQ(result->return_type, i32);
+ ASSERT_EQ(result->parameters.Length(), 1u);
+ EXPECT_EQ(result->parameters[0].type, i32);
}
TEST_F(IntrinsicTableTest, MatchIU32AsU32) {
auto* u32 = create<type::U32>();
auto result = table->Lookup(core::Function::kCountOneBits, Vector{u32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kCountOneBits);
- EXPECT_EQ(result.sem->ReturnType(), u32);
- ASSERT_EQ(result.sem->Parameters().Length(), 1u);
- EXPECT_EQ(result.sem->Parameters()[0]->Type(), u32);
+ EXPECT_EQ(result->return_type, u32);
+ ASSERT_EQ(result->parameters.Length(), 1u);
+ EXPECT_EQ(result->parameters[0].type, u32);
}
TEST_F(IntrinsicTableTest, MismatchIU32) {
auto* f32 = create<type::F32>();
auto result = table->Lookup(core::Function::kCountOneBits, Vector{f32},
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -159,49 +156,46 @@
auto* i32 = create<type::I32>();
auto result = table->Lookup(core::Function::kClamp, Vector{i32, i32, i32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kClamp);
- EXPECT_EQ(result.sem->ReturnType(), i32);
- ASSERT_EQ(result.sem->Parameters().Length(), 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);
+ EXPECT_EQ(result->return_type, i32);
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, i32);
+ EXPECT_EQ(result->parameters[1].type, i32);
+ EXPECT_EQ(result->parameters[2].type, i32);
}
TEST_F(IntrinsicTableTest, MatchFIU32AsU32) {
auto* u32 = create<type::U32>();
auto result = table->Lookup(core::Function::kClamp, Vector{u32, u32, u32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kClamp);
- EXPECT_EQ(result.sem->ReturnType(), u32);
- ASSERT_EQ(result.sem->Parameters().Length(), 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);
+ EXPECT_EQ(result->return_type, u32);
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, u32);
+ EXPECT_EQ(result->parameters[1].type, u32);
+ EXPECT_EQ(result->parameters[2].type, u32);
}
TEST_F(IntrinsicTableTest, MatchFIU32AsF32) {
auto* f32 = create<type::F32>();
auto result = table->Lookup(core::Function::kClamp, Vector{f32, f32, f32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kClamp);
- EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 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);
+ EXPECT_EQ(result->return_type, f32);
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, f32);
+ EXPECT_EQ(result->parameters[1].type, f32);
+ EXPECT_EQ(result->parameters[2].type, f32);
}
TEST_F(IntrinsicTableTest, MismatchFIU32) {
auto* bool_ = create<type::Bool>();
auto result = table->Lookup(core::Function::kClamp, Vector{bool_, bool_, bool_},
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -210,21 +204,20 @@
auto* bool_ = create<type::Bool>();
auto result = table->Lookup(core::Function::kSelect, Vector{f32, f32, bool_},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kSelect);
- EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 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_);
+ EXPECT_EQ(result->return_type, f32);
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, f32);
+ EXPECT_EQ(result->parameters[1].type, f32);
+ EXPECT_EQ(result->parameters[2].type, bool_);
}
TEST_F(IntrinsicTableTest, MismatchBool) {
auto* f32 = create<type::F32>();
auto result = table->Lookup(core::Function::kSelect, Vector{f32, f32, f32},
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -235,12 +228,11 @@
create<type::Pointer>(core::AddressSpace::kWorkgroup, atomicI32, core::Access::kReadWrite);
auto result = table->Lookup(core::Function::kAtomicLoad, Vector{ptr},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kAtomicLoad);
- EXPECT_EQ(result.sem->ReturnType(), i32);
- ASSERT_EQ(result.sem->Parameters().Length(), 1u);
- EXPECT_EQ(result.sem->Parameters()[0]->Type(), ptr);
+ EXPECT_EQ(result->return_type, i32);
+ ASSERT_EQ(result->parameters.Length(), 1u);
+ EXPECT_EQ(result->parameters[0].type, ptr);
}
TEST_F(IntrinsicTableTest, MismatchPointer) {
@@ -248,7 +240,7 @@
auto* atomicI32 = create<type::Atomic>(i32);
auto result = table->Lookup(core::Function::kAtomicLoad, Vector{atomicI32},
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -259,12 +251,11 @@
create<type::Pointer>(core::AddressSpace::kStorage, arr, core::Access::kReadWrite);
auto result = table->Lookup(core::Function::kArrayLength, Vector{arr_ptr},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kArrayLength);
- EXPECT_TRUE(result.sem->ReturnType()->Is<type::U32>());
- ASSERT_EQ(result.sem->Parameters().Length(), 1u);
- auto* param_type = result.sem->Parameters()[0]->Type();
+ EXPECT_TRUE(result->return_type->Is<type::U32>());
+ ASSERT_EQ(result->parameters.Length(), 1u);
+ auto* param_type = result->parameters[0].type;
ASSERT_TRUE(param_type->Is<type::Pointer>());
EXPECT_TRUE(param_type->As<type::Pointer>()->StoreType()->Is<type::Array>());
}
@@ -273,7 +264,7 @@
auto* f32 = create<type::F32>();
auto result = table->Lookup(core::Function::kArrayLength, Vector{f32},
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -285,17 +276,16 @@
auto* sampler = create<type::Sampler>(type::SamplerKind::kSampler);
auto result = table->Lookup(core::Function::kTextureSample, Vector{tex, sampler, vec2_f32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kTextureSample);
- EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 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);
+ EXPECT_EQ(result->return_type, vec4_f32);
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, tex);
+ EXPECT_EQ(result->parameters[0].usage, ParameterUsage::kTexture);
+ EXPECT_EQ(result->parameters[1].type, sampler);
+ EXPECT_EQ(result->parameters[1].usage, ParameterUsage::kSampler);
+ EXPECT_EQ(result->parameters[2].type, vec2_f32);
+ EXPECT_EQ(result->parameters[2].usage, ParameterUsage::kCoords);
}
TEST_F(IntrinsicTableTest, MismatchSampler) {
@@ -304,7 +294,7 @@
auto* tex = create<type::SampledTexture>(type::TextureDimension::k2d, f32);
auto result = table->Lookup(core::Function::kTextureSample, Vector{tex, f32, vec2_f32},
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -316,17 +306,16 @@
auto* tex = create<type::SampledTexture>(type::TextureDimension::k2d, f32);
auto result = table->Lookup(core::Function::kTextureLoad, Vector{tex, vec2_i32, i32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kTextureLoad);
- EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 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);
+ EXPECT_EQ(result->return_type, vec4_f32);
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, tex);
+ EXPECT_EQ(result->parameters[0].usage, ParameterUsage::kTexture);
+ EXPECT_EQ(result->parameters[1].type, vec2_i32);
+ EXPECT_EQ(result->parameters[1].usage, ParameterUsage::kCoords);
+ EXPECT_EQ(result->parameters[2].type, i32);
+ EXPECT_EQ(result->parameters[2].usage, ParameterUsage::kLevel);
}
TEST_F(IntrinsicTableTest, MatchMultisampledTexture) {
@@ -337,17 +326,16 @@
auto* tex = create<type::MultisampledTexture>(type::TextureDimension::k2d, f32);
auto result = table->Lookup(core::Function::kTextureLoad, Vector{tex, vec2_i32, i32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kTextureLoad);
- EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 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);
+ EXPECT_EQ(result->return_type, vec4_f32);
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, tex);
+ EXPECT_EQ(result->parameters[0].usage, ParameterUsage::kTexture);
+ EXPECT_EQ(result->parameters[1].type, vec2_i32);
+ EXPECT_EQ(result->parameters[1].usage, ParameterUsage::kCoords);
+ EXPECT_EQ(result->parameters[2].type, i32);
+ EXPECT_EQ(result->parameters[2].usage, ParameterUsage::kSampleIndex);
}
TEST_F(IntrinsicTableTest, MatchDepthTexture) {
@@ -357,17 +345,16 @@
auto* tex = create<type::DepthTexture>(type::TextureDimension::k2d);
auto result = table->Lookup(core::Function::kTextureLoad, Vector{tex, vec2_i32, i32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kTextureLoad);
- EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 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);
+ EXPECT_EQ(result->return_type, f32);
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, tex);
+ EXPECT_EQ(result->parameters[0].usage, ParameterUsage::kTexture);
+ EXPECT_EQ(result->parameters[1].type, vec2_i32);
+ EXPECT_EQ(result->parameters[1].usage, ParameterUsage::kCoords);
+ EXPECT_EQ(result->parameters[2].type, i32);
+ EXPECT_EQ(result->parameters[2].usage, ParameterUsage::kLevel);
}
TEST_F(IntrinsicTableTest, MatchDepthMultisampledTexture) {
@@ -377,17 +364,16 @@
auto* tex = create<type::DepthMultisampledTexture>(type::TextureDimension::k2d);
auto result = table->Lookup(core::Function::kTextureLoad, Vector{tex, vec2_i32, i32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kTextureLoad);
- EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 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);
+ EXPECT_EQ(result->return_type, f32);
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, tex);
+ EXPECT_EQ(result->parameters[0].usage, ParameterUsage::kTexture);
+ EXPECT_EQ(result->parameters[1].type, vec2_i32);
+ EXPECT_EQ(result->parameters[1].usage, ParameterUsage::kCoords);
+ EXPECT_EQ(result->parameters[2].type, i32);
+ EXPECT_EQ(result->parameters[2].usage, ParameterUsage::kSampleIndex);
}
TEST_F(IntrinsicTableTest, MatchExternalTexture) {
@@ -398,15 +384,14 @@
auto* tex = create<type::ExternalTexture>();
auto result = table->Lookup(core::Function::kTextureLoad, Vector{tex, vec2_i32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kTextureLoad);
- EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 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);
+ EXPECT_EQ(result->return_type, vec4_f32);
+ ASSERT_EQ(result->parameters.Length(), 2u);
+ EXPECT_EQ(result->parameters[0].type, tex);
+ EXPECT_EQ(result->parameters[0].usage, ParameterUsage::kTexture);
+ EXPECT_EQ(result->parameters[1].type, vec2_i32);
+ EXPECT_EQ(result->parameters[1].usage, ParameterUsage::kCoords);
}
TEST_F(IntrinsicTableTest, MatchWOStorageTexture) {
@@ -420,17 +405,16 @@
auto result = table->Lookup(core::Function::kTextureStore, Vector{tex, vec2_i32, vec4_f32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kTextureStore);
- EXPECT_TRUE(result.sem->ReturnType()->Is<type::Void>());
- ASSERT_EQ(result.sem->Parameters().Length(), 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);
+ EXPECT_TRUE(result->return_type->Is<type::Void>());
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, tex);
+ EXPECT_EQ(result->parameters[0].usage, ParameterUsage::kTexture);
+ EXPECT_EQ(result->parameters[1].type, vec2_i32);
+ EXPECT_EQ(result->parameters[1].usage, ParameterUsage::kCoords);
+ EXPECT_EQ(result->parameters[2].type, vec4_f32);
+ EXPECT_EQ(result->parameters[2].usage, ParameterUsage::kValue);
}
TEST_F(IntrinsicTableTest, MismatchTexture) {
@@ -439,7 +423,7 @@
auto* vec2_i32 = create<type::Vector>(i32, 2u);
auto result = table->Lookup(core::Function::kTextureLoad, Vector{f32, vec2_i32},
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -451,25 +435,23 @@
create<type::Reference>(core::AddressSpace::kFunction, f32, core::Access::kReadWrite),
},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kCos);
- EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 1u);
- EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32);
+ EXPECT_EQ(result->return_type, f32);
+ ASSERT_EQ(result->parameters.Length(), 1u);
+ EXPECT_EQ(result->parameters[0].type, f32);
}
TEST_F(IntrinsicTableTest, MatchTemplateType) {
auto* f32 = create<type::F32>();
auto result = table->Lookup(core::Function::kClamp, Vector{f32, f32, f32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::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);
+ EXPECT_EQ(result->return_type, f32);
+ EXPECT_EQ(result->parameters[0].type, f32);
+ EXPECT_EQ(result->parameters[1].type, f32);
+ EXPECT_EQ(result->parameters[2].type, f32);
}
TEST_F(IntrinsicTableTest, MismatchTemplateType) {
@@ -477,7 +459,7 @@
auto* u32 = create<type::U32>();
auto result = table->Lookup(core::Function::kClamp, Vector{f32, u32, f32},
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -486,14 +468,13 @@
auto* vec2_f32 = create<type::Vector>(f32, 2u);
auto result = table->Lookup(core::Function::kClamp, Vector{vec2_f32, vec2_f32, vec2_f32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kClamp);
- EXPECT_EQ(result.sem->ReturnType(), vec2_f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 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);
+ EXPECT_EQ(result->return_type, vec2_f32);
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, vec2_f32);
+ EXPECT_EQ(result->parameters[1].type, vec2_f32);
+ EXPECT_EQ(result->parameters[2].type, vec2_f32);
}
TEST_F(IntrinsicTableTest, MismatchOpenSizeVector) {
@@ -502,7 +483,7 @@
auto* vec2_f32 = create<type::Vector>(f32, 2u);
auto result = table->Lookup(core::Function::kClamp, Vector{vec2_f32, u32, vec2_f32},
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -512,12 +493,11 @@
auto* mat3_f32 = create<type::Matrix>(vec3_f32, 3u);
auto result = table->Lookup(core::Function::kDeterminant, Vector{mat3_f32},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Type(), core::Function::kDeterminant);
- EXPECT_EQ(result.sem->ReturnType(), f32);
- ASSERT_EQ(result.sem->Parameters().Length(), 1u);
- EXPECT_EQ(result.sem->Parameters()[0]->Type(), mat3_f32);
+ EXPECT_EQ(result->return_type, f32);
+ ASSERT_EQ(result->parameters.Length(), 1u);
+ EXPECT_EQ(result->parameters[0].type, mat3_f32);
}
TEST_F(IntrinsicTableTest, MismatchOpenSizeMatrix) {
@@ -526,7 +506,7 @@
auto* mat3x2_f32 = create<type::Matrix>(vec2_f32, 3u);
auto result = table->Lookup(core::Function::kDeterminant, Vector{mat3x2_f32},
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -535,15 +515,14 @@
auto* bool_ = create<type::Bool>();
auto result = table->Lookup(core::Function::kSelect, Vector{af, af, bool_},
EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Stage(), EvaluationStage::kConstant);
- EXPECT_EQ(result.sem->Type(), core::Function::kSelect);
- EXPECT_EQ(result.sem->ReturnType(), af);
- ASSERT_EQ(result.sem->Parameters().Length(), 3u);
- EXPECT_EQ(result.sem->Parameters()[0]->Type(), af);
- EXPECT_EQ(result.sem->Parameters()[1]->Type(), af);
- EXPECT_EQ(result.sem->Parameters()[2]->Type(), bool_);
+ EXPECT_NE(result->info->const_eval_fn, nullptr);
+ EXPECT_EQ(result->return_type, af);
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, af);
+ EXPECT_EQ(result->parameters[1].type, af);
+ EXPECT_EQ(result->parameters[2].type, bool_);
}
TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_Builtin_RuntimeEval) {
@@ -552,15 +531,14 @@
core::Access::kReadWrite);
auto result = table->Lookup(core::Function::kSelect, Vector{af, af, bool_ref},
EvaluationStage::kRuntime, Source{});
- ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.sem->Stage(), EvaluationStage::kConstant);
- EXPECT_EQ(result.sem->Type(), core::Function::kSelect);
- EXPECT_TRUE(result.sem->ReturnType()->Is<type::F32>());
- ASSERT_EQ(result.sem->Parameters().Length(), 3u);
- EXPECT_TRUE(result.sem->Parameters()[0]->Type()->Is<type::F32>());
- EXPECT_TRUE(result.sem->Parameters()[1]->Type()->Is<type::F32>());
- EXPECT_TRUE(result.sem->Parameters()[2]->Type()->Is<type::Bool>());
+ EXPECT_NE(result->info->const_eval_fn, nullptr);
+ EXPECT_TRUE(result->return_type->Is<type::F32>());
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_TRUE(result->parameters[0].type->Is<type::F32>());
+ EXPECT_TRUE(result->parameters[1].type->Is<type::F32>());
+ EXPECT_TRUE(result->parameters[2].type->Is<type::Bool>());
}
TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_Binary_ConstantEval) {
@@ -568,12 +546,12 @@
auto* u32 = create<type::U32>();
auto result = table->Lookup(core::BinaryOp::kShiftLeft, ai, u32, EvaluationStage::kConstant,
Source{}, false);
- ASSERT_NE(result.result, nullptr) << Diagnostics().str();
- ASSERT_NE(result.const_eval_fn, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
+ ASSERT_NE(result->info->const_eval_fn, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_EQ(result.result, ai);
- EXPECT_EQ(result.lhs, ai);
- EXPECT_EQ(result.rhs, u32);
+ EXPECT_EQ(result->return_type, ai);
+ EXPECT_EQ(result->parameters[0].type, ai);
+ EXPECT_EQ(result->parameters[1].type, u32);
}
TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_Binary_RuntimeEval) {
@@ -581,20 +559,21 @@
auto* u32 = create<type::U32>();
auto result = table->Lookup(core::BinaryOp::kShiftLeft, ai, u32, EvaluationStage::kRuntime,
Source{}, false);
- ASSERT_NE(result.result, nullptr) << Diagnostics().str();
- ASSERT_NE(result.const_eval_fn, nullptr) << Diagnostics().str();
+ ASSERT_TRUE(result) << Diagnostics().str();
+ ASSERT_NE(result->info->const_eval_fn, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
- EXPECT_TRUE(result.result->Is<type::I32>());
- EXPECT_TRUE(result.lhs->Is<type::I32>());
- EXPECT_TRUE(result.rhs->Is<type::U32>());
+ EXPECT_TRUE(result->return_type->Is<type::I32>());
+ EXPECT_TRUE(result->parameters[0].type->Is<type::I32>());
+ EXPECT_TRUE(result->parameters[1].type->Is<type::U32>());
}
TEST_F(IntrinsicTableTest, OverloadOrderByNumberOfParameters) {
// None of the arguments match, so expect the overloads with 2 parameters to
// come first
auto* bool_ = create<type::Bool>();
- table->Lookup(core::Function::kTextureDimensions, Vector{bool_, bool_},
- EvaluationStage::kConstant, Source{});
+ auto result = table->Lookup(core::Function::kTextureDimensions, Vector{bool_, bool_},
+ EvaluationStage::kConstant, Source{});
+ EXPECT_FALSE(result);
ASSERT_EQ(Diagnostics().str(),
R"(error: no matching call to textureDimensions(bool, bool)
@@ -632,8 +611,9 @@
TEST_F(IntrinsicTableTest, OverloadOrderByMatchingParameter) {
auto* tex = create<type::DepthTexture>(type::TextureDimension::k2d);
auto* bool_ = create<type::Bool>();
- table->Lookup(core::Function::kTextureDimensions, Vector{tex, bool_},
- EvaluationStage::kConstant, Source{});
+ auto result = table->Lookup(core::Function::kTextureDimensions, Vector{tex, bool_},
+ EvaluationStage::kConstant, Source{});
+ EXPECT_FALSE(result);
ASSERT_EQ(Diagnostics().str(),
R"(error: no matching call to textureDimensions(texture_depth_2d, bool)
@@ -668,35 +648,12 @@
)");
}
-TEST_F(IntrinsicTableTest, SameOverloadReturnsSameBuiltinPointer) {
- auto* f32 = create<type::F32>();
- auto* vec2_f32 = create<type::Vector>(create<type::F32>(), 2u);
- auto* bool_ = create<type::Bool>();
- auto a = table->Lookup(core::Function::kSelect, Vector{f32, f32, bool_},
- EvaluationStage::kConstant, Source{});
- ASSERT_NE(a.sem, nullptr) << Diagnostics().str();
-
- auto b = table->Lookup(core::Function::kSelect, Vector{f32, f32, bool_},
- EvaluationStage::kConstant, Source{});
- ASSERT_NE(b.sem, nullptr) << Diagnostics().str();
- ASSERT_EQ(Diagnostics().str(), "");
-
- auto c = table->Lookup(core::Function::kSelect, Vector{vec2_f32, vec2_f32, bool_},
- EvaluationStage::kConstant, 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<type::I32>();
auto* vec3_i32 = create<type::Vector>(i32, 3u);
auto result = table->Lookup(core::UnaryOp::kNegation, vec3_i32, EvaluationStage::kConstant,
Source{{12, 34}});
- EXPECT_EQ(result.result, vec3_i32);
+ EXPECT_EQ(result->return_type, vec3_i32);
EXPECT_EQ(Diagnostics().str(), "");
}
@@ -704,7 +661,7 @@
auto* bool_ = create<type::Bool>();
auto result = table->Lookup(core::UnaryOp::kNegation, bool_, EvaluationStage::kConstant,
Source{{12, 34}});
- ASSERT_EQ(result.result, nullptr);
+ ASSERT_FALSE(result);
EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator - (bool)
2 candidate operators:
@@ -717,7 +674,7 @@
auto* ai = create<type::AbstractInt>();
auto result =
table->Lookup(core::UnaryOp::kNegation, ai, EvaluationStage::kConstant, Source{{12, 34}});
- EXPECT_EQ(result.result, ai);
+ EXPECT_EQ(result->return_type, ai);
EXPECT_EQ(Diagnostics().str(), "");
}
@@ -725,8 +682,8 @@
auto* ai = create<type::AbstractInt>();
auto result =
table->Lookup(core::UnaryOp::kNegation, ai, EvaluationStage::kRuntime, Source{{12, 34}});
- EXPECT_NE(result.result, ai);
- EXPECT_TRUE(result.result->Is<type::I32>());
+ EXPECT_NE(result->return_type, ai);
+ EXPECT_TRUE(result->return_type->Is<type::I32>());
EXPECT_EQ(Diagnostics().str(), "");
}
@@ -736,9 +693,9 @@
auto result = table->Lookup(core::BinaryOp::kMultiply, i32, vec3_i32,
EvaluationStage::kConstant, 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(result->return_type, vec3_i32);
+ EXPECT_EQ(result->parameters[0].type, i32);
+ EXPECT_EQ(result->parameters[1].type, vec3_i32);
EXPECT_EQ(Diagnostics().str(), "");
}
@@ -748,7 +705,7 @@
auto result = table->Lookup(core::BinaryOp::kMultiply, f32, bool_, EvaluationStage::kConstant,
Source{{12, 34}},
/* is_compound */ false);
- ASSERT_EQ(result.result, nullptr);
+ ASSERT_FALSE(result);
EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator * (f32, bool)
9 candidate operators:
@@ -770,9 +727,9 @@
auto result = table->Lookup(core::BinaryOp::kMultiply, i32, vec3_i32,
EvaluationStage::kConstant, 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(result->return_type, vec3_i32);
+ EXPECT_EQ(result->parameters[0].type, i32);
+ EXPECT_EQ(result->parameters[1].type, vec3_i32);
EXPECT_EQ(Diagnostics().str(), "");
}
@@ -782,7 +739,7 @@
auto result = table->Lookup(core::BinaryOp::kMultiply, f32, bool_, EvaluationStage::kConstant,
Source{{12, 34}},
/* is_compound */ true);
- ASSERT_EQ(result.result, nullptr);
+ ASSERT_FALSE(result);
EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator *= (f32, bool)
9 candidate operators:
@@ -803,14 +760,14 @@
auto* vec3_i32 = create<type::Vector>(i32, 3u);
auto result = table->Lookup(CtorConv::kVec3, nullptr, Vector{i32, i32, i32},
EvaluationStage::kConstant, Source{{12, 34}});
- ASSERT_NE(result.target, nullptr);
- EXPECT_EQ(result.target->ReturnType(), vec3_i32);
- EXPECT_TRUE(result.target->Is<sem::ValueConstructor>());
- ASSERT_EQ(result.target->Parameters().Length(), 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);
+ ASSERT_TRUE(result) << Diagnostics().str();
+ EXPECT_EQ(result->return_type, vec3_i32);
+ EXPECT_TRUE(result->info->flags.Contains(TableData::OverloadFlag::kIsConstructor));
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, i32);
+ EXPECT_EQ(result->parameters[1].type, i32);
+ EXPECT_EQ(result->parameters[2].type, i32);
+ EXPECT_NE(result->info->const_eval_fn, nullptr);
}
TEST_F(IntrinsicTableTest, MatchTypeInitializerExplicit) {
@@ -818,14 +775,14 @@
auto* vec3_i32 = create<type::Vector>(i32, 3u);
auto result = table->Lookup(CtorConv::kVec3, i32, Vector{i32, i32, i32},
EvaluationStage::kConstant, Source{{12, 34}});
- ASSERT_NE(result.target, nullptr);
- EXPECT_EQ(result.target->ReturnType(), vec3_i32);
- EXPECT_TRUE(result.target->Is<sem::ValueConstructor>());
- ASSERT_EQ(result.target->Parameters().Length(), 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);
+ ASSERT_TRUE(result) << Diagnostics().str();
+ EXPECT_EQ(result->return_type, vec3_i32);
+ EXPECT_TRUE(result->info->flags.Contains(TableData::OverloadFlag::kIsConstructor));
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, i32);
+ EXPECT_EQ(result->parameters[1].type, i32);
+ EXPECT_EQ(result->parameters[2].type, i32);
+ EXPECT_NE(result->info->const_eval_fn, nullptr);
}
TEST_F(IntrinsicTableTest, MismatchTypeInitializerImplicit) {
@@ -833,7 +790,7 @@
auto* f32 = create<type::F32>();
auto result = table->Lookup(CtorConv::kVec3, nullptr, Vector{i32, f32, i32},
EvaluationStage::kConstant, Source{{12, 34}});
- ASSERT_EQ(result.target, nullptr);
+ ASSERT_FALSE(result);
EXPECT_EQ(Diagnostics().str(),
R"(12:34 error: no matching constructor for vec3(i32, f32, i32)
@@ -860,7 +817,7 @@
auto* f32 = create<type::F32>();
auto result = table->Lookup(CtorConv::kVec3, i32, Vector{i32, f32, i32},
EvaluationStage::kConstant, Source{{12, 34}});
- ASSERT_EQ(result.target, nullptr);
+ ASSERT_FALSE(result);
EXPECT_EQ(Diagnostics().str(),
R"(12:34 error: no matching constructor for vec3<i32>(i32, f32, i32)
@@ -887,12 +844,12 @@
auto* vec3_ai = create<type::Vector>(ai, 3u);
auto result = table->Lookup(CtorConv::kVec3, nullptr, Vector{vec3_ai},
EvaluationStage::kConstant, Source{{12, 34}});
- ASSERT_NE(result.target, nullptr);
- EXPECT_EQ(result.target->ReturnType(), vec3_ai);
- EXPECT_TRUE(result.target->Is<sem::ValueConstructor>());
- ASSERT_EQ(result.target->Parameters().Length(), 1u);
- EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_ai);
- EXPECT_NE(result.const_eval_fn, nullptr);
+ ASSERT_TRUE(result) << Diagnostics().str();
+ EXPECT_EQ(result->return_type, vec3_ai);
+ EXPECT_TRUE(result->info->flags.Contains(TableData::OverloadFlag::kIsConstructor));
+ ASSERT_EQ(result->parameters.Length(), 1u);
+ EXPECT_EQ(result->parameters[0].type, vec3_ai);
+ EXPECT_NE(result->info->const_eval_fn, nullptr);
}
TEST_F(IntrinsicTableTest, MatchTypeInitializerImplicitMatFromVec) {
@@ -902,13 +859,13 @@
auto* mat2x2_af = create<type::Matrix>(vec2_af, 2u);
auto result = table->Lookup(CtorConv::kMat2x2, nullptr, Vector{vec2_ai, vec2_ai},
EvaluationStage::kConstant, Source{{12, 34}});
- ASSERT_NE(result.target, nullptr);
- EXPECT_TYPE(result.target->ReturnType(), mat2x2_af);
- EXPECT_TRUE(result.target->Is<sem::ValueConstructor>());
- ASSERT_EQ(result.target->Parameters().Length(), 2u);
- EXPECT_TYPE(result.target->Parameters()[0]->Type(), vec2_af);
- EXPECT_TYPE(result.target->Parameters()[1]->Type(), vec2_af);
- EXPECT_NE(result.const_eval_fn, nullptr);
+ ASSERT_TRUE(result) << Diagnostics().str();
+ EXPECT_TYPE(result->return_type, mat2x2_af);
+ EXPECT_TRUE(result->info->flags.Contains(TableData::OverloadFlag::kIsConstructor));
+ ASSERT_EQ(result->parameters.Length(), 2u);
+ EXPECT_TYPE(result->parameters[0].type, vec2_af);
+ EXPECT_TYPE(result->parameters[1].type, vec2_af);
+ EXPECT_NE(result->info->const_eval_fn, nullptr);
}
TEST_F(IntrinsicTableTest, MatchTypeInitializer_ConstantEval) {
@@ -916,15 +873,15 @@
auto* vec3_ai = create<type::Vector>(ai, 3u);
auto result = table->Lookup(CtorConv::kVec3, nullptr, Vector{ai, ai, ai},
EvaluationStage::kConstant, Source{{12, 34}});
- ASSERT_NE(result.target, nullptr);
- EXPECT_EQ(result.target->Stage(), EvaluationStage::kConstant);
- EXPECT_EQ(result.target->ReturnType(), vec3_ai);
- EXPECT_TRUE(result.target->Is<sem::ValueConstructor>());
- ASSERT_EQ(result.target->Parameters().Length(), 3u);
- EXPECT_EQ(result.target->Parameters()[0]->Type(), ai);
- EXPECT_EQ(result.target->Parameters()[1]->Type(), ai);
- EXPECT_EQ(result.target->Parameters()[2]->Type(), ai);
- EXPECT_NE(result.const_eval_fn, nullptr);
+ ASSERT_TRUE(result) << Diagnostics().str();
+ EXPECT_NE(result->info->const_eval_fn, nullptr);
+ EXPECT_EQ(result->return_type, vec3_ai);
+ EXPECT_TRUE(result->info->flags.Contains(TableData::OverloadFlag::kIsConstructor));
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, ai);
+ EXPECT_EQ(result->parameters[1].type, ai);
+ EXPECT_EQ(result->parameters[2].type, ai);
+ EXPECT_NE(result->info->const_eval_fn, nullptr);
}
TEST_F(IntrinsicTableTest, MatchTypeInitializer_RuntimeEval) {
@@ -933,15 +890,15 @@
EvaluationStage::kRuntime, Source{{12, 34}});
auto* i32 = create<type::I32>();
auto* vec3_i32 = create<type::Vector>(i32, 3u);
- ASSERT_NE(result.target, nullptr);
- EXPECT_EQ(result.target->Stage(), EvaluationStage::kConstant);
- EXPECT_EQ(result.target->ReturnType(), vec3_i32);
- EXPECT_TRUE(result.target->Is<sem::ValueConstructor>());
- ASSERT_EQ(result.target->Parameters().Length(), 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);
+ ASSERT_TRUE(result) << Diagnostics().str();
+ EXPECT_NE(result->info->const_eval_fn, nullptr);
+ EXPECT_EQ(result->return_type, vec3_i32);
+ EXPECT_TRUE(result->info->flags.Contains(TableData::OverloadFlag::kIsConstructor));
+ ASSERT_EQ(result->parameters.Length(), 3u);
+ EXPECT_EQ(result->parameters[0].type, i32);
+ EXPECT_EQ(result->parameters[1].type, i32);
+ EXPECT_EQ(result->parameters[2].type, i32);
+ EXPECT_NE(result->info->const_eval_fn, nullptr);
}
TEST_F(IntrinsicTableTest, MatchTypeConversion) {
@@ -951,11 +908,11 @@
auto* vec3_f32 = create<type::Vector>(f32, 3u);
auto result = table->Lookup(CtorConv::kVec3, i32, Vector{vec3_f32}, EvaluationStage::kConstant,
Source{{12, 34}});
- ASSERT_NE(result.target, nullptr);
- EXPECT_EQ(result.target->ReturnType(), vec3_i32);
- EXPECT_TRUE(result.target->Is<sem::ValueConversion>());
- ASSERT_EQ(result.target->Parameters().Length(), 1u);
- EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_f32);
+ ASSERT_TRUE(result) << Diagnostics().str();
+ EXPECT_EQ(result->return_type, vec3_i32);
+ EXPECT_FALSE(result->info->flags.Contains(TableData::OverloadFlag::kIsConstructor));
+ ASSERT_EQ(result->parameters.Length(), 1u);
+ EXPECT_EQ(result->parameters[0].type, vec3_f32);
}
TEST_F(IntrinsicTableTest, MismatchTypeConversion) {
@@ -964,7 +921,7 @@
auto* f32 = create<type::F32>();
auto result = table->Lookup(CtorConv::kVec3, f32, Vector{arr}, EvaluationStage::kConstant,
Source{{12, 34}});
- ASSERT_EQ(result.target, nullptr);
+ ASSERT_FALSE(result);
EXPECT_EQ(Diagnostics().str(),
R"(12:34 error: no matching constructor for vec3<f32>(array<u32>)
@@ -994,13 +951,13 @@
auto* vec3_f32 = create<type::Vector>(f32, 3u);
auto result = table->Lookup(CtorConv::kVec3, af, Vector{vec3_ai}, EvaluationStage::kConstant,
Source{{12, 34}});
- ASSERT_NE(result.target, nullptr);
- EXPECT_EQ(result.target->Stage(), EvaluationStage::kConstant);
+ ASSERT_TRUE(result) << Diagnostics().str();
+ EXPECT_NE(result->info->const_eval_fn, nullptr);
// NOTE: Conversions are explicit, so there's no way to have it return abstracts
- EXPECT_EQ(result.target->ReturnType(), vec3_f32);
- EXPECT_TRUE(result.target->Is<sem::ValueConversion>());
- ASSERT_EQ(result.target->Parameters().Length(), 1u);
- EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_ai);
+ EXPECT_EQ(result->return_type, vec3_f32);
+ EXPECT_FALSE(result->info->flags.Contains(TableData::OverloadFlag::kIsConstructor));
+ ASSERT_EQ(result->parameters.Length(), 1u);
+ EXPECT_EQ(result->parameters[0].type, vec3_ai);
}
TEST_F(IntrinsicTableTest, MatchTypeConversion_RuntimeEval) {
@@ -1011,12 +968,12 @@
auto* vec3_i32 = create<type::Vector>(create<type::I32>(), 3u);
auto result = table->Lookup(CtorConv::kVec3, af, Vector{vec3_ai}, EvaluationStage::kRuntime,
Source{{12, 34}});
- ASSERT_NE(result.target, nullptr);
- EXPECT_EQ(result.target->Stage(), EvaluationStage::kConstant);
- EXPECT_EQ(result.target->ReturnType(), vec3_f32);
- EXPECT_TRUE(result.target->Is<sem::ValueConversion>());
- ASSERT_EQ(result.target->Parameters().Length(), 1u);
- EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_i32);
+ ASSERT_TRUE(result) << Diagnostics().str();
+ EXPECT_NE(result->info->const_eval_fn, nullptr);
+ EXPECT_EQ(result->return_type, vec3_f32);
+ EXPECT_FALSE(result->info->flags.Contains(TableData::OverloadFlag::kIsConstructor));
+ ASSERT_EQ(result->parameters.Length(), 1u);
+ EXPECT_EQ(result->parameters[0].type, vec3_i32);
}
TEST_F(IntrinsicTableTest, Err257Arguments) { // crbug.com/1323605
@@ -1025,7 +982,7 @@
arg_tys.Resize(257, f32);
auto result = table->Lookup(core::Function::kAbs, std::move(arg_tys),
EvaluationStage::kConstant, Source{});
- ASSERT_EQ(result.sem, nullptr);
+ ASSERT_FALSE(result);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@@ -1038,10 +995,10 @@
auto* i32 = create<type::I32>();
auto result =
table->Lookup(CtorConv::kI32, nullptr, Vector{ai}, EvaluationStage::kConstant, Source{});
- ASSERT_NE(result.target, nullptr);
- EXPECT_EQ(result.target->ReturnType(), i32);
- EXPECT_EQ(result.target->Parameters().Length(), 1u);
- EXPECT_EQ(result.target->Parameters()[0]->Type(), ai);
+ ASSERT_TRUE(result) << Diagnostics().str();
+ EXPECT_EQ(result->return_type, i32);
+ EXPECT_EQ(result->parameters.Length(), 1u);
+ EXPECT_EQ(result->parameters[0].type, ai);
}
////////////////////////////////////////////////////////////////////////////////
@@ -1073,7 +1030,8 @@
};
struct IntrinsicTableAbstractBinaryTest : public resolver::ResolverTestWithParam<Case> {
- std::unique_ptr<Table> table = Table::Create(*this);
+ std::unique_ptr<Table> table =
+ Table::Create(core::kIntrinsicData, Types(), Symbols(), Diagnostics());
};
TEST_P(IntrinsicTableAbstractBinaryTest, MatchAdd) {
@@ -1083,18 +1041,20 @@
Source{{12, 34}},
/* is_compound */ false);
- bool matched = result.result != nullptr;
+ bool matched = result;
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);
+ if (matched) {
+ auto* expected_result = GetParam().expected_result(*this);
+ EXPECT_TYPE(result->return_type, expected_result);
- auto* expected_param_lhs = GetParam().expected_param_lhs(*this);
- EXPECT_TYPE(result.lhs, expected_param_lhs);
+ auto* expected_param_lhs = GetParam().expected_param_lhs(*this);
+ EXPECT_TYPE(result->parameters[0].type, expected_param_lhs);
- auto* expected_param_rhs = GetParam().expected_param_rhs(*this);
- EXPECT_TYPE(result.rhs, expected_param_rhs);
+ auto* expected_param_rhs = GetParam().expected_param_rhs(*this);
+ EXPECT_TYPE(result->parameters[1].type, expected_param_rhs);
+ }
}
INSTANTIATE_TEST_SUITE_P(AFloat_AInt,
@@ -1255,7 +1215,8 @@
};
struct IntrinsicTableAbstractTernaryTest : public resolver::ResolverTestWithParam<Case> {
- std::unique_ptr<Table> table = Table::Create(*this);
+ std::unique_ptr<Table> table =
+ Table::Create(core::kIntrinsicData, Types(), Symbols(), Diagnostics());
};
TEST_P(IntrinsicTableAbstractTernaryTest, MatchClamp) {
@@ -1265,23 +1226,22 @@
auto builtin = table->Lookup(core::Function::kClamp, Vector{arg_a, arg_b, arg_c},
EvaluationStage::kConstant, Source{{12, 34}});
- bool matched = builtin.sem != nullptr;
bool expected_match = GetParam().expected_match;
- EXPECT_EQ(matched, expected_match) << Diagnostics().str();
+ EXPECT_EQ(builtin == true, expected_match) << Diagnostics().str();
- auto* result = builtin.sem ? builtin.sem->ReturnType() : nullptr;
+ auto* result = builtin ? builtin->return_type : 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* param_a = builtin ? builtin->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* param_b = builtin ? builtin->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* param_c = builtin ? builtin->parameters[2].type : nullptr;
auto* expected_param_c = GetParam().expected_param_c(*this);
EXPECT_TYPE(param_c, expected_param_c);
}
diff --git a/src/tint/lang/core/intrinsic/core_table_data.cc b/src/tint/lang/core/intrinsic_data.cc
similarity index 98%
rename from src/tint/lang/core/intrinsic/core_table_data.cc
rename to src/tint/lang/core/intrinsic_data.cc
index c46680b..ea3daf9 100644
--- a/src/tint/lang/core/intrinsic/core_table_data.cc
+++ b/src/tint/lang/core/intrinsic_data.cc
@@ -15,7 +15,7 @@
////////////////////////////////////////////////////////////////////////////////
// File generated by tools/src/cmd/gen
// using the template:
-// src/tint/lang/core/intrinsic/core_table_data.cc.tmpl
+// src/tint/lang/core/intrinsic_data.cc.tmpl
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
@@ -23,11 +23,11 @@
#include <limits>
#include <string>
-#include "src/tint/lang/core/intrinsic/core_table_data.h"
-#include "src/tint/lang/core/intrinsic/core_type_matchers.h"
+#include "src/tint/lang/core/intrinsic_data.h"
+#include "src/tint/lang/core/intrinsic_type_matchers.h"
#include "src/tint/utils/text/string_stream.h"
-namespace tint::core::intrinsic {
+namespace tint::core {
namespace {
using IntrinsicInfo = tint::core::intrinsic::TableData::IntrinsicInfo;
@@ -14367,35 +14367,32 @@
} // anonymous namespace
-const TableData& CoreTableData() {
- static const TableData data{
- /* type_matchers */ kTypeMatchers,
- /* number_matchers */ kNumberMatchers,
- /* ctor_conv */ kConstructorsAndConverters,
- /* builtins */ kBuiltins,
- /* binary_plus */ kBinaryOperators[kBinaryOperatorPlus],
- /* binary_minus */ kBinaryOperators[kBinaryOperatorMinus],
- /* binary_star */ kBinaryOperators[kBinaryOperatorStar],
- /* binary_divide */ kBinaryOperators[kBinaryOperatorDivide],
- /* binary_modulo */ kBinaryOperators[kBinaryOperatorModulo],
- /* binary_xor */ kBinaryOperators[kBinaryOperatorXor],
- /* binary_and */ kBinaryOperators[kBinaryOperatorAnd],
- /* binary_or */ kBinaryOperators[kBinaryOperatorOr],
- /* binary_logical_and */ kBinaryOperators[kBinaryOperatorLogicalAnd],
- /* binary_logical_or */ kBinaryOperators[kBinaryOperatorLogicalOr],
- /* binary_equal */ kBinaryOperators[kBinaryOperatorEqual],
- /* binary_not_equal */ kBinaryOperators[kBinaryOperatorNotEqual],
- /* binary_less_than */ kBinaryOperators[kBinaryOperatorLessThan],
- /* binary_greater_than */ kBinaryOperators[kBinaryOperatorGreaterThan],
- /* binary_less_than_equal */ kBinaryOperators[kBinaryOperatorLessThanEqual],
- /* binary_greater_than_equal */ kBinaryOperators[kBinaryOperatorGreaterThanEqual],
- /* binary_shift_left */ kBinaryOperators[kBinaryOperatorShiftLeft],
- /* binary_shift_right */ kBinaryOperators[kBinaryOperatorShiftRight],
- /* unary_not */ kUnaryOperators[kUnaryOperatorNot],
- /* unary_complement */ kUnaryOperators[kUnaryOperatorComplement],
- /* unary_minus */ kUnaryOperators[kUnaryOperatorMinus],
- };
- return data;
-}
+const core::intrinsic::TableData kIntrinsicData{
+ /* type_matchers */ kTypeMatchers,
+ /* number_matchers */ kNumberMatchers,
+ /* ctor_conv */ kConstructorsAndConverters,
+ /* builtins */ kBuiltins,
+ /* binary_plus */ kBinaryOperators[kBinaryOperatorPlus],
+ /* binary_minus */ kBinaryOperators[kBinaryOperatorMinus],
+ /* binary_star */ kBinaryOperators[kBinaryOperatorStar],
+ /* binary_divide */ kBinaryOperators[kBinaryOperatorDivide],
+ /* binary_modulo */ kBinaryOperators[kBinaryOperatorModulo],
+ /* binary_xor */ kBinaryOperators[kBinaryOperatorXor],
+ /* binary_and */ kBinaryOperators[kBinaryOperatorAnd],
+ /* binary_or */ kBinaryOperators[kBinaryOperatorOr],
+ /* binary_logical_and */ kBinaryOperators[kBinaryOperatorLogicalAnd],
+ /* binary_logical_or */ kBinaryOperators[kBinaryOperatorLogicalOr],
+ /* binary_equal */ kBinaryOperators[kBinaryOperatorEqual],
+ /* binary_not_equal */ kBinaryOperators[kBinaryOperatorNotEqual],
+ /* binary_less_than */ kBinaryOperators[kBinaryOperatorLessThan],
+ /* binary_greater_than */ kBinaryOperators[kBinaryOperatorGreaterThan],
+ /* binary_less_than_equal */ kBinaryOperators[kBinaryOperatorLessThanEqual],
+ /* binary_greater_than_equal */ kBinaryOperators[kBinaryOperatorGreaterThanEqual],
+ /* binary_shift_left */ kBinaryOperators[kBinaryOperatorShiftLeft],
+ /* binary_shift_right */ kBinaryOperators[kBinaryOperatorShiftRight],
+ /* unary_not */ kUnaryOperators[kUnaryOperatorNot],
+ /* unary_complement */ kUnaryOperators[kUnaryOperatorComplement],
+ /* unary_minus */ kUnaryOperators[kUnaryOperatorMinus],
+};
-} // namespace tint::core::intrinsic
+} // namespace tint::core
diff --git a/src/tint/lang/core/intrinsic/core_table_data.cc.tmpl b/src/tint/lang/core/intrinsic_data.cc.tmpl
similarity index 77%
rename from src/tint/lang/core/intrinsic/core_table_data.cc.tmpl
rename to src/tint/lang/core/intrinsic_data.cc.tmpl
index e0b096b..25d601d 100644
--- a/src/tint/lang/core/intrinsic/core_table_data.cc.tmpl
+++ b/src/tint/lang/core/intrinsic_data.cc.tmpl
@@ -19,8 +19,8 @@
#include <limits>
#include <string>
-#include "src/tint/lang/core/intrinsic/core_table_data.h"
-#include "src/tint/lang/core/intrinsic/core_type_matchers.h"
+#include "src/tint/lang/core/intrinsic_data.h"
+#include "src/tint/lang/core/intrinsic_type_matchers.h"
#include "src/tint/utils/text/string_stream.h"
-{{ Eval "Data" "Intrinsics" $I "Namespace" "tint::core::intrinsic" "Name" "CoreTableData" -}}
+{{ Eval "Data" "Intrinsics" $I "Namespace" "tint::core" "Name" "kIntrinsicData" -}}
diff --git a/src/tint/lang/core/intrinsic/core_table_data.h b/src/tint/lang/core/intrinsic_data.h
similarity index 69%
rename from src/tint/lang/core/intrinsic/core_table_data.h
rename to src/tint/lang/core/intrinsic_data.h
index a9a7bd1..7275126 100644
--- a/src/tint/lang/core/intrinsic/core_table_data.h
+++ b/src/tint/lang/core/intrinsic_data.h
@@ -12,15 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef SRC_TINT_LANG_CORE_INTRINSIC_CORE_TABLE_DATA_H_
-#define SRC_TINT_LANG_CORE_INTRINSIC_CORE_TABLE_DATA_H_
+#ifndef SRC_TINT_LANG_CORE_INTRINSIC_DATA_H_
+#define SRC_TINT_LANG_CORE_INTRINSIC_DATA_H_
#include "src/tint/lang/core/intrinsic/table_data.h"
-namespace tint::core::intrinsic {
+namespace tint::core {
-const TableData& CoreTableData();
+extern const intrinsic::TableData kIntrinsicData;
-} // namespace tint::core::intrinsic
+} // namespace tint::core
-#endif // SRC_TINT_LANG_CORE_INTRINSIC_CORE_TABLE_DATA_H_
+#endif // SRC_TINT_LANG_CORE_INTRINSIC_DATA_H_
diff --git a/src/tint/lang/core/intrinsic_type_matchers.h b/src/tint/lang/core/intrinsic_type_matchers.h
new file mode 100644
index 0000000..3319b6c
--- /dev/null
+++ b/src/tint/lang/core/intrinsic_type_matchers.h
@@ -0,0 +1,594 @@
+// Copyright 2023 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.
+
+#ifndef SRC_TINT_LANG_CORE_INTRINSIC_TYPE_MATCHERS_H_
+#define SRC_TINT_LANG_CORE_INTRINSIC_TYPE_MATCHERS_H_
+
+#include "src/tint/lang/core/evaluation_stage.h"
+#include "src/tint/lang/core/intrinsic/table_data.h"
+#include "src/tint/lang/core/type/abstract_float.h"
+#include "src/tint/lang/core/type/abstract_int.h"
+#include "src/tint/lang/core/type/abstract_numeric.h"
+#include "src/tint/lang/core/type/array.h"
+#include "src/tint/lang/core/type/atomic.h"
+#include "src/tint/lang/core/type/bool.h"
+#include "src/tint/lang/core/type/builtin_structs.h"
+#include "src/tint/lang/core/type/depth_multisampled_texture.h"
+#include "src/tint/lang/core/type/depth_texture.h"
+#include "src/tint/lang/core/type/external_texture.h"
+#include "src/tint/lang/core/type/f16.h"
+#include "src/tint/lang/core/type/f32.h"
+#include "src/tint/lang/core/type/i32.h"
+#include "src/tint/lang/core/type/manager.h"
+#include "src/tint/lang/core/type/matrix.h"
+#include "src/tint/lang/core/type/multisampled_texture.h"
+#include "src/tint/lang/core/type/pointer.h"
+#include "src/tint/lang/core/type/sampled_texture.h"
+#include "src/tint/lang/core/type/storage_texture.h"
+#include "src/tint/lang/core/type/texture_dimension.h"
+#include "src/tint/lang/core/type/u32.h"
+#include "src/tint/lang/core/type/vector.h"
+
+namespace tint::core {
+
+inline bool match_bool(intrinsic::TableData::MatchState&, const type::Type* ty) {
+ return ty->IsAnyOf<intrinsic::TableData::Any, type::Bool>();
+}
+
+inline const type::AbstractFloat* build_fa(intrinsic::TableData::MatchState& state) {
+ return state.types.AFloat();
+}
+
+inline bool match_fa(intrinsic::TableData::MatchState& state, const type::Type* ty) {
+ return (state.earliest_eval_stage <= EvaluationStage::kConstant) &&
+ ty->IsAnyOf<intrinsic::TableData::Any, type::AbstractNumeric>();
+}
+
+inline const type::AbstractInt* build_ia(intrinsic::TableData::MatchState& state) {
+ return state.types.AInt();
+}
+
+inline bool match_ia(intrinsic::TableData::MatchState& state, const type::Type* ty) {
+ return (state.earliest_eval_stage <= EvaluationStage::kConstant) &&
+ ty->IsAnyOf<intrinsic::TableData::Any, type::AbstractInt>();
+}
+
+inline const type::Bool* build_bool(intrinsic::TableData::MatchState& state) {
+ return state.types.bool_();
+}
+
+inline const type::F16* build_f16(intrinsic::TableData::MatchState& state) {
+ return state.types.f16();
+}
+
+inline bool match_f16(intrinsic::TableData::MatchState&, const type::Type* ty) {
+ return ty->IsAnyOf<intrinsic::TableData::Any, type::F16, type::AbstractNumeric>();
+}
+
+inline const type::F32* build_f32(intrinsic::TableData::MatchState& state) {
+ return state.types.f32();
+}
+
+inline bool match_f32(intrinsic::TableData::MatchState&, const type::Type* ty) {
+ return ty->IsAnyOf<intrinsic::TableData::Any, type::F32, type::AbstractNumeric>();
+}
+
+inline const type::I32* build_i32(intrinsic::TableData::MatchState& state) {
+ return state.types.i32();
+}
+
+inline bool match_i32(intrinsic::TableData::MatchState&, const type::Type* ty) {
+ return ty->IsAnyOf<intrinsic::TableData::Any, type::I32, type::AbstractInt>();
+}
+
+inline const type::U32* build_u32(intrinsic::TableData::MatchState& state) {
+ return state.types.u32();
+}
+
+inline bool match_u32(intrinsic::TableData::MatchState&, const type::Type* ty) {
+ return ty->IsAnyOf<intrinsic::TableData::Any, type::U32, type::AbstractInt>();
+}
+
+inline bool match_vec(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ intrinsic::TableData::Number& N,
+ const type::Type*& T) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ N = intrinsic::TableData::Number::any;
+ T = ty;
+ return true;
+ }
+
+ if (auto* v = ty->As<type::Vector>()) {
+ N = v->Width();
+ T = v->type();
+ return true;
+ }
+ return false;
+}
+
+template <uint32_t N>
+inline bool match_vec(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ const type::Type*& T) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ T = ty;
+ return true;
+ }
+
+ if (auto* v = ty->As<type::Vector>()) {
+ if (v->Width() == N) {
+ T = v->type();
+ return true;
+ }
+ }
+ return false;
+}
+
+inline const type::Vector* build_vec(intrinsic::TableData::MatchState& state,
+ intrinsic::TableData::Number N,
+ const type::Type* el) {
+ return state.types.vec(el, N.Value());
+}
+
+template <uint32_t N>
+inline const type::Vector* build_vec(intrinsic::TableData::MatchState& state,
+ const type::Type* el) {
+ return state.types.vec(el, N);
+}
+
+constexpr auto match_vec2 = match_vec<2>;
+constexpr auto match_vec3 = match_vec<3>;
+constexpr auto match_vec4 = match_vec<4>;
+
+constexpr auto build_vec2 = build_vec<2>;
+constexpr auto build_vec3 = build_vec<3>;
+constexpr auto build_vec4 = build_vec<4>;
+
+inline bool match_packedVec3(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ const type::Type*& T) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ T = ty;
+ return true;
+ }
+
+ if (auto* v = ty->As<type::Vector>()) {
+ if (v->Packed()) {
+ T = v->type();
+ return true;
+ }
+ }
+ return false;
+}
+
+inline const type::Vector* build_packedVec3(intrinsic::TableData::MatchState& state,
+ const type::Type* el) {
+ return state.types.Get<type::Vector>(el, 3u, /* packed */ true);
+}
+
+inline bool match_mat(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ intrinsic::TableData::Number& M,
+ intrinsic::TableData::Number& N,
+ const type::Type*& T) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ M = intrinsic::TableData::Number::any;
+ N = intrinsic::TableData::Number::any;
+ T = ty;
+ return true;
+ }
+ if (auto* m = ty->As<type::Matrix>()) {
+ M = m->columns();
+ N = m->ColumnType()->Width();
+ T = m->type();
+ return true;
+ }
+ return false;
+}
+
+template <uint32_t C, uint32_t R>
+inline bool match_mat(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ const type::Type*& T) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ T = ty;
+ return true;
+ }
+ if (auto* m = ty->As<type::Matrix>()) {
+ if (m->columns() == C && m->rows() == R) {
+ T = m->type();
+ return true;
+ }
+ }
+ return false;
+}
+
+inline const type::Matrix* build_mat(intrinsic::TableData::MatchState& state,
+ intrinsic::TableData::Number C,
+ intrinsic::TableData::Number R,
+ const type::Type* T) {
+ auto* column_type = state.types.vec(T, R.Value());
+ return state.types.mat(column_type, C.Value());
+}
+
+template <uint32_t C, uint32_t R>
+inline const type::Matrix* build_mat(intrinsic::TableData::MatchState& state, const type::Type* T) {
+ auto* column_type = state.types.vec(T, R);
+ return state.types.mat(column_type, C);
+}
+
+constexpr auto build_mat2x2 = build_mat<2, 2>;
+constexpr auto build_mat2x3 = build_mat<2, 3>;
+constexpr auto build_mat2x4 = build_mat<2, 4>;
+constexpr auto build_mat3x2 = build_mat<3, 2>;
+constexpr auto build_mat3x3 = build_mat<3, 3>;
+constexpr auto build_mat3x4 = build_mat<3, 4>;
+constexpr auto build_mat4x2 = build_mat<4, 2>;
+constexpr auto build_mat4x3 = build_mat<4, 3>;
+constexpr auto build_mat4x4 = build_mat<4, 4>;
+
+constexpr auto match_mat2x2 = match_mat<2, 2>;
+constexpr auto match_mat2x3 = match_mat<2, 3>;
+constexpr auto match_mat2x4 = match_mat<2, 4>;
+constexpr auto match_mat3x2 = match_mat<3, 2>;
+constexpr auto match_mat3x3 = match_mat<3, 3>;
+constexpr auto match_mat3x4 = match_mat<3, 4>;
+constexpr auto match_mat4x2 = match_mat<4, 2>;
+constexpr auto match_mat4x3 = match_mat<4, 3>;
+constexpr auto match_mat4x4 = match_mat<4, 4>;
+
+inline bool match_array(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ const type::Type*& T) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ T = ty;
+ return true;
+ }
+
+ if (auto* a = ty->As<type::Array>()) {
+ if (a->Count()->Is<type::RuntimeArrayCount>()) {
+ T = a->ElemType();
+ return true;
+ }
+ }
+ return false;
+}
+
+inline const type::Array* build_array(intrinsic::TableData::MatchState& state,
+ const type::Type* el) {
+ return state.types.Get<type::Array>(el,
+ /* count */ state.types.Get<type::RuntimeArrayCount>(),
+ /* align */ 0u,
+ /* size */ 0u,
+ /* stride */ 0u,
+ /* stride_implicit */ 0u);
+}
+
+inline bool match_ptr(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ intrinsic::TableData::Number& S,
+ const type::Type*& T,
+ intrinsic::TableData::Number& A) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ S = intrinsic::TableData::Number::any;
+ T = ty;
+ A = intrinsic::TableData::Number::any;
+ return true;
+ }
+
+ if (auto* p = ty->As<type::Pointer>()) {
+ S = intrinsic::TableData::Number(static_cast<uint32_t>(p->AddressSpace()));
+ T = p->StoreType();
+ A = intrinsic::TableData::Number(static_cast<uint32_t>(p->Access()));
+ return true;
+ }
+ return false;
+}
+
+inline const type::Pointer* build_ptr(intrinsic::TableData::MatchState& state,
+ intrinsic::TableData::Number S,
+ const type::Type* T,
+ intrinsic::TableData::Number& A) {
+ return state.types.ptr(static_cast<core::AddressSpace>(S.Value()), T,
+ static_cast<core::Access>(A.Value()));
+}
+
+inline bool match_atomic(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ const type::Type*& T) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ T = ty;
+ return true;
+ }
+
+ if (auto* a = ty->As<type::Atomic>()) {
+ T = a->Type();
+ return true;
+ }
+ return false;
+}
+
+inline const type::Atomic* build_atomic(intrinsic::TableData::MatchState& state,
+ const type::Type* T) {
+ return state.types.atomic(T);
+}
+
+inline bool match_sampler(intrinsic::TableData::MatchState&, const type::Type* ty) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ return true;
+ }
+ return ty->Is([](const type::Sampler* s) { return s->kind() == type::SamplerKind::kSampler; });
+}
+
+inline const type::Sampler* build_sampler(intrinsic::TableData::MatchState& state) {
+ return state.types.sampler();
+}
+
+inline bool match_sampler_comparison(intrinsic::TableData::MatchState&, const type::Type* ty) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ return true;
+ }
+ return ty->Is(
+ [](const type::Sampler* s) { return s->kind() == type::SamplerKind::kComparisonSampler; });
+}
+
+inline const type::Sampler* build_sampler_comparison(intrinsic::TableData::MatchState& state) {
+ return state.types.comparison_sampler();
+}
+
+inline bool match_texture(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ type::TextureDimension dim,
+ const type::Type*& T) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ T = ty;
+ return true;
+ }
+ if (auto* v = ty->As<type::SampledTexture>()) {
+ if (v->dim() == dim) {
+ T = v->type();
+ return true;
+ }
+ }
+ return false;
+}
+
+#define JOIN(a, b) a##b
+
+#define DECLARE_SAMPLED_TEXTURE(suffix, dim) \
+ inline bool JOIN(match_texture_, suffix)(intrinsic::TableData::MatchState & state, \
+ const type::Type* ty, const type::Type*& T) { \
+ return match_texture(state, ty, dim, T); \
+ } \
+ inline const type::SampledTexture* JOIN(build_texture_, suffix)( \
+ intrinsic::TableData::MatchState & state, const type::Type* T) { \
+ return state.types.Get<type::SampledTexture>(dim, T); \
+ }
+
+DECLARE_SAMPLED_TEXTURE(1d, type::TextureDimension::k1d)
+DECLARE_SAMPLED_TEXTURE(2d, type::TextureDimension::k2d)
+DECLARE_SAMPLED_TEXTURE(2d_array, type::TextureDimension::k2dArray)
+DECLARE_SAMPLED_TEXTURE(3d, type::TextureDimension::k3d)
+DECLARE_SAMPLED_TEXTURE(cube, type::TextureDimension::kCube)
+DECLARE_SAMPLED_TEXTURE(cube_array, type::TextureDimension::kCubeArray)
+#undef DECLARE_SAMPLED_TEXTURE
+
+inline bool match_texture_multisampled(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ type::TextureDimension dim,
+ const type::Type*& T) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ T = ty;
+ return true;
+ }
+ if (auto* v = ty->As<type::MultisampledTexture>()) {
+ if (v->dim() == dim) {
+ T = v->type();
+ return true;
+ }
+ }
+ return false;
+}
+
+#define DECLARE_MULTISAMPLED_TEXTURE(suffix, dim) \
+ inline bool JOIN(match_texture_multisampled_, suffix)( \
+ intrinsic::TableData::MatchState & state, const type::Type* ty, const type::Type*& T) { \
+ return match_texture_multisampled(state, ty, dim, T); \
+ } \
+ inline const type::MultisampledTexture* JOIN(build_texture_multisampled_, suffix)( \
+ intrinsic::TableData::MatchState & state, const type::Type* T) { \
+ return state.types.Get<type::MultisampledTexture>(dim, T); \
+ }
+
+DECLARE_MULTISAMPLED_TEXTURE(2d, type::TextureDimension::k2d)
+#undef DECLARE_MULTISAMPLED_TEXTURE
+
+inline bool match_texture_depth(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ type::TextureDimension dim) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ return true;
+ }
+ return ty->Is([&](const type::DepthTexture* t) { return t->dim() == dim; });
+}
+
+#define DECLARE_DEPTH_TEXTURE(suffix, dim) \
+ inline bool JOIN(match_texture_depth_, suffix)(intrinsic::TableData::MatchState & state, \
+ const type::Type* ty) { \
+ return match_texture_depth(state, ty, dim); \
+ } \
+ inline const type::DepthTexture* JOIN(build_texture_depth_, \
+ suffix)(intrinsic::TableData::MatchState & state) { \
+ return state.types.Get<type::DepthTexture>(dim); \
+ }
+
+DECLARE_DEPTH_TEXTURE(2d, type::TextureDimension::k2d)
+DECLARE_DEPTH_TEXTURE(2d_array, type::TextureDimension::k2dArray)
+DECLARE_DEPTH_TEXTURE(cube, type::TextureDimension::kCube)
+DECLARE_DEPTH_TEXTURE(cube_array, type::TextureDimension::kCubeArray)
+#undef DECLARE_DEPTH_TEXTURE
+
+inline bool match_texture_depth_multisampled_2d(intrinsic::TableData::MatchState&,
+ const type::Type* ty) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ return true;
+ }
+ return ty->Is([&](const type::DepthMultisampledTexture* t) {
+ return t->dim() == type::TextureDimension::k2d;
+ });
+}
+
+inline type::DepthMultisampledTexture* build_texture_depth_multisampled_2d(
+ intrinsic::TableData::MatchState& state) {
+ return state.types.Get<type::DepthMultisampledTexture>(type::TextureDimension::k2d);
+}
+
+inline bool match_texture_storage(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ type::TextureDimension dim,
+ intrinsic::TableData::Number& F,
+ intrinsic::TableData::Number& A) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ F = intrinsic::TableData::Number::any;
+ A = intrinsic::TableData::Number::any;
+ return true;
+ }
+ if (auto* v = ty->As<type::StorageTexture>()) {
+ if (v->dim() == dim) {
+ F = intrinsic::TableData::Number(static_cast<uint32_t>(v->texel_format()));
+ A = intrinsic::TableData::Number(static_cast<uint32_t>(v->access()));
+ return true;
+ }
+ }
+ return false;
+}
+
+#define DECLARE_STORAGE_TEXTURE(suffix, dim) \
+ inline bool JOIN(match_texture_storage_, suffix)( \
+ intrinsic::TableData::MatchState & state, const type::Type* ty, \
+ intrinsic::TableData::Number& F, intrinsic::TableData::Number& A) { \
+ return match_texture_storage(state, ty, dim, F, A); \
+ } \
+ inline const type::StorageTexture* JOIN(build_texture_storage_, suffix)( \
+ intrinsic::TableData::MatchState & state, intrinsic::TableData::Number F, \
+ intrinsic::TableData::Number A) { \
+ auto format = static_cast<TexelFormat>(F.Value()); \
+ auto access = static_cast<Access>(A.Value()); \
+ auto* T = type::StorageTexture::SubtypeFor(format, state.types); \
+ return state.types.Get<type::StorageTexture>(dim, format, access, T); \
+ }
+
+DECLARE_STORAGE_TEXTURE(1d, type::TextureDimension::k1d)
+DECLARE_STORAGE_TEXTURE(2d, type::TextureDimension::k2d)
+DECLARE_STORAGE_TEXTURE(2d_array, type::TextureDimension::k2dArray)
+DECLARE_STORAGE_TEXTURE(3d, type::TextureDimension::k3d)
+#undef DECLARE_STORAGE_TEXTURE
+
+inline bool match_texture_external(intrinsic::TableData::MatchState&, const type::Type* ty) {
+ return ty->IsAnyOf<intrinsic::TableData::Any, type::ExternalTexture>();
+}
+
+inline const type::ExternalTexture* build_texture_external(
+ intrinsic::TableData::MatchState& state) {
+ return state.types.Get<type::ExternalTexture>();
+}
+
+// Builtin types starting with a _ prefix cannot be declared in WGSL, so they
+// can only be used as return types. Because of this, they must only match Any,
+// which is used as the return type matcher.
+inline bool match_modf_result(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ const type::Type*& T) {
+ if (!ty->Is<intrinsic::TableData::Any>()) {
+ return false;
+ }
+ T = ty;
+ return true;
+}
+inline bool match_modf_result_vec(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ intrinsic::TableData::Number& N,
+ const type::Type*& T) {
+ if (!ty->Is<intrinsic::TableData::Any>()) {
+ return false;
+ }
+ N = intrinsic::TableData::Number::any;
+ T = ty;
+ return true;
+}
+inline bool match_frexp_result(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ const type::Type*& T) {
+ if (!ty->Is<intrinsic::TableData::Any>()) {
+ return false;
+ }
+ T = ty;
+ return true;
+}
+inline bool match_frexp_result_vec(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ intrinsic::TableData::Number& N,
+ const type::Type*& T) {
+ if (!ty->Is<intrinsic::TableData::Any>()) {
+ return false;
+ }
+ N = intrinsic::TableData::Number::any;
+ T = ty;
+ return true;
+}
+
+inline bool match_atomic_compare_exchange_result(intrinsic::TableData::MatchState&,
+ const type::Type* ty,
+ const type::Type*& T) {
+ if (ty->Is<intrinsic::TableData::Any>()) {
+ T = ty;
+ return true;
+ }
+ return false;
+}
+
+inline const type::Struct* build_modf_result(intrinsic::TableData::MatchState& state,
+ const type::Type* el) {
+ return type::CreateModfResult(state.types, state.symbols, el);
+}
+
+inline const type::Struct* build_modf_result_vec(intrinsic::TableData::MatchState& state,
+ intrinsic::TableData::Number& n,
+ const type::Type* el) {
+ auto* vec = state.types.vec(el, n.Value());
+ return type::CreateModfResult(state.types, state.symbols, vec);
+}
+
+inline const type::Struct* build_frexp_result(intrinsic::TableData::MatchState& state,
+ const type::Type* el) {
+ return type::CreateFrexpResult(state.types, state.symbols, el);
+}
+
+inline const type::Struct* build_frexp_result_vec(intrinsic::TableData::MatchState& state,
+ intrinsic::TableData::Number& n,
+ const type::Type* el) {
+ auto* vec = state.types.vec(el, n.Value());
+ return type::CreateFrexpResult(state.types, state.symbols, vec);
+}
+
+inline const type::Struct* build_atomic_compare_exchange_result(
+ intrinsic::TableData::MatchState& state,
+ const type::Type* ty) {
+ return type::CreateAtomicCompareExchangeResult(state.types, state.symbols, ty);
+}
+
+} // namespace tint::core
+
+#endif // SRC_TINT_LANG_CORE_INTRINSIC_TYPE_MATCHERS_H_
diff --git a/src/tint/lang/wgsl/resolver/builtin_test.cc b/src/tint/lang/wgsl/resolver/builtin_test.cc
index d9c0a96..52ee20f 100644
--- a/src/tint/lang/wgsl/resolver/builtin_test.cc
+++ b/src/tint/lang/wgsl/resolver/builtin_test.cc
@@ -73,6 +73,26 @@
R"(12:34 error: const initializer requires a const-expression, but expression is a runtime-expression)");
}
+TEST_F(ResolverBuiltinTest, SameOverloadReturnsSameCallTarget) {
+ // let i = 42i;
+ // let a = select(1_i, 2_i, true);
+ // let b = select(3_i, 4_i, false);
+ // let c = select(5_u, 6_u, true);
+ auto* select_a = Call(core::Function::kSelect, 1_i, 2_i, true);
+ auto* select_b = Call(core::Function::kSelect, 3_i, 4_i, false);
+ auto* select_c = Call(core::Function::kSelect, 5_u, 6_u, true);
+ WrapInFunction(Decl(Let("i", Expr(42_i))), //
+ Decl(Let("a", select_a)), //
+ Decl(Let("b", select_b)), //
+ Decl(Let("c", select_c)));
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+ EXPECT_EQ(Sem().Get<sem::Call>(select_a)->Target(), Sem().Get<sem::Call>(select_b)->Target());
+ EXPECT_NE(Sem().Get<sem::Call>(select_a)->Target(), Sem().Get<sem::Call>(select_c)->Target());
+ EXPECT_NE(Sem().Get<sem::Call>(select_b)->Target(), Sem().Get<sem::Call>(select_c)->Target());
+}
+
// Tests for Logical builtins
namespace logical_builtin_tests {
diff --git a/src/tint/lang/wgsl/resolver/resolver.cc b/src/tint/lang/wgsl/resolver/resolver.cc
index 2badb72..ab58d14 100644
--- a/src/tint/lang/wgsl/resolver/resolver.cc
+++ b/src/tint/lang/wgsl/resolver/resolver.cc
@@ -22,6 +22,7 @@
#include "src/tint/lang/core/builtin.h"
#include "src/tint/lang/core/constant/scalar.h"
+#include "src/tint/lang/core/intrinsic_data.h"
#include "src/tint/lang/core/type/abstract_float.h"
#include "src/tint/lang/core/type/abstract_int.h"
#include "src/tint/lang/core/type/array.h"
@@ -101,6 +102,7 @@
namespace {
using CtorConvIntrinsic = core::intrinsic::CtorConv;
+using OverloadFlag = core::intrinsic::TableData::OverloadFlag;
constexpr int64_t kMaxArrayElementCount = 65536;
constexpr uint32_t kMaxStatementDepth = 127;
@@ -112,7 +114,10 @@
: builder_(builder),
diagnostics_(builder->Diagnostics()),
const_eval_(builder->constants, diagnostics_),
- intrinsic_table_(core::intrinsic::Table::Create(*builder)),
+ intrinsic_table_(core::intrinsic::Table::Create(core::kIntrinsicData,
+ builder->Types(),
+ builder->Symbols(),
+ builder->Diagnostics())),
sem_(builder),
validator_(builder,
sem_,
@@ -2061,32 +2066,62 @@
// sem::ValueConversion call for a CtorConvIntrinsic with an optional template argument type.
auto ctor_or_conv = [&](CtorConvIntrinsic ty, const type::Type* template_arg) -> sem::Call* {
auto arg_tys = tint::Transform(args, [](auto* arg) { return arg->Type(); });
- auto entry = intrinsic_table_->Lookup(ty, template_arg, arg_tys, args_stage, expr->source);
- if (!entry.target) {
+ auto match = intrinsic_table_->Lookup(ty, template_arg, arg_tys, args_stage, expr->source);
+ if (!match) {
return nullptr;
}
- if (!MaybeMaterializeAndLoadArguments(args, entry.target)) {
+
+ auto overload_stage = match->info->const_eval_fn ? core::EvaluationStage::kConstant
+ : core::EvaluationStage::kRuntime;
+
+ sem::CallTarget* target_sem = nullptr;
+
+ // Is this overload a constructor or conversion?
+ if (match->info->flags.Contains(OverloadFlag::kIsConstructor)) {
+ // Type constructor
+ auto params = Transform(match->parameters, [&](auto& p, size_t i) {
+ return builder_->create<sem::Parameter>(nullptr, static_cast<uint32_t>(i), p.type,
+ core::AddressSpace::kUndefined,
+ core::Access::kUndefined, p.usage);
+ });
+ target_sem = constructors_.GetOrCreate(match.Get(), [&] {
+ return builder_->create<sem::ValueConstructor>(match->return_type,
+ std::move(params), overload_stage);
+ });
+ } else {
+ // Type conversion
+ target_sem = converters_.GetOrCreate(match.Get(), [&] {
+ auto param = builder_->create<sem::Parameter>(
+ nullptr, 0u, match->parameters[0].type, core::AddressSpace::kUndefined,
+ core::Access::kUndefined, match->parameters[0].usage);
+ return builder_->create<sem::ValueConversion>(match->return_type, param,
+ overload_stage);
+ });
+ }
+
+ if (!MaybeMaterializeAndLoadArguments(args, target_sem)) {
return nullptr;
}
const core::constant::Value* value = nullptr;
- auto stage = core::EarliestStage(entry.target->Stage(), args_stage);
+ auto stage = core::EarliestStage(overload_stage, args_stage);
if (stage == core::EvaluationStage::kConstant && skip_const_eval_.Contains(expr)) {
stage = core::EvaluationStage::kNotEvaluated;
}
if (stage == core::EvaluationStage::kConstant) {
- auto const_args = ConvertArguments(args, entry.target);
+ auto const_args = ConvertArguments(args, target_sem);
if (!const_args) {
return nullptr;
}
- if (auto r = (const_eval_.*entry.const_eval_fn)(entry.target->ReturnType(),
- const_args.Get(), expr->source)) {
+ auto const_eval_fn = match->info->const_eval_fn;
+ if (auto r = (const_eval_.*const_eval_fn)(target_sem->ReturnType(), const_args.Get(),
+ expr->source)) {
value = r.Get();
} else {
return nullptr;
}
}
- return builder_->create<sem::Call>(expr, entry.target, stage, std::move(args),
+ return builder_->create<sem::Call>(expr, target_sem, stage, std::move(args),
current_statement_, value, has_side_effects);
};
@@ -2345,53 +2380,75 @@
template <size_t N>
sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
- core::Function builtin_type,
+ core::Function fn,
Vector<const sem::ValueExpression*, N>& args) {
auto arg_stage = core::EvaluationStage::kConstant;
for (auto* arg : args) {
arg_stage = core::EarliestStage(arg_stage, arg->Stage());
}
- core::intrinsic::Table::Builtin builtin;
- {
- auto arg_tys = tint::Transform(args, [](auto* arg) { return arg->Type(); });
- builtin = intrinsic_table_->Lookup(builtin_type, arg_tys, arg_stage, expr->source);
- if (!builtin.sem) {
- return nullptr;
- }
+ auto arg_tys = tint::Transform(args, [](auto* arg) { return arg->Type(); });
+ auto overload = intrinsic_table_->Lookup(fn, arg_tys, arg_stage, expr->source);
+ if (!overload) {
+ return nullptr;
}
- if (builtin_type == core::Function::kTintMaterialize) {
+ // De-duplicate builtins that are identical.
+ auto* target = builtins_.GetOrCreate(std::make_pair(overload.Get(), fn), [&] {
+ auto params = Transform(overload->parameters, [&](auto& p, size_t i) {
+ return builder_->create<sem::Parameter>(nullptr, static_cast<uint32_t>(i), p.type,
+ core::AddressSpace::kUndefined,
+ core::Access::kUndefined, p.usage);
+ });
+ sem::PipelineStageSet supported_stages;
+ auto flags = overload->info->flags;
+ if (flags.Contains(OverloadFlag::kSupportsVertexPipeline)) {
+ supported_stages.Add(ast::PipelineStage::kVertex);
+ }
+ if (flags.Contains(OverloadFlag::kSupportsFragmentPipeline)) {
+ supported_stages.Add(ast::PipelineStage::kFragment);
+ }
+ if (flags.Contains(OverloadFlag::kSupportsComputePipeline)) {
+ supported_stages.Add(ast::PipelineStage::kCompute);
+ }
+ auto eval_stage = overload->info->const_eval_fn ? core::EvaluationStage::kConstant
+ : core::EvaluationStage::kRuntime;
+ return builder_->create<sem::Builtin>(
+ fn, overload->return_type, std::move(params), eval_stage, supported_stages,
+ flags.Contains(OverloadFlag::kIsDeprecated), flags.Contains(OverloadFlag::kMustUse));
+ });
+
+ if (fn == core::Function::kTintMaterialize) {
args[0] = Materialize(args[0]);
if (!args[0]) {
return nullptr;
}
} else {
// Materialize arguments if the parameter type is not abstract
- if (!MaybeMaterializeAndLoadArguments(args, builtin.sem)) {
+ if (!MaybeMaterializeAndLoadArguments(args, target)) {
return nullptr;
}
}
- if (builtin.sem->IsDeprecated()) {
+ if (target->IsDeprecated()) {
AddWarning("use of deprecated builtin", expr->source);
}
// If the builtin is @const, and all arguments have constant values, evaluate the builtin
// now.
const core::constant::Value* value = nullptr;
- auto stage = core::EarliestStage(arg_stage, builtin.sem->Stage());
+ auto stage = core::EarliestStage(arg_stage, target->Stage());
if (stage == core::EvaluationStage::kConstant && skip_const_eval_.Contains(expr)) {
stage = core::EvaluationStage::kNotEvaluated;
}
if (stage == core::EvaluationStage::kConstant) {
- auto const_args = ConvertArguments(args, builtin.sem);
+ auto const_args = ConvertArguments(args, target);
if (!const_args) {
return nullptr;
}
-
- if (auto r = (const_eval_.*builtin.const_eval_fn)(builtin.sem->ReturnType(),
- const_args.Get(), expr->source)) {
+ auto const_eval_fn = overload->info->const_eval_fn;
+ if (auto r = (const_eval_.*const_eval_fn)(target->ReturnType(), const_args.Get(),
+ expr->source)) {
value = r.Get();
} else {
return nullptr;
@@ -2399,13 +2456,13 @@
}
bool has_side_effects =
- builtin.sem->HasSideEffects() ||
+ target->HasSideEffects() ||
std::any_of(args.begin(), args.end(), [](auto* e) { return e->HasSideEffects(); });
- auto* call = builder_->create<sem::Call>(expr, builtin.sem, stage, std::move(args),
+ auto* call = builder_->create<sem::Call>(expr, target, stage, std::move(args),
current_statement_, value, has_side_effects);
if (current_function_) {
- current_function_->AddDirectlyCalledBuiltin(builtin.sem);
+ current_function_->AddDirectlyCalledBuiltin(target);
current_function_->AddDirectCall(call);
}
@@ -2413,14 +2470,14 @@
return nullptr;
}
- if (IsTextureBuiltin(builtin_type)) {
+ if (IsTextureBuiltin(fn)) {
if (!validator_.TextureBuiltinFunction(call)) {
return nullptr;
}
- CollectTextureSamplerPairs(builtin.sem, call->Arguments());
+ CollectTextureSamplerPairs(target, call->Arguments());
}
- if (builtin_type == core::Function::kWorkgroupUniformLoad) {
+ if (fn == core::Function::kWorkgroupUniformLoad) {
if (!validator_.WorkgroupUniformLoad(call)) {
return nullptr;
}
@@ -3458,22 +3515,26 @@
return nullptr;
}
- auto* lhs_ty = lhs->Type();
- auto* rhs_ty = rhs->Type();
-
auto stage = core::EarliestStage(lhs->Stage(), rhs->Stage());
- auto op = intrinsic_table_->Lookup(expr->op, lhs_ty, rhs_ty, stage, expr->source, false);
- if (!op.result) {
+ auto overload =
+ intrinsic_table_->Lookup(expr->op, lhs->Type(), rhs->Type(), stage, expr->source, false);
+ if (!overload) {
return nullptr;
}
- if (ShouldMaterializeArgument(op.lhs)) {
- lhs = Materialize(lhs, op.lhs);
+
+ auto* res_ty = overload->return_type;
+
+ // Parameter types
+ auto* lhs_ty = overload->parameters[0].type;
+ auto* rhs_ty = overload->parameters[1].type;
+ if (ShouldMaterializeArgument(lhs_ty)) {
+ lhs = Materialize(lhs, lhs_ty);
if (!lhs) {
return nullptr;
}
}
- if (ShouldMaterializeArgument(op.rhs)) {
- rhs = Materialize(rhs, op.rhs);
+ if (ShouldMaterializeArgument(rhs_ty)) {
+ rhs = Materialize(rhs, rhs_ty);
if (!rhs) {
return nullptr;
}
@@ -3491,18 +3552,19 @@
stage = core::EvaluationStage::kConstant;
} else if (stage == core::EvaluationStage::kConstant) {
// Both LHS and RHS have expressions that are constant evaluation stage.
- if (op.const_eval_fn) { // Do we have a @const operator?
+ auto const_eval_fn = overload->info->const_eval_fn;
+ if (const_eval_fn) { // Do we have a @const operator?
// Yes. Perform any required abstract argument values implicit conversions to the
// overload parameter types, and const-eval.
Vector const_args{lhs->ConstantValue(), rhs->ConstantValue()};
// Implicit conversion (e.g. AInt -> AFloat)
- if (!Convert(const_args[0], op.lhs, lhs->Declaration()->source)) {
+ if (!Convert(const_args[0], lhs_ty, lhs->Declaration()->source)) {
return nullptr;
}
- if (!Convert(const_args[1], op.rhs, rhs->Declaration()->source)) {
+ if (!Convert(const_args[1], rhs_ty, rhs->Declaration()->source)) {
return nullptr;
}
- if (auto r = (const_eval_.*op.const_eval_fn)(op.result, const_args, expr->source)) {
+ if (auto r = (const_eval_.*const_eval_fn)(res_ty, const_args, expr->source)) {
value = r.Get();
} else {
return nullptr;
@@ -3515,7 +3577,7 @@
}
bool has_side_effects = lhs->HasSideEffects() || rhs->HasSideEffects();
- auto* sem = builder_->create<sem::ValueExpression>(expr, op.result, stage, current_statement_,
+ auto* sem = builder_->create<sem::ValueExpression>(expr, res_ty, stage, current_statement_,
value, has_side_effects);
sem->Behaviors() = lhs->Behaviors() + rhs->Behaviors();
@@ -3575,13 +3637,14 @@
default: {
stage = expr->Stage();
- auto op = intrinsic_table_->Lookup(unary->op, expr_ty, stage, unary->source);
- if (!op.result) {
+ auto overload = intrinsic_table_->Lookup(unary->op, expr_ty, stage, unary->source);
+ if (!overload) {
return nullptr;
}
- ty = op.result;
- if (ShouldMaterializeArgument(op.parameter)) {
- expr = Materialize(expr, op.parameter);
+ ty = overload->return_type;
+ auto* param_ty = overload->parameters[0].type;
+ if (ShouldMaterializeArgument(param_ty)) {
+ expr = Materialize(expr, param_ty);
if (!expr) {
return nullptr;
}
@@ -3595,9 +3658,10 @@
stage = expr->Stage();
if (stage == core::EvaluationStage::kConstant) {
- if (op.const_eval_fn) {
- if (auto r = (const_eval_.*op.const_eval_fn)(ty, Vector{expr->ConstantValue()},
- expr->Declaration()->source)) {
+ auto const_eval_fn = overload->info->const_eval_fn;
+ if (const_eval_fn) {
+ if (auto r = (const_eval_.*const_eval_fn)(ty, Vector{expr->ConstantValue()},
+ expr->Declaration()->source)) {
value = r.Get();
} else {
return nullptr;
@@ -4599,22 +4663,22 @@
sem->Behaviors() = rhs->Behaviors() + lhs->Behaviors();
- auto* lhs_ty = lhs->Type()->UnwrapRef();
- auto* rhs_ty = rhs->Type()->UnwrapRef();
auto stage = core::EarliestStage(lhs->Stage(), rhs->Stage());
- auto op = intrinsic_table_->Lookup(stmt->op, lhs_ty, rhs_ty, stage, stmt->source, true);
- if (!op.result) {
+ auto overload =
+ intrinsic_table_->Lookup(stmt->op, lhs->Type()->UnwrapRef(), rhs->Type()->UnwrapRef(),
+ stage, stmt->source, true);
+ if (!overload) {
return false;
}
// Load or materialize the RHS if necessary.
- rhs = Load(Materialize(rhs, op.rhs));
+ rhs = Load(Materialize(rhs, overload->parameters[1].type));
if (!rhs) {
return false;
}
- return validator_.Assignment(stmt, op.result);
+ return validator_.Assignment(stmt, overload->return_type);
});
}
diff --git a/src/tint/lang/wgsl/resolver/resolver.h b/src/tint/lang/wgsl/resolver/resolver.h
index 4a56d53..fce71e5 100644
--- a/src/tint/lang/wgsl/resolver/resolver.h
+++ b/src/tint/lang/wgsl/resolver/resolver.h
@@ -67,6 +67,8 @@
class Statement;
class StructMember;
class SwitchStatement;
+class ValueConstructor;
+class ValueConversion;
class WhileStatement;
} // namespace tint::sem
namespace tint::type {
@@ -627,6 +629,10 @@
Hashset<const ast::Expression*, 8> skip_const_eval_;
IdentifierResolveHint identifier_resolve_hint_;
Hashmap<const type::Type*, size_t, 8> nest_depth_;
+ Hashmap<std::pair<core::intrinsic::Table::Overload, core::Function>, sem::Builtin*, 64>
+ builtins_;
+ Hashmap<core::intrinsic::Table::Overload, sem::ValueConstructor*, 16> constructors_;
+ Hashmap<core::intrinsic::Table::Overload, sem::ValueConversion*, 16> converters_;
};
} // namespace tint::resolver
diff --git a/src/tint/utils/containers/slice.h b/src/tint/utils/containers/slice.h
index 259ae6a..10378d9 100644
--- a/src/tint/utils/containers/slice.h
+++ b/src/tint/utils/containers/slice.h
@@ -114,10 +114,10 @@
size_t cap = 0;
/// Constructor
- Slice() = default;
+ constexpr Slice() = default;
/// Constructor
- Slice(EmptyType) {} // NOLINT
+ constexpr Slice(EmptyType) {} // NOLINT
/// Copy constructor with covariance / const conversion
/// @param other the vector to copy
@@ -132,12 +132,12 @@
/// @param d pointer to the first element in the slice
/// @param l total number of elements in the slice
/// @param c total capacity of the backing store for the slice
- Slice(T* d, size_t l, size_t c) : data(d), len(l), cap(c) {}
+ constexpr Slice(T* d, size_t l, size_t c) : data(d), len(l), cap(c) {}
/// Constructor
/// @param elements c-array of elements
template <size_t N>
- Slice(T (&elements)[N]) // NOLINT
+ constexpr Slice(T (&elements)[N]) // NOLINT
: data(elements), len(N), cap(N) {}
/// Reinterprets this slice as `const Slice<TO>&`
diff --git a/src/tint/utils/diagnostic/diagnostic.h b/src/tint/utils/diagnostic/diagnostic.h
index 0eb7727..0fb3f36 100644
--- a/src/tint/utils/diagnostic/diagnostic.h
+++ b/src/tint/utils/diagnostic/diagnostic.h
@@ -33,14 +33,14 @@
return static_cast<int>(a) >= static_cast<int>(b);
}
-/// System is an enumerator of Tint systems that can be the originator of a
-/// diagnostic message.
+/// System is an enumerator of Tint systems that can be the originator of a diagnostic message.
enum class System {
AST,
Builtin,
Clone,
Constant,
Inspector,
+ Intrinsics,
IR,
Program,
ProgramBuilder,
diff --git a/src/tint/utils/templates/intrinsic_table_data.tmpl.inc b/src/tint/utils/templates/intrinsic_table_data.tmpl.inc
index 467a871..e01c8fb 100644
--- a/src/tint/utils/templates/intrinsic_table_data.tmpl.inc
+++ b/src/tint/utils/templates/intrinsic_table_data.tmpl.inc
@@ -211,36 +211,33 @@
} // anonymous namespace
-const TableData& {{$.Name}}() {
- static const TableData data{
- /* type_matchers */ kTypeMatchers,
- /* number_matchers */ kNumberMatchers,
- /* ctor_conv */ kConstructorsAndConverters,
- /* builtins */ kBuiltins,
- /* binary_plus */ kBinaryOperators[kBinaryOperatorPlus],
- /* binary_minus */ kBinaryOperators[kBinaryOperatorMinus],
- /* binary_star */ kBinaryOperators[kBinaryOperatorStar],
- /* binary_divide */ kBinaryOperators[kBinaryOperatorDivide],
- /* binary_modulo */ kBinaryOperators[kBinaryOperatorModulo],
- /* binary_xor */ kBinaryOperators[kBinaryOperatorXor],
- /* binary_and */ kBinaryOperators[kBinaryOperatorAnd],
- /* binary_or */ kBinaryOperators[kBinaryOperatorOr],
- /* binary_logical_and */ kBinaryOperators[kBinaryOperatorLogicalAnd],
- /* binary_logical_or */ kBinaryOperators[kBinaryOperatorLogicalOr],
- /* binary_equal */ kBinaryOperators[kBinaryOperatorEqual],
- /* binary_not_equal */ kBinaryOperators[kBinaryOperatorNotEqual],
- /* binary_less_than */ kBinaryOperators[kBinaryOperatorLessThan],
- /* binary_greater_than */ kBinaryOperators[kBinaryOperatorGreaterThan],
- /* binary_less_than_equal */ kBinaryOperators[kBinaryOperatorLessThanEqual],
- /* binary_greater_than_equal */ kBinaryOperators[kBinaryOperatorGreaterThanEqual],
- /* binary_shift_left */ kBinaryOperators[kBinaryOperatorShiftLeft],
- /* binary_shift_right */ kBinaryOperators[kBinaryOperatorShiftRight],
- /* unary_not */ kUnaryOperators[kUnaryOperatorNot],
- /* unary_complement */ kUnaryOperators[kUnaryOperatorComplement],
- /* unary_minus */ kUnaryOperators[kUnaryOperatorMinus],
- };
- return data;
-}
+const core::intrinsic::TableData {{$.Name}}{
+ /* type_matchers */ kTypeMatchers,
+ /* number_matchers */ kNumberMatchers,
+ /* ctor_conv */ kConstructorsAndConverters,
+ /* builtins */ kBuiltins,
+ /* binary_plus */ kBinaryOperators[kBinaryOperatorPlus],
+ /* binary_minus */ kBinaryOperators[kBinaryOperatorMinus],
+ /* binary_star */ kBinaryOperators[kBinaryOperatorStar],
+ /* binary_divide */ kBinaryOperators[kBinaryOperatorDivide],
+ /* binary_modulo */ kBinaryOperators[kBinaryOperatorModulo],
+ /* binary_xor */ kBinaryOperators[kBinaryOperatorXor],
+ /* binary_and */ kBinaryOperators[kBinaryOperatorAnd],
+ /* binary_or */ kBinaryOperators[kBinaryOperatorOr],
+ /* binary_logical_and */ kBinaryOperators[kBinaryOperatorLogicalAnd],
+ /* binary_logical_or */ kBinaryOperators[kBinaryOperatorLogicalOr],
+ /* binary_equal */ kBinaryOperators[kBinaryOperatorEqual],
+ /* binary_not_equal */ kBinaryOperators[kBinaryOperatorNotEqual],
+ /* binary_less_than */ kBinaryOperators[kBinaryOperatorLessThan],
+ /* binary_greater_than */ kBinaryOperators[kBinaryOperatorGreaterThan],
+ /* binary_less_than_equal */ kBinaryOperators[kBinaryOperatorLessThanEqual],
+ /* binary_greater_than_equal */ kBinaryOperators[kBinaryOperatorGreaterThanEqual],
+ /* binary_shift_left */ kBinaryOperators[kBinaryOperatorShiftLeft],
+ /* binary_shift_right */ kBinaryOperators[kBinaryOperatorShiftRight],
+ /* unary_not */ kUnaryOperators[kUnaryOperatorNot],
+ /* unary_complement */ kUnaryOperators[kUnaryOperatorComplement],
+ /* unary_minus */ kUnaryOperators[kUnaryOperatorMinus],
+};
} // namespace {{$.Namespace}}
diff --git a/tools/src/cmd/git-stats/main.go b/tools/src/cmd/git-stats/main.go
index 38374de..183f2f1 100644
--- a/tools/src/cmd/git-stats/main.go
+++ b/tools/src/cmd/git-stats/main.go
@@ -62,7 +62,8 @@
"package-lock.json",
"src/tint/builtin_table.inl",
"src/tint/lang/core/intrinsic/table.inl",
- "src/tint/lang/core/intrinsic/core_table_data.cc.tmpl",
+ "src/tint/lang/core/*.cc",
+ "src/tint/lang/core/*.h",
"test/tint/",
"third_party/gn/webgpu-cts/test_list.txt",
"third_party/khronos/",