tint: always pass in earliest evaluation stage to intrinsic table lookup
This fixes cases where input args of different type are mixed between constant and runtime evaluated. We initially did this only for builtins (https://dawn-review.googlesource.com/c/dawn/+/104545) to fix cases like `select`, but we also need this for binary operators like shift left/right that also take args of differing types. For consistency, this change also includes passing in the earliest evaluation stage when looking up unary ops and initializer/conversions. Bug: tint:1713 Change-Id: I196c67acfe767aa01aa45298d75cfc4d345d08ea Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/107140 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
6c8603cac1
commit
e0f78f924c
|
@ -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<const sem::Type*> 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<size_t, const char*> {
|
||||
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<size_t, const char*> {
|
||||
|
@ -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<const sem::Type*> 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<size_t>(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;
|
||||
|
|
|
@ -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<const sem::Type*> args,
|
||||
sem::EvaluationStage earliest_eval_stage,
|
||||
const Source& source) = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -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<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->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<sem::AbstractFloat>();
|
||||
auto* bool_ref = create<sem::Reference>(create<sem::Bool>(), 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<sem::F32>());
|
||||
ASSERT_EQ(result.sem->Parameters().Length(), 3u);
|
||||
|
@ -558,6 +560,33 @@ TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_RuntimeEval) {
|
|||
EXPECT_TRUE(result.sem->Parameters()[2]->Type()->Is<sem::Bool>());
|
||||
}
|
||||
|
||||
// TODO(amaiorano): Enable once const eval of left shift lands
|
||||
TEST_F(IntrinsicTableTest, DISABLED_MatchDifferentArgsElementType_Binary_ConstantEval) {
|
||||
auto* ai = create<sem::AbstractInt>();
|
||||
auto* u32 = create<sem::U32>();
|
||||
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<sem::AbstractInt>();
|
||||
auto* u32 = create<sem::U32>();
|
||||
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<sem::I32>());
|
||||
EXPECT_TRUE(result.lhs->Is<sem::I32>());
|
||||
EXPECT_TRUE(result.rhs->Is<sem::U32>());
|
||||
}
|
||||
|
||||
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<sem::I32>();
|
||||
auto* vec3_i32 = create<sem::Vector>(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<sem::Bool>();
|
||||
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<sem::AbstractInt>();
|
||||
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<sem::AbstractInt>();
|
||||
auto result = table->Lookup(ast::UnaryOp::kNegation, ai, sem::EvaluationStage::kRuntime,
|
||||
Source{{12, 34}});
|
||||
EXPECT_NE(result.result, ai);
|
||||
EXPECT_TRUE(result.result->Is<sem::I32>());
|
||||
EXPECT_EQ(Diagnostics().str(), "");
|
||||
}
|
||||
|
||||
TEST_F(IntrinsicTableTest, MatchBinaryOp) {
|
||||
auto* i32 = create<sem::I32>();
|
||||
auto* vec3_i32 = create<sem::Vector>(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<sem::F32>();
|
||||
auto* bool_ = create<sem::Bool>();
|
||||
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<sem::I32>();
|
||||
auto* vec3_i32 = create<sem::Vector>(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<sem::F32>();
|
||||
auto* bool_ = create<sem::Bool>();
|
||||
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<sem::I32>();
|
||||
auto* vec3_i32 = create<sem::Vector>(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<sem::TypeInitializer>());
|
||||
|
@ -764,7 +815,7 @@ TEST_F(IntrinsicTableTest, MatchTypeInitializerExplicit) {
|
|||
auto* i32 = create<sem::I32>();
|
||||
auto* vec3_i32 = create<sem::Vector>(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<sem::TypeInitializer>());
|
||||
|
@ -779,7 +830,7 @@ TEST_F(IntrinsicTableTest, MismatchTypeInitializerImplicit) {
|
|||
auto* i32 = create<sem::I32>();
|
||||
auto* f32 = create<sem::F32>();
|
||||
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<sem::I32>();
|
||||
auto* f32 = create<sem::F32>();
|
||||
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>(i32, f32, i32)
|
||||
|
@ -832,8 +883,9 @@ TEST_F(IntrinsicTableTest, MatchTypeInitializerImplicitMatFromVec) {
|
|||
auto* vec2_ai = create<sem::Vector>(create<sem::AbstractInt>(), 2u);
|
||||
auto* vec2_af = create<sem::Vector>(af, 2u);
|
||||
auto* mat2x2_af = create<sem::Matrix>(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<sem::TypeInitializer>());
|
||||
|
@ -843,13 +895,46 @@ TEST_F(IntrinsicTableTest, MatchTypeInitializerImplicitMatFromVec) {
|
|||
EXPECT_NE(result.const_eval_fn, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(IntrinsicTableTest, MatchTypeInitializer_ConstantEval) {
|
||||
auto* ai = create<sem::AbstractInt>();
|
||||
auto* vec3_ai = create<sem::Vector>(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<sem::TypeInitializer>());
|
||||
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<sem::AbstractInt>();
|
||||
auto result = table->Lookup(InitConvIntrinsic::kVec3, nullptr, utils::Vector{ai, ai, ai},
|
||||
sem::EvaluationStage::kRuntime, Source{{12, 34}});
|
||||
auto* i32 = create<sem::I32>();
|
||||
auto* vec3_i32 = create<sem::Vector>(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<sem::TypeInitializer>());
|
||||
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<sem::I32>();
|
||||
auto* vec3_i32 = create<sem::Vector>(i32, 3u);
|
||||
auto* f32 = create<sem::F32>();
|
||||
auto* vec3_f32 = create<sem::Vector>(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<sem::TypeConversion>());
|
||||
|
@ -860,8 +945,8 @@ TEST_F(IntrinsicTableTest, MatchTypeConversion) {
|
|||
TEST_F(IntrinsicTableTest, MismatchTypeConversion) {
|
||||
auto* arr = create<sem::Array>(create<sem::U32>(), sem::RuntimeArrayCount{}, 4u, 4u, 4u, 4u);
|
||||
auto* f32 = create<sem::F32>();
|
||||
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<f32>(array<u32>)
|
||||
|
@ -883,6 +968,39 @@ TEST_F(IntrinsicTableTest, MismatchTypeConversion) {
|
|||
)");
|
||||
}
|
||||
|
||||
TEST_F(IntrinsicTableTest, MatchTypeConversion_ConstantEval) {
|
||||
auto* ai = create<sem::AbstractInt>();
|
||||
auto* af = create<sem::AbstractFloat>();
|
||||
auto* vec3_ai = create<sem::Vector>(ai, 3u);
|
||||
auto* f32 = create<sem::F32>();
|
||||
auto* vec3_f32 = create<sem::Vector>(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<sem::TypeConversion>());
|
||||
ASSERT_EQ(result.target->Parameters().Length(), 1u);
|
||||
EXPECT_EQ(result.target->Parameters()[0]->Type(), vec3_ai);
|
||||
}
|
||||
|
||||
TEST_F(IntrinsicTableTest, MatchTypeConversion_RuntimeEval) {
|
||||
auto* ai = create<sem::AbstractInt>();
|
||||
auto* af = create<sem::AbstractFloat>();
|
||||
auto* vec3_ai = create<sem::Vector>(ai, 3u);
|
||||
auto* vec3_f32 = create<sem::Vector>(create<sem::F32>(), 3u);
|
||||
auto* vec3_i32 = create<sem::Vector>(create<sem::I32>(), 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<sem::TypeConversion>());
|
||||
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<sem::F32>();
|
||||
utils::Vector<const sem::Type*, 0> arg_tys;
|
||||
|
@ -900,7 +1018,8 @@ TEST_F(IntrinsicTableTest, OverloadResolution) {
|
|||
// The first should win overload resolution.
|
||||
auto* ai = create<sem::AbstractInt>();
|
||||
auto* i32 = create<sem::I32>();
|
||||
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<Case> {
|
|||
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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue