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:
Ben Clayton 2023-02-05 22:59:40 +00:00 committed by Dawn LUCI CQ
parent ef1811a18b
commit 0b4a2f1f50
55 changed files with 295 additions and 156 deletions

View File

@ -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",

View File

@ -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

View File

@ -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.

View File

@ -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 =

View File

@ -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

View File

@ -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>()) {

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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));
} }

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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
} }

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -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;
} }

View File

@ -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

View File

@ -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());

View File

@ -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";

View File

@ -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);
} }

View File

@ -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

55
src/tint/sem/expression.h Normal file
View File

@ -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_

View File

@ -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

View File

@ -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

View File

@ -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_);

View File

@ -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_;

View File

@ -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) {

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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()) {

View File

@ -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 "

View File

@ -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());

View File

@ -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));
} }
}); });
} }

View File

@ -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));
}); });

View File

@ -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);
} }
} }

View File

@ -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;

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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())

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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);
} }

View File

@ -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;

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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