| // Copyright 2023 The Dawn & Tint Authors |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // 1. Redistributions of source code must retain the above copyright notice, this |
| // list of conditions and the following disclaimer. |
| // |
| // 2. Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // |
| // 3. Neither the name of the copyright holder nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #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/input_attachment.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/reference.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::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 MatchRef(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::Reference>()) { |
| 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::Reference* BuildRef(intrinsic::MatchState& state, |
| const type::Type*, |
| intrinsic::Number S, |
| const type::Type* T, |
| intrinsic::Number& A) { |
| return state.types.ref(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>(); |
| } |
| |
| inline bool MatchInputAttachment(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::InputAttachment>()) { |
| T = v->type(); |
| return true; |
| } |
| return false; |
| } |
| |
| inline const type::InputAttachment* BuildInputAttachment(intrinsic::MatchState& state, |
| const type::Type*, |
| const type::Type* T) { |
| return state.types.Get<type::InputAttachment>(T); |
| } |
| |
| // 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_ |