tint: Add sem::Expression
A new base class for sem::ValueExpression, which other types of expression can derive from. Example: sem::TypeExpression - an expression that resolves to a type. Bug: tint:1810 Change-Id: I90dfb66b265b67d9fdf0c04eb3dce2442c7e18ea Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/118404 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: James Price <jrprice@google.com> Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
ef1811a18b
commit
0b4a2f1f50
|
@ -368,6 +368,7 @@ libtint_source_set("libtint_syntax_tree_src") {
|
||||||
"sem/call.h",
|
"sem/call.h",
|
||||||
"sem/call_target.h",
|
"sem/call_target.h",
|
||||||
"sem/evaluation_stage.h",
|
"sem/evaluation_stage.h",
|
||||||
|
"sem/expression.h",
|
||||||
"sem/for_loop_statement.h",
|
"sem/for_loop_statement.h",
|
||||||
"sem/function.h",
|
"sem/function.h",
|
||||||
"sem/if_statement.h",
|
"sem/if_statement.h",
|
||||||
|
@ -763,6 +764,8 @@ libtint_source_set("libtint_sem_src") {
|
||||||
"sem/call_target.cc",
|
"sem/call_target.cc",
|
||||||
"sem/call_target.h",
|
"sem/call_target.h",
|
||||||
"sem/evaluation_stage.h",
|
"sem/evaluation_stage.h",
|
||||||
|
"sem/expression.cc",
|
||||||
|
"sem/expression.h",
|
||||||
"sem/for_loop_statement.cc",
|
"sem/for_loop_statement.cc",
|
||||||
"sem/for_loop_statement.h",
|
"sem/for_loop_statement.h",
|
||||||
"sem/function.cc",
|
"sem/function.cc",
|
||||||
|
|
|
@ -330,6 +330,8 @@ list(APPEND TINT_LIB_SRCS
|
||||||
sem/call.cc
|
sem/call.cc
|
||||||
sem/call.h
|
sem/call.h
|
||||||
sem/evaluation_stage.h
|
sem/evaluation_stage.h
|
||||||
|
sem/expression.cc
|
||||||
|
sem/expression.h
|
||||||
sem/for_loop_statement.cc
|
sem/for_loop_statement.cc
|
||||||
sem/for_loop_statement.h
|
sem/for_loop_statement.h
|
||||||
sem/function.cc
|
sem/function.cc
|
||||||
|
|
|
@ -51,7 +51,7 @@ MutationList MutationFinderWrapUnaryOperators::FindMutations(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto* expr_sem_node = program.Sem().Get(expr_ast_node);
|
const auto* expr_sem_node = program.Sem().GetVal(expr_ast_node);
|
||||||
|
|
||||||
// Transformation applies only when the semantic node for the given
|
// Transformation applies only when the semantic node for the given
|
||||||
// expression is present.
|
// expression is present.
|
||||||
|
|
|
@ -297,8 +297,8 @@ bool MutationChangeBinaryOperator::CanReplaceBinaryOperator(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the types of the operators.
|
// Get the types of the operators.
|
||||||
const auto* lhs_type = program.Sem().Get(binary_expr.lhs)->Type();
|
const auto* lhs_type = program.Sem().GetVal(binary_expr.lhs)->Type();
|
||||||
const auto* rhs_type = program.Sem().Get(binary_expr.rhs)->Type();
|
const auto* rhs_type = program.Sem().GetVal(binary_expr.rhs)->Type();
|
||||||
|
|
||||||
// If these are reference types, unwrap them to get the pointee type.
|
// If these are reference types, unwrap them to get the pointee type.
|
||||||
const type::Type* lhs_basic_type =
|
const type::Type* lhs_basic_type =
|
||||||
|
|
|
@ -50,7 +50,7 @@ bool MutationWrapUnaryOperator::IsApplicable(const tint::Program& program,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto* expression_sem_node = program.Sem().Get(expression_ast_node);
|
const auto* expression_sem_node = program.Sem().GetVal(expression_ast_node);
|
||||||
|
|
||||||
if (!expression_sem_node) {
|
if (!expression_sem_node) {
|
||||||
// Semantic information for the expression ast node is not present
|
// Semantic information for the expression ast node is not present
|
||||||
|
|
|
@ -900,7 +900,7 @@ void Inspector::GetOriginatingResources(std::array<const ast::Expression*, N> ex
|
||||||
utils::UniqueVector<const ast::CallExpression*, 8> callsites;
|
utils::UniqueVector<const ast::CallExpression*, 8> callsites;
|
||||||
|
|
||||||
for (size_t i = 0; i < N; i++) {
|
for (size_t i = 0; i < N; i++) {
|
||||||
const sem::Variable* root_ident = sem.Get(exprs[i])->RootIdentifier();
|
const sem::Variable* root_ident = sem.GetVal(exprs[i])->RootIdentifier();
|
||||||
if (auto* global = root_ident->As<sem::GlobalVariable>()) {
|
if (auto* global = root_ident->As<sem::GlobalVariable>()) {
|
||||||
globals[i] = global;
|
globals[i] = global;
|
||||||
} else if (auto* param = root_ident->As<sem::Parameter>()) {
|
} else if (auto* param = root_ident->As<sem::Parameter>()) {
|
||||||
|
|
|
@ -118,7 +118,7 @@ bool Program::IsValid() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
const type::Type* Program::TypeOf(const ast::Expression* expr) const {
|
const type::Type* Program::TypeOf(const ast::Expression* expr) const {
|
||||||
auto* sem = Sem().Get(expr);
|
auto* sem = Sem().GetVal(expr);
|
||||||
return sem ? sem->Type() : nullptr;
|
return sem ? sem->Type() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ void ProgramBuilder::AssertNotMoved() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
const type::Type* ProgramBuilder::TypeOf(const ast::Expression* expr) const {
|
const type::Type* ProgramBuilder::TypeOf(const ast::Expression* expr) const {
|
||||||
auto* sem = Sem().Get(expr);
|
auto* sem = Sem().GetVal(expr);
|
||||||
return sem ? sem->Type() : nullptr;
|
return sem ? sem->Type() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,7 @@ TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsGlobalVarUsedAsVariable
|
||||||
WrapInFunction(Decl(Var("v", use)));
|
WrapInFunction(Decl(Var("v", use)));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
auto* sem = Sem().Get(use)->UnwrapLoad()->As<sem::VariableUser>();
|
auto* sem = Sem().GetVal(use)->UnwrapLoad()->As<sem::VariableUser>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Variable(), Sem().Get(mix));
|
EXPECT_EQ(sem->Variable(), Sem().Get(mix));
|
||||||
}
|
}
|
||||||
|
|
|
@ -896,7 +896,7 @@ TEST_F(ResolverConstEvalTest, NotAndOrOfVecs) {
|
||||||
ASSERT_NE(value, nullptr);
|
ASSERT_NE(value, nullptr);
|
||||||
EXPECT_TYPE(value->Type(), sem->Type());
|
EXPECT_TYPE(value->Type(), sem->Type());
|
||||||
|
|
||||||
auto* expected_sem = Sem().Get(expected_expr);
|
auto* expected_sem = Sem().GetVal(expected_expr);
|
||||||
const constant::Value* expected_value = expected_sem->ConstantValue();
|
const constant::Value* expected_value = expected_sem->ConstantValue();
|
||||||
ASSERT_NE(expected_value, nullptr);
|
ASSERT_NE(expected_value, nullptr);
|
||||||
EXPECT_TYPE(expected_value->Type(), expected_sem->Type());
|
EXPECT_TYPE(expected_value->Type(), expected_sem->Type());
|
||||||
|
@ -1374,12 +1374,12 @@ static void ValidateAnd(const sem::Info& sem, const ast::BinaryExpression* binar
|
||||||
auto* lhs = binary->lhs;
|
auto* lhs = binary->lhs;
|
||||||
auto* rhs = binary->rhs;
|
auto* rhs = binary->rhs;
|
||||||
|
|
||||||
auto* lhs_sem = sem.Get(lhs);
|
auto* lhs_sem = sem.GetVal(lhs);
|
||||||
ASSERT_TRUE(lhs_sem->ConstantValue());
|
ASSERT_TRUE(lhs_sem->ConstantValue());
|
||||||
EXPECT_EQ(lhs_sem->ConstantValue()->ValueAs<bool>(), false);
|
EXPECT_EQ(lhs_sem->ConstantValue()->ValueAs<bool>(), false);
|
||||||
EXPECT_EQ(lhs_sem->Stage(), sem::EvaluationStage::kConstant);
|
EXPECT_EQ(lhs_sem->Stage(), sem::EvaluationStage::kConstant);
|
||||||
|
|
||||||
auto* rhs_sem = sem.Get(rhs);
|
auto* rhs_sem = sem.GetVal(rhs);
|
||||||
EXPECT_EQ(rhs_sem->ConstantValue(), nullptr);
|
EXPECT_EQ(rhs_sem->ConstantValue(), nullptr);
|
||||||
EXPECT_EQ(rhs_sem->Stage(), sem::EvaluationStage::kNotEvaluated);
|
EXPECT_EQ(rhs_sem->Stage(), sem::EvaluationStage::kNotEvaluated);
|
||||||
|
|
||||||
|
@ -1394,12 +1394,12 @@ static void ValidateOr(const sem::Info& sem, const ast::BinaryExpression* binary
|
||||||
auto* lhs = binary->lhs;
|
auto* lhs = binary->lhs;
|
||||||
auto* rhs = binary->rhs;
|
auto* rhs = binary->rhs;
|
||||||
|
|
||||||
auto* lhs_sem = sem.Get(lhs);
|
auto* lhs_sem = sem.GetVal(lhs);
|
||||||
ASSERT_TRUE(lhs_sem->ConstantValue());
|
ASSERT_TRUE(lhs_sem->ConstantValue());
|
||||||
EXPECT_EQ(lhs_sem->ConstantValue()->ValueAs<bool>(), true);
|
EXPECT_EQ(lhs_sem->ConstantValue()->ValueAs<bool>(), true);
|
||||||
EXPECT_EQ(lhs_sem->Stage(), sem::EvaluationStage::kConstant);
|
EXPECT_EQ(lhs_sem->Stage(), sem::EvaluationStage::kConstant);
|
||||||
|
|
||||||
auto* rhs_sem = sem.Get(rhs);
|
auto* rhs_sem = sem.GetVal(rhs);
|
||||||
EXPECT_EQ(rhs_sem->ConstantValue(), nullptr);
|
EXPECT_EQ(rhs_sem->ConstantValue(), nullptr);
|
||||||
EXPECT_EQ(rhs_sem->Stage(), sem::EvaluationStage::kNotEvaluated);
|
EXPECT_EQ(rhs_sem->Stage(), sem::EvaluationStage::kNotEvaluated);
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ TEST_P(ResolverConstEvalBitcastTest, Test) {
|
||||||
if (expected) {
|
if (expected) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(expr);
|
auto* sem = Sem().GetVal(expr);
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_TYPE(sem->Type(), target_sem_ty);
|
EXPECT_TYPE(sem->Type(), target_sem_ty);
|
||||||
ASSERT_NE(sem->ConstantValue(), nullptr);
|
ASSERT_NE(sem->ConstantValue(), nullptr);
|
||||||
|
|
|
@ -1712,7 +1712,7 @@ TEST_P(ResolverConstEvalArrayInitTest, Test) {
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(expr);
|
auto* sem = Sem().GetVal(expr);
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
auto* arr = sem->Type()->As<type::Array>();
|
auto* arr = sem->Type()->As<type::Array>();
|
||||||
ASSERT_NE(arr, nullptr);
|
ASSERT_NE(arr, nullptr);
|
||||||
|
|
|
@ -287,7 +287,7 @@ TEST_P(ResolverConstEvalArrayAccessTest, Test) {
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(expr);
|
auto* sem = Sem().GetVal(expr);
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
auto* arr = sem->Type()->As<type::Array>();
|
auto* arr = sem->Type()->As<type::Array>();
|
||||||
ASSERT_NE(arr, nullptr);
|
ASSERT_NE(arr, nullptr);
|
||||||
|
@ -362,7 +362,7 @@ TEST_P(ResolverConstEvalVectorAccessTest, Test) {
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(expr);
|
auto* sem = Sem().GetVal(expr);
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
auto* vec = sem->Type()->As<type::Vector>();
|
auto* vec = sem->Type()->As<type::Vector>();
|
||||||
ASSERT_NE(vec, nullptr);
|
ASSERT_NE(vec, nullptr);
|
||||||
|
|
|
@ -361,7 +361,7 @@ TEST_F(ResolverLoadTest, AddressOf) {
|
||||||
Let("l", AddressOf(ident)));
|
Let("l", AddressOf(ident)));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
auto* no_load = Sem().Get(ident);
|
auto* no_load = Sem().GetVal(ident);
|
||||||
ASSERT_NE(no_load, nullptr);
|
ASSERT_NE(no_load, nullptr);
|
||||||
EXPECT_TRUE(no_load->Type()->Is<type::Reference>()); // No load
|
EXPECT_TRUE(no_load->Type()->Is<type::Reference>()); // No load
|
||||||
}
|
}
|
||||||
|
|
|
@ -404,7 +404,7 @@ TEST_P(MaterializeAbstractNumericToConcreteType, Test) {
|
||||||
}
|
}
|
||||||
case Expectation::kNoMaterialize: {
|
case Expectation::kNoMaterialize: {
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
auto* sem = Sem().Get(abstract_expr);
|
auto* sem = Sem().GetVal(abstract_expr);
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_FALSE(sem->Is<sem::Materialize>());
|
EXPECT_FALSE(sem->Is<sem::Materialize>());
|
||||||
CheckTypesAndValues(sem, data.target_sem_ty(*this), data.materialized_value);
|
CheckTypesAndValues(sem, data.target_sem_ty(*this), data.materialized_value);
|
||||||
|
|
|
@ -1318,7 +1318,7 @@ sem::CaseStatement* Resolver::CaseStatement(const ast::CaseStatement* stmt, cons
|
||||||
if (!sel->IsDefault()) {
|
if (!sel->IsDefault()) {
|
||||||
// The sem statement was created in the switch when attempting to determine the
|
// The sem statement was created in the switch when attempting to determine the
|
||||||
// common type.
|
// common type.
|
||||||
auto* materialized = Materialize(sem_.Get(sel->expr), ty);
|
auto* materialized = Materialize(sem_.GetVal(sel->expr), ty);
|
||||||
if (!materialized) {
|
if (!materialized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1923,11 +1923,11 @@ utils::Result<utils::Vector<const constant::Value*, N>> Resolver::ConvertArgumen
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::ValueExpression* Resolver::IndexAccessor(const ast::IndexAccessorExpression* expr) {
|
sem::ValueExpression* Resolver::IndexAccessor(const ast::IndexAccessorExpression* expr) {
|
||||||
auto* idx = Load(Materialize(sem_.Get(expr->index)));
|
auto* idx = Load(Materialize(sem_.GetVal(expr->index)));
|
||||||
if (!idx) {
|
if (!idx) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
const auto* obj = sem_.Get(expr->object);
|
const auto* obj = sem_.GetVal(expr->object);
|
||||||
if (idx->Stage() != sem::EvaluationStage::kConstant) {
|
if (idx->Stage() != sem::EvaluationStage::kConstant) {
|
||||||
// If the index is non-constant, then the resulting expression is non-constant, so we'll
|
// If the index is non-constant, then the resulting expression is non-constant, so we'll
|
||||||
// have to materialize the object. For example, consider:
|
// have to materialize the object. For example, consider:
|
||||||
|
@ -1986,7 +1986,7 @@ sem::ValueExpression* Resolver::IndexAccessor(const ast::IndexAccessorExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::ValueExpression* Resolver::Bitcast(const ast::BitcastExpression* expr) {
|
sem::ValueExpression* Resolver::Bitcast(const ast::BitcastExpression* expr) {
|
||||||
auto* inner = Load(Materialize(sem_.Get(expr->expr)));
|
auto* inner = Load(Materialize(sem_.GetVal(expr->expr)));
|
||||||
if (!inner) {
|
if (!inner) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2031,7 +2031,7 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
||||||
auto args_stage = sem::EvaluationStage::kConstant;
|
auto args_stage = sem::EvaluationStage::kConstant;
|
||||||
sem::Behaviors arg_behaviors;
|
sem::Behaviors arg_behaviors;
|
||||||
for (size_t i = 0; i < expr->args.Length(); i++) {
|
for (size_t i = 0; i < expr->args.Length(); i++) {
|
||||||
auto* arg = sem_.Get(expr->args[i]);
|
auto* arg = sem_.GetVal(expr->args[i]);
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2780,13 +2780,17 @@ sem::ValueExpression* Resolver::Identifier(const ast::IdentifierExpression* expr
|
||||||
sem::ValueExpression* Resolver::MemberAccessor(const ast::MemberAccessorExpression* expr) {
|
sem::ValueExpression* Resolver::MemberAccessor(const ast::MemberAccessorExpression* expr) {
|
||||||
auto* structure = sem_.TypeOf(expr->object);
|
auto* structure = sem_.TypeOf(expr->object);
|
||||||
auto* storage_ty = structure->UnwrapRef();
|
auto* storage_ty = structure->UnwrapRef();
|
||||||
auto* object = sem_.Get(expr->object);
|
auto* object = sem_.GetVal(expr->object);
|
||||||
|
if (!object) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
auto* root_ident = object->RootIdentifier();
|
auto* root_ident = object->RootIdentifier();
|
||||||
|
|
||||||
const type::Type* ty = nullptr;
|
const type::Type* ty = nullptr;
|
||||||
|
|
||||||
// Object may be a side-effecting expression (e.g. function call).
|
// Object may be a side-effecting expression (e.g. function call).
|
||||||
bool has_side_effects = object && object->HasSideEffects();
|
bool has_side_effects = object->HasSideEffects();
|
||||||
|
|
||||||
Mark(expr->member);
|
Mark(expr->member);
|
||||||
|
|
||||||
|
@ -2909,8 +2913,8 @@ sem::ValueExpression* Resolver::MemberAccessor(const ast::MemberAccessorExpressi
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::ValueExpression* Resolver::Binary(const ast::BinaryExpression* expr) {
|
sem::ValueExpression* Resolver::Binary(const ast::BinaryExpression* expr) {
|
||||||
const auto* lhs = sem_.Get(expr->lhs);
|
const auto* lhs = sem_.GetVal(expr->lhs);
|
||||||
const auto* rhs = sem_.Get(expr->rhs);
|
const auto* rhs = sem_.GetVal(expr->rhs);
|
||||||
auto* lhs_ty = lhs->Type()->UnwrapRef();
|
auto* lhs_ty = lhs->Type()->UnwrapRef();
|
||||||
auto* rhs_ty = rhs->Type()->UnwrapRef();
|
auto* rhs_ty = rhs->Type()->UnwrapRef();
|
||||||
|
|
||||||
|
@ -2986,7 +2990,7 @@ sem::ValueExpression* Resolver::Binary(const ast::BinaryExpression* expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::ValueExpression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
sem::ValueExpression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
const auto* expr = sem_.Get(unary->expr);
|
const auto* expr = sem_.GetVal(unary->expr);
|
||||||
auto* expr_ty = expr->Type();
|
auto* expr_ty = expr->Type();
|
||||||
if (!expr_ty) {
|
if (!expr_ty) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -83,9 +83,12 @@ class TestHelper : public ProgramBuilder {
|
||||||
/// @return the resolved sem::Variable of the identifier, or nullptr if
|
/// @return the resolved sem::Variable of the identifier, or nullptr if
|
||||||
/// the expression did not resolve to a variable.
|
/// the expression did not resolve to a variable.
|
||||||
const sem::Variable* VarOf(const ast::Expression* expr) {
|
const sem::Variable* VarOf(const ast::Expression* expr) {
|
||||||
auto* sem_ident = Sem().Get(expr)->UnwrapLoad();
|
if (auto* sem = Sem().GetVal(expr)) {
|
||||||
auto* var_user = sem_ident ? sem_ident->As<sem::VariableUser>() : nullptr;
|
if (auto* var_user = As<sem::VariableUser>(sem->UnwrapLoad())) {
|
||||||
return var_user ? var_user->Variable() : nullptr;
|
return var_user->Variable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that all the users of the given variable are as expected
|
/// Checks that all the users of the given variable are as expected
|
||||||
|
|
|
@ -34,7 +34,7 @@ TEST_F(ResolverRootIdentifierTest, GlobalPrivateVar) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem_a = Sem().Get(a);
|
auto* sem_a = Sem().Get(a);
|
||||||
EXPECT_EQ(Sem().Get(expr)->RootIdentifier(), sem_a);
|
EXPECT_EQ(Sem().GetVal(expr)->RootIdentifier(), sem_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, GlobalWorkgroupVar) {
|
TEST_F(ResolverRootIdentifierTest, GlobalWorkgroupVar) {
|
||||||
|
@ -45,7 +45,7 @@ TEST_F(ResolverRootIdentifierTest, GlobalWorkgroupVar) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem_a = Sem().Get(a);
|
auto* sem_a = Sem().Get(a);
|
||||||
EXPECT_EQ(Sem().Get(expr)->RootIdentifier(), sem_a);
|
EXPECT_EQ(Sem().GetVal(expr)->RootIdentifier(), sem_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, GlobalStorageVar) {
|
TEST_F(ResolverRootIdentifierTest, GlobalStorageVar) {
|
||||||
|
@ -56,7 +56,7 @@ TEST_F(ResolverRootIdentifierTest, GlobalStorageVar) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem_a = Sem().Get(a);
|
auto* sem_a = Sem().Get(a);
|
||||||
EXPECT_EQ(Sem().Get(expr)->RootIdentifier(), sem_a);
|
EXPECT_EQ(Sem().GetVal(expr)->RootIdentifier(), sem_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, GlobalUniformVar) {
|
TEST_F(ResolverRootIdentifierTest, GlobalUniformVar) {
|
||||||
|
@ -67,7 +67,7 @@ TEST_F(ResolverRootIdentifierTest, GlobalUniformVar) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem_a = Sem().Get(a);
|
auto* sem_a = Sem().Get(a);
|
||||||
EXPECT_EQ(Sem().Get(expr)->RootIdentifier(), sem_a);
|
EXPECT_EQ(Sem().GetVal(expr)->RootIdentifier(), sem_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, GlobalTextureVar) {
|
TEST_F(ResolverRootIdentifierTest, GlobalTextureVar) {
|
||||||
|
@ -79,7 +79,7 @@ TEST_F(ResolverRootIdentifierTest, GlobalTextureVar) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem_a = Sem().Get(a);
|
auto* sem_a = Sem().Get(a);
|
||||||
EXPECT_EQ(Sem().Get(expr)->RootIdentifier(), sem_a);
|
EXPECT_EQ(Sem().GetVal(expr)->RootIdentifier(), sem_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, GlobalOverride) {
|
TEST_F(ResolverRootIdentifierTest, GlobalOverride) {
|
||||||
|
@ -90,7 +90,7 @@ TEST_F(ResolverRootIdentifierTest, GlobalOverride) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem_a = Sem().Get(a);
|
auto* sem_a = Sem().Get(a);
|
||||||
EXPECT_EQ(Sem().Get(expr)->RootIdentifier(), sem_a);
|
EXPECT_EQ(Sem().GetVal(expr)->RootIdentifier(), sem_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, GlobalConst) {
|
TEST_F(ResolverRootIdentifierTest, GlobalConst) {
|
||||||
|
@ -101,7 +101,7 @@ TEST_F(ResolverRootIdentifierTest, GlobalConst) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem_a = Sem().Get(a);
|
auto* sem_a = Sem().Get(a);
|
||||||
EXPECT_EQ(Sem().Get(expr)->RootIdentifier(), sem_a);
|
EXPECT_EQ(Sem().GetVal(expr)->RootIdentifier(), sem_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, FunctionVar) {
|
TEST_F(ResolverRootIdentifierTest, FunctionVar) {
|
||||||
|
@ -112,7 +112,7 @@ TEST_F(ResolverRootIdentifierTest, FunctionVar) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem_a = Sem().Get(a);
|
auto* sem_a = Sem().Get(a);
|
||||||
EXPECT_EQ(Sem().Get(expr)->RootIdentifier(), sem_a);
|
EXPECT_EQ(Sem().GetVal(expr)->RootIdentifier(), sem_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, FunctionLet) {
|
TEST_F(ResolverRootIdentifierTest, FunctionLet) {
|
||||||
|
@ -123,7 +123,7 @@ TEST_F(ResolverRootIdentifierTest, FunctionLet) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem_a = Sem().Get(a);
|
auto* sem_a = Sem().Get(a);
|
||||||
EXPECT_EQ(Sem().Get(expr)->RootIdentifier(), sem_a);
|
EXPECT_EQ(Sem().GetVal(expr)->RootIdentifier(), sem_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, Parameter) {
|
TEST_F(ResolverRootIdentifierTest, Parameter) {
|
||||||
|
@ -134,7 +134,7 @@ TEST_F(ResolverRootIdentifierTest, Parameter) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem_a = Sem().Get(a);
|
auto* sem_a = Sem().Get(a);
|
||||||
EXPECT_EQ(Sem().Get(expr)->RootIdentifier(), sem_a);
|
EXPECT_EQ(Sem().GetVal(expr)->RootIdentifier(), sem_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, PointerParameter) {
|
TEST_F(ResolverRootIdentifierTest, PointerParameter) {
|
||||||
|
@ -152,8 +152,8 @@ TEST_F(ResolverRootIdentifierTest, PointerParameter) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem_param = Sem().Get(param);
|
auto* sem_param = Sem().Get(param);
|
||||||
EXPECT_EQ(Sem().Get(expr_param)->RootIdentifier(), sem_param);
|
EXPECT_EQ(Sem().GetVal(expr_param)->RootIdentifier(), sem_param);
|
||||||
EXPECT_EQ(Sem().Get(expr_let)->RootIdentifier(), sem_param);
|
EXPECT_EQ(Sem().GetVal(expr_let)->RootIdentifier(), sem_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, VarCopyVar) {
|
TEST_F(ResolverRootIdentifierTest, VarCopyVar) {
|
||||||
|
@ -171,8 +171,8 @@ TEST_F(ResolverRootIdentifierTest, VarCopyVar) {
|
||||||
|
|
||||||
auto* sem_a = Sem().Get(a);
|
auto* sem_a = Sem().Get(a);
|
||||||
auto* sem_b = Sem().Get(b);
|
auto* sem_b = Sem().Get(b);
|
||||||
EXPECT_EQ(Sem().Get(expr_a)->RootIdentifier(), sem_a);
|
EXPECT_EQ(Sem().GetVal(expr_a)->RootIdentifier(), sem_a);
|
||||||
EXPECT_EQ(Sem().Get(expr_b)->RootIdentifier(), sem_b);
|
EXPECT_EQ(Sem().GetVal(expr_b)->RootIdentifier(), sem_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, LetCopyVar) {
|
TEST_F(ResolverRootIdentifierTest, LetCopyVar) {
|
||||||
|
@ -190,8 +190,8 @@ TEST_F(ResolverRootIdentifierTest, LetCopyVar) {
|
||||||
|
|
||||||
auto* sem_a = Sem().Get(a);
|
auto* sem_a = Sem().Get(a);
|
||||||
auto* sem_b = Sem().Get(b);
|
auto* sem_b = Sem().Get(b);
|
||||||
EXPECT_EQ(Sem().Get(expr_a)->RootIdentifier(), sem_a);
|
EXPECT_EQ(Sem().GetVal(expr_a)->RootIdentifier(), sem_a);
|
||||||
EXPECT_EQ(Sem().Get(expr_b)->RootIdentifier(), sem_b);
|
EXPECT_EQ(Sem().GetVal(expr_b)->RootIdentifier(), sem_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverRootIdentifierTest, ThroughIndexAccessor) {
|
TEST_F(ResolverRootIdentifierTest, ThroughIndexAccessor) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ std::string SemHelper::RawTypeNameOf(const type::Type* ty) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
type::Type* SemHelper::TypeOf(const ast::Expression* expr) const {
|
type::Type* SemHelper::TypeOf(const ast::Expression* expr) const {
|
||||||
auto* sem = Get(expr);
|
auto* sem = GetVal(expr);
|
||||||
return sem ? const_cast<type::Type*>(sem->Type()) : nullptr;
|
return sem ? const_cast<type::Type*>(sem->Type()) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,13 @@ class SemHelper {
|
||||||
~SemHelper();
|
~SemHelper();
|
||||||
|
|
||||||
/// Get is a helper for obtaining the semantic node for the given AST node.
|
/// Get is a helper for obtaining the semantic node for the given AST node.
|
||||||
|
/// Raises an ICE and returns `nullptr` if there is no semantic node associated with the AST
|
||||||
|
/// node.
|
||||||
/// @param ast the ast node to get the sem for
|
/// @param ast the ast node to get the sem for
|
||||||
/// @returns the sem node for the provided |ast|
|
/// @returns the sem node for @p ast
|
||||||
template <typename SEM = sem::Info::InferFromAST, typename AST_OR_TYPE = CastableBase>
|
template <typename SEM = sem::Info::InferFromAST, typename AST = ast::Node>
|
||||||
auto* Get(const AST_OR_TYPE* ast) const {
|
auto* Get(const AST* ast) const {
|
||||||
using T = sem::Info::GetResultType<SEM, AST_OR_TYPE>;
|
using T = sem::Info::GetResultType<SEM, AST>;
|
||||||
auto* sem = builder_->Sem().Get(ast);
|
auto* sem = builder_->Sem().Get(ast);
|
||||||
if (TINT_UNLIKELY(!sem)) {
|
if (TINT_UNLIKELY(!sem)) {
|
||||||
TINT_ICE(Resolver, builder_->Diagnostics())
|
TINT_ICE(Resolver, builder_->Diagnostics())
|
||||||
|
@ -49,6 +51,31 @@ class SemHelper {
|
||||||
return const_cast<T*>(As<T>(sem));
|
return const_cast<T*>(As<T>(sem));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// GetVal is a helper for obtaining the semantic sem::ValueExpression for the given AST node.
|
||||||
|
/// Raises an error diagnostic and returns `nullptr` if the semantic node is not a
|
||||||
|
/// sem::ValueExpression.
|
||||||
|
/// @param ast the ast node to get the sem for
|
||||||
|
/// @returns the sem node for @p ast
|
||||||
|
template <typename AST = ast::Node>
|
||||||
|
auto* GetVal(const AST* ast) const {
|
||||||
|
if constexpr (traits::IsTypeOrDerived<sem::SemanticNodeTypeFor<AST>,
|
||||||
|
sem::ValueExpression>) {
|
||||||
|
return Get(ast);
|
||||||
|
} else {
|
||||||
|
if (auto* sem = Get(ast); TINT_LIKELY(sem)) {
|
||||||
|
auto* val = sem->template As<sem::ValueExpression>();
|
||||||
|
if (TINT_LIKELY(val)) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
// TODO(crbug.com/tint/1810): Improve error
|
||||||
|
builder_->Diagnostics().add_error(diag::System::Resolver,
|
||||||
|
"required value expression, got something else",
|
||||||
|
ast->source);
|
||||||
|
}
|
||||||
|
return static_cast<sem::ValueExpression*>(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// @returns the resolved symbol (function, type or variable) for the given ast::Identifier or
|
/// @returns the resolved symbol (function, type or variable) for the given ast::Identifier or
|
||||||
/// ast::TypeName cast to the given semantic type.
|
/// ast::TypeName cast to the given semantic type.
|
||||||
/// @param node the node to retrieve
|
/// @param node the node to retrieve
|
||||||
|
|
|
@ -82,7 +82,7 @@ TEST_F(SideEffectsTest, VariableUser) {
|
||||||
WrapInFunction(var, expr);
|
WrapInFunction(var, expr);
|
||||||
|
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
auto* sem = Sem().Get(expr);
|
auto* sem = Sem().GetVal(expr);
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_TRUE(sem->UnwrapLoad()->Is<sem::VariableUser>());
|
EXPECT_TRUE(sem->UnwrapLoad()->Is<sem::VariableUser>());
|
||||||
EXPECT_FALSE(sem->HasSideEffects());
|
EXPECT_FALSE(sem->HasSideEffects());
|
||||||
|
|
|
@ -1141,9 +1141,11 @@ class UniformityGraph {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto* var_user = sem_.Get(ident)->Unwrap()->As<sem::VariableUser>();
|
|
||||||
auto* sem = var_user->Variable();
|
|
||||||
auto* node = CreateNode({NameFor(ident->identifier), "_ident_expr"}, ident);
|
auto* node = CreateNode({NameFor(ident->identifier), "_ident_expr"}, ident);
|
||||||
|
auto* sem_ident = sem_.GetVal(ident);
|
||||||
|
TINT_ASSERT(Resolver, sem_ident);
|
||||||
|
auto* var_user = sem_ident->Unwrap()->As<sem::VariableUser>();
|
||||||
|
auto* sem = var_user->Variable();
|
||||||
return Switch(
|
return Switch(
|
||||||
sem,
|
sem,
|
||||||
|
|
||||||
|
@ -1357,7 +1359,7 @@ class UniformityGraph {
|
||||||
expr,
|
expr,
|
||||||
|
|
||||||
[&](const ast::IdentifierExpression* i) {
|
[&](const ast::IdentifierExpression* i) {
|
||||||
auto* sem = sem_.Get(i)->UnwrapLoad()->As<sem::VariableUser>();
|
auto* sem = sem_.GetVal(i)->UnwrapLoad()->As<sem::VariableUser>();
|
||||||
if (sem->Variable()->Is<sem::GlobalVariable>()) {
|
if (sem->Variable()->Is<sem::GlobalVariable>()) {
|
||||||
return std::make_pair(cf, current_function_->may_be_non_uniform);
|
return std::make_pair(cf, current_function_->may_be_non_uniform);
|
||||||
} else if (auto* local = sem->Variable()->As<sem::LocalVariable>()) {
|
} else if (auto* local = sem->Variable()->As<sem::LocalVariable>()) {
|
||||||
|
@ -1452,7 +1454,7 @@ class UniformityGraph {
|
||||||
|
|
||||||
// For pointer arguments, create an additional node to represent the contents of that
|
// For pointer arguments, create an additional node to represent the contents of that
|
||||||
// pointer prior to the function call.
|
// pointer prior to the function call.
|
||||||
auto* sem_arg = sem_.Get(call->args[i]);
|
auto* sem_arg = sem_.GetVal(call->args[i]);
|
||||||
if (sem_arg->Type()->Is<type::Pointer>()) {
|
if (sem_arg->Type()->Is<type::Pointer>()) {
|
||||||
auto* arg_contents =
|
auto* arg_contents =
|
||||||
CreateNode({name, "_ptrarg_", std::to_string(i), "_contents"}, call);
|
CreateNode({name, "_ptrarg_", std::to_string(i), "_contents"}, call);
|
||||||
|
@ -1581,7 +1583,7 @@ class UniformityGraph {
|
||||||
|
|
||||||
// Capture the effects of other call parameters on the contents of this parameter
|
// Capture the effects of other call parameters on the contents of this parameter
|
||||||
// after the call returns.
|
// after the call returns.
|
||||||
auto* sem_arg = sem_.Get(call->args[i]);
|
auto* sem_arg = sem_.GetVal(call->args[i]);
|
||||||
if (sem_arg->Type()->Is<type::Pointer>()) {
|
if (sem_arg->Type()->Is<type::Pointer>()) {
|
||||||
auto* ptr_result =
|
auto* ptr_result =
|
||||||
CreateNode({name, "_ptrarg_", std::to_string(i), "_result"}, call);
|
CreateNode({name, "_ptrarg_", std::to_string(i), "_result"}, call);
|
||||||
|
@ -1762,7 +1764,7 @@ class UniformityGraph {
|
||||||
Switch(
|
Switch(
|
||||||
non_uniform_source->ast,
|
non_uniform_source->ast,
|
||||||
[&](const ast::IdentifierExpression* ident) {
|
[&](const ast::IdentifierExpression* ident) {
|
||||||
auto* var = sem_.Get(ident)->UnwrapLoad()->As<sem::VariableUser>()->Variable();
|
auto* var = sem_.GetVal(ident)->UnwrapLoad()->As<sem::VariableUser>()->Variable();
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
if (auto* param = var->As<sem::Parameter>()) {
|
if (auto* param = var->As<sem::Parameter>()) {
|
||||||
auto* func = param->Owner()->As<sem::Function>();
|
auto* func = param->Owner()->As<sem::Function>();
|
||||||
|
@ -1792,7 +1794,7 @@ class UniformityGraph {
|
||||||
}
|
}
|
||||||
case Node::kFunctionCallArgumentContents: {
|
case Node::kFunctionCallArgumentContents: {
|
||||||
auto* arg = c->args[non_uniform_source->arg_index];
|
auto* arg = c->args[non_uniform_source->arg_index];
|
||||||
auto* var = sem_.Get(arg)->RootIdentifier();
|
auto* var = sem_.GetVal(arg)->RootIdentifier();
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << "reading from " << var_type(var) << "'" << NameFor(var->Declaration())
|
ss << "reading from " << var_type(var) << "'" << NameFor(var->Declaration())
|
||||||
<< "' may result in a non-uniform value";
|
<< "' may result in a non-uniform value";
|
||||||
|
|
|
@ -250,7 +250,7 @@ TEST_F(ResolverVariableTest, LocalVar_ShadowsGlobalVar) {
|
||||||
EXPECT_EQ(local->Shadows(), global);
|
EXPECT_EQ(local->Shadows(), global);
|
||||||
|
|
||||||
auto* user_v =
|
auto* user_v =
|
||||||
Sem().Get(local->Declaration()->initializer)->UnwrapLoad()->As<sem::VariableUser>();
|
Sem().GetVal(local->Declaration()->initializer)->UnwrapLoad()->As<sem::VariableUser>();
|
||||||
ASSERT_NE(user_v, nullptr);
|
ASSERT_NE(user_v, nullptr);
|
||||||
EXPECT_EQ(user_v->Variable(), global);
|
EXPECT_EQ(user_v->Variable(), global);
|
||||||
}
|
}
|
||||||
|
@ -300,7 +300,7 @@ TEST_F(ResolverVariableTest, LocalVar_ShadowsLocalVar) {
|
||||||
EXPECT_EQ(local_y->Shadows(), local_x);
|
EXPECT_EQ(local_y->Shadows(), local_x);
|
||||||
|
|
||||||
auto* user_y =
|
auto* user_y =
|
||||||
Sem().Get(local_y->Declaration()->initializer)->UnwrapLoad()->As<sem::VariableUser>();
|
Sem().GetVal(local_y->Declaration()->initializer)->UnwrapLoad()->As<sem::VariableUser>();
|
||||||
ASSERT_NE(user_y, nullptr);
|
ASSERT_NE(user_y, nullptr);
|
||||||
EXPECT_EQ(user_y->Variable(), local_x);
|
EXPECT_EQ(user_y->Variable(), local_x);
|
||||||
}
|
}
|
||||||
|
@ -370,7 +370,7 @@ TEST_F(ResolverVariableTest, LocalVar_ShadowsParam) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* param = Sem().Get<sem::Parameter>(p);
|
auto* param = Sem().Get(p);
|
||||||
auto* local = Sem().Get<sem::LocalVariable>(v);
|
auto* local = Sem().Get<sem::LocalVariable>(v);
|
||||||
|
|
||||||
ASSERT_NE(param, nullptr);
|
ASSERT_NE(param, nullptr);
|
||||||
|
@ -566,7 +566,7 @@ TEST_F(ResolverVariableTest, LocalLet_ShadowsGlobalVar) {
|
||||||
EXPECT_EQ(local->Shadows(), global);
|
EXPECT_EQ(local->Shadows(), global);
|
||||||
|
|
||||||
auto* user =
|
auto* user =
|
||||||
Sem().Get(local->Declaration()->initializer)->UnwrapLoad()->As<sem::VariableUser>();
|
Sem().GetVal(local->Declaration()->initializer)->UnwrapLoad()->As<sem::VariableUser>();
|
||||||
ASSERT_NE(user, nullptr);
|
ASSERT_NE(user, nullptr);
|
||||||
EXPECT_EQ(user->Variable(), global);
|
EXPECT_EQ(user->Variable(), global);
|
||||||
}
|
}
|
||||||
|
@ -616,7 +616,7 @@ TEST_F(ResolverVariableTest, LocalLet_ShadowsLocalVar) {
|
||||||
EXPECT_EQ(local_l->Shadows(), local_v);
|
EXPECT_EQ(local_l->Shadows(), local_v);
|
||||||
|
|
||||||
auto* user =
|
auto* user =
|
||||||
Sem().Get(local_l->Declaration()->initializer)->UnwrapLoad()->As<sem::VariableUser>();
|
Sem().GetVal(local_l->Declaration()->initializer)->UnwrapLoad()->As<sem::VariableUser>();
|
||||||
ASSERT_NE(user, nullptr);
|
ASSERT_NE(user, nullptr);
|
||||||
EXPECT_EQ(user->Variable(), local_v);
|
EXPECT_EQ(user->Variable(), local_v);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Copyright 2023 The Tint Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "src/tint/sem/expression.h"
|
||||||
|
|
||||||
|
TINT_INSTANTIATE_TYPEINFO(tint::sem::Expression);
|
||||||
|
|
||||||
|
namespace tint::sem {
|
||||||
|
|
||||||
|
Expression::Expression(const ast::Expression* declaration, const Statement* statement)
|
||||||
|
: declaration_(declaration), statement_(statement) {}
|
||||||
|
|
||||||
|
Expression::~Expression() = default;
|
||||||
|
|
||||||
|
} // namespace tint::sem
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2023 The Tint Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef SRC_TINT_SEM_EXPRESSION_H_
|
||||||
|
#define SRC_TINT_SEM_EXPRESSION_H_
|
||||||
|
|
||||||
|
#include "src/tint/ast/expression.h"
|
||||||
|
#include "src/tint/sem/node.h"
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
namespace tint::sem {
|
||||||
|
class Statement;
|
||||||
|
} // namespace tint::sem
|
||||||
|
|
||||||
|
namespace tint::sem {
|
||||||
|
|
||||||
|
/// Expression holds the semantic information for expression nodes.
|
||||||
|
class Expression : public Castable<Expression, Node> {
|
||||||
|
public:
|
||||||
|
/// Constructor
|
||||||
|
/// @param declaration the AST node
|
||||||
|
/// @param statement the statement that owns this expression
|
||||||
|
Expression(const ast::Expression* declaration, const Statement* statement);
|
||||||
|
|
||||||
|
/// Destructor
|
||||||
|
~Expression() override;
|
||||||
|
|
||||||
|
/// @returns the AST node
|
||||||
|
const ast::Expression* Declaration() const { return declaration_; }
|
||||||
|
|
||||||
|
/// @return the statement that owns this expression
|
||||||
|
const Statement* Stmt() const { return statement_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// The AST expression node for this semantic expression
|
||||||
|
const ast::Expression* const declaration_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Statement* const statement_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace tint::sem
|
||||||
|
|
||||||
|
#endif // SRC_TINT_SEM_EXPRESSION_H_
|
|
@ -30,6 +30,7 @@
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
class Module;
|
class Module;
|
||||||
|
class ValueExpression;
|
||||||
} // namespace tint::sem
|
} // namespace tint::sem
|
||||||
namespace tint::type {
|
namespace tint::type {
|
||||||
class Node;
|
class Node;
|
||||||
|
@ -88,6 +89,14 @@ class Info {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience function that's an alias for Get<ValueExpression>()
|
||||||
|
/// @param ast_node the AST node
|
||||||
|
/// @returns a pointer to the semantic node if found, otherwise nullptr
|
||||||
|
template <typename AST>
|
||||||
|
const sem::ValueExpression* GetVal(const AST* ast_node) const {
|
||||||
|
return Get<ValueExpression>(ast_node);
|
||||||
|
}
|
||||||
|
|
||||||
/// Add registers the semantic node `sem_node` for the AST node `ast_node`.
|
/// Add registers the semantic node `sem_node` for the AST node `ast_node`.
|
||||||
/// @param ast_node the AST node
|
/// @param ast_node the AST node
|
||||||
/// @param sem_node the semantic node
|
/// @param sem_node the semantic node
|
||||||
|
|
|
@ -22,13 +22,19 @@ namespace tint {
|
||||||
class CastableBase;
|
class CastableBase;
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
namespace tint::ast {
|
namespace tint::ast {
|
||||||
|
class AccessorExpression;
|
||||||
class Array;
|
class Array;
|
||||||
|
class BinaryExpression;
|
||||||
|
class BitcastExpression;
|
||||||
|
class CallExpression;
|
||||||
class Expression;
|
class Expression;
|
||||||
class ForLoopStatement;
|
class ForLoopStatement;
|
||||||
class Function;
|
class Function;
|
||||||
class IfStatement;
|
class IfStatement;
|
||||||
|
class LiteralExpression;
|
||||||
class Node;
|
class Node;
|
||||||
class Override;
|
class Override;
|
||||||
|
class PhonyExpression;
|
||||||
class Statement;
|
class Statement;
|
||||||
class Struct;
|
class Struct;
|
||||||
class StructMember;
|
class StructMember;
|
||||||
|
@ -37,8 +43,10 @@ class Type;
|
||||||
class TypeDecl;
|
class TypeDecl;
|
||||||
class Variable;
|
class Variable;
|
||||||
class WhileStatement;
|
class WhileStatement;
|
||||||
|
class UnaryOpExpression;
|
||||||
} // namespace tint::ast
|
} // namespace tint::ast
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
class Expression;
|
||||||
class ForLoopStatement;
|
class ForLoopStatement;
|
||||||
class Function;
|
class Function;
|
||||||
class GlobalVariable;
|
class GlobalVariable;
|
||||||
|
@ -77,17 +85,24 @@ struct TypeMappings {
|
||||||
SwitchStatement* operator()(ast::SwitchStatement*);
|
SwitchStatement* operator()(ast::SwitchStatement*);
|
||||||
type::Type* operator()(ast::Type*);
|
type::Type* operator()(ast::Type*);
|
||||||
type::Type* operator()(ast::TypeDecl*);
|
type::Type* operator()(ast::TypeDecl*);
|
||||||
ValueExpression* operator()(ast::Expression*);
|
Expression* operator()(ast::Expression*);
|
||||||
|
ValueExpression* operator()(ast::AccessorExpression*);
|
||||||
|
ValueExpression* operator()(ast::CallExpression*);
|
||||||
|
ValueExpression* operator()(ast::BinaryExpression*);
|
||||||
|
ValueExpression* operator()(ast::BitcastExpression*);
|
||||||
|
ValueExpression* operator()(ast::LiteralExpression*);
|
||||||
|
ValueExpression* operator()(ast::PhonyExpression*);
|
||||||
|
ValueExpression* operator()(ast::UnaryOpExpression*);
|
||||||
Variable* operator()(ast::Variable*);
|
Variable* operator()(ast::Variable*);
|
||||||
WhileStatement* operator()(ast::WhileStatement*);
|
WhileStatement* operator()(ast::WhileStatement*);
|
||||||
//! @endcond
|
//! @endcond
|
||||||
};
|
};
|
||||||
|
|
||||||
/// SemanticNodeTypeFor resolves to the appropriate sem::Node type for the
|
/// SemanticNodeTypeFor resolves to the appropriate sem::Node type for the
|
||||||
/// AST or type node `AST_OR_TYPE`.
|
/// AST node `AST`.
|
||||||
template <typename AST_OR_TYPE>
|
template <typename AST>
|
||||||
using SemanticNodeTypeFor =
|
using SemanticNodeTypeFor =
|
||||||
typename std::remove_pointer<decltype(TypeMappings()(std::declval<AST_OR_TYPE*>()))>::type;
|
typename std::remove_pointer<decltype(TypeMappings()(std::declval<AST*>()))>::type;
|
||||||
|
|
||||||
} // namespace tint::sem
|
} // namespace tint::sem
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,10 @@ ValueExpression::ValueExpression(const ast::Expression* declaration,
|
||||||
const constant::Value* constant,
|
const constant::Value* constant,
|
||||||
bool has_side_effects,
|
bool has_side_effects,
|
||||||
const Variable* root_ident /* = nullptr */)
|
const Variable* root_ident /* = nullptr */)
|
||||||
: declaration_(declaration),
|
: Base(declaration, statement),
|
||||||
root_identifier_(root_ident),
|
root_identifier_(root_ident),
|
||||||
type_(type),
|
type_(type),
|
||||||
stage_(stage),
|
stage_(stage),
|
||||||
statement_(statement),
|
|
||||||
constant_(std::move(constant)),
|
constant_(std::move(constant)),
|
||||||
has_side_effects_(has_side_effects) {
|
has_side_effects_(has_side_effects) {
|
||||||
TINT_ASSERT(Semantic, type_);
|
TINT_ASSERT(Semantic, type_);
|
||||||
|
|
|
@ -15,11 +15,10 @@
|
||||||
#ifndef SRC_TINT_SEM_VALUE_EXPRESSION_H_
|
#ifndef SRC_TINT_SEM_VALUE_EXPRESSION_H_
|
||||||
#define SRC_TINT_SEM_VALUE_EXPRESSION_H_
|
#define SRC_TINT_SEM_VALUE_EXPRESSION_H_
|
||||||
|
|
||||||
#include "src/tint/ast/expression.h"
|
|
||||||
#include "src/tint/constant/value.h"
|
#include "src/tint/constant/value.h"
|
||||||
#include "src/tint/sem/behavior.h"
|
#include "src/tint/sem/behavior.h"
|
||||||
#include "src/tint/sem/evaluation_stage.h"
|
#include "src/tint/sem/evaluation_stage.h"
|
||||||
#include "src/tint/sem/node.h"
|
#include "src/tint/sem/expression.h"
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
@ -30,7 +29,7 @@ class Variable;
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
/// ValueExpression holds the semantic information for expression nodes.
|
/// ValueExpression holds the semantic information for expression nodes.
|
||||||
class ValueExpression : public Castable<ValueExpression, Node> {
|
class ValueExpression : public Castable<ValueExpression, Expression> {
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param declaration the AST node
|
/// @param declaration the AST node
|
||||||
|
@ -51,18 +50,12 @@ class ValueExpression : public Castable<ValueExpression, Node> {
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~ValueExpression() override;
|
~ValueExpression() override;
|
||||||
|
|
||||||
/// @returns the AST node
|
|
||||||
const ast::Expression* Declaration() const { return declaration_; }
|
|
||||||
|
|
||||||
/// @return the resolved type of the expression
|
/// @return the resolved type of the expression
|
||||||
const type::Type* Type() const { return type_; }
|
const type::Type* Type() const { return type_; }
|
||||||
|
|
||||||
/// @return the earliest evaluation stage for the expression
|
/// @return the earliest evaluation stage for the expression
|
||||||
EvaluationStage Stage() const { return stage_; }
|
EvaluationStage Stage() const { return stage_; }
|
||||||
|
|
||||||
/// @return the statement that owns this expression
|
|
||||||
const Statement* Stmt() const { return statement_; }
|
|
||||||
|
|
||||||
/// @return the constant value of this expression
|
/// @return the constant value of this expression
|
||||||
const constant::Value* ConstantValue() const { return constant_; }
|
const constant::Value* ConstantValue() const { return constant_; }
|
||||||
|
|
||||||
|
@ -92,15 +85,12 @@ class ValueExpression : public Castable<ValueExpression, Node> {
|
||||||
const ValueExpression* Unwrap() const;
|
const ValueExpression* Unwrap() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// The AST expression node for this semantic expression
|
|
||||||
const ast::Expression* const declaration_;
|
|
||||||
/// The root identifier for this semantic expression, or nullptr
|
/// The root identifier for this semantic expression, or nullptr
|
||||||
const Variable* root_identifier_;
|
const Variable* root_identifier_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const type::Type* const type_;
|
const type::Type* const type_;
|
||||||
const EvaluationStage stage_;
|
const EvaluationStage stage_;
|
||||||
const Statement* const statement_;
|
|
||||||
const constant::Value* const constant_;
|
const constant::Value* const constant_;
|
||||||
sem::Behaviors behaviors_{sem::Behavior::kNext};
|
sem::Behaviors behaviors_{sem::Behavior::kNext};
|
||||||
const bool has_side_effects_;
|
const bool has_side_effects_;
|
||||||
|
|
|
@ -74,7 +74,7 @@ struct OffsetExpr : Offset {
|
||||||
explicit OffsetExpr(const ast::Expression* e) : expr(e) {}
|
explicit OffsetExpr(const ast::Expression* e) : expr(e) {}
|
||||||
|
|
||||||
const ast::Expression* Build(CloneContext& ctx) const override {
|
const ast::Expression* Build(CloneContext& ctx) const override {
|
||||||
auto* type = ctx.src->Sem().Get(expr)->Type()->UnwrapRef();
|
auto* type = ctx.src->Sem().GetVal(expr)->Type()->UnwrapRef();
|
||||||
auto* res = ctx.Clone(expr);
|
auto* res = ctx.Clone(expr);
|
||||||
if (!type->Is<type::U32>()) {
|
if (!type->Is<type::U32>()) {
|
||||||
res = ctx.dst->Construct<u32>(res);
|
res = ctx.dst->Construct<u32>(res);
|
||||||
|
@ -881,7 +881,7 @@ Transform::ApplyResult DecomposeMemoryAccess::Apply(const Program* src,
|
||||||
for (auto* node : src->ASTNodes().Objects()) {
|
for (auto* node : src->ASTNodes().Objects()) {
|
||||||
if (auto* ident = node->As<ast::IdentifierExpression>()) {
|
if (auto* ident = node->As<ast::IdentifierExpression>()) {
|
||||||
// X
|
// X
|
||||||
if (auto* sem_ident = sem.Get(ident)) {
|
if (auto* sem_ident = sem.GetVal(ident)) {
|
||||||
if (auto* var = sem_ident->UnwrapLoad()->As<sem::VariableUser>()) {
|
if (auto* var = sem_ident->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||||
if (var->Variable()->AddressSpace() == type::AddressSpace::kStorage ||
|
if (var->Variable()->AddressSpace() == type::AddressSpace::kStorage ||
|
||||||
var->Variable()->AddressSpace() == type::AddressSpace::kUniform) {
|
var->Variable()->AddressSpace() == type::AddressSpace::kUniform) {
|
||||||
|
|
|
@ -123,7 +123,7 @@ Transform::ApplyResult DemoteToHelper::Apply(const Program* src, const DataMap&,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip writes to invocation-private address spaces.
|
// Skip writes to invocation-private address spaces.
|
||||||
auto* ref = sem.Get(assign->lhs)->Type()->As<type::Reference>();
|
auto* ref = sem.GetVal(assign->lhs)->Type()->As<type::Reference>();
|
||||||
switch (ref->AddressSpace()) {
|
switch (ref->AddressSpace()) {
|
||||||
case type::AddressSpace::kStorage:
|
case type::AddressSpace::kStorage:
|
||||||
// Need to mask these.
|
// Need to mask these.
|
||||||
|
|
|
@ -216,7 +216,7 @@ struct DirectVariableAccess::State {
|
||||||
// are grown and moved up the expression tree. After this stage, we are left with all the
|
// are grown and moved up the expression tree. After this stage, we are left with all the
|
||||||
// expression access chains to variables that we may need to transform.
|
// expression access chains to variables that we may need to transform.
|
||||||
for (auto* node : ctx.src->ASTNodes().Objects()) {
|
for (auto* node : ctx.src->ASTNodes().Objects()) {
|
||||||
if (auto* expr = sem.Get<sem::ValueExpression>(node)) {
|
if (auto* expr = sem.GetVal(node)) {
|
||||||
AppendAccessChain(expr);
|
AppendAccessChain(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,7 +464,7 @@ struct DirectVariableAccess::State {
|
||||||
[&](const ast::Let*) {
|
[&](const ast::Let*) {
|
||||||
if (variable->Type()->Is<type::Pointer>()) {
|
if (variable->Type()->Is<type::Pointer>()) {
|
||||||
// variable is a pointer-let.
|
// variable is a pointer-let.
|
||||||
auto* init = sem.Get(variable->Declaration()->initializer);
|
auto* init = sem.GetVal(variable->Declaration()->initializer);
|
||||||
// Note: We do not use take_chain() here, as we need to preserve the
|
// Note: We do not use take_chain() here, as we need to preserve the
|
||||||
// AccessChain on the let's initializer, as the let needs its
|
// AccessChain on the let's initializer, as the let needs its
|
||||||
// initializer updated, and the let may be used multiple times. Instead
|
// initializer updated, and the let may be used multiple times. Instead
|
||||||
|
@ -498,7 +498,7 @@ struct DirectVariableAccess::State {
|
||||||
// If this is a '&' or '*', simply move the chain to the unary op expression.
|
// If this is a '&' or '*', simply move the chain to the unary op expression.
|
||||||
if (unary->op == ast::UnaryOp::kAddressOf ||
|
if (unary->op == ast::UnaryOp::kAddressOf ||
|
||||||
unary->op == ast::UnaryOp::kIndirection) {
|
unary->op == ast::UnaryOp::kIndirection) {
|
||||||
take_chain(sem.Get(unary->expr));
|
take_chain(sem.GetVal(unary->expr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -990,7 +990,7 @@ struct DirectVariableAccess::State {
|
||||||
return nullptr; // Just clone the expression.
|
return nullptr; // Just clone the expression.
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* expr = sem.Get(ast_expr);
|
auto* expr = sem.GetVal(ast_expr);
|
||||||
if (!expr) {
|
if (!expr) {
|
||||||
// No semantic node for the expression.
|
// No semantic node for the expression.
|
||||||
return nullptr; // Just clone the expression.
|
return nullptr; // Just clone the expression.
|
||||||
|
|
|
@ -86,7 +86,10 @@ struct ExpandCompoundAssignment::State {
|
||||||
|
|
||||||
// Helper function that returns `true` if the type of `expr` is a vector.
|
// Helper function that returns `true` if the type of `expr` is a vector.
|
||||||
auto is_vec = [&](const ast::Expression* expr) {
|
auto is_vec = [&](const ast::Expression* expr) {
|
||||||
return ctx.src->Sem().Get(expr)->Type()->UnwrapRef()->Is<type::Vector>();
|
if (auto* val_expr = ctx.src->Sem().GetVal(expr)) {
|
||||||
|
return val_expr->Type()->UnwrapRef()->Is<type::Vector>();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Hoist the LHS expression subtree into local constants to produce a new
|
// Hoist the LHS expression subtree into local constants to produce a new
|
||||||
|
|
|
@ -138,7 +138,7 @@ Transform::ApplyResult FirstIndexOffset::Apply(const Program* src,
|
||||||
|
|
||||||
// Fix up all references to the builtins with the offsets
|
// Fix up all references to the builtins with the offsets
|
||||||
ctx.ReplaceAll([=, &ctx](const ast::Expression* expr) -> const ast::Expression* {
|
ctx.ReplaceAll([=, &ctx](const ast::Expression* expr) -> const ast::Expression* {
|
||||||
if (auto* sem = ctx.src->Sem().Get(expr)) {
|
if (auto* sem = ctx.src->Sem().GetVal(expr)) {
|
||||||
if (auto* user = sem->UnwrapLoad()->As<sem::VariableUser>()) {
|
if (auto* user = sem->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||||
auto it = builtin_vars.find(user->Variable());
|
auto it = builtin_vars.find(user->Variable());
|
||||||
if (it != builtin_vars.end()) {
|
if (it != builtin_vars.end()) {
|
||||||
|
|
|
@ -164,7 +164,7 @@ struct LocalizeStructArrayAssignment::State {
|
||||||
ast::TraverseExpressions(
|
ast::TraverseExpressions(
|
||||||
expr, b.Diagnostics(), [&](const ast::IndexAccessorExpression* ia) {
|
expr, b.Diagnostics(), [&](const ast::IndexAccessorExpression* ia) {
|
||||||
// Indexing using a runtime value?
|
// Indexing using a runtime value?
|
||||||
auto* idx_sem = src->Sem().Get(ia->index);
|
auto* idx_sem = src->Sem().GetVal(ia->index);
|
||||||
if (!idx_sem->ConstantValue()) {
|
if (!idx_sem->ConstantValue()) {
|
||||||
// Indexing a member access expr?
|
// Indexing a member access expr?
|
||||||
if (auto* ma = ia->object->As<ast::MemberAccessorExpression>()) {
|
if (auto* ma = ia->object->As<ast::MemberAccessorExpression>()) {
|
||||||
|
@ -186,7 +186,7 @@ struct LocalizeStructArrayAssignment::State {
|
||||||
// See https://www.w3.org/TR/WGSL/#originating-variable-section
|
// See https://www.w3.org/TR/WGSL/#originating-variable-section
|
||||||
std::pair<const type::Type*, type::AddressSpace> GetOriginatingTypeAndAddressSpace(
|
std::pair<const type::Type*, type::AddressSpace> GetOriginatingTypeAndAddressSpace(
|
||||||
const ast::AssignmentStatement* assign_stmt) {
|
const ast::AssignmentStatement* assign_stmt) {
|
||||||
auto* root_ident = src->Sem().Get(assign_stmt->lhs)->RootIdentifier();
|
auto* root_ident = src->Sem().GetVal(assign_stmt->lhs)->RootIdentifier();
|
||||||
if (TINT_UNLIKELY(!root_ident)) {
|
if (TINT_UNLIKELY(!root_ident)) {
|
||||||
TINT_ICE(Transform, b.Diagnostics())
|
TINT_ICE(Transform, b.Diagnostics())
|
||||||
<< "Unable to determine originating variable for lhs of assignment "
|
<< "Unable to determine originating variable for lhs of assignment "
|
||||||
|
|
|
@ -198,7 +198,7 @@ struct MultiplanarExternalTexture::State {
|
||||||
builtin->Parameters()[0]->Type()->Is<type::ExternalTexture>() &&
|
builtin->Parameters()[0]->Type()->Is<type::ExternalTexture>() &&
|
||||||
builtin->Type() != sem::BuiltinType::kTextureDimensions) {
|
builtin->Type() != sem::BuiltinType::kTextureDimensions) {
|
||||||
if (auto* var_user =
|
if (auto* var_user =
|
||||||
sem.Get(expr->args[0])->UnwrapLoad()->As<sem::VariableUser>()) {
|
sem.GetVal(expr->args[0])->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||||
auto it = new_binding_symbols.find(var_user->Variable());
|
auto it = new_binding_symbols.find(var_user->Variable());
|
||||||
if (it == new_binding_symbols.end()) {
|
if (it == new_binding_symbols.end()) {
|
||||||
// If valid new binding locations were not provided earlier, we would have
|
// If valid new binding locations were not provided earlier, we would have
|
||||||
|
@ -223,7 +223,7 @@ struct MultiplanarExternalTexture::State {
|
||||||
// texture_external parameter. These need to be expanded out to multiple plane
|
// texture_external parameter. These need to be expanded out to multiple plane
|
||||||
// textures and the texture parameters structure.
|
// textures and the texture parameters structure.
|
||||||
for (auto* arg : expr->args) {
|
for (auto* arg : expr->args) {
|
||||||
if (auto* var_user = sem.Get(arg)->UnwrapLoad()->As<sem::VariableUser>()) {
|
if (auto* var_user = sem.GetVal(arg)->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||||
// Check if a parameter is a texture_external by trying to find
|
// Check if a parameter is a texture_external by trying to find
|
||||||
// it in the transform state.
|
// it in the transform state.
|
||||||
auto it = new_binding_symbols.find(var_user->Variable());
|
auto it = new_binding_symbols.find(var_user->Variable());
|
||||||
|
|
|
@ -109,7 +109,7 @@ struct PackedVec3::State {
|
||||||
if (unary->op == ast::UnaryOp::kAddressOf ||
|
if (unary->op == ast::UnaryOp::kAddressOf ||
|
||||||
unary->op == ast::UnaryOp::kIndirection) {
|
unary->op == ast::UnaryOp::kIndirection) {
|
||||||
// Memory access on the packed vector. Track these.
|
// Memory access on the packed vector. Track these.
|
||||||
auto* inner = sem.Get(unary->expr);
|
auto* inner = sem.GetVal(unary->expr);
|
||||||
if (refs.Remove(inner)) {
|
if (refs.Remove(inner)) {
|
||||||
refs.Add(expr);
|
refs.Add(expr);
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ struct PackedVec3::State {
|
||||||
[&](const sem::Statement* e) {
|
[&](const sem::Statement* e) {
|
||||||
if (auto* assign = e->Declaration()->As<ast::AssignmentStatement>()) {
|
if (auto* assign = e->Declaration()->As<ast::AssignmentStatement>()) {
|
||||||
// We don't want to cast packed_vectors if they're being assigned to.
|
// We don't want to cast packed_vectors if they're being assigned to.
|
||||||
refs.Remove(sem.Get(assign->lhs));
|
refs.Remove(sem.GetVal(assign->lhs));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ struct PreservePadding::State {
|
||||||
Switch(
|
Switch(
|
||||||
node, //
|
node, //
|
||||||
[&](const ast::AssignmentStatement* assign) {
|
[&](const ast::AssignmentStatement* assign) {
|
||||||
auto* ty = sem.Get(assign->lhs)->Type();
|
auto* ty = sem.GetVal(assign->lhs)->Type();
|
||||||
if (assign->lhs->Is<ast::PhonyExpression>()) {
|
if (assign->lhs->Is<ast::PhonyExpression>()) {
|
||||||
// Ignore phony assignment.
|
// Ignore phony assignment.
|
||||||
return;
|
return;
|
||||||
|
@ -80,7 +80,7 @@ struct PreservePadding::State {
|
||||||
if (!assignments_to_transform.count(assign)) {
|
if (!assignments_to_transform.count(assign)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto* ty = sem.Get(assign->lhs)->Type()->UnwrapRef();
|
auto* ty = sem.GetVal(assign->lhs)->Type()->UnwrapRef();
|
||||||
return MakeAssignment(ty, ctx.Clone(assign->lhs), ctx.Clone(assign->rhs));
|
return MakeAssignment(ty, ctx.Clone(assign->lhs), ctx.Clone(assign->rhs));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ Transform::ApplyResult PromoteInitializersToLet::Apply(const Program* src,
|
||||||
|
|
||||||
// Walk the AST nodes. This order guarantees that leaf-expressions are visited first.
|
// Walk the AST nodes. This order guarantees that leaf-expressions are visited first.
|
||||||
for (auto* node : src->ASTNodes().Objects()) {
|
for (auto* node : src->ASTNodes().Objects()) {
|
||||||
if (auto* sem = src->Sem().Get<sem::ValueExpression>(node)) {
|
if (auto* sem = src->Sem().GetVal(node)) {
|
||||||
auto* stmt = sem->Stmt();
|
auto* stmt = sem->Stmt();
|
||||||
if (!stmt) {
|
if (!stmt) {
|
||||||
// Expression is outside of a statement. This usually means the expression is part
|
// Expression is outside of a statement. This usually means the expression is part
|
||||||
|
@ -118,7 +118,7 @@ Transform::ApplyResult PromoteInitializersToLet::Apply(const Program* src,
|
||||||
// After walking the full AST, const_chains only contains the outer-most constant expressions.
|
// After walking the full AST, const_chains only contains the outer-most constant expressions.
|
||||||
// Check if any of these need hoisting, and append those to to_hoist.
|
// Check if any of these need hoisting, and append those to to_hoist.
|
||||||
for (auto* expr : const_chains) {
|
for (auto* expr : const_chains) {
|
||||||
if (auto* sem = src->Sem().Get(expr); should_hoist(sem)) {
|
if (auto* sem = src->Sem().GetVal(expr); should_hoist(sem)) {
|
||||||
to_hoist.Push(sem);
|
to_hoist.Push(sem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,9 +66,8 @@ Transform::ApplyResult SimplifySideEffectStatements::Apply(const Program* src,
|
||||||
|
|
||||||
HoistToDeclBefore hoist_to_decl_before(ctx);
|
HoistToDeclBefore hoist_to_decl_before(ctx);
|
||||||
for (auto* node : ctx.src->ASTNodes().Objects()) {
|
for (auto* node : ctx.src->ASTNodes().Objects()) {
|
||||||
if (auto* expr = node->As<ast::Expression>()) {
|
if (auto* sem_expr = src->Sem().GetVal(node)) {
|
||||||
auto* sem_expr = src->Sem().Get(expr);
|
if (!sem_expr->HasSideEffects()) {
|
||||||
if (!sem_expr || !sem_expr->HasSideEffects()) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +277,7 @@ class DecomposeSideEffects::CollectHoistsState : public StateBase {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
[&](const ast::IdentifierExpression* e) {
|
[&](const ast::IdentifierExpression* e) {
|
||||||
if (auto* sem_e = sem.Get(e)) {
|
if (auto* sem_e = sem.GetVal(e)) {
|
||||||
if (auto* var_user = sem_e->UnwrapLoad()->As<sem::VariableUser>()) {
|
if (auto* var_user = sem_e->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||||
// Don't hoist constants.
|
// Don't hoist constants.
|
||||||
if (var_user->ConstantValue()) {
|
if (var_user->ConstantValue()) {
|
||||||
|
@ -417,8 +416,8 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
|
||||||
|
|
||||||
// Returns true if `binary_expr` should be decomposed for short-circuit eval.
|
// Returns true if `binary_expr` should be decomposed for short-circuit eval.
|
||||||
bool IsLogicalWithSideEffects(const ast::BinaryExpression* binary_expr) {
|
bool IsLogicalWithSideEffects(const ast::BinaryExpression* binary_expr) {
|
||||||
return binary_expr->IsLogical() && (sem.Get(binary_expr->lhs)->HasSideEffects() ||
|
return binary_expr->IsLogical() && (sem.GetVal(binary_expr->lhs)->HasSideEffects() ||
|
||||||
sem.Get(binary_expr->rhs)->HasSideEffects());
|
sem.GetVal(binary_expr->rhs)->HasSideEffects());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursive function used to decompose an expression for short-circuit eval.
|
// Recursive function used to decompose an expression for short-circuit eval.
|
||||||
|
@ -560,7 +559,8 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
|
||||||
return Switch(
|
return Switch(
|
||||||
stmt,
|
stmt,
|
||||||
[&](const ast::AssignmentStatement* s) -> const ast::Statement* {
|
[&](const ast::AssignmentStatement* s) -> const ast::Statement* {
|
||||||
if (!sem.Get(s->lhs)->HasSideEffects() && !sem.Get(s->rhs)->HasSideEffects()) {
|
if (!sem.GetVal(s->lhs)->HasSideEffects() &&
|
||||||
|
!sem.GetVal(s->rhs)->HasSideEffects()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// rhs before lhs
|
// rhs before lhs
|
||||||
|
@ -580,7 +580,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
|
||||||
return ctx.CloneWithoutTransform(s);
|
return ctx.CloneWithoutTransform(s);
|
||||||
},
|
},
|
||||||
[&](const ast::ForLoopStatement* s) -> const ast::Statement* {
|
[&](const ast::ForLoopStatement* s) -> const ast::Statement* {
|
||||||
if (!s->condition || !sem.Get(s->condition)->HasSideEffects()) {
|
if (!s->condition || !sem.GetVal(s->condition)->HasSideEffects()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
tint::utils::Vector<const ast::Statement*, 8> stmts;
|
tint::utils::Vector<const ast::Statement*, 8> stmts;
|
||||||
|
@ -589,7 +589,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
|
||||||
return ctx.CloneWithoutTransform(s);
|
return ctx.CloneWithoutTransform(s);
|
||||||
},
|
},
|
||||||
[&](const ast::WhileStatement* s) -> const ast::Statement* {
|
[&](const ast::WhileStatement* s) -> const ast::Statement* {
|
||||||
if (!sem.Get(s->condition)->HasSideEffects()) {
|
if (!sem.GetVal(s->condition)->HasSideEffects()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
tint::utils::Vector<const ast::Statement*, 8> stmts;
|
tint::utils::Vector<const ast::Statement*, 8> stmts;
|
||||||
|
@ -598,7 +598,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
|
||||||
return ctx.CloneWithoutTransform(s);
|
return ctx.CloneWithoutTransform(s);
|
||||||
},
|
},
|
||||||
[&](const ast::IfStatement* s) -> const ast::Statement* {
|
[&](const ast::IfStatement* s) -> const ast::Statement* {
|
||||||
if (!sem.Get(s->condition)->HasSideEffects()) {
|
if (!sem.GetVal(s->condition)->HasSideEffects()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
tint::utils::Vector<const ast::Statement*, 8> stmts;
|
tint::utils::Vector<const ast::Statement*, 8> stmts;
|
||||||
|
@ -607,7 +607,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
|
||||||
return ctx.CloneWithoutTransform(s);
|
return ctx.CloneWithoutTransform(s);
|
||||||
},
|
},
|
||||||
[&](const ast::ReturnStatement* s) -> const ast::Statement* {
|
[&](const ast::ReturnStatement* s) -> const ast::Statement* {
|
||||||
if (!s->value || !sem.Get(s->value)->HasSideEffects()) {
|
if (!s->value || !sem.GetVal(s->value)->HasSideEffects()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
tint::utils::Vector<const ast::Statement*, 8> stmts;
|
tint::utils::Vector<const ast::Statement*, 8> stmts;
|
||||||
|
@ -626,7 +626,7 @@ class DecomposeSideEffects::DecomposeState : public StateBase {
|
||||||
},
|
},
|
||||||
[&](const ast::VariableDeclStatement* s) -> const ast::Statement* {
|
[&](const ast::VariableDeclStatement* s) -> const ast::Statement* {
|
||||||
auto* var = s->variable;
|
auto* var = s->variable;
|
||||||
if (!var->initializer || !sem.Get(var->initializer)->HasSideEffects()) {
|
if (!var->initializer || !sem.GetVal(var->initializer)->HasSideEffects()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
tint::utils::Vector<const ast::Statement*, 8> stmts;
|
tint::utils::Vector<const ast::Statement*, 8> stmts;
|
||||||
|
|
|
@ -102,7 +102,7 @@ Transform::ApplyResult RemovePhonies::Apply(const Program* src, const DataMap&,
|
||||||
ctx.Replace(stmt, [&, side_effects] {
|
ctx.Replace(stmt, [&, side_effects] {
|
||||||
SinkSignature sig;
|
SinkSignature sig;
|
||||||
for (auto* arg : side_effects) {
|
for (auto* arg : side_effects) {
|
||||||
sig.push_back(sem.Get(arg)->Type()->UnwrapRef());
|
sig.push_back(sem.GetVal(arg)->Type()->UnwrapRef());
|
||||||
}
|
}
|
||||||
auto sink = sinks.GetOrCreate(sig, [&] {
|
auto sink = sinks.GetOrCreate(sig, [&] {
|
||||||
auto name = b.Symbols().New("phony_sink");
|
auto name = b.Symbols().New("phony_sink");
|
||||||
|
|
|
@ -1286,7 +1286,7 @@ Transform::ApplyResult Renamer::Apply(const Program* src,
|
||||||
auto* sem = src->Sem().Get(accessor)->UnwrapLoad();
|
auto* sem = src->Sem().Get(accessor)->UnwrapLoad();
|
||||||
if (sem->Is<sem::Swizzle>()) {
|
if (sem->Is<sem::Swizzle>()) {
|
||||||
preserved_identifiers.Add(accessor->member);
|
preserved_identifiers.Add(accessor->member);
|
||||||
} else if (auto* str_expr = src->Sem().Get(accessor->object)) {
|
} else if (auto* str_expr = src->Sem().GetVal(accessor->object)) {
|
||||||
if (auto* ty = str_expr->Type()->UnwrapRef()->As<sem::Struct>()) {
|
if (auto* ty = str_expr->Type()->UnwrapRef()->As<sem::Struct>()) {
|
||||||
if (ty->Declaration() == nullptr) { // Builtin structure
|
if (ty->Declaration() == nullptr) { // Builtin structure
|
||||||
preserved_identifiers.Add(accessor->member);
|
preserved_identifiers.Add(accessor->member);
|
||||||
|
|
|
@ -101,7 +101,7 @@ struct SpirvAtomic::State {
|
||||||
|
|
||||||
// Keep track of this expression. We'll need to modify the root identifier /
|
// Keep track of this expression. We'll need to modify the root identifier /
|
||||||
// structure to be atomic.
|
// structure to be atomic.
|
||||||
atomic_expressions.Add(ctx.src->Sem().Get(args[0]));
|
atomic_expressions.Add(ctx.src->Sem().GetVal(args[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the stub from the output program
|
// Remove the stub from the output program
|
||||||
|
@ -186,7 +186,7 @@ struct SpirvAtomic::State {
|
||||||
},
|
},
|
||||||
[&](const sem::ValueExpression* e) {
|
[&](const sem::ValueExpression* e) {
|
||||||
if (auto* unary = e->Declaration()->As<ast::UnaryOpExpression>()) {
|
if (auto* unary = e->Declaration()->As<ast::UnaryOpExpression>()) {
|
||||||
atomic_expressions.Add(ctx.src->Sem().Get(unary->expr));
|
atomic_expressions.Add(ctx.src->Sem().GetVal(unary->expr));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,7 @@ struct SpirvAtomic::State {
|
||||||
Switch(
|
Switch(
|
||||||
vu->Stmt()->Declaration(),
|
vu->Stmt()->Declaration(),
|
||||||
[&](const ast::AssignmentStatement* assign) {
|
[&](const ast::AssignmentStatement* assign) {
|
||||||
auto* sem_lhs = ctx.src->Sem().Get(assign->lhs);
|
auto* sem_lhs = ctx.src->Sem().GetVal(assign->lhs);
|
||||||
if (is_ref_to_atomic_var(sem_lhs)) {
|
if (is_ref_to_atomic_var(sem_lhs)) {
|
||||||
ctx.Replace(assign, [=] {
|
ctx.Replace(assign, [=] {
|
||||||
auto* lhs = ctx.CloneWithoutTransform(assign->lhs);
|
auto* lhs = ctx.CloneWithoutTransform(assign->lhs);
|
||||||
|
@ -261,7 +261,7 @@ struct SpirvAtomic::State {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sem_rhs = ctx.src->Sem().Get(assign->rhs);
|
auto sem_rhs = ctx.src->Sem().GetVal(assign->rhs);
|
||||||
if (is_ref_to_atomic_var(sem_rhs->UnwrapLoad())) {
|
if (is_ref_to_atomic_var(sem_rhs->UnwrapLoad())) {
|
||||||
ctx.Replace(assign->rhs, [=] {
|
ctx.Replace(assign->rhs, [=] {
|
||||||
auto* rhs = ctx.CloneWithoutTransform(assign->rhs);
|
auto* rhs = ctx.CloneWithoutTransform(assign->rhs);
|
||||||
|
@ -273,7 +273,7 @@ struct SpirvAtomic::State {
|
||||||
},
|
},
|
||||||
[&](const ast::VariableDeclStatement* decl) {
|
[&](const ast::VariableDeclStatement* decl) {
|
||||||
auto* var = decl->variable;
|
auto* var = decl->variable;
|
||||||
if (auto* sem_init = ctx.src->Sem().Get(var->initializer)) {
|
if (auto* sem_init = ctx.src->Sem().GetVal(var->initializer)) {
|
||||||
if (is_ref_to_atomic_var(sem_init->UnwrapLoad())) {
|
if (is_ref_to_atomic_var(sem_init->UnwrapLoad())) {
|
||||||
ctx.Replace(var->initializer, [=] {
|
ctx.Replace(var->initializer, [=] {
|
||||||
auto* rhs = ctx.CloneWithoutTransform(var->initializer);
|
auto* rhs = ctx.CloneWithoutTransform(var->initializer);
|
||||||
|
|
|
@ -494,7 +494,7 @@ struct Std140::State {
|
||||||
/// @returns an AccessChain if the expression is an access to a std140-forked uniform buffer,
|
/// @returns an AccessChain if the expression is an access to a std140-forked uniform buffer,
|
||||||
/// otherwise returns a std::nullopt.
|
/// otherwise returns a std::nullopt.
|
||||||
std::optional<AccessChain> AccessChainFor(const ast::Expression* ast_expr) {
|
std::optional<AccessChain> AccessChainFor(const ast::Expression* ast_expr) {
|
||||||
auto* expr = sem.Get(ast_expr);
|
auto* expr = sem.GetVal(ast_expr);
|
||||||
if (!expr) {
|
if (!expr) {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
@ -580,7 +580,7 @@ struct Std140::State {
|
||||||
switch (u->op) {
|
switch (u->op) {
|
||||||
case ast::UnaryOp::kAddressOf:
|
case ast::UnaryOp::kAddressOf:
|
||||||
case ast::UnaryOp::kIndirection:
|
case ast::UnaryOp::kIndirection:
|
||||||
expr = sem.Get(u->expr);
|
expr = sem.GetVal(u->expr);
|
||||||
return Action::kContinue;
|
return Action::kContinue;
|
||||||
default:
|
default:
|
||||||
TINT_ICE(Transform, b.Diagnostics())
|
TINT_ICE(Transform, b.Diagnostics())
|
||||||
|
|
|
@ -106,7 +106,7 @@ struct Unshadow::State {
|
||||||
|
|
||||||
ctx.ReplaceAll(
|
ctx.ReplaceAll(
|
||||||
[&](const ast::IdentifierExpression* ident) -> const tint::ast::IdentifierExpression* {
|
[&](const ast::IdentifierExpression* ident) -> const tint::ast::IdentifierExpression* {
|
||||||
if (auto* sem_ident = sem.Get(ident)) {
|
if (auto* sem_ident = sem.GetVal(ident)) {
|
||||||
if (auto* user = sem_ident->UnwrapLoad()->As<sem::VariableUser>()) {
|
if (auto* user = sem_ident->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||||
if (auto renamed = renamed_to.Find(user->Variable())) {
|
if (auto renamed = renamed_to.Find(user->Variable())) {
|
||||||
return b.Expr(*renamed);
|
return b.Expr(*renamed);
|
||||||
|
|
|
@ -108,7 +108,7 @@ TEST_F(HoistToDeclBeforeTest, ForLoopCond) {
|
||||||
CloneContext ctx(&cloned_b, &original);
|
CloneContext ctx(&cloned_b, &original);
|
||||||
|
|
||||||
HoistToDeclBefore hoistToDeclBefore(ctx);
|
HoistToDeclBefore hoistToDeclBefore(ctx);
|
||||||
auto* sem_expr = ctx.src->Sem().Get(expr);
|
auto* sem_expr = ctx.src->Sem().GetVal(expr);
|
||||||
hoistToDeclBefore.Add(sem_expr, expr, HoistToDeclBefore::VariableKind::kConst);
|
hoistToDeclBefore.Add(sem_expr, expr, HoistToDeclBefore::VariableKind::kConst);
|
||||||
|
|
||||||
ctx.Clone();
|
ctx.Clone();
|
||||||
|
@ -189,7 +189,7 @@ TEST_F(HoistToDeclBeforeTest, WhileCond) {
|
||||||
CloneContext ctx(&cloned_b, &original);
|
CloneContext ctx(&cloned_b, &original);
|
||||||
|
|
||||||
HoistToDeclBefore hoistToDeclBefore(ctx);
|
HoistToDeclBefore hoistToDeclBefore(ctx);
|
||||||
auto* sem_expr = ctx.src->Sem().Get(expr);
|
auto* sem_expr = ctx.src->Sem().GetVal(expr);
|
||||||
hoistToDeclBefore.Add(sem_expr, expr, HoistToDeclBefore::VariableKind::kVar);
|
hoistToDeclBefore.Add(sem_expr, expr, HoistToDeclBefore::VariableKind::kVar);
|
||||||
|
|
||||||
ctx.Clone();
|
ctx.Clone();
|
||||||
|
@ -233,7 +233,7 @@ TEST_F(HoistToDeclBeforeTest, ElseIf) {
|
||||||
CloneContext ctx(&cloned_b, &original);
|
CloneContext ctx(&cloned_b, &original);
|
||||||
|
|
||||||
HoistToDeclBefore hoistToDeclBefore(ctx);
|
HoistToDeclBefore hoistToDeclBefore(ctx);
|
||||||
auto* sem_expr = ctx.src->Sem().Get(expr);
|
auto* sem_expr = ctx.src->Sem().GetVal(expr);
|
||||||
hoistToDeclBefore.Add(sem_expr, expr, HoistToDeclBefore::VariableKind::kConst);
|
hoistToDeclBefore.Add(sem_expr, expr, HoistToDeclBefore::VariableKind::kConst);
|
||||||
|
|
||||||
ctx.Clone();
|
ctx.Clone();
|
||||||
|
@ -339,7 +339,7 @@ TEST_F(HoistToDeclBeforeTest, Prepare_ForLoopCond) {
|
||||||
CloneContext ctx(&cloned_b, &original);
|
CloneContext ctx(&cloned_b, &original);
|
||||||
|
|
||||||
HoistToDeclBefore hoistToDeclBefore(ctx);
|
HoistToDeclBefore hoistToDeclBefore(ctx);
|
||||||
auto* sem_expr = ctx.src->Sem().Get(expr);
|
auto* sem_expr = ctx.src->Sem().GetVal(expr);
|
||||||
hoistToDeclBefore.Prepare(sem_expr);
|
hoistToDeclBefore.Prepare(sem_expr);
|
||||||
|
|
||||||
ctx.Clone();
|
ctx.Clone();
|
||||||
|
@ -422,7 +422,7 @@ TEST_F(HoistToDeclBeforeTest, Prepare_ElseIf) {
|
||||||
CloneContext ctx(&cloned_b, &original);
|
CloneContext ctx(&cloned_b, &original);
|
||||||
|
|
||||||
HoistToDeclBefore hoistToDeclBefore(ctx);
|
HoistToDeclBefore hoistToDeclBefore(ctx);
|
||||||
auto* sem_expr = ctx.src->Sem().Get(expr);
|
auto* sem_expr = ctx.src->Sem().GetVal(expr);
|
||||||
hoistToDeclBefore.Prepare(sem_expr);
|
hoistToDeclBefore.Prepare(sem_expr);
|
||||||
|
|
||||||
ctx.Clone();
|
ctx.Clone();
|
||||||
|
|
|
@ -40,13 +40,13 @@ Transform::ApplyResult VarForDynamicIndex::Apply(const Program* src,
|
||||||
auto* object_expr = access_expr->object;
|
auto* object_expr = access_expr->object;
|
||||||
auto& sem = src->Sem();
|
auto& sem = src->Sem();
|
||||||
|
|
||||||
if (sem.Get(index_expr)->ConstantValue()) {
|
if (sem.GetVal(index_expr)->ConstantValue()) {
|
||||||
// Index expression resolves to a compile time value.
|
// Index expression resolves to a compile time value.
|
||||||
// As this isn't a dynamic index, we can ignore this.
|
// As this isn't a dynamic index, we can ignore this.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* indexed = sem.Get(object_expr);
|
auto* indexed = sem.GetVal(object_expr);
|
||||||
if (!indexed->Type()->IsAnyOf<type::Array, type::Matrix>()) {
|
if (!indexed->Type()->IsAnyOf<type::Array, type::Matrix>()) {
|
||||||
// We only care about array and matrices.
|
// We only care about array and matrices.
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -34,7 +34,7 @@ namespace {
|
||||||
|
|
||||||
bool ShouldRun(const Program* program) {
|
bool ShouldRun(const Program* program) {
|
||||||
for (auto* node : program->ASTNodes().Objects()) {
|
for (auto* node : program->ASTNodes().Objects()) {
|
||||||
if (auto* sem = program->Sem().Get<sem::ValueExpression>(node)) {
|
if (auto* sem = program->Sem().GetVal(node)) {
|
||||||
if (auto* call = sem->UnwrapMaterialize()->As<sem::Call>()) {
|
if (auto* call = sem->UnwrapMaterialize()->As<sem::Call>()) {
|
||||||
if (call->Target()->Is<sem::TypeConversion>() && call->Type()->Is<type::Matrix>()) {
|
if (call->Target()->Is<sem::TypeConversion>() && call->Type()->Is<type::Matrix>()) {
|
||||||
auto& args = call->Arguments();
|
auto& args = call->Arguments();
|
||||||
|
|
|
@ -403,7 +403,7 @@ struct ZeroInitWorkgroupMemory::State {
|
||||||
if (!expr) {
|
if (!expr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto* sem = ctx.src->Sem().Get(expr);
|
auto* sem = ctx.src->Sem().GetVal(expr);
|
||||||
if (auto* c = sem->ConstantValue()) {
|
if (auto* c = sem->ConstantValue()) {
|
||||||
workgroup_size_const *= c->ValueAs<AInt>();
|
workgroup_size_const *= c->ValueAs<AInt>();
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -75,8 +75,8 @@ const sem::Call* AppendVector(ProgramBuilder* b,
|
||||||
const ast::Expression* scalar_ast) {
|
const ast::Expression* scalar_ast) {
|
||||||
uint32_t packed_size;
|
uint32_t packed_size;
|
||||||
const type::Type* packed_el_sem_ty;
|
const type::Type* packed_el_sem_ty;
|
||||||
auto* vector_sem = b->Sem().Get(vector_ast);
|
auto* vector_sem = b->Sem().GetVal(vector_ast);
|
||||||
auto* scalar_sem = b->Sem().Get(scalar_ast);
|
auto* scalar_sem = b->Sem().GetVal(scalar_ast);
|
||||||
auto* vector_ty = vector_sem->Type()->UnwrapRef();
|
auto* vector_ty = vector_sem->Type()->UnwrapRef();
|
||||||
if (auto* vec = vector_ty->As<type::Vector>()) {
|
if (auto* vec = vector_ty->As<type::Vector>()) {
|
||||||
packed_size = vec->Width() + 1;
|
packed_size = vec->Width() + 1;
|
||||||
|
|
|
@ -1814,7 +1814,7 @@ bool GeneratorImpl::EmitDiscard(const ast::DiscardStatement*) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
|
bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
|
||||||
if (auto* sem = builder_.Sem().Get(expr)) {
|
if (auto* sem = builder_.Sem().GetVal(expr)) {
|
||||||
if (auto* constant = sem->ConstantValue()) {
|
if (auto* constant = sem->ConstantValue()) {
|
||||||
return EmitConstant(out, constant);
|
return EmitConstant(out, constant);
|
||||||
}
|
}
|
||||||
|
|
|
@ -658,8 +658,8 @@ bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
|
||||||
// with at least one dynamic index
|
// with at least one dynamic index
|
||||||
if (auto* lhs_sub_access = lhs_access->object->As<ast::IndexAccessorExpression>()) {
|
if (auto* lhs_sub_access = lhs_access->object->As<ast::IndexAccessorExpression>()) {
|
||||||
if (auto* mat = TypeOf(lhs_sub_access->object)->UnwrapRef()->As<type::Matrix>()) {
|
if (auto* mat = TypeOf(lhs_sub_access->object)->UnwrapRef()->As<type::Matrix>()) {
|
||||||
auto* rhs_row_idx_sem = builder_.Sem().Get(lhs_access->index);
|
auto* rhs_row_idx_sem = builder_.Sem().GetVal(lhs_access->index);
|
||||||
auto* rhs_col_idx_sem = builder_.Sem().Get(lhs_sub_access->index);
|
auto* rhs_col_idx_sem = builder_.Sem().GetVal(lhs_sub_access->index);
|
||||||
if (!rhs_row_idx_sem->ConstantValue() || !rhs_col_idx_sem->ConstantValue()) {
|
if (!rhs_row_idx_sem->ConstantValue() || !rhs_col_idx_sem->ConstantValue()) {
|
||||||
return EmitDynamicMatrixScalarAssignment(stmt, mat);
|
return EmitDynamicMatrixScalarAssignment(stmt, mat);
|
||||||
}
|
}
|
||||||
|
@ -669,7 +669,7 @@ bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
|
||||||
// with dynamic indices
|
// with dynamic indices
|
||||||
const auto* lhs_access_type = TypeOf(lhs_access->object)->UnwrapRef();
|
const auto* lhs_access_type = TypeOf(lhs_access->object)->UnwrapRef();
|
||||||
if (auto* mat = lhs_access_type->As<type::Matrix>()) {
|
if (auto* mat = lhs_access_type->As<type::Matrix>()) {
|
||||||
auto* lhs_index_sem = builder_.Sem().Get(lhs_access->index);
|
auto* lhs_index_sem = builder_.Sem().GetVal(lhs_access->index);
|
||||||
if (!lhs_index_sem->ConstantValue()) {
|
if (!lhs_index_sem->ConstantValue()) {
|
||||||
return EmitDynamicMatrixVectorAssignment(stmt, mat);
|
return EmitDynamicMatrixVectorAssignment(stmt, mat);
|
||||||
}
|
}
|
||||||
|
@ -677,7 +677,7 @@ bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
|
||||||
// BUG(crbug.com/tint/534): work around assignment to vectors with dynamic
|
// BUG(crbug.com/tint/534): work around assignment to vectors with dynamic
|
||||||
// indices
|
// indices
|
||||||
if (auto* vec = lhs_access_type->As<type::Vector>()) {
|
if (auto* vec = lhs_access_type->As<type::Vector>()) {
|
||||||
auto* rhs_sem = builder_.Sem().Get(lhs_access->index);
|
auto* rhs_sem = builder_.Sem().GetVal(lhs_access->index);
|
||||||
if (!rhs_sem->ConstantValue()) {
|
if (!rhs_sem->ConstantValue()) {
|
||||||
return EmitDynamicVectorAssignment(stmt, vec);
|
return EmitDynamicVectorAssignment(stmt, vec);
|
||||||
}
|
}
|
||||||
|
@ -1109,7 +1109,7 @@ bool GeneratorImpl::EmitUniformBufferAccess(
|
||||||
const ast::CallExpression* expr,
|
const ast::CallExpression* expr,
|
||||||
const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
|
const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
|
||||||
const auto& args = expr->args;
|
const auto& args = expr->args;
|
||||||
auto* offset_arg = builder_.Sem().Get(args[1]);
|
auto* offset_arg = builder_.Sem().GetVal(args[1]);
|
||||||
|
|
||||||
// offset in bytes
|
// offset in bytes
|
||||||
uint32_t scalar_offset_bytes = 0;
|
uint32_t scalar_offset_bytes = 0;
|
||||||
|
@ -2790,7 +2790,7 @@ bool GeneratorImpl::EmitDiscard(const ast::DiscardStatement*) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
|
bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
|
||||||
if (auto* sem = builder_.Sem().Get(expr)) {
|
if (auto* sem = builder_.Sem().GetVal(expr)) {
|
||||||
if (auto* constant = sem->ConstantValue()) {
|
if (auto* constant = sem->ConstantValue()) {
|
||||||
bool is_variable_initializer = false;
|
bool is_variable_initializer = false;
|
||||||
if (auto* stmt = sem->Stmt()) {
|
if (auto* stmt = sem->Stmt()) {
|
||||||
|
@ -3864,7 +3864,7 @@ bool GeneratorImpl::EmitDefaultOnlySwitch(const ast::SwitchStatement* stmt) {
|
||||||
|
|
||||||
// Emit the switch condition as-is if it has side-effects (e.g.
|
// Emit the switch condition as-is if it has side-effects (e.g.
|
||||||
// function call). Note that we can ignore the result of the expression (if any).
|
// function call). Note that we can ignore the result of the expression (if any).
|
||||||
if (auto* sem_cond = builder_.Sem().Get(stmt->condition); sem_cond->HasSideEffects()) {
|
if (auto* sem_cond = builder_.Sem().GetVal(stmt->condition); sem_cond->HasSideEffects()) {
|
||||||
auto out = line();
|
auto out = line();
|
||||||
if (!EmitExpression(out, stmt->condition)) {
|
if (!EmitExpression(out, stmt->condition)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -733,7 +733,7 @@ bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
|
||||||
}
|
}
|
||||||
|
|
||||||
case sem::BuiltinType::kLength: {
|
case sem::BuiltinType::kLength: {
|
||||||
auto* sem = builder_.Sem().Get(expr->args[0]);
|
auto* sem = builder_.Sem().GetVal(expr->args[0]);
|
||||||
if (sem->Type()->UnwrapRef()->is_scalar()) {
|
if (sem->Type()->UnwrapRef()->is_scalar()) {
|
||||||
// Emulate scalar overload using fabs(x).
|
// Emulate scalar overload using fabs(x).
|
||||||
name = "fabs";
|
name = "fabs";
|
||||||
|
@ -742,7 +742,7 @@ bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
|
||||||
}
|
}
|
||||||
|
|
||||||
case sem::BuiltinType::kDistance: {
|
case sem::BuiltinType::kDistance: {
|
||||||
auto* sem = builder_.Sem().Get(expr->args[0]);
|
auto* sem = builder_.Sem().GetVal(expr->args[0]);
|
||||||
if (sem->Type()->UnwrapRef()->is_scalar()) {
|
if (sem->Type()->UnwrapRef()->is_scalar()) {
|
||||||
// Emulate scalar overload using fabs(x - y);
|
// Emulate scalar overload using fabs(x - y);
|
||||||
out << "fabs";
|
out << "fabs";
|
||||||
|
@ -1827,7 +1827,7 @@ bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression*
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
|
bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
|
||||||
if (auto* sem = builder_.Sem().Get(expr)) {
|
if (auto* sem = builder_.Sem().GetVal(expr)) {
|
||||||
if (auto* constant = sem->ConstantValue()) {
|
if (auto* constant = sem->ConstantValue()) {
|
||||||
return EmitConstant(out, constant);
|
return EmitConstant(out, constant);
|
||||||
}
|
}
|
||||||
|
|
|
@ -424,7 +424,7 @@ bool Builder::GenerateLabel(uint32_t id) {
|
||||||
|
|
||||||
bool Builder::GenerateAssignStatement(const ast::AssignmentStatement* assign) {
|
bool Builder::GenerateAssignStatement(const ast::AssignmentStatement* assign) {
|
||||||
if (assign->lhs->Is<ast::PhonyExpression>()) {
|
if (assign->lhs->Is<ast::PhonyExpression>()) {
|
||||||
if (builder_.Sem().Get(assign->rhs)->ConstantValue()) {
|
if (builder_.Sem().GetVal(assign->rhs)->ConstantValue()) {
|
||||||
// RHS of phony assignment is constant.
|
// RHS of phony assignment is constant.
|
||||||
// Constants can't have side-effects, so just drop this.
|
// Constants can't have side-effects, so just drop this.
|
||||||
return true;
|
return true;
|
||||||
|
@ -558,9 +558,11 @@ bool Builder::GenerateExecutionModes(const ast::Function* func, uint32_t id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Builder::GenerateExpression(const sem::ValueExpression* expr) {
|
uint32_t Builder::GenerateExpression(const sem::Expression* expr) {
|
||||||
if (auto* constant = expr->ConstantValue()) {
|
if (auto* val_expr = expr->As<sem::ValueExpression>()) {
|
||||||
return GenerateConstantIfNeeded(constant);
|
if (auto* constant = val_expr->ConstantValue()) {
|
||||||
|
return GenerateConstantIfNeeded(constant);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (auto* load = expr->As<sem::Load>()) {
|
if (auto* load = expr->As<sem::Load>()) {
|
||||||
auto ref_id = GenerateExpression(load->Reference());
|
auto ref_id = GenerateExpression(load->Reference());
|
||||||
|
@ -909,7 +911,7 @@ bool Builder::GenerateIndexAccessor(const ast::IndexAccessorExpression* expr, Ac
|
||||||
auto extract_id = std::get<uint32_t>(extract);
|
auto extract_id = std::get<uint32_t>(extract);
|
||||||
|
|
||||||
// If the index is compile-time constant, we use OpCompositeExtract.
|
// If the index is compile-time constant, we use OpCompositeExtract.
|
||||||
auto* idx = builder_.Sem().Get(expr->index);
|
auto* idx = builder_.Sem().GetVal(expr->index);
|
||||||
if (auto idx_constval = idx->ConstantValue()) {
|
if (auto idx_constval = idx->ConstantValue()) {
|
||||||
if (!push_function_inst(spv::Op::OpCompositeExtract,
|
if (!push_function_inst(spv::Op::OpCompositeExtract,
|
||||||
{
|
{
|
||||||
|
@ -1140,8 +1142,7 @@ uint32_t Builder::GenerateAccessorExpression(const ast::AccessorExpression* expr
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Builder::GenerateIdentifierExpression(const ast::IdentifierExpression* expr) {
|
uint32_t Builder::GenerateIdentifierExpression(const ast::IdentifierExpression* expr) {
|
||||||
auto* sem = builder_.Sem().Get(expr);
|
if (auto* sem = builder_.Sem().GetVal(expr); sem) {
|
||||||
if (sem) {
|
|
||||||
if (auto* user = sem->UnwrapLoad()->As<sem::VariableUser>()) {
|
if (auto* user = sem->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||||
return LookupVariableID(user->Variable());
|
return LookupVariableID(user->Variable());
|
||||||
}
|
}
|
||||||
|
@ -1231,7 +1232,7 @@ uint32_t Builder::GetGLSLstd450Import() {
|
||||||
|
|
||||||
uint32_t Builder::GenerateInitializerExpression(const ast::Variable* var,
|
uint32_t Builder::GenerateInitializerExpression(const ast::Variable* var,
|
||||||
const ast::Expression* expr) {
|
const ast::Expression* expr) {
|
||||||
if (auto* sem = builder_.Sem().Get(expr)) {
|
if (auto* sem = builder_.Sem().GetVal(expr)) {
|
||||||
if (auto constant = sem->ConstantValue()) {
|
if (auto constant = sem->ConstantValue()) {
|
||||||
return GenerateConstantIfNeeded(constant);
|
return GenerateConstantIfNeeded(constant);
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,7 +275,7 @@ class Builder {
|
||||||
/// Generates an expression
|
/// Generates an expression
|
||||||
/// @param expr the expression to generate
|
/// @param expr the expression to generate
|
||||||
/// @returns the resulting ID of the expression or 0 on error
|
/// @returns the resulting ID of the expression or 0 on error
|
||||||
uint32_t GenerateExpression(const sem::ValueExpression* expr);
|
uint32_t GenerateExpression(const sem::Expression* expr);
|
||||||
/// Generates an expression
|
/// Generates an expression
|
||||||
/// @param expr the expression to generate
|
/// @param expr the expression to generate
|
||||||
/// @returns the resulting ID of the expression or 0 on error
|
/// @returns the resulting ID of the expression or 0 on error
|
||||||
|
|
Loading…
Reference in New Issue