blob: 37735c2f9647d38bd9947c0334791a33ff973e75 [file] [log] [blame]
// 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"
//! @cond Doxygen_Suppress
namespace tint::core::intrinsic {
inline bool MatchBool(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::Bool>();
}
inline const type::AbstractFloat* BuildFa(intrinsic::MatchState& state, const type::Type*) {
return state.types.AFloat();
}
inline bool MatchFa(intrinsic::MatchState& state, const type::Type* ty) {
return (state.earliest_eval_stage <= EvaluationStage::kConstant) &&
ty->IsAnyOf<intrinsic::Any, type::AbstractNumeric>();
}
inline const type::AbstractInt* BuildIa(intrinsic::MatchState& state, const type::Type*) {
return state.types.AInt();
}
inline bool MatchIa(intrinsic::MatchState& state, const type::Type* ty) {
return (state.earliest_eval_stage <= EvaluationStage::kConstant) &&
ty->IsAnyOf<intrinsic::Any, type::AbstractInt>();
}
inline const type::Bool* BuildBool(intrinsic::MatchState& state, const type::Type*) {
return state.types.bool_();
}
inline const type::F16* BuildF16(intrinsic::MatchState& state, const type::Type*) {
return state.types.f16();
}
inline bool MatchF16(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::F16, type::AbstractNumeric>();
}
inline const type::F32* BuildF32(intrinsic::MatchState& state, const type::Type*) {
return state.types.f32();
}
inline bool MatchF32(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::F32, type::AbstractNumeric>();
}
inline const type::I32* BuildI32(intrinsic::MatchState& state, const type::Type*) {
return state.types.i32();
}
inline bool MatchI32(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::I32, type::AbstractInt>();
}
inline const type::U32* BuildU32(intrinsic::MatchState& state, const type::Type*) {
return state.types.u32();
}
inline bool MatchU32(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::U32, type::AbstractInt>();
}
inline bool MatchVec(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& N,
const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
N = intrinsic::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 MatchVec(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (ty->Is<intrinsic::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* BuildVec(intrinsic::MatchState& state,
const type::Type*,
intrinsic::Number N,
const type::Type* el) {
return state.types.vec(el, N.Value());
}
template <uint32_t N>
inline const type::Vector* BuildVec(intrinsic::MatchState& state,
const type::Type*,
const type::Type* el) {
return state.types.vec(el, N);
}
constexpr auto MatchVec2 = MatchVec<2>;
constexpr auto MatchVec3 = MatchVec<3>;
constexpr auto MatchVec4 = MatchVec<4>;
constexpr auto BuildVec2 = BuildVec<2>;
constexpr auto BuildVec3 = BuildVec<3>;
constexpr auto BuildVec4 = BuildVec<4>;
inline bool MatchPackedVec3(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (ty->Is<intrinsic::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* BuildPackedVec3(intrinsic::MatchState& state,
const type::Type*,
const type::Type* el) {
return state.types.Get<type::Vector>(el, 3u, /* packed */ true);
}
inline bool MatchMat(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& M,
intrinsic::Number& N,
const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
M = intrinsic::Number::any;
N = intrinsic::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 MatchMat(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (ty->Is<intrinsic::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* BuildMat(intrinsic::MatchState& state,
const type::Type*,
intrinsic::Number C,
intrinsic::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* BuildMat(intrinsic::MatchState& state,
const type::Type*,
const type::Type* T) {
auto* column_type = state.types.vec(T, R);
return state.types.mat(column_type, C);
}
constexpr auto BuildMat2X2 = BuildMat<2, 2>;
constexpr auto BuildMat2X3 = BuildMat<2, 3>;
constexpr auto BuildMat2X4 = BuildMat<2, 4>;
constexpr auto BuildMat3X2 = BuildMat<3, 2>;
constexpr auto BuildMat3X3 = BuildMat<3, 3>;
constexpr auto BuildMat3X4 = BuildMat<3, 4>;
constexpr auto BuildMat4X2 = BuildMat<4, 2>;
constexpr auto BuildMat4X3 = BuildMat<4, 3>;
constexpr auto BuildMat4X4 = BuildMat<4, 4>;
constexpr auto MatchMat2X2 = MatchMat<2, 2>;
constexpr auto MatchMat2X3 = MatchMat<2, 3>;
constexpr auto MatchMat2X4 = MatchMat<2, 4>;
constexpr auto MatchMat3X2 = MatchMat<3, 2>;
constexpr auto MatchMat3X3 = MatchMat<3, 3>;
constexpr auto MatchMat3X4 = MatchMat<3, 4>;
constexpr auto MatchMat4X2 = MatchMat<4, 2>;
constexpr auto MatchMat4X3 = MatchMat<4, 3>;
constexpr auto MatchMat4X4 = MatchMat<4, 4>;
inline bool MatchArray(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (ty->Is<intrinsic::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* BuildArray(intrinsic::MatchState& state,
const type::Type*,
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 MatchPtr(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& S,
const type::Type*& T,
intrinsic::Number& A) {
if (ty->Is<intrinsic::Any>()) {
S = intrinsic::Number::any;
T = ty;
A = intrinsic::Number::any;
return true;
}
if (auto* p = ty->As<type::Pointer>()) {
S = intrinsic::Number(static_cast<uint32_t>(p->AddressSpace()));
T = p->StoreType();
A = intrinsic::Number(static_cast<uint32_t>(p->Access()));
return true;
}
return false;
}
inline const type::Pointer* BuildPtr(intrinsic::MatchState& state,
const type::Type*,
intrinsic::Number S,
const type::Type* T,
intrinsic::Number& A) {
return state.types.ptr(static_cast<core::AddressSpace>(S.Value()), T,
static_cast<core::Access>(A.Value()));
}
inline bool MatchAtomic(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
T = ty;
return true;
}
if (auto* a = ty->As<type::Atomic>()) {
T = a->Type();
return true;
}
return false;
}
inline const type::Atomic* BuildAtomic(intrinsic::MatchState& state,
const type::Type*,
const type::Type* T) {
return state.types.atomic(T);
}
inline bool MatchSampler(intrinsic::MatchState&, const type::Type* ty) {
if (ty->Is<intrinsic::Any>()) {
return true;
}
return ty->Is([](const type::Sampler* s) { return s->kind() == type::SamplerKind::kSampler; });
}
inline const type::Sampler* BuildSampler(intrinsic::MatchState& state, const type::Type*) {
return state.types.sampler();
}
inline bool MatchSamplerComparison(intrinsic::MatchState&, const type::Type* ty) {
if (ty->Is<intrinsic::Any>()) {
return true;
}
return ty->Is(
[](const type::Sampler* s) { return s->kind() == type::SamplerKind::kComparisonSampler; });
}
inline const type::Sampler* BuildSamplerComparison(intrinsic::MatchState& state,
const type::Type*) {
return state.types.comparison_sampler();
}
inline bool MatchTexture(intrinsic::MatchState&,
const type::Type* ty,
type::TextureDimension dim,
const type::Type*& T) {
if (ty->Is<intrinsic::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(MatchTexture, suffix)(intrinsic::MatchState & state, const type::Type* ty, \
const type::Type*& T) { \
return MatchTexture(state, ty, dim, T); \
} \
inline const type::SampledTexture* JOIN(BuildTexture, suffix)( \
intrinsic::MatchState & state, const type::Type*, 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(2DArray, type::TextureDimension::k2dArray)
DECLARE_SAMPLED_TEXTURE(3D, type::TextureDimension::k3d)
DECLARE_SAMPLED_TEXTURE(Cube, type::TextureDimension::kCube)
DECLARE_SAMPLED_TEXTURE(CubeArray, type::TextureDimension::kCubeArray)
#undef DECLARE_SAMPLED_TEXTURE
inline bool MatchTextureMultisampled(intrinsic::MatchState&,
const type::Type* ty,
type::TextureDimension dim,
const type::Type*& T) {
if (ty->Is<intrinsic::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(MatchTextureMultisampled, suffix)( \
intrinsic::MatchState & state, const type::Type* ty, const type::Type*& T) { \
return MatchTextureMultisampled(state, ty, dim, T); \
} \
inline const type::MultisampledTexture* JOIN(BuildTextureMultisampled, suffix)( \
intrinsic::MatchState & state, const type::Type*, 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 MatchTextureDepth(intrinsic::MatchState&,
const type::Type* ty,
type::TextureDimension dim) {
if (ty->Is<intrinsic::Any>()) {
return true;
}
return ty->Is([&](const type::DepthTexture* t) { return t->dim() == dim; });
}
#define DECLARE_DEPTH_TEXTURE(suffix, dim) \
inline bool JOIN(MatchTextureDepth, suffix)(intrinsic::MatchState & state, \
const type::Type* ty) { \
return MatchTextureDepth(state, ty, dim); \
} \
inline const type::DepthTexture* JOIN(BuildTextureDepth, suffix)( \
intrinsic::MatchState & state, const type::Type*) { \
return state.types.Get<type::DepthTexture>(dim); \
}
DECLARE_DEPTH_TEXTURE(2D, type::TextureDimension::k2d)
DECLARE_DEPTH_TEXTURE(2DArray, type::TextureDimension::k2dArray)
DECLARE_DEPTH_TEXTURE(Cube, type::TextureDimension::kCube)
DECLARE_DEPTH_TEXTURE(CubeArray, type::TextureDimension::kCubeArray)
#undef DECLARE_DEPTH_TEXTURE
inline bool MatchTextureDepthMultisampled2D(intrinsic::MatchState&, const type::Type* ty) {
if (ty->Is<intrinsic::Any>()) {
return true;
}
return ty->Is([&](const type::DepthMultisampledTexture* t) {
return t->dim() == type::TextureDimension::k2d;
});
}
inline type::DepthMultisampledTexture* BuildTextureDepthMultisampled2D(intrinsic::MatchState& state,
const type::Type*) {
return state.types.Get<type::DepthMultisampledTexture>(type::TextureDimension::k2d);
}
inline bool MatchTextureStorage(intrinsic::MatchState&,
const type::Type* ty,
type::TextureDimension dim,
intrinsic::Number& F,
intrinsic::Number& A) {
if (ty->Is<intrinsic::Any>()) {
F = intrinsic::Number::any;
A = intrinsic::Number::any;
return true;
}
if (auto* v = ty->As<type::StorageTexture>()) {
if (v->dim() == dim) {
F = intrinsic::Number(static_cast<uint32_t>(v->texel_format()));
A = intrinsic::Number(static_cast<uint32_t>(v->access()));
return true;
}
}
return false;
}
#define DECLARE_STORAGE_TEXTURE(suffix, dim) \
inline bool JOIN(MatchTextureStorage, suffix)(intrinsic::MatchState & state, \
const type::Type* ty, intrinsic::Number& F, \
intrinsic::Number& A) { \
return MatchTextureStorage(state, ty, dim, F, A); \
} \
inline const type::StorageTexture* JOIN(BuildTextureStorage, suffix)( \
intrinsic::MatchState & state, const type::Type*, intrinsic::Number F, \
intrinsic::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(2DArray, type::TextureDimension::k2dArray)
DECLARE_STORAGE_TEXTURE(3D, type::TextureDimension::k3d)
#undef DECLARE_STORAGE_TEXTURE
inline bool MatchTextureExternal(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::ExternalTexture>();
}
inline const type::ExternalTexture* BuildTextureExternal(intrinsic::MatchState& state,
const type::Type*) {
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 MatchModfResult(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (!ty->Is<intrinsic::Any>()) {
return false;
}
T = ty;
return true;
}
inline bool MatchModfResultVec(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& N,
const type::Type*& T) {
if (!ty->Is<intrinsic::Any>()) {
return false;
}
N = intrinsic::Number::any;
T = ty;
return true;
}
inline bool MatchFrexpResult(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (!ty->Is<intrinsic::Any>()) {
return false;
}
T = ty;
return true;
}
inline bool MatchFrexpResultVec(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& N,
const type::Type*& T) {
if (!ty->Is<intrinsic::Any>()) {
return false;
}
N = intrinsic::Number::any;
T = ty;
return true;
}
inline bool MatchAtomicCompareExchangeResult(intrinsic::MatchState&,
const type::Type* ty,
const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
T = ty;
return true;
}
return false;
}
inline const type::Struct* BuildModfResult(intrinsic::MatchState& state,
const type::Type*,
const type::Type* el) {
return type::CreateModfResult(state.types, state.symbols, el);
}
inline const type::Struct* BuildModfResultVec(intrinsic::MatchState& state,
const type::Type*,
intrinsic::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* BuildFrexpResult(intrinsic::MatchState& state,
const type::Type*,
const type::Type* el) {
return type::CreateFrexpResult(state.types, state.symbols, el);
}
inline const type::Struct* BuildFrexpResultVec(intrinsic::MatchState& state,
const type::Type*,
intrinsic::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* BuildAtomicCompareExchangeResult(intrinsic::MatchState& state,
const type::Type*,
const type::Type* ty) {
return type::CreateAtomicCompareExchangeResult(state.types, state.symbols, ty);
}
} // namespace tint::core::intrinsic
//! @endcond
#endif // SRC_TINT_LANG_CORE_INTRINSIC_TYPE_MATCHERS_H_