tint: fix intrinsic table lookup of mixed const and non-const with non-matching arg element types

Bug: tint:1581
Change-Id: I7676ec6857c5fd790cb9c5644bfe674a603113ab
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/104545
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Antonio Maiorano 2022-10-04 22:19:48 +00:00 committed by Dawn LUCI CQ
parent 2e25382707
commit fc7994ba4c
6 changed files with 355 additions and 254 deletions

View File

@ -27,6 +27,7 @@
#include "src/tint/sem/atomic.h"
#include "src/tint/sem/depth_multisampled_texture.h"
#include "src/tint/sem/depth_texture.h"
#include "src/tint/sem/evaluation_stage.h"
#include "src/tint/sem/external_texture.h"
#include "src/tint/sem/multisampled_texture.h"
#include "src/tint/sem/pipeline_stage_set.h"
@ -195,8 +196,14 @@ class MatchState {
TemplateState& t,
const Matchers& m,
const OverloadInfo* o,
MatcherIndex const* matcher_indices)
: builder(b), templates(t), matchers(m), overload(o), matcher_indices_(matcher_indices) {}
MatcherIndex const* matcher_indices,
sem::EvaluationStage s)
: builder(b),
templates(t),
matchers(m),
overload(o),
earliest_eval_stage(s),
matcher_indices_(matcher_indices) {}
/// The program builder
ProgramBuilder& builder;
@ -206,6 +213,8 @@ class MatchState {
Matchers const& matchers;
/// The current overload being evaluated
OverloadInfo const* overload;
/// The earliest evaluation stage of the builtin call
sem::EvaluationStage earliest_eval_stage;
/// Type uses the next TypeMatcher from the matcher indices to match the type
/// `ty`. If the type matches, the canonical expected type is returned. If the
@ -340,7 +349,7 @@ enum class OverloadFlag {
// An enum set of OverloadFlag, used by OperatorInfo
using OverloadFlags = utils::EnumSet<OverloadFlag>;
bool match_bool(const sem::Type* ty) {
bool match_bool(MatchState&, const sem::Type* ty) {
return ty->IsAnyOf<Any, sem::Bool>();
}
@ -348,16 +357,18 @@ const sem::AbstractFloat* build_fa(MatchState& state) {
return state.builder.create<sem::AbstractFloat>();
}
bool match_fa(const sem::Type* ty) {
return ty->IsAnyOf<Any, sem::AbstractNumeric>();
bool match_fa(MatchState& state, const sem::Type* ty) {
return (state.earliest_eval_stage == sem::EvaluationStage::kConstant) &&
ty->IsAnyOf<Any, sem::AbstractNumeric>();
}
const sem::AbstractInt* build_ia(MatchState& state) {
return state.builder.create<sem::AbstractInt>();
}
bool match_ia(const sem::Type* ty) {
return ty->IsAnyOf<Any, sem::AbstractInt>();
bool match_ia(MatchState& state, const sem::Type* ty) {
return (state.earliest_eval_stage == sem::EvaluationStage::kConstant) &&
ty->IsAnyOf<Any, sem::AbstractInt>();
}
const sem::Bool* build_bool(MatchState& state) {
@ -368,7 +379,7 @@ const sem::F16* build_f16(MatchState& state) {
return state.builder.create<sem::F16>();
}
bool match_f16(const sem::Type* ty) {
bool match_f16(MatchState&, const sem::Type* ty) {
return ty->IsAnyOf<Any, sem::F16, sem::AbstractNumeric>();
}
@ -376,7 +387,7 @@ const sem::F32* build_f32(MatchState& state) {
return state.builder.create<sem::F32>();
}
bool match_f32(const sem::Type* ty) {
bool match_f32(MatchState&, const sem::Type* ty) {
return ty->IsAnyOf<Any, sem::F32, sem::AbstractNumeric>();
}
@ -384,7 +395,7 @@ const sem::I32* build_i32(MatchState& state) {
return state.builder.create<sem::I32>();
}
bool match_i32(const sem::Type* ty) {
bool match_i32(MatchState&, const sem::Type* ty) {
return ty->IsAnyOf<Any, sem::I32, sem::AbstractInt>();
}
@ -392,11 +403,11 @@ const sem::U32* build_u32(MatchState& state) {
return state.builder.create<sem::U32>();
}
bool match_u32(const sem::Type* ty) {
bool match_u32(MatchState&, const sem::Type* ty) {
return ty->IsAnyOf<Any, sem::U32, sem::AbstractInt>();
}
bool match_vec(const sem::Type* ty, Number& N, const sem::Type*& T) {
bool match_vec(MatchState&, const sem::Type* ty, Number& N, const sem::Type*& T) {
if (ty->Is<Any>()) {
N = Number::any;
T = ty;
@ -412,7 +423,7 @@ bool match_vec(const sem::Type* ty, Number& N, const sem::Type*& T) {
}
template <uint32_t N>
bool match_vec(const sem::Type* ty, const sem::Type*& T) {
bool match_vec(MatchState&, const sem::Type* ty, const sem::Type*& T) {
if (ty->Is<Any>()) {
T = ty;
return true;
@ -444,7 +455,7 @@ constexpr auto build_vec2 = build_vec<2>;
constexpr auto build_vec3 = build_vec<3>;
constexpr auto build_vec4 = build_vec<4>;
bool match_mat(const sem::Type* ty, Number& M, Number& N, const sem::Type*& T) {
bool match_mat(MatchState&, const sem::Type* ty, Number& M, Number& N, const sem::Type*& T) {
if (ty->Is<Any>()) {
M = Number::any;
N = Number::any;
@ -461,7 +472,7 @@ bool match_mat(const sem::Type* ty, Number& M, Number& N, const sem::Type*& T) {
}
template <uint32_t C, uint32_t R>
bool match_mat(const sem::Type* ty, const sem::Type*& T) {
bool match_mat(MatchState&, const sem::Type* ty, const sem::Type*& T) {
if (ty->Is<Any>()) {
T = ty;
return true;
@ -506,7 +517,7 @@ constexpr auto match_mat4x2 = match_mat<4, 2>;
constexpr auto match_mat4x3 = match_mat<4, 3>;
constexpr auto match_mat4x4 = match_mat<4, 4>;
bool match_array(const sem::Type* ty, const sem::Type*& T) {
bool match_array(MatchState&, const sem::Type* ty, const sem::Type*& T) {
if (ty->Is<Any>()) {
T = ty;
return true;
@ -530,7 +541,7 @@ const sem::Array* build_array(MatchState& state, const sem::Type* el) {
/* stride_implicit */ 0u);
}
bool match_ptr(const sem::Type* ty, Number& S, const sem::Type*& T, Number& A) {
bool match_ptr(MatchState&, const sem::Type* ty, Number& S, const sem::Type*& T, Number& A) {
if (ty->Is<Any>()) {
S = Number::any;
T = ty;
@ -552,7 +563,7 @@ const sem::Pointer* build_ptr(MatchState& state, Number S, const sem::Type* T, N
static_cast<ast::Access>(A.Value()));
}
bool match_atomic(const sem::Type* ty, const sem::Type*& T) {
bool match_atomic(MatchState&, const sem::Type* ty, const sem::Type*& T) {
if (ty->Is<Any>()) {
T = ty;
return true;
@ -569,7 +580,7 @@ const sem::Atomic* build_atomic(MatchState& state, const sem::Type* T) {
return state.builder.create<sem::Atomic>(T);
}
bool match_sampler(const sem::Type* ty) {
bool match_sampler(MatchState&, const sem::Type* ty) {
if (ty->Is<Any>()) {
return true;
}
@ -580,7 +591,7 @@ const sem::Sampler* build_sampler(MatchState& state) {
return state.builder.create<sem::Sampler>(ast::SamplerKind::kSampler);
}
bool match_sampler_comparison(const sem::Type* ty) {
bool match_sampler_comparison(MatchState&, const sem::Type* ty) {
if (ty->Is<Any>()) {
return true;
}
@ -592,7 +603,10 @@ const sem::Sampler* build_sampler_comparison(MatchState& state) {
return state.builder.create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
}
bool match_texture(const sem::Type* ty, ast::TextureDimension dim, const sem::Type*& T) {
bool match_texture(MatchState&,
const sem::Type* ty,
ast::TextureDimension dim,
const sem::Type*& T) {
if (ty->Is<Any>()) {
T = ty;
return true;
@ -609,8 +623,9 @@ bool match_texture(const sem::Type* ty, ast::TextureDimension dim, const sem::Ty
#define JOIN(a, b) a##b
#define DECLARE_SAMPLED_TEXTURE(suffix, dim) \
bool JOIN(match_texture_, suffix)(const sem::Type* ty, const sem::Type*& T) { \
return match_texture(ty, dim, T); \
bool JOIN(match_texture_, suffix)(MatchState & state, const sem::Type* ty, \
const sem::Type*& T) { \
return match_texture(state, ty, dim, T); \
} \
const sem::SampledTexture* JOIN(build_texture_, suffix)(MatchState & state, \
const sem::Type* T) { \
@ -625,7 +640,8 @@ DECLARE_SAMPLED_TEXTURE(cube, ast::TextureDimension::kCube)
DECLARE_SAMPLED_TEXTURE(cube_array, ast::TextureDimension::kCubeArray)
#undef DECLARE_SAMPLED_TEXTURE
bool match_texture_multisampled(const sem::Type* ty,
bool match_texture_multisampled(MatchState&,
const sem::Type* ty,
ast::TextureDimension dim,
const sem::Type*& T) {
if (ty->Is<Any>()) {
@ -641,31 +657,32 @@ bool match_texture_multisampled(const sem::Type* ty,
return false;
}
#define DECLARE_MULTISAMPLED_TEXTURE(suffix, dim) \
bool JOIN(match_texture_multisampled_, suffix)(const sem::Type* ty, const sem::Type*& T) { \
return match_texture_multisampled(ty, dim, T); \
} \
const sem::MultisampledTexture* JOIN(build_texture_multisampled_, suffix)( \
MatchState & state, const sem::Type* T) { \
return state.builder.create<sem::MultisampledTexture>(dim, T); \
#define DECLARE_MULTISAMPLED_TEXTURE(suffix, dim) \
bool JOIN(match_texture_multisampled_, suffix)(MatchState & state, const sem::Type* ty, \
const sem::Type*& T) { \
return match_texture_multisampled(state, ty, dim, T); \
} \
const sem::MultisampledTexture* JOIN(build_texture_multisampled_, suffix)( \
MatchState & state, const sem::Type* T) { \
return state.builder.create<sem::MultisampledTexture>(dim, T); \
}
DECLARE_MULTISAMPLED_TEXTURE(2d, ast::TextureDimension::k2d)
#undef DECLARE_MULTISAMPLED_TEXTURE
bool match_texture_depth(const sem::Type* ty, ast::TextureDimension dim) {
bool match_texture_depth(MatchState&, const sem::Type* ty, ast::TextureDimension dim) {
if (ty->Is<Any>()) {
return true;
}
return ty->Is([&](const sem::DepthTexture* t) { return t->dim() == dim; });
}
#define DECLARE_DEPTH_TEXTURE(suffix, dim) \
bool JOIN(match_texture_depth_, suffix)(const sem::Type* ty) { \
return match_texture_depth(ty, dim); \
} \
const sem::DepthTexture* JOIN(build_texture_depth_, suffix)(MatchState & state) { \
return state.builder.create<sem::DepthTexture>(dim); \
#define DECLARE_DEPTH_TEXTURE(suffix, dim) \
bool JOIN(match_texture_depth_, suffix)(MatchState & state, const sem::Type* ty) { \
return match_texture_depth(state, ty, dim); \
} \
const sem::DepthTexture* JOIN(build_texture_depth_, suffix)(MatchState & state) { \
return state.builder.create<sem::DepthTexture>(dim); \
}
DECLARE_DEPTH_TEXTURE(2d, ast::TextureDimension::k2d)
@ -674,7 +691,7 @@ DECLARE_DEPTH_TEXTURE(cube, ast::TextureDimension::kCube)
DECLARE_DEPTH_TEXTURE(cube_array, ast::TextureDimension::kCubeArray)
#undef DECLARE_DEPTH_TEXTURE
bool match_texture_depth_multisampled_2d(const sem::Type* ty) {
bool match_texture_depth_multisampled_2d(MatchState&, const sem::Type* ty) {
if (ty->Is<Any>()) {
return true;
}
@ -687,7 +704,11 @@ sem::DepthMultisampledTexture* build_texture_depth_multisampled_2d(MatchState& s
return state.builder.create<sem::DepthMultisampledTexture>(ast::TextureDimension::k2d);
}
bool match_texture_storage(const sem::Type* ty, ast::TextureDimension dim, Number& F, Number& A) {
bool match_texture_storage(MatchState&,
const sem::Type* ty,
ast::TextureDimension dim,
Number& F,
Number& A) {
if (ty->Is<Any>()) {
F = Number::any;
A = Number::any;
@ -704,8 +725,9 @@ bool match_texture_storage(const sem::Type* ty, ast::TextureDimension dim, Numbe
}
#define DECLARE_STORAGE_TEXTURE(suffix, dim) \
bool JOIN(match_texture_storage_, suffix)(const sem::Type* ty, Number& F, Number& A) { \
return match_texture_storage(ty, dim, F, A); \
bool JOIN(match_texture_storage_, suffix)(MatchState & state, const sem::Type* ty, Number& F, \
Number& A) { \
return match_texture_storage(state, ty, dim, F, A); \
} \
const sem::StorageTexture* JOIN(build_texture_storage_, suffix)(MatchState & state, Number F, \
Number A) { \
@ -721,7 +743,7 @@ DECLARE_STORAGE_TEXTURE(2d_array, ast::TextureDimension::k2dArray)
DECLARE_STORAGE_TEXTURE(3d, ast::TextureDimension::k3d)
#undef DECLARE_STORAGE_TEXTURE
bool match_texture_external(const sem::Type* ty) {
bool match_texture_external(MatchState&, const sem::Type* ty) {
return ty->IsAnyOf<Any, sem::ExternalTexture>();
}
@ -732,14 +754,14 @@ const sem::ExternalTexture* build_texture_external(MatchState& state) {
// 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.
bool match_modf_result(const sem::Type* ty, const sem::Type*& T) {
bool match_modf_result(MatchState&, const sem::Type* ty, const sem::Type*& T) {
if (!ty->Is<Any>()) {
return false;
}
T = ty;
return true;
}
bool match_modf_result_vec(const sem::Type* ty, Number& N, const sem::Type*& T) {
bool match_modf_result_vec(MatchState&, const sem::Type* ty, Number& N, const sem::Type*& T) {
if (!ty->Is<Any>()) {
return false;
}
@ -747,14 +769,14 @@ bool match_modf_result_vec(const sem::Type* ty, Number& N, const sem::Type*& T)
T = ty;
return true;
}
bool match_frexp_result(const sem::Type* ty, const sem::Type*& T) {
bool match_frexp_result(MatchState&, const sem::Type* ty, const sem::Type*& T) {
if (!ty->Is<Any>()) {
return false;
}
T = ty;
return true;
}
bool match_frexp_result_vec(const sem::Type* ty, Number& N, const sem::Type*& T) {
bool match_frexp_result_vec(MatchState&, const sem::Type* ty, Number& N, const sem::Type*& T) {
if (!ty->Is<Any>()) {
return false;
}
@ -763,7 +785,7 @@ bool match_frexp_result_vec(const sem::Type* ty, Number& N, const sem::Type*& T)
return true;
}
bool match_atomic_compare_exchange_result(const sem::Type* ty, const sem::Type*& T) {
bool match_atomic_compare_exchange_result(MatchState&, const sem::Type* ty, const sem::Type*& T) {
if (ty->Is<Any>()) {
T = ty;
return true;
@ -970,6 +992,7 @@ class Impl : public IntrinsicTable {
Builtin Lookup(sem::BuiltinType builtin_type,
utils::VectorRef<const sem::Type*> args,
sem::EvaluationStage earliest_eval_stage,
const Source& source) override;
UnaryOperator Lookup(ast::UnaryOp op, const sem::Type* arg, const Source& source) override;
@ -1028,6 +1051,7 @@ class Impl : public IntrinsicTable {
IntrinsicPrototype MatchIntrinsic(const IntrinsicInfo& intrinsic,
const char* intrinsic_name,
utils::VectorRef<const sem::Type*> args,
sem::EvaluationStage earliest_eval_stage,
TemplateState templates,
OnNoMatch on_no_match) const;
@ -1040,6 +1064,7 @@ class Impl : public IntrinsicTable {
/// @returns the evaluated Candidate information.
Candidate ScoreOverload(const OverloadInfo* overload,
utils::VectorRef<const sem::Type*> args,
sem::EvaluationStage earliest_eval_stage,
TemplateState templates) const;
/// Performs overload resolution given the list of candidates, by ranking the conversions of
@ -1063,7 +1088,8 @@ class Impl : public IntrinsicTable {
/// @param matcher_indices pointer to a list of matcher indices
MatchState Match(TemplateState& templates,
const OverloadInfo* overload,
MatcherIndex const* matcher_indices) const;
MatcherIndex const* matcher_indices,
sem::EvaluationStage earliest_eval_stage) const;
// Prints the overload for emitting diagnostics
void PrintOverload(std::ostream& ss,
@ -1129,6 +1155,7 @@ Impl::Impl(ProgramBuilder& b) : builder(b) {}
Impl::Builtin Impl::Lookup(sem::BuiltinType builtin_type,
utils::VectorRef<const sem::Type*> args,
sem::EvaluationStage earliest_eval_stage,
const Source& source) {
const char* intrinsic_name = sem::str(builtin_type);
@ -1147,7 +1174,7 @@ Impl::Builtin Impl::Lookup(sem::BuiltinType builtin_type,
// Resolve the intrinsic overload
auto match = MatchIntrinsic(kBuiltins[static_cast<size_t>(builtin_type)], intrinsic_name, args,
TemplateState{}, on_no_match);
earliest_eval_stage, TemplateState{}, on_no_match);
if (!match.overload) {
return {};
}
@ -1213,7 +1240,7 @@ IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op,
// Resolve the intrinsic overload
auto match = MatchIntrinsic(kUnaryOperators[intrinsic_index], intrinsic_name, args,
TemplateState{}, on_no_match);
sem::EvaluationStage::kConstant, TemplateState{}, on_no_match);
if (!match.overload) {
return {};
}
@ -1290,7 +1317,7 @@ IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op,
// Resolve the intrinsic overload
auto match = MatchIntrinsic(kBinaryOperators[intrinsic_index], intrinsic_name, args,
TemplateState{}, on_no_match);
sem::EvaluationStage::kConstant, TemplateState{}, on_no_match);
if (!match.overload) {
return {};
}
@ -1345,7 +1372,7 @@ IntrinsicTable::CtorOrConv Impl::Lookup(CtorConvIntrinsic type,
// Resolve the intrinsic overload
auto match = MatchIntrinsic(kConstructorsAndConverters[static_cast<size_t>(type)], name, args,
templates, on_no_match);
sem::EvaluationStage::kConstant, templates, on_no_match);
if (!match.overload) {
return {};
}
@ -1383,6 +1410,7 @@ IntrinsicTable::CtorOrConv Impl::Lookup(CtorConvIntrinsic type,
IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
const char* intrinsic_name,
utils::VectorRef<const sem::Type*> args,
sem::EvaluationStage earliest_eval_stage,
TemplateState templates,
OnNoMatch on_no_match) const {
size_t num_matched = 0;
@ -1391,7 +1419,8 @@ IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
candidates.Reserve(intrinsic.num_overloads);
for (size_t overload_idx = 0; overload_idx < static_cast<size_t>(intrinsic.num_overloads);
overload_idx++) {
auto candidate = ScoreOverload(&intrinsic.overloads[overload_idx], args, templates);
auto candidate =
ScoreOverload(&intrinsic.overloads[overload_idx], args, earliest_eval_stage, templates);
if (candidate.score == 0) {
match_idx = overload_idx;
num_matched++;
@ -1423,7 +1452,8 @@ IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
const sem::Type* return_type = nullptr;
if (auto* indices = match.overload->return_matcher_indices) {
Any any;
return_type = Match(match.templates, match.overload, indices).Type(&any);
return_type =
Match(match.templates, match.overload, indices, earliest_eval_stage).Type(&any);
if (!return_type) {
TINT_ICE(Resolver, builder.Diagnostics()) << "MatchState.Match() returned null";
return {};
@ -1437,6 +1467,7 @@ IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
utils::VectorRef<const sem::Type*> args,
sem::EvaluationStage earliest_eval_stage,
TemplateState templates) const {
// Penalty weights for overload mismatching.
// This scoring is used to order the suggested overloads in diagnostic on overload mismatch, and
@ -1469,7 +1500,7 @@ Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
for (size_t p = 0; p < num_params; p++) {
auto& parameter = overload->parameters[p];
auto* indices = parameter.matcher_indices;
if (!Match(templates, overload, indices).Type(args[p]->UnwrapRef())) {
if (!Match(templates, overload, indices, earliest_eval_stage).Type(args[p]->UnwrapRef())) {
score += kMismatchedParamTypePenalty;
}
}
@ -1485,7 +1516,8 @@ Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
auto* matcher_index = &overload->template_types[ot].matcher_index;
if (*matcher_index != kNoMatcher) {
if (auto* template_type = templates.Type(ot)) {
if (auto* ty = Match(templates, overload, matcher_index).Type(template_type)) {
if (auto* ty = Match(templates, overload, matcher_index, earliest_eval_stage)
.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);
@ -1507,7 +1539,9 @@ Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
if (*matcher_index != kNoMatcher) {
auto template_num = templates.Num(on);
if (!template_num.IsValid() ||
!Match(templates, overload, matcher_index).Num(template_num).IsValid()) {
!Match(templates, overload, matcher_index, earliest_eval_stage)
.Num(template_num)
.IsValid()) {
score += kMismatchedTemplateNumberPenalty;
}
}
@ -1521,7 +1555,8 @@ Impl::Candidate Impl::ScoreOverload(const OverloadInfo* overload,
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());
auto* ty =
Match(templates, overload, indices, earliest_eval_stage).Type(args[p]->UnwrapRef());
parameters.Emplace(ty, parameter.usage);
}
}
@ -1596,8 +1631,9 @@ Impl::Candidate Impl::ResolveCandidate(Impl::Candidates&& candidates,
MatchState Impl::Match(TemplateState& templates,
const OverloadInfo* overload,
MatcherIndex const* matcher_indices) const {
return MatchState(builder, templates, matchers, overload, matcher_indices);
MatcherIndex const* matcher_indices,
sem::EvaluationStage earliest_eval_stage) const {
return MatchState(builder, templates, matchers, overload, matcher_indices, earliest_eval_stage);
}
void Impl::PrintOverload(std::ostream& ss,
@ -1605,6 +1641,8 @@ void Impl::PrintOverload(std::ostream& ss,
const char* intrinsic_name) const {
TemplateState templates;
auto earliest_eval_stage = sem::EvaluationStage::kConstant;
ss << intrinsic_name << "(";
for (size_t p = 0; p < overload->num_parameters; p++) {
auto& parameter = overload->parameters[p];
@ -1615,13 +1653,13 @@ void Impl::PrintOverload(std::ostream& ss,
ss << sem::str(parameter.usage) << ": ";
}
auto* indices = parameter.matcher_indices;
ss << Match(templates, overload, indices).TypeName();
ss << Match(templates, overload, indices, earliest_eval_stage).TypeName();
}
ss << ")";
if (overload->return_matcher_indices) {
ss << " -> ";
auto* indices = overload->return_matcher_indices;
ss << Match(templates, overload, indices).TypeName();
ss << Match(templates, overload, indices, earliest_eval_stage).TypeName();
}
bool first = true;
@ -1635,7 +1673,7 @@ void Impl::PrintOverload(std::ostream& ss,
separator();
ss << template_type.name;
auto* index = &template_type.matcher_index;
ss << " is " << Match(templates, overload, index).TypeName();
ss << " is " << Match(templates, overload, index, earliest_eval_stage).TypeName();
}
}
for (size_t i = 0; i < overload->num_template_numbers; i++) {
@ -1644,7 +1682,7 @@ void Impl::PrintOverload(std::ostream& ss,
separator();
ss << template_number.name;
auto* index = &template_number.matcher_index;
ss << " is " << Match(templates, overload, index).NumName();
ss << " is " << Match(templates, overload, index, earliest_eval_stage).NumName();
}
}
}

View File

@ -84,10 +84,17 @@ class IntrinsicTable {
/// if the builtin was not found.
/// @param type the builtin type
/// @param args the argument types passed to the builtin function
/// @param earliest_eval_stage the the earliest evaluation stage that a call to
/// the builtin can be made. This can alter the overloads considered.
/// For example, if the earliest evaluation stage is
/// `sem::EvaluationStage::kRuntime`, then only concrete argument types
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (sem::EvaluationStage::kConstant).
/// @param source the source of the builtin call
/// @return the semantic builtin if found, otherwise nullptr
virtual Builtin Lookup(sem::BuiltinType type,
utils::VectorRef<const sem::Type*> args,
sem::EvaluationStage earliest_eval_stage,
const Source& source) = 0;
/// Lookup looks for the unary op overload with the given signature, raising an error

View File

@ -38,7 +38,7 @@ class Bool : public TypeMatcher {
};
const sem::Type* Bool::Match(MatchState& state, const sem::Type* ty) const {
if (!match_bool(ty)) {
if (!match_bool(state, ty)) {
return nullptr;
}
return build_bool(state);
@ -64,7 +64,7 @@ class Ia : public TypeMatcher {
};
const sem::Type* Ia::Match(MatchState& state, const sem::Type* ty) const {
if (!match_ia(ty)) {
if (!match_ia(state, ty)) {
return nullptr;
}
return build_ia(state);
@ -92,7 +92,7 @@ class Fa : public TypeMatcher {
};
const sem::Type* Fa::Match(MatchState& state, const sem::Type* ty) const {
if (!match_fa(ty)) {
if (!match_fa(state, ty)) {
return nullptr;
}
return build_fa(state);
@ -120,7 +120,7 @@ class I32 : public TypeMatcher {
};
const sem::Type* I32::Match(MatchState& state, const sem::Type* ty) const {
if (!match_i32(ty)) {
if (!match_i32(state, ty)) {
return nullptr;
}
return build_i32(state);
@ -146,7 +146,7 @@ class U32 : public TypeMatcher {
};
const sem::Type* U32::Match(MatchState& state, const sem::Type* ty) const {
if (!match_u32(ty)) {
if (!match_u32(state, ty)) {
return nullptr;
}
return build_u32(state);
@ -172,7 +172,7 @@ class F32 : public TypeMatcher {
};
const sem::Type* F32::Match(MatchState& state, const sem::Type* ty) const {
if (!match_f32(ty)) {
if (!match_f32(state, ty)) {
return nullptr;
}
return build_f32(state);
@ -198,7 +198,7 @@ class F16 : public TypeMatcher {
};
const sem::Type* F16::Match(MatchState& state, const sem::Type* ty) const {
if (!match_f16(ty)) {
if (!match_f16(state, ty)) {
return nullptr;
}
return build_f16(state);
@ -225,7 +225,7 @@ class Vec2 : public TypeMatcher {
const sem::Type* Vec2::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_vec2(ty, T)) {
if (!match_vec2(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -257,7 +257,7 @@ class Vec3 : public TypeMatcher {
const sem::Type* Vec3::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_vec3(ty, T)) {
if (!match_vec3(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -289,7 +289,7 @@ class Vec4 : public TypeMatcher {
const sem::Type* Vec4::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_vec4(ty, T)) {
if (!match_vec4(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -321,7 +321,7 @@ class Mat2X2 : public TypeMatcher {
const sem::Type* Mat2X2::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_mat2x2(ty, T)) {
if (!match_mat2x2(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -353,7 +353,7 @@ class Mat2X3 : public TypeMatcher {
const sem::Type* Mat2X3::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_mat2x3(ty, T)) {
if (!match_mat2x3(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -385,7 +385,7 @@ class Mat2X4 : public TypeMatcher {
const sem::Type* Mat2X4::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_mat2x4(ty, T)) {
if (!match_mat2x4(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -417,7 +417,7 @@ class Mat3X2 : public TypeMatcher {
const sem::Type* Mat3X2::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_mat3x2(ty, T)) {
if (!match_mat3x2(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -449,7 +449,7 @@ class Mat3X3 : public TypeMatcher {
const sem::Type* Mat3X3::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_mat3x3(ty, T)) {
if (!match_mat3x3(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -481,7 +481,7 @@ class Mat3X4 : public TypeMatcher {
const sem::Type* Mat3X4::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_mat3x4(ty, T)) {
if (!match_mat3x4(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -513,7 +513,7 @@ class Mat4X2 : public TypeMatcher {
const sem::Type* Mat4X2::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_mat4x2(ty, T)) {
if (!match_mat4x2(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -545,7 +545,7 @@ class Mat4X3 : public TypeMatcher {
const sem::Type* Mat4X3::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_mat4x3(ty, T)) {
if (!match_mat4x3(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -577,7 +577,7 @@ class Mat4X4 : public TypeMatcher {
const sem::Type* Mat4X4::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_mat4x4(ty, T)) {
if (!match_mat4x4(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -610,7 +610,7 @@ class Vec : public TypeMatcher {
const sem::Type* Vec::Match(MatchState& state, const sem::Type* ty) const {
Number N = Number::invalid;
const sem::Type* T = nullptr;
if (!match_vec(ty, N, T)) {
if (!match_vec(state, ty, N, T)) {
return nullptr;
}
N = state.Num(N);
@ -651,7 +651,7 @@ const sem::Type* Mat::Match(MatchState& state, const sem::Type* ty) const {
Number N = Number::invalid;
Number M = Number::invalid;
const sem::Type* T = nullptr;
if (!match_mat(ty, N, M, T)) {
if (!match_mat(state, ty, N, M, T)) {
return nullptr;
}
N = state.Num(N);
@ -697,7 +697,7 @@ const sem::Type* Ptr::Match(MatchState& state, const sem::Type* ty) const {
Number S = Number::invalid;
const sem::Type* T = nullptr;
Number A = Number::invalid;
if (!match_ptr(ty, S, T, A)) {
if (!match_ptr(state, ty, S, T, A)) {
return nullptr;
}
S = state.Num(S);
@ -739,7 +739,7 @@ class Atomic : public TypeMatcher {
const sem::Type* Atomic::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_atomic(ty, T)) {
if (!match_atomic(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -771,7 +771,7 @@ class Array : public TypeMatcher {
const sem::Type* Array::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_array(ty, T)) {
if (!match_array(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -802,7 +802,7 @@ class Sampler : public TypeMatcher {
};
const sem::Type* Sampler::Match(MatchState& state, const sem::Type* ty) const {
if (!match_sampler(ty)) {
if (!match_sampler(state, ty)) {
return nullptr;
}
return build_sampler(state);
@ -828,7 +828,7 @@ class SamplerComparison : public TypeMatcher {
};
const sem::Type* SamplerComparison::Match(MatchState& state, const sem::Type* ty) const {
if (!match_sampler_comparison(ty)) {
if (!match_sampler_comparison(state, ty)) {
return nullptr;
}
return build_sampler_comparison(state);
@ -855,7 +855,7 @@ class Texture1D : public TypeMatcher {
const sem::Type* Texture1D::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_texture_1d(ty, T)) {
if (!match_texture_1d(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -887,7 +887,7 @@ class Texture2D : public TypeMatcher {
const sem::Type* Texture2D::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_texture_2d(ty, T)) {
if (!match_texture_2d(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -919,7 +919,7 @@ class Texture2DArray : public TypeMatcher {
const sem::Type* Texture2DArray::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_texture_2d_array(ty, T)) {
if (!match_texture_2d_array(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -951,7 +951,7 @@ class Texture3D : public TypeMatcher {
const sem::Type* Texture3D::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_texture_3d(ty, T)) {
if (!match_texture_3d(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -983,7 +983,7 @@ class TextureCube : public TypeMatcher {
const sem::Type* TextureCube::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_texture_cube(ty, T)) {
if (!match_texture_cube(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -1015,7 +1015,7 @@ class TextureCubeArray : public TypeMatcher {
const sem::Type* TextureCubeArray::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_texture_cube_array(ty, T)) {
if (!match_texture_cube_array(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -1047,7 +1047,7 @@ class TextureMultisampled2D : public TypeMatcher {
const sem::Type* TextureMultisampled2D::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_texture_multisampled_2d(ty, T)) {
if (!match_texture_multisampled_2d(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -1078,7 +1078,7 @@ class TextureDepth2D : public TypeMatcher {
};
const sem::Type* TextureDepth2D::Match(MatchState& state, const sem::Type* ty) const {
if (!match_texture_depth_2d(ty)) {
if (!match_texture_depth_2d(state, ty)) {
return nullptr;
}
return build_texture_depth_2d(state);
@ -1104,7 +1104,7 @@ class TextureDepth2DArray : public TypeMatcher {
};
const sem::Type* TextureDepth2DArray::Match(MatchState& state, const sem::Type* ty) const {
if (!match_texture_depth_2d_array(ty)) {
if (!match_texture_depth_2d_array(state, ty)) {
return nullptr;
}
return build_texture_depth_2d_array(state);
@ -1130,7 +1130,7 @@ class TextureDepthCube : public TypeMatcher {
};
const sem::Type* TextureDepthCube::Match(MatchState& state, const sem::Type* ty) const {
if (!match_texture_depth_cube(ty)) {
if (!match_texture_depth_cube(state, ty)) {
return nullptr;
}
return build_texture_depth_cube(state);
@ -1156,7 +1156,7 @@ class TextureDepthCubeArray : public TypeMatcher {
};
const sem::Type* TextureDepthCubeArray::Match(MatchState& state, const sem::Type* ty) const {
if (!match_texture_depth_cube_array(ty)) {
if (!match_texture_depth_cube_array(state, ty)) {
return nullptr;
}
return build_texture_depth_cube_array(state);
@ -1182,7 +1182,7 @@ class TextureDepthMultisampled2D : public TypeMatcher {
};
const sem::Type* TextureDepthMultisampled2D::Match(MatchState& state, const sem::Type* ty) const {
if (!match_texture_depth_multisampled_2d(ty)) {
if (!match_texture_depth_multisampled_2d(state, ty)) {
return nullptr;
}
return build_texture_depth_multisampled_2d(state);
@ -1210,7 +1210,7 @@ class TextureStorage1D : public TypeMatcher {
const sem::Type* TextureStorage1D::Match(MatchState& state, const sem::Type* ty) const {
Number F = Number::invalid;
Number A = Number::invalid;
if (!match_texture_storage_1d(ty, F, A)) {
if (!match_texture_storage_1d(state, ty, F, A)) {
return nullptr;
}
F = state.Num(F);
@ -1248,7 +1248,7 @@ class TextureStorage2D : public TypeMatcher {
const sem::Type* TextureStorage2D::Match(MatchState& state, const sem::Type* ty) const {
Number F = Number::invalid;
Number A = Number::invalid;
if (!match_texture_storage_2d(ty, F, A)) {
if (!match_texture_storage_2d(state, ty, F, A)) {
return nullptr;
}
F = state.Num(F);
@ -1286,7 +1286,7 @@ class TextureStorage2DArray : public TypeMatcher {
const sem::Type* TextureStorage2DArray::Match(MatchState& state, const sem::Type* ty) const {
Number F = Number::invalid;
Number A = Number::invalid;
if (!match_texture_storage_2d_array(ty, F, A)) {
if (!match_texture_storage_2d_array(state, ty, F, A)) {
return nullptr;
}
F = state.Num(F);
@ -1324,7 +1324,7 @@ class TextureStorage3D : public TypeMatcher {
const sem::Type* TextureStorage3D::Match(MatchState& state, const sem::Type* ty) const {
Number F = Number::invalid;
Number A = Number::invalid;
if (!match_texture_storage_3d(ty, F, A)) {
if (!match_texture_storage_3d(state, ty, F, A)) {
return nullptr;
}
F = state.Num(F);
@ -1360,7 +1360,7 @@ class TextureExternal : public TypeMatcher {
};
const sem::Type* TextureExternal::Match(MatchState& state, const sem::Type* ty) const {
if (!match_texture_external(ty)) {
if (!match_texture_external(state, ty)) {
return nullptr;
}
return build_texture_external(state);
@ -1387,7 +1387,7 @@ class ModfResult : public TypeMatcher {
const sem::Type* ModfResult::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_modf_result(ty, T)) {
if (!match_modf_result(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -1422,7 +1422,7 @@ class ModfResultVec : public TypeMatcher {
const sem::Type* ModfResultVec::Match(MatchState& state, const sem::Type* ty) const {
Number N = Number::invalid;
const sem::Type* T = nullptr;
if (!match_modf_result_vec(ty, N, T)) {
if (!match_modf_result_vec(state, ty, N, T)) {
return nullptr;
}
N = state.Num(N);
@ -1461,7 +1461,7 @@ class FrexpResult : public TypeMatcher {
const sem::Type* FrexpResult::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_frexp_result(ty, T)) {
if (!match_frexp_result(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -1496,7 +1496,7 @@ class FrexpResultVec : public TypeMatcher {
const sem::Type* FrexpResultVec::Match(MatchState& state, const sem::Type* ty) const {
Number N = Number::invalid;
const sem::Type* T = nullptr;
if (!match_frexp_result_vec(ty, N, T)) {
if (!match_frexp_result_vec(state, ty, N, T)) {
return nullptr;
}
N = state.Num(N);
@ -1535,7 +1535,7 @@ class AtomicCompareExchangeResult : public TypeMatcher {
const sem::Type* AtomicCompareExchangeResult::Match(MatchState& state, const sem::Type* ty) const {
const sem::Type* T = nullptr;
if (!match_atomic_compare_exchange_result(ty, T)) {
if (!match_atomic_compare_exchange_result(state, ty, T)) {
return nullptr;
}
T = state.Type(T);
@ -1567,25 +1567,25 @@ class AbstractOrScalar : public TypeMatcher {
};
const sem::Type* AbstractOrScalar::Match(MatchState& state, const sem::Type* ty) const {
if (match_ia(ty)) {
if (match_ia(state, ty)) {
return build_ia(state);
}
if (match_fa(ty)) {
if (match_fa(state, ty)) {
return build_fa(state);
}
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
if (match_u32(state, ty)) {
return build_u32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
if (match_f16(ty)) {
if (match_f16(state, ty)) {
return build_f16(state);
}
if (match_bool(ty)) {
if (match_bool(state, ty)) {
return build_bool(state);
}
return nullptr;
@ -1616,19 +1616,19 @@ class Scalar : public TypeMatcher {
};
const sem::Type* Scalar::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
if (match_u32(state, ty)) {
return build_u32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
if (match_f16(ty)) {
if (match_f16(state, ty)) {
return build_f16(state);
}
if (match_bool(ty)) {
if (match_bool(state, ty)) {
return build_bool(state);
}
return nullptr;
@ -1659,16 +1659,16 @@ class ScalarNoF32 : public TypeMatcher {
};
const sem::Type* ScalarNoF32::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
if (match_u32(state, ty)) {
return build_u32(state);
}
if (match_f16(ty)) {
if (match_f16(state, ty)) {
return build_f16(state);
}
if (match_bool(ty)) {
if (match_bool(state, ty)) {
return build_bool(state);
}
return nullptr;
@ -1699,16 +1699,16 @@ class ScalarNoF16 : public TypeMatcher {
};
const sem::Type* ScalarNoF16::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
if (match_u32(state, ty)) {
return build_u32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
if (match_bool(ty)) {
if (match_bool(state, ty)) {
return build_bool(state);
}
return nullptr;
@ -1739,16 +1739,16 @@ class ScalarNoI32 : public TypeMatcher {
};
const sem::Type* ScalarNoI32::Match(MatchState& state, const sem::Type* ty) const {
if (match_u32(ty)) {
if (match_u32(state, ty)) {
return build_u32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
if (match_f16(ty)) {
if (match_f16(state, ty)) {
return build_f16(state);
}
if (match_bool(ty)) {
if (match_bool(state, ty)) {
return build_bool(state);
}
return nullptr;
@ -1779,16 +1779,16 @@ class ScalarNoU32 : public TypeMatcher {
};
const sem::Type* ScalarNoU32::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
if (match_f16(ty)) {
if (match_f16(state, ty)) {
return build_f16(state);
}
if (match_bool(ty)) {
if (match_bool(state, ty)) {
return build_bool(state);
}
return nullptr;
@ -1819,16 +1819,16 @@ class ScalarNoBool : public TypeMatcher {
};
const sem::Type* ScalarNoBool::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
if (match_u32(state, ty)) {
return build_u32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
if (match_f16(ty)) {
if (match_f16(state, ty)) {
return build_f16(state);
}
return nullptr;
@ -1859,22 +1859,22 @@ class FiaFiu32F16 : public TypeMatcher {
};
const sem::Type* FiaFiu32F16::Match(MatchState& state, const sem::Type* ty) const {
if (match_ia(ty)) {
if (match_ia(state, ty)) {
return build_ia(state);
}
if (match_fa(ty)) {
if (match_fa(state, ty)) {
return build_fa(state);
}
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
if (match_u32(state, ty)) {
return build_u32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
if (match_f16(ty)) {
if (match_f16(state, ty)) {
return build_f16(state);
}
return nullptr;
@ -1905,19 +1905,19 @@ class FiaFi32F16 : public TypeMatcher {
};
const sem::Type* FiaFi32F16::Match(MatchState& state, const sem::Type* ty) const {
if (match_ia(ty)) {
if (match_ia(state, ty)) {
return build_ia(state);
}
if (match_fa(ty)) {
if (match_fa(state, ty)) {
return build_fa(state);
}
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
if (match_f16(ty)) {
if (match_f16(state, ty)) {
return build_f16(state);
}
return nullptr;
@ -1948,19 +1948,19 @@ class FiaFiu32 : public TypeMatcher {
};
const sem::Type* FiaFiu32::Match(MatchState& state, const sem::Type* ty) const {
if (match_ia(ty)) {
if (match_ia(state, ty)) {
return build_ia(state);
}
if (match_fa(ty)) {
if (match_fa(state, ty)) {
return build_fa(state);
}
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
if (match_u32(state, ty)) {
return build_u32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
return nullptr;
@ -1991,10 +1991,10 @@ class FaF32 : public TypeMatcher {
};
const sem::Type* FaF32::Match(MatchState& state, const sem::Type* ty) const {
if (match_fa(ty)) {
if (match_fa(state, ty)) {
return build_fa(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
return nullptr;
@ -2025,13 +2025,13 @@ class FaF32F16 : public TypeMatcher {
};
const sem::Type* FaF32F16::Match(MatchState& state, const sem::Type* ty) const {
if (match_fa(ty)) {
if (match_fa(state, ty)) {
return build_fa(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
if (match_f16(ty)) {
if (match_f16(state, ty)) {
return build_f16(state);
}
return nullptr;
@ -2062,13 +2062,13 @@ class IaIu32 : public TypeMatcher {
};
const sem::Type* IaIu32::Match(MatchState& state, const sem::Type* ty) const {
if (match_ia(ty)) {
if (match_ia(state, ty)) {
return build_ia(state);
}
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
if (match_u32(state, ty)) {
return build_u32(state);
}
return nullptr;
@ -2099,16 +2099,16 @@ class Fiu32F16 : public TypeMatcher {
};
const sem::Type* Fiu32F16::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
if (match_u32(state, ty)) {
return build_u32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
if (match_f16(ty)) {
if (match_f16(state, ty)) {
return build_f16(state);
}
return nullptr;
@ -2139,13 +2139,13 @@ class Fiu32 : public TypeMatcher {
};
const sem::Type* Fiu32::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
if (match_u32(state, ty)) {
return build_u32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
return nullptr;
@ -2176,13 +2176,13 @@ class Fi32F16 : public TypeMatcher {
};
const sem::Type* Fi32F16::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
if (match_f16(ty)) {
if (match_f16(state, ty)) {
return build_f16(state);
}
return nullptr;
@ -2213,10 +2213,10 @@ class Fi32 : public TypeMatcher {
};
const sem::Type* Fi32::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
return nullptr;
@ -2247,10 +2247,10 @@ class F32F16 : public TypeMatcher {
};
const sem::Type* F32F16::Match(MatchState& state, const sem::Type* ty) const {
if (match_f32(ty)) {
if (match_f32(state, ty)) {
return build_f32(state);
}
if (match_f16(ty)) {
if (match_f16(state, ty)) {
return build_f16(state);
}
return nullptr;
@ -2281,10 +2281,10 @@ class Iu32 : public TypeMatcher {
};
const sem::Type* Iu32::Match(MatchState& state, const sem::Type* ty) const {
if (match_i32(ty)) {
if (match_i32(state, ty)) {
return build_i32(state);
}
if (match_u32(ty)) {
if (match_u32(state, ty)) {
return build_u32(state);
}
return nullptr;

View File

@ -201,7 +201,7 @@ const sem::Type* {{$class}}::Match(MatchState& state, const sem::Type* ty) const
{{- range .TemplateParams }}
{{- template "DeclareLocalTemplateParam" . }}
{{- end }}
if (!match_{{TrimLeft .Name "_"}}(ty{{range .TemplateParams}}, {{.GetName}}{{end}})) {
if (!match_{{TrimLeft .Name "_"}}(state, ty{{range .TemplateParams}}, {{.GetName}}{{end}})) {
return nullptr;
}
{{- range .TemplateParams }}
@ -254,7 +254,7 @@ class {{$class}} : public TypeMatcher {
const sem::Type* {{$class}}::Match(MatchState& state, const sem::Type* ty) const {
{{- range .PrecedenceSortedTypes }}
if (match_{{.Name}}(ty)) {
if (match_{{.Name}}(state, ty)) {
return build_{{.Name}}(state);
}
{{- end }}

View File

@ -53,7 +53,8 @@ class IntrinsicTableTest : public testing::Test, public ProgramBuilder {
TEST_F(IntrinsicTableTest, MatchF32) {
auto* f32 = create<sem::F32>();
auto result = table->Lookup(BuiltinType::kCos, utils::Vector{f32}, Source{});
auto result = table->Lookup(BuiltinType::kCos, utils::Vector{f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kCos);
@ -64,7 +65,8 @@ TEST_F(IntrinsicTableTest, MatchF32) {
TEST_F(IntrinsicTableTest, MismatchF32) {
auto* i32 = create<sem::I32>();
auto result = table->Lookup(BuiltinType::kCos, utils::Vector{i32}, Source{});
auto result = table->Lookup(BuiltinType::kCos, utils::Vector{i32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@ -73,7 +75,8 @@ TEST_F(IntrinsicTableTest, MatchU32) {
auto* f32 = create<sem::F32>();
auto* u32 = create<sem::U32>();
auto* vec2_f32 = create<sem::Vector>(f32, 2u);
auto result = table->Lookup(BuiltinType::kUnpack2x16float, utils::Vector{u32}, Source{});
auto result = table->Lookup(BuiltinType::kUnpack2x16float, utils::Vector{u32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kUnpack2x16float);
@ -84,7 +87,8 @@ TEST_F(IntrinsicTableTest, MatchU32) {
TEST_F(IntrinsicTableTest, MismatchU32) {
auto* f32 = create<sem::F32>();
auto result = table->Lookup(BuiltinType::kUnpack2x16float, utils::Vector{f32}, Source{});
auto result = table->Lookup(BuiltinType::kUnpack2x16float, utils::Vector{f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@ -94,7 +98,8 @@ TEST_F(IntrinsicTableTest, MatchI32) {
auto* i32 = create<sem::I32>();
auto* vec4_f32 = create<sem::Vector>(f32, 4u);
auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, i32, i32}, Source{});
auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, i32, i32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
@ -111,14 +116,16 @@ TEST_F(IntrinsicTableTest, MatchI32) {
TEST_F(IntrinsicTableTest, MismatchI32) {
auto* f32 = create<sem::F32>();
auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, f32}, Source{});
auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
TEST_F(IntrinsicTableTest, MatchIU32AsI32) {
auto* i32 = create<sem::I32>();
auto result = table->Lookup(BuiltinType::kCountOneBits, utils::Vector{i32}, Source{});
auto result = table->Lookup(BuiltinType::kCountOneBits, utils::Vector{i32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kCountOneBits);
@ -129,7 +136,8 @@ TEST_F(IntrinsicTableTest, MatchIU32AsI32) {
TEST_F(IntrinsicTableTest, MatchIU32AsU32) {
auto* u32 = create<sem::U32>();
auto result = table->Lookup(BuiltinType::kCountOneBits, utils::Vector{u32}, Source{});
auto result = table->Lookup(BuiltinType::kCountOneBits, utils::Vector{u32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kCountOneBits);
@ -140,14 +148,16 @@ TEST_F(IntrinsicTableTest, MatchIU32AsU32) {
TEST_F(IntrinsicTableTest, MismatchIU32) {
auto* f32 = create<sem::F32>();
auto result = table->Lookup(BuiltinType::kCountOneBits, utils::Vector{f32}, Source{});
auto result = table->Lookup(BuiltinType::kCountOneBits, utils::Vector{f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
TEST_F(IntrinsicTableTest, MatchFIU32AsI32) {
auto* i32 = create<sem::I32>();
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{i32, i32, i32}, Source{});
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{i32, i32, i32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
@ -160,7 +170,8 @@ TEST_F(IntrinsicTableTest, MatchFIU32AsI32) {
TEST_F(IntrinsicTableTest, MatchFIU32AsU32) {
auto* u32 = create<sem::U32>();
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{u32, u32, u32}, Source{});
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{u32, u32, u32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
@ -173,7 +184,8 @@ TEST_F(IntrinsicTableTest, MatchFIU32AsU32) {
TEST_F(IntrinsicTableTest, MatchFIU32AsF32) {
auto* f32 = create<sem::F32>();
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{f32, f32, f32}, Source{});
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{f32, f32, f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
@ -186,7 +198,8 @@ TEST_F(IntrinsicTableTest, MatchFIU32AsF32) {
TEST_F(IntrinsicTableTest, MismatchFIU32) {
auto* bool_ = create<sem::Bool>();
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{bool_, bool_, bool_}, Source{});
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{bool_, bool_, bool_},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@ -194,7 +207,8 @@ TEST_F(IntrinsicTableTest, MismatchFIU32) {
TEST_F(IntrinsicTableTest, MatchBool) {
auto* f32 = create<sem::F32>();
auto* bool_ = create<sem::Bool>();
auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, bool_}, Source{});
auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, bool_},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect);
@ -207,7 +221,8 @@ TEST_F(IntrinsicTableTest, MatchBool) {
TEST_F(IntrinsicTableTest, MismatchBool) {
auto* f32 = create<sem::F32>();
auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, f32}, Source{});
auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@ -217,7 +232,8 @@ TEST_F(IntrinsicTableTest, MatchPointer) {
auto* atomicI32 = create<sem::Atomic>(i32);
auto* ptr =
create<sem::Pointer>(atomicI32, ast::AddressSpace::kWorkgroup, ast::Access::kReadWrite);
auto result = table->Lookup(BuiltinType::kAtomicLoad, utils::Vector{ptr}, Source{});
auto result = table->Lookup(BuiltinType::kAtomicLoad, utils::Vector{ptr},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kAtomicLoad);
@ -229,7 +245,8 @@ TEST_F(IntrinsicTableTest, MatchPointer) {
TEST_F(IntrinsicTableTest, MismatchPointer) {
auto* i32 = create<sem::I32>();
auto* atomicI32 = create<sem::Atomic>(i32);
auto result = table->Lookup(BuiltinType::kAtomicLoad, utils::Vector{atomicI32}, Source{});
auto result = table->Lookup(BuiltinType::kAtomicLoad, utils::Vector{atomicI32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@ -237,7 +254,8 @@ TEST_F(IntrinsicTableTest, MismatchPointer) {
TEST_F(IntrinsicTableTest, MatchArray) {
auto* arr = create<sem::Array>(create<sem::U32>(), sem::RuntimeArrayCount{}, 4u, 4u, 4u, 4u);
auto* arr_ptr = create<sem::Pointer>(arr, ast::AddressSpace::kStorage, ast::Access::kReadWrite);
auto result = table->Lookup(BuiltinType::kArrayLength, utils::Vector{arr_ptr}, Source{});
auto result = table->Lookup(BuiltinType::kArrayLength, utils::Vector{arr_ptr},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kArrayLength);
@ -250,7 +268,8 @@ TEST_F(IntrinsicTableTest, MatchArray) {
TEST_F(IntrinsicTableTest, MismatchArray) {
auto* f32 = create<sem::F32>();
auto result = table->Lookup(BuiltinType::kArrayLength, utils::Vector{f32}, Source{});
auto result = table->Lookup(BuiltinType::kArrayLength, utils::Vector{f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@ -261,8 +280,8 @@ TEST_F(IntrinsicTableTest, MatchSampler) {
auto* vec4_f32 = create<sem::Vector>(f32, 4u);
auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
auto result =
table->Lookup(BuiltinType::kTextureSample, utils::Vector{tex, sampler, vec2_f32}, Source{});
auto result = table->Lookup(BuiltinType::kTextureSample, utils::Vector{tex, sampler, vec2_f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureSample);
@ -280,8 +299,8 @@ TEST_F(IntrinsicTableTest, MismatchSampler) {
auto* f32 = create<sem::F32>();
auto* vec2_f32 = create<sem::Vector>(f32, 2u);
auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
auto result =
table->Lookup(BuiltinType::kTextureSample, utils::Vector{tex, f32, vec2_f32}, Source{});
auto result = table->Lookup(BuiltinType::kTextureSample, utils::Vector{tex, f32, vec2_f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@ -292,8 +311,8 @@ TEST_F(IntrinsicTableTest, MatchSampledTexture) {
auto* vec2_i32 = create<sem::Vector>(i32, 2u);
auto* vec4_f32 = create<sem::Vector>(f32, 4u);
auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
auto result =
table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32}, Source{});
auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
@ -313,8 +332,8 @@ TEST_F(IntrinsicTableTest, MatchMultisampledTexture) {
auto* vec2_i32 = create<sem::Vector>(i32, 2u);
auto* vec4_f32 = create<sem::Vector>(f32, 4u);
auto* tex = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
auto result =
table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32}, Source{});
auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
@ -333,8 +352,8 @@ TEST_F(IntrinsicTableTest, MatchDepthTexture) {
auto* i32 = create<sem::I32>();
auto* vec2_i32 = create<sem::Vector>(i32, 2u);
auto* tex = create<sem::DepthTexture>(ast::TextureDimension::k2d);
auto result =
table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32}, Source{});
auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
@ -353,8 +372,8 @@ TEST_F(IntrinsicTableTest, MatchDepthMultisampledTexture) {
auto* i32 = create<sem::I32>();
auto* vec2_i32 = create<sem::Vector>(i32, 2u);
auto* tex = create<sem::DepthMultisampledTexture>(ast::TextureDimension::k2d);
auto result =
table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32}, Source{});
auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
@ -374,7 +393,8 @@ TEST_F(IntrinsicTableTest, MatchExternalTexture) {
auto* vec2_i32 = create<sem::Vector>(i32, 2u);
auto* vec4_f32 = create<sem::Vector>(f32, 4u);
auto* tex = create<sem::ExternalTexture>();
auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32}, Source{});
auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
@ -395,8 +415,8 @@ TEST_F(IntrinsicTableTest, MatchWOStorageTexture) {
auto* tex = create<sem::StorageTexture>(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
ast::Access::kWrite, subtype);
auto result =
table->Lookup(BuiltinType::kTextureStore, utils::Vector{tex, vec2_i32, vec4_f32}, Source{});
auto result = table->Lookup(BuiltinType::kTextureStore, utils::Vector{tex, vec2_i32, vec4_f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureStore);
@ -414,7 +434,8 @@ TEST_F(IntrinsicTableTest, MismatchTexture) {
auto* f32 = create<sem::F32>();
auto* i32 = create<sem::I32>();
auto* vec2_i32 = create<sem::Vector>(i32, 2u);
auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{f32, vec2_i32}, Source{});
auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{f32, vec2_i32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@ -426,7 +447,7 @@ TEST_F(IntrinsicTableTest, ImplicitLoadOnReference) {
utils::Vector{
create<sem::Reference>(f32, ast::AddressSpace::kFunction, ast::Access::kReadWrite),
},
Source{});
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kCos);
@ -437,7 +458,8 @@ TEST_F(IntrinsicTableTest, ImplicitLoadOnReference) {
TEST_F(IntrinsicTableTest, MatchTemplateType) {
auto* f32 = create<sem::F32>();
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{f32, f32, f32}, Source{});
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{f32, f32, f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
@ -450,7 +472,8 @@ TEST_F(IntrinsicTableTest, MatchTemplateType) {
TEST_F(IntrinsicTableTest, MismatchTemplateType) {
auto* f32 = create<sem::F32>();
auto* u32 = create<sem::U32>();
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{f32, u32, f32}, Source{});
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{f32, u32, f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@ -458,8 +481,8 @@ TEST_F(IntrinsicTableTest, MismatchTemplateType) {
TEST_F(IntrinsicTableTest, MatchOpenSizeVector) {
auto* f32 = create<sem::F32>();
auto* vec2_f32 = create<sem::Vector>(f32, 2u);
auto result =
table->Lookup(BuiltinType::kClamp, utils::Vector{vec2_f32, vec2_f32, vec2_f32}, Source{});
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{vec2_f32, vec2_f32, vec2_f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
@ -474,8 +497,8 @@ TEST_F(IntrinsicTableTest, MismatchOpenSizeVector) {
auto* f32 = create<sem::F32>();
auto* u32 = create<sem::U32>();
auto* vec2_f32 = create<sem::Vector>(f32, 2u);
auto result =
table->Lookup(BuiltinType::kClamp, utils::Vector{vec2_f32, u32, vec2_f32}, Source{});
auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{vec2_f32, u32, vec2_f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@ -484,7 +507,8 @@ TEST_F(IntrinsicTableTest, MatchOpenSizeMatrix) {
auto* f32 = create<sem::F32>();
auto* vec3_f32 = create<sem::Vector>(f32, 3u);
auto* mat3_f32 = create<sem::Matrix>(vec3_f32, 3u);
auto result = table->Lookup(BuiltinType::kDeterminant, utils::Vector{mat3_f32}, Source{});
auto result = table->Lookup(BuiltinType::kDeterminant, utils::Vector{mat3_f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kDeterminant);
@ -497,16 +521,50 @@ TEST_F(IntrinsicTableTest, MismatchOpenSizeMatrix) {
auto* f32 = create<sem::F32>();
auto* vec2_f32 = create<sem::Vector>(f32, 2u);
auto* mat3x2_f32 = create<sem::Matrix>(vec2_f32, 3u);
auto result = table->Lookup(BuiltinType::kDeterminant, utils::Vector{mat3x2_f32}, Source{});
auto result = table->Lookup(BuiltinType::kDeterminant, utils::Vector{mat3x2_f32},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
// TODO(amaiorano): Enable this test when constexpr `select` is implemented.
TEST_F(IntrinsicTableTest, DISABLED_MatchDifferentArgsElementType_ConstantEval) {
auto* af = create<sem::AbstractFloat>();
auto* bool_ = create<sem::Bool>();
auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{af, af, bool_},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect);
EXPECT_EQ(result.sem->ReturnType(), af);
ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_EQ(result.sem->Parameters()[0]->Type(), af);
EXPECT_EQ(result.sem->Parameters()[1]->Type(), af);
EXPECT_EQ(result.sem->Parameters()[2]->Type(), bool_);
}
TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_RuntimeEval) {
auto* af = create<sem::AbstractFloat>();
auto* bool_ref = create<sem::Reference>(create<sem::Bool>(), ast::AddressSpace::kFunction,
ast::Access::kReadWrite);
auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{af, af, bool_ref},
sem::EvaluationStage::kRuntime, Source{});
ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect);
EXPECT_TRUE(result.sem->ReturnType()->Is<sem::F32>());
ASSERT_EQ(result.sem->Parameters().Length(), 3u);
EXPECT_TRUE(result.sem->Parameters()[0]->Type()->Is<sem::F32>());
EXPECT_TRUE(result.sem->Parameters()[1]->Type()->Is<sem::F32>());
EXPECT_TRUE(result.sem->Parameters()[2]->Type()->Is<sem::Bool>());
}
TEST_F(IntrinsicTableTest, OverloadOrderByNumberOfParameters) {
// None of the arguments match, so expect the overloads with 2 parameters to
// come first
auto* bool_ = create<sem::Bool>();
table->Lookup(BuiltinType::kTextureDimensions, utils::Vector{bool_, bool_}, Source{});
table->Lookup(BuiltinType::kTextureDimensions, utils::Vector{bool_, bool_},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(Diagnostics().str(),
R"(error: no matching call to textureDimensions(bool, bool)
@ -544,7 +602,8 @@ TEST_F(IntrinsicTableTest, OverloadOrderByNumberOfParameters) {
TEST_F(IntrinsicTableTest, OverloadOrderByMatchingParameter) {
auto* tex = create<sem::DepthTexture>(ast::TextureDimension::k2d);
auto* bool_ = create<sem::Bool>();
table->Lookup(BuiltinType::kTextureDimensions, utils::Vector{tex, bool_}, Source{});
table->Lookup(BuiltinType::kTextureDimensions, utils::Vector{tex, bool_},
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(Diagnostics().str(),
R"(error: no matching call to textureDimensions(texture_depth_2d, bool)
@ -583,15 +642,17 @@ TEST_F(IntrinsicTableTest, SameOverloadReturnsSameBuiltinPointer) {
auto* f32 = create<sem::F32>();
auto* vec2_f32 = create<sem::Vector>(create<sem::F32>(), 2u);
auto* bool_ = create<sem::Bool>();
auto a = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, bool_}, Source{});
auto a = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, bool_},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(a.sem, nullptr) << Diagnostics().str();
auto b = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, bool_}, Source{});
auto b = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, bool_},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(b.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
auto c =
table->Lookup(BuiltinType::kSelect, utils::Vector{vec2_f32, vec2_f32, bool_}, Source{});
auto c = table->Lookup(BuiltinType::kSelect, utils::Vector{vec2_f32, vec2_f32, bool_},
sem::EvaluationStage::kConstant, Source{});
ASSERT_NE(c.sem, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
@ -827,7 +888,8 @@ TEST_F(IntrinsicTableTest, Err257Arguments) { // crbug.com/1323605
auto* f32 = create<sem::F32>();
utils::Vector<const sem::Type*, 0> arg_tys;
arg_tys.Resize(257, f32);
auto result = table->Lookup(BuiltinType::kAbs, std::move(arg_tys), Source{});
auto result = table->Lookup(BuiltinType::kAbs, std::move(arg_tys),
sem::EvaluationStage::kConstant, Source{});
ASSERT_EQ(result.sem, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}
@ -1064,7 +1126,7 @@ TEST_P(IntrinsicTableAbstractTernaryTest, MatchClamp) {
auto* arg_b = GetParam().arg_b(*this);
auto* arg_c = GetParam().arg_c(*this);
auto builtin = table->Lookup(sem::BuiltinType::kClamp, utils::Vector{arg_a, arg_b, arg_c},
Source{{12, 34}});
sem::EvaluationStage::kConstant, Source{{12, 34}});
bool matched = builtin.sem != nullptr;
bool expected_match = GetParam().expected_match;
@ -1295,8 +1357,8 @@ TEST_P(IntrinsicTableAbstractTernaryTest_NonConstEval, MatchMix) {
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::kMix, utils::Vector{arg_a, arg_b, arg_c}, Source{{12, 34}});
auto builtin = table->Lookup(sem::BuiltinType::kMix, utils::Vector{arg_a, arg_b, arg_c},
sem::EvaluationStage::kConstant, Source{{12, 34}});
bool matched = builtin.sem != nullptr;
bool expected_match = GetParam().expected_match;

View File

@ -1999,10 +1999,15 @@ template <size_t N>
sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
sem::BuiltinType builtin_type,
utils::Vector<const sem::Expression*, N>& args) {
auto arg_stage = sem::EvaluationStage::kConstant;
for (auto* arg : args) {
arg_stage = sem::EarliestStage(arg_stage, arg->Stage());
}
IntrinsicTable::Builtin builtin;
{
auto arg_tys = utils::Transform(args, [](auto* arg) { return arg->Type(); });
builtin = intrinsic_table_->Lookup(builtin_type, arg_tys, expr->source);
builtin = intrinsic_table_->Lookup(builtin_type, arg_tys, arg_stage, expr->source);
if (!builtin.sem) {
return nullptr;
}
@ -2016,19 +2021,8 @@ sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
AddWarning("use of deprecated builtin", expr->source);
}
auto stage = builtin.sem->Stage();
if (stage == sem::EvaluationStage::kConstant) { // <-- Optimization
// If the builtin is not annotated with @const, then it can only be evaluated
// at runtime, in which case there's no point checking the evaluation stage of the
// arguments.
// The builtin is @const annotated. Check all arguments are also constant.
for (auto* arg : args) {
stage = sem::EarliestStage(stage, arg->Stage());
}
}
// If the builtin is @const, and all arguments have constant values, evaluate the builtin now.
auto stage = sem::EarliestStage(arg_stage, builtin.sem->Stage());
const sem::Constant* value = nullptr;
if (stage == sem::EvaluationStage::kConstant) {
auto const_args = ConvertArguments(args, builtin.sem);