diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc index 7b0e3bc0cf..c76ca4de93 100644 --- a/src/tint/resolver/intrinsic_table.cc +++ b/src/tint/resolver/intrinsic_table.cc @@ -995,17 +995,22 @@ class Impl : public IntrinsicTable { sem::EvaluationStage earliest_eval_stage, const Source& source) override; - UnaryOperator Lookup(ast::UnaryOp op, const sem::Type* arg, const Source& source) override; + UnaryOperator Lookup(ast::UnaryOp op, + const sem::Type* arg, + sem::EvaluationStage earliest_eval_stage, + const Source& source) override; BinaryOperator Lookup(ast::BinaryOp op, const sem::Type* lhs, const sem::Type* rhs, + sem::EvaluationStage earliest_eval_stage, const Source& source, bool is_compound) override; InitOrConv Lookup(InitConvIntrinsic type, const sem::Type* template_arg, utils::VectorRef args, + sem::EvaluationStage earliest_eval_stage, const Source& source) override; private: @@ -1209,6 +1214,7 @@ Impl::Builtin Impl::Lookup(sem::BuiltinType builtin_type, IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op, const sem::Type* arg, + sem::EvaluationStage earliest_eval_stage, const Source& source) { auto [intrinsic_index, intrinsic_name] = [&]() -> std::pair { switch (op) { @@ -1240,7 +1246,7 @@ IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op, // Resolve the intrinsic overload auto match = MatchIntrinsic(kUnaryOperators[intrinsic_index], intrinsic_name, args, - sem::EvaluationStage::kConstant, TemplateState{}, on_no_match); + earliest_eval_stage, TemplateState{}, on_no_match); if (!match.overload) { return {}; } @@ -1255,6 +1261,7 @@ IntrinsicTable::UnaryOperator Impl::Lookup(ast::UnaryOp op, IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op, const sem::Type* lhs, const sem::Type* rhs, + sem::EvaluationStage earliest_eval_stage, const Source& source, bool is_compound) { auto [intrinsic_index, intrinsic_name] = [&]() -> std::pair { @@ -1317,7 +1324,7 @@ IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op, // Resolve the intrinsic overload auto match = MatchIntrinsic(kBinaryOperators[intrinsic_index], intrinsic_name, args, - sem::EvaluationStage::kConstant, TemplateState{}, on_no_match); + earliest_eval_stage, TemplateState{}, on_no_match); if (!match.overload) { return {}; } @@ -1333,6 +1340,7 @@ IntrinsicTable::BinaryOperator Impl::Lookup(ast::BinaryOp op, IntrinsicTable::InitOrConv Impl::Lookup(InitConvIntrinsic type, const sem::Type* template_arg, utils::VectorRef args, + sem::EvaluationStage earliest_eval_stage, const Source& source) { auto name = str(type); @@ -1372,7 +1380,7 @@ IntrinsicTable::InitOrConv Impl::Lookup(InitConvIntrinsic type, // Resolve the intrinsic overload auto match = MatchIntrinsic(kInitializersAndConverters[static_cast(type)], name, args, - sem::EvaluationStage::kConstant, templates, on_no_match); + earliest_eval_stage, templates, on_no_match); if (!match.overload) { return {}; } @@ -1641,6 +1649,7 @@ void Impl::PrintOverload(std::ostream& ss, const char* intrinsic_name) const { TemplateState templates; + // TODO(crbug.com/tint/1730): Use input evaluation stage to output only relevant overloads. auto earliest_eval_stage = sem::EvaluationStage::kConstant; ss << intrinsic_name; diff --git a/src/tint/resolver/intrinsic_table.h b/src/tint/resolver/intrinsic_table.h index bea1e3cea7..a873df946a 100644 --- a/src/tint/resolver/intrinsic_table.h +++ b/src/tint/resolver/intrinsic_table.h @@ -87,7 +87,7 @@ class IntrinsicTable { /// @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 + /// `sem::EvaluationStage::kRuntime`, then only overloads with 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 @@ -101,10 +101,19 @@ class IntrinsicTable { /// diagnostic if the operator was not found. /// @param op the unary operator /// @param arg the type of the expression passed to the operator + /// @param earliest_eval_stage the the earliest evaluation stage that a call to + /// the unary operator can be made. This can alter the overloads considered. + /// For example, if the earliest evaluation stage is + /// `sem::EvaluationStage::kRuntime`, then only overloads with 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 operator call /// @return the operator call target signature. If the operator was not found /// UnaryOperator::result will be nullptr. - virtual UnaryOperator Lookup(ast::UnaryOp op, const sem::Type* arg, const Source& source) = 0; + virtual UnaryOperator Lookup(ast::UnaryOp op, + const sem::Type* arg, + sem::EvaluationStage earliest_eval_stage, + const Source& source) = 0; /// Lookup looks for the binary op overload with the given signature, raising an error /// diagnostic if the operator was not found. @@ -112,12 +121,19 @@ class IntrinsicTable { /// @param lhs the LHS value type passed to the operator /// @param rhs the RHS value type passed to the operator /// @param source the source of the operator call + /// @param earliest_eval_stage the the earliest evaluation stage that a call to + /// the binary operator can be made. This can alter the overloads considered. + /// For example, if the earliest evaluation stage is + /// `sem::EvaluationStage::kRuntime`, then only overloads with concrete argument types + /// will be considered, as all abstract-numerics will have been materialized + /// after shader creation time (sem::EvaluationStage::kConstant). /// @param is_compound true if the binary operator is being used as a compound assignment /// @return the operator call target signature. If the operator was not found /// BinaryOperator::result will be nullptr. virtual BinaryOperator Lookup(ast::BinaryOp op, const sem::Type* lhs, const sem::Type* rhs, + sem::EvaluationStage earliest_eval_stage, const Source& source, bool is_compound) = 0; @@ -126,11 +142,19 @@ class IntrinsicTable { /// @param type the type being constructed or converted /// @param template_arg the optional template argument /// @param args the argument types passed to the initializer / conversion call + /// @param earliest_eval_stage the the earliest evaluation stage that a call to + /// the initializer or conversion can be made. This can alter the overloads considered. + /// For example, if the earliest evaluation stage is + /// `sem::EvaluationStage::kRuntime`, then only overloads with 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 call /// @return a sem::TypeInitializer, sem::TypeConversion or nullptr if nothing matched virtual InitOrConv Lookup(InitConvIntrinsic type, const sem::Type* template_arg, utils::VectorRef args, + sem::EvaluationStage earliest_eval_stage, const Source& source) = 0; }; diff --git a/src/tint/resolver/intrinsic_table_test.cc b/src/tint/resolver/intrinsic_table_test.cc index 1fb4d16242..4f2ed2e9bc 100644 --- a/src/tint/resolver/intrinsic_table_test.cc +++ b/src/tint/resolver/intrinsic_table_test.cc @@ -527,13 +527,14 @@ TEST_F(IntrinsicTableTest, MismatchOpenSizeMatrix) { ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call")); } -TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_ConstantEval) { +TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_Builtin_ConstantEval) { auto* af = create(); auto* bool_ = create(); 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->Stage(), sem::EvaluationStage::kConstant); EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect); EXPECT_EQ(result.sem->ReturnType(), af); ASSERT_EQ(result.sem->Parameters().Length(), 3u); @@ -542,7 +543,7 @@ TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_ConstantEval) { EXPECT_EQ(result.sem->Parameters()[2]->Type(), bool_); } -TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_RuntimeEval) { +TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_Builtin_RuntimeEval) { auto* af = create(); auto* bool_ref = create(create(), ast::AddressSpace::kFunction, ast::Access::kReadWrite); @@ -550,6 +551,7 @@ TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_RuntimeEval) { sem::EvaluationStage::kRuntime, Source{}); ASSERT_NE(result.sem, nullptr) << Diagnostics().str(); ASSERT_EQ(Diagnostics().str(), ""); + EXPECT_EQ(result.sem->Stage(), sem::EvaluationStage::kConstant); EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect); EXPECT_TRUE(result.sem->ReturnType()->Is()); ASSERT_EQ(result.sem->Parameters().Length(), 3u); @@ -558,6 +560,33 @@ TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_RuntimeEval) { EXPECT_TRUE(result.sem->Parameters()[2]->Type()->Is()); } +// TODO(amaiorano): Enable once const eval of left shift lands +TEST_F(IntrinsicTableTest, DISABLED_MatchDifferentArgsElementType_Binary_ConstantEval) { + auto* ai = create(); + auto* u32 = create(); + auto result = table->Lookup(ast::BinaryOp::kShiftLeft, ai, u32, sem::EvaluationStage::kConstant, + Source{}, false); + ASSERT_NE(result.result, nullptr) << Diagnostics().str(); + ASSERT_NE(result.const_eval_fn, nullptr) << Diagnostics().str(); + ASSERT_EQ(Diagnostics().str(), ""); + EXPECT_EQ(result.result, ai); + EXPECT_EQ(result.lhs, ai); + EXPECT_EQ(result.rhs, u32); +} + +TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_Binary_RuntimeEval) { + auto* ai = create(); + auto* u32 = create(); + auto result = table->Lookup(ast::BinaryOp::kShiftLeft, ai, u32, sem::EvaluationStage::kRuntime, + Source{}, false); + ASSERT_NE(result.result, nullptr) << Diagnostics().str(); + ASSERT_NE(result.const_eval_fn, nullptr) << Diagnostics().str(); + ASSERT_EQ(Diagnostics().str(), ""); + EXPECT_TRUE(result.result->Is()); + EXPECT_TRUE(result.lhs->Is()); + EXPECT_TRUE(result.rhs->Is()); +} + TEST_F(IntrinsicTableTest, OverloadOrderByNumberOfParameters) { // None of the arguments match, so expect the overloads with 2 parameters to // come first @@ -663,15 +692,16 @@ TEST_F(IntrinsicTableTest, SameOverloadReturnsSameBuiltinPointer) { TEST_F(IntrinsicTableTest, MatchUnaryOp) { auto* i32 = create(); auto* vec3_i32 = create(i32, 3u); - auto result = table->Lookup(ast::UnaryOp::kNegation, vec3_i32, Source{{12, 34}}); - EXPECT_EQ(result.result, vec3_i32); + auto result = table->Lookup(ast::UnaryOp::kNegation, vec3_i32, sem::EvaluationStage::kConstant, + Source{{12, 34}}); EXPECT_EQ(result.result, vec3_i32); EXPECT_EQ(Diagnostics().str(), ""); } TEST_F(IntrinsicTableTest, MismatchUnaryOp) { auto* bool_ = create(); - auto result = table->Lookup(ast::UnaryOp::kNegation, bool_, Source{{12, 34}}); + auto result = table->Lookup(ast::UnaryOp::kNegation, bool_, sem::EvaluationStage::kConstant, + Source{{12, 34}}); ASSERT_EQ(result.result, nullptr); EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator - (bool) @@ -681,10 +711,28 @@ TEST_F(IntrinsicTableTest, MismatchUnaryOp) { )"); } +TEST_F(IntrinsicTableTest, MatchUnaryOp_Constant) { + auto* ai = create(); + auto result = table->Lookup(ast::UnaryOp::kNegation, ai, sem::EvaluationStage::kConstant, + Source{{12, 34}}); + EXPECT_EQ(result.result, ai); + EXPECT_EQ(Diagnostics().str(), ""); +} + +TEST_F(IntrinsicTableTest, MatchUnaryOp_Runtime) { + auto* ai = create(); + auto result = table->Lookup(ast::UnaryOp::kNegation, ai, sem::EvaluationStage::kRuntime, + Source{{12, 34}}); + EXPECT_NE(result.result, ai); + EXPECT_TRUE(result.result->Is()); + EXPECT_EQ(Diagnostics().str(), ""); +} + TEST_F(IntrinsicTableTest, MatchBinaryOp) { auto* i32 = create(); auto* vec3_i32 = create(i32, 3u); - auto result = table->Lookup(ast::BinaryOp::kMultiply, i32, vec3_i32, Source{{12, 34}}, + auto result = table->Lookup(ast::BinaryOp::kMultiply, i32, vec3_i32, + sem::EvaluationStage::kConstant, Source{{12, 34}}, /* is_compound */ false); EXPECT_EQ(result.result, vec3_i32); EXPECT_EQ(result.lhs, i32); @@ -695,7 +743,8 @@ TEST_F(IntrinsicTableTest, MatchBinaryOp) { TEST_F(IntrinsicTableTest, MismatchBinaryOp) { auto* f32 = create(); auto* bool_ = create(); - auto result = table->Lookup(ast::BinaryOp::kMultiply, f32, bool_, Source{{12, 34}}, + auto result = table->Lookup(ast::BinaryOp::kMultiply, f32, bool_, + sem::EvaluationStage::kConstant, Source{{12, 34}}, /* is_compound */ false); ASSERT_EQ(result.result, nullptr); EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator * (f32, bool) @@ -716,7 +765,8 @@ TEST_F(IntrinsicTableTest, MismatchBinaryOp) { TEST_F(IntrinsicTableTest, MatchCompoundOp) { auto* i32 = create(); auto* vec3_i32 = create(i32, 3u); - auto result = table->Lookup(ast::BinaryOp::kMultiply, i32, vec3_i32, Source{{12, 34}}, + auto result = table->Lookup(ast::BinaryOp::kMultiply, i32, vec3_i32, + sem::EvaluationStage::kConstant, Source{{12, 34}}, /* is_compound */ true); EXPECT_EQ(result.result, vec3_i32); EXPECT_EQ(result.lhs, i32); @@ -727,7 +777,8 @@ TEST_F(IntrinsicTableTest, MatchCompoundOp) { TEST_F(IntrinsicTableTest, MismatchCompoundOp) { auto* f32 = create(); auto* bool_ = create(); - auto result = table->Lookup(ast::BinaryOp::kMultiply, f32, bool_, Source{{12, 34}}, + auto result = table->Lookup(ast::BinaryOp::kMultiply, f32, bool_, + sem::EvaluationStage::kConstant, Source{{12, 34}}, /* is_compound */ true); ASSERT_EQ(result.result, nullptr); EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching overload for operator *= (f32, bool) @@ -749,7 +800,7 @@ TEST_F(IntrinsicTableTest, MatchTypeInitializerImplicit) { auto* i32 = create(); auto* vec3_i32 = create(i32, 3u); auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{i32, i32, i32}, - Source{{12, 34}}); + sem::EvaluationStage::kConstant, Source{{12, 34}}); ASSERT_NE(result.target, nullptr); EXPECT_EQ(result.target->ReturnType(), vec3_i32); EXPECT_TRUE(result.target->Is()); @@ -764,7 +815,7 @@ TEST_F(IntrinsicTableTest, MatchTypeInitializerExplicit) { auto* i32 = create(); auto* vec3_i32 = create(i32, 3u); auto result = table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{i32, i32, i32}, - Source{{12, 34}}); + sem::EvaluationStage::kConstant, Source{{12, 34}}); ASSERT_NE(result.target, nullptr); EXPECT_EQ(result.target->ReturnType(), vec3_i32); EXPECT_TRUE(result.target->Is()); @@ -779,7 +830,7 @@ TEST_F(IntrinsicTableTest, MismatchTypeInitializerImplicit) { auto* i32 = create(); auto* f32 = create(); auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{i32, f32, i32}, - Source{{12, 34}}); + sem::EvaluationStage::kConstant, Source{{12, 34}}); ASSERT_EQ(result.target, nullptr); EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching initializer for vec3(i32, f32, i32) @@ -805,7 +856,7 @@ TEST_F(IntrinsicTableTest, MismatchTypeInitializerExplicit) { auto* i32 = create(); auto* f32 = create(); auto result = table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{i32, f32, i32}, - Source{{12, 34}}); + sem::EvaluationStage::kConstant, Source{{12, 34}}); ASSERT_EQ(result.target, nullptr); EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching initializer for vec3(i32, f32, i32) @@ -832,8 +883,9 @@ TEST_F(IntrinsicTableTest, MatchTypeInitializerImplicitMatFromVec) { auto* vec2_ai = create(create(), 2u); auto* vec2_af = create(af, 2u); auto* mat2x2_af = create(vec2_af, 2u); - auto result = table->Lookup(InitConvIntrinsic::kMat2x2, nullptr, - utils::Vector{vec2_ai, vec2_ai}, Source{{12, 34}}); + auto result = + table->Lookup(InitConvIntrinsic::kMat2x2, nullptr, utils::Vector{vec2_ai, vec2_ai}, + sem::EvaluationStage::kConstant, Source{{12, 34}}); ASSERT_NE(result.target, nullptr); EXPECT_TYPE(result.target->ReturnType(), mat2x2_af); EXPECT_TRUE(result.target->Is()); @@ -843,13 +895,46 @@ TEST_F(IntrinsicTableTest, MatchTypeInitializerImplicitMatFromVec) { EXPECT_NE(result.const_eval_fn, nullptr); } +TEST_F(IntrinsicTableTest, MatchTypeInitializer_ConstantEval) { + auto* ai = create(); + auto* vec3_ai = create(ai, 3u); + auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{ai, ai, ai}, + sem::EvaluationStage::kConstant, Source{{12, 34}}); + ASSERT_NE(result.target, nullptr); + EXPECT_EQ(result.target->Stage(), sem::EvaluationStage::kConstant); + EXPECT_EQ(result.target->ReturnType(), vec3_ai); + EXPECT_TRUE(result.target->Is()); + ASSERT_EQ(result.target->Parameters().Length(), 3u); + EXPECT_EQ(result.target->Parameters()[0]->Type(), ai); + EXPECT_EQ(result.target->Parameters()[1]->Type(), ai); + EXPECT_EQ(result.target->Parameters()[2]->Type(), ai); + EXPECT_NE(result.const_eval_fn, nullptr); +} + +TEST_F(IntrinsicTableTest, MatchTypeInitializer_RuntimeEval) { + auto* ai = create(); + auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{ai, ai, ai}, + sem::EvaluationStage::kRuntime, Source{{12, 34}}); + auto* i32 = create(); + auto* vec3_i32 = create(i32, 3u); + ASSERT_NE(result.target, nullptr); + EXPECT_EQ(result.target->Stage(), sem::EvaluationStage::kConstant); + EXPECT_EQ(result.target->ReturnType(), vec3_i32); + EXPECT_TRUE(result.target->Is()); + ASSERT_EQ(result.target->Parameters().Length(), 3u); + EXPECT_EQ(result.target->Parameters()[0]->Type(), i32); + EXPECT_EQ(result.target->Parameters()[1]->Type(), i32); + EXPECT_EQ(result.target->Parameters()[2]->Type(), i32); + EXPECT_NE(result.const_eval_fn, nullptr); +} + TEST_F(IntrinsicTableTest, MatchTypeConversion) { auto* i32 = create(); auto* vec3_i32 = create(i32, 3u); auto* f32 = create(); auto* vec3_f32 = create(f32, 3u); - auto result = - table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{vec3_f32}, Source{{12, 34}}); + auto result = table->Lookup(InitConvIntrinsic::kVec3, i32, utils::Vector{vec3_f32}, + sem::EvaluationStage::kConstant, Source{{12, 34}}); ASSERT_NE(result.target, nullptr); EXPECT_EQ(result.target->ReturnType(), vec3_i32); EXPECT_TRUE(result.target->Is()); @@ -860,8 +945,8 @@ TEST_F(IntrinsicTableTest, MatchTypeConversion) { TEST_F(IntrinsicTableTest, MismatchTypeConversion) { auto* arr = create(create(), sem::RuntimeArrayCount{}, 4u, 4u, 4u, 4u); auto* f32 = create(); - auto result = - table->Lookup(InitConvIntrinsic::kVec3, f32, utils::Vector{arr}, Source{{12, 34}}); + auto result = table->Lookup(InitConvIntrinsic::kVec3, f32, utils::Vector{arr}, + sem::EvaluationStage::kConstant, Source{{12, 34}}); ASSERT_EQ(result.target, nullptr); EXPECT_EQ(Diagnostics().str(), R"(12:34 error: no matching initializer for vec3(array) @@ -883,6 +968,39 @@ TEST_F(IntrinsicTableTest, MismatchTypeConversion) { )"); } +TEST_F(IntrinsicTableTest, MatchTypeConversion_ConstantEval) { + auto* ai = create(); + auto* af = create(); + auto* vec3_ai = create(ai, 3u); + auto* f32 = create(); + auto* vec3_f32 = create(f32, 3u); + auto result = table->Lookup(InitConvIntrinsic::kVec3, af, utils::Vector{vec3_ai}, + sem::EvaluationStage::kConstant, Source{{12, 34}}); + ASSERT_NE(result.target, nullptr); + EXPECT_EQ(result.target->Stage(), sem::EvaluationStage::kConstant); + // NOTE: Conversions are explicit, so there's no way to have it return abstracts + EXPECT_EQ(result.target->ReturnType(), vec3_f32); + EXPECT_TRUE(result.target->Is()); + ASSERT_EQ(result.target->Parameters().Length(), 1u); + EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_ai); +} + +TEST_F(IntrinsicTableTest, MatchTypeConversion_RuntimeEval) { + auto* ai = create(); + auto* af = create(); + auto* vec3_ai = create(ai, 3u); + auto* vec3_f32 = create(create(), 3u); + auto* vec3_i32 = create(create(), 3u); + auto result = table->Lookup(InitConvIntrinsic::kVec3, af, utils::Vector{vec3_ai}, + sem::EvaluationStage::kRuntime, Source{{12, 34}}); + ASSERT_NE(result.target, nullptr); + EXPECT_EQ(result.target->Stage(), sem::EvaluationStage::kConstant); + EXPECT_EQ(result.target->ReturnType(), vec3_f32); + EXPECT_TRUE(result.target->Is()); + ASSERT_EQ(result.target->Parameters().Length(), 1u); + EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_i32); +} + TEST_F(IntrinsicTableTest, Err257Arguments) { // crbug.com/1323605 auto* f32 = create(); utils::Vector arg_tys; @@ -900,7 +1018,8 @@ TEST_F(IntrinsicTableTest, OverloadResolution) { // The first should win overload resolution. auto* ai = create(); auto* i32 = create(); - auto result = table->Lookup(InitConvIntrinsic::kI32, nullptr, utils::Vector{ai}, Source{}); + auto result = table->Lookup(InitConvIntrinsic::kI32, nullptr, utils::Vector{ai}, + sem::EvaluationStage::kConstant, Source{}); ASSERT_NE(result.target, nullptr); EXPECT_EQ(result.target->ReturnType(), i32); EXPECT_EQ(result.target->Parameters().Length(), 1u); @@ -942,7 +1061,8 @@ struct IntrinsicTableAbstractBinaryTest : public ResolverTestWithParam { 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}}, + auto result = table->Lookup(ast::BinaryOp::kAdd, arg_lhs, arg_rhs, + sem::EvaluationStage::kConstant, Source{{12, 34}}, /* is_compound */ false); bool matched = result.result != nullptr; diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc index 7c655c136f..3d949a2865 100644 --- a/src/tint/resolver/resolver.cc +++ b/src/tint/resolver/resolver.cc @@ -1780,7 +1780,8 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) { // call for a InitConvIntrinsic with an optional template argument type. auto ct_init_or_conv = [&](InitConvIntrinsic ty, const sem::Type* template_arg) -> sem::Call* { auto arg_tys = utils::Transform(args, [](auto* arg) { return arg->Type(); }); - auto ctor_or_conv = intrinsic_table_->Lookup(ty, template_arg, arg_tys, expr->source); + auto ctor_or_conv = + intrinsic_table_->Lookup(ty, template_arg, arg_tys, args_stage, expr->source); if (!ctor_or_conv.target) { return nullptr; } @@ -2495,7 +2496,8 @@ sem::Expression* Resolver::Binary(const ast::BinaryExpression* expr) { auto* lhs_ty = lhs->Type()->UnwrapRef(); auto* rhs_ty = rhs->Type()->UnwrapRef(); - auto op = intrinsic_table_->Lookup(expr->op, lhs_ty, rhs_ty, expr->source, false); + auto stage = sem::EarliestStage(lhs->Stage(), rhs->Stage()); + auto op = intrinsic_table_->Lookup(expr->op, lhs_ty, rhs_ty, stage, expr->source, false); if (!op.result) { return nullptr; } @@ -2513,7 +2515,6 @@ sem::Expression* Resolver::Binary(const ast::BinaryExpression* expr) { } const sem::Constant* value = nullptr; - auto stage = sem::EarliestStage(lhs->Stage(), rhs->Stage()); if (stage == sem::EvaluationStage::kConstant) { if (op.const_eval_fn) { auto const_args = utils::Vector{lhs->ConstantValue(), rhs->ConstantValue()}; @@ -2595,7 +2596,8 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) { break; default: { - auto op = intrinsic_table_->Lookup(unary->op, expr_ty, unary->source); + stage = expr->Stage(); + auto op = intrinsic_table_->Lookup(unary->op, expr_ty, stage, unary->source); if (!op.result) { return nullptr; } @@ -2606,7 +2608,6 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) { return nullptr; } } - stage = expr->Stage(); if (stage == sem::EvaluationStage::kConstant) { if (op.const_eval_fn) { if (auto r = (const_eval_.*op.const_eval_fn)( @@ -3274,7 +3275,9 @@ sem::Statement* Resolver::CompoundAssignmentStatement( auto* lhs_ty = lhs->Type()->UnwrapRef(); auto* rhs_ty = rhs->Type()->UnwrapRef(); - auto* ty = intrinsic_table_->Lookup(stmt->op, lhs_ty, rhs_ty, stmt->source, true).result; + auto stage = sem::EarliestStage(lhs->Stage(), rhs->Stage()); + auto* ty = + intrinsic_table_->Lookup(stmt->op, lhs_ty, rhs_ty, stage, stmt->source, true).result; if (!ty) { return false; }