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:
parent
e93d46fcbc
commit
86c2cbfb7e
|
@ -1631,20 +1631,30 @@ void Resolver::CreateSemanticNodes() const {
|
||||||
for (auto it : variable_to_info_) {
|
for (auto it : variable_to_info_) {
|
||||||
auto* var = it.first;
|
auto* var = it.first;
|
||||||
auto* info = it.second;
|
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) {
|
for (auto* user : info->users) {
|
||||||
// Create semantic node for the identifier expression if necessary
|
// Create semantic node for the identifier expression if necessary
|
||||||
auto* sem_expr = sem.Get(user);
|
auto* sem_expr = sem.Get(user);
|
||||||
if (sem_expr == nullptr) {
|
if (sem_expr == nullptr) {
|
||||||
auto* type = expr_info_.at(user).type;
|
auto* type = expr_info_.at(user).type;
|
||||||
auto* stmt = expr_info_.at(user).statement;
|
auto* stmt = expr_info_.at(user).statement;
|
||||||
sem_expr = builder_->create<semantic::Expression>(user, type, stmt);
|
auto* sem_user =
|
||||||
sem.Add(user, sem_expr);
|
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>(
|
sem.Add(var, sem_var);
|
||||||
var, info->type, info->storage_class, std::move(users)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remap_vars = [&sem](const std::vector<VariableInfo*>& in) {
|
auto remap_vars = [&sem](const std::vector<VariableInfo*>& in) {
|
||||||
|
|
|
@ -135,7 +135,7 @@ class Resolver {
|
||||||
StructInfo();
|
StructInfo();
|
||||||
~StructInfo();
|
~StructInfo();
|
||||||
|
|
||||||
std::vector<semantic::StructMember*> members;
|
std::vector<const semantic::StructMember*> members;
|
||||||
uint32_t align = 0;
|
uint32_t align = 0;
|
||||||
uint32_t size = 0;
|
uint32_t size = 0;
|
||||||
uint32_t size_no_padding = 0;
|
uint32_t size_no_padding = 0;
|
||||||
|
|
|
@ -338,6 +338,10 @@ TEST_F(ResolverTest, Stmt_VariableDecl_OuterScopeAfterInnerScope) {
|
||||||
EXPECT_EQ(StmtOf(bar_f32_init), bar_f32_decl);
|
EXPECT_EQ(StmtOf(bar_f32_init), bar_f32_decl);
|
||||||
EXPECT_TRUE(CheckVarUsers(foo_i32, {bar_i32->constructor()}));
|
EXPECT_TRUE(CheckVarUsers(foo_i32, {bar_i32->constructor()}));
|
||||||
EXPECT_TRUE(CheckVarUsers(foo_f32, {bar_f32->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) {
|
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_EQ(StmtOf(fn_f32_init), fn_f32_decl);
|
||||||
EXPECT_TRUE(CheckVarUsers(fn_i32, {}));
|
EXPECT_TRUE(CheckVarUsers(fn_i32, {}));
|
||||||
EXPECT_TRUE(CheckVarUsers(mod_f32, {fn_f32->constructor()}));
|
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) {
|
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)->Is<type::Pointer>());
|
||||||
EXPECT_TRUE(TypeOf(ident)->As<type::Pointer>()->type()->Is<type::F32>());
|
EXPECT_TRUE(TypeOf(ident)->As<type::Pointer>()->type()->Is<type::F32>());
|
||||||
EXPECT_TRUE(CheckVarUsers(my_var, {ident}));
|
EXPECT_TRUE(CheckVarUsers(my_var, {ident}));
|
||||||
|
ASSERT_NE(VarOf(ident), nullptr);
|
||||||
|
EXPECT_EQ(VarOf(ident)->Declaration(), my_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Expr_Identifier_GlobalConstant) {
|
TEST_F(ResolverTest, Expr_Identifier_GlobalConstant) {
|
||||||
|
@ -625,6 +633,8 @@ TEST_F(ResolverTest, Expr_Identifier_GlobalConstant) {
|
||||||
ASSERT_NE(TypeOf(ident), nullptr);
|
ASSERT_NE(TypeOf(ident), nullptr);
|
||||||
EXPECT_TRUE(TypeOf(ident)->Is<type::F32>());
|
EXPECT_TRUE(TypeOf(ident)->Is<type::F32>());
|
||||||
EXPECT_TRUE(CheckVarUsers(my_var, {ident}));
|
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) {
|
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_TRUE(TypeOf(my_var_a)->Is<type::F32>());
|
||||||
EXPECT_EQ(StmtOf(my_var_a), decl);
|
EXPECT_EQ(StmtOf(my_var_a), decl);
|
||||||
EXPECT_TRUE(CheckVarUsers(var, {my_var_a}));
|
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) {
|
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_TRUE(TypeOf(my_var_b)->As<type::Pointer>()->type()->Is<type::F32>());
|
||||||
EXPECT_EQ(StmtOf(my_var_b), assign);
|
EXPECT_EQ(StmtOf(my_var_b), assign);
|
||||||
EXPECT_TRUE(CheckVarUsers(var, {my_var_a, my_var_b}));
|
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) {
|
TEST_F(ResolverTest, Expr_Identifier_Function_Ptr) {
|
||||||
|
|
|
@ -67,6 +67,17 @@ class TestHelper : public ProgramBuilder {
|
||||||
return sem_stmt ? sem_stmt->Block() : nullptr;
|
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
|
/// Checks that all the users of the given variable are as expected
|
||||||
/// @param var the variable to check
|
/// @param var the variable to check
|
||||||
/// @param expected_users the expected users of the variable
|
/// @param expected_users the expected users of the variable
|
||||||
|
|
|
@ -37,9 +37,9 @@ class Expression : public Castable<Expression, Node> {
|
||||||
/// @param declaration the AST node
|
/// @param declaration the AST node
|
||||||
/// @param type the resolved type of the expression
|
/// @param type the resolved type of the expression
|
||||||
/// @param statement the statement that owns this expression
|
/// @param statement the statement that owns this expression
|
||||||
explicit Expression(ast::Expression* declaration,
|
Expression(ast::Expression* declaration,
|
||||||
type::Type* type,
|
type::Type* type,
|
||||||
Statement* statement);
|
Statement* statement);
|
||||||
|
|
||||||
/// @return the resolved type of the expression
|
/// @return the resolved type of the expression
|
||||||
type::Type* Type() const { return type_; }
|
type::Type* Type() const { return type_; }
|
||||||
|
|
|
@ -14,21 +14,26 @@
|
||||||
|
|
||||||
#include "src/semantic/variable.h"
|
#include "src/semantic/variable.h"
|
||||||
|
|
||||||
|
#include "src/ast/identifier_expression.h"
|
||||||
|
|
||||||
TINT_INSTANTIATE_TYPEINFO(tint::semantic::Variable);
|
TINT_INSTANTIATE_TYPEINFO(tint::semantic::Variable);
|
||||||
|
TINT_INSTANTIATE_TYPEINFO(tint::semantic::VariableUser);
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace semantic {
|
namespace semantic {
|
||||||
|
|
||||||
Variable::Variable(const ast::Variable* declaration,
|
Variable::Variable(const ast::Variable* declaration,
|
||||||
type::Type* type,
|
type::Type* type,
|
||||||
ast::StorageClass storage_class,
|
ast::StorageClass storage_class)
|
||||||
std::vector<const Expression*> users)
|
: declaration_(declaration), type_(type), storage_class_(storage_class) {}
|
||||||
: declaration_(declaration),
|
|
||||||
type_(type),
|
|
||||||
storage_class_(storage_class),
|
|
||||||
users_(std::move(users)) {}
|
|
||||||
|
|
||||||
Variable::~Variable() = default;
|
Variable::~Variable() = default;
|
||||||
|
|
||||||
|
VariableUser::VariableUser(ast::IdentifierExpression* declaration,
|
||||||
|
type::Type* type,
|
||||||
|
Statement* statement,
|
||||||
|
semantic::Variable* variable)
|
||||||
|
: Base(declaration, type, statement), variable_(variable) {}
|
||||||
|
|
||||||
} // namespace semantic
|
} // namespace semantic
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace semantic {
|
||||||
class StructMember;
|
class StructMember;
|
||||||
|
|
||||||
/// A vector of StructMember pointers.
|
/// A vector of StructMember pointers.
|
||||||
using StructMemberList = std::vector<StructMember*>;
|
using StructMemberList = std::vector<const StructMember*>;
|
||||||
|
|
||||||
/// Metadata to capture how a structure is used in a shader module.
|
/// Metadata to capture how a structure is used in a shader module.
|
||||||
enum class PipelineStageUsage {
|
enum class PipelineStageUsage {
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace tint {
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
namespace ast {
|
namespace ast {
|
||||||
|
class IdentifierExpression;
|
||||||
class Variable;
|
class Variable;
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
namespace type {
|
namespace type {
|
||||||
|
@ -32,6 +33,8 @@ class Type;
|
||||||
|
|
||||||
namespace semantic {
|
namespace semantic {
|
||||||
|
|
||||||
|
class VariableUser;
|
||||||
|
|
||||||
/// Variable holds the semantic information for variables.
|
/// Variable holds the semantic information for variables.
|
||||||
class Variable : public Castable<Variable, Node> {
|
class Variable : public Castable<Variable, Node> {
|
||||||
public:
|
public:
|
||||||
|
@ -39,11 +42,9 @@ class Variable : public Castable<Variable, Node> {
|
||||||
/// @param declaration the AST declaration node
|
/// @param declaration the AST declaration node
|
||||||
/// @param type the variable type
|
/// @param type the variable type
|
||||||
/// @param storage_class the variable storage class
|
/// @param storage_class the variable storage class
|
||||||
/// @param users the expressions that use the variable
|
Variable(const ast::Variable* declaration,
|
||||||
explicit Variable(const ast::Variable* declaration,
|
type::Type* type,
|
||||||
type::Type* type,
|
ast::StorageClass storage_class);
|
||||||
ast::StorageClass storage_class,
|
|
||||||
std::vector<const Expression*> users);
|
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Variable() override;
|
~Variable() override;
|
||||||
|
@ -58,13 +59,37 @@ class Variable : public Castable<Variable, Node> {
|
||||||
ast::StorageClass StorageClass() const { return storage_class_; }
|
ast::StorageClass StorageClass() const { return storage_class_; }
|
||||||
|
|
||||||
/// @returns the expressions that use the variable
|
/// @returns the expressions that use the variable
|
||||||
const std::vector<const Expression*>& Users() const { return users_; }
|
const std::vector<const VariableUser*>& Users() const { return users_; }
|
||||||
|
|
||||||
|
/// @param user the user to add
|
||||||
|
void AddUser(const VariableUser* user) { users_.emplace_back(user); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ast::Variable* const declaration_;
|
const ast::Variable* const declaration_;
|
||||||
type::Type* const type_;
|
type::Type* const type_;
|
||||||
ast::StorageClass const storage_class_;
|
ast::StorageClass const storage_class_;
|
||||||
std::vector<const Expression*> const users_;
|
std::vector<const VariableUser*> users_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// VariableUser holds the semantic information for an identifier expression
|
||||||
|
/// node that resolves to a variable.
|
||||||
|
class VariableUser : public Castable<VariableUser, Expression> {
|
||||||
|
public:
|
||||||
|
/// Constructor
|
||||||
|
/// @param declaration the AST identifier node
|
||||||
|
/// @param type the resolved type of the expression
|
||||||
|
/// @param statement the statement that owns this expression
|
||||||
|
/// @param variable the semantic variable
|
||||||
|
VariableUser(ast::IdentifierExpression* declaration,
|
||||||
|
type::Type* type,
|
||||||
|
Statement* statement,
|
||||||
|
semantic::Variable* variable);
|
||||||
|
|
||||||
|
/// @returns the variable that this expression refers to
|
||||||
|
const semantic::Variable* Variable() const { return variable_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
semantic::Variable const* const variable_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace semantic
|
} // namespace semantic
|
||||||
|
|
Loading…
Reference in New Issue