Add semantic::VariableUser

Derives from semantic::Expression.
Maps to ast::IdentifierExpressions that resolve to a variable.

Breaks pure-immutability of semantic::Variable, as we have discussed in the past.

Change-Id: I362d4d1ed61291282a60626b84fb15566655fb14
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/46627
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
This commit is contained in:
Ben Clayton
2021-04-07 08:09:01 +00:00
committed by Commit Bot service account
parent e93d46fcbc
commit 86c2cbfb7e
8 changed files with 91 additions and 24 deletions

View File

@@ -1631,20 +1631,30 @@ void Resolver::CreateSemanticNodes() const {
for (auto it : variable_to_info_) {
auto* var = it.first;
auto* info = it.second;
std::vector<const semantic::Expression*> users;
auto* sem_var = builder_->create<semantic::Variable>(var, info->type,
info->storage_class);
std::vector<const semantic::VariableUser*> users;
for (auto* user : info->users) {
// Create semantic node for the identifier expression if necessary
auto* sem_expr = sem.Get(user);
if (sem_expr == nullptr) {
auto* type = expr_info_.at(user).type;
auto* stmt = expr_info_.at(user).statement;
sem_expr = builder_->create<semantic::Expression>(user, type, stmt);
sem.Add(user, sem_expr);
auto* sem_user =
builder_->create<semantic::VariableUser>(user, type, stmt, sem_var);
sem_var->AddUser(sem_user);
sem.Add(user, sem_user);
} else {
auto* sem_user = sem_expr->As<semantic::VariableUser>();
if (!sem_user) {
TINT_ICE(builder_->Diagnostics())
<< "expected semantic::VariableUser, got "
<< sem_expr->TypeInfo().name;
}
sem_var->AddUser(sem_user);
}
users.push_back(sem_expr);
}
sem.Add(var, builder_->create<semantic::Variable>(
var, info->type, info->storage_class, std::move(users)));
sem.Add(var, sem_var);
}
auto remap_vars = [&sem](const std::vector<VariableInfo*>& in) {

View File

@@ -135,7 +135,7 @@ class Resolver {
StructInfo();
~StructInfo();
std::vector<semantic::StructMember*> members;
std::vector<const semantic::StructMember*> members;
uint32_t align = 0;
uint32_t size = 0;
uint32_t size_no_padding = 0;

View File

@@ -338,6 +338,10 @@ TEST_F(ResolverTest, Stmt_VariableDecl_OuterScopeAfterInnerScope) {
EXPECT_EQ(StmtOf(bar_f32_init), bar_f32_decl);
EXPECT_TRUE(CheckVarUsers(foo_i32, {bar_i32->constructor()}));
EXPECT_TRUE(CheckVarUsers(foo_f32, {bar_f32->constructor()}));
ASSERT_NE(VarOf(bar_i32->constructor()), nullptr);
EXPECT_EQ(VarOf(bar_i32->constructor())->Declaration(), foo_i32);
ASSERT_NE(VarOf(bar_f32->constructor()), nullptr);
EXPECT_EQ(VarOf(bar_f32->constructor())->Declaration(), foo_f32);
}
TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) {
@@ -383,6 +387,8 @@ TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) {
EXPECT_EQ(StmtOf(fn_f32_init), fn_f32_decl);
EXPECT_TRUE(CheckVarUsers(fn_i32, {}));
EXPECT_TRUE(CheckVarUsers(mod_f32, {fn_f32->constructor()}));
ASSERT_NE(VarOf(fn_f32->constructor()), nullptr);
EXPECT_EQ(VarOf(fn_f32->constructor())->Declaration(), mod_f32);
}
TEST_F(ResolverTest, Expr_ArrayAccessor_Array) {
@@ -612,6 +618,8 @@ TEST_F(ResolverTest, Expr_Identifier_GlobalVariable) {
EXPECT_TRUE(TypeOf(ident)->Is<type::Pointer>());
EXPECT_TRUE(TypeOf(ident)->As<type::Pointer>()->type()->Is<type::F32>());
EXPECT_TRUE(CheckVarUsers(my_var, {ident}));
ASSERT_NE(VarOf(ident), nullptr);
EXPECT_EQ(VarOf(ident)->Declaration(), my_var);
}
TEST_F(ResolverTest, Expr_Identifier_GlobalConstant) {
@@ -625,6 +633,8 @@ TEST_F(ResolverTest, Expr_Identifier_GlobalConstant) {
ASSERT_NE(TypeOf(ident), nullptr);
EXPECT_TRUE(TypeOf(ident)->Is<type::F32>());
EXPECT_TRUE(CheckVarUsers(my_var, {ident}));
ASSERT_NE(VarOf(ident), nullptr);
EXPECT_EQ(VarOf(ident)->Declaration(), my_var);
}
TEST_F(ResolverTest, Expr_Identifier_FunctionVariable_Const) {
@@ -645,6 +655,8 @@ TEST_F(ResolverTest, Expr_Identifier_FunctionVariable_Const) {
EXPECT_TRUE(TypeOf(my_var_a)->Is<type::F32>());
EXPECT_EQ(StmtOf(my_var_a), decl);
EXPECT_TRUE(CheckVarUsers(var, {my_var_a}));
ASSERT_NE(VarOf(my_var_a), nullptr);
EXPECT_EQ(VarOf(my_var_a)->Declaration(), var);
}
TEST_F(ResolverTest, Expr_Identifier_FunctionVariable) {
@@ -672,6 +684,10 @@ TEST_F(ResolverTest, Expr_Identifier_FunctionVariable) {
EXPECT_TRUE(TypeOf(my_var_b)->As<type::Pointer>()->type()->Is<type::F32>());
EXPECT_EQ(StmtOf(my_var_b), assign);
EXPECT_TRUE(CheckVarUsers(var, {my_var_a, my_var_b}));
ASSERT_NE(VarOf(my_var_a), nullptr);
EXPECT_EQ(VarOf(my_var_a)->Declaration(), var);
ASSERT_NE(VarOf(my_var_b), nullptr);
EXPECT_EQ(VarOf(my_var_b)->Declaration(), var);
}
TEST_F(ResolverTest, Expr_Identifier_Function_Ptr) {

View File

@@ -67,6 +67,17 @@ class TestHelper : public ProgramBuilder {
return sem_stmt ? sem_stmt->Block() : nullptr;
}
/// Returns the semantic variable for the given identifier expression.
/// @param expr the identifier expression
/// @return the resolved semantic::Variable of the identifier, or nullptr if
/// the expression did not resolve to a variable.
const semantic::Variable* VarOf(ast::Expression* expr) {
auto* sem_ident = Sem().Get(expr);
auto* var_user =
sem_ident ? sem_ident->As<semantic::VariableUser>() : nullptr;
return var_user ? var_user->Variable() : nullptr;
}
/// Checks that all the users of the given variable are as expected
/// @param var the variable to check
/// @param expected_users the expected users of the variable