diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index 6e379fdc56..0cacca4681 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -384,6 +384,9 @@ libtint_source_set("libtint_core_all_src") { "resolver/validator.cc", "resolver/validator.h", "scope_stack.h", + "sem/abstract_float.h", + "sem/abstract_int.h", + "sem/abstract_numeric.h", "sem/array.h", "sem/atomic.h", "sem/behavior.h", diff --git a/src/tint/intrinsics.def b/src/tint/intrinsics.def index 400b937d75..b12244cb28 100644 --- a/src/tint/intrinsics.def +++ b/src/tint/intrinsics.def @@ -199,14 +199,30 @@ match workgroup_or_storage: workgroup | storage // the same argument type. // // // // // -// Matching algorithm: // -// ------------------- // +// Matching algorithm for a single overload: // +// ----------------------------------------- // +// // +// The goal of matching is to compare a function call's arguments in the // +// program source against a possibly-templated overload declaration, and // +// determine if the call satisfies the form and type constraints of the // +// overload. Currently it is impossible for a call to match more than one // +// overload definition. In the event that more than one overload matches, an // +// ICE will be raised. Note that Tint may need to support multiple-overload // +// resolution in the future, depending on future overload definitions. // // // // Prior to matching an overload, all template types are undefined. // // // -// Template types become defined on the first attempt to match an argument to // -// that template type. Once template types are defined, they remain that type // -// for the rest of the overload evaluation. // +// Template types are first defined with the type of the leftmost argument // +// that matches against that template type name. Subsequent arguments that // +// attempt to match against the template type name will either reject the // +// overload or refine the template, in one of 3 ways: // +// (a) Fail to match, causing the overload to be immediately rejected. // +// (b) Match the existing template type, either exactly or via implicit // +// conversion, and overload resolution continues. // +// (c) Match via implicit conversion of the currently defined template type // +// to the argument type. In this situation, the template type is refined // +// with the more constrained argument type, and overload resolution // +// continues. // // // // To better understand, let's consider the following hypothetical overload // // declaration: // @@ -228,17 +244,24 @@ match workgroup_or_storage: workgroup | storage // type of the first argument. // // There's no verification that the T type is a scalar at this stage. // // (2) The second parameter is then compared against the second argument. // -// As the template type T is now defined the argument type is compared // -// against the value of the defined type of T. If the types match, then // -// the overload is still a candidate for matching, otherwise the // -// overload is no longer considered. // +// As the template type T is now defined the argument type is compared // +// against the value of the defined type of T. Depending on the // +// comparison of the argument type to the template type, either the // +// actions of (a), (b) or (c) from above will occur. // // (3) If all the parameters matched, constraints on the template types // // need to be checked next. If the defined type does not match the // // 'match' constraint, then the overload is no longer considered. // // // -// The algorithm for matching template numbers is almost identical to // -// matching template types, except of course, they match against integer // -// numbers or enumerators instead of types. // +// This algorithm is less general than the overload resolution described in // +// the WGSL spec. But it makes the same decisions because the overloads // +// defined by WGSL are monotonic in the sense that once a template parameter // +// has been refined, there is never a need to backtrack and un-refine it to // +// match a later argument. // +// // +// The algorithm for matching template numbers is similar to matching // +// template types, except numbers need to exactly match across all uses - // +// there is no implicit conversion. Template numbers may match integer // +// numbers or enumerators. // // // // // // * More examples: // diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc index 67f14dd6f7..af8902386d 100644 --- a/src/tint/resolver/intrinsic_table.cc +++ b/src/tint/resolver/intrinsic_table.cc @@ -20,6 +20,9 @@ #include #include "src/tint/program_builder.h" +#include "src/tint/sem/abstract_float.h" +#include "src/tint/sem/abstract_int.h" +#include "src/tint/sem/abstract_numeric.h" #include "src/tint/sem/atomic.h" #include "src/tint/sem/depth_multisampled_texture.h" #include "src/tint/sem/depth_texture.h" @@ -104,12 +107,33 @@ const Number Number::invalid{Number::kInvalid}; /// Used by the MatchState. class TemplateState { public: - /// If the type with index `idx` is undefined, then it is defined with type `ty` and Type() - /// returns true. If the template type is defined, then `Type()` returns true iff it is equal to - /// `ty`. - bool Type(size_t idx, const sem::Type* ty) { + /// If the template type with index `idx` is undefined, then it is defined with the `ty` and + /// Type() returns `ty`. + /// If the template type is defined, and `ty` can be converted to the template type then the + /// template type is returned. + /// If the template type is defined, and the template type can be converted to `ty`, then the + /// template type is replaced with `ty`, and `ty` is returned. + /// If none of the above applies, then `ty` is a type mismatch for the template type, and + /// nullptr is returned. + const sem::Type* Type(size_t idx, const sem::Type* ty) { auto res = types_.emplace(idx, ty); - return res.second || res.first->second == ty; + if (res.second) { + return ty; + } + auto* existing = res.first->second; + if (existing == ty) { + return ty; + } + if (sem::Type::ConversionRank(ty, existing) != sem::Type::kNoConversion) { + // ty can be converted to the existing type. Keep the existing type. + return existing; + } + if (sem::Type::ConversionRank(existing, ty) != sem::Type::kNoConversion) { + // template type can be converted to ty. Constrain the existing type. + types_[idx] = ty; + return ty; + } + return nullptr; } /// If the number with index `idx` is undefined, then it is defined with the number `number` and @@ -126,6 +150,9 @@ class TemplateState { return (it != types_.end()) ? it->second : nullptr; } + /// SetType replaces the template type with index `idx` with type `ty`. + void SetType(size_t idx, const sem::Type* ty) { types_[idx] = ty; } + /// Type returns the number type with index `idx`. Number Num(size_t idx) const { auto it = numbers_.find(idx); @@ -197,7 +224,7 @@ class TypeMatcher { /// Checks whether the given type matches the matcher rules, and returns the /// expected, canonicalized type on success. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr virtual const sem::Type* Match(MatchState& state, const sem::Type* type) const = 0; @@ -226,8 +253,8 @@ class NumberMatcher { }; /// TemplateTypeMatcher is a Matcher for a template type. -/// The TemplateTypeMatcher will initially match against any type (so long as it is -/// consistent for all uses in the overload) +/// The TemplateTypeMatcher will initially match against any type, and then will only be further +/// constrained based on the conversion rules defined at https://www.w3.org/TR/WGSL/#conversion-rank class TemplateTypeMatcher : public TypeMatcher { public: /// Constructor @@ -237,7 +264,10 @@ class TemplateTypeMatcher : public TypeMatcher { if (type->Is()) { return state.templates.Type(index_); } - return state.templates.Type(index_, type) ? type : nullptr; + if (auto* templates = state.templates.Type(index_, type)) { + return templates; + } + return nullptr; } std::string String(MatchState& state) const override; @@ -305,7 +335,7 @@ const sem::F32* build_f32(MatchState& state) { } bool match_f32(const sem::Type* ty) { - return ty->IsAnyOf(); + return ty->IsAnyOf(); } const sem::I32* build_i32(MatchState& state) { @@ -313,7 +343,7 @@ const sem::I32* build_i32(MatchState& state) { } bool match_i32(const sem::Type* ty) { - return ty->IsAnyOf(); + return ty->IsAnyOf(); } const sem::U32* build_u32(MatchState& state) { @@ -321,7 +351,7 @@ const sem::U32* build_u32(MatchState& state) { } bool match_u32(const sem::Type* ty) { - return ty->IsAnyOf(); + return ty->IsAnyOf(); } bool match_vec(const sem::Type* ty, Number& N, const sem::Type*& T) { @@ -1247,6 +1277,11 @@ IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic, case 1: break; default: + // Note: Currently the intrinsic table does not contain any overloads which may result + // in ambiguities, so here we call ErrMultipleOverloadsMatched() which will produce and + // ICE. If we end up in the situation where this is unavoidable, we'll need to perform + // further overload resolution as described in + // https://www.w3.org/TR/WGSL/#overload-resolution-section. ErrMultipleOverloadsMatched(num_matched, intrinsic_name, args, templates, candidates); } @@ -1290,36 +1325,51 @@ Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload, std::min(num_parameters, num_arguments)); } - std::vector parameters; - + // Invoke the matchers for each parameter <-> argument pair. + // If any arguments cannot be matched, then `score` will be increased. + // If the overload has any template types or numbers then these will be set based on the + // argument types. Template types may be refined by constraining with later argument types. For + // example calling `F(T, T)` with the argument types (abstract-int, i32) will first set T to + // abstract-int when matching the first argument, and then constrained down to i32 when matching + // the second argument. + // Note that inferred template types are not tested against their matchers at this point. auto num_params = std::min(num_parameters, num_arguments); for (size_t p = 0; p < num_params; p++) { auto& parameter = overload->parameters[p]; auto* indices = parameter.matcher_indices; - auto* type = Match(templates, overload, indices).Type(args[p]->UnwrapRef()); - if (type) { - parameters.emplace_back(IntrinsicPrototype::Parameter{type, parameter.usage}); - } else { + if (!Match(templates, overload, indices).Type(args[p]->UnwrapRef())) { score += kMismatchedParamTypePenalty; } } if (score == 0) { - // Check all constrained template types matched + // Check all constrained template types matched their constraint matchers. + // If the template type *does not* match any of the types in the constraint matcher, then + // `score` is incremented. If the template type *does* match a type, then the template type + // is replaced with the first matching type. The order of types in the template matcher is + // important here, which can be controlled with the [[precedence(N)]] decorations on the + // types in intrinsics.def. for (size_t ot = 0; ot < overload->num_template_types; ot++) { auto* matcher_index = &overload->template_types[ot].matcher_index; if (*matcher_index != kNoMatcher) { - auto* template_type = templates.Type(ot); - if (!template_type || - !Match(templates, overload, matcher_index).Type(template_type)) { - score += kMismatchedTemplateTypePenalty; + if (auto* template_type = templates.Type(ot)) { + if (auto* ty = Match(templates, overload, matcher_index).Type(template_type)) { + // Template type matched one of the types in the template type's matcher. + // Replace the template type with this type. + templates.SetType(ot, ty); + continue; + } } + score += kMismatchedTemplateTypePenalty; } } } if (score == 0) { - // Check all constrained open numbers matched + // Check all constrained open numbers matched. + // Unlike template types, numbers are not constrained, so we're just checking that the + // inferred number matches the constraints on the overload. Increments `score` if the + // template numbers do not match their constraint matchers. for (size_t on = 0; on < overload->num_template_numbers; on++) { auto* matcher_index = &overload->template_numbers[on].matcher_index; if (*matcher_index != kNoMatcher) { @@ -1332,6 +1382,18 @@ Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload, } } + // Now that all the template types have been finalized, we can construct the parameters. + std::vector parameters; + if (score == 0) { + parameters.reserve(num_params); + for (size_t p = 0; p < num_params; p++) { + auto& parameter = overload->parameters[p]; + auto* indices = parameter.matcher_indices; + auto* ty = Match(templates, overload, indices).Type(args[p]->UnwrapRef()); + parameters.emplace_back(IntrinsicPrototype::Parameter{ty, parameter.usage}); + } + } + return Candidate{overload, templates, parameters, score}; } diff --git a/src/tint/resolver/intrinsic_table.inl b/src/tint/resolver/intrinsic_table.inl index 5f6203c93a..f6502a1d6f 100644 --- a/src/tint/resolver/intrinsic_table.inl +++ b/src/tint/resolver/intrinsic_table.inl @@ -29,7 +29,7 @@ class Bool : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -56,7 +56,7 @@ std::string Bool::String(MatchState&) const { class I32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -83,7 +83,7 @@ std::string I32::String(MatchState&) const { class U32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -110,7 +110,7 @@ std::string U32::String(MatchState&) const { class F32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -137,7 +137,7 @@ std::string F32::String(MatchState&) const { class Vec2 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -170,7 +170,7 @@ std::string Vec2::String(MatchState& state) const { class Vec3 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -203,7 +203,7 @@ std::string Vec3::String(MatchState& state) const { class Vec4 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -236,7 +236,7 @@ std::string Vec4::String(MatchState& state) const { class Mat2X2 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -269,7 +269,7 @@ std::string Mat2X2::String(MatchState& state) const { class Mat2X3 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -302,7 +302,7 @@ std::string Mat2X3::String(MatchState& state) const { class Mat2X4 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -335,7 +335,7 @@ std::string Mat2X4::String(MatchState& state) const { class Mat3X2 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -368,7 +368,7 @@ std::string Mat3X2::String(MatchState& state) const { class Mat3X3 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -401,7 +401,7 @@ std::string Mat3X3::String(MatchState& state) const { class Mat3X4 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -434,7 +434,7 @@ std::string Mat3X4::String(MatchState& state) const { class Mat4X2 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -467,7 +467,7 @@ std::string Mat4X2::String(MatchState& state) const { class Mat4X3 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -500,7 +500,7 @@ std::string Mat4X3::String(MatchState& state) const { class Mat4X4 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -533,7 +533,7 @@ std::string Mat4X4::String(MatchState& state) const { class Vec : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -574,7 +574,7 @@ std::string Vec::String(MatchState& state) const { class Mat : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -621,7 +621,7 @@ std::string Mat::String(MatchState& state) const { class Ptr : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -666,7 +666,7 @@ std::string Ptr::String(MatchState& state) const { class Atomic : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -699,7 +699,7 @@ std::string Atomic::String(MatchState& state) const { class Array : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -732,7 +732,7 @@ std::string Array::String(MatchState& state) const { class Sampler : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -759,7 +759,7 @@ std::string Sampler::String(MatchState&) const { class SamplerComparison : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -786,7 +786,7 @@ std::string SamplerComparison::String(MatchState&) const { class Texture1D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -819,7 +819,7 @@ std::string Texture1D::String(MatchState& state) const { class Texture2D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -852,7 +852,7 @@ std::string Texture2D::String(MatchState& state) const { class Texture2DArray : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -885,7 +885,7 @@ std::string Texture2DArray::String(MatchState& state) const { class Texture3D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -918,7 +918,7 @@ std::string Texture3D::String(MatchState& state) const { class TextureCube : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -951,7 +951,7 @@ std::string TextureCube::String(MatchState& state) const { class TextureCubeArray : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -984,7 +984,7 @@ std::string TextureCubeArray::String(MatchState& state) const { class TextureMultisampled2D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1017,7 +1017,7 @@ std::string TextureMultisampled2D::String(MatchState& state) const { class TextureDepth2D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1044,7 +1044,7 @@ std::string TextureDepth2D::String(MatchState&) const { class TextureDepth2DArray : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1071,7 +1071,7 @@ std::string TextureDepth2DArray::String(MatchState&) const { class TextureDepthCube : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1098,7 +1098,7 @@ std::string TextureDepthCube::String(MatchState&) const { class TextureDepthCubeArray : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1125,7 +1125,7 @@ std::string TextureDepthCubeArray::String(MatchState&) const { class TextureDepthMultisampled2D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1152,7 +1152,7 @@ std::string TextureDepthMultisampled2D::String(MatchState&) const { class TextureStorage1D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1191,7 +1191,7 @@ std::string TextureStorage1D::String(MatchState& state) const { class TextureStorage2D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1230,7 +1230,7 @@ std::string TextureStorage2D::String(MatchState& state) const { class TextureStorage2DArray : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1269,7 +1269,7 @@ std::string TextureStorage2DArray::String(MatchState& state) const { class TextureStorage3D : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1308,7 +1308,7 @@ std::string TextureStorage3D::String(MatchState& state) const { class TextureExternal : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1335,7 +1335,7 @@ std::string TextureExternal::String(MatchState&) const { class ModfResult : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1362,7 +1362,7 @@ std::string ModfResult::String(MatchState&) const { class ModfResultVec : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1397,7 +1397,7 @@ std::string ModfResultVec::String(MatchState& state) const { class FrexpResult : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1424,7 +1424,7 @@ std::string FrexpResult::String(MatchState&) const { class FrexpResultVec : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1460,7 +1460,7 @@ class Fiu32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the /// expected, canonicalized type on success. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1494,7 +1494,7 @@ class Fi32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the /// expected, canonicalized type on success. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1525,7 +1525,7 @@ class Iu32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the /// expected, canonicalized type on success. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1556,7 +1556,7 @@ class Scalar : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the /// expected, canonicalized type on success. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1593,7 +1593,7 @@ class ScalarNoF32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the /// expected, canonicalized type on success. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1627,7 +1627,7 @@ class ScalarNoI32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the /// expected, canonicalized type on success. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1661,7 +1661,7 @@ class ScalarNoU32 : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the /// expected, canonicalized type on success. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1695,7 +1695,7 @@ class ScalarNoBool : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the /// expected, canonicalized type on success. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -1728,7 +1728,7 @@ std::string ScalarNoBool::String(MatchState&) const { class F32TexelFormat : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. - /// Match may define template types and numbers in state. + /// Match may define template numbers in state. /// @param state the MatchState /// @param number the enum value as a Number /// @return true if the enum value matches the set @@ -1761,7 +1761,7 @@ std::string F32TexelFormat::String(MatchState&) const { class I32TexelFormat : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. - /// Match may define template types and numbers in state. + /// Match may define template numbers in state. /// @param state the MatchState /// @param number the enum value as a Number /// @return true if the enum value matches the set @@ -1793,7 +1793,7 @@ std::string I32TexelFormat::String(MatchState&) const { class U32TexelFormat : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. - /// Match may define template types and numbers in state. + /// Match may define template numbers in state. /// @param state the MatchState /// @param number the enum value as a Number /// @return true if the enum value matches the set @@ -1825,7 +1825,7 @@ std::string U32TexelFormat::String(MatchState&) const { class WriteOnly : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. - /// Match may define template types and numbers in state. + /// Match may define template numbers in state. /// @param state the MatchState /// @param number the enum value as a Number /// @return true if the enum value matches the set @@ -1851,7 +1851,7 @@ std::string WriteOnly::String(MatchState&) const { class FunctionPrivateWorkgroup : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. - /// Match may define template types and numbers in state. + /// Match may define template numbers in state. /// @param state the MatchState /// @param number the enum value as a Number /// @return true if the enum value matches the set @@ -1881,7 +1881,7 @@ std::string FunctionPrivateWorkgroup::String(MatchState&) const { class WorkgroupOrStorage : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. - /// Match may define template types and numbers in state. + /// Match may define template numbers in state. /// @param state the MatchState /// @param number the enum value as a Number /// @return true if the enum value matches the set @@ -1909,7 +1909,7 @@ std::string WorkgroupOrStorage::String(MatchState&) const { class Storage : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. - /// Match may define template types and numbers in state. + /// Match may define template numbers in state. /// @param state the MatchState /// @param number the enum value as a Number /// @return true if the enum value matches the set @@ -1934,7 +1934,7 @@ std::string Storage::String(MatchState&) const { class Write : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. - /// Match may define template types and numbers in state. + /// Match may define template numbers in state. /// @param state the MatchState /// @param number the enum value as a Number /// @return true if the enum value matches the set @@ -1959,7 +1959,7 @@ std::string Write::String(MatchState&) const { class ReadWrite : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. - /// Match may define template types and numbers in state. + /// Match may define template numbers in state. /// @param state the MatchState /// @param number the enum value as a Number /// @return true if the enum value matches the set diff --git a/src/tint/resolver/intrinsic_table.inl.tmpl b/src/tint/resolver/intrinsic_table.inl.tmpl index 832e696a37..d09d340ed5 100644 --- a/src/tint/resolver/intrinsic_table.inl.tmpl +++ b/src/tint/resolver/intrinsic_table.inl.tmpl @@ -180,7 +180,7 @@ constexpr IntrinsicInfo kConstructorsAndConverters[] = { class {{$class}} : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -236,7 +236,7 @@ class {{$class}} : public TypeMatcher { public: /// Checks whether the given type matches the matcher rules, and returns the /// expected, canonicalized type on success. - /// Match may define template types and numbers in state. + /// Match may define and refine the template types and numbers in state. /// @param state the MatchState /// @param type the type to match /// @returns the canonicalized type on match, otherwise nullptr @@ -280,7 +280,7 @@ std::string {{$class}}::String(MatchState&) const { class {{$class}} : public NumberMatcher { public: /// Checks whether the given number matches the enum matcher rules. - /// Match may define template types and numbers in state. + /// Match may define template numbers in state. /// @param state the MatchState /// @param number the enum value as a Number /// @return true if the enum value matches the set diff --git a/src/tint/resolver/intrinsic_table_test.cc b/src/tint/resolver/intrinsic_table_test.cc index 206c951881..a72eb00f72 100644 --- a/src/tint/resolver/intrinsic_table_test.cc +++ b/src/tint/resolver/intrinsic_table_test.cc @@ -18,6 +18,7 @@ #include "gmock/gmock.h" #include "src/tint/program_builder.h" +#include "src/tint/resolver/resolver_test_helper.h" #include "src/tint/sem/atomic.h" #include "src/tint/sem/depth_multisampled_texture.h" #include "src/tint/sem/depth_texture.h" @@ -32,12 +33,27 @@ namespace tint::resolver { namespace { +#define EXPECT_TYPE(GOT, EXPECT) \ + if ((GOT) != (EXPECT)) { \ + FAIL() << #GOT " != " #EXPECT "\n" \ + << " " #GOT ": " << NameOf(GOT) << "\n" \ + << " " #EXPECT ": " << NameOf(EXPECT); \ + } \ + do { \ + } while (false) + using ::testing::HasSubstr; using BuiltinType = sem::BuiltinType; using Parameter = sem::Parameter; using ParameterUsage = sem::ParameterUsage; +using AFloatV = builder::vec<3, AFloat>; +using AIntV = builder::vec<3, AInt>; +using f32V = builder::vec<3, f32>; +using i32V = builder::vec<3, i32>; +using u32V = builder::vec<3, u32>; + class IntrinsicTableTest : public testing::Test, public ProgramBuilder { public: std::unique_ptr table = IntrinsicTable::Create(*this); @@ -418,7 +434,7 @@ TEST_F(IntrinsicTableTest, ImplicitLoadOnReference) { EXPECT_EQ(result->Parameters()[0]->Type(), f32); } -TEST_F(IntrinsicTableTest, MatchOpenType) { +TEST_F(IntrinsicTableTest, MatchTemplateType) { auto* f32 = create(); auto* result = table->Lookup(BuiltinType::kClamp, {f32, f32, f32}, Source{}); ASSERT_NE(result, nullptr) << Diagnostics().str(); @@ -430,7 +446,7 @@ TEST_F(IntrinsicTableTest, MatchOpenType) { EXPECT_EQ(result->Parameters()[2]->Type(), f32); } -TEST_F(IntrinsicTableTest, MismatchOpenType) { +TEST_F(IntrinsicTableTest, MismatchTemplateType) { auto* f32 = create(); auto* u32 = create(); auto* result = table->Lookup(BuiltinType::kClamp, {f32, u32, f32}, Source{}); @@ -785,5 +801,461 @@ TEST_F(IntrinsicTableTest, Err257Arguments) { // crbug.com/1323605 ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } +//////////////////////////////////////////////////////////////////////////////// +// AbstractBinaryTests +//////////////////////////////////////////////////////////////////////////////// +namespace AbstractBinaryTests { + +struct Case { + template + static Case Create(bool match = true) { + return { + match, // + builder::DataType::Sem, // + builder::DataType::Sem, // + builder::DataType::Sem, // + builder::DataType::Sem, // + builder::DataType::Sem, // + }; + } + bool expected_match; + builder::sem_type_func_ptr expected_result; + builder::sem_type_func_ptr expected_param_lhs; + builder::sem_type_func_ptr expected_param_rhs; + builder::sem_type_func_ptr arg_lhs; + builder::sem_type_func_ptr arg_rhs; +}; + +class IntrinsicTableAbstractBinaryTest : public testing::TestWithParam, + public ProgramBuilder { + public: + std::string NameOf(const sem::Type* type) { + return type ? type->FriendlyName(Symbols()) : ""; + } + + std::unique_ptr table = IntrinsicTable::Create(*this); +}; + +TEST_P(IntrinsicTableAbstractBinaryTest, MatchAdd) { + auto* arg_lhs = GetParam().arg_lhs(*this); + auto* arg_rhs = GetParam().arg_rhs(*this); + auto result = table->Lookup(ast::BinaryOp::kAdd, arg_lhs, arg_rhs, Source{{12, 34}}, + /* is_compound */ false); + + bool matched = result.result != nullptr; + bool expected_match = GetParam().expected_match; + EXPECT_EQ(matched, expected_match) << Diagnostics().str(); + + auto* expected_result = GetParam().expected_result(*this); + EXPECT_TYPE(result.result, expected_result); + + auto* expected_param_lhs = GetParam().expected_param_lhs(*this); + EXPECT_TYPE(result.lhs, expected_param_lhs); + + auto* expected_param_rhs = GetParam().expected_param_rhs(*this); + EXPECT_TYPE(result.rhs, expected_param_rhs); +} + +INSTANTIATE_TEST_SUITE_P(AFloat_AInt, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create() + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P(VecAFloat_VecAInt, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create() + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P(AFloat_f32, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(), +Case::Create() + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P(VecAFloat_Vecf32, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(), +Case::Create() + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P( + AFloat_i32, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(false), +Case::Create(false) + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P( + VecAFloat_Veci32, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(false), +Case::Create(false) + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P( + AFloat_u32, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(false), +Case::Create(false) + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P( + VecAFloat_Vecu32, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(false), +Case::Create(false) + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P(AInt_f32, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(), +Case::Create() + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P(VecAInt_Vecf32, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(), +Case::Create() + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P(AInt_i32, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(), +Case::Create() + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P(VecAInt_Veci32, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(), +Case::Create() + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P(AInt_u32, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(), +Case::Create() + )); // clang-format on + +INSTANTIATE_TEST_SUITE_P(VecAInt_Vecu32, + IntrinsicTableAbstractBinaryTest, + testing::Values( // clang-format off +// result | param lhs | param rhs | arg lhs | arg rhs +Case::Create(), +Case::Create() + )); // clang-format on + +} // namespace AbstractBinaryTests + +//////////////////////////////////////////////////////////////////////////////// +// AbstractTernaryTests +//////////////////////////////////////////////////////////////////////////////// +namespace AbstractTernaryTests { + +struct Case { + template + static Case Create(bool match = true) { + return { + match, + builder::DataType::Sem, // + builder::DataType::Sem, // + builder::DataType::Sem, // + builder::DataType::Sem, // + builder::DataType::Sem, // + builder::DataType::Sem, // + builder::DataType::Sem, // + }; + } + bool expected_match; + builder::sem_type_func_ptr expected_result; + builder::sem_type_func_ptr expected_param_a; + builder::sem_type_func_ptr expected_param_b; + builder::sem_type_func_ptr expected_param_c; + builder::sem_type_func_ptr arg_a; + builder::sem_type_func_ptr arg_b; + builder::sem_type_func_ptr arg_c; +}; + +class IntrinsicTableAbstractTernaryTest : public testing::TestWithParam, + public ProgramBuilder { + public: + std::string NameOf(const sem::Type* type) { + return type ? type->FriendlyName(Symbols()) : ""; + } + + std::unique_ptr table = IntrinsicTable::Create(*this); +}; + +TEST_P(IntrinsicTableAbstractTernaryTest, MatchClamp) { + auto* arg_a = GetParam().arg_a(*this); + auto* arg_b = GetParam().arg_b(*this); + auto* arg_c = GetParam().arg_c(*this); + auto* builtin = + table->Lookup(sem::BuiltinType::kClamp, {arg_a, arg_b, arg_c}, Source{{12, 34}}); + + bool matched = builtin != nullptr; + bool expected_match = GetParam().expected_match; + EXPECT_EQ(matched, expected_match) << Diagnostics().str(); + + auto* result = builtin ? builtin->ReturnType() : nullptr; + auto* expected_result = GetParam().expected_result(*this); + EXPECT_TYPE(result, expected_result); + + 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 ? 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 ? builtin->Parameters()[2]->Type() : nullptr; + auto* expected_param_c = GetParam().expected_param_c(*this); + EXPECT_TYPE(param_c, expected_param_c); +} + +INSTANTIATE_TEST_SUITE_P( + AFloat_AInt, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create() + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + VecAFloat_VecAInt, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create() + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + AFloat_f32, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create() + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + VecAFloat_Vecf32, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create () + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + AFloat_i32, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(false), +Case::Create(false), +Case::Create(false), +Case::Create(false), +Case::Create(false), +Case::Create(false) + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + VecAFloat_Veci32, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(false), +Case::Create(false), +Case::Create(false), +Case::Create(false), +Case::Create(false), +Case::Create(false) + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + AFloat_u32, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(false), +Case::Create(false), +Case::Create(false), +Case::Create(false), +Case::Create(false), +Case::Create(false) + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + VecAFloat_Vecu32, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(false), +Case::Create(false), +Case::Create(false), +Case::Create(false), +Case::Create(false), +Case::Create(false) + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + AInt_f32, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create() + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + VecAInt_Vecf32, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create() + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + AInt_i32, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create() + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + VecAInt_Veci32, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create() + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + AInt_u32, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create() + // clang-format on + )); + +INSTANTIATE_TEST_SUITE_P( + VecAInt_Vecu32, + IntrinsicTableAbstractTernaryTest, + testing::Values( // clang-format off +// result | param a | param b | param c | arg a | arg b | arg c +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create(), +Case::Create() + // clang-format on + )); + +} // namespace AbstractTernaryTests + } // namespace } // namespace tint::resolver diff --git a/src/tint/resolver/resolver_test_helper.h b/src/tint/resolver/resolver_test_helper.h index d54e57c6b0..aca1b2930b 100644 --- a/src/tint/resolver/resolver_test_helper.h +++ b/src/tint/resolver/resolver_test_helper.h @@ -22,6 +22,8 @@ #include "gtest/gtest.h" #include "src/tint/program_builder.h" #include "src/tint/resolver/resolver.h" +#include "src/tint/sem/abstract_float.h" +#include "src/tint/sem/abstract_int.h" #include "src/tint/sem/expression.h" #include "src/tint/sem/statement.h" #include "src/tint/sem/variable.h" @@ -174,6 +176,15 @@ using sem_type_func_ptr = const sem::Type* (*)(ProgramBuilder& b); template struct DataType {}; +/// Helper that represents no-type. Returns nullptr for all static methods. +template <> +struct DataType { + /// @return nullptr + static inline const ast::Type* AST(ProgramBuilder&) { return nullptr; } + /// @return nullptr + static inline const sem::Type* Sem(ProgramBuilder&) { return nullptr; } +}; + /// Helper for building bool types and expressions template <> struct DataType { @@ -254,6 +265,40 @@ struct DataType { } }; +/// Helper for building abstract float types and expressions +template <> +struct DataType { + /// false as AFloat is not a composite type + static constexpr bool is_composite = false; + + /// @param b the ProgramBuilder + /// @return the semantic abstract-float type + static inline const sem::Type* Sem(ProgramBuilder& b) { return b.create(); } + /// @param b the ProgramBuilder + /// @param elem_value the abstract-float value + /// @return a new AST abstract-float literal value expression + static inline const ast::Expression* Expr(ProgramBuilder& b, AFloat elem_value) { + return b.Expr(elem_value); + } +}; + +/// Helper for building abstract integer types and expressions +template <> +struct DataType { + /// false as AFloat is not a composite type + static constexpr bool is_composite = false; + + /// @param b the ProgramBuilder + /// @return the semantic abstract-int type + static inline const sem::Type* Sem(ProgramBuilder& b) { return b.create(); } + /// @param b the ProgramBuilder + /// @param elem_value the abstract-int value + /// @return a new AST abstract-int literal value expression + static inline const ast::Expression* Expr(ProgramBuilder& b, AInt elem_value) { + return b.Expr(elem_value); + } +}; + /// Helper for building vector types and expressions template struct DataType> {