ast: Migrate to using ast::Type
Remove all sem::Type references from the AST. ConstructedTypes are now all AST types. The parsers will still create semantic types, but these are now disjoint and ignored. The parsers will be updated with future changes to stop creating these semantic types. Resolver creates semantic types from the AST types. Most downstream logic continues to use the semantic types, however transforms will now need to rebuild AST type information instead of reassigning semantic information, as semantic nodes are fully rebuilt by the Resolver. Bug: tint:724 Change-Id: I4ce03a075f13c77648cda5c3691bae202752ecc5 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/49747 Commit-Queue: Ben Clayton <bclayton@chromium.org> Commit-Queue: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com> Reviewed-by: James Price <jrprice@google.com>
This commit is contained in:
parent
781de097eb
commit
02ebf0dcae
|
@ -23,10 +23,10 @@ namespace ast {
|
||||||
|
|
||||||
BitcastExpression::BitcastExpression(ProgramID program_id,
|
BitcastExpression::BitcastExpression(ProgramID program_id,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
Expression* expr)
|
Expression* expr)
|
||||||
: Base(program_id, source), type_(type), expr_(expr) {
|
: Base(program_id, source), type_(type), expr_(expr) {
|
||||||
TINT_ASSERT(type_.ast || type_.sem);
|
TINT_ASSERT(type_);
|
||||||
TINT_ASSERT(expr_);
|
TINT_ASSERT(expr_);
|
||||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(expr, program_id);
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(expr, program_id);
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ BitcastExpression::~BitcastExpression() = default;
|
||||||
BitcastExpression* BitcastExpression::Clone(CloneContext* ctx) const {
|
BitcastExpression* BitcastExpression::Clone(CloneContext* ctx) const {
|
||||||
// Clone arguments outside of create() call to have deterministic ordering
|
// Clone arguments outside of create() call to have deterministic ordering
|
||||||
auto src = ctx->Clone(source());
|
auto src = ctx->Clone(source());
|
||||||
auto ty = ctx->Clone(type());
|
auto* ty = ctx->Clone(type());
|
||||||
auto* e = ctx->Clone(expr_);
|
auto* e = ctx->Clone(expr_);
|
||||||
return ctx->dst->create<BitcastExpression>(src, ty, e);
|
return ctx->dst->create<BitcastExpression>(src, ty, e);
|
||||||
}
|
}
|
||||||
|
@ -46,9 +46,8 @@ void BitcastExpression::to_str(const sem::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
make_indent(out, indent);
|
make_indent(out, indent);
|
||||||
out << "Bitcast[" << result_type_str(sem) << "]<"
|
out << "Bitcast[" << result_type_str(sem) << "]<" << type_->type_name()
|
||||||
<< (type_.ast ? type_.ast->type_name() : type_.sem->type_name()) << ">{"
|
<< ">{" << std::endl;
|
||||||
<< std::endl;
|
|
||||||
expr_->to_str(sem, out, indent + 2);
|
expr_->to_str(sem, out, indent + 2);
|
||||||
make_indent(out, indent);
|
make_indent(out, indent);
|
||||||
out << "}" << std::endl;
|
out << "}" << std::endl;
|
||||||
|
|
|
@ -30,14 +30,14 @@ class BitcastExpression : public Castable<BitcastExpression, Expression> {
|
||||||
/// @param expr the expr
|
/// @param expr the expr
|
||||||
BitcastExpression(ProgramID program_id,
|
BitcastExpression(ProgramID program_id,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
Expression* expr);
|
Expression* expr);
|
||||||
/// Move constructor
|
/// Move constructor
|
||||||
BitcastExpression(BitcastExpression&&);
|
BitcastExpression(BitcastExpression&&);
|
||||||
~BitcastExpression() override;
|
~BitcastExpression() override;
|
||||||
|
|
||||||
/// @returns the left side expression
|
/// @returns the left side expression
|
||||||
typ::Type type() const { return type_; }
|
ast::Type* type() const { return type_; }
|
||||||
/// @returns the expression
|
/// @returns the expression
|
||||||
Expression* expr() const { return expr_; }
|
Expression* expr() const { return expr_; }
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class BitcastExpression : public Castable<BitcastExpression, Expression> {
|
||||||
private:
|
private:
|
||||||
BitcastExpression(const BitcastExpression&) = delete;
|
BitcastExpression(const BitcastExpression&) = delete;
|
||||||
|
|
||||||
typ::Type const type_;
|
ast::Type* const type_;
|
||||||
Expression* const expr_;
|
Expression* const expr_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ TEST_F(BitcastExpressionTest, Create) {
|
||||||
auto* expr = Expr("expr");
|
auto* expr = Expr("expr");
|
||||||
|
|
||||||
auto* exp = create<BitcastExpression>(ty.f32(), expr);
|
auto* exp = create<BitcastExpression>(ty.f32(), expr);
|
||||||
ASSERT_EQ(exp->type(), ty.f32());
|
EXPECT_TRUE(exp->type()->Is<ast::F32>());
|
||||||
ASSERT_EQ(exp->expr(), expr);
|
ASSERT_EQ(exp->expr(), expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ Function::Function(ProgramID program_id,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
Symbol symbol,
|
Symbol symbol,
|
||||||
VariableList params,
|
VariableList params,
|
||||||
typ::Type return_type,
|
ast::Type* return_type,
|
||||||
BlockStatement* body,
|
BlockStatement* body,
|
||||||
DecorationList decorations,
|
DecorationList decorations,
|
||||||
DecorationList return_type_decorations)
|
DecorationList return_type_decorations)
|
||||||
|
@ -45,7 +45,7 @@ Function::Function(ProgramID program_id,
|
||||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(param, program_id);
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(param, program_id);
|
||||||
}
|
}
|
||||||
TINT_ASSERT(symbol_.IsValid());
|
TINT_ASSERT(symbol_.IsValid());
|
||||||
TINT_ASSERT(return_type_.ast || return_type_.sem);
|
TINT_ASSERT(return_type_);
|
||||||
for (auto* deco : decorations_) {
|
for (auto* deco : decorations_) {
|
||||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(deco, program_id);
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(deco, program_id);
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ Function* Function::Clone(CloneContext* ctx) const {
|
||||||
auto src = ctx->Clone(source());
|
auto src = ctx->Clone(source());
|
||||||
auto sym = ctx->Clone(symbol());
|
auto sym = ctx->Clone(symbol());
|
||||||
auto p = ctx->Clone(params_);
|
auto p = ctx->Clone(params_);
|
||||||
auto ret = ctx->Clone(return_type_);
|
auto* ret = ctx->Clone(return_type_);
|
||||||
auto* b = ctx->Clone(body_);
|
auto* b = ctx->Clone(body_);
|
||||||
auto decos = ctx->Clone(decorations_);
|
auto decos = ctx->Clone(decorations_);
|
||||||
auto ret_decos = ctx->Clone(return_type_decorations_);
|
auto ret_decos = ctx->Clone(return_type_decorations_);
|
||||||
|
@ -92,9 +92,7 @@ void Function::to_str(const sem::Info& sem,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
size_t indent) const {
|
size_t indent) const {
|
||||||
make_indent(out, indent);
|
make_indent(out, indent);
|
||||||
out << "Function " << symbol_.to_str() << " -> "
|
out << "Function " << symbol_.to_str() << " -> " << return_type_->type_name()
|
||||||
<< (return_type_.ast ? return_type_.ast->type_name()
|
|
||||||
: return_type_.sem->type_name())
|
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
for (auto* deco : decorations()) {
|
for (auto* deco : decorations()) {
|
||||||
|
@ -134,7 +132,7 @@ std::string Function::type_name() const {
|
||||||
for (auto* param : params_) {
|
for (auto* param : params_) {
|
||||||
// No need for the sem::Variable here, functions params must have a
|
// No need for the sem::Variable here, functions params must have a
|
||||||
// type
|
// type
|
||||||
out << param->declared_type()->type_name();
|
out << param->type()->type_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
return out.str();
|
return out.str();
|
||||||
|
|
|
@ -49,7 +49,7 @@ class Function : public Castable<Function, Node> {
|
||||||
const Source& source,
|
const Source& source,
|
||||||
Symbol symbol,
|
Symbol symbol,
|
||||||
VariableList params,
|
VariableList params,
|
||||||
typ::Type return_type,
|
ast::Type* return_type,
|
||||||
BlockStatement* body,
|
BlockStatement* body,
|
||||||
DecorationList decorations,
|
DecorationList decorations,
|
||||||
DecorationList return_type_decorations);
|
DecorationList return_type_decorations);
|
||||||
|
@ -77,7 +77,7 @@ class Function : public Castable<Function, Node> {
|
||||||
bool IsEntryPoint() const { return pipeline_stage() != PipelineStage::kNone; }
|
bool IsEntryPoint() const { return pipeline_stage() != PipelineStage::kNone; }
|
||||||
|
|
||||||
/// @returns the function return type.
|
/// @returns the function return type.
|
||||||
typ::Type return_type() const { return return_type_; }
|
ast::Type* return_type() const { return return_type_; }
|
||||||
|
|
||||||
/// @returns the decorations attached to the function return type.
|
/// @returns the decorations attached to the function return type.
|
||||||
const DecorationList& return_type_decorations() const {
|
const DecorationList& return_type_decorations() const {
|
||||||
|
@ -115,7 +115,7 @@ class Function : public Castable<Function, Node> {
|
||||||
|
|
||||||
Symbol const symbol_;
|
Symbol const symbol_;
|
||||||
VariableList const params_;
|
VariableList const params_;
|
||||||
typ::Type const return_type_;
|
ast::Type* const return_type_;
|
||||||
BlockStatement* const body_;
|
BlockStatement* const body_;
|
||||||
DecorationList const decorations_;
|
DecorationList const decorations_;
|
||||||
DecorationList const return_type_decorations_;
|
DecorationList const return_type_decorations_;
|
||||||
|
|
|
@ -32,7 +32,7 @@ TEST_F(FunctionTest, Creation) {
|
||||||
auto* f = Func("func", params, ty.void_(), StatementList{}, DecorationList{});
|
auto* f = Func("func", params, ty.void_(), StatementList{}, DecorationList{});
|
||||||
EXPECT_EQ(f->symbol(), Symbols().Get("func"));
|
EXPECT_EQ(f->symbol(), Symbols().Get("func"));
|
||||||
ASSERT_EQ(f->params().size(), 1u);
|
ASSERT_EQ(f->params().size(), 1u);
|
||||||
EXPECT_EQ(f->return_type(), ty.void_());
|
EXPECT_TRUE(f->return_type()->Is<ast::Void>());
|
||||||
EXPECT_EQ(f->params()[0], var);
|
EXPECT_EQ(f->params()[0], var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,7 @@ std::ostream& operator<<(std::ostream& out, const TextureOverloadCase& data) {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
typ::Type TextureOverloadCase::resultVectorComponentType(
|
ast::Type* TextureOverloadCase::resultVectorComponentType(
|
||||||
ProgramBuilder* b) const {
|
ProgramBuilder* b) const {
|
||||||
switch (texture_data_type) {
|
switch (texture_data_type) {
|
||||||
case ast::intrinsic::test::TextureDataType::kF32:
|
case ast::intrinsic::test::TextureDataType::kF32:
|
||||||
|
@ -149,7 +149,7 @@ typ::Type TextureOverloadCase::resultVectorComponentType(
|
||||||
|
|
||||||
ast::Variable* TextureOverloadCase::buildTextureVariable(
|
ast::Variable* TextureOverloadCase::buildTextureVariable(
|
||||||
ProgramBuilder* b) const {
|
ProgramBuilder* b) const {
|
||||||
auto datatype = resultVectorComponentType(b);
|
auto* datatype = resultVectorComponentType(b);
|
||||||
|
|
||||||
DecorationList decos = {
|
DecorationList decos = {
|
||||||
b->create<ast::GroupDecoration>(0),
|
b->create<ast::GroupDecoration>(0),
|
||||||
|
@ -166,10 +166,9 @@ ast::Variable* TextureOverloadCase::buildTextureVariable(
|
||||||
ast::StorageClass::kUniformConstant, nullptr, decos);
|
ast::StorageClass::kUniformConstant, nullptr, decos);
|
||||||
|
|
||||||
case ast::intrinsic::test::TextureKind::kMultisampled:
|
case ast::intrinsic::test::TextureKind::kMultisampled:
|
||||||
return b->Global(
|
return b->Global("texture",
|
||||||
"texture",
|
b->ty.multisampled_texture(texture_dimension, datatype),
|
||||||
b->ty.multisampled_texture(texture_dimension, datatype),
|
ast::StorageClass::kUniformConstant, nullptr, decos);
|
||||||
ast::StorageClass::kUniformConstant, nullptr, decos);
|
|
||||||
|
|
||||||
case ast::intrinsic::test::TextureKind::kStorage: {
|
case ast::intrinsic::test::TextureKind::kStorage: {
|
||||||
auto st = b->ty.storage_texture(texture_dimension, image_format);
|
auto st = b->ty.storage_texture(texture_dimension, image_format);
|
||||||
|
|
|
@ -209,7 +209,7 @@ struct TextureOverloadCase {
|
||||||
|
|
||||||
/// @param builder the AST builder used for the test
|
/// @param builder the AST builder used for the test
|
||||||
/// @returns the vector component type of the texture function return value
|
/// @returns the vector component type of the texture function return value
|
||||||
typ::Type resultVectorComponentType(ProgramBuilder* builder) const;
|
ast::Type* resultVectorComponentType(ProgramBuilder* builder) const;
|
||||||
/// @param builder the AST builder used for the test
|
/// @param builder the AST builder used for the test
|
||||||
/// @returns a variable holding the test texture, automatically registered as
|
/// @returns a variable holding the test texture, automatically registered as
|
||||||
/// a global variable.
|
/// a global variable.
|
||||||
|
|
|
@ -29,14 +29,14 @@ Module::Module(ProgramID program_id, const Source& source)
|
||||||
|
|
||||||
Module::Module(ProgramID program_id,
|
Module::Module(ProgramID program_id,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
std::vector<Cloneable*> global_decls)
|
std::vector<ast::Node*> global_decls)
|
||||||
: Base(program_id, source), global_declarations_(std::move(global_decls)) {
|
: Base(program_id, source), global_declarations_(std::move(global_decls)) {
|
||||||
for (auto* decl : global_declarations_) {
|
for (auto* decl : global_declarations_) {
|
||||||
if (decl == nullptr) {
|
if (decl == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto* ty = decl->As<sem::Type>()) {
|
if (auto* ty = decl->As<ast::NamedType>()) {
|
||||||
constructed_types_.push_back(ty);
|
constructed_types_.push_back(ty);
|
||||||
} else if (auto* func = decl->As<Function>()) {
|
} else if (auto* func = decl->As<Function>()) {
|
||||||
functions_.push_back(func);
|
functions_.push_back(func);
|
||||||
|
@ -52,16 +52,34 @@ Module::Module(ProgramID program_id,
|
||||||
Module::~Module() = default;
|
Module::~Module() = default;
|
||||||
|
|
||||||
const ast::NamedType* Module::LookupType(Symbol name) const {
|
const ast::NamedType* Module::LookupType(Symbol name) const {
|
||||||
for (auto ct : ConstructedTypes()) {
|
for (auto* ty : ConstructedTypes()) {
|
||||||
if (auto* ty = ct.ast->As<ast::NamedType>()) {
|
if (ty->name() == name) {
|
||||||
if (ty->name() == name) {
|
return ty;
|
||||||
return ty;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Module::AddGlobalVariable(ast::Variable* var) {
|
||||||
|
TINT_ASSERT(var);
|
||||||
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(var, program_id());
|
||||||
|
global_variables_.push_back(var);
|
||||||
|
global_declarations_.push_back(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Module::AddConstructedType(ast::NamedType* type) {
|
||||||
|
TINT_ASSERT(type);
|
||||||
|
constructed_types_.push_back(type);
|
||||||
|
global_declarations_.push_back(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Module::AddFunction(ast::Function* func) {
|
||||||
|
TINT_ASSERT(func);
|
||||||
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(func, program_id());
|
||||||
|
functions_.push_back(func);
|
||||||
|
global_declarations_.push_back(func);
|
||||||
|
}
|
||||||
|
|
||||||
Module* Module::Clone(CloneContext* ctx) const {
|
Module* Module::Clone(CloneContext* ctx) const {
|
||||||
auto* out = ctx->dst->create<Module>();
|
auto* out = ctx->dst->create<Module>();
|
||||||
out->Copy(ctx, this);
|
out->Copy(ctx, this);
|
||||||
|
@ -74,7 +92,7 @@ void Module::Copy(CloneContext* ctx, const Module* src) {
|
||||||
TINT_ICE(ctx->dst->Diagnostics()) << "src global declaration was nullptr";
|
TINT_ICE(ctx->dst->Diagnostics()) << "src global declaration was nullptr";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (auto* ty = decl->As<sem::Type>()) {
|
if (auto* ty = decl->As<ast::NamedType>()) {
|
||||||
AddConstructedType(ty);
|
AddConstructedType(ty);
|
||||||
} else if (auto* func = decl->As<Function>()) {
|
} else if (auto* func = decl->As<Function>()) {
|
||||||
AddFunction(func);
|
AddFunction(func);
|
||||||
|
@ -92,16 +110,16 @@ void Module::to_str(const sem::Info& sem,
|
||||||
make_indent(out, indent);
|
make_indent(out, indent);
|
||||||
out << "Module{" << std::endl;
|
out << "Module{" << std::endl;
|
||||||
indent += 2;
|
indent += 2;
|
||||||
for (auto const ty : constructed_types_) {
|
for (auto* ty : constructed_types_) {
|
||||||
make_indent(out, indent);
|
make_indent(out, indent);
|
||||||
if (auto* alias = ty->As<sem::Alias>()) {
|
if (auto* alias = ty->As<ast::Alias>()) {
|
||||||
out << alias->symbol().to_str() << " -> " << alias->type()->type_name()
|
out << alias->symbol().to_str() << " -> " << alias->type()->type_name()
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
if (auto* str = alias->type()->As<sem::StructType>()) {
|
if (auto* str = alias->type()->As<ast::Struct>()) {
|
||||||
str->impl()->to_str(sem, out, indent);
|
str->to_str(sem, out, indent);
|
||||||
}
|
}
|
||||||
} else if (auto* str = ty->As<sem::StructType>()) {
|
} else if (auto* str = ty->As<ast::Struct>()) {
|
||||||
str->impl()->to_str(sem, out, indent);
|
str->to_str(sem, out, indent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto* var : global_variables_) {
|
for (auto* var : global_variables_) {
|
||||||
|
|
|
@ -42,28 +42,23 @@ class Module : public Castable<Module, Node> {
|
||||||
/// the order they were declared in the source program
|
/// the order they were declared in the source program
|
||||||
Module(ProgramID program_id,
|
Module(ProgramID program_id,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
std::vector<Cloneable*> global_decls);
|
std::vector<ast::Node*> global_decls);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Module() override;
|
~Module() override;
|
||||||
|
|
||||||
/// @returns the ordered global declarations for the translation unit
|
/// @returns the ordered global declarations for the translation unit
|
||||||
const std::vector<Cloneable*>& GlobalDeclarations() const {
|
const std::vector<ast::Node*>& GlobalDeclarations() const {
|
||||||
return global_declarations_;
|
return global_declarations_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a global variable to the Builder
|
/// Add a global variable to the Builder
|
||||||
/// @param var the variable to add
|
/// @param var the variable to add
|
||||||
void AddGlobalVariable(ast::Variable* var) {
|
void AddGlobalVariable(ast::Variable* var);
|
||||||
TINT_ASSERT(var);
|
|
||||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(var, program_id());
|
|
||||||
global_variables_.push_back(var);
|
|
||||||
global_declarations_.push_back(var);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns true if the module has the global declaration `decl`
|
/// @returns true if the module has the global declaration `decl`
|
||||||
/// @param decl the declaration to check
|
/// @param decl the declaration to check
|
||||||
bool HasGlobalDeclaration(const Cloneable* decl) const {
|
bool HasGlobalDeclaration(ast::Node* decl) const {
|
||||||
for (auto* d : global_declarations_) {
|
for (auto* d : global_declarations_) {
|
||||||
if (d == decl) {
|
if (d == decl) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -79,31 +74,21 @@ class Module : public Castable<Module, Node> {
|
||||||
VariableList& GlobalVariables() { return global_variables_; }
|
VariableList& GlobalVariables() { return global_variables_; }
|
||||||
|
|
||||||
/// Adds a constructed type to the Builder.
|
/// Adds a constructed type to the Builder.
|
||||||
/// The type must be an alias or a struct.
|
|
||||||
/// @param type the constructed type to add
|
/// @param type the constructed type to add
|
||||||
void AddConstructedType(typ::Type type) {
|
void AddConstructedType(ast::NamedType* type);
|
||||||
TINT_ASSERT(type);
|
|
||||||
constructed_types_.push_back(type);
|
|
||||||
global_declarations_.push_back(const_cast<sem::Type*>(type.sem));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns the NamedType registered as a ConstructedType()
|
/// @returns the NamedType registered as a ConstructedType()
|
||||||
/// @param name the name of the type to search for
|
/// @param name the name of the type to search for
|
||||||
const ast::NamedType* LookupType(Symbol name) const;
|
const ast::NamedType* LookupType(Symbol name) const;
|
||||||
|
|
||||||
/// @returns the constructed types in the translation unit
|
/// @returns the constructed types in the translation unit
|
||||||
const std::vector<typ::Type>& ConstructedTypes() const {
|
const std::vector<ast::NamedType*>& ConstructedTypes() const {
|
||||||
return constructed_types_;
|
return constructed_types_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a function to the Builder
|
/// Add a function to the Builder
|
||||||
/// @param func the function to add
|
/// @param func the function to add
|
||||||
void AddFunction(ast::Function* func) {
|
void AddFunction(ast::Function* func);
|
||||||
TINT_ASSERT(func);
|
|
||||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(func, program_id());
|
|
||||||
functions_.push_back(func);
|
|
||||||
global_declarations_.push_back(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @returns the functions declared in the translation unit
|
/// @returns the functions declared in the translation unit
|
||||||
const FunctionList& Functions() const { return functions_; }
|
const FunctionList& Functions() const { return functions_; }
|
||||||
|
@ -132,8 +117,8 @@ class Module : public Castable<Module, Node> {
|
||||||
std::string to_str(const sem::Info& sem) const;
|
std::string to_str(const sem::Info& sem) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Cloneable*> global_declarations_;
|
std::vector<ast::Node*> global_declarations_;
|
||||||
std::vector<typ::Type> constructed_types_;
|
std::vector<ast::NamedType*> constructed_types_;
|
||||||
FunctionList functions_;
|
FunctionList functions_;
|
||||||
VariableList global_variables_;
|
VariableList global_variables_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,13 +24,13 @@ namespace ast {
|
||||||
StructMember::StructMember(ProgramID program_id,
|
StructMember::StructMember(ProgramID program_id,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
const Symbol& sym,
|
const Symbol& sym,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
DecorationList decorations)
|
DecorationList decorations)
|
||||||
: Base(program_id, source),
|
: Base(program_id, source),
|
||||||
symbol_(sym),
|
symbol_(sym),
|
||||||
type_(type),
|
type_(type),
|
||||||
decorations_(std::move(decorations)) {
|
decorations_(std::move(decorations)) {
|
||||||
TINT_ASSERT(type.ast || type.sem);
|
TINT_ASSERT(type);
|
||||||
TINT_ASSERT(symbol_.IsValid());
|
TINT_ASSERT(symbol_.IsValid());
|
||||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(symbol_, program_id);
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(symbol_, program_id);
|
||||||
for (auto* deco : decorations_) {
|
for (auto* deco : decorations_) {
|
||||||
|
@ -59,7 +59,7 @@ StructMember* StructMember::Clone(CloneContext* ctx) const {
|
||||||
// Clone arguments outside of create() call to have deterministic ordering
|
// Clone arguments outside of create() call to have deterministic ordering
|
||||||
auto src = ctx->Clone(source());
|
auto src = ctx->Clone(source());
|
||||||
auto sym = ctx->Clone(symbol_);
|
auto sym = ctx->Clone(symbol_);
|
||||||
auto ty = ctx->Clone(type_);
|
auto* ty = ctx->Clone(type_);
|
||||||
auto decos = ctx->Clone(decorations_);
|
auto decos = ctx->Clone(decorations_);
|
||||||
return ctx->dst->create<StructMember>(src, sym, ty, decos);
|
return ctx->dst->create<StructMember>(src, sym, ty, decos);
|
||||||
}
|
}
|
||||||
|
@ -76,9 +76,7 @@ void StructMember::to_str(const sem::Info& sem,
|
||||||
out << "]] ";
|
out << "]] ";
|
||||||
}
|
}
|
||||||
|
|
||||||
out << symbol_.to_str() << ": "
|
out << symbol_.to_str() << ": " << type_->type_name() << "}" << std::endl;
|
||||||
<< (type_.ast ? type_.ast->type_name() : type_.sem->type_name()) << "}"
|
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
|
|
|
@ -36,7 +36,7 @@ class StructMember : public Castable<StructMember, Node> {
|
||||||
StructMember(ProgramID program_id,
|
StructMember(ProgramID program_id,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
const Symbol& sym,
|
const Symbol& sym,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
DecorationList decorations);
|
DecorationList decorations);
|
||||||
/// Move constructor
|
/// Move constructor
|
||||||
StructMember(StructMember&&);
|
StructMember(StructMember&&);
|
||||||
|
@ -47,7 +47,7 @@ class StructMember : public Castable<StructMember, Node> {
|
||||||
const Symbol& symbol() const { return symbol_; }
|
const Symbol& symbol() const { return symbol_; }
|
||||||
|
|
||||||
/// @returns the type
|
/// @returns the type
|
||||||
typ::Type type() const { return type_; }
|
ast::Type* type() const { return type_; }
|
||||||
|
|
||||||
/// @returns the decorations
|
/// @returns the decorations
|
||||||
const DecorationList& decorations() const { return decorations_; }
|
const DecorationList& decorations() const { return decorations_; }
|
||||||
|
@ -75,7 +75,7 @@ class StructMember : public Castable<StructMember, Node> {
|
||||||
StructMember(const StructMember&) = delete;
|
StructMember(const StructMember&) = delete;
|
||||||
|
|
||||||
Symbol const symbol_;
|
Symbol const symbol_;
|
||||||
typ::Type const type_;
|
ast::Type* const type_;
|
||||||
DecorationList const decorations_;
|
DecorationList const decorations_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ using StructMemberTest = TestHelper;
|
||||||
TEST_F(StructMemberTest, Creation) {
|
TEST_F(StructMemberTest, Creation) {
|
||||||
auto* st = Member("a", ty.i32(), {MemberSize(4)});
|
auto* st = Member("a", ty.i32(), {MemberSize(4)});
|
||||||
EXPECT_EQ(st->symbol(), Symbol(1, ID()));
|
EXPECT_EQ(st->symbol(), Symbol(1, ID()));
|
||||||
EXPECT_EQ(st->type(), ty.i32());
|
EXPECT_TRUE(st->type()->Is<ast::I32>());
|
||||||
EXPECT_EQ(st->decorations().size(), 1u);
|
EXPECT_EQ(st->decorations().size(), 1u);
|
||||||
EXPECT_TRUE(st->decorations()[0]->Is<StructMemberSizeDecoration>());
|
EXPECT_TRUE(st->decorations()[0]->Is<StructMemberSizeDecoration>());
|
||||||
EXPECT_EQ(st->source().range.begin.line, 0u);
|
EXPECT_EQ(st->source().range.begin.line, 0u);
|
||||||
|
@ -38,7 +38,7 @@ TEST_F(StructMemberTest, CreationWithSource) {
|
||||||
Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}},
|
Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}},
|
||||||
"a", ty.i32());
|
"a", ty.i32());
|
||||||
EXPECT_EQ(st->symbol(), Symbol(1, ID()));
|
EXPECT_EQ(st->symbol(), Symbol(1, ID()));
|
||||||
EXPECT_EQ(st->type(), ty.i32());
|
EXPECT_TRUE(st->type()->Is<ast::I32>());
|
||||||
EXPECT_EQ(st->decorations().size(), 0u);
|
EXPECT_EQ(st->decorations().size(), 0u);
|
||||||
EXPECT_EQ(st->source().range.begin.line, 27u);
|
EXPECT_EQ(st->source().range.begin.line, 27u);
|
||||||
EXPECT_EQ(st->source().range.begin.column, 4u);
|
EXPECT_EQ(st->source().range.begin.column, 4u);
|
||||||
|
|
|
@ -23,10 +23,10 @@ namespace ast {
|
||||||
|
|
||||||
TypeConstructorExpression::TypeConstructorExpression(ProgramID program_id,
|
TypeConstructorExpression::TypeConstructorExpression(ProgramID program_id,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ExpressionList values)
|
ExpressionList values)
|
||||||
: Base(program_id, source), type_(type), values_(std::move(values)) {
|
: Base(program_id, source), type_(type), values_(std::move(values)) {
|
||||||
TINT_ASSERT(type_.ast || type_.sem);
|
TINT_ASSERT(type_);
|
||||||
for (auto* val : values_) {
|
for (auto* val : values_) {
|
||||||
TINT_ASSERT(val);
|
TINT_ASSERT(val);
|
||||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(val, program_id);
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(val, program_id);
|
||||||
|
@ -42,7 +42,7 @@ TypeConstructorExpression* TypeConstructorExpression::Clone(
|
||||||
CloneContext* ctx) const {
|
CloneContext* ctx) const {
|
||||||
// Clone arguments outside of create() call to have deterministic ordering
|
// Clone arguments outside of create() call to have deterministic ordering
|
||||||
auto src = ctx->Clone(source());
|
auto src = ctx->Clone(source());
|
||||||
auto ty = ctx->Clone(type());
|
auto* ty = ctx->Clone(type());
|
||||||
auto vals = ctx->Clone(values());
|
auto vals = ctx->Clone(values());
|
||||||
return ctx->dst->create<TypeConstructorExpression>(src, ty, vals);
|
return ctx->dst->create<TypeConstructorExpression>(src, ty, vals);
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,7 @@ void TypeConstructorExpression::to_str(const sem::Info& sem,
|
||||||
make_indent(out, indent);
|
make_indent(out, indent);
|
||||||
out << "TypeConstructor[" << result_type_str(sem) << "]{" << std::endl;
|
out << "TypeConstructor[" << result_type_str(sem) << "]{" << std::endl;
|
||||||
make_indent(out, indent + 2);
|
make_indent(out, indent + 2);
|
||||||
out << (type_.ast ? type_.ast->type_name() : type_.sem->type_name())
|
out << type_->type_name() << std::endl;
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
for (auto* val : values_) {
|
for (auto* val : values_) {
|
||||||
val->to_str(sem, out, indent + 2);
|
val->to_str(sem, out, indent + 2);
|
||||||
|
|
|
@ -33,14 +33,14 @@ class TypeConstructorExpression
|
||||||
/// @param values the constructor values
|
/// @param values the constructor values
|
||||||
TypeConstructorExpression(ProgramID program_id,
|
TypeConstructorExpression(ProgramID program_id,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ExpressionList values);
|
ExpressionList values);
|
||||||
/// Move constructor
|
/// Move constructor
|
||||||
TypeConstructorExpression(TypeConstructorExpression&&);
|
TypeConstructorExpression(TypeConstructorExpression&&);
|
||||||
~TypeConstructorExpression() override;
|
~TypeConstructorExpression() override;
|
||||||
|
|
||||||
/// @returns the type
|
/// @returns the type
|
||||||
typ::Type type() const { return type_; }
|
ast::Type* type() const { return type_; }
|
||||||
|
|
||||||
/// @returns the values
|
/// @returns the values
|
||||||
const ExpressionList& values() const { return values_; }
|
const ExpressionList& values() const { return values_; }
|
||||||
|
@ -62,7 +62,7 @@ class TypeConstructorExpression
|
||||||
private:
|
private:
|
||||||
TypeConstructorExpression(const TypeConstructorExpression&) = delete;
|
TypeConstructorExpression(const TypeConstructorExpression&) = delete;
|
||||||
|
|
||||||
typ::Type const type_;
|
ast::Type* const type_;
|
||||||
ExpressionList const values_;
|
ExpressionList const values_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ TEST_F(TypeConstructorExpressionTest, Creation) {
|
||||||
expr.push_back(Expr("expr"));
|
expr.push_back(Expr("expr"));
|
||||||
|
|
||||||
auto* t = create<TypeConstructorExpression>(ty.f32(), expr);
|
auto* t = create<TypeConstructorExpression>(ty.f32(), expr);
|
||||||
EXPECT_EQ(t->type(), ty.f32());
|
EXPECT_TRUE(t->type()->Is<ast::F32>());
|
||||||
ASSERT_EQ(t->values().size(), 1u);
|
ASSERT_EQ(t->values().size(), 1u);
|
||||||
EXPECT_EQ(t->values()[0], expr[0]);
|
EXPECT_EQ(t->values()[0], expr[0]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ Variable::Variable(ProgramID program_id,
|
||||||
const Source& source,
|
const Source& source,
|
||||||
const Symbol& sym,
|
const Symbol& sym,
|
||||||
StorageClass declared_storage_class,
|
StorageClass declared_storage_class,
|
||||||
const typ::Type type,
|
ast::Type* type,
|
||||||
bool is_const,
|
bool is_const,
|
||||||
Expression* constructor,
|
Expression* constructor,
|
||||||
DecorationList decorations)
|
DecorationList decorations)
|
||||||
|
@ -41,7 +41,7 @@ Variable::Variable(ProgramID program_id,
|
||||||
TINT_ASSERT(symbol_.IsValid());
|
TINT_ASSERT(symbol_.IsValid());
|
||||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(symbol_, program_id);
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(symbol_, program_id);
|
||||||
// no type means we must have a constructor to infer it
|
// no type means we must have a constructor to infer it
|
||||||
TINT_ASSERT(type_.ast || type_.sem || constructor);
|
TINT_ASSERT(type_ || constructor);
|
||||||
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(constructor, program_id);
|
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(constructor, program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ uint32_t Variable::constant_id() const {
|
||||||
Variable* Variable::Clone(CloneContext* ctx) const {
|
Variable* Variable::Clone(CloneContext* ctx) const {
|
||||||
auto src = ctx->Clone(source());
|
auto src = ctx->Clone(source());
|
||||||
auto sym = ctx->Clone(symbol());
|
auto sym = ctx->Clone(symbol());
|
||||||
auto ty = ctx->Clone(type());
|
auto* ty = ctx->Clone(type());
|
||||||
auto* ctor = ctx->Clone(constructor());
|
auto* ctor = ctx->Clone(constructor());
|
||||||
auto decos = ctx->Clone(decorations());
|
auto decos = ctx->Clone(decorations());
|
||||||
return ctx->dst->create<Variable>(src, sym, declared_storage_class(), ty,
|
return ctx->dst->create<Variable>(src, sym, declared_storage_class(), ty,
|
||||||
|
@ -90,8 +90,7 @@ void Variable::info_to_str(const sem::Info& sem,
|
||||||
out << (var_sem ? var_sem->StorageClass() : declared_storage_class())
|
out << (var_sem ? var_sem->StorageClass() : declared_storage_class())
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
make_indent(out, indent);
|
make_indent(out, indent);
|
||||||
out << (type_.sem ? type_.sem->type_name() : type_.ast->type_name())
|
out << type_->type_name() << std::endl;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Variable::constructor_to_str(const sem::Info& sem,
|
void Variable::constructor_to_str(const sem::Info& sem,
|
||||||
|
|
|
@ -109,7 +109,7 @@ class Variable : public Castable<Variable, Node> {
|
||||||
const Source& source,
|
const Source& source,
|
||||||
const Symbol& sym,
|
const Symbol& sym,
|
||||||
StorageClass declared_storage_class,
|
StorageClass declared_storage_class,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
bool is_const,
|
bool is_const,
|
||||||
Expression* constructor,
|
Expression* constructor,
|
||||||
DecorationList decorations);
|
DecorationList decorations);
|
||||||
|
@ -121,12 +121,8 @@ class Variable : public Castable<Variable, Node> {
|
||||||
/// @returns the variable symbol
|
/// @returns the variable symbol
|
||||||
const Symbol& symbol() const { return symbol_; }
|
const Symbol& symbol() const { return symbol_; }
|
||||||
|
|
||||||
/// @returns the declared type
|
|
||||||
// TODO(crbug.com/tint/697): Remove and use type() instead
|
|
||||||
sem::Type* declared_type() const { return const_cast<sem::Type*>(type_.sem); }
|
|
||||||
|
|
||||||
/// @returns the variable type
|
/// @returns the variable type
|
||||||
typ::Type type() const { return type_; }
|
ast::Type* type() const { return type_; }
|
||||||
|
|
||||||
/// @returns the declared storage class
|
/// @returns the declared storage class
|
||||||
StorageClass declared_storage_class() const {
|
StorageClass declared_storage_class() const {
|
||||||
|
@ -185,7 +181,7 @@ class Variable : public Castable<Variable, Node> {
|
||||||
|
|
||||||
Symbol const symbol_;
|
Symbol const symbol_;
|
||||||
// The value type if a const or formal paramter, and the store type if a var
|
// The value type if a const or formal paramter, and the store type if a var
|
||||||
typ::Type const type_;
|
ast::Type* const type_;
|
||||||
bool const is_const_;
|
bool const is_const_;
|
||||||
Expression* const constructor_;
|
Expression* const constructor_;
|
||||||
DecorationList const decorations_;
|
DecorationList const decorations_;
|
||||||
|
|
|
@ -27,7 +27,7 @@ TEST_F(VariableTest, Creation) {
|
||||||
|
|
||||||
EXPECT_EQ(v->symbol(), Symbol(1, ID()));
|
EXPECT_EQ(v->symbol(), Symbol(1, ID()));
|
||||||
EXPECT_EQ(v->declared_storage_class(), StorageClass::kFunction);
|
EXPECT_EQ(v->declared_storage_class(), StorageClass::kFunction);
|
||||||
EXPECT_EQ(v->declared_type(), ty.i32());
|
EXPECT_TRUE(v->type()->Is<ast::I32>());
|
||||||
EXPECT_EQ(v->source().range.begin.line, 0u);
|
EXPECT_EQ(v->source().range.begin.line, 0u);
|
||||||
EXPECT_EQ(v->source().range.begin.column, 0u);
|
EXPECT_EQ(v->source().range.begin.column, 0u);
|
||||||
EXPECT_EQ(v->source().range.end.line, 0u);
|
EXPECT_EQ(v->source().range.end.line, 0u);
|
||||||
|
@ -41,7 +41,7 @@ TEST_F(VariableTest, CreationWithSource) {
|
||||||
|
|
||||||
EXPECT_EQ(v->symbol(), Symbol(1, ID()));
|
EXPECT_EQ(v->symbol(), Symbol(1, ID()));
|
||||||
EXPECT_EQ(v->declared_storage_class(), StorageClass::kPrivate);
|
EXPECT_EQ(v->declared_storage_class(), StorageClass::kPrivate);
|
||||||
EXPECT_EQ(v->declared_type(), ty.f32());
|
EXPECT_TRUE(v->type()->Is<ast::F32>());
|
||||||
EXPECT_EQ(v->source().range.begin.line, 27u);
|
EXPECT_EQ(v->source().range.begin.line, 27u);
|
||||||
EXPECT_EQ(v->source().range.begin.column, 4u);
|
EXPECT_EQ(v->source().range.begin.column, 4u);
|
||||||
EXPECT_EQ(v->source().range.end.line, 27u);
|
EXPECT_EQ(v->source().range.end.line, 27u);
|
||||||
|
@ -55,7 +55,7 @@ TEST_F(VariableTest, CreationEmpty) {
|
||||||
|
|
||||||
EXPECT_EQ(v->symbol(), Symbol(1, ID()));
|
EXPECT_EQ(v->symbol(), Symbol(1, ID()));
|
||||||
EXPECT_EQ(v->declared_storage_class(), StorageClass::kWorkgroup);
|
EXPECT_EQ(v->declared_storage_class(), StorageClass::kWorkgroup);
|
||||||
EXPECT_EQ(v->declared_type(), ty.i32());
|
EXPECT_TRUE(v->type()->Is<ast::I32>());
|
||||||
EXPECT_EQ(v->source().range.begin.line, 27u);
|
EXPECT_EQ(v->source().range.begin.line, 27u);
|
||||||
EXPECT_EQ(v->source().range.begin.column, 4u);
|
EXPECT_EQ(v->source().range.begin.column, 4u);
|
||||||
EXPECT_EQ(v->source().range.end.line, 27u);
|
EXPECT_EQ(v->source().range.end.line, 27u);
|
||||||
|
|
|
@ -190,12 +190,12 @@ class CloneContext {
|
||||||
return CheckedCast<T>(c);
|
return CheckedCast<T>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clones the type pair
|
/// Clones the AST node of the type pair
|
||||||
/// @param tp the type pair to clone
|
/// @param tp the type pair to clone
|
||||||
/// @return the cloned type pair
|
/// @return the cloned AST node wrapped in a type pair
|
||||||
template <typename AST, typename SEM>
|
template <typename AST, typename SEM>
|
||||||
typ::TypePair<AST, SEM> Clone(const typ::TypePair<AST, SEM>& tp) {
|
typ::TypePair<AST, SEM> Clone(const typ::TypePair<AST, SEM>& tp) {
|
||||||
return Clone(const_cast<sem::Type*>(tp.sem));
|
return Clone(const_cast<ast::Type*>(tp.ast));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clones the Source `s` into #dst
|
/// Clones the Source `s` into #dst
|
||||||
|
|
|
@ -194,6 +194,8 @@ std::vector<EntryPoint> Inspector::GetEntryPoints() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* sem = program_->Sem().Get(func);
|
||||||
|
|
||||||
EntryPoint entry_point;
|
EntryPoint entry_point;
|
||||||
entry_point.name = program_->Symbols().NameFor(func->symbol());
|
entry_point.name = program_->Symbols().NameFor(func->symbol());
|
||||||
entry_point.remapped_name = program_->Symbols().NameFor(func->symbol());
|
entry_point.remapped_name = program_->Symbols().NameFor(func->symbol());
|
||||||
|
@ -201,20 +203,21 @@ std::vector<EntryPoint> Inspector::GetEntryPoints() {
|
||||||
std::tie(entry_point.workgroup_size_x, entry_point.workgroup_size_y,
|
std::tie(entry_point.workgroup_size_x, entry_point.workgroup_size_y,
|
||||||
entry_point.workgroup_size_z) = func->workgroup_size();
|
entry_point.workgroup_size_z) = func->workgroup_size();
|
||||||
|
|
||||||
for (auto* param : func->params()) {
|
for (auto* param : sem->Parameters()) {
|
||||||
AddEntryPointInOutVariables(program_->Symbols().NameFor(param->symbol()),
|
AddEntryPointInOutVariables(
|
||||||
param->declared_type(), param->decorations(),
|
program_->Symbols().NameFor(param->Declaration()->symbol()),
|
||||||
entry_point.input_variables);
|
param->Type(), param->Declaration()->decorations(),
|
||||||
|
entry_point.input_variables);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!func->return_type()->Is<sem::Void>()) {
|
if (!sem->ReturnType()->Is<sem::Void>()) {
|
||||||
AddEntryPointInOutVariables("<retval>", func->return_type(),
|
AddEntryPointInOutVariables("<retval>", sem->ReturnType(),
|
||||||
func->return_type_decorations(),
|
func->return_type_decorations(),
|
||||||
entry_point.output_variables);
|
entry_point.output_variables);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(crbug.com/tint/697): Remove this.
|
// TODO(crbug.com/tint/697): Remove this.
|
||||||
for (auto* var : program_->Sem().Get(func)->ReferencedModuleVariables()) {
|
for (auto* var : sem->ReferencedModuleVariables()) {
|
||||||
auto* decl = var->Declaration();
|
auto* decl = var->Declaration();
|
||||||
|
|
||||||
auto name = program_->Symbols().NameFor(decl->symbol());
|
auto name = program_->Symbols().NameFor(decl->symbol());
|
||||||
|
@ -553,10 +556,12 @@ void Inspector::AddEntryPointInOutVariables(
|
||||||
|
|
||||||
if (auto* struct_ty = unwrapped_type->As<sem::StructType>()) {
|
if (auto* struct_ty = unwrapped_type->As<sem::StructType>()) {
|
||||||
// Recurse into members.
|
// Recurse into members.
|
||||||
for (auto* member : struct_ty->impl()->members()) {
|
auto* sem = program_->Sem().Get(struct_ty);
|
||||||
|
for (auto* member : sem->Members()) {
|
||||||
AddEntryPointInOutVariables(
|
AddEntryPointInOutVariables(
|
||||||
name + "." + program_->Symbols().NameFor(member->symbol()),
|
name + "." +
|
||||||
member->type(), member->decorations(), variables);
|
program_->Symbols().NameFor(member->Declaration()->symbol()),
|
||||||
|
member->Type(), member->Declaration()->decorations(), variables);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param val value to initialize the variable with, if NULL no initializer
|
/// @param val value to initialize the variable with, if NULL no initializer
|
||||||
/// will be added.
|
/// will be added.
|
||||||
template <class T>
|
template <class T>
|
||||||
void AddConstantID(std::string name, uint32_t id, typ::Type type, T* val) {
|
void AddConstantID(std::string name, uint32_t id, ast::Type* type, T* val) {
|
||||||
ast::Expression* constructor = nullptr;
|
ast::Expression* constructor = nullptr;
|
||||||
if (val) {
|
if (val) {
|
||||||
constructor = Expr(*val);
|
constructor = Expr(*val);
|
||||||
|
@ -172,9 +172,8 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param idx index of member
|
/// @param idx index of member
|
||||||
/// @param type type of member
|
/// @param type type of member
|
||||||
/// @returns a string for the member
|
/// @returns a string for the member
|
||||||
std::string StructMemberName(size_t idx, typ::Type type) {
|
std::string StructMemberName(size_t idx, ast::Type* type) {
|
||||||
return std::to_string(idx) +
|
return std::to_string(idx) + type->type_name();
|
||||||
(type.sem ? type.sem->type_name() : type.ast->type_name());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a struct type
|
/// Generates a struct type
|
||||||
|
@ -182,11 +181,11 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param member_types a vector of member types
|
/// @param member_types a vector of member types
|
||||||
/// @param is_block whether or not to decorate as a Block
|
/// @param is_block whether or not to decorate as a Block
|
||||||
/// @returns a struct type
|
/// @returns a struct type
|
||||||
typ::Struct MakeStructType(const std::string& name,
|
ast::Struct* MakeStructType(const std::string& name,
|
||||||
std::vector<typ::Type> member_types,
|
std::vector<ast::Type*> member_types,
|
||||||
bool is_block) {
|
bool is_block) {
|
||||||
ast::StructMemberList members;
|
ast::StructMemberList members;
|
||||||
for (auto type : member_types) {
|
for (auto* type : member_types) {
|
||||||
members.push_back(Member(StructMemberName(members.size(), type), type));
|
members.push_back(Member(StructMemberName(members.size(), type), type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,37 +201,37 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param name name for the type
|
/// @param name name for the type
|
||||||
/// @param member_types a vector of member types
|
/// @param member_types a vector of member types
|
||||||
/// @returns a struct type that has the layout for an uniform buffer.
|
/// @returns a struct type that has the layout for an uniform buffer.
|
||||||
typ::Struct MakeUniformBufferType(const std::string& name,
|
ast::Struct* MakeUniformBufferType(const std::string& name,
|
||||||
std::vector<typ::Type> member_types) {
|
std::vector<ast::Type*> member_types) {
|
||||||
return MakeStructType(name, member_types, true);
|
return MakeStructType(name, member_types, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates types appropriate for using in a storage buffer
|
/// Generates types appropriate for using in a storage buffer
|
||||||
/// @param name name for the type
|
/// @param name name for the type
|
||||||
/// @param member_types a vector of member types
|
/// @param member_types a vector of member types
|
||||||
/// @returns a tuple {struct type, access control type}, where the struct has
|
/// @returns a function that returns an ast::AccessControl to the created
|
||||||
/// the layout for a storage buffer, and the control type wraps the
|
/// structure.
|
||||||
/// struct.
|
std::function<ast::AccessControl*()> MakeStorageBufferTypes(
|
||||||
std::tuple<typ::Struct, typ::AccessControl> MakeStorageBufferTypes(
|
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
std::vector<typ::Type> member_types) {
|
std::vector<ast::Type*> member_types) {
|
||||||
auto struct_type = MakeStructType(name, member_types, true);
|
MakeStructType(name, member_types, true);
|
||||||
auto access_type = ty.access(ast::AccessControl::kReadWrite, struct_type);
|
return [this, name] {
|
||||||
return {struct_type, std::move(access_type)};
|
return ty.access(ast::AccessControl::kReadWrite, ty.type_name(name));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates types appropriate for using in a read-only storage buffer
|
/// Generates types appropriate for using in a read-only storage buffer
|
||||||
/// @param name name for the type
|
/// @param name name for the type
|
||||||
/// @param member_types a vector of member types
|
/// @param member_types a vector of member types
|
||||||
/// @returns a tuple {struct type, access control type}, where the struct has
|
/// @returns a function that returns an ast::AccessControl to the created
|
||||||
/// the layout for a read-only storage buffer, and the control type
|
/// structure.
|
||||||
/// wraps the struct.
|
std::function<ast::AccessControl*()> MakeReadOnlyStorageBufferTypes(
|
||||||
std::tuple<typ::Struct, typ::AccessControl> MakeReadOnlyStorageBufferTypes(
|
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
std::vector<typ::Type> member_types) {
|
std::vector<ast::Type*> member_types) {
|
||||||
auto struct_type = MakeStructType(name, member_types, true);
|
MakeStructType(name, member_types, true);
|
||||||
auto access_type = ty.access(ast::AccessControl::kReadOnly, struct_type);
|
return [this, name] {
|
||||||
return {struct_type, std::move(access_type)};
|
return ty.access(ast::AccessControl::kReadOnly, ty.type_name(name));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a binding variable with a struct type to the program
|
/// Adds a binding variable with a struct type to the program
|
||||||
|
@ -242,7 +241,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param group the binding and group to use for the uniform buffer
|
/// @param group the binding and group to use for the uniform buffer
|
||||||
/// @param binding the binding number to use for the uniform buffer
|
/// @param binding the binding number to use for the uniform buffer
|
||||||
void AddBinding(const std::string& name,
|
void AddBinding(const std::string& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::StorageClass storage_class,
|
ast::StorageClass storage_class,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
|
@ -259,7 +258,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param group the binding/group/ to use for the uniform buffer
|
/// @param group the binding/group/ to use for the uniform buffer
|
||||||
/// @param binding the binding number to use for the uniform buffer
|
/// @param binding the binding number to use for the uniform buffer
|
||||||
void AddUniformBuffer(const std::string& name,
|
void AddUniformBuffer(const std::string& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
AddBinding(name, type, ast::StorageClass::kUniform, group, binding);
|
AddBinding(name, type, ast::StorageClass::kUniform, group, binding);
|
||||||
|
@ -271,7 +270,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param group the binding/group to use for the storage buffer
|
/// @param group the binding/group to use for the storage buffer
|
||||||
/// @param binding the binding number to use for the storage buffer
|
/// @param binding the binding number to use for the storage buffer
|
||||||
void AddStorageBuffer(const std::string& name,
|
void AddStorageBuffer(const std::string& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
AddBinding(name, type, ast::StorageClass::kStorage, group, binding);
|
AddBinding(name, type, ast::StorageClass::kStorage, group, binding);
|
||||||
|
@ -284,11 +283,11 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
void MakeStructVariableReferenceBodyFunction(
|
void MakeStructVariableReferenceBodyFunction(
|
||||||
std::string func_name,
|
std::string func_name,
|
||||||
std::string struct_name,
|
std::string struct_name,
|
||||||
std::vector<std::tuple<size_t, typ::Type>> members) {
|
std::vector<std::tuple<size_t, ast::Type*>> members) {
|
||||||
ast::StatementList stmts;
|
ast::StatementList stmts;
|
||||||
for (auto member : members) {
|
for (auto member : members) {
|
||||||
size_t member_idx;
|
size_t member_idx;
|
||||||
typ::Type member_type;
|
ast::Type* member_type;
|
||||||
std::tie(member_idx, member_type) = member;
|
std::tie(member_idx, member_type) = member;
|
||||||
std::string member_name = StructMemberName(member_idx, member_type);
|
std::string member_name = StructMemberName(member_idx, member_type);
|
||||||
|
|
||||||
|
@ -298,7 +297,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
|
|
||||||
for (auto member : members) {
|
for (auto member : members) {
|
||||||
size_t member_idx;
|
size_t member_idx;
|
||||||
typ::Type member_type;
|
ast::Type* member_type;
|
||||||
std::tie(member_idx, member_type) = member;
|
std::tie(member_idx, member_type) = member;
|
||||||
std::string member_name = StructMemberName(member_idx, member_type);
|
std::string member_name = StructMemberName(member_idx, member_type);
|
||||||
|
|
||||||
|
@ -337,7 +336,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param type the data type of the sampled texture
|
/// @param type the data type of the sampled texture
|
||||||
/// @returns the generated SampleTextureType
|
/// @returns the generated SampleTextureType
|
||||||
typ::SampledTexture MakeSampledTextureType(ast::TextureDimension dim,
|
typ::SampledTexture MakeSampledTextureType(ast::TextureDimension dim,
|
||||||
typ::Type type) {
|
ast::Type* type) {
|
||||||
return ty.sampled_texture(dim, type);
|
return ty.sampled_texture(dim, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +353,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @returns the generated SampleTextureType
|
/// @returns the generated SampleTextureType
|
||||||
typ::MultisampledTexture MakeMultisampledTextureType(
|
typ::MultisampledTexture MakeMultisampledTextureType(
|
||||||
ast::TextureDimension dim,
|
ast::TextureDimension dim,
|
||||||
typ::Type type) {
|
ast::Type* type) {
|
||||||
return ty.multisampled_texture(dim, type);
|
return ty.multisampled_texture(dim, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,7 +363,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param group the binding/group to use for the sampled texture
|
/// @param group the binding/group to use for the sampled texture
|
||||||
/// @param binding the binding number to use for the sampled texture
|
/// @param binding the binding number to use for the sampled texture
|
||||||
void AddSampledTexture(const std::string& name,
|
void AddSampledTexture(const std::string& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
|
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
|
||||||
|
@ -376,13 +375,13 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param group the binding/group to use for the multi-sampled texture
|
/// @param group the binding/group to use for the multi-sampled texture
|
||||||
/// @param binding the binding number to use for the multi-sampled texture
|
/// @param binding the binding number to use for the multi-sampled texture
|
||||||
void AddMultisampledTexture(const std::string& name,
|
void AddMultisampledTexture(const std::string& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
|
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddGlobalVariable(const std::string& name, typ::Type type) {
|
void AddGlobalVariable(const std::string& name, ast::Type* type) {
|
||||||
Global(name, type, ast::StorageClass::kUniformConstant);
|
Global(name, type, ast::StorageClass::kUniformConstant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,7 +391,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param group the binding/group to use for the depth texture
|
/// @param group the binding/group to use for the depth texture
|
||||||
/// @param binding the binding number to use for the depth texture
|
/// @param binding the binding number to use for the depth texture
|
||||||
void AddDepthTexture(const std::string& name,
|
void AddDepthTexture(const std::string& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
|
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
|
||||||
|
@ -411,7 +410,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
const std::string& texture_name,
|
const std::string& texture_name,
|
||||||
const std::string& sampler_name,
|
const std::string& sampler_name,
|
||||||
const std::string& coords_name,
|
const std::string& coords_name,
|
||||||
typ::Type base_type,
|
ast::Type* base_type,
|
||||||
ast::DecorationList decorations) {
|
ast::DecorationList decorations) {
|
||||||
std::string result_name = "sampler_result";
|
std::string result_name = "sampler_result";
|
||||||
|
|
||||||
|
@ -442,7 +441,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
const std::string& sampler_name,
|
const std::string& sampler_name,
|
||||||
const std::string& coords_name,
|
const std::string& coords_name,
|
||||||
const std::string& array_index,
|
const std::string& array_index,
|
||||||
typ::Type base_type,
|
ast::Type* base_type,
|
||||||
ast::DecorationList decorations) {
|
ast::DecorationList decorations) {
|
||||||
std::string result_name = "sampler_result";
|
std::string result_name = "sampler_result";
|
||||||
|
|
||||||
|
@ -475,7 +474,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
const std::string& sampler_name,
|
const std::string& sampler_name,
|
||||||
const std::string& coords_name,
|
const std::string& coords_name,
|
||||||
const std::string& depth_name,
|
const std::string& depth_name,
|
||||||
typ::Type base_type,
|
ast::Type* base_type,
|
||||||
ast::DecorationList decorations) {
|
ast::DecorationList decorations) {
|
||||||
std::string result_name = "sampler_result";
|
std::string result_name = "sampler_result";
|
||||||
|
|
||||||
|
@ -494,7 +493,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// Gets an appropriate type for the data in a given texture type.
|
/// Gets an appropriate type for the data in a given texture type.
|
||||||
/// @param sampled_kind type of in the texture
|
/// @param sampled_kind type of in the texture
|
||||||
/// @returns a pointer to a type appropriate for the coord param
|
/// @returns a pointer to a type appropriate for the coord param
|
||||||
typ::Type GetBaseType(ResourceBinding::SampledKind sampled_kind) {
|
ast::Type* GetBaseType(ResourceBinding::SampledKind sampled_kind) {
|
||||||
switch (sampled_kind) {
|
switch (sampled_kind) {
|
||||||
case ResourceBinding::SampledKind::kFloat:
|
case ResourceBinding::SampledKind::kFloat:
|
||||||
return ty.f32();
|
return ty.f32();
|
||||||
|
@ -512,17 +511,17 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param dim dimensionality of the texture being sampled
|
/// @param dim dimensionality of the texture being sampled
|
||||||
/// @param scalar the scalar type
|
/// @param scalar the scalar type
|
||||||
/// @returns a pointer to a type appropriate for the coord param
|
/// @returns a pointer to a type appropriate for the coord param
|
||||||
typ::Type GetCoordsType(ast::TextureDimension dim, typ::Type scalar) {
|
ast::Type* GetCoordsType(ast::TextureDimension dim, ast::Type* scalar) {
|
||||||
switch (dim) {
|
switch (dim) {
|
||||||
case ast::TextureDimension::k1d:
|
case ast::TextureDimension::k1d:
|
||||||
return scalar;
|
return scalar;
|
||||||
case ast::TextureDimension::k2d:
|
case ast::TextureDimension::k2d:
|
||||||
case ast::TextureDimension::k2dArray:
|
case ast::TextureDimension::k2dArray:
|
||||||
return create<sem::Vector>(scalar, 2);
|
return create<ast::Vector>(scalar, 2);
|
||||||
case ast::TextureDimension::k3d:
|
case ast::TextureDimension::k3d:
|
||||||
case ast::TextureDimension::kCube:
|
case ast::TextureDimension::kCube:
|
||||||
case ast::TextureDimension::kCubeArray:
|
case ast::TextureDimension::kCubeArray:
|
||||||
return create<sem::Vector>(scalar, 3);
|
return create<ast::Vector>(scalar, 3);
|
||||||
default:
|
default:
|
||||||
[=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
|
[=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
|
||||||
}
|
}
|
||||||
|
@ -604,8 +603,10 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
return *inspector_;
|
return *inspector_;
|
||||||
}
|
}
|
||||||
|
|
||||||
typ::Sampler sampler_type() { return ty.sampler(ast::SamplerKind::kSampler); }
|
ast::Sampler* sampler_type() {
|
||||||
typ::Sampler comparison_sampler_type() {
|
return ty.sampler(ast::SamplerKind::kSampler);
|
||||||
|
}
|
||||||
|
ast::Sampler* comparison_sampler_type() {
|
||||||
return ty.sampler(ast::SamplerKind::kComparisonSampler);
|
return ty.sampler(ast::SamplerKind::kComparisonSampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -835,23 +836,23 @@ TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
|
||||||
|
|
||||||
TEST_P(InspectorGetEntryPointTestWithComponentTypeParam, InOutVariables) {
|
TEST_P(InspectorGetEntryPointTestWithComponentTypeParam, InOutVariables) {
|
||||||
ComponentType inspector_type = GetParam();
|
ComponentType inspector_type = GetParam();
|
||||||
typ::Type tint_type = nullptr;
|
std::function<typ::Type()> tint_type;
|
||||||
switch (inspector_type) {
|
switch (inspector_type) {
|
||||||
case ComponentType::kFloat:
|
case ComponentType::kFloat:
|
||||||
tint_type = ty.f32();
|
tint_type = [this]() -> typ::Type { return ty.f32(); };
|
||||||
break;
|
break;
|
||||||
case ComponentType::kSInt:
|
case ComponentType::kSInt:
|
||||||
tint_type = ty.i32();
|
tint_type = [this]() -> typ::Type { return ty.i32(); };
|
||||||
break;
|
break;
|
||||||
case ComponentType::kUInt:
|
case ComponentType::kUInt:
|
||||||
tint_type = ty.u32();
|
tint_type = [this]() -> typ::Type { return ty.u32(); };
|
||||||
break;
|
break;
|
||||||
case ComponentType::kUnknown:
|
case ComponentType::kUnknown:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* in_var = Param("in_var", tint_type, {Location(0u)});
|
auto* in_var = Param("in_var", tint_type(), {Location(0u)});
|
||||||
Func("foo", {in_var}, tint_type, {Return("in_var")},
|
Func("foo", {in_var}, tint_type(), {Return("in_var")},
|
||||||
{Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
|
{Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
|
||||||
Inspector& inspector = Build();
|
Inspector& inspector = Build();
|
||||||
|
|
||||||
|
@ -1600,18 +1601,12 @@ TEST_F(InspectorGetResourceBindingsTest, Simple) {
|
||||||
AddUniformBuffer("ub_var", ub_struct_type, 0, 0);
|
AddUniformBuffer("ub_var", ub_struct_type, 0, 0);
|
||||||
MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
|
MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
|
||||||
|
|
||||||
typ::Struct sb_struct_type;
|
auto sb = MakeStorageBufferTypes("sb_type", {ty.i32()});
|
||||||
typ::AccessControl sb_control_type;
|
AddStorageBuffer("sb_var", sb(), 1, 0);
|
||||||
std::tie(sb_struct_type, sb_control_type) =
|
|
||||||
MakeStorageBufferTypes("sb_type", {ty.i32()});
|
|
||||||
AddStorageBuffer("sb_var", sb_control_type, 1, 0);
|
|
||||||
MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
|
MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
|
||||||
|
|
||||||
typ::Struct rosb_struct_type;
|
auto ro_sb = MakeReadOnlyStorageBufferTypes("rosb_type", {ty.i32()});
|
||||||
typ::AccessControl rosb_control_type;
|
AddStorageBuffer("rosb_var", ro_sb(), 1, 1);
|
||||||
std::tie(rosb_struct_type, rosb_control_type) =
|
|
||||||
MakeReadOnlyStorageBufferTypes("rosb_type", {ty.i32()});
|
|
||||||
AddStorageBuffer("rosb_var", rosb_control_type, 1, 1);
|
|
||||||
MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
|
MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
|
||||||
{{0, ty.i32()}});
|
{{0, ty.i32()}});
|
||||||
|
|
||||||
|
@ -1896,11 +1891,8 @@ TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingArray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple) {
|
TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple) {
|
||||||
typ::Struct foo_struct_type;
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
|
||||||
typ::AccessControl foo_control_type;
|
AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
|
||||||
std::tie(foo_struct_type, foo_control_type) =
|
|
||||||
MakeStorageBufferTypes("foo_type", {ty.i32()});
|
|
||||||
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
|
|
||||||
|
|
||||||
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
||||||
|
|
||||||
|
@ -1924,11 +1916,12 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleMembers) {
|
TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleMembers) {
|
||||||
typ::Struct foo_struct_type;
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
|
||||||
typ::AccessControl foo_control_type;
|
ty.i32(),
|
||||||
std::tie(foo_struct_type, foo_control_type) =
|
ty.u32(),
|
||||||
MakeStorageBufferTypes("foo_type", {ty.i32(), ty.u32(), ty.f32()});
|
ty.f32(),
|
||||||
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
|
});
|
||||||
|
AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
|
||||||
|
|
||||||
MakeStructVariableReferenceBodyFunction(
|
MakeStructVariableReferenceBodyFunction(
|
||||||
"sb_func", "foo_sb", {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
|
"sb_func", "foo_sb", {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
|
||||||
|
@ -1953,13 +1946,14 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleMembers) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
|
TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
|
||||||
typ::Struct sb_struct_type;
|
auto sb_struct_type = MakeStorageBufferTypes("sb_type", {
|
||||||
typ::AccessControl sb_control_type;
|
ty.i32(),
|
||||||
std::tie(sb_struct_type, sb_control_type) =
|
ty.u32(),
|
||||||
MakeStorageBufferTypes("sb_type", {ty.i32(), ty.u32(), ty.f32()});
|
ty.f32(),
|
||||||
AddStorageBuffer("sb_foo", sb_control_type, 0, 0);
|
});
|
||||||
AddStorageBuffer("sb_bar", sb_control_type, 0, 1);
|
AddStorageBuffer("sb_foo", sb_struct_type(), 0, 0);
|
||||||
AddStorageBuffer("sb_baz", sb_control_type, 2, 0);
|
AddStorageBuffer("sb_bar", sb_struct_type(), 0, 1);
|
||||||
|
AddStorageBuffer("sb_baz", sb_struct_type(), 2, 0);
|
||||||
|
|
||||||
auto AddReferenceFunc = [this](const std::string& func_name,
|
auto AddReferenceFunc = [this](const std::string& func_name,
|
||||||
const std::string& var_name) {
|
const std::string& var_name) {
|
||||||
|
@ -2014,11 +2008,9 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingArray) {
|
TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingArray) {
|
||||||
typ::Struct foo_struct_type;
|
auto foo_struct_type =
|
||||||
typ::AccessControl foo_control_type;
|
|
||||||
std::tie(foo_struct_type, foo_control_type) =
|
|
||||||
MakeStorageBufferTypes("foo_type", {ty.i32(), ty.array<u32, 4>()});
|
MakeStorageBufferTypes("foo_type", {ty.i32(), ty.array<u32, 4>()});
|
||||||
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
|
AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
|
||||||
|
|
||||||
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
||||||
|
|
||||||
|
@ -2042,11 +2034,11 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingArray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingRuntimeArray) {
|
TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingRuntimeArray) {
|
||||||
typ::Struct foo_struct_type;
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
|
||||||
typ::AccessControl foo_control_type;
|
ty.i32(),
|
||||||
std::tie(foo_struct_type, foo_control_type) =
|
ty.array<u32>(),
|
||||||
MakeStorageBufferTypes("foo_type", {ty.i32(), ty.array<u32>()});
|
});
|
||||||
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
|
AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
|
||||||
|
|
||||||
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
||||||
|
|
||||||
|
@ -2070,11 +2062,8 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingRuntimeArray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingPadding) {
|
TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingPadding) {
|
||||||
typ::Struct foo_struct_type;
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.vec3<f32>()});
|
||||||
typ::AccessControl foo_control_type;
|
AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
|
||||||
std::tie(foo_struct_type, foo_control_type) =
|
|
||||||
MakeStorageBufferTypes("foo_type", {ty.vec3<f32>()});
|
|
||||||
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
|
|
||||||
|
|
||||||
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
|
||||||
{{0, ty.vec3<f32>()}});
|
{{0, ty.vec3<f32>()}});
|
||||||
|
@ -2099,11 +2088,8 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingPadding) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetStorageBufferResourceBindingsTest, SkipReadOnly) {
|
TEST_F(InspectorGetStorageBufferResourceBindingsTest, SkipReadOnly) {
|
||||||
typ::Struct foo_struct_type;
|
auto foo_struct_type = MakeReadOnlyStorageBufferTypes("foo_type", {ty.i32()});
|
||||||
typ::AccessControl foo_control_type;
|
AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
|
||||||
std::tie(foo_struct_type, foo_control_type) =
|
|
||||||
MakeReadOnlyStorageBufferTypes("foo_type", {ty.i32()});
|
|
||||||
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
|
|
||||||
|
|
||||||
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
||||||
|
|
||||||
|
@ -2120,11 +2106,8 @@ TEST_F(InspectorGetStorageBufferResourceBindingsTest, SkipReadOnly) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, Simple) {
|
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, Simple) {
|
||||||
typ::Struct foo_struct_type;
|
auto foo_struct_type = MakeReadOnlyStorageBufferTypes("foo_type", {ty.i32()});
|
||||||
typ::AccessControl foo_control_type;
|
AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
|
||||||
std::tie(foo_struct_type, foo_control_type) =
|
|
||||||
MakeReadOnlyStorageBufferTypes("foo_type", {ty.i32()});
|
|
||||||
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
|
|
||||||
|
|
||||||
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
||||||
|
|
||||||
|
@ -2149,13 +2132,14 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, Simple) {
|
||||||
|
|
||||||
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
|
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
|
||||||
MultipleStorageBuffers) {
|
MultipleStorageBuffers) {
|
||||||
typ::Struct sb_struct_type;
|
auto sb_struct_type = MakeReadOnlyStorageBufferTypes("sb_type", {
|
||||||
typ::AccessControl sb_control_type;
|
ty.i32(),
|
||||||
std::tie(sb_struct_type, sb_control_type) =
|
ty.u32(),
|
||||||
MakeReadOnlyStorageBufferTypes("sb_type", {ty.i32(), ty.u32(), ty.f32()});
|
ty.f32(),
|
||||||
AddStorageBuffer("sb_foo", sb_control_type, 0, 0);
|
});
|
||||||
AddStorageBuffer("sb_bar", sb_control_type, 0, 1);
|
AddStorageBuffer("sb_foo", sb_struct_type(), 0, 0);
|
||||||
AddStorageBuffer("sb_baz", sb_control_type, 2, 0);
|
AddStorageBuffer("sb_bar", sb_struct_type(), 0, 1);
|
||||||
|
AddStorageBuffer("sb_baz", sb_struct_type(), 2, 0);
|
||||||
|
|
||||||
auto AddReferenceFunc = [this](const std::string& func_name,
|
auto AddReferenceFunc = [this](const std::string& func_name,
|
||||||
const std::string& var_name) {
|
const std::string& var_name) {
|
||||||
|
@ -2210,11 +2194,12 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingArray) {
|
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingArray) {
|
||||||
typ::Struct foo_struct_type;
|
auto foo_struct_type =
|
||||||
typ::AccessControl foo_control_type;
|
MakeReadOnlyStorageBufferTypes("foo_type", {
|
||||||
std::tie(foo_struct_type, foo_control_type) = MakeReadOnlyStorageBufferTypes(
|
ty.i32(),
|
||||||
"foo_type", {ty.i32(), ty.array<u32, 4>()});
|
ty.array<u32, 4>(),
|
||||||
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
|
});
|
||||||
|
AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
|
||||||
|
|
||||||
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
||||||
|
|
||||||
|
@ -2239,11 +2224,12 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingArray) {
|
||||||
|
|
||||||
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
|
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
|
||||||
ContainingRuntimeArray) {
|
ContainingRuntimeArray) {
|
||||||
typ::Struct foo_struct_type;
|
auto foo_struct_type =
|
||||||
typ::AccessControl foo_control_type;
|
MakeReadOnlyStorageBufferTypes("foo_type", {
|
||||||
std::tie(foo_struct_type, foo_control_type) =
|
ty.i32(),
|
||||||
MakeReadOnlyStorageBufferTypes("foo_type", {ty.i32(), ty.array<u32>()});
|
ty.array<u32>(),
|
||||||
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
|
});
|
||||||
|
AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
|
||||||
|
|
||||||
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
||||||
|
|
||||||
|
@ -2267,11 +2253,8 @@ TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, SkipNonReadOnly) {
|
TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, SkipNonReadOnly) {
|
||||||
typ::Struct foo_struct_type;
|
auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
|
||||||
typ::AccessControl foo_control_type;
|
AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
|
||||||
std::tie(foo_struct_type, foo_control_type) =
|
|
||||||
MakeStorageBufferTypes("foo_type", {ty.i32()});
|
|
||||||
AddStorageBuffer("foo_sb", foo_control_type, 0, 0);
|
|
||||||
|
|
||||||
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
|
||||||
|
|
||||||
|
@ -2514,7 +2497,7 @@ TEST_P(InspectorGetSampledTextureResourceBindingsTestWithParam, textureSample) {
|
||||||
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
|
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
|
||||||
AddSampledTexture("foo_texture", sampled_texture_type, 0, 0);
|
AddSampledTexture("foo_texture", sampled_texture_type, 0, 0);
|
||||||
AddSampler("foo_sampler", 0, 1);
|
AddSampler("foo_sampler", 0, 1);
|
||||||
auto coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
|
auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
|
||||||
AddGlobalVariable("foo_coords", coord_type);
|
AddGlobalVariable("foo_coords", coord_type);
|
||||||
|
|
||||||
MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
|
MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
|
||||||
|
@ -2572,7 +2555,7 @@ TEST_P(InspectorGetSampledArrayTextureResourceBindingsTestWithParam,
|
||||||
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
|
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
|
||||||
AddSampledTexture("foo_texture", sampled_texture_type, 0, 0);
|
AddSampledTexture("foo_texture", sampled_texture_type, 0, 0);
|
||||||
AddSampler("foo_sampler", 0, 1);
|
AddSampler("foo_sampler", 0, 1);
|
||||||
auto coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
|
auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
|
||||||
AddGlobalVariable("foo_coords", coord_type);
|
AddGlobalVariable("foo_coords", coord_type);
|
||||||
AddGlobalVariable("foo_array_index", ty.i32());
|
AddGlobalVariable("foo_array_index", ty.i32());
|
||||||
|
|
||||||
|
@ -2615,7 +2598,7 @@ TEST_P(InspectorGetMultisampledTextureResourceBindingsTestWithParam,
|
||||||
auto multisampled_texture_type = MakeMultisampledTextureType(
|
auto multisampled_texture_type = MakeMultisampledTextureType(
|
||||||
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
|
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
|
||||||
AddMultisampledTexture("foo_texture", multisampled_texture_type, 0, 0);
|
AddMultisampledTexture("foo_texture", multisampled_texture_type, 0, 0);
|
||||||
auto coord_type = GetCoordsType(GetParam().type_dim, ty.i32());
|
auto* coord_type = GetCoordsType(GetParam().type_dim, ty.i32());
|
||||||
AddGlobalVariable("foo_coords", coord_type);
|
AddGlobalVariable("foo_coords", coord_type);
|
||||||
AddGlobalVariable("foo_sample_index", ty.i32());
|
AddGlobalVariable("foo_sample_index", ty.i32());
|
||||||
|
|
||||||
|
@ -2633,9 +2616,9 @@ TEST_P(InspectorGetMultisampledTextureResourceBindingsTestWithParam,
|
||||||
auto result = inspector.GetMultisampledTextureResourceBindings("ep");
|
auto result = inspector.GetMultisampledTextureResourceBindings("ep");
|
||||||
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
ASSERT_FALSE(inspector.has_error()) << inspector.error();
|
||||||
|
|
||||||
|
ASSERT_EQ(1u, result.size());
|
||||||
EXPECT_EQ(ResourceBinding::ResourceType::kMultisampledTexture,
|
EXPECT_EQ(ResourceBinding::ResourceType::kMultisampledTexture,
|
||||||
result[0].resource_type);
|
result[0].resource_type);
|
||||||
ASSERT_EQ(1u, result.size());
|
|
||||||
EXPECT_EQ(0u, result[0].bind_group);
|
EXPECT_EQ(0u, result[0].bind_group);
|
||||||
EXPECT_EQ(0u, result[0].binding);
|
EXPECT_EQ(0u, result[0].binding);
|
||||||
EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
|
EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
|
||||||
|
@ -2685,7 +2668,7 @@ TEST_P(InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam,
|
||||||
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
|
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
|
||||||
AddMultisampledTexture("foo_texture", multisampled_texture_type, 0, 0);
|
AddMultisampledTexture("foo_texture", multisampled_texture_type, 0, 0);
|
||||||
AddSampler("foo_sampler", 0, 1);
|
AddSampler("foo_sampler", 0, 1);
|
||||||
auto coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
|
auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
|
||||||
AddGlobalVariable("foo_coords", coord_type);
|
AddGlobalVariable("foo_coords", coord_type);
|
||||||
AddGlobalVariable("foo_array_index", ty.i32());
|
AddGlobalVariable("foo_array_index", ty.i32());
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
#include "src/ast/assignment_statement.h"
|
#include "src/ast/assignment_statement.h"
|
||||||
#include "src/ast/call_statement.h"
|
#include "src/ast/call_statement.h"
|
||||||
#include "src/ast/type_name.h"
|
|
||||||
#include "src/ast/variable_decl_statement.h"
|
#include "src/ast/variable_decl_statement.h"
|
||||||
#include "src/debug.h"
|
#include "src/debug.h"
|
||||||
#include "src/demangler.h"
|
#include "src/demangler.h"
|
||||||
|
@ -96,51 +95,62 @@ const sem::Type* ProgramBuilder::TypeOf(const ast::Type* type) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::ConstructorExpression* ProgramBuilder::ConstructValueFilledWith(
|
ast::ConstructorExpression* ProgramBuilder::ConstructValueFilledWith(
|
||||||
typ::Type type,
|
const ast::Type* type,
|
||||||
int elem_value) {
|
int elem_value) {
|
||||||
auto* unwrapped_type = type->UnwrapAliasIfNeeded();
|
CloneContext ctx(this);
|
||||||
if (unwrapped_type->Is<sem::Bool>()) {
|
|
||||||
|
if (type->Is<ast::Bool>()) {
|
||||||
return create<ast::ScalarConstructorExpression>(
|
return create<ast::ScalarConstructorExpression>(
|
||||||
create<ast::BoolLiteral>(elem_value == 0 ? false : true));
|
create<ast::BoolLiteral>(elem_value == 0 ? false : true));
|
||||||
}
|
}
|
||||||
if (unwrapped_type->Is<sem::I32>()) {
|
if (type->Is<ast::I32>()) {
|
||||||
return create<ast::ScalarConstructorExpression>(
|
return create<ast::ScalarConstructorExpression>(
|
||||||
create<ast::SintLiteral>(static_cast<i32>(elem_value)));
|
create<ast::SintLiteral>(static_cast<i32>(elem_value)));
|
||||||
}
|
}
|
||||||
if (unwrapped_type->Is<sem::U32>()) {
|
if (type->Is<ast::U32>()) {
|
||||||
return create<ast::ScalarConstructorExpression>(
|
return create<ast::ScalarConstructorExpression>(
|
||||||
create<ast::UintLiteral>(static_cast<u32>(elem_value)));
|
create<ast::UintLiteral>(static_cast<u32>(elem_value)));
|
||||||
}
|
}
|
||||||
if (unwrapped_type->Is<sem::F32>()) {
|
if (type->Is<ast::F32>()) {
|
||||||
return create<ast::ScalarConstructorExpression>(
|
return create<ast::ScalarConstructorExpression>(
|
||||||
create<ast::FloatLiteral>(static_cast<f32>(elem_value)));
|
create<ast::FloatLiteral>(static_cast<f32>(elem_value)));
|
||||||
}
|
}
|
||||||
if (auto* v = unwrapped_type->As<sem::Vector>()) {
|
if (auto* v = type->As<ast::Vector>()) {
|
||||||
ast::ExpressionList el(v->size());
|
ast::ExpressionList el(v->size());
|
||||||
for (size_t i = 0; i < el.size(); i++) {
|
for (size_t i = 0; i < el.size(); i++) {
|
||||||
el[i] = ConstructValueFilledWith(v->type(), elem_value);
|
el[i] = ConstructValueFilledWith(ctx.Clone(v->type()), elem_value);
|
||||||
}
|
}
|
||||||
return create<ast::TypeConstructorExpression>(type, std::move(el));
|
return create<ast::TypeConstructorExpression>(const_cast<ast::Type*>(type),
|
||||||
|
std::move(el));
|
||||||
}
|
}
|
||||||
if (auto* m = unwrapped_type->As<sem::Matrix>()) {
|
if (auto* m = type->As<ast::Matrix>()) {
|
||||||
auto* col_vec_type = create<sem::Vector>(m->type(), m->rows());
|
ast::ExpressionList el(m->columns());
|
||||||
ast::ExpressionList el(col_vec_type->size());
|
|
||||||
for (size_t i = 0; i < el.size(); i++) {
|
for (size_t i = 0; i < el.size(); i++) {
|
||||||
|
auto* col_vec_type = create<ast::Vector>(ctx.Clone(m->type()), m->rows());
|
||||||
el[i] = ConstructValueFilledWith(col_vec_type, elem_value);
|
el[i] = ConstructValueFilledWith(col_vec_type, elem_value);
|
||||||
}
|
}
|
||||||
return create<ast::TypeConstructorExpression>(type, std::move(el));
|
return create<ast::TypeConstructorExpression>(const_cast<ast::Type*>(type),
|
||||||
|
std::move(el));
|
||||||
}
|
}
|
||||||
TINT_ASSERT(false);
|
if (auto* tn = type->As<ast::TypeName>()) {
|
||||||
|
if (auto* lookup = AST().LookupType(tn->name())) {
|
||||||
|
if (auto* alias = lookup->As<ast::Alias>()) {
|
||||||
|
return ConstructValueFilledWith(ctx.Clone(alias->type()), elem_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TINT_ICE(diagnostics_) << "unable to find NamedType '"
|
||||||
|
<< Symbols().NameFor(tn->name()) << "'";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
TINT_ICE(diagnostics_) << "unhandled type: " << type->TypeInfo().name;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
typ::Type ProgramBuilder::TypesBuilder::MaybeCreateTypename(
|
typ::Type ProgramBuilder::TypesBuilder::MaybeCreateTypename(
|
||||||
typ::Type type) const {
|
typ::Type type) const {
|
||||||
if (auto* alias = As<ast::Alias>(type.ast)) {
|
if (auto* nt = As<ast::NamedType>(type.ast)) {
|
||||||
return {builder->create<ast::TypeName>(alias->symbol()), type.sem};
|
return {type_name(nt->name()), type.sem};
|
||||||
}
|
|
||||||
if (auto* str = As<ast::Struct>(type.ast)) {
|
|
||||||
return {builder->create<ast::TypeName>(str->name()), type.sem};
|
|
||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1060,7 +1060,7 @@ class ProgramBuilder {
|
||||||
/// @return an `ast::TypeConstructorExpression` of `type` constructed with the
|
/// @return an `ast::TypeConstructorExpression` of `type` constructed with the
|
||||||
/// values `args`.
|
/// values `args`.
|
||||||
template <typename... ARGS>
|
template <typename... ARGS>
|
||||||
ast::TypeConstructorExpression* Construct(typ::Type type, ARGS&&... args) {
|
ast::TypeConstructorExpression* Construct(ast::Type* type, ARGS&&... args) {
|
||||||
type = ty.MaybeCreateTypename(type);
|
type = ty.MaybeCreateTypename(type);
|
||||||
return create<ast::TypeConstructorExpression>(
|
return create<ast::TypeConstructorExpression>(
|
||||||
type, ExprList(std::forward<ARGS>(args)...));
|
type, ExprList(std::forward<ARGS>(args)...));
|
||||||
|
@ -1074,7 +1074,7 @@ class ProgramBuilder {
|
||||||
/// @param elem_value the initial or element value (for vec and mat) to
|
/// @param elem_value the initial or element value (for vec and mat) to
|
||||||
/// construct with
|
/// construct with
|
||||||
/// @return the constructor expression
|
/// @return the constructor expression
|
||||||
ast::ConstructorExpression* ConstructValueFilledWith(typ::Type type,
|
ast::ConstructorExpression* ConstructValueFilledWith(const ast::Type* type,
|
||||||
int elem_value = 0);
|
int elem_value = 0);
|
||||||
|
|
||||||
/// @param args the arguments for the vector constructor
|
/// @param args the arguments for the vector constructor
|
||||||
|
@ -1187,7 +1187,7 @@ class ProgramBuilder {
|
||||||
/// @return an `ast::TypeConstructorExpression` of an array with element type
|
/// @return an `ast::TypeConstructorExpression` of an array with element type
|
||||||
/// `subtype`, constructed with the values `args`.
|
/// `subtype`, constructed with the values `args`.
|
||||||
template <typename... ARGS>
|
template <typename... ARGS>
|
||||||
ast::TypeConstructorExpression* array(typ::Type subtype,
|
ast::TypeConstructorExpression* array(ast::Type* subtype,
|
||||||
uint32_t n,
|
uint32_t n,
|
||||||
ARGS&&... args) {
|
ARGS&&... args) {
|
||||||
return Construct(ty.array(subtype, n), std::forward<ARGS>(args)...);
|
return Construct(ty.array(subtype, n), std::forward<ARGS>(args)...);
|
||||||
|
@ -1201,7 +1201,7 @@ class ProgramBuilder {
|
||||||
/// @returns a `ast::Variable` with the given name, storage and type
|
/// @returns a `ast::Variable` with the given name, storage and type
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
ast::Variable* Var(NAME&& name,
|
ast::Variable* Var(NAME&& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::StorageClass storage,
|
ast::StorageClass storage,
|
||||||
ast::Expression* constructor = nullptr,
|
ast::Expression* constructor = nullptr,
|
||||||
ast::DecorationList decorations = {}) {
|
ast::DecorationList decorations = {}) {
|
||||||
|
@ -1220,7 +1220,7 @@ class ProgramBuilder {
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
ast::Variable* Var(const Source& source,
|
ast::Variable* Var(const Source& source,
|
||||||
NAME&& name,
|
NAME&& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::StorageClass storage,
|
ast::StorageClass storage,
|
||||||
ast::Expression* constructor = nullptr,
|
ast::Expression* constructor = nullptr,
|
||||||
ast::DecorationList decorations = {}) {
|
ast::DecorationList decorations = {}) {
|
||||||
|
@ -1236,7 +1236,7 @@ class ProgramBuilder {
|
||||||
/// @returns a constant `ast::Variable` with the given name and type
|
/// @returns a constant `ast::Variable` with the given name and type
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
ast::Variable* Const(NAME&& name,
|
ast::Variable* Const(NAME&& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::Expression* constructor = nullptr,
|
ast::Expression* constructor = nullptr,
|
||||||
ast::DecorationList decorations = {}) {
|
ast::DecorationList decorations = {}) {
|
||||||
type = ty.MaybeCreateTypename(type);
|
type = ty.MaybeCreateTypename(type);
|
||||||
|
@ -1254,7 +1254,7 @@ class ProgramBuilder {
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
ast::Variable* Const(const Source& source,
|
ast::Variable* Const(const Source& source,
|
||||||
NAME&& name,
|
NAME&& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::Expression* constructor = nullptr,
|
ast::Expression* constructor = nullptr,
|
||||||
ast::DecorationList decorations = {}) {
|
ast::DecorationList decorations = {}) {
|
||||||
type = ty.MaybeCreateTypename(type);
|
type = ty.MaybeCreateTypename(type);
|
||||||
|
@ -1269,7 +1269,7 @@ class ProgramBuilder {
|
||||||
/// @returns a constant `ast::Variable` with the given name and type
|
/// @returns a constant `ast::Variable` with the given name and type
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
ast::Variable* Param(NAME&& name,
|
ast::Variable* Param(NAME&& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::DecorationList decorations = {}) {
|
ast::DecorationList decorations = {}) {
|
||||||
type = ty.MaybeCreateTypename(type);
|
type = ty.MaybeCreateTypename(type);
|
||||||
return create<ast::Variable>(Sym(std::forward<NAME>(name)),
|
return create<ast::Variable>(Sym(std::forward<NAME>(name)),
|
||||||
|
@ -1285,7 +1285,7 @@ class ProgramBuilder {
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
ast::Variable* Param(const Source& source,
|
ast::Variable* Param(const Source& source,
|
||||||
NAME&& name,
|
NAME&& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::DecorationList decorations = {}) {
|
ast::DecorationList decorations = {}) {
|
||||||
type = ty.MaybeCreateTypename(type);
|
type = ty.MaybeCreateTypename(type);
|
||||||
return create<ast::Variable>(source, Sym(std::forward<NAME>(name)),
|
return create<ast::Variable>(source, Sym(std::forward<NAME>(name)),
|
||||||
|
@ -1302,7 +1302,7 @@ class ProgramBuilder {
|
||||||
/// global variable with the ast::Module.
|
/// global variable with the ast::Module.
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
ast::Variable* Global(NAME&& name,
|
ast::Variable* Global(NAME&& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::StorageClass storage,
|
ast::StorageClass storage,
|
||||||
ast::Expression* constructor = nullptr,
|
ast::Expression* constructor = nullptr,
|
||||||
ast::DecorationList decorations = {}) {
|
ast::DecorationList decorations = {}) {
|
||||||
|
@ -1323,7 +1323,7 @@ class ProgramBuilder {
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
ast::Variable* Global(const Source& source,
|
ast::Variable* Global(const Source& source,
|
||||||
NAME&& name,
|
NAME&& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::StorageClass storage,
|
ast::StorageClass storage,
|
||||||
ast::Expression* constructor = nullptr,
|
ast::Expression* constructor = nullptr,
|
||||||
ast::DecorationList decorations = {}) {
|
ast::DecorationList decorations = {}) {
|
||||||
|
@ -1476,7 +1476,7 @@ class ProgramBuilder {
|
||||||
ast::Function* Func(const Source& source,
|
ast::Function* Func(const Source& source,
|
||||||
NAME&& name,
|
NAME&& name,
|
||||||
ast::VariableList params,
|
ast::VariableList params,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::StatementList body,
|
ast::StatementList body,
|
||||||
ast::DecorationList decorations = {},
|
ast::DecorationList decorations = {},
|
||||||
ast::DecorationList return_type_decorations = {}) {
|
ast::DecorationList return_type_decorations = {}) {
|
||||||
|
@ -1501,7 +1501,7 @@ class ProgramBuilder {
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
ast::Function* Func(NAME&& name,
|
ast::Function* Func(NAME&& name,
|
||||||
ast::VariableList params,
|
ast::VariableList params,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::StatementList body,
|
ast::StatementList body,
|
||||||
ast::DecorationList decorations = {},
|
ast::DecorationList decorations = {},
|
||||||
ast::DecorationList return_type_decorations = {}) {
|
ast::DecorationList return_type_decorations = {}) {
|
||||||
|
@ -1588,7 +1588,7 @@ class ProgramBuilder {
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
ast::StructMember* Member(const Source& source,
|
ast::StructMember* Member(const Source& source,
|
||||||
NAME&& name,
|
NAME&& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::DecorationList decorations = {}) {
|
ast::DecorationList decorations = {}) {
|
||||||
type = ty.MaybeCreateTypename(type);
|
type = ty.MaybeCreateTypename(type);
|
||||||
return create<ast::StructMember>(source, Sym(std::forward<NAME>(name)),
|
return create<ast::StructMember>(source, Sym(std::forward<NAME>(name)),
|
||||||
|
@ -1602,7 +1602,7 @@ class ProgramBuilder {
|
||||||
/// @returns the struct member pointer
|
/// @returns the struct member pointer
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
ast::StructMember* Member(NAME&& name,
|
ast::StructMember* Member(NAME&& name,
|
||||||
typ::Type type,
|
ast::Type* type,
|
||||||
ast::DecorationList decorations = {}) {
|
ast::DecorationList decorations = {}) {
|
||||||
type = ty.MaybeCreateTypename(type);
|
type = ty.MaybeCreateTypename(type);
|
||||||
return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)),
|
return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)),
|
||||||
|
@ -1615,7 +1615,7 @@ class ProgramBuilder {
|
||||||
/// @param type the struct member type
|
/// @param type the struct member type
|
||||||
/// @returns the struct member pointer
|
/// @returns the struct member pointer
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
ast::StructMember* Member(uint32_t offset, NAME&& name, typ::Type type) {
|
ast::StructMember* Member(uint32_t offset, NAME&& name, ast::Type* type) {
|
||||||
type = ty.MaybeCreateTypename(type);
|
type = ty.MaybeCreateTypename(type);
|
||||||
return create<ast::StructMember>(
|
return create<ast::StructMember>(
|
||||||
source_, Sym(std::forward<NAME>(name)), type,
|
source_, Sym(std::forward<NAME>(name)), type,
|
||||||
|
|
|
@ -218,7 +218,7 @@ TEST_F(SpvParserTest_Composite_Construct, Struct) {
|
||||||
VariableConst{
|
VariableConst{
|
||||||
x_1
|
x_1
|
||||||
none
|
none
|
||||||
__struct_S
|
__type_name_S
|
||||||
{
|
{
|
||||||
TypeConstructor[not set]{
|
TypeConstructor[not set]{
|
||||||
__type_name_S
|
__type_name_S
|
||||||
|
@ -835,14 +835,14 @@ TEST_F(SpvParserTest_CompositeInsert, Struct) {
|
||||||
Variable{
|
Variable{
|
||||||
x_35
|
x_35
|
||||||
function
|
function
|
||||||
__struct_S
|
__type_name_S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VariableDeclStatement{
|
VariableDeclStatement{
|
||||||
VariableConst{
|
VariableConst{
|
||||||
x_1
|
x_1
|
||||||
none
|
none
|
||||||
__struct_S
|
__type_name_S
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_35}
|
Identifier[not set]{x_35}
|
||||||
}
|
}
|
||||||
|
@ -852,7 +852,7 @@ VariableDeclStatement{
|
||||||
Variable{
|
Variable{
|
||||||
x_2_1
|
x_2_1
|
||||||
function
|
function
|
||||||
__struct_S
|
__type_name_S
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_1}
|
Identifier[not set]{x_1}
|
||||||
}
|
}
|
||||||
|
@ -869,7 +869,7 @@ VariableDeclStatement{
|
||||||
VariableConst{
|
VariableConst{
|
||||||
x_2
|
x_2
|
||||||
none
|
none
|
||||||
__struct_S
|
__type_name_S
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_2_1}
|
Identifier[not set]{x_2_1}
|
||||||
}
|
}
|
||||||
|
@ -909,21 +909,21 @@ TEST_F(SpvParserTest_CompositeInsert, Struct_DifferOnlyInMemberName) {
|
||||||
Variable{
|
Variable{
|
||||||
x_40
|
x_40
|
||||||
function
|
function
|
||||||
__struct_S_2
|
__type_name_S_2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VariableDeclStatement{
|
VariableDeclStatement{
|
||||||
Variable{
|
Variable{
|
||||||
x_41
|
x_41
|
||||||
function
|
function
|
||||||
__struct_S_2
|
__type_name_S_2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VariableDeclStatement{
|
VariableDeclStatement{
|
||||||
VariableConst{
|
VariableConst{
|
||||||
x_1
|
x_1
|
||||||
none
|
none
|
||||||
__struct_S_1
|
__type_name_S_1
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_40}
|
Identifier[not set]{x_40}
|
||||||
}
|
}
|
||||||
|
@ -933,7 +933,7 @@ VariableDeclStatement{
|
||||||
Variable{
|
Variable{
|
||||||
x_2_1
|
x_2_1
|
||||||
function
|
function
|
||||||
__struct_S_1
|
__type_name_S_1
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_1}
|
Identifier[not set]{x_1}
|
||||||
}
|
}
|
||||||
|
@ -950,7 +950,7 @@ VariableDeclStatement{
|
||||||
VariableConst{
|
VariableConst{
|
||||||
x_2
|
x_2
|
||||||
none
|
none
|
||||||
__struct_S_1
|
__type_name_S_1
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_2_1}
|
Identifier[not set]{x_2_1}
|
||||||
}
|
}
|
||||||
|
@ -960,7 +960,7 @@ VariableDeclStatement{
|
||||||
VariableConst{
|
VariableConst{
|
||||||
x_3
|
x_3
|
||||||
none
|
none
|
||||||
__struct_S_2
|
__type_name_S_2
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_41}
|
Identifier[not set]{x_41}
|
||||||
}
|
}
|
||||||
|
@ -970,7 +970,7 @@ VariableDeclStatement{
|
||||||
Variable{
|
Variable{
|
||||||
x_4_1
|
x_4_1
|
||||||
function
|
function
|
||||||
__struct_S_2
|
__type_name_S_2
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_3}
|
Identifier[not set]{x_3}
|
||||||
}
|
}
|
||||||
|
@ -987,7 +987,7 @@ VariableDeclStatement{
|
||||||
VariableConst{
|
VariableConst{
|
||||||
x_4
|
x_4
|
||||||
none
|
none
|
||||||
__struct_S_2
|
__type_name_S_2
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_4_1}
|
Identifier[not set]{x_4_1}
|
||||||
}
|
}
|
||||||
|
@ -998,7 +998,7 @@ VariableDeclStatement{
|
||||||
Variable{
|
Variable{
|
||||||
x_4_1
|
x_4_1
|
||||||
function
|
function
|
||||||
__struct_S_2
|
__type_name_S_2
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_3}
|
Identifier[not set]{x_3}
|
||||||
}
|
}
|
||||||
|
@ -1015,7 +1015,7 @@ VariableDeclStatement{
|
||||||
VariableConst{
|
VariableConst{
|
||||||
x_4
|
x_4
|
||||||
none
|
none
|
||||||
__struct_S_2
|
__type_name_S_2
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_4_1}
|
Identifier[not set]{x_4_1}
|
||||||
}
|
}
|
||||||
|
@ -1066,14 +1066,14 @@ TEST_F(SpvParserTest_CompositeInsert, Struct_Array_Matrix_Vector) {
|
||||||
Variable{
|
Variable{
|
||||||
x_37
|
x_37
|
||||||
function
|
function
|
||||||
__struct_S_1
|
__type_name_S_1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VariableDeclStatement{
|
VariableDeclStatement{
|
||||||
VariableConst{
|
VariableConst{
|
||||||
x_1
|
x_1
|
||||||
none
|
none
|
||||||
__struct_S_1
|
__type_name_S_1
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_37}
|
Identifier[not set]{x_37}
|
||||||
}
|
}
|
||||||
|
@ -1083,7 +1083,7 @@ VariableDeclStatement{
|
||||||
Variable{
|
Variable{
|
||||||
x_2_1
|
x_2_1
|
||||||
function
|
function
|
||||||
__struct_S_1
|
__type_name_S_1
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_1}
|
Identifier[not set]{x_1}
|
||||||
}
|
}
|
||||||
|
@ -1109,7 +1109,7 @@ VariableDeclStatement{
|
||||||
VariableConst{
|
VariableConst{
|
||||||
x_2
|
x_2
|
||||||
none
|
none
|
||||||
__struct_S_1
|
__type_name_S_1
|
||||||
{
|
{
|
||||||
Identifier[not set]{x_2_1}
|
Identifier[not set]{x_2_1}
|
||||||
}
|
}
|
||||||
|
|
|
@ -806,7 +806,7 @@ TEST_F(SpvParserTest, RemapStorageBuffer_TypesAndVarDeclarations) {
|
||||||
Variable{
|
Variable{
|
||||||
myvar
|
myvar
|
||||||
storage
|
storage
|
||||||
__access_control_read_write__struct_S
|
__access_control_read_write__type_name_S
|
||||||
})"));
|
})"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -409,7 +409,7 @@ TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Struct) {
|
||||||
VariableConst{
|
VariableConst{
|
||||||
x_11
|
x_11
|
||||||
none
|
none
|
||||||
__struct_S
|
__type_name_S
|
||||||
{
|
{
|
||||||
TypeConstructor[not set]{
|
TypeConstructor[not set]{
|
||||||
__type_name_S
|
__type_name_S
|
||||||
|
|
|
@ -467,7 +467,7 @@ TEST_F(SpvParserTest, EmitFunctionVariables_ArrayInitializer_Alias) {
|
||||||
Variable{
|
Variable{
|
||||||
x_200
|
x_200
|
||||||
function
|
function
|
||||||
__alias_Arr__array__u32_2_stride_16
|
__type_name_Arr
|
||||||
{
|
{
|
||||||
TypeConstructor[not set]{
|
TypeConstructor[not set]{
|
||||||
__type_name_Arr
|
__type_name_Arr
|
||||||
|
@ -537,7 +537,7 @@ TEST_F(SpvParserTest, EmitFunctionVariables_ArrayInitializer_Alias_Null) {
|
||||||
Variable{
|
Variable{
|
||||||
x_200
|
x_200
|
||||||
function
|
function
|
||||||
__alias_Arr__array__u32_2_stride_16
|
__type_name_Arr
|
||||||
{
|
{
|
||||||
TypeConstructor[not set]{
|
TypeConstructor[not set]{
|
||||||
__type_name_Arr
|
__type_name_Arr
|
||||||
|
@ -572,7 +572,7 @@ TEST_F(SpvParserTest, EmitFunctionVariables_StructInitializer) {
|
||||||
Variable{
|
Variable{
|
||||||
x_200
|
x_200
|
||||||
function
|
function
|
||||||
__struct_S
|
__type_name_S
|
||||||
{
|
{
|
||||||
TypeConstructor[not set]{
|
TypeConstructor[not set]{
|
||||||
__type_name_S
|
__type_name_S
|
||||||
|
@ -612,7 +612,7 @@ TEST_F(SpvParserTest, EmitFunctionVariables_StructInitializer_Null) {
|
||||||
Variable{
|
Variable{
|
||||||
x_200
|
x_200
|
||||||
function
|
function
|
||||||
__struct_S
|
__type_name_S
|
||||||
{
|
{
|
||||||
TypeConstructor[not set]{
|
TypeConstructor[not set]{
|
||||||
__type_name_S
|
__type_name_S
|
||||||
|
|
|
@ -233,7 +233,8 @@ bool AssumesResultSignednessMatchesFirstOperand(GLSLstd450 extended_opcode) {
|
||||||
// @param tp the type pair
|
// @param tp the type pair
|
||||||
// @returns the unwrapped type pair
|
// @returns the unwrapped type pair
|
||||||
typ::Type UnwrapIfNeeded(typ::Type tp) {
|
typ::Type UnwrapIfNeeded(typ::Type tp) {
|
||||||
return typ::Type{tp.ast->UnwrapIfNeeded(), tp.sem->UnwrapIfNeeded()};
|
return typ::Type{tp.ast ? tp.ast->UnwrapIfNeeded() : nullptr,
|
||||||
|
tp.sem ? tp.sem->UnwrapIfNeeded() : nullptr};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -1037,7 +1038,7 @@ typ::Type ParserImpl::ConvertType(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParserImpl::AddConstructedType(Symbol name, typ::Type type) {
|
void ParserImpl::AddConstructedType(Symbol name, ast::NamedType* type) {
|
||||||
auto iter = constructed_types_.insert(name);
|
auto iter = constructed_types_.insert(name);
|
||||||
if (iter.second) {
|
if (iter.second) {
|
||||||
builder_.AST().AddConstructedType(type);
|
builder_.AST().AddConstructedType(type);
|
||||||
|
@ -1539,7 +1540,7 @@ TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::Expression* ParserImpl::MakeNullValue(typ::Type type) {
|
ast::Expression* ParserImpl::MakeNullValue(ast::Type* type) {
|
||||||
// TODO(dneto): Use the no-operands constructor syntax when it becomes
|
// TODO(dneto): Use the no-operands constructor syntax when it becomes
|
||||||
// available in Tint.
|
// available in Tint.
|
||||||
// https://github.com/gpuweb/gpuweb/issues/685
|
// https://github.com/gpuweb/gpuweb/issues/685
|
||||||
|
@ -1550,43 +1551,43 @@ ast::Expression* ParserImpl::MakeNullValue(typ::Type type) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto original_type = type;
|
auto* original_type = type;
|
||||||
type = UnwrapIfNeeded(type);
|
type = UnwrapIfNeeded(type);
|
||||||
|
|
||||||
if (type.ast->Is<ast::Bool>()) {
|
if (type->Is<ast::Bool>()) {
|
||||||
return create<ast::ScalarConstructorExpression>(
|
return create<ast::ScalarConstructorExpression>(
|
||||||
Source{}, create<ast::BoolLiteral>(Source{}, false));
|
Source{}, create<ast::BoolLiteral>(Source{}, false));
|
||||||
}
|
}
|
||||||
if (type.ast->Is<ast::U32>()) {
|
if (type->Is<ast::U32>()) {
|
||||||
return create<ast::ScalarConstructorExpression>(
|
return create<ast::ScalarConstructorExpression>(
|
||||||
Source{}, create<ast::UintLiteral>(Source{}, 0u));
|
Source{}, create<ast::UintLiteral>(Source{}, 0u));
|
||||||
}
|
}
|
||||||
if (type.ast->Is<ast::I32>()) {
|
if (type->Is<ast::I32>()) {
|
||||||
return create<ast::ScalarConstructorExpression>(
|
return create<ast::ScalarConstructorExpression>(
|
||||||
Source{}, create<ast::SintLiteral>(Source{}, 0));
|
Source{}, create<ast::SintLiteral>(Source{}, 0));
|
||||||
}
|
}
|
||||||
if (type.ast->Is<ast::F32>()) {
|
if (type->Is<ast::F32>()) {
|
||||||
return create<ast::ScalarConstructorExpression>(
|
return create<ast::ScalarConstructorExpression>(
|
||||||
Source{}, create<ast::FloatLiteral>(Source{}, 0.0f));
|
Source{}, create<ast::FloatLiteral>(Source{}, 0.0f));
|
||||||
}
|
}
|
||||||
if (type.ast->Is<ast::TypeName>()) {
|
if (type->Is<ast::TypeName>()) {
|
||||||
// TODO(amaiorano): No type constructor for TypeName (yet?)
|
// TODO(amaiorano): No type constructor for TypeName (yet?)
|
||||||
ast::ExpressionList ast_components;
|
ast::ExpressionList ast_components;
|
||||||
return create<ast::TypeConstructorExpression>(Source{}, original_type,
|
return create<ast::TypeConstructorExpression>(Source{}, original_type,
|
||||||
std::move(ast_components));
|
std::move(ast_components));
|
||||||
}
|
}
|
||||||
if (auto vec_ty = typ::As<typ::Vector>(type)) {
|
if (auto* vec_ty = type->As<ast::Vector>()) {
|
||||||
ast::ExpressionList ast_components;
|
ast::ExpressionList ast_components;
|
||||||
for (size_t i = 0; i < vec_ty->size(); ++i) {
|
for (size_t i = 0; i < vec_ty->size(); ++i) {
|
||||||
ast_components.emplace_back(MakeNullValue(typ::Call_type(vec_ty)));
|
ast_components.emplace_back(MakeNullValue(vec_ty->type()));
|
||||||
}
|
}
|
||||||
return create<ast::TypeConstructorExpression>(
|
return create<ast::TypeConstructorExpression>(
|
||||||
Source{}, builder_.ty.MaybeCreateTypename(type),
|
Source{}, builder_.ty.MaybeCreateTypename(type),
|
||||||
std::move(ast_components));
|
std::move(ast_components));
|
||||||
}
|
}
|
||||||
if (auto mat_ty = typ::As<typ::Matrix>(type)) {
|
if (auto* mat_ty = type->As<ast::Matrix>()) {
|
||||||
// Matrix components are columns
|
// Matrix components are columns
|
||||||
auto column_ty = builder_.ty.vec(typ::Call_type(mat_ty), mat_ty->rows());
|
auto column_ty = builder_.ty.vec(mat_ty->type(), mat_ty->rows());
|
||||||
ast::ExpressionList ast_components;
|
ast::ExpressionList ast_components;
|
||||||
for (size_t i = 0; i < mat_ty->columns(); ++i) {
|
for (size_t i = 0; i < mat_ty->columns(); ++i) {
|
||||||
ast_components.emplace_back(MakeNullValue(column_ty));
|
ast_components.emplace_back(MakeNullValue(column_ty));
|
||||||
|
@ -1595,18 +1596,18 @@ ast::Expression* ParserImpl::MakeNullValue(typ::Type type) {
|
||||||
Source{}, builder_.ty.MaybeCreateTypename(type),
|
Source{}, builder_.ty.MaybeCreateTypename(type),
|
||||||
std::move(ast_components));
|
std::move(ast_components));
|
||||||
}
|
}
|
||||||
if (auto arr_ty = typ::As<typ::Array>(type)) {
|
if (auto* arr_ty = type->As<ast::Array>()) {
|
||||||
ast::ExpressionList ast_components;
|
ast::ExpressionList ast_components;
|
||||||
for (size_t i = 0; i < arr_ty->size(); ++i) {
|
for (size_t i = 0; i < arr_ty->size(); ++i) {
|
||||||
ast_components.emplace_back(MakeNullValue(typ::Call_type(arr_ty)));
|
ast_components.emplace_back(MakeNullValue(arr_ty->type()));
|
||||||
}
|
}
|
||||||
return create<ast::TypeConstructorExpression>(
|
return create<ast::TypeConstructorExpression>(
|
||||||
Source{}, builder_.ty.MaybeCreateTypename(original_type),
|
Source{}, builder_.ty.MaybeCreateTypename(original_type),
|
||||||
std::move(ast_components));
|
std::move(ast_components));
|
||||||
}
|
}
|
||||||
if (auto struct_ty = typ::As<typ::Struct>(type)) {
|
if (auto* struct_ty = type->As<ast::Struct>()) {
|
||||||
ast::ExpressionList ast_components;
|
ast::ExpressionList ast_components;
|
||||||
for (auto* member : struct_ty.ast->members()) {
|
for (auto* member : struct_ty->members()) {
|
||||||
ast_components.emplace_back(MakeNullValue(member->type()));
|
ast_components.emplace_back(MakeNullValue(member->type()));
|
||||||
}
|
}
|
||||||
return create<ast::TypeConstructorExpression>(
|
return create<ast::TypeConstructorExpression>(
|
||||||
|
|
|
@ -334,7 +334,7 @@ class ParserImpl : Reader {
|
||||||
/// Creates an AST expression node for the null value for the given type.
|
/// Creates an AST expression node for the null value for the given type.
|
||||||
/// @param type the AST type
|
/// @param type the AST type
|
||||||
/// @returns a new expression
|
/// @returns a new expression
|
||||||
ast::Expression* MakeNullValue(typ::Type type);
|
ast::Expression* MakeNullValue(ast::Type* type);
|
||||||
|
|
||||||
/// Make a typed expression for the null value for the given type.
|
/// Make a typed expression for the null value for the given type.
|
||||||
/// @param type the AST type
|
/// @param type the AST type
|
||||||
|
@ -598,7 +598,7 @@ class ParserImpl : Reader {
|
||||||
/// Adds `type` as a constructed type if it hasn't been added yet.
|
/// Adds `type` as a constructed type if it hasn't been added yet.
|
||||||
/// @param name the type's unique name
|
/// @param name the type's unique name
|
||||||
/// @param type the type to add
|
/// @param type the type to add
|
||||||
void AddConstructedType(Symbol name, typ::Type type);
|
void AddConstructedType(Symbol name, ast::NamedType* type);
|
||||||
|
|
||||||
/// Creates a new `ast::Node` owned by the ProgramBuilder.
|
/// Creates a new `ast::Node` owned by the ProgramBuilder.
|
||||||
/// @param args the arguments to pass to the type constructor
|
/// @param args the arguments to pass to the type constructor
|
||||||
|
|
|
@ -1408,7 +1408,7 @@ TEST_F(SpvModuleScopeVarParserTest, StructInitializer) {
|
||||||
EXPECT_THAT(module_str, HasSubstr(R"(Variable{
|
EXPECT_THAT(module_str, HasSubstr(R"(Variable{
|
||||||
x_200
|
x_200
|
||||||
private
|
private
|
||||||
__struct_S
|
__type_name_S
|
||||||
{
|
{
|
||||||
TypeConstructor[not set]{
|
TypeConstructor[not set]{
|
||||||
__type_name_S
|
__type_name_S
|
||||||
|
@ -1437,7 +1437,7 @@ TEST_F(SpvModuleScopeVarParserTest, StructNullInitializer) {
|
||||||
EXPECT_THAT(module_str, HasSubstr(R"(Variable{
|
EXPECT_THAT(module_str, HasSubstr(R"(Variable{
|
||||||
x_200
|
x_200
|
||||||
private
|
private
|
||||||
__struct_S
|
__type_name_S
|
||||||
{
|
{
|
||||||
TypeConstructor[not set]{
|
TypeConstructor[not set]{
|
||||||
__type_name_S
|
__type_name_S
|
||||||
|
@ -1466,7 +1466,7 @@ TEST_F(SpvModuleScopeVarParserTest, StructUndefInitializer) {
|
||||||
EXPECT_THAT(module_str, HasSubstr(R"(Variable{
|
EXPECT_THAT(module_str, HasSubstr(R"(Variable{
|
||||||
x_200
|
x_200
|
||||||
private
|
private
|
||||||
__struct_S
|
__type_name_S
|
||||||
{
|
{
|
||||||
TypeConstructor[not set]{
|
TypeConstructor[not set]{
|
||||||
__type_name_S
|
__type_name_S
|
||||||
|
@ -1553,7 +1553,7 @@ TEST_F(SpvModuleScopeVarParserTest, DescriptorGroupDecoration_Valid) {
|
||||||
}
|
}
|
||||||
myvar
|
myvar
|
||||||
storage
|
storage
|
||||||
__access_control_read_write__struct_S
|
__access_control_read_write__type_name_S
|
||||||
})"))
|
})"))
|
||||||
<< module_str;
|
<< module_str;
|
||||||
}
|
}
|
||||||
|
@ -1607,7 +1607,7 @@ TEST_F(SpvModuleScopeVarParserTest, BindingDecoration_Valid) {
|
||||||
}
|
}
|
||||||
myvar
|
myvar
|
||||||
storage
|
storage
|
||||||
__access_control_read_write__struct_S
|
__access_control_read_write__type_name_S
|
||||||
})"))
|
})"))
|
||||||
<< module_str;
|
<< module_str;
|
||||||
}
|
}
|
||||||
|
@ -1664,7 +1664,7 @@ TEST_F(SpvModuleScopeVarParserTest,
|
||||||
Variable{
|
Variable{
|
||||||
myvar
|
myvar
|
||||||
storage
|
storage
|
||||||
__access_control_read_write__struct_S
|
__access_control_read_write__type_name_S
|
||||||
}
|
}
|
||||||
)")) << module_str;
|
)")) << module_str;
|
||||||
}
|
}
|
||||||
|
@ -1693,7 +1693,7 @@ TEST_F(SpvModuleScopeVarParserTest, ColMajorDecoration_Dropped) {
|
||||||
Variable{
|
Variable{
|
||||||
myvar
|
myvar
|
||||||
storage
|
storage
|
||||||
__access_control_read_write__struct_S
|
__access_control_read_write__type_name_S
|
||||||
}
|
}
|
||||||
})")) << module_str;
|
})")) << module_str;
|
||||||
}
|
}
|
||||||
|
@ -1722,7 +1722,7 @@ TEST_F(SpvModuleScopeVarParserTest, MatrixStrideDecoration_Dropped) {
|
||||||
Variable{
|
Variable{
|
||||||
myvar
|
myvar
|
||||||
storage
|
storage
|
||||||
__access_control_read_write__struct_S
|
__access_control_read_write__type_name_S
|
||||||
}
|
}
|
||||||
})")) << module_str;
|
})")) << module_str;
|
||||||
}
|
}
|
||||||
|
@ -1772,7 +1772,7 @@ TEST_F(SpvModuleScopeVarParserTest, StorageBuffer_NonWritable_AllMembers) {
|
||||||
Variable{
|
Variable{
|
||||||
myvar
|
myvar
|
||||||
storage
|
storage
|
||||||
__access_control_read_only__struct_S
|
__access_control_read_only__type_name_S
|
||||||
}
|
}
|
||||||
})")) << module_str;
|
})")) << module_str;
|
||||||
}
|
}
|
||||||
|
@ -1801,7 +1801,7 @@ TEST_F(SpvModuleScopeVarParserTest, StorageBuffer_NonWritable_NotAllMembers) {
|
||||||
Variable{
|
Variable{
|
||||||
myvar
|
myvar
|
||||||
storage
|
storage
|
||||||
__access_control_read_write__struct_S
|
__access_control_read_write__type_name_S
|
||||||
}
|
}
|
||||||
})")) << module_str;
|
})")) << module_str;
|
||||||
}
|
}
|
||||||
|
@ -1833,7 +1833,7 @@ TEST_F(
|
||||||
Variable{
|
Variable{
|
||||||
myvar
|
myvar
|
||||||
storage
|
storage
|
||||||
__access_control_read_write__struct_S
|
__access_control_read_write__type_name_S
|
||||||
}
|
}
|
||||||
})")) << module_str;
|
})")) << module_str;
|
||||||
}
|
}
|
||||||
|
|
|
@ -401,7 +401,7 @@ Expect<bool> ParserImpl::expect_global_decl() {
|
||||||
if (!expect("type alias", Token::Type::kSemicolon))
|
if (!expect("type alias", Token::Type::kSemicolon))
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
|
|
||||||
builder_.AST().AddConstructedType(ta.value);
|
builder_.AST().AddConstructedType(const_cast<ast::Alias*>(ta.value.ast));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,7 +415,8 @@ Expect<bool> ParserImpl::expect_global_decl() {
|
||||||
|
|
||||||
register_constructed(
|
register_constructed(
|
||||||
builder_.Symbols().NameFor(str.value->impl()->name()), str.value);
|
builder_.Symbols().NameFor(str.value->impl()->name()), str.value);
|
||||||
builder_.AST().AddConstructedType(str.value);
|
builder_.AST().AddConstructedType(
|
||||||
|
const_cast<ast::Struct*>(str.value.ast));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,7 +562,8 @@ Maybe<ParserImpl::VarDeclInfo> ParserImpl::variable_decl() {
|
||||||
if (decl.errored)
|
if (decl.errored)
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
|
|
||||||
if (decl->type->UnwrapAll()->is_handle()) {
|
if ((decl->type.sem && decl->type.sem->UnwrapAll()->is_handle()) ||
|
||||||
|
(decl->type.ast && decl->type.ast->UnwrapAll()->is_handle())) {
|
||||||
// handle types implicitly have the `UniformConstant` storage class.
|
// handle types implicitly have the `UniformConstant` storage class.
|
||||||
if (explicit_sc.matched) {
|
if (explicit_sc.matched) {
|
||||||
return add_error(
|
return add_error(
|
||||||
|
@ -960,7 +962,7 @@ Maybe<ast::StorageClass> ParserImpl::variable_storage_decoration() {
|
||||||
|
|
||||||
// type_alias
|
// type_alias
|
||||||
// : TYPE IDENT EQUAL type_decl
|
// : TYPE IDENT EQUAL type_decl
|
||||||
Maybe<typ::Type> ParserImpl::type_alias() {
|
Maybe<typ::Alias> ParserImpl::type_alias() {
|
||||||
auto t = peek();
|
auto t = peek();
|
||||||
if (!t.IsType())
|
if (!t.IsType())
|
||||||
return Failure::kNoMatch;
|
return Failure::kNoMatch;
|
||||||
|
@ -1234,7 +1236,7 @@ Expect<ast::StorageClass> ParserImpl::expect_storage_class(
|
||||||
|
|
||||||
// struct_decl
|
// struct_decl
|
||||||
// : struct_decoration_decl* STRUCT IDENT struct_body_decl
|
// : struct_decoration_decl* STRUCT IDENT struct_body_decl
|
||||||
Maybe<sem::StructType*> ParserImpl::struct_decl(ast::DecorationList& decos) {
|
Maybe<typ::Struct> ParserImpl::struct_decl(ast::DecorationList& decos) {
|
||||||
auto t = peek();
|
auto t = peek();
|
||||||
auto source = t.source();
|
auto source = t.source();
|
||||||
|
|
||||||
|
@ -1250,8 +1252,9 @@ Maybe<sem::StructType*> ParserImpl::struct_decl(ast::DecorationList& decos) {
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
|
|
||||||
auto sym = builder_.Symbols().Register(name.value);
|
auto sym = builder_.Symbols().Register(name.value);
|
||||||
return create<sem::StructType>(create<ast::Struct>(
|
auto* str =
|
||||||
source, sym, std::move(body.value), std::move(decos)));
|
create<ast::Struct>(source, sym, std::move(body.value), std::move(decos));
|
||||||
|
return typ::Struct{str, create<sem::StructType>(str)};
|
||||||
}
|
}
|
||||||
|
|
||||||
// struct_body_decl
|
// struct_body_decl
|
||||||
|
|
|
@ -398,7 +398,7 @@ class ParserImpl {
|
||||||
Maybe<ast::StorageClass> variable_storage_decoration();
|
Maybe<ast::StorageClass> variable_storage_decoration();
|
||||||
/// Parses a `type_alias` grammar element
|
/// Parses a `type_alias` grammar element
|
||||||
/// @returns the type alias or nullptr on error
|
/// @returns the type alias or nullptr on error
|
||||||
Maybe<typ::Type> type_alias();
|
Maybe<typ::Alias> type_alias();
|
||||||
/// Parses a `type_decl` grammar element
|
/// Parses a `type_decl` grammar element
|
||||||
/// @returns the parsed Type or nullptr if none matched.
|
/// @returns the parsed Type or nullptr if none matched.
|
||||||
Maybe<typ::Type> type_decl();
|
Maybe<typ::Type> type_decl();
|
||||||
|
@ -415,7 +415,7 @@ class ParserImpl {
|
||||||
/// `struct_decoration_decl*` provided as `decos`.
|
/// `struct_decoration_decl*` provided as `decos`.
|
||||||
/// @returns the struct type or nullptr on error
|
/// @returns the struct type or nullptr on error
|
||||||
/// @param decos the list of decorations for the struct declaration.
|
/// @param decos the list of decorations for the struct declaration.
|
||||||
Maybe<sem::StructType*> struct_decl(ast::DecorationList& decos);
|
Maybe<typ::Struct> struct_decl(ast::DecorationList& decos);
|
||||||
/// Parses a `struct_body_decl` grammar element, erroring on parse failure.
|
/// Parses a `struct_body_decl` grammar element, erroring on parse failure.
|
||||||
/// @returns the struct members
|
/// @returns the struct members
|
||||||
Expect<ast::StructMemberList> expect_struct_body_decl();
|
Expect<ast::StructMemberList> expect_struct_body_decl();
|
||||||
|
|
|
@ -28,8 +28,8 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl) {
|
||||||
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
||||||
|
|
||||||
auto* t = e->As<ast::TypeConstructorExpression>();
|
auto* t = e->As<ast::TypeConstructorExpression>();
|
||||||
ASSERT_TRUE(t->type()->Is<sem::Vector>());
|
ASSERT_TRUE(t->type()->Is<ast::Vector>());
|
||||||
EXPECT_EQ(t->type()->As<sem::Vector>()->size(), 2u);
|
EXPECT_EQ(t->type()->As<ast::Vector>()->size(), 2u);
|
||||||
|
|
||||||
ASSERT_EQ(t->values().size(), 2u);
|
ASSERT_EQ(t->values().size(), 2u);
|
||||||
auto& v = t->values();
|
auto& v = t->values();
|
||||||
|
@ -56,8 +56,8 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl_Empty) {
|
||||||
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
||||||
|
|
||||||
auto* t = e->As<ast::TypeConstructorExpression>();
|
auto* t = e->As<ast::TypeConstructorExpression>();
|
||||||
ASSERT_TRUE(t->type()->Is<sem::Vector>());
|
ASSERT_TRUE(t->type()->Is<ast::Vector>());
|
||||||
EXPECT_EQ(t->type()->As<sem::Vector>()->size(), 2u);
|
EXPECT_EQ(t->type()->As<ast::Vector>()->size(), 2u);
|
||||||
|
|
||||||
ASSERT_EQ(t->values().size(), 0u);
|
ASSERT_EQ(t->values().size(), 0u);
|
||||||
}
|
}
|
||||||
|
@ -71,8 +71,8 @@ TEST_F(ParserImplTest, ConstExpr_TypeDecl_TrailingComma) {
|
||||||
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
||||||
|
|
||||||
auto* t = e->As<ast::TypeConstructorExpression>();
|
auto* t = e->As<ast::TypeConstructorExpression>();
|
||||||
ASSERT_TRUE(t->type()->Is<sem::Vector>());
|
ASSERT_TRUE(t->type()->Is<ast::Vector>());
|
||||||
EXPECT_EQ(t->type()->As<sem::Vector>()->size(), 2u);
|
EXPECT_EQ(t->type()->As<ast::Vector>()->size(), 2u);
|
||||||
|
|
||||||
ASSERT_EQ(t->values().size(), 2u);
|
ASSERT_EQ(t->values().size(), 2u);
|
||||||
ASSERT_TRUE(t->values()[0]->Is<ast::ScalarConstructorExpression>());
|
ASSERT_TRUE(t->values()[0]->Is<ast::ScalarConstructorExpression>());
|
||||||
|
|
|
@ -34,14 +34,14 @@ TEST_F(ParserImplTest, FunctionDecl) {
|
||||||
|
|
||||||
EXPECT_EQ(f->symbol(), p->builder().Symbols().Get("main"));
|
EXPECT_EQ(f->symbol(), p->builder().Symbols().Get("main"));
|
||||||
ASSERT_NE(f->return_type(), nullptr);
|
ASSERT_NE(f->return_type(), nullptr);
|
||||||
EXPECT_TRUE(f->return_type()->Is<sem::Void>());
|
EXPECT_TRUE(f->return_type()->Is<ast::Void>());
|
||||||
|
|
||||||
ASSERT_EQ(f->params().size(), 2u);
|
ASSERT_EQ(f->params().size(), 2u);
|
||||||
EXPECT_EQ(f->params()[0]->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(f->params()[0]->symbol(), p->builder().Symbols().Get("a"));
|
||||||
EXPECT_EQ(f->params()[1]->symbol(), p->builder().Symbols().Get("b"));
|
EXPECT_EQ(f->params()[1]->symbol(), p->builder().Symbols().Get("b"));
|
||||||
|
|
||||||
ASSERT_NE(f->return_type(), nullptr);
|
ASSERT_NE(f->return_type(), nullptr);
|
||||||
EXPECT_TRUE(f->return_type()->Is<sem::Void>());
|
EXPECT_TRUE(f->return_type()->Is<ast::Void>());
|
||||||
|
|
||||||
auto* body = f->body();
|
auto* body = f->body();
|
||||||
ASSERT_EQ(body->size(), 1u);
|
ASSERT_EQ(body->size(), 1u);
|
||||||
|
@ -62,10 +62,8 @@ TEST_F(ParserImplTest, FunctionDecl_DecorationList) {
|
||||||
|
|
||||||
EXPECT_EQ(f->symbol(), p->builder().Symbols().Get("main"));
|
EXPECT_EQ(f->symbol(), p->builder().Symbols().Get("main"));
|
||||||
ASSERT_NE(f->return_type(), nullptr);
|
ASSERT_NE(f->return_type(), nullptr);
|
||||||
EXPECT_TRUE(f->return_type()->Is<sem::Void>());
|
EXPECT_TRUE(f->return_type()->Is<ast::Void>());
|
||||||
ASSERT_EQ(f->params().size(), 0u);
|
ASSERT_EQ(f->params().size(), 0u);
|
||||||
ASSERT_NE(f->return_type(), nullptr);
|
|
||||||
EXPECT_TRUE(f->return_type()->Is<sem::Void>());
|
|
||||||
|
|
||||||
auto& decorations = f->decorations();
|
auto& decorations = f->decorations();
|
||||||
ASSERT_EQ(decorations.size(), 1u);
|
ASSERT_EQ(decorations.size(), 1u);
|
||||||
|
@ -100,10 +98,8 @@ fn main() { return; })");
|
||||||
|
|
||||||
EXPECT_EQ(f->symbol(), p->builder().Symbols().Get("main"));
|
EXPECT_EQ(f->symbol(), p->builder().Symbols().Get("main"));
|
||||||
ASSERT_NE(f->return_type(), nullptr);
|
ASSERT_NE(f->return_type(), nullptr);
|
||||||
EXPECT_TRUE(f->return_type()->Is<sem::Void>());
|
EXPECT_TRUE(f->return_type()->Is<ast::Void>());
|
||||||
ASSERT_EQ(f->params().size(), 0u);
|
ASSERT_EQ(f->params().size(), 0u);
|
||||||
ASSERT_NE(f->return_type(), nullptr);
|
|
||||||
EXPECT_TRUE(f->return_type()->Is<sem::Void>());
|
|
||||||
|
|
||||||
auto& decorations = f->decorations();
|
auto& decorations = f->decorations();
|
||||||
ASSERT_EQ(decorations.size(), 2u);
|
ASSERT_EQ(decorations.size(), 2u);
|
||||||
|
@ -145,10 +141,8 @@ fn main() { return; })");
|
||||||
|
|
||||||
EXPECT_EQ(f->symbol(), p->builder().Symbols().Get("main"));
|
EXPECT_EQ(f->symbol(), p->builder().Symbols().Get("main"));
|
||||||
ASSERT_NE(f->return_type(), nullptr);
|
ASSERT_NE(f->return_type(), nullptr);
|
||||||
EXPECT_TRUE(f->return_type()->Is<sem::Void>());
|
EXPECT_TRUE(f->return_type()->Is<ast::Void>());
|
||||||
ASSERT_EQ(f->params().size(), 0u);
|
ASSERT_EQ(f->params().size(), 0u);
|
||||||
ASSERT_NE(f->return_type(), nullptr);
|
|
||||||
EXPECT_TRUE(f->return_type()->Is<sem::Void>());
|
|
||||||
|
|
||||||
auto& decos = f->decorations();
|
auto& decos = f->decorations();
|
||||||
ASSERT_EQ(decos.size(), 2u);
|
ASSERT_EQ(decos.size(), 2u);
|
||||||
|
@ -187,7 +181,7 @@ TEST_F(ParserImplTest, FunctionDecl_ReturnTypeDecorationList) {
|
||||||
|
|
||||||
EXPECT_EQ(f->symbol(), p->builder().Symbols().Get("main"));
|
EXPECT_EQ(f->symbol(), p->builder().Symbols().Get("main"));
|
||||||
ASSERT_NE(f->return_type(), nullptr);
|
ASSERT_NE(f->return_type(), nullptr);
|
||||||
EXPECT_TRUE(f->return_type()->Is<sem::F32>());
|
EXPECT_TRUE(f->return_type()->Is<ast::F32>());
|
||||||
ASSERT_EQ(f->params().size(), 0u);
|
ASSERT_EQ(f->params().size(), 0u);
|
||||||
|
|
||||||
auto& decorations = f->decorations();
|
auto& decorations = f->decorations();
|
||||||
|
|
|
@ -33,8 +33,8 @@ TEST_F(ParserImplTest, GlobalConstantDecl) {
|
||||||
|
|
||||||
EXPECT_TRUE(e->is_const());
|
EXPECT_TRUE(e->is_const());
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
ASSERT_NE(e->declared_type(), nullptr);
|
ASSERT_NE(e->type(), nullptr);
|
||||||
EXPECT_TRUE(e->declared_type()->Is<sem::F32>());
|
EXPECT_TRUE(e->type()->Is<ast::F32>());
|
||||||
|
|
||||||
EXPECT_EQ(e->source().range.begin.line, 1u);
|
EXPECT_EQ(e->source().range.begin.line, 1u);
|
||||||
EXPECT_EQ(e->source().range.begin.column, 5u);
|
EXPECT_EQ(e->source().range.begin.column, 5u);
|
||||||
|
@ -114,8 +114,8 @@ TEST_F(ParserImplTest, GlobalConstantDec_Override_WithId) {
|
||||||
|
|
||||||
EXPECT_TRUE(e->is_const());
|
EXPECT_TRUE(e->is_const());
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
ASSERT_NE(e->declared_type(), nullptr);
|
ASSERT_NE(e->type(), nullptr);
|
||||||
EXPECT_TRUE(e->declared_type()->Is<sem::F32>());
|
EXPECT_TRUE(e->type()->Is<ast::F32>());
|
||||||
|
|
||||||
EXPECT_EQ(e->source().range.begin.line, 1u);
|
EXPECT_EQ(e->source().range.begin.line, 1u);
|
||||||
EXPECT_EQ(e->source().range.begin.column, 21u);
|
EXPECT_EQ(e->source().range.begin.column, 21u);
|
||||||
|
|
|
@ -84,10 +84,10 @@ TEST_F(ParserImplTest, GlobalDecl_TypeAlias) {
|
||||||
|
|
||||||
auto program = p->program();
|
auto program = p->program();
|
||||||
ASSERT_EQ(program.AST().ConstructedTypes().size(), 1u);
|
ASSERT_EQ(program.AST().ConstructedTypes().size(), 1u);
|
||||||
ASSERT_TRUE(program.AST().ConstructedTypes()[0]->Is<sem::Alias>());
|
ASSERT_TRUE(program.AST().ConstructedTypes()[0]->Is<ast::Alias>());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
program.Symbols().NameFor(
|
program.Symbols().NameFor(
|
||||||
program.AST().ConstructedTypes()[0]->As<sem::Alias>()->symbol()),
|
program.AST().ConstructedTypes()[0]->As<ast::Alias>()->symbol()),
|
||||||
"A");
|
"A");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,14 +102,16 @@ type B = A;)");
|
||||||
|
|
||||||
auto program = p->program();
|
auto program = p->program();
|
||||||
ASSERT_EQ(program.AST().ConstructedTypes().size(), 2u);
|
ASSERT_EQ(program.AST().ConstructedTypes().size(), 2u);
|
||||||
ASSERT_TRUE(program.AST().ConstructedTypes()[0]->Is<sem::StructType>());
|
ASSERT_TRUE(program.AST().ConstructedTypes()[0]->Is<ast::Struct>());
|
||||||
auto* str = program.AST().ConstructedTypes()[0]->As<sem::StructType>();
|
auto* str = program.AST().ConstructedTypes()[0]->As<ast::Struct>();
|
||||||
EXPECT_EQ(str->impl()->name(), program.Symbols().Get("A"));
|
EXPECT_EQ(str->name(), program.Symbols().Get("A"));
|
||||||
|
|
||||||
ASSERT_TRUE(program.AST().ConstructedTypes()[1]->Is<sem::Alias>());
|
ASSERT_TRUE(program.AST().ConstructedTypes()[1]->Is<ast::Alias>());
|
||||||
auto* alias = program.AST().ConstructedTypes()[1]->As<sem::Alias>();
|
auto* alias = program.AST().ConstructedTypes()[1]->As<ast::Alias>();
|
||||||
EXPECT_EQ(alias->symbol(), program.Symbols().Get("B"));
|
EXPECT_EQ(alias->symbol(), program.Symbols().Get("B"));
|
||||||
EXPECT_EQ(alias->type(), str);
|
auto* tn = alias->type()->As<ast::TypeName>();
|
||||||
|
EXPECT_NE(tn, nullptr);
|
||||||
|
EXPECT_EQ(tn->name(), str->name());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalDecl_TypeAlias_Invalid) {
|
TEST_F(ParserImplTest, GlobalDecl_TypeAlias_Invalid) {
|
||||||
|
@ -163,13 +165,13 @@ TEST_F(ParserImplTest, GlobalDecl_ParsesStruct) {
|
||||||
auto program = p->program();
|
auto program = p->program();
|
||||||
ASSERT_EQ(program.AST().ConstructedTypes().size(), 1u);
|
ASSERT_EQ(program.AST().ConstructedTypes().size(), 1u);
|
||||||
|
|
||||||
auto t = program.AST().ConstructedTypes()[0];
|
auto* t = program.AST().ConstructedTypes()[0];
|
||||||
ASSERT_NE(t, nullptr);
|
ASSERT_NE(t, nullptr);
|
||||||
ASSERT_TRUE(t->Is<sem::StructType>());
|
ASSERT_TRUE(t->Is<ast::Struct>());
|
||||||
|
|
||||||
auto* str = t->As<sem::StructType>();
|
auto* str = t->As<ast::Struct>();
|
||||||
EXPECT_EQ(str->impl()->name(), program.Symbols().Get("A"));
|
EXPECT_EQ(str->name(), program.Symbols().Get("A"));
|
||||||
EXPECT_EQ(str->impl()->members().size(), 2u);
|
EXPECT_EQ(str->members().size(), 2u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalDecl_Struct_WithStride) {
|
TEST_F(ParserImplTest, GlobalDecl_Struct_WithStride) {
|
||||||
|
@ -181,18 +183,18 @@ TEST_F(ParserImplTest, GlobalDecl_Struct_WithStride) {
|
||||||
auto program = p->program();
|
auto program = p->program();
|
||||||
ASSERT_EQ(program.AST().ConstructedTypes().size(), 1u);
|
ASSERT_EQ(program.AST().ConstructedTypes().size(), 1u);
|
||||||
|
|
||||||
auto t = program.AST().ConstructedTypes()[0];
|
auto* t = program.AST().ConstructedTypes()[0];
|
||||||
ASSERT_NE(t, nullptr);
|
ASSERT_NE(t, nullptr);
|
||||||
ASSERT_TRUE(t->Is<sem::StructType>());
|
ASSERT_TRUE(t->Is<ast::Struct>());
|
||||||
|
|
||||||
auto* str = t->As<sem::StructType>();
|
auto* str = t->As<ast::Struct>();
|
||||||
EXPECT_EQ(str->impl()->name(), program.Symbols().Get("A"));
|
EXPECT_EQ(str->name(), program.Symbols().Get("A"));
|
||||||
EXPECT_EQ(str->impl()->members().size(), 1u);
|
EXPECT_EQ(str->members().size(), 1u);
|
||||||
EXPECT_FALSE(str->IsBlockDecorated());
|
EXPECT_FALSE(str->IsBlockDecorated());
|
||||||
|
|
||||||
const auto ty = str->impl()->members()[0]->type();
|
const auto* ty = str->members()[0]->type();
|
||||||
ASSERT_TRUE(ty->Is<sem::ArrayType>());
|
ASSERT_TRUE(ty->Is<ast::Array>());
|
||||||
const auto* arr = ty->As<sem::ArrayType>();
|
const auto* arr = ty->As<ast::Array>();
|
||||||
|
|
||||||
ASSERT_EQ(arr->decorations().size(), 1u);
|
ASSERT_EQ(arr->decorations().size(), 1u);
|
||||||
auto* stride = arr->decorations()[0];
|
auto* stride = arr->decorations()[0];
|
||||||
|
@ -208,13 +210,13 @@ TEST_F(ParserImplTest, GlobalDecl_Struct_WithDecoration) {
|
||||||
auto program = p->program();
|
auto program = p->program();
|
||||||
ASSERT_EQ(program.AST().ConstructedTypes().size(), 1u);
|
ASSERT_EQ(program.AST().ConstructedTypes().size(), 1u);
|
||||||
|
|
||||||
auto t = program.AST().ConstructedTypes()[0];
|
auto* t = program.AST().ConstructedTypes()[0];
|
||||||
ASSERT_NE(t, nullptr);
|
ASSERT_NE(t, nullptr);
|
||||||
ASSERT_TRUE(t->Is<sem::StructType>());
|
ASSERT_TRUE(t->Is<ast::Struct>());
|
||||||
|
|
||||||
auto* str = t->As<sem::StructType>();
|
auto* str = t->As<ast::Struct>();
|
||||||
EXPECT_EQ(str->impl()->name(), program.Symbols().Get("A"));
|
EXPECT_EQ(str->name(), program.Symbols().Get("A"));
|
||||||
EXPECT_EQ(str->impl()->members().size(), 1u);
|
EXPECT_EQ(str->members().size(), 1u);
|
||||||
EXPECT_TRUE(str->IsBlockDecorated());
|
EXPECT_TRUE(str->IsBlockDecorated());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithoutConstructor) {
|
||||||
ASSERT_NE(e.value, nullptr);
|
ASSERT_NE(e.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
EXPECT_TRUE(e->declared_type()->Is<sem::F32>());
|
EXPECT_TRUE(e->type()->Is<ast::F32>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kPrivate);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kPrivate);
|
||||||
|
|
||||||
EXPECT_EQ(e->source().range.begin.line, 1u);
|
EXPECT_EQ(e->source().range.begin.line, 1u);
|
||||||
|
@ -54,7 +54,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) {
|
||||||
ASSERT_NE(e.value, nullptr);
|
ASSERT_NE(e.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
EXPECT_TRUE(e->declared_type()->Is<sem::F32>());
|
EXPECT_TRUE(e->type()->Is<ast::F32>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kPrivate);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kPrivate);
|
||||||
|
|
||||||
EXPECT_EQ(e->source().range.begin.line, 1u);
|
EXPECT_EQ(e->source().range.begin.line, 1u);
|
||||||
|
@ -79,8 +79,8 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
|
||||||
ASSERT_NE(e.value, nullptr);
|
ASSERT_NE(e.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
ASSERT_NE(e->declared_type(), nullptr);
|
ASSERT_NE(e->type(), nullptr);
|
||||||
EXPECT_TRUE(e->declared_type()->Is<sem::F32>());
|
EXPECT_TRUE(e->type()->Is<ast::F32>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniform);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniform);
|
||||||
|
|
||||||
EXPECT_EQ(e->source().range.begin.line, 1u);
|
EXPECT_EQ(e->source().range.begin.line, 1u);
|
||||||
|
@ -109,8 +109,8 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration_MulitpleGroups) {
|
||||||
ASSERT_NE(e.value, nullptr);
|
ASSERT_NE(e.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
ASSERT_NE(e->declared_type(), nullptr);
|
ASSERT_NE(e->type(), nullptr);
|
||||||
EXPECT_TRUE(e->declared_type()->Is<sem::F32>());
|
EXPECT_TRUE(e->type()->Is<ast::F32>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniform);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniform);
|
||||||
|
|
||||||
EXPECT_EQ(e->source().range.begin.line, 1u);
|
EXPECT_EQ(e->source().range.begin.line, 1u);
|
||||||
|
@ -180,7 +180,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_SamplerImplicitStorageClass) {
|
||||||
ASSERT_NE(e.value, nullptr);
|
ASSERT_NE(e.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("s"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("s"));
|
||||||
EXPECT_TRUE(e->declared_type()->Is<sem::Sampler>());
|
EXPECT_TRUE(e->type()->Is<ast::Sampler>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniformConstant);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniformConstant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_TextureImplicitStorageClass) {
|
||||||
ASSERT_NE(e.value, nullptr);
|
ASSERT_NE(e.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("s"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("s"));
|
||||||
EXPECT_TRUE(e->declared_type()->UnwrapAll()->Is<sem::Texture>());
|
EXPECT_TRUE(e->type()->UnwrapAll()->Is<ast::Texture>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniformConstant);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniformConstant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_StorageClassIn_Deprecated) {
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
ASSERT_FALSE(p->has_error()) << p->error();
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
EXPECT_TRUE(e->declared_type()->Is<sem::F32>());
|
EXPECT_TRUE(e->type()->Is<ast::F32>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kInput);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kInput);
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
|
@ -231,7 +231,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_StorageClassOut_Deprecated) {
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
ASSERT_FALSE(p->has_error()) << p->error();
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("a"));
|
||||||
EXPECT_TRUE(e->declared_type()->Is<sem::F32>());
|
EXPECT_TRUE(e->type()->Is<ast::F32>());
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kOutput);
|
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kOutput);
|
||||||
|
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
|
|
|
@ -22,15 +22,13 @@ namespace {
|
||||||
TEST_F(ParserImplTest, ParamList_Single) {
|
TEST_F(ParserImplTest, ParamList_Single) {
|
||||||
auto p = parser("a : i32");
|
auto p = parser("a : i32");
|
||||||
|
|
||||||
auto* i32 = p->builder().create<sem::I32>();
|
|
||||||
|
|
||||||
auto e = p->expect_param_list();
|
auto e = p->expect_param_list();
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
ASSERT_FALSE(p->has_error()) << p->error();
|
||||||
ASSERT_FALSE(e.errored);
|
ASSERT_FALSE(e.errored);
|
||||||
EXPECT_EQ(e.value.size(), 1u);
|
EXPECT_EQ(e.value.size(), 1u);
|
||||||
|
|
||||||
EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("a"));
|
||||||
EXPECT_EQ(e.value[0]->declared_type(), i32);
|
EXPECT_TRUE(e.value[0]->type()->Is<ast::I32>());
|
||||||
EXPECT_TRUE(e.value[0]->is_const());
|
EXPECT_TRUE(e.value[0]->is_const());
|
||||||
|
|
||||||
ASSERT_EQ(e.value[0]->source().range.begin.line, 1u);
|
ASSERT_EQ(e.value[0]->source().range.begin.line, 1u);
|
||||||
|
@ -42,17 +40,13 @@ TEST_F(ParserImplTest, ParamList_Single) {
|
||||||
TEST_F(ParserImplTest, ParamList_Multiple) {
|
TEST_F(ParserImplTest, ParamList_Multiple) {
|
||||||
auto p = parser("a : i32, b: f32, c: vec2<f32>");
|
auto p = parser("a : i32, b: f32, c: vec2<f32>");
|
||||||
|
|
||||||
auto* i32 = p->builder().create<sem::I32>();
|
|
||||||
auto* f32 = p->builder().create<sem::F32>();
|
|
||||||
auto* vec2 = p->builder().create<sem::Vector>(f32, 2);
|
|
||||||
|
|
||||||
auto e = p->expect_param_list();
|
auto e = p->expect_param_list();
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
ASSERT_FALSE(p->has_error()) << p->error();
|
||||||
ASSERT_FALSE(e.errored);
|
ASSERT_FALSE(e.errored);
|
||||||
EXPECT_EQ(e.value.size(), 3u);
|
EXPECT_EQ(e.value.size(), 3u);
|
||||||
|
|
||||||
EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("a"));
|
EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("a"));
|
||||||
EXPECT_EQ(e.value[0]->declared_type(), i32);
|
EXPECT_TRUE(e.value[0]->type()->Is<ast::I32>());
|
||||||
EXPECT_TRUE(e.value[0]->is_const());
|
EXPECT_TRUE(e.value[0]->is_const());
|
||||||
|
|
||||||
ASSERT_EQ(e.value[0]->source().range.begin.line, 1u);
|
ASSERT_EQ(e.value[0]->source().range.begin.line, 1u);
|
||||||
|
@ -61,7 +55,7 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
|
||||||
ASSERT_EQ(e.value[0]->source().range.end.column, 2u);
|
ASSERT_EQ(e.value[0]->source().range.end.column, 2u);
|
||||||
|
|
||||||
EXPECT_EQ(e.value[1]->symbol(), p->builder().Symbols().Get("b"));
|
EXPECT_EQ(e.value[1]->symbol(), p->builder().Symbols().Get("b"));
|
||||||
EXPECT_EQ(e.value[1]->declared_type(), f32);
|
EXPECT_TRUE(e.value[1]->type()->Is<ast::F32>());
|
||||||
EXPECT_TRUE(e.value[1]->is_const());
|
EXPECT_TRUE(e.value[1]->is_const());
|
||||||
|
|
||||||
ASSERT_EQ(e.value[1]->source().range.begin.line, 1u);
|
ASSERT_EQ(e.value[1]->source().range.begin.line, 1u);
|
||||||
|
@ -70,7 +64,9 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
|
||||||
ASSERT_EQ(e.value[1]->source().range.end.column, 11u);
|
ASSERT_EQ(e.value[1]->source().range.end.column, 11u);
|
||||||
|
|
||||||
EXPECT_EQ(e.value[2]->symbol(), p->builder().Symbols().Get("c"));
|
EXPECT_EQ(e.value[2]->symbol(), p->builder().Symbols().Get("c"));
|
||||||
EXPECT_EQ(e.value[2]->declared_type(), vec2);
|
ASSERT_TRUE(e.value[2]->type()->Is<ast::Vector>());
|
||||||
|
ASSERT_TRUE(e.value[2]->type()->As<ast::Vector>()->type()->Is<ast::F32>());
|
||||||
|
EXPECT_EQ(e.value[2]->type()->As<ast::Vector>()->size(), 2u);
|
||||||
EXPECT_TRUE(e.value[2]->is_const());
|
EXPECT_TRUE(e.value[2]->is_const());
|
||||||
|
|
||||||
ASSERT_EQ(e.value[2]->source().range.begin.line, 1u);
|
ASSERT_EQ(e.value[2]->source().range.begin.line, 1u);
|
||||||
|
@ -100,16 +96,15 @@ TEST_F(ParserImplTest, ParamList_Decorations) {
|
||||||
"[[builtin(position)]] coord : vec4<f32>, "
|
"[[builtin(position)]] coord : vec4<f32>, "
|
||||||
"[[location(1)]] loc1 : f32");
|
"[[location(1)]] loc1 : f32");
|
||||||
|
|
||||||
auto* f32 = p->builder().create<sem::F32>();
|
|
||||||
auto* vec4 = p->builder().create<sem::Vector>(f32, 4);
|
|
||||||
|
|
||||||
auto e = p->expect_param_list();
|
auto e = p->expect_param_list();
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
ASSERT_FALSE(p->has_error()) << p->error();
|
||||||
ASSERT_FALSE(e.errored);
|
ASSERT_FALSE(e.errored);
|
||||||
ASSERT_EQ(e.value.size(), 2u);
|
ASSERT_EQ(e.value.size(), 2u);
|
||||||
|
|
||||||
EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("coord"));
|
EXPECT_EQ(e.value[0]->symbol(), p->builder().Symbols().Get("coord"));
|
||||||
EXPECT_EQ(e.value[0]->declared_type(), vec4);
|
ASSERT_TRUE(e.value[0]->type()->Is<ast::Vector>());
|
||||||
|
EXPECT_TRUE(e.value[0]->type()->As<ast::Vector>()->type()->Is<ast::F32>());
|
||||||
|
EXPECT_EQ(e.value[0]->type()->As<ast::Vector>()->size(), 4u);
|
||||||
EXPECT_TRUE(e.value[0]->is_const());
|
EXPECT_TRUE(e.value[0]->is_const());
|
||||||
auto decos0 = e.value[0]->decorations();
|
auto decos0 = e.value[0]->decorations();
|
||||||
ASSERT_EQ(decos0.size(), 1u);
|
ASSERT_EQ(decos0.size(), 1u);
|
||||||
|
@ -123,7 +118,7 @@ TEST_F(ParserImplTest, ParamList_Decorations) {
|
||||||
ASSERT_EQ(e.value[0]->source().range.end.column, 28u);
|
ASSERT_EQ(e.value[0]->source().range.end.column, 28u);
|
||||||
|
|
||||||
EXPECT_EQ(e.value[1]->symbol(), p->builder().Symbols().Get("loc1"));
|
EXPECT_EQ(e.value[1]->symbol(), p->builder().Symbols().Get("loc1"));
|
||||||
EXPECT_EQ(e.value[1]->declared_type(), f32);
|
EXPECT_TRUE(e.value[1]->type()->Is<ast::F32>());
|
||||||
EXPECT_TRUE(e.value[1]->is_const());
|
EXPECT_TRUE(e.value[1]->is_const());
|
||||||
auto decos1 = e.value[1]->decorations();
|
auto decos1 = e.value[1]->decorations();
|
||||||
ASSERT_EQ(decos1.size(), 1u);
|
ASSERT_EQ(decos1.size(), 1u);
|
||||||
|
|
|
@ -141,7 +141,9 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructConstructor_Empty) {
|
||||||
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
||||||
|
|
||||||
auto* constructor = e->As<ast::TypeConstructorExpression>();
|
auto* constructor = e->As<ast::TypeConstructorExpression>();
|
||||||
EXPECT_EQ(constructor->type(), p->get_constructed("S"));
|
ASSERT_TRUE(constructor->type()->Is<ast::TypeName>());
|
||||||
|
EXPECT_EQ(constructor->type()->As<ast::TypeName>()->name(),
|
||||||
|
p->builder().Symbols().Get("S"));
|
||||||
|
|
||||||
auto values = constructor->values();
|
auto values = constructor->values();
|
||||||
ASSERT_EQ(values.size(), 0u);
|
ASSERT_EQ(values.size(), 0u);
|
||||||
|
@ -164,7 +166,9 @@ TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructConstructor_NotEmpty) {
|
||||||
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
||||||
|
|
||||||
auto* constructor = e->As<ast::TypeConstructorExpression>();
|
auto* constructor = e->As<ast::TypeConstructorExpression>();
|
||||||
EXPECT_EQ(constructor->type(), p->get_constructed("S"));
|
ASSERT_TRUE(constructor->type()->Is<ast::TypeName>());
|
||||||
|
EXPECT_EQ(constructor->type()->As<ast::TypeName>()->name(),
|
||||||
|
p->builder().Symbols().Get("S"));
|
||||||
|
|
||||||
auto values = constructor->values();
|
auto values = constructor->values();
|
||||||
ASSERT_EQ(values.size(), 2u);
|
ASSERT_EQ(values.size(), 2u);
|
||||||
|
@ -237,8 +241,6 @@ TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_InvalidExpr) {
|
||||||
TEST_F(ParserImplTest, PrimaryExpression_Cast) {
|
TEST_F(ParserImplTest, PrimaryExpression_Cast) {
|
||||||
auto p = parser("f32(1)");
|
auto p = parser("f32(1)");
|
||||||
|
|
||||||
auto* f32 = p->builder().create<sem::F32>();
|
|
||||||
|
|
||||||
auto e = p->primary_expression();
|
auto e = p->primary_expression();
|
||||||
EXPECT_TRUE(e.matched);
|
EXPECT_TRUE(e.matched);
|
||||||
EXPECT_FALSE(e.errored);
|
EXPECT_FALSE(e.errored);
|
||||||
|
@ -248,7 +250,7 @@ TEST_F(ParserImplTest, PrimaryExpression_Cast) {
|
||||||
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
ASSERT_TRUE(e->Is<ast::TypeConstructorExpression>());
|
||||||
|
|
||||||
auto* c = e->As<ast::TypeConstructorExpression>();
|
auto* c = e->As<ast::TypeConstructorExpression>();
|
||||||
ASSERT_EQ(c->type(), f32);
|
ASSERT_TRUE(c->type()->Is<ast::F32>());
|
||||||
ASSERT_EQ(c->values().size(), 1u);
|
ASSERT_EQ(c->values().size(), 1u);
|
||||||
|
|
||||||
ASSERT_TRUE(c->values()[0]->Is<ast::ConstructorExpression>());
|
ASSERT_TRUE(c->values()[0]->Is<ast::ConstructorExpression>());
|
||||||
|
@ -258,8 +260,6 @@ TEST_F(ParserImplTest, PrimaryExpression_Cast) {
|
||||||
TEST_F(ParserImplTest, PrimaryExpression_Bitcast) {
|
TEST_F(ParserImplTest, PrimaryExpression_Bitcast) {
|
||||||
auto p = parser("bitcast<f32>(1)");
|
auto p = parser("bitcast<f32>(1)");
|
||||||
|
|
||||||
auto* f32 = p->builder().create<sem::F32>();
|
|
||||||
|
|
||||||
auto e = p->primary_expression();
|
auto e = p->primary_expression();
|
||||||
EXPECT_TRUE(e.matched);
|
EXPECT_TRUE(e.matched);
|
||||||
EXPECT_FALSE(e.errored);
|
EXPECT_FALSE(e.errored);
|
||||||
|
@ -268,8 +268,7 @@ TEST_F(ParserImplTest, PrimaryExpression_Bitcast) {
|
||||||
ASSERT_TRUE(e->Is<ast::BitcastExpression>());
|
ASSERT_TRUE(e->Is<ast::BitcastExpression>());
|
||||||
|
|
||||||
auto* c = e->As<ast::BitcastExpression>();
|
auto* c = e->As<ast::BitcastExpression>();
|
||||||
ASSERT_EQ(c->type(), f32);
|
ASSERT_TRUE(c->type()->Is<ast::F32>());
|
||||||
|
|
||||||
ASSERT_TRUE(c->expr()->Is<ast::ConstructorExpression>());
|
ASSERT_TRUE(c->expr()->Is<ast::ConstructorExpression>());
|
||||||
ASSERT_TRUE(c->expr()->Is<ast::ScalarConstructorExpression>());
|
ASSERT_TRUE(c->expr()->Is<ast::ScalarConstructorExpression>());
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ TEST_F(ParserImplTest, StructBodyDecl_Parses) {
|
||||||
auto p = parser("{a : i32;}");
|
auto p = parser("{a : i32;}");
|
||||||
|
|
||||||
auto& builder = p->builder();
|
auto& builder = p->builder();
|
||||||
auto* i32 = builder.create<sem::I32>();
|
|
||||||
|
|
||||||
auto m = p->expect_struct_body_decl();
|
auto m = p->expect_struct_body_decl();
|
||||||
ASSERT_FALSE(p->has_error());
|
ASSERT_FALSE(p->has_error());
|
||||||
|
@ -32,7 +31,7 @@ TEST_F(ParserImplTest, StructBodyDecl_Parses) {
|
||||||
|
|
||||||
const auto* mem = m.value[0];
|
const auto* mem = m.value[0];
|
||||||
EXPECT_EQ(mem->symbol(), builder.Symbols().Get("a"));
|
EXPECT_EQ(mem->symbol(), builder.Symbols().Get("a"));
|
||||||
EXPECT_EQ(mem->type(), i32);
|
EXPECT_TRUE(mem->type()->Is<ast::I32>());
|
||||||
EXPECT_EQ(mem->decorations().size(), 0u);
|
EXPECT_EQ(mem->decorations().size(), 0u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ TEST_F(ParserImplTest, StructMember_Parses) {
|
||||||
auto p = parser("a : i32;");
|
auto p = parser("a : i32;");
|
||||||
|
|
||||||
auto& builder = p->builder();
|
auto& builder = p->builder();
|
||||||
auto i32 = builder.ty.i32();
|
|
||||||
|
|
||||||
auto decos = p->decoration_list();
|
auto decos = p->decoration_list();
|
||||||
EXPECT_FALSE(decos.errored);
|
EXPECT_FALSE(decos.errored);
|
||||||
|
@ -36,18 +35,17 @@ TEST_F(ParserImplTest, StructMember_Parses) {
|
||||||
ASSERT_NE(m.value, nullptr);
|
ASSERT_NE(m.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(m->symbol(), builder.Symbols().Get("a"));
|
EXPECT_EQ(m->symbol(), builder.Symbols().Get("a"));
|
||||||
EXPECT_EQ(m->type(), i32);
|
EXPECT_TRUE(m->type()->Is<ast::I32>());
|
||||||
EXPECT_EQ(m->decorations().size(), 0u);
|
EXPECT_EQ(m->decorations().size(), 0u);
|
||||||
|
|
||||||
EXPECT_EQ(m->source().range, (Source::Range{{1u, 1u}, {1u, 2u}}));
|
EXPECT_EQ(m->source().range, (Source::Range{{1u, 1u}, {1u, 2u}}));
|
||||||
EXPECT_EQ(m->type().ast->source().range, (Source::Range{{1u, 5u}, {1u, 8u}}));
|
EXPECT_EQ(m->type()->source().range, (Source::Range{{1u, 5u}, {1u, 8u}}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, StructMember_ParsesWithOffsetDecoration_DEPRECATED) {
|
TEST_F(ParserImplTest, StructMember_ParsesWithOffsetDecoration_DEPRECATED) {
|
||||||
auto p = parser("[[offset(2)]] a : i32;");
|
auto p = parser("[[offset(2)]] a : i32;");
|
||||||
|
|
||||||
auto& builder = p->builder();
|
auto& builder = p->builder();
|
||||||
auto i32 = builder.ty.i32();
|
|
||||||
|
|
||||||
auto decos = p->decoration_list();
|
auto decos = p->decoration_list();
|
||||||
EXPECT_FALSE(decos.errored);
|
EXPECT_FALSE(decos.errored);
|
||||||
|
@ -60,7 +58,7 @@ TEST_F(ParserImplTest, StructMember_ParsesWithOffsetDecoration_DEPRECATED) {
|
||||||
ASSERT_NE(m.value, nullptr);
|
ASSERT_NE(m.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(m->symbol(), builder.Symbols().Get("a"));
|
EXPECT_EQ(m->symbol(), builder.Symbols().Get("a"));
|
||||||
EXPECT_EQ(m->type(), i32);
|
EXPECT_TRUE(m->type()->Is<ast::I32>());
|
||||||
EXPECT_EQ(m->decorations().size(), 1u);
|
EXPECT_EQ(m->decorations().size(), 1u);
|
||||||
EXPECT_TRUE(m->decorations()[0]->Is<ast::StructMemberOffsetDecoration>());
|
EXPECT_TRUE(m->decorations()[0]->Is<ast::StructMemberOffsetDecoration>());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
|
@ -68,15 +66,13 @@ TEST_F(ParserImplTest, StructMember_ParsesWithOffsetDecoration_DEPRECATED) {
|
||||||
2u);
|
2u);
|
||||||
|
|
||||||
EXPECT_EQ(m->source().range, (Source::Range{{1u, 15u}, {1u, 16u}}));
|
EXPECT_EQ(m->source().range, (Source::Range{{1u, 15u}, {1u, 16u}}));
|
||||||
EXPECT_EQ(m->type().ast->source().range,
|
EXPECT_EQ(m->type()->source().range, (Source::Range{{1u, 19u}, {1u, 22u}}));
|
||||||
(Source::Range{{1u, 19u}, {1u, 22u}}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, StructMember_ParsesWithAlignDecoration) {
|
TEST_F(ParserImplTest, StructMember_ParsesWithAlignDecoration) {
|
||||||
auto p = parser("[[align(2)]] a : i32;");
|
auto p = parser("[[align(2)]] a : i32;");
|
||||||
|
|
||||||
auto& builder = p->builder();
|
auto& builder = p->builder();
|
||||||
auto i32 = builder.ty.i32();
|
|
||||||
|
|
||||||
auto decos = p->decoration_list();
|
auto decos = p->decoration_list();
|
||||||
EXPECT_FALSE(decos.errored);
|
EXPECT_FALSE(decos.errored);
|
||||||
|
@ -89,22 +85,20 @@ TEST_F(ParserImplTest, StructMember_ParsesWithAlignDecoration) {
|
||||||
ASSERT_NE(m.value, nullptr);
|
ASSERT_NE(m.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(m->symbol(), builder.Symbols().Get("a"));
|
EXPECT_EQ(m->symbol(), builder.Symbols().Get("a"));
|
||||||
EXPECT_EQ(m->type(), i32);
|
EXPECT_TRUE(m->type()->Is<ast::I32>());
|
||||||
EXPECT_EQ(m->decorations().size(), 1u);
|
EXPECT_EQ(m->decorations().size(), 1u);
|
||||||
EXPECT_TRUE(m->decorations()[0]->Is<ast::StructMemberAlignDecoration>());
|
EXPECT_TRUE(m->decorations()[0]->Is<ast::StructMemberAlignDecoration>());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
m->decorations()[0]->As<ast::StructMemberAlignDecoration>()->align(), 2u);
|
m->decorations()[0]->As<ast::StructMemberAlignDecoration>()->align(), 2u);
|
||||||
|
|
||||||
EXPECT_EQ(m->source().range, (Source::Range{{1u, 14u}, {1u, 15u}}));
|
EXPECT_EQ(m->source().range, (Source::Range{{1u, 14u}, {1u, 15u}}));
|
||||||
EXPECT_EQ(m->type().ast->source().range,
|
EXPECT_EQ(m->type()->source().range, (Source::Range{{1u, 18u}, {1u, 21u}}));
|
||||||
(Source::Range{{1u, 18u}, {1u, 21u}}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, StructMember_ParsesWithSizeDecoration) {
|
TEST_F(ParserImplTest, StructMember_ParsesWithSizeDecoration) {
|
||||||
auto p = parser("[[size(2)]] a : i32;");
|
auto p = parser("[[size(2)]] a : i32;");
|
||||||
|
|
||||||
auto& builder = p->builder();
|
auto& builder = p->builder();
|
||||||
auto i32 = builder.ty.i32();
|
|
||||||
|
|
||||||
auto decos = p->decoration_list();
|
auto decos = p->decoration_list();
|
||||||
EXPECT_FALSE(decos.errored);
|
EXPECT_FALSE(decos.errored);
|
||||||
|
@ -117,22 +111,20 @@ TEST_F(ParserImplTest, StructMember_ParsesWithSizeDecoration) {
|
||||||
ASSERT_NE(m.value, nullptr);
|
ASSERT_NE(m.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(m->symbol(), builder.Symbols().Get("a"));
|
EXPECT_EQ(m->symbol(), builder.Symbols().Get("a"));
|
||||||
EXPECT_EQ(m->type(), i32);
|
EXPECT_TRUE(m->type()->Is<ast::I32>());
|
||||||
EXPECT_EQ(m->decorations().size(), 1u);
|
EXPECT_EQ(m->decorations().size(), 1u);
|
||||||
EXPECT_TRUE(m->decorations()[0]->Is<ast::StructMemberSizeDecoration>());
|
EXPECT_TRUE(m->decorations()[0]->Is<ast::StructMemberSizeDecoration>());
|
||||||
EXPECT_EQ(m->decorations()[0]->As<ast::StructMemberSizeDecoration>()->size(),
|
EXPECT_EQ(m->decorations()[0]->As<ast::StructMemberSizeDecoration>()->size(),
|
||||||
2u);
|
2u);
|
||||||
|
|
||||||
EXPECT_EQ(m->source().range, (Source::Range{{1u, 13u}, {1u, 14u}}));
|
EXPECT_EQ(m->source().range, (Source::Range{{1u, 13u}, {1u, 14u}}));
|
||||||
EXPECT_EQ(m->type().ast->source().range,
|
EXPECT_EQ(m->type()->source().range, (Source::Range{{1u, 17u}, {1u, 20u}}));
|
||||||
(Source::Range{{1u, 17u}, {1u, 20u}}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
|
TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
|
||||||
auto p = parser("[[size(2)]] a : i32;");
|
auto p = parser("[[size(2)]] a : i32;");
|
||||||
|
|
||||||
auto& builder = p->builder();
|
auto& builder = p->builder();
|
||||||
auto i32 = builder.ty.i32();
|
|
||||||
|
|
||||||
auto decos = p->decoration_list();
|
auto decos = p->decoration_list();
|
||||||
EXPECT_FALSE(decos.errored);
|
EXPECT_FALSE(decos.errored);
|
||||||
|
@ -145,15 +137,14 @@ TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
|
||||||
ASSERT_NE(m.value, nullptr);
|
ASSERT_NE(m.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(m->symbol(), builder.Symbols().Get("a"));
|
EXPECT_EQ(m->symbol(), builder.Symbols().Get("a"));
|
||||||
EXPECT_EQ(m->type(), i32);
|
EXPECT_TRUE(m->type()->Is<ast::I32>());
|
||||||
EXPECT_EQ(m->decorations().size(), 1u);
|
EXPECT_EQ(m->decorations().size(), 1u);
|
||||||
EXPECT_TRUE(m->decorations()[0]->Is<ast::StructMemberSizeDecoration>());
|
EXPECT_TRUE(m->decorations()[0]->Is<ast::StructMemberSizeDecoration>());
|
||||||
EXPECT_EQ(m->decorations()[0]->As<ast::StructMemberSizeDecoration>()->size(),
|
EXPECT_EQ(m->decorations()[0]->As<ast::StructMemberSizeDecoration>()->size(),
|
||||||
2u);
|
2u);
|
||||||
|
|
||||||
EXPECT_EQ(m->source().range, (Source::Range{{1u, 13u}, {1u, 14u}}));
|
EXPECT_EQ(m->source().range, (Source::Range{{1u, 13u}, {1u, 14u}}));
|
||||||
EXPECT_EQ(m->type().ast->source().range,
|
EXPECT_EQ(m->type()->source().range, (Source::Range{{1u, 17u}, {1u, 20u}}));
|
||||||
(Source::Range{{1u, 17u}, {1u, 20u}}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
|
TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
|
||||||
|
@ -161,7 +152,6 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
|
||||||
[[align(4)]] a : i32;)");
|
[[align(4)]] a : i32;)");
|
||||||
|
|
||||||
auto& builder = p->builder();
|
auto& builder = p->builder();
|
||||||
auto i32 = builder.ty.i32();
|
|
||||||
|
|
||||||
auto decos = p->decoration_list();
|
auto decos = p->decoration_list();
|
||||||
EXPECT_FALSE(decos.errored);
|
EXPECT_FALSE(decos.errored);
|
||||||
|
@ -174,7 +164,7 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
|
||||||
ASSERT_NE(m.value, nullptr);
|
ASSERT_NE(m.value, nullptr);
|
||||||
|
|
||||||
EXPECT_EQ(m->symbol(), builder.Symbols().Get("a"));
|
EXPECT_EQ(m->symbol(), builder.Symbols().Get("a"));
|
||||||
EXPECT_EQ(m->type(), i32);
|
EXPECT_TRUE(m->type()->Is<ast::I32>());
|
||||||
EXPECT_EQ(m->decorations().size(), 2u);
|
EXPECT_EQ(m->decorations().size(), 2u);
|
||||||
EXPECT_TRUE(m->decorations()[0]->Is<ast::StructMemberSizeDecoration>());
|
EXPECT_TRUE(m->decorations()[0]->Is<ast::StructMemberSizeDecoration>());
|
||||||
EXPECT_EQ(m->decorations()[0]->As<ast::StructMemberSizeDecoration>()->size(),
|
EXPECT_EQ(m->decorations()[0]->As<ast::StructMemberSizeDecoration>()->size(),
|
||||||
|
@ -184,8 +174,7 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
|
||||||
m->decorations()[1]->As<ast::StructMemberAlignDecoration>()->align(), 4u);
|
m->decorations()[1]->As<ast::StructMemberAlignDecoration>()->align(), 4u);
|
||||||
|
|
||||||
EXPECT_EQ(m->source().range, (Source::Range{{2u, 14u}, {2u, 15u}}));
|
EXPECT_EQ(m->source().range, (Source::Range{{2u, 14u}, {2u, 15u}}));
|
||||||
EXPECT_EQ(m->type().ast->source().range,
|
EXPECT_EQ(m->type()->source().range, (Source::Range{{2u, 18u}, {2u, 21u}}));
|
||||||
(Source::Range{{2u, 18u}, {2u, 21u}}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, StructMember_InvalidDecoration) {
|
TEST_F(ParserImplTest, StructMember_InvalidDecoration) {
|
||||||
|
|
|
@ -308,7 +308,7 @@ namespace ArrayStrideTests {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct Params {
|
struct Params {
|
||||||
create_type_func_ptr create_el_type;
|
create_ast_type_func_ptr create_el_type;
|
||||||
uint32_t stride;
|
uint32_t stride;
|
||||||
bool should_pass;
|
bool should_pass;
|
||||||
};
|
};
|
||||||
|
@ -318,17 +318,16 @@ struct TestWithParams : ResolverTestWithParam<Params> {};
|
||||||
using ArrayStrideTest = TestWithParams;
|
using ArrayStrideTest = TestWithParams;
|
||||||
TEST_P(ArrayStrideTest, All) {
|
TEST_P(ArrayStrideTest, All) {
|
||||||
auto& params = GetParam();
|
auto& params = GetParam();
|
||||||
auto el_ty = params.create_el_type(ty);
|
auto* el_ty = params.create_el_type(ty);
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "el_ty: " << el_ty->FriendlyName(Symbols())
|
ss << "el_ty: " << FriendlyName(el_ty) << ", stride: " << params.stride
|
||||||
<< ", stride: " << params.stride
|
|
||||||
<< ", should_pass: " << params.should_pass;
|
<< ", should_pass: " << params.should_pass;
|
||||||
SCOPED_TRACE(ss.str());
|
SCOPED_TRACE(ss.str());
|
||||||
|
|
||||||
auto arr = ty.array(el_ty, 4, params.stride);
|
auto arr = ty.array(Source{{12, 34}}, el_ty, 4, params.stride);
|
||||||
|
|
||||||
Global(Source{{12, 34}}, "myarray", arr, ast::StorageClass::kInput);
|
Global("myarray", arr, ast::StorageClass::kInput);
|
||||||
|
|
||||||
if (params.should_pass) {
|
if (params.should_pass) {
|
||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
@ -366,58 +365,58 @@ INSTANTIATE_TEST_SUITE_P(
|
||||||
testing::Values(
|
testing::Values(
|
||||||
// Succeed because stride >= element size (while being multiple of
|
// Succeed because stride >= element size (while being multiple of
|
||||||
// element alignment)
|
// element alignment)
|
||||||
Params{ty_u32, default_u32.size, true},
|
Params{ast_u32, default_u32.size, true},
|
||||||
Params{ty_i32, default_i32.size, true},
|
Params{ast_i32, default_i32.size, true},
|
||||||
Params{ty_f32, default_f32.size, true},
|
Params{ast_f32, default_f32.size, true},
|
||||||
Params{ty_vec2<f32>, default_vec2.size, true},
|
Params{ast_vec2<f32>, default_vec2.size, true},
|
||||||
// vec3's default size is not a multiple of its alignment
|
// vec3's default size is not a multiple of its alignment
|
||||||
// Params{ty_vec3<f32>, default_vec3.size, true},
|
// Params{ast_vec3<f32>, default_vec3.size, true},
|
||||||
Params{ty_vec4<f32>, default_vec4.size, true},
|
Params{ast_vec4<f32>, default_vec4.size, true},
|
||||||
Params{ty_mat2x2<f32>, default_mat2x2.size, true},
|
Params{ast_mat2x2<f32>, default_mat2x2.size, true},
|
||||||
Params{ty_mat3x3<f32>, default_mat3x3.size, true},
|
Params{ast_mat3x3<f32>, default_mat3x3.size, true},
|
||||||
Params{ty_mat4x4<f32>, default_mat4x4.size, true},
|
Params{ast_mat4x4<f32>, default_mat4x4.size, true},
|
||||||
|
|
||||||
// Fail because stride is < element size
|
// Fail because stride is < element size
|
||||||
Params{ty_u32, default_u32.size - 1, false},
|
Params{ast_u32, default_u32.size - 1, false},
|
||||||
Params{ty_i32, default_i32.size - 1, false},
|
Params{ast_i32, default_i32.size - 1, false},
|
||||||
Params{ty_f32, default_f32.size - 1, false},
|
Params{ast_f32, default_f32.size - 1, false},
|
||||||
Params{ty_vec2<f32>, default_vec2.size - 1, false},
|
Params{ast_vec2<f32>, default_vec2.size - 1, false},
|
||||||
Params{ty_vec3<f32>, default_vec3.size - 1, false},
|
Params{ast_vec3<f32>, default_vec3.size - 1, false},
|
||||||
Params{ty_vec4<f32>, default_vec4.size - 1, false},
|
Params{ast_vec4<f32>, default_vec4.size - 1, false},
|
||||||
Params{ty_mat2x2<f32>, default_mat2x2.size - 1, false},
|
Params{ast_mat2x2<f32>, default_mat2x2.size - 1, false},
|
||||||
Params{ty_mat3x3<f32>, default_mat3x3.size - 1, false},
|
Params{ast_mat3x3<f32>, default_mat3x3.size - 1, false},
|
||||||
Params{ty_mat4x4<f32>, default_mat4x4.size - 1, false},
|
Params{ast_mat4x4<f32>, default_mat4x4.size - 1, false},
|
||||||
|
|
||||||
// Succeed because stride equals multiple of element alignment
|
// Succeed because stride equals multiple of element alignment
|
||||||
Params{ty_u32, default_u32.align * 7, true},
|
Params{ast_u32, default_u32.align * 7, true},
|
||||||
Params{ty_i32, default_i32.align * 7, true},
|
Params{ast_i32, default_i32.align * 7, true},
|
||||||
Params{ty_f32, default_f32.align * 7, true},
|
Params{ast_f32, default_f32.align * 7, true},
|
||||||
Params{ty_vec2<f32>, default_vec2.align * 7, true},
|
Params{ast_vec2<f32>, default_vec2.align * 7, true},
|
||||||
Params{ty_vec3<f32>, default_vec3.align * 7, true},
|
Params{ast_vec3<f32>, default_vec3.align * 7, true},
|
||||||
Params{ty_vec4<f32>, default_vec4.align * 7, true},
|
Params{ast_vec4<f32>, default_vec4.align * 7, true},
|
||||||
Params{ty_mat2x2<f32>, default_mat2x2.align * 7, true},
|
Params{ast_mat2x2<f32>, default_mat2x2.align * 7, true},
|
||||||
Params{ty_mat3x3<f32>, default_mat3x3.align * 7, true},
|
Params{ast_mat3x3<f32>, default_mat3x3.align * 7, true},
|
||||||
Params{ty_mat4x4<f32>, default_mat4x4.align * 7, true},
|
Params{ast_mat4x4<f32>, default_mat4x4.align * 7, true},
|
||||||
|
|
||||||
// Fail because stride is not multiple of element alignment
|
// Fail because stride is not multiple of element alignment
|
||||||
Params{ty_u32, (default_u32.align - 1) * 7, false},
|
Params{ast_u32, (default_u32.align - 1) * 7, false},
|
||||||
Params{ty_i32, (default_i32.align - 1) * 7, false},
|
Params{ast_i32, (default_i32.align - 1) * 7, false},
|
||||||
Params{ty_f32, (default_f32.align - 1) * 7, false},
|
Params{ast_f32, (default_f32.align - 1) * 7, false},
|
||||||
Params{ty_vec2<f32>, (default_vec2.align - 1) * 7, false},
|
Params{ast_vec2<f32>, (default_vec2.align - 1) * 7, false},
|
||||||
Params{ty_vec3<f32>, (default_vec3.align - 1) * 7, false},
|
Params{ast_vec3<f32>, (default_vec3.align - 1) * 7, false},
|
||||||
Params{ty_vec4<f32>, (default_vec4.align - 1) * 7, false},
|
Params{ast_vec4<f32>, (default_vec4.align - 1) * 7, false},
|
||||||
Params{ty_mat2x2<f32>, (default_mat2x2.align - 1) * 7, false},
|
Params{ast_mat2x2<f32>, (default_mat2x2.align - 1) * 7, false},
|
||||||
Params{ty_mat3x3<f32>, (default_mat3x3.align - 1) * 7, false},
|
Params{ast_mat3x3<f32>, (default_mat3x3.align - 1) * 7, false},
|
||||||
Params{ty_mat4x4<f32>, (default_mat4x4.align - 1) * 7, false}));
|
Params{ast_mat4x4<f32>, (default_mat4x4.align - 1) * 7, false}));
|
||||||
|
|
||||||
TEST_F(ArrayStrideTest, MultipleDecorations) {
|
TEST_F(ArrayStrideTest, MultipleDecorations) {
|
||||||
auto arr = ty.array(ty.i32(), 4,
|
auto arr = ty.array(Source{{12, 34}}, ty.i32(), 4,
|
||||||
{
|
{
|
||||||
create<ast::StrideDecoration>(4),
|
create<ast::StrideDecoration>(4),
|
||||||
create<ast::StrideDecoration>(4),
|
create<ast::StrideDecoration>(4),
|
||||||
});
|
});
|
||||||
|
|
||||||
Global(Source{{12, 34}}, "myarray", arr, ast::StorageClass::kInput);
|
Global("myarray", arr, ast::StorageClass::kInput);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "src/ast/storage_texture.h"
|
#include "src/ast/storage_texture.h"
|
||||||
#include "src/ast/struct_block_decoration.h"
|
#include "src/ast/struct_block_decoration.h"
|
||||||
#include "src/ast/switch_statement.h"
|
#include "src/ast/switch_statement.h"
|
||||||
|
#include "src/ast/type_name.h"
|
||||||
#include "src/ast/unary_op_expression.h"
|
#include "src/ast/unary_op_expression.h"
|
||||||
#include "src/ast/variable_decl_statement.h"
|
#include "src/ast/variable_decl_statement.h"
|
||||||
#include "src/ast/vector.h"
|
#include "src/ast/vector.h"
|
||||||
|
@ -151,8 +152,17 @@ void Resolver::set_referenced_from_function_if_needed(VariableInfo* var,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::Resolve() {
|
bool Resolver::Resolve() {
|
||||||
|
if (builder_->Diagnostics().contains_errors()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool result = ResolveInternal();
|
bool result = ResolveInternal();
|
||||||
|
|
||||||
|
if (result && diagnostics_.contains_errors()) {
|
||||||
|
TINT_ICE(diagnostics_) << "resolving failed, but no error was raised";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Even if resolving failed, create all the semantic nodes for information we
|
// Even if resolving failed, create all the semantic nodes for information we
|
||||||
// did generate.
|
// did generate.
|
||||||
CreateSemanticNodes();
|
CreateSemanticNodes();
|
||||||
|
@ -169,13 +179,15 @@ bool Resolver::IsStorable(const sem::Type* type) {
|
||||||
if (auto* arr = type->As<sem::ArrayType>()) {
|
if (auto* arr = type->As<sem::ArrayType>()) {
|
||||||
return IsStorable(arr->type());
|
return IsStorable(arr->type());
|
||||||
}
|
}
|
||||||
if (auto* str = type->As<sem::StructType>()) {
|
if (auto* str_ty = type->As<sem::StructType>()) {
|
||||||
for (const auto* member : str->impl()->members()) {
|
if (auto* str = Structure(str_ty)) {
|
||||||
if (!IsStorable(member->type())) {
|
for (const auto* member : str->members) {
|
||||||
return false;
|
if (!IsStorable(member->Type())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -196,8 +208,12 @@ bool Resolver::IsHostShareable(const sem::Type* type) {
|
||||||
return IsHostShareable(arr->type());
|
return IsHostShareable(arr->type());
|
||||||
}
|
}
|
||||||
if (auto* str = type->As<sem::StructType>()) {
|
if (auto* str = type->As<sem::StructType>()) {
|
||||||
for (auto* member : str->impl()->members()) {
|
auto* info = Structure(str);
|
||||||
if (!IsHostShareable(member->type())) {
|
if (!info) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (auto* member : info->members) {
|
||||||
|
if (!IsHostShareable(member->Type())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,11 +241,28 @@ bool Resolver::IsValidAssignment(const sem::Type* lhs, const sem::Type* rhs) {
|
||||||
bool Resolver::ResolveInternal() {
|
bool Resolver::ResolveInternal() {
|
||||||
Mark(&builder_->AST());
|
Mark(&builder_->AST());
|
||||||
|
|
||||||
|
auto register_named_type = [this](Symbol name, const sem::Type* type,
|
||||||
|
const Source& source) {
|
||||||
|
auto added = named_types_.emplace(name, type).second;
|
||||||
|
if (!added) {
|
||||||
|
diagnostics_.add_error("type with the name '" +
|
||||||
|
builder_->Symbols().NameFor(name) +
|
||||||
|
"' was already declared",
|
||||||
|
source);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
// Process everything else in the order they appear in the module. This is
|
// Process everything else in the order they appear in the module. This is
|
||||||
// necessary for validation of use-before-declaration.
|
// necessary for validation of use-before-declaration.
|
||||||
for (auto* decl : builder_->AST().GlobalDeclarations()) {
|
for (auto* decl : builder_->AST().GlobalDeclarations()) {
|
||||||
if (auto* ty = decl->As<sem::Type>()) {
|
if (auto* ty = decl->As<ast::NamedType>()) {
|
||||||
if (!Type(ty)) {
|
auto* sem_ty = Type(ty);
|
||||||
|
if (sem_ty == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!register_named_type(ty->name(), sem_ty, ty->source())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (auto* func = decl->As<ast::Function>()) {
|
} else if (auto* func = decl->As<ast::Function>()) {
|
||||||
|
@ -249,6 +282,8 @@ bool Resolver::ResolveInternal() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
for (auto* node : builder_->ASTNodes().Objects()) {
|
for (auto* node : builder_->ASTNodes().Objects()) {
|
||||||
if (marked_.count(node) == 0) {
|
if (marked_.count(node) == 0) {
|
||||||
if (node->IsAnyOf<ast::AccessDecoration, ast::StrideDecoration,
|
if (node->IsAnyOf<ast::AccessDecoration, ast::StrideDecoration,
|
||||||
|
@ -268,10 +303,11 @@ bool Resolver::ResolveInternal() {
|
||||||
<< "At: " << node->source() << "\n"
|
<< "At: " << node->source() << "\n"
|
||||||
<< "Content: " << builder_->str(node) << "\n"
|
<< "Content: " << builder_->str(node) << "\n"
|
||||||
<< "Pointer: " << node;
|
<< "Pointer: " << node;
|
||||||
|
result = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sem::Type* Resolver::Type(const ast::Type* ty) {
|
const sem::Type* Resolver::Type(const ast::Type* ty) {
|
||||||
|
@ -360,6 +396,16 @@ const sem::Type* Resolver::Type(const ast::Type* ty) {
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
if (auto* t = ty->As<ast::TypeName>()) {
|
||||||
|
auto it = named_types_.find(t->name());
|
||||||
|
if (it == named_types_.end()) {
|
||||||
|
diagnostics_.add_error(
|
||||||
|
"unknown type '" + builder_->Symbols().NameFor(t->name()) + "'",
|
||||||
|
t->source());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
TINT_UNREACHABLE(diagnostics_)
|
TINT_UNREACHABLE(diagnostics_)
|
||||||
<< "Unhandled ast::Type: " << ty->TypeInfo().name;
|
<< "Unhandled ast::Type: " << ty->TypeInfo().name;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -392,21 +438,26 @@ bool Resolver::Type(const sem::Type* ty, const Source& source /* = {} */) {
|
||||||
|
|
||||||
Resolver::VariableInfo* Resolver::Variable(
|
Resolver::VariableInfo* Resolver::Variable(
|
||||||
ast::Variable* var,
|
ast::Variable* var,
|
||||||
const sem::Type* type /* = nullptr*/) {
|
const sem::Type* type, /* = nullptr */
|
||||||
|
std::string type_name /* = "" */) {
|
||||||
auto it = variable_to_info_.find(var);
|
auto it = variable_to_info_.find(var);
|
||||||
if (it != variable_to_info_.end()) {
|
if (it != variable_to_info_.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!type) {
|
if (type == nullptr && var->type()) {
|
||||||
type = var->declared_type();
|
type = Type(var->type());
|
||||||
|
type_name = var->type()->FriendlyName(builder_->Symbols());
|
||||||
|
}
|
||||||
|
if (type == nullptr) {
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto type_name = type->FriendlyName(builder_->Symbols());
|
|
||||||
auto* ctype = Canonical(type);
|
auto* ctype = Canonical(type);
|
||||||
auto* info = variable_infos_.Create(var, ctype, type_name);
|
auto* info = variable_infos_.Create(var, ctype, type_name);
|
||||||
variable_to_info_.emplace(var, info);
|
variable_to_info_.emplace(var, info);
|
||||||
|
|
||||||
|
// TODO(bclayton): Why is this here? Needed?
|
||||||
// Resolve variable's type
|
// Resolve variable's type
|
||||||
if (auto* arr = info->type->As<sem::ArrayType>()) {
|
if (auto* arr = info->type->As<sem::ArrayType>()) {
|
||||||
if (!Array(arr, var->source())) {
|
if (!Array(arr, var->source())) {
|
||||||
|
@ -805,12 +856,12 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
|
||||||
if (auto* struct_ty = Canonical(ty)->As<sem::StructType>()) {
|
if (auto* struct_ty = Canonical(ty)->As<sem::StructType>()) {
|
||||||
// Validate the decorations for each struct members, and also check for
|
// Validate the decorations for each struct members, and also check for
|
||||||
// invalid member types.
|
// invalid member types.
|
||||||
for (auto* member : struct_ty->impl()->members()) {
|
for (auto* member : Structure(struct_ty)->members) {
|
||||||
auto* member_ty = Canonical(member->type());
|
auto* member_ty = Canonical(member->Type());
|
||||||
if (member_ty->Is<sem::StructType>()) {
|
if (member_ty->Is<sem::StructType>()) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"entry point IO types cannot contain nested structures",
|
"entry point IO types cannot contain nested structures",
|
||||||
member->source());
|
member->Declaration()->source());
|
||||||
diagnostics_.add_note("while analysing entry point " +
|
diagnostics_.add_note("while analysing entry point " +
|
||||||
builder_->Symbols().NameFor(func->symbol()),
|
builder_->Symbols().NameFor(func->symbol()),
|
||||||
func->source());
|
func->source());
|
||||||
|
@ -819,7 +870,7 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
|
||||||
if (arr->IsRuntimeArray()) {
|
if (arr->IsRuntimeArray()) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"entry point IO types cannot contain runtime sized arrays",
|
"entry point IO types cannot contain runtime sized arrays",
|
||||||
member->source());
|
member->Declaration()->source());
|
||||||
diagnostics_.add_note(
|
diagnostics_.add_note(
|
||||||
"while analysing entry point " +
|
"while analysing entry point " +
|
||||||
builder_->Symbols().NameFor(func->symbol()),
|
builder_->Symbols().NameFor(func->symbol()),
|
||||||
|
@ -828,9 +879,9 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validate_entry_point_decorations_inner(member->decorations(),
|
if (!validate_entry_point_decorations_inner(
|
||||||
member_ty, member->source(),
|
member->Declaration()->decorations(), member_ty,
|
||||||
param_or_ret, true)) {
|
member->Declaration()->source(), param_or_ret, true)) {
|
||||||
diagnostics_.add_note("while analysing entry point " +
|
diagnostics_.add_note("while analysing entry point " +
|
||||||
builder_->Symbols().NameFor(func->symbol()),
|
builder_->Symbols().NameFor(func->symbol()),
|
||||||
func->source());
|
func->source());
|
||||||
|
@ -842,10 +893,10 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto* param : func->params()) {
|
for (auto* param : info->parameters) {
|
||||||
if (!validate_entry_point_decorations(
|
if (!validate_entry_point_decorations(
|
||||||
param->decorations(), param->declared_type(), param->source(),
|
param->declaration->decorations(), param->type,
|
||||||
ParamOrRetType::kParameter)) {
|
param->declaration->source(), ParamOrRetType::kParameter)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -943,19 +994,18 @@ bool Resolver::Function(ast::Function* func) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func->return_type().ast || func->return_type().sem) {
|
if (auto* ty = func->return_type()) {
|
||||||
info->return_type = func->return_type();
|
info->return_type = Type(ty);
|
||||||
if (!info->return_type) {
|
info->return_type_name = ty->FriendlyName(builder_->Symbols());
|
||||||
info->return_type = Type(func->return_type().ast);
|
|
||||||
}
|
|
||||||
if (!info->return_type) {
|
if (!info->return_type) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info->return_type = builder_->create<sem::Void>();
|
info->return_type = builder_->create<sem::Void>();
|
||||||
|
info->return_type_name =
|
||||||
|
info->return_type->FriendlyName(builder_->Symbols());
|
||||||
}
|
}
|
||||||
|
|
||||||
info->return_type_name = info->return_type->FriendlyName(builder_->Symbols());
|
|
||||||
info->return_type = Canonical(info->return_type);
|
info->return_type = Canonical(info->return_type);
|
||||||
|
|
||||||
if (auto* str = info->return_type->As<sem::StructType>()) {
|
if (auto* str = info->return_type->As<sem::StructType>()) {
|
||||||
|
@ -1374,17 +1424,16 @@ bool Resolver::Constructor(ast::ConstructorExpression* expr) {
|
||||||
|
|
||||||
SetType(expr, type_ctor->type());
|
SetType(expr, type_ctor->type());
|
||||||
|
|
||||||
|
const sem::Type* type = TypeOf(expr);
|
||||||
|
|
||||||
// Now that the argument types have been determined, make sure that they
|
// Now that the argument types have been determined, make sure that they
|
||||||
// obey the constructor type rules laid out in
|
// obey the constructor type rules laid out in
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl.html#type-constructor-expr.
|
// https://gpuweb.github.io/gpuweb/wgsl.html#type-constructor-expr.
|
||||||
if (auto* vec_type = type_ctor->type()->As<sem::Vector>()) {
|
if (auto* vec_type = type->As<sem::Vector>()) {
|
||||||
return ValidateVectorConstructor(type_ctor, vec_type,
|
return ValidateVectorConstructor(type_ctor, vec_type);
|
||||||
type_ctor->values());
|
|
||||||
}
|
}
|
||||||
if (auto* mat_type = type_ctor->type()->As<sem::Matrix>()) {
|
if (auto* mat_type = type->As<sem::Matrix>()) {
|
||||||
auto mat_typename = TypeNameOf(type_ctor);
|
return ValidateMatrixConstructor(type_ctor, mat_type);
|
||||||
return ValidateMatrixConstructor(type_ctor, mat_type,
|
|
||||||
type_ctor->values());
|
|
||||||
}
|
}
|
||||||
// TODO(crbug.com/tint/634): Validate array constructor
|
// TODO(crbug.com/tint/634): Validate array constructor
|
||||||
} else if (auto* scalar_ctor = expr->As<ast::ScalarConstructorExpression>()) {
|
} else if (auto* scalar_ctor = expr->As<ast::ScalarConstructorExpression>()) {
|
||||||
|
@ -1398,8 +1447,8 @@ bool Resolver::Constructor(ast::ConstructorExpression* expr) {
|
||||||
|
|
||||||
bool Resolver::ValidateVectorConstructor(
|
bool Resolver::ValidateVectorConstructor(
|
||||||
const ast::TypeConstructorExpression* ctor,
|
const ast::TypeConstructorExpression* ctor,
|
||||||
const sem::Vector* vec_type,
|
const sem::Vector* vec_type) {
|
||||||
const ast::ExpressionList& values) {
|
auto& values = ctor->values();
|
||||||
auto* elem_type = vec_type->type()->UnwrapAll();
|
auto* elem_type = vec_type->type()->UnwrapAll();
|
||||||
size_t value_cardinality_sum = 0;
|
size_t value_cardinality_sum = 0;
|
||||||
for (auto* value : values) {
|
for (auto* value : values) {
|
||||||
|
@ -1467,8 +1516,8 @@ bool Resolver::ValidateVectorConstructor(
|
||||||
|
|
||||||
bool Resolver::ValidateMatrixConstructor(
|
bool Resolver::ValidateMatrixConstructor(
|
||||||
const ast::TypeConstructorExpression* ctor,
|
const ast::TypeConstructorExpression* ctor,
|
||||||
const sem::Matrix* matrix_type,
|
const sem::Matrix* matrix_type) {
|
||||||
const ast::ExpressionList& values) {
|
auto& values = ctor->values();
|
||||||
// Zero Value expression
|
// Zero Value expression
|
||||||
if (values.empty()) {
|
if (values.empty()) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1600,7 +1649,7 @@ bool Resolver::MemberAccessor(ast::MemberAccessorExpression* expr) {
|
||||||
const sem::StructMember* member = nullptr;
|
const sem::StructMember* member = nullptr;
|
||||||
for (auto* m : str->members) {
|
for (auto* m : str->members) {
|
||||||
if (m->Declaration()->symbol() == symbol) {
|
if (m->Declaration()->symbol() == symbol) {
|
||||||
ret = m->Declaration()->type();
|
ret = m->Type();
|
||||||
member = m;
|
member = m;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1961,7 +2010,16 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
||||||
ast::Variable* var = stmt->variable();
|
ast::Variable* var = stmt->variable();
|
||||||
Mark(var);
|
Mark(var);
|
||||||
|
|
||||||
const sem::Type* type = var->declared_type();
|
// If the variable has a declared type, resolve it.
|
||||||
|
std::string type_name;
|
||||||
|
const sem::Type* type = nullptr;
|
||||||
|
if (auto* ast_ty = var->type()) {
|
||||||
|
type_name = ast_ty->FriendlyName(builder_->Symbols());
|
||||||
|
type = Type(ast_ty);
|
||||||
|
if (!type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool is_global = false;
|
bool is_global = false;
|
||||||
if (variable_stack_.get(var->symbol(), nullptr, &is_global)) {
|
if (variable_stack_.get(var->symbol(), nullptr, &is_global)) {
|
||||||
|
@ -1982,14 +2040,15 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
||||||
|
|
||||||
// If the variable has no type, infer it from the rhs
|
// If the variable has no type, infer it from the rhs
|
||||||
if (type == nullptr) {
|
if (type == nullptr) {
|
||||||
|
type_name = TypeNameOf(ctor);
|
||||||
type = rhs_type->UnwrapPtrIfNeeded();
|
type = rhs_type->UnwrapPtrIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsValidAssignment(type, rhs_type)) {
|
if (!IsValidAssignment(type, rhs_type)) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"variable of type '" + type->FriendlyName(builder_->Symbols()) +
|
"variable of type '" + type_name +
|
||||||
"' cannot be initialized with a value of type '" +
|
"' cannot be initialized with a value of type '" +
|
||||||
rhs_type->FriendlyName(builder_->Symbols()) + "'",
|
TypeNameOf(ctor) + "'",
|
||||||
stmt->source());
|
stmt->source());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2000,7 +2059,7 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
||||||
Mark(deco);
|
Mark(deco);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* info = Variable(var, type);
|
auto* info = Variable(var, type, type_name);
|
||||||
if (!info) {
|
if (!info) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2071,13 +2130,19 @@ const sem::Type* Resolver::TypeOf(const ast::Literal* lit) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Resolver::SetType(ast::Expression* expr, const sem::Type* type) {
|
void Resolver::SetType(ast::Expression* expr, typ::Type type) {
|
||||||
SetType(expr, type, type->FriendlyName(builder_->Symbols()));
|
SetType(expr, type,
|
||||||
|
type.sem ? type.sem->FriendlyName(builder_->Symbols())
|
||||||
|
: type.ast->FriendlyName(builder_->Symbols()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Resolver::SetType(ast::Expression* expr,
|
void Resolver::SetType(ast::Expression* expr,
|
||||||
const sem::Type* type,
|
typ::Type type,
|
||||||
const std::string& type_name) {
|
const std::string& type_name) {
|
||||||
|
if (!type.sem) {
|
||||||
|
type.sem = Type(type.ast);
|
||||||
|
TINT_ASSERT(type.sem);
|
||||||
|
}
|
||||||
if (expr_info_.count(expr)) {
|
if (expr_info_.count(expr)) {
|
||||||
TINT_ICE(builder_->Diagnostics())
|
TINT_ICE(builder_->Diagnostics())
|
||||||
<< "SetType() called twice for the same expression";
|
<< "SetType() called twice for the same expression";
|
||||||
|
@ -2195,7 +2260,7 @@ void Resolver::CreateSemanticNodes() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::DefaultAlignAndSize(sem::Type* ty,
|
bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
|
||||||
uint32_t& align,
|
uint32_t& align,
|
||||||
uint32_t& size,
|
uint32_t& size,
|
||||||
const Source& source) {
|
const Source& source) {
|
||||||
|
@ -2363,24 +2428,24 @@ bool Resolver::ValidateArrayStrideDecoration(const ast::StrideDecoration* deco,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::ValidateStructure(const sem::StructType* st) {
|
bool Resolver::ValidateStructure(const StructInfo* st) {
|
||||||
for (auto* member : st->impl()->members()) {
|
for (auto* member : st->members) {
|
||||||
if (auto* r = member->type()->UnwrapAll()->As<sem::ArrayType>()) {
|
if (auto* r = member->Type()->UnwrapAll()->As<sem::ArrayType>()) {
|
||||||
if (r->IsRuntimeArray()) {
|
if (r->IsRuntimeArray()) {
|
||||||
if (member != st->impl()->members().back()) {
|
if (member != st->members.back()) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"v-0015",
|
"v-0015",
|
||||||
"runtime arrays may only appear as the last member of a struct",
|
"runtime arrays may only appear as the last member of a struct",
|
||||||
member->source());
|
member->Declaration()->source());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!st->IsBlockDecorated()) {
|
if (!st->type->impl()->IsBlockDecorated()) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"v-0015",
|
"v-0015",
|
||||||
"a struct containing a runtime-sized array "
|
"a struct containing a runtime-sized array "
|
||||||
"requires the [[block]] attribute: '" +
|
"requires the [[block]] attribute: '" +
|
||||||
builder_->Symbols().NameFor(st->impl()->name()) + "'",
|
builder_->Symbols().NameFor(st->type->impl()->name()) + "'",
|
||||||
member->source());
|
member->Declaration()->source());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2394,7 +2459,7 @@ bool Resolver::ValidateStructure(const sem::StructType* st) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* deco : member->decorations()) {
|
for (auto* deco : member->Declaration()->decorations()) {
|
||||||
if (!(deco->Is<ast::BuiltinDecoration>() ||
|
if (!(deco->Is<ast::BuiltinDecoration>() ||
|
||||||
deco->Is<ast::LocationDecoration>() ||
|
deco->Is<ast::LocationDecoration>() ||
|
||||||
deco->Is<ast::StructMemberOffsetDecoration>() ||
|
deco->Is<ast::StructMemberOffsetDecoration>() ||
|
||||||
|
@ -2407,7 +2472,7 @@ bool Resolver::ValidateStructure(const sem::StructType* st) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* deco : st->impl()->decorations()) {
|
for (auto* deco : st->type->impl()->decorations()) {
|
||||||
if (!(deco->Is<ast::StructBlockDecoration>())) {
|
if (!(deco->Is<ast::StructBlockDecoration>())) {
|
||||||
diagnostics_.add_error("decoration is not valid for struct declarations",
|
diagnostics_.add_error("decoration is not valid for struct declarations",
|
||||||
deco->source());
|
deco->source());
|
||||||
|
@ -2425,15 +2490,10 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
|
||||||
return info_it->second;
|
return info_it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mark(str->impl());
|
|
||||||
for (auto* deco : str->impl()->decorations()) {
|
for (auto* deco : str->impl()->decorations()) {
|
||||||
Mark(deco);
|
Mark(deco);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ValidateStructure(str)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
sem::StructMemberList sem_members;
|
sem::StructMemberList sem_members;
|
||||||
sem_members.reserve(str->impl()->members().size());
|
sem_members.reserve(str->impl()->members().size());
|
||||||
|
|
||||||
|
@ -2454,12 +2514,16 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
|
||||||
for (auto* member : str->impl()->members()) {
|
for (auto* member : str->impl()->members()) {
|
||||||
Mark(member);
|
Mark(member);
|
||||||
|
|
||||||
auto type = member->type();
|
// Resolve member type
|
||||||
|
auto* type = Type(member->type());
|
||||||
|
if (!type) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// First check the member type is legal
|
// Validate member type
|
||||||
if (!IsStorable(type)) {
|
if (!IsStorable(type)) {
|
||||||
builder_->Diagnostics().add_error(
|
builder_->Diagnostics().add_error(
|
||||||
std::string(type->FriendlyName(builder_->Symbols())) +
|
type->FriendlyName(builder_->Symbols()) +
|
||||||
" cannot be used as the type of a structure member");
|
" cannot be used as the type of a structure member");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2518,8 +2582,8 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
|
||||||
|
|
||||||
offset = utils::RoundUp(align, offset);
|
offset = utils::RoundUp(align, offset);
|
||||||
|
|
||||||
auto* sem_member =
|
auto* sem_member = builder_->create<sem::StructMember>(
|
||||||
builder_->create<sem::StructMember>(member, type, offset, align, size);
|
member, const_cast<sem::Type*>(type), offset, align, size);
|
||||||
builder_->Sem().Add(member, sem_member);
|
builder_->Sem().Add(member, sem_member);
|
||||||
sem_members.emplace_back(sem_member);
|
sem_members.emplace_back(sem_member);
|
||||||
|
|
||||||
|
@ -2531,11 +2595,17 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
|
||||||
struct_size = utils::RoundUp(struct_align, struct_size);
|
struct_size = utils::RoundUp(struct_align, struct_size);
|
||||||
|
|
||||||
auto* info = struct_infos_.Create();
|
auto* info = struct_infos_.Create();
|
||||||
|
info->type = str;
|
||||||
info->members = std::move(sem_members);
|
info->members = std::move(sem_members);
|
||||||
info->align = struct_align;
|
info->align = struct_align;
|
||||||
info->size = struct_size;
|
info->size = struct_size;
|
||||||
info->size_no_padding = size_no_padding;
|
info->size_no_padding = size_no_padding;
|
||||||
struct_info_.emplace(str, info);
|
struct_info_.emplace(str, info);
|
||||||
|
|
||||||
|
if (!ValidateStructure(info)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2745,13 +2815,13 @@ bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
|
||||||
return true; // Already applied
|
return true; // Already applied
|
||||||
}
|
}
|
||||||
info->storage_class_usage.emplace(sc);
|
info->storage_class_usage.emplace(sc);
|
||||||
for (auto* member : str->impl()->members()) {
|
for (auto* member : info->members) {
|
||||||
if (!ApplyStorageClassUsageToType(sc, member->type(), usage)) {
|
if (!ApplyStorageClassUsageToType(sc, member->Type(), usage)) {
|
||||||
std::stringstream err;
|
std::stringstream err;
|
||||||
err << "while analysing structure member "
|
err << "while analysing structure member "
|
||||||
<< str->FriendlyName(builder_->Symbols()) << "."
|
<< str->FriendlyName(builder_->Symbols()) << "."
|
||||||
<< builder_->Symbols().NameFor(member->symbol());
|
<< builder_->Symbols().NameFor(member->Declaration()->symbol());
|
||||||
diagnostics_.add_note(err.str(), member->source());
|
diagnostics_.add_note(err.str(), member->Declaration()->source());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2798,6 +2868,11 @@ const sem::Type* Resolver::Canonical(const sem::Type* type) {
|
||||||
using Type = sem::Type;
|
using Type = sem::Type;
|
||||||
using Vector = sem::Vector;
|
using Vector = sem::Vector;
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
TINT_ICE(diagnostics_) << "Canonical() called with nullptr";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
std::function<const Type*(const Type*)> make_canonical;
|
std::function<const Type*(const Type*)> make_canonical;
|
||||||
make_canonical = [&](const Type* t) -> const sem::Type* {
|
make_canonical = [&](const Type* t) -> const sem::Type* {
|
||||||
// Unwrap alias sequence
|
// Unwrap alias sequence
|
||||||
|
|
|
@ -73,11 +73,11 @@ class Resolver {
|
||||||
|
|
||||||
/// @param type the given type
|
/// @param type the given type
|
||||||
/// @returns true if the given type is storable
|
/// @returns true if the given type is storable
|
||||||
static bool IsStorable(const sem::Type* type);
|
bool IsStorable(const sem::Type* type);
|
||||||
|
|
||||||
/// @param type the given type
|
/// @param type the given type
|
||||||
/// @returns true if the given type is host-shareable
|
/// @returns true if the given type is host-shareable
|
||||||
static bool IsHostShareable(const sem::Type* type);
|
bool IsHostShareable(const sem::Type* type);
|
||||||
|
|
||||||
/// @param lhs the assignment store type (non-pointer)
|
/// @param lhs the assignment store type (non-pointer)
|
||||||
/// @param rhs the assignment source type (non-pointer or pointer with
|
/// @param rhs the assignment source type (non-pointer or pointer with
|
||||||
|
@ -148,6 +148,7 @@ class Resolver {
|
||||||
StructInfo();
|
StructInfo();
|
||||||
~StructInfo();
|
~StructInfo();
|
||||||
|
|
||||||
|
sem::StructType const* type = nullptr;
|
||||||
std::vector<const sem::StructMember*> members;
|
std::vector<const sem::StructMember*> members;
|
||||||
uint32_t align = 0;
|
uint32_t align = 0;
|
||||||
uint32_t size = 0;
|
uint32_t size = 0;
|
||||||
|
@ -253,16 +254,14 @@ class Resolver {
|
||||||
bool ValidateFunction(const ast::Function* func, const FunctionInfo* info);
|
bool ValidateFunction(const ast::Function* func, const FunctionInfo* info);
|
||||||
bool ValidateGlobalVariable(const VariableInfo* var);
|
bool ValidateGlobalVariable(const VariableInfo* var);
|
||||||
bool ValidateMatrixConstructor(const ast::TypeConstructorExpression* ctor,
|
bool ValidateMatrixConstructor(const ast::TypeConstructorExpression* ctor,
|
||||||
const sem::Matrix* matrix_type,
|
const sem::Matrix* matrix_type);
|
||||||
const ast::ExpressionList& values);
|
|
||||||
bool ValidateParameter(const ast::Variable* param);
|
bool ValidateParameter(const ast::Variable* param);
|
||||||
bool ValidateReturn(const ast::ReturnStatement* ret);
|
bool ValidateReturn(const ast::ReturnStatement* ret);
|
||||||
bool ValidateStructure(const sem::StructType* st);
|
bool ValidateStructure(const StructInfo* st);
|
||||||
bool ValidateSwitch(const ast::SwitchStatement* s);
|
bool ValidateSwitch(const ast::SwitchStatement* s);
|
||||||
bool ValidateVariable(const ast::Variable* param);
|
bool ValidateVariable(const ast::Variable* param);
|
||||||
bool ValidateVectorConstructor(const ast::TypeConstructorExpression* ctor,
|
bool ValidateVectorConstructor(const ast::TypeConstructorExpression* ctor,
|
||||||
const sem::Vector* vec_type,
|
const sem::Vector* vec_type);
|
||||||
const ast::ExpressionList& values);
|
|
||||||
|
|
||||||
/// @returns the sem::Type for the ast::Type `ty`, building it if it
|
/// @returns the sem::Type for the ast::Type `ty`, building it if it
|
||||||
/// hasn't been constructed already. If an error is raised, nullptr is
|
/// hasn't been constructed already. If an error is raised, nullptr is
|
||||||
|
@ -284,9 +283,12 @@ class Resolver {
|
||||||
/// @returns the VariableInfo for the variable `var`, building it if it hasn't
|
/// @returns the VariableInfo for the variable `var`, building it if it hasn't
|
||||||
/// been constructed already. If an error is raised, nullptr is returned.
|
/// been constructed already. If an error is raised, nullptr is returned.
|
||||||
/// @param var the variable to create or return the `VariableInfo` for
|
/// @param var the variable to create or return the `VariableInfo` for
|
||||||
/// @param type optional type of `var` to use instead of
|
/// @param type optional type of `var` to use instead of `var->type()`.
|
||||||
/// `var->declared_type()`. For type inference.
|
/// @param type_name optional type name of `var` to use instead of
|
||||||
VariableInfo* Variable(ast::Variable* var, const sem::Type* type = nullptr);
|
/// `var->type()->FriendlyName()`.
|
||||||
|
VariableInfo* Variable(ast::Variable* var,
|
||||||
|
const sem::Type* type = nullptr,
|
||||||
|
std::string type_name = "");
|
||||||
|
|
||||||
/// Records the storage class usage for the given type, and any transient
|
/// Records the storage class usage for the given type, and any transient
|
||||||
/// dependencies of the type. Validates that the type can be used for the
|
/// dependencies of the type. Validates that the type can be used for the
|
||||||
|
@ -304,7 +306,7 @@ class Resolver {
|
||||||
/// @param size the output default size in bytes for the type `ty`
|
/// @param size the output default size in bytes for the type `ty`
|
||||||
/// @param source the Source of the variable declaration of type `ty`
|
/// @param source the Source of the variable declaration of type `ty`
|
||||||
/// @returns true on success, false on error
|
/// @returns true on success, false on error
|
||||||
bool DefaultAlignAndSize(sem::Type* ty,
|
bool DefaultAlignAndSize(const sem::Type* ty,
|
||||||
uint32_t& align,
|
uint32_t& align,
|
||||||
uint32_t& size,
|
uint32_t& size,
|
||||||
const Source& source);
|
const Source& source);
|
||||||
|
@ -325,7 +327,7 @@ class Resolver {
|
||||||
/// assigns this semantic node to the expression `expr`.
|
/// assigns this semantic node to the expression `expr`.
|
||||||
/// @param expr the expression
|
/// @param expr the expression
|
||||||
/// @param type the resolved type
|
/// @param type the resolved type
|
||||||
void SetType(ast::Expression* expr, const sem::Type* type);
|
void SetType(ast::Expression* expr, typ::Type type);
|
||||||
|
|
||||||
/// Creates a sem::Expression node with the resolved type `type`, the declared
|
/// Creates a sem::Expression node with the resolved type `type`, the declared
|
||||||
/// type name `type_name` and assigns this semantic node to the expression
|
/// type name `type_name` and assigns this semantic node to the expression
|
||||||
|
@ -334,7 +336,7 @@ class Resolver {
|
||||||
/// @param type the resolved type
|
/// @param type the resolved type
|
||||||
/// @param type_name the declared type name
|
/// @param type_name the declared type name
|
||||||
void SetType(ast::Expression* expr,
|
void SetType(ast::Expression* expr,
|
||||||
const sem::Type* type,
|
typ::Type type,
|
||||||
const std::string& type_name);
|
const std::string& type_name);
|
||||||
|
|
||||||
/// Constructs a new BlockInfo with the given type and with #current_block_ as
|
/// Constructs a new BlockInfo with the given type and with #current_block_ as
|
||||||
|
@ -369,6 +371,7 @@ class Resolver {
|
||||||
std::unordered_map<const ast::Expression*, ExpressionInfo> expr_info_;
|
std::unordered_map<const ast::Expression*, ExpressionInfo> expr_info_;
|
||||||
std::unordered_map<const sem::StructType*, StructInfo*> struct_info_;
|
std::unordered_map<const sem::StructType*, StructInfo*> struct_info_;
|
||||||
std::unordered_map<const sem::Type*, const sem::Type*> type_to_canonical_;
|
std::unordered_map<const sem::Type*, const sem::Type*> type_to_canonical_;
|
||||||
|
std::unordered_map<Symbol, const sem::Type*> named_types_;
|
||||||
std::unordered_set<const ast::Node*> marked_;
|
std::unordered_set<const ast::Node*> marked_;
|
||||||
FunctionInfo* current_function_ = nullptr;
|
FunctionInfo* current_function_ = nullptr;
|
||||||
sem::Statement* current_statement_ = nullptr;
|
sem::Statement* current_statement_ = nullptr;
|
||||||
|
|
|
@ -1024,15 +1024,15 @@ namespace ExprBinaryTest {
|
||||||
|
|
||||||
struct Params {
|
struct Params {
|
||||||
ast::BinaryOp op;
|
ast::BinaryOp op;
|
||||||
create_type_func_ptr create_lhs_type;
|
create_ast_type_func_ptr create_lhs_type;
|
||||||
create_type_func_ptr create_rhs_type;
|
create_ast_type_func_ptr create_rhs_type;
|
||||||
create_type_func_ptr create_result_type;
|
create_sem_type_func_ptr create_result_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr create_type_func_ptr all_create_type_funcs[] = {
|
static constexpr create_ast_type_func_ptr all_create_type_funcs[] = {
|
||||||
ty_bool_, ty_u32, ty_i32, ty_f32,
|
ast_bool, ast_u32, ast_i32, ast_f32,
|
||||||
ty_vec3<bool>, ty_vec3<i32>, ty_vec3<u32>, ty_vec3<f32>,
|
ast_vec3<bool>, ast_vec3<i32>, ast_vec3<u32>, ast_vec3<f32>,
|
||||||
ty_mat3x3<i32>, ty_mat3x3<u32>, ty_mat3x3<f32>};
|
ast_mat3x3<i32>, ast_mat3x3<u32>, ast_mat3x3<f32>};
|
||||||
|
|
||||||
// A list of all valid test cases for 'lhs op rhs', except that for vecN and
|
// A list of all valid test cases for 'lhs op rhs', except that for vecN and
|
||||||
// matNxN, we only test N=3.
|
// matNxN, we only test N=3.
|
||||||
|
@ -1041,156 +1041,163 @@ static constexpr Params all_valid_cases[] = {
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl.html#logical-expr
|
// https://gpuweb.github.io/gpuweb/wgsl.html#logical-expr
|
||||||
|
|
||||||
// Binary logical expressions
|
// Binary logical expressions
|
||||||
Params{Op::kLogicalAnd, ty_bool_, ty_bool_, ty_bool_},
|
Params{Op::kLogicalAnd, ast_bool, ast_bool, sem_bool},
|
||||||
Params{Op::kLogicalOr, ty_bool_, ty_bool_, ty_bool_},
|
Params{Op::kLogicalOr, ast_bool, ast_bool, sem_bool},
|
||||||
|
|
||||||
Params{Op::kAnd, ty_bool_, ty_bool_, ty_bool_},
|
Params{Op::kAnd, ast_bool, ast_bool, sem_bool},
|
||||||
Params{Op::kOr, ty_bool_, ty_bool_, ty_bool_},
|
Params{Op::kOr, ast_bool, ast_bool, sem_bool},
|
||||||
Params{Op::kAnd, ty_vec3<bool>, ty_vec3<bool>, ty_vec3<bool>},
|
Params{Op::kAnd, ast_vec3<bool>, ast_vec3<bool>, sem_vec3<sem_bool>},
|
||||||
Params{Op::kOr, ty_vec3<bool>, ty_vec3<bool>, ty_vec3<bool>},
|
Params{Op::kOr, ast_vec3<bool>, ast_vec3<bool>, sem_vec3<sem_bool>},
|
||||||
|
|
||||||
// Arithmetic expressions
|
// Arithmetic expressions
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl.html#arithmetic-expr
|
// https://gpuweb.github.io/gpuweb/wgsl.html#arithmetic-expr
|
||||||
|
|
||||||
// Binary arithmetic expressions over scalars
|
// Binary arithmetic expressions over scalars
|
||||||
Params{Op::kAdd, ty_i32, ty_i32, ty_i32},
|
Params{Op::kAdd, ast_i32, ast_i32, sem_i32},
|
||||||
Params{Op::kSubtract, ty_i32, ty_i32, ty_i32},
|
Params{Op::kSubtract, ast_i32, ast_i32, sem_i32},
|
||||||
Params{Op::kMultiply, ty_i32, ty_i32, ty_i32},
|
Params{Op::kMultiply, ast_i32, ast_i32, sem_i32},
|
||||||
Params{Op::kDivide, ty_i32, ty_i32, ty_i32},
|
Params{Op::kDivide, ast_i32, ast_i32, sem_i32},
|
||||||
Params{Op::kModulo, ty_i32, ty_i32, ty_i32},
|
Params{Op::kModulo, ast_i32, ast_i32, sem_i32},
|
||||||
|
|
||||||
Params{Op::kAdd, ty_u32, ty_u32, ty_u32},
|
Params{Op::kAdd, ast_u32, ast_u32, sem_u32},
|
||||||
Params{Op::kSubtract, ty_u32, ty_u32, ty_u32},
|
Params{Op::kSubtract, ast_u32, ast_u32, sem_u32},
|
||||||
Params{Op::kMultiply, ty_u32, ty_u32, ty_u32},
|
Params{Op::kMultiply, ast_u32, ast_u32, sem_u32},
|
||||||
Params{Op::kDivide, ty_u32, ty_u32, ty_u32},
|
Params{Op::kDivide, ast_u32, ast_u32, sem_u32},
|
||||||
Params{Op::kModulo, ty_u32, ty_u32, ty_u32},
|
Params{Op::kModulo, ast_u32, ast_u32, sem_u32},
|
||||||
|
|
||||||
Params{Op::kAdd, ty_f32, ty_f32, ty_f32},
|
Params{Op::kAdd, ast_f32, ast_f32, sem_f32},
|
||||||
Params{Op::kSubtract, ty_f32, ty_f32, ty_f32},
|
Params{Op::kSubtract, ast_f32, ast_f32, sem_f32},
|
||||||
Params{Op::kMultiply, ty_f32, ty_f32, ty_f32},
|
Params{Op::kMultiply, ast_f32, ast_f32, sem_f32},
|
||||||
Params{Op::kDivide, ty_f32, ty_f32, ty_f32},
|
Params{Op::kDivide, ast_f32, ast_f32, sem_f32},
|
||||||
Params{Op::kModulo, ty_f32, ty_f32, ty_f32},
|
Params{Op::kModulo, ast_f32, ast_f32, sem_f32},
|
||||||
|
|
||||||
// Binary arithmetic expressions over vectors
|
// Binary arithmetic expressions over vectors
|
||||||
Params{Op::kAdd, ty_vec3<i32>, ty_vec3<i32>, ty_vec3<i32>},
|
Params{Op::kAdd, ast_vec3<i32>, ast_vec3<i32>, sem_vec3<sem_i32>},
|
||||||
Params{Op::kSubtract, ty_vec3<i32>, ty_vec3<i32>, ty_vec3<i32>},
|
Params{Op::kSubtract, ast_vec3<i32>, ast_vec3<i32>, sem_vec3<sem_i32>},
|
||||||
Params{Op::kMultiply, ty_vec3<i32>, ty_vec3<i32>, ty_vec3<i32>},
|
Params{Op::kMultiply, ast_vec3<i32>, ast_vec3<i32>, sem_vec3<sem_i32>},
|
||||||
Params{Op::kDivide, ty_vec3<i32>, ty_vec3<i32>, ty_vec3<i32>},
|
Params{Op::kDivide, ast_vec3<i32>, ast_vec3<i32>, sem_vec3<sem_i32>},
|
||||||
Params{Op::kModulo, ty_vec3<i32>, ty_vec3<i32>, ty_vec3<i32>},
|
Params{Op::kModulo, ast_vec3<i32>, ast_vec3<i32>, sem_vec3<sem_i32>},
|
||||||
|
|
||||||
Params{Op::kAdd, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<u32>},
|
Params{Op::kAdd, ast_vec3<u32>, ast_vec3<u32>, sem_vec3<sem_u32>},
|
||||||
Params{Op::kSubtract, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<u32>},
|
Params{Op::kSubtract, ast_vec3<u32>, ast_vec3<u32>, sem_vec3<sem_u32>},
|
||||||
Params{Op::kMultiply, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<u32>},
|
Params{Op::kMultiply, ast_vec3<u32>, ast_vec3<u32>, sem_vec3<sem_u32>},
|
||||||
Params{Op::kDivide, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<u32>},
|
Params{Op::kDivide, ast_vec3<u32>, ast_vec3<u32>, sem_vec3<sem_u32>},
|
||||||
Params{Op::kModulo, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<u32>},
|
Params{Op::kModulo, ast_vec3<u32>, ast_vec3<u32>, sem_vec3<sem_u32>},
|
||||||
|
|
||||||
Params{Op::kAdd, ty_vec3<f32>, ty_vec3<f32>, ty_vec3<f32>},
|
Params{Op::kAdd, ast_vec3<f32>, ast_vec3<f32>, sem_vec3<sem_f32>},
|
||||||
Params{Op::kSubtract, ty_vec3<f32>, ty_vec3<f32>, ty_vec3<f32>},
|
Params{Op::kSubtract, ast_vec3<f32>, ast_vec3<f32>, sem_vec3<sem_f32>},
|
||||||
Params{Op::kMultiply, ty_vec3<f32>, ty_vec3<f32>, ty_vec3<f32>},
|
Params{Op::kMultiply, ast_vec3<f32>, ast_vec3<f32>, sem_vec3<sem_f32>},
|
||||||
Params{Op::kDivide, ty_vec3<f32>, ty_vec3<f32>, ty_vec3<f32>},
|
Params{Op::kDivide, ast_vec3<f32>, ast_vec3<f32>, sem_vec3<sem_f32>},
|
||||||
Params{Op::kModulo, ty_vec3<f32>, ty_vec3<f32>, ty_vec3<f32>},
|
Params{Op::kModulo, ast_vec3<f32>, ast_vec3<f32>, sem_vec3<sem_f32>},
|
||||||
|
|
||||||
// Binary arithmetic expressions with mixed scalar, vector, and matrix
|
// Binary arithmetic expressions with mixed scalar, vector, and matrix
|
||||||
// operands
|
// operands
|
||||||
Params{Op::kMultiply, ty_vec3<f32>, ty_f32, ty_vec3<f32>},
|
Params{Op::kMultiply, ast_vec3<f32>, ast_f32, sem_vec3<sem_f32>},
|
||||||
Params{Op::kMultiply, ty_f32, ty_vec3<f32>, ty_vec3<f32>},
|
Params{Op::kMultiply, ast_f32, ast_vec3<f32>, sem_vec3<sem_f32>},
|
||||||
|
|
||||||
Params{Op::kMultiply, ty_mat3x3<f32>, ty_f32, ty_mat3x3<f32>},
|
Params{Op::kMultiply, ast_mat3x3<f32>, ast_f32, sem_mat3x3<sem_f32>},
|
||||||
Params{Op::kMultiply, ty_f32, ty_mat3x3<f32>, ty_mat3x3<f32>},
|
Params{Op::kMultiply, ast_f32, ast_mat3x3<f32>, sem_mat3x3<sem_f32>},
|
||||||
|
|
||||||
Params{Op::kMultiply, ty_vec3<f32>, ty_mat3x3<f32>, ty_vec3<f32>},
|
Params{Op::kMultiply, ast_vec3<f32>, ast_mat3x3<f32>, sem_vec3<sem_f32>},
|
||||||
Params{Op::kMultiply, ty_mat3x3<f32>, ty_vec3<f32>, ty_vec3<f32>},
|
Params{Op::kMultiply, ast_mat3x3<f32>, ast_vec3<f32>, sem_vec3<sem_f32>},
|
||||||
Params{Op::kMultiply, ty_mat3x3<f32>, ty_mat3x3<f32>, ty_mat3x3<f32>},
|
Params{Op::kMultiply, ast_mat3x3<f32>, ast_mat3x3<f32>,
|
||||||
|
sem_mat3x3<sem_f32>},
|
||||||
|
|
||||||
// Comparison expressions
|
// Comparison expressions
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl.html#comparison-expr
|
// https://gpuweb.github.io/gpuweb/wgsl.html#comparison-expr
|
||||||
|
|
||||||
// Comparisons over scalars
|
// Comparisons over scalars
|
||||||
Params{Op::kEqual, ty_bool_, ty_bool_, ty_bool_},
|
Params{Op::kEqual, ast_bool, ast_bool, sem_bool},
|
||||||
Params{Op::kNotEqual, ty_bool_, ty_bool_, ty_bool_},
|
Params{Op::kNotEqual, ast_bool, ast_bool, sem_bool},
|
||||||
|
|
||||||
Params{Op::kEqual, ty_i32, ty_i32, ty_bool_},
|
Params{Op::kEqual, ast_i32, ast_i32, sem_bool},
|
||||||
Params{Op::kNotEqual, ty_i32, ty_i32, ty_bool_},
|
Params{Op::kNotEqual, ast_i32, ast_i32, sem_bool},
|
||||||
Params{Op::kLessThan, ty_i32, ty_i32, ty_bool_},
|
Params{Op::kLessThan, ast_i32, ast_i32, sem_bool},
|
||||||
Params{Op::kLessThanEqual, ty_i32, ty_i32, ty_bool_},
|
Params{Op::kLessThanEqual, ast_i32, ast_i32, sem_bool},
|
||||||
Params{Op::kGreaterThan, ty_i32, ty_i32, ty_bool_},
|
Params{Op::kGreaterThan, ast_i32, ast_i32, sem_bool},
|
||||||
Params{Op::kGreaterThanEqual, ty_i32, ty_i32, ty_bool_},
|
Params{Op::kGreaterThanEqual, ast_i32, ast_i32, sem_bool},
|
||||||
|
|
||||||
Params{Op::kEqual, ty_u32, ty_u32, ty_bool_},
|
Params{Op::kEqual, ast_u32, ast_u32, sem_bool},
|
||||||
Params{Op::kNotEqual, ty_u32, ty_u32, ty_bool_},
|
Params{Op::kNotEqual, ast_u32, ast_u32, sem_bool},
|
||||||
Params{Op::kLessThan, ty_u32, ty_u32, ty_bool_},
|
Params{Op::kLessThan, ast_u32, ast_u32, sem_bool},
|
||||||
Params{Op::kLessThanEqual, ty_u32, ty_u32, ty_bool_},
|
Params{Op::kLessThanEqual, ast_u32, ast_u32, sem_bool},
|
||||||
Params{Op::kGreaterThan, ty_u32, ty_u32, ty_bool_},
|
Params{Op::kGreaterThan, ast_u32, ast_u32, sem_bool},
|
||||||
Params{Op::kGreaterThanEqual, ty_u32, ty_u32, ty_bool_},
|
Params{Op::kGreaterThanEqual, ast_u32, ast_u32, sem_bool},
|
||||||
|
|
||||||
Params{Op::kEqual, ty_f32, ty_f32, ty_bool_},
|
Params{Op::kEqual, ast_f32, ast_f32, sem_bool},
|
||||||
Params{Op::kNotEqual, ty_f32, ty_f32, ty_bool_},
|
Params{Op::kNotEqual, ast_f32, ast_f32, sem_bool},
|
||||||
Params{Op::kLessThan, ty_f32, ty_f32, ty_bool_},
|
Params{Op::kLessThan, ast_f32, ast_f32, sem_bool},
|
||||||
Params{Op::kLessThanEqual, ty_f32, ty_f32, ty_bool_},
|
Params{Op::kLessThanEqual, ast_f32, ast_f32, sem_bool},
|
||||||
Params{Op::kGreaterThan, ty_f32, ty_f32, ty_bool_},
|
Params{Op::kGreaterThan, ast_f32, ast_f32, sem_bool},
|
||||||
Params{Op::kGreaterThanEqual, ty_f32, ty_f32, ty_bool_},
|
Params{Op::kGreaterThanEqual, ast_f32, ast_f32, sem_bool},
|
||||||
|
|
||||||
// Comparisons over vectors
|
// Comparisons over vectors
|
||||||
Params{Op::kEqual, ty_vec3<bool>, ty_vec3<bool>, ty_vec3<bool>},
|
Params{Op::kEqual, ast_vec3<bool>, ast_vec3<bool>, sem_vec3<sem_bool>},
|
||||||
Params{Op::kNotEqual, ty_vec3<bool>, ty_vec3<bool>, ty_vec3<bool>},
|
Params{Op::kNotEqual, ast_vec3<bool>, ast_vec3<bool>, sem_vec3<sem_bool>},
|
||||||
|
|
||||||
Params{Op::kEqual, ty_vec3<i32>, ty_vec3<i32>, ty_vec3<bool>},
|
Params{Op::kEqual, ast_vec3<i32>, ast_vec3<i32>, sem_vec3<sem_bool>},
|
||||||
Params{Op::kNotEqual, ty_vec3<i32>, ty_vec3<i32>, ty_vec3<bool>},
|
Params{Op::kNotEqual, ast_vec3<i32>, ast_vec3<i32>, sem_vec3<sem_bool>},
|
||||||
Params{Op::kLessThan, ty_vec3<i32>, ty_vec3<i32>, ty_vec3<bool>},
|
Params{Op::kLessThan, ast_vec3<i32>, ast_vec3<i32>, sem_vec3<sem_bool>},
|
||||||
Params{Op::kLessThanEqual, ty_vec3<i32>, ty_vec3<i32>, ty_vec3<bool>},
|
Params{Op::kLessThanEqual, ast_vec3<i32>, ast_vec3<i32>,
|
||||||
Params{Op::kGreaterThan, ty_vec3<i32>, ty_vec3<i32>, ty_vec3<bool>},
|
sem_vec3<sem_bool>},
|
||||||
Params{Op::kGreaterThanEqual, ty_vec3<i32>, ty_vec3<i32>, ty_vec3<bool>},
|
Params{Op::kGreaterThan, ast_vec3<i32>, ast_vec3<i32>, sem_vec3<sem_bool>},
|
||||||
|
Params{Op::kGreaterThanEqual, ast_vec3<i32>, ast_vec3<i32>,
|
||||||
|
sem_vec3<sem_bool>},
|
||||||
|
|
||||||
Params{Op::kEqual, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<bool>},
|
Params{Op::kEqual, ast_vec3<u32>, ast_vec3<u32>, sem_vec3<sem_bool>},
|
||||||
Params{Op::kNotEqual, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<bool>},
|
Params{Op::kNotEqual, ast_vec3<u32>, ast_vec3<u32>, sem_vec3<sem_bool>},
|
||||||
Params{Op::kLessThan, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<bool>},
|
Params{Op::kLessThan, ast_vec3<u32>, ast_vec3<u32>, sem_vec3<sem_bool>},
|
||||||
Params{Op::kLessThanEqual, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<bool>},
|
Params{Op::kLessThanEqual, ast_vec3<u32>, ast_vec3<u32>,
|
||||||
Params{Op::kGreaterThan, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<bool>},
|
sem_vec3<sem_bool>},
|
||||||
Params{Op::kGreaterThanEqual, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<bool>},
|
Params{Op::kGreaterThan, ast_vec3<u32>, ast_vec3<u32>, sem_vec3<sem_bool>},
|
||||||
|
Params{Op::kGreaterThanEqual, ast_vec3<u32>, ast_vec3<u32>,
|
||||||
|
sem_vec3<sem_bool>},
|
||||||
|
|
||||||
Params{Op::kEqual, ty_vec3<f32>, ty_vec3<f32>, ty_vec3<bool>},
|
Params{Op::kEqual, ast_vec3<f32>, ast_vec3<f32>, sem_vec3<sem_bool>},
|
||||||
Params{Op::kNotEqual, ty_vec3<f32>, ty_vec3<f32>, ty_vec3<bool>},
|
Params{Op::kNotEqual, ast_vec3<f32>, ast_vec3<f32>, sem_vec3<sem_bool>},
|
||||||
Params{Op::kLessThan, ty_vec3<f32>, ty_vec3<f32>, ty_vec3<bool>},
|
Params{Op::kLessThan, ast_vec3<f32>, ast_vec3<f32>, sem_vec3<sem_bool>},
|
||||||
Params{Op::kLessThanEqual, ty_vec3<f32>, ty_vec3<f32>, ty_vec3<bool>},
|
Params{Op::kLessThanEqual, ast_vec3<f32>, ast_vec3<f32>,
|
||||||
Params{Op::kGreaterThan, ty_vec3<f32>, ty_vec3<f32>, ty_vec3<bool>},
|
sem_vec3<sem_bool>},
|
||||||
Params{Op::kGreaterThanEqual, ty_vec3<f32>, ty_vec3<f32>, ty_vec3<bool>},
|
Params{Op::kGreaterThan, ast_vec3<f32>, ast_vec3<f32>, sem_vec3<sem_bool>},
|
||||||
|
Params{Op::kGreaterThanEqual, ast_vec3<f32>, ast_vec3<f32>,
|
||||||
|
sem_vec3<sem_bool>},
|
||||||
|
|
||||||
// Bit expressions
|
// Bit expressions
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl.html#bit-expr
|
// https://gpuweb.github.io/gpuweb/wgsl.html#bit-expr
|
||||||
|
|
||||||
// Binary bitwise operations
|
// Binary bitwise operations
|
||||||
Params{Op::kOr, ty_i32, ty_i32, ty_i32},
|
Params{Op::kOr, ast_i32, ast_i32, sem_i32},
|
||||||
Params{Op::kAnd, ty_i32, ty_i32, ty_i32},
|
Params{Op::kAnd, ast_i32, ast_i32, sem_i32},
|
||||||
Params{Op::kXor, ty_i32, ty_i32, ty_i32},
|
Params{Op::kXor, ast_i32, ast_i32, sem_i32},
|
||||||
|
|
||||||
Params{Op::kOr, ty_u32, ty_u32, ty_u32},
|
Params{Op::kOr, ast_u32, ast_u32, sem_u32},
|
||||||
Params{Op::kAnd, ty_u32, ty_u32, ty_u32},
|
Params{Op::kAnd, ast_u32, ast_u32, sem_u32},
|
||||||
Params{Op::kXor, ty_u32, ty_u32, ty_u32},
|
Params{Op::kXor, ast_u32, ast_u32, sem_u32},
|
||||||
|
|
||||||
// Bit shift expressions
|
// Bit shift expressions
|
||||||
Params{Op::kShiftLeft, ty_i32, ty_u32, ty_i32},
|
Params{Op::kShiftLeft, ast_i32, ast_u32, sem_i32},
|
||||||
Params{Op::kShiftLeft, ty_vec3<i32>, ty_vec3<u32>, ty_vec3<i32>},
|
Params{Op::kShiftLeft, ast_vec3<i32>, ast_vec3<u32>, sem_vec3<sem_i32>},
|
||||||
|
|
||||||
Params{Op::kShiftLeft, ty_u32, ty_u32, ty_u32},
|
Params{Op::kShiftLeft, ast_u32, ast_u32, sem_u32},
|
||||||
Params{Op::kShiftLeft, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<u32>},
|
Params{Op::kShiftLeft, ast_vec3<u32>, ast_vec3<u32>, sem_vec3<sem_u32>},
|
||||||
|
|
||||||
Params{Op::kShiftRight, ty_i32, ty_u32, ty_i32},
|
Params{Op::kShiftRight, ast_i32, ast_u32, sem_i32},
|
||||||
Params{Op::kShiftRight, ty_vec3<i32>, ty_vec3<u32>, ty_vec3<i32>},
|
Params{Op::kShiftRight, ast_vec3<i32>, ast_vec3<u32>, sem_vec3<sem_i32>},
|
||||||
|
|
||||||
Params{Op::kShiftRight, ty_u32, ty_u32, ty_u32},
|
Params{Op::kShiftRight, ast_u32, ast_u32, sem_u32},
|
||||||
Params{Op::kShiftRight, ty_vec3<u32>, ty_vec3<u32>, ty_vec3<u32>}};
|
Params{Op::kShiftRight, ast_vec3<u32>, ast_vec3<u32>, sem_vec3<sem_u32>}};
|
||||||
|
|
||||||
using Expr_Binary_Test_Valid = ResolverTestWithParam<Params>;
|
using Expr_Binary_Test_Valid = ResolverTestWithParam<Params>;
|
||||||
TEST_P(Expr_Binary_Test_Valid, All) {
|
TEST_P(Expr_Binary_Test_Valid, All) {
|
||||||
auto& params = GetParam();
|
auto& params = GetParam();
|
||||||
|
|
||||||
auto lhs_type = params.create_lhs_type(ty);
|
auto* lhs_type = params.create_lhs_type(ty);
|
||||||
auto rhs_type = params.create_rhs_type(ty);
|
auto* rhs_type = params.create_rhs_type(ty);
|
||||||
auto result_type = params.create_result_type(ty);
|
auto* result_type = params.create_result_type(ty);
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << lhs_type->FriendlyName(Symbols()) << " " << params.op << " "
|
ss << FriendlyName(lhs_type) << " " << params.op << " "
|
||||||
<< rhs_type->FriendlyName(Symbols());
|
<< FriendlyName(rhs_type);
|
||||||
SCOPED_TRACE(ss.str());
|
SCOPED_TRACE(ss.str());
|
||||||
|
|
||||||
Global("lhs", lhs_type, ast::StorageClass::kInput);
|
Global("lhs", lhs_type, ast::StorageClass::kInput);
|
||||||
|
@ -1215,27 +1222,28 @@ TEST_P(Expr_Binary_Test_WithAlias_Valid, All) {
|
||||||
const Params& params = std::get<0>(GetParam());
|
const Params& params = std::get<0>(GetParam());
|
||||||
BinaryExprSide side = std::get<1>(GetParam());
|
BinaryExprSide side = std::get<1>(GetParam());
|
||||||
|
|
||||||
auto lhs_type = params.create_lhs_type(ty);
|
auto* lhs_type = params.create_lhs_type(ty);
|
||||||
auto rhs_type = params.create_rhs_type(ty);
|
auto* rhs_type = params.create_rhs_type(ty);
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << lhs_type->FriendlyName(Symbols()) << " " << params.op << " "
|
ss << FriendlyName(lhs_type) << " " << params.op << " "
|
||||||
<< rhs_type->FriendlyName(Symbols());
|
<< FriendlyName(rhs_type);
|
||||||
|
|
||||||
// For vectors and matrices, wrap the sub type in an alias
|
// For vectors and matrices, wrap the sub type in an alias
|
||||||
auto make_alias = [this](sem::Type* type) -> sem::Type* {
|
auto make_alias = [this](ast::Type* type) -> ast::Type* {
|
||||||
sem::Type* result;
|
if (auto* v = type->As<ast::Vector>()) {
|
||||||
if (auto* v = type->As<sem::Vector>()) {
|
auto alias = ty.alias(Symbols().New(), v->type());
|
||||||
result = create<sem::Vector>(
|
AST().AddConstructedType(alias);
|
||||||
create<sem::Alias>(Symbols().New(), v->type()), v->size());
|
return ty.vec(alias, v->size());
|
||||||
} else if (auto* m = type->As<sem::Matrix>()) {
|
|
||||||
result =
|
|
||||||
create<sem::Matrix>(create<sem::Alias>(Symbols().New(), m->type()),
|
|
||||||
m->rows(), m->columns());
|
|
||||||
} else {
|
|
||||||
result = create<sem::Alias>(Symbols().New(), type);
|
|
||||||
}
|
}
|
||||||
return result;
|
if (auto* m = type->As<ast::Matrix>()) {
|
||||||
|
auto alias = ty.alias(Symbols().New(), m->type());
|
||||||
|
AST().AddConstructedType(alias);
|
||||||
|
return ty.mat(alias, m->columns(), m->rows());
|
||||||
|
}
|
||||||
|
auto alias = ty.alias(Symbols().New(), type);
|
||||||
|
AST().AddConstructedType(alias);
|
||||||
|
return ty.type_name(alias.ast->name());
|
||||||
};
|
};
|
||||||
|
|
||||||
// Wrap in alias
|
// Wrap in alias
|
||||||
|
@ -1246,8 +1254,8 @@ TEST_P(Expr_Binary_Test_WithAlias_Valid, All) {
|
||||||
rhs_type = make_alias(rhs_type);
|
rhs_type = make_alias(rhs_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
ss << ", After aliasing: " << lhs_type->FriendlyName(Symbols()) << " "
|
ss << ", After aliasing: " << FriendlyName(lhs_type) << " " << params.op
|
||||||
<< params.op << " " << rhs_type->FriendlyName(Symbols());
|
<< " " << FriendlyName(rhs_type);
|
||||||
SCOPED_TRACE(ss.str());
|
SCOPED_TRACE(ss.str());
|
||||||
|
|
||||||
Global("lhs", lhs_type, ast::StorageClass::kInput);
|
Global("lhs", lhs_type, ast::StorageClass::kInput);
|
||||||
|
@ -1261,7 +1269,7 @@ TEST_P(Expr_Binary_Test_WithAlias_Valid, All) {
|
||||||
ASSERT_NE(TypeOf(expr), nullptr);
|
ASSERT_NE(TypeOf(expr), nullptr);
|
||||||
// TODO(amaiorano): Bring this back once we have a way to get the canonical
|
// TODO(amaiorano): Bring this back once we have a way to get the canonical
|
||||||
// type
|
// type
|
||||||
// auto* result_type = params.create_result_type(ty);
|
// auto* *result_type = params.create_result_type(ty);
|
||||||
// ASSERT_TRUE(TypeOf(expr) == result_type);
|
// ASSERT_TRUE(TypeOf(expr) == result_type);
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
@ -1273,10 +1281,10 @@ INSTANTIATE_TEST_SUITE_P(
|
||||||
BinaryExprSide::Both)));
|
BinaryExprSide::Both)));
|
||||||
|
|
||||||
using Expr_Binary_Test_Invalid =
|
using Expr_Binary_Test_Invalid =
|
||||||
ResolverTestWithParam<std::tuple<Params, create_type_func_ptr>>;
|
ResolverTestWithParam<std::tuple<Params, create_ast_type_func_ptr>>;
|
||||||
TEST_P(Expr_Binary_Test_Invalid, All) {
|
TEST_P(Expr_Binary_Test_Invalid, All) {
|
||||||
const Params& params = std::get<0>(GetParam());
|
const Params& params = std::get<0>(GetParam());
|
||||||
const create_type_func_ptr& create_type_func = std::get<1>(GetParam());
|
auto& create_type_func = std::get<1>(GetParam());
|
||||||
|
|
||||||
// Currently, for most operations, for a given lhs type, there is exactly one
|
// Currently, for most operations, for a given lhs type, there is exactly one
|
||||||
// rhs type allowed. The only exception is for multiplication, which allows
|
// rhs type allowed. The only exception is for multiplication, which allows
|
||||||
|
@ -1290,8 +1298,8 @@ TEST_P(Expr_Binary_Test_Invalid, All) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lhs_type = params.create_lhs_type(ty);
|
auto* lhs_type = params.create_lhs_type(ty);
|
||||||
auto rhs_type = create_type_func(ty);
|
auto* rhs_type = create_type_func(ty);
|
||||||
|
|
||||||
// Skip exceptions: multiplication of f32, vecN<f32>, and matNxN<f32>
|
// Skip exceptions: multiplication of f32, vecN<f32>, and matNxN<f32>
|
||||||
if (params.op == Op::kMultiply &&
|
if (params.op == Op::kMultiply &&
|
||||||
|
@ -1301,8 +1309,8 @@ TEST_P(Expr_Binary_Test_Invalid, All) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << lhs_type->FriendlyName(Symbols()) << " " << params.op << " "
|
ss << FriendlyName(lhs_type) << " " << params.op << " "
|
||||||
<< rhs_type->FriendlyName(Symbols());
|
<< FriendlyName(rhs_type);
|
||||||
SCOPED_TRACE(ss.str());
|
SCOPED_TRACE(ss.str());
|
||||||
|
|
||||||
Global("lhs", lhs_type, ast::StorageClass::kInput);
|
Global("lhs", lhs_type, ast::StorageClass::kInput);
|
||||||
|
@ -1316,9 +1324,8 @@ TEST_P(Expr_Binary_Test_Invalid, All) {
|
||||||
ASSERT_EQ(r()->error(),
|
ASSERT_EQ(r()->error(),
|
||||||
"12:34 error: Binary expression operand types are invalid for "
|
"12:34 error: Binary expression operand types are invalid for "
|
||||||
"this operation: " +
|
"this operation: " +
|
||||||
lhs_type->FriendlyName(Symbols()) + " " +
|
FriendlyName(lhs_type) + " " + ast::FriendlyName(expr->op()) +
|
||||||
FriendlyName(expr->op()) + " " +
|
" " + FriendlyName(rhs_type));
|
||||||
rhs_type->FriendlyName(Symbols()));
|
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
ResolverTest,
|
ResolverTest,
|
||||||
|
@ -1365,9 +1372,8 @@ TEST_P(Expr_Binary_Test_Invalid_VectorMatrixMultiply, All) {
|
||||||
ASSERT_EQ(r()->error(),
|
ASSERT_EQ(r()->error(),
|
||||||
"12:34 error: Binary expression operand types are invalid for "
|
"12:34 error: Binary expression operand types are invalid for "
|
||||||
"this operation: " +
|
"this operation: " +
|
||||||
lhs_type->FriendlyName(Symbols()) + " " +
|
FriendlyName(lhs_type) + " " + ast::FriendlyName(expr->op()) +
|
||||||
FriendlyName(expr->op()) + " " +
|
" " + FriendlyName(rhs_type));
|
||||||
rhs_type->FriendlyName(Symbols()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto all_dimension_values = testing::Values(2u, 3u, 4u);
|
auto all_dimension_values = testing::Values(2u, 3u, 4u);
|
||||||
|
@ -1405,9 +1411,8 @@ TEST_P(Expr_Binary_Test_Invalid_MatrixMatrixMultiply, All) {
|
||||||
ASSERT_EQ(r()->error(),
|
ASSERT_EQ(r()->error(),
|
||||||
"12:34 error: Binary expression operand types are invalid for "
|
"12:34 error: Binary expression operand types are invalid for "
|
||||||
"this operation: " +
|
"this operation: " +
|
||||||
lhs_type->FriendlyName(Symbols()) + " " +
|
FriendlyName(lhs_type) + " " + ast::FriendlyName(expr->op()) +
|
||||||
FriendlyName(expr->op()) + " " +
|
" " + FriendlyName(rhs_type));
|
||||||
rhs_type->FriendlyName(Symbols()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(ResolverTest,
|
INSTANTIATE_TEST_SUITE_P(ResolverTest,
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#define SRC_RESOLVER_RESOLVER_TEST_HELPER_H_
|
#define SRC_RESOLVER_RESOLVER_TEST_HELPER_H_
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
@ -95,6 +96,14 @@ class TestHelper : public ProgramBuilder {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @param type a type
|
||||||
|
/// @returns the name for `type` that closely resembles how it would be
|
||||||
|
/// declared in WGSL.
|
||||||
|
std::string FriendlyName(typ::Type type) {
|
||||||
|
return type.ast ? type.ast->FriendlyName(Symbols())
|
||||||
|
: type.sem->FriendlyName(Symbols());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Resolver> resolver_;
|
std::unique_ptr<Resolver> resolver_;
|
||||||
};
|
};
|
||||||
|
@ -105,94 +114,151 @@ template <typename T>
|
||||||
class ResolverTestWithParam : public TestHelper,
|
class ResolverTestWithParam : public TestHelper,
|
||||||
public testing::TestWithParam<T> {};
|
public testing::TestWithParam<T> {};
|
||||||
|
|
||||||
inline typ::Type ty_bool_(const ProgramBuilder::TypesBuilder& ty) {
|
inline ast::Type* ast_bool(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.bool_();
|
return ty.bool_();
|
||||||
}
|
}
|
||||||
inline typ::Type ty_i32(const ProgramBuilder::TypesBuilder& ty) {
|
inline ast::Type* ast_i32(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.i32();
|
return ty.i32();
|
||||||
}
|
}
|
||||||
inline typ::Type ty_u32(const ProgramBuilder::TypesBuilder& ty) {
|
inline ast::Type* ast_u32(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.u32();
|
return ty.u32();
|
||||||
}
|
}
|
||||||
inline typ::Type ty_f32(const ProgramBuilder::TypesBuilder& ty) {
|
inline ast::Type* ast_f32(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.f32();
|
return ty.f32();
|
||||||
}
|
}
|
||||||
|
|
||||||
using create_type_func_ptr =
|
using create_ast_type_func_ptr =
|
||||||
typ::Type (*)(const ProgramBuilder::TypesBuilder& ty);
|
ast::Type* (*)(const ProgramBuilder::TypesBuilder& ty);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typ::Type ty_vec2(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_vec2(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.vec2<T>();
|
return ty.vec2<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <create_type_func_ptr create_type>
|
template <create_ast_type_func_ptr create_type>
|
||||||
typ::Type ty_vec2(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_vec2(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.vec2(create_type(ty));
|
return ty.vec2(create_type(ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typ::Type ty_vec3(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_vec3(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.vec3<T>();
|
return ty.vec3<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <create_type_func_ptr create_type>
|
template <create_ast_type_func_ptr create_type>
|
||||||
typ::Type ty_vec3(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_vec3(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.vec3(create_type(ty));
|
return ty.vec3(create_type(ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typ::Type ty_vec4(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_vec4(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.vec4<T>();
|
return ty.vec4<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <create_type_func_ptr create_type>
|
template <create_ast_type_func_ptr create_type>
|
||||||
typ::Type ty_vec4(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_vec4(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.vec4(create_type(ty));
|
return ty.vec4(create_type(ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typ::Type ty_mat2x2(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_mat2x2(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.mat2x2<T>();
|
return ty.mat2x2<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <create_type_func_ptr create_type>
|
template <create_ast_type_func_ptr create_type>
|
||||||
typ::Type ty_mat2x2(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_mat2x2(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.mat2x2(create_type(ty));
|
return ty.mat2x2(create_type(ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typ::Type ty_mat3x3(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_mat3x3(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.mat3x3<T>();
|
return ty.mat3x3<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <create_type_func_ptr create_type>
|
template <create_ast_type_func_ptr create_type>
|
||||||
typ::Type ty_mat3x3(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_mat3x3(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.mat3x3(create_type(ty));
|
return ty.mat3x3(create_type(ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typ::Type ty_mat4x4(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_mat4x4(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.mat4x4<T>();
|
return ty.mat4x4<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <create_type_func_ptr create_type>
|
template <create_ast_type_func_ptr create_type>
|
||||||
typ::Type ty_mat4x4(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_mat4x4(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.mat4x4(create_type(ty));
|
return ty.mat4x4(create_type(ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <create_type_func_ptr create_type>
|
template <create_ast_type_func_ptr create_type>
|
||||||
typ::Type ty_alias(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_alias(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
auto type = create_type(ty);
|
auto* type = create_type(ty);
|
||||||
return ty.alias("alias_" + type->type_name(), type);
|
auto name = ty.builder->Symbols().Register("alias_" + type->type_name());
|
||||||
|
if (!ty.builder->AST().LookupType(name)) {
|
||||||
|
ty.builder->AST().AddConstructedType(ty.alias(name, type));
|
||||||
|
}
|
||||||
|
return ty.builder->create<ast::TypeName>(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <create_type_func_ptr create_type>
|
template <create_ast_type_func_ptr create_type>
|
||||||
typ::Type ty_access(const ProgramBuilder::TypesBuilder& ty) {
|
ast::Type* ast_access(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
auto type = create_type(ty);
|
auto* type = create_type(ty);
|
||||||
return ty.access(ast::AccessControl::kReadOnly, type);
|
return ty.access(ast::AccessControl::kReadOnly, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline sem::Type* sem_bool(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
|
return ty.builder->create<sem::Bool>();
|
||||||
|
}
|
||||||
|
inline sem::Type* sem_i32(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
|
return ty.builder->create<sem::I32>();
|
||||||
|
}
|
||||||
|
inline sem::Type* sem_u32(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
|
return ty.builder->create<sem::U32>();
|
||||||
|
}
|
||||||
|
inline sem::Type* sem_f32(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
|
return ty.builder->create<sem::F32>();
|
||||||
|
}
|
||||||
|
|
||||||
|
using create_sem_type_func_ptr =
|
||||||
|
sem::Type* (*)(const ProgramBuilder::TypesBuilder& ty);
|
||||||
|
|
||||||
|
template <create_sem_type_func_ptr create_type>
|
||||||
|
sem::Type* sem_vec2(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
|
return ty.builder->create<sem::Vector>(create_type(ty), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <create_sem_type_func_ptr create_type>
|
||||||
|
sem::Type* sem_vec3(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
|
return ty.builder->create<sem::Vector>(create_type(ty), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <create_sem_type_func_ptr create_type>
|
||||||
|
sem::Type* sem_vec4(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
|
return ty.builder->create<sem::Vector>(create_type(ty), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <create_sem_type_func_ptr create_type>
|
||||||
|
sem::Type* sem_mat2x2(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
|
return ty.builder->create<sem::Matrix>(create_type(ty), 2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <create_sem_type_func_ptr create_type>
|
||||||
|
sem::Type* sem_mat3x3(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
|
return ty.builder->create<sem::Matrix>(create_type(ty), 3, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <create_sem_type_func_ptr create_type>
|
||||||
|
sem::Type* sem_mat4x4(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
|
return ty.builder->create<sem::Matrix>(create_type(ty), 4, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <create_sem_type_func_ptr create_type>
|
||||||
|
sem::Type* sem_access(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
|
auto* type = create_type(ty);
|
||||||
|
return ty.builder->create<sem::AccessControl>(ast::AccessControl::kReadOnly,
|
||||||
|
type);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace resolver
|
} // namespace resolver
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,11 @@ namespace resolver {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/// @return the element type of `type` for vec and mat, otherwise `type` itself
|
/// @return the element type of `type` for vec and mat, otherwise `type` itself
|
||||||
sem::Type* ElementTypeOf(sem::Type* type) {
|
ast::Type* ElementTypeOf(ast::Type* type) {
|
||||||
if (auto* v = type->As<sem::Vector>()) {
|
if (auto* v = type->As<ast::Vector>()) {
|
||||||
return v->type();
|
return v->type();
|
||||||
}
|
}
|
||||||
if (auto* m = type->As<sem::Matrix>()) {
|
if (auto* m = type->As<ast::Matrix>()) {
|
||||||
return m->type();
|
return m->type();
|
||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
|
@ -34,7 +34,8 @@ class ResolverTypeConstructorValidationTest : public resolver::TestHelper,
|
||||||
|
|
||||||
namespace InferTypeTest {
|
namespace InferTypeTest {
|
||||||
struct Params {
|
struct Params {
|
||||||
create_type_func_ptr create_rhs_type;
|
create_ast_type_func_ptr create_rhs_ast_type;
|
||||||
|
create_sem_type_func_ptr create_rhs_sem_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helpers and typedefs
|
// Helpers and typedefs
|
||||||
|
@ -66,7 +67,7 @@ TEST_P(InferTypeTest_FromConstructorExpression, All) {
|
||||||
// }
|
// }
|
||||||
auto& params = GetParam();
|
auto& params = GetParam();
|
||||||
|
|
||||||
auto rhs_type = params.create_rhs_type(ty);
|
auto* rhs_type = params.create_rhs_ast_type(ty);
|
||||||
auto* constructor_expr = ConstructValueFilledWith(rhs_type, 0);
|
auto* constructor_expr = ConstructValueFilledWith(rhs_type, 0);
|
||||||
|
|
||||||
auto sc = ast::StorageClass::kFunction;
|
auto sc = ast::StorageClass::kFunction;
|
||||||
|
@ -77,30 +78,33 @@ TEST_P(InferTypeTest_FromConstructorExpression, All) {
|
||||||
WrapInFunction(Decl(a), Assign(a_ident, "a"));
|
WrapInFunction(Decl(a), Assign(a_ident, "a"));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
ASSERT_EQ(TypeOf(a_ident), ty.pointer(rhs_type->UnwrapAliasIfNeeded(), sc));
|
auto* got = TypeOf(a_ident);
|
||||||
|
auto* expected = ty.pointer(params.create_rhs_sem_type(ty), sc).sem;
|
||||||
|
ASSERT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
|
||||||
|
<< "expected: " << FriendlyName(expected) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr Params from_constructor_expression_cases[] = {
|
static constexpr Params from_constructor_expression_cases[] = {
|
||||||
Params{ty_bool_},
|
Params{ast_bool, sem_bool},
|
||||||
Params{ty_i32},
|
Params{ast_i32, sem_i32},
|
||||||
Params{ty_u32},
|
Params{ast_u32, sem_u32},
|
||||||
Params{ty_f32},
|
Params{ast_f32, sem_f32},
|
||||||
Params{ty_vec3<i32>},
|
Params{ast_vec3<i32>, sem_vec3<sem_i32>},
|
||||||
Params{ty_vec3<u32>},
|
Params{ast_vec3<u32>, sem_vec3<sem_u32>},
|
||||||
Params{ty_vec3<f32>},
|
Params{ast_vec3<f32>, sem_vec3<sem_f32>},
|
||||||
Params{ty_mat3x3<i32>},
|
Params{ast_mat3x3<i32>, sem_mat3x3<sem_i32>},
|
||||||
Params{ty_mat3x3<u32>},
|
Params{ast_mat3x3<u32>, sem_mat3x3<sem_u32>},
|
||||||
Params{ty_mat3x3<f32>},
|
Params{ast_mat3x3<f32>, sem_mat3x3<sem_f32>},
|
||||||
Params{ty_alias<ty_bool_>},
|
Params{ast_alias<ast_bool>, sem_bool},
|
||||||
Params{ty_alias<ty_i32>},
|
Params{ast_alias<ast_i32>, sem_i32},
|
||||||
Params{ty_alias<ty_u32>},
|
Params{ast_alias<ast_u32>, sem_u32},
|
||||||
Params{ty_alias<ty_f32>},
|
Params{ast_alias<ast_f32>, sem_f32},
|
||||||
Params{ty_alias<ty_vec3<i32>>},
|
Params{ast_alias<ast_vec3<i32>>, sem_vec3<sem_i32>},
|
||||||
Params{ty_alias<ty_vec3<u32>>},
|
Params{ast_alias<ast_vec3<u32>>, sem_vec3<sem_u32>},
|
||||||
Params{ty_alias<ty_vec3<f32>>},
|
Params{ast_alias<ast_vec3<f32>>, sem_vec3<sem_f32>},
|
||||||
Params{ty_alias<ty_mat3x3<i32>>},
|
Params{ast_alias<ast_mat3x3<i32>>, sem_mat3x3<sem_i32>},
|
||||||
Params{ty_alias<ty_mat3x3<u32>>},
|
Params{ast_alias<ast_mat3x3<u32>>, sem_mat3x3<sem_u32>},
|
||||||
Params{ty_alias<ty_mat3x3<f32>>},
|
Params{ast_alias<ast_mat3x3<f32>>, sem_mat3x3<sem_f32>},
|
||||||
};
|
};
|
||||||
INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
|
INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
|
||||||
InferTypeTest_FromConstructorExpression,
|
InferTypeTest_FromConstructorExpression,
|
||||||
|
@ -114,7 +118,7 @@ TEST_P(InferTypeTest_FromArithmeticExpression, All) {
|
||||||
// }
|
// }
|
||||||
auto& params = GetParam();
|
auto& params = GetParam();
|
||||||
|
|
||||||
auto rhs_type = params.create_rhs_type(ty);
|
auto* rhs_type = params.create_rhs_ast_type(ty);
|
||||||
|
|
||||||
auto* arith_lhs_expr = ConstructValueFilledWith(rhs_type, 2);
|
auto* arith_lhs_expr = ConstructValueFilledWith(rhs_type, 2);
|
||||||
auto* arith_rhs_expr = ConstructValueFilledWith(ElementTypeOf(rhs_type), 3);
|
auto* arith_rhs_expr = ConstructValueFilledWith(ElementTypeOf(rhs_type), 3);
|
||||||
|
@ -128,11 +132,17 @@ TEST_P(InferTypeTest_FromArithmeticExpression, All) {
|
||||||
WrapInFunction(Decl(a), Assign(a_ident, "a"));
|
WrapInFunction(Decl(a), Assign(a_ident, "a"));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
ASSERT_EQ(TypeOf(a_ident), ty.pointer(rhs_type, sc));
|
auto* got = TypeOf(a_ident);
|
||||||
|
auto* expected = ty.pointer(params.create_rhs_sem_type(ty), sc).sem;
|
||||||
|
ASSERT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
|
||||||
|
<< "expected: " << FriendlyName(expected) << "\n";
|
||||||
}
|
}
|
||||||
static constexpr Params from_arithmetic_expression_cases[] = {
|
static constexpr Params from_arithmetic_expression_cases[] = {
|
||||||
Params{ty_i32}, Params{ty_u32}, Params{ty_f32},
|
Params{ast_i32, sem_i32},
|
||||||
Params{ty_vec3<f32>}, Params{ty_mat3x3<f32>},
|
Params{ast_u32, sem_u32},
|
||||||
|
Params{ast_f32, sem_f32},
|
||||||
|
Params{ast_vec3<f32>, sem_vec3<sem_f32>},
|
||||||
|
Params{ast_mat3x3<f32>, sem_mat3x3<sem_f32>},
|
||||||
|
|
||||||
// TODO(amaiorano): Uncomment once https://crbug.com/tint/680 is fixed
|
// TODO(amaiorano): Uncomment once https://crbug.com/tint/680 is fixed
|
||||||
// Params{ty_alias<ty_i32>},
|
// Params{ty_alias<ty_i32>},
|
||||||
|
@ -159,43 +169,44 @@ TEST_P(InferTypeTest_FromCallExpression, All) {
|
||||||
// }
|
// }
|
||||||
auto& params = GetParam();
|
auto& params = GetParam();
|
||||||
|
|
||||||
auto rhs_type = params.create_rhs_type(ty);
|
Func("foo", {}, params.create_rhs_ast_type(ty),
|
||||||
|
{Return(ConstructValueFilledWith(params.create_rhs_ast_type(ty), 0))},
|
||||||
Func("foo", {}, rhs_type, {Return(ConstructValueFilledWith(rhs_type, 0))},
|
|
||||||
{});
|
{});
|
||||||
auto* constructor_expr = Call(Expr("foo"));
|
|
||||||
|
|
||||||
auto sc = ast::StorageClass::kFunction;
|
auto sc = ast::StorageClass::kFunction;
|
||||||
auto* a = Var("a", nullptr, sc, constructor_expr);
|
auto* a = Var("a", nullptr, sc, Call(Expr("foo")));
|
||||||
// Self-assign 'a' to force the expression to be resolved so we can test its
|
// Self-assign 'a' to force the expression to be resolved so we can test its
|
||||||
// type below
|
// type below
|
||||||
auto* a_ident = Expr("a");
|
auto* a_ident = Expr("a");
|
||||||
WrapInFunction(Decl(a), Assign(a_ident, "a"));
|
WrapInFunction(Decl(a), Assign(a_ident, "a"));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
ASSERT_EQ(TypeOf(a_ident), ty.pointer(rhs_type->UnwrapAliasIfNeeded(), sc));
|
auto* got = TypeOf(a_ident);
|
||||||
|
auto* expected = ty.pointer(params.create_rhs_sem_type(ty), sc).sem;
|
||||||
|
ASSERT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
|
||||||
|
<< "expected: " << FriendlyName(expected) << "\n";
|
||||||
}
|
}
|
||||||
static constexpr Params from_call_expression_cases[] = {
|
static constexpr Params from_call_expression_cases[] = {
|
||||||
Params{ty_bool_},
|
Params{ast_bool, sem_bool},
|
||||||
Params{ty_i32},
|
Params{ast_i32, sem_i32},
|
||||||
Params{ty_u32},
|
Params{ast_u32, sem_u32},
|
||||||
Params{ty_f32},
|
Params{ast_f32, sem_f32},
|
||||||
Params{ty_vec3<i32>},
|
Params{ast_vec3<i32>, sem_vec3<sem_i32>},
|
||||||
Params{ty_vec3<u32>},
|
Params{ast_vec3<u32>, sem_vec3<sem_u32>},
|
||||||
Params{ty_vec3<f32>},
|
Params{ast_vec3<f32>, sem_vec3<sem_f32>},
|
||||||
Params{ty_mat3x3<i32>},
|
Params{ast_mat3x3<i32>, sem_mat3x3<sem_i32>},
|
||||||
Params{ty_mat3x3<u32>},
|
Params{ast_mat3x3<u32>, sem_mat3x3<sem_u32>},
|
||||||
Params{ty_mat3x3<f32>},
|
Params{ast_mat3x3<f32>, sem_mat3x3<sem_f32>},
|
||||||
Params{ty_alias<ty_bool_>},
|
Params{ast_alias<ast_bool>, sem_bool},
|
||||||
Params{ty_alias<ty_i32>},
|
Params{ast_alias<ast_i32>, sem_i32},
|
||||||
Params{ty_alias<ty_u32>},
|
Params{ast_alias<ast_u32>, sem_u32},
|
||||||
Params{ty_alias<ty_f32>},
|
Params{ast_alias<ast_f32>, sem_f32},
|
||||||
Params{ty_alias<ty_vec3<i32>>},
|
Params{ast_alias<ast_vec3<i32>>, sem_vec3<sem_i32>},
|
||||||
Params{ty_alias<ty_vec3<u32>>},
|
Params{ast_alias<ast_vec3<u32>>, sem_vec3<sem_u32>},
|
||||||
Params{ty_alias<ty_vec3<f32>>},
|
Params{ast_alias<ast_vec3<f32>>, sem_vec3<sem_f32>},
|
||||||
Params{ty_alias<ty_mat3x3<i32>>},
|
Params{ast_alias<ast_mat3x3<i32>>, sem_mat3x3<sem_i32>},
|
||||||
Params{ty_alias<ty_mat3x3<u32>>},
|
Params{ast_alias<ast_mat3x3<u32>>, sem_mat3x3<sem_u32>},
|
||||||
Params{ty_alias<ty_mat3x3<f32>>},
|
Params{ast_alias<ast_mat3x3<f32>>, sem_mat3x3<sem_f32>},
|
||||||
};
|
};
|
||||||
INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
|
INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
|
||||||
InferTypeTest_FromCallExpression,
|
InferTypeTest_FromCallExpression,
|
||||||
|
|
|
@ -445,48 +445,57 @@ TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsLast_Pass) {
|
||||||
|
|
||||||
namespace GetCanonicalTests {
|
namespace GetCanonicalTests {
|
||||||
struct Params {
|
struct Params {
|
||||||
create_type_func_ptr create_type;
|
create_ast_type_func_ptr create_ast_type;
|
||||||
create_type_func_ptr create_canonical_type;
|
create_sem_type_func_ptr create_sem_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr Params cases[] = {
|
static constexpr Params cases[] = {
|
||||||
Params{ty_bool_, ty_bool_},
|
Params{ast_bool, sem_bool},
|
||||||
Params{ty_alias<ty_bool_>, ty_bool_},
|
Params{ast_alias<ast_bool>, sem_bool},
|
||||||
Params{ty_alias<ty_alias<ty_bool_>>, ty_bool_},
|
Params{ast_alias<ast_alias<ast_bool>>, sem_bool},
|
||||||
|
|
||||||
Params{ty_vec3<ty_f32>, ty_vec3<ty_f32>},
|
Params{ast_vec3<ast_f32>, sem_vec3<sem_f32>},
|
||||||
Params{ty_alias<ty_vec3<ty_f32>>, ty_vec3<ty_f32>},
|
Params{ast_alias<ast_vec3<ast_f32>>, sem_vec3<sem_f32>},
|
||||||
Params{ty_alias<ty_alias<ty_vec3<ty_f32>>>, ty_vec3<ty_f32>},
|
Params{ast_alias<ast_alias<ast_vec3<ast_f32>>>, sem_vec3<sem_f32>},
|
||||||
|
|
||||||
Params{ty_vec3<ty_alias<ty_f32>>, ty_vec3<ty_f32>},
|
Params{ast_vec3<ast_alias<ast_f32>>, sem_vec3<sem_f32>},
|
||||||
Params{ty_alias<ty_vec3<ty_alias<ty_f32>>>, ty_vec3<ty_f32>},
|
Params{ast_alias<ast_vec3<ast_alias<ast_f32>>>, sem_vec3<sem_f32>},
|
||||||
Params{ty_alias<ty_alias<ty_vec3<ty_alias<ty_f32>>>>, ty_vec3<ty_f32>},
|
Params{ast_alias<ast_alias<ast_vec3<ast_alias<ast_f32>>>>,
|
||||||
Params{ty_alias<ty_alias<ty_vec3<ty_alias<ty_alias<ty_f32>>>>>,
|
sem_vec3<sem_f32>},
|
||||||
ty_vec3<ty_f32>},
|
Params{ast_alias<ast_alias<ast_vec3<ast_alias<ast_alias<ast_f32>>>>>,
|
||||||
|
sem_vec3<sem_f32>},
|
||||||
|
|
||||||
Params{ty_mat3x3<ty_alias<ty_f32>>, ty_mat3x3<ty_f32>},
|
Params{ast_mat3x3<ast_alias<ast_f32>>, sem_mat3x3<sem_f32>},
|
||||||
Params{ty_alias<ty_mat3x3<ty_alias<ty_f32>>>, ty_mat3x3<ty_f32>},
|
Params{ast_alias<ast_mat3x3<ast_alias<ast_f32>>>, sem_mat3x3<sem_f32>},
|
||||||
Params{ty_alias<ty_alias<ty_mat3x3<ty_alias<ty_f32>>>>, ty_mat3x3<ty_f32>},
|
Params{ast_alias<ast_alias<ast_mat3x3<ast_alias<ast_f32>>>>,
|
||||||
Params{ty_alias<ty_alias<ty_mat3x3<ty_alias<ty_alias<ty_f32>>>>>,
|
sem_mat3x3<sem_f32>},
|
||||||
ty_mat3x3<ty_f32>},
|
Params{ast_alias<ast_alias<ast_mat3x3<ast_alias<ast_alias<ast_f32>>>>>,
|
||||||
|
sem_mat3x3<sem_f32>},
|
||||||
|
|
||||||
Params{ty_alias<ty_access<ty_alias<ty_bool_>>>, ty_access<ty_bool_>},
|
Params{ast_alias<ast_access<ast_alias<ast_bool>>>, sem_access<sem_bool>},
|
||||||
Params{ty_alias<ty_access<ty_alias<ty_vec3<ty_access<ty_f32>>>>>,
|
Params{ast_alias<ast_access<ast_alias<ast_vec3<ast_access<ast_f32>>>>>,
|
||||||
ty_access<ty_vec3<ty_access<ty_f32>>>},
|
sem_access<sem_vec3<sem_access<sem_f32>>>},
|
||||||
Params{ty_alias<ty_access<ty_alias<ty_mat3x3<ty_access<ty_f32>>>>>,
|
Params{ast_alias<ast_access<ast_alias<ast_mat3x3<ast_access<ast_f32>>>>>,
|
||||||
ty_access<ty_mat3x3<ty_access<ty_f32>>>},
|
sem_access<sem_mat3x3<sem_access<sem_f32>>>},
|
||||||
};
|
};
|
||||||
|
|
||||||
using CanonicalTest = ResolverTestWithParam<Params>;
|
using CanonicalTest = ResolverTestWithParam<Params>;
|
||||||
TEST_P(CanonicalTest, All) {
|
TEST_P(CanonicalTest, All) {
|
||||||
auto& params = GetParam();
|
auto& params = GetParam();
|
||||||
|
|
||||||
auto type = params.create_type(ty);
|
auto* type = params.create_ast_type(ty);
|
||||||
auto expected_canonical_type = params.create_canonical_type(ty);
|
|
||||||
|
|
||||||
auto* canonical_type = r()->Canonical(type);
|
auto* var = Var("v", type, ast::StorageClass::kFunction);
|
||||||
|
auto* expr = Expr("v");
|
||||||
|
WrapInFunction(var, expr);
|
||||||
|
|
||||||
EXPECT_EQ(canonical_type, expected_canonical_type);
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* got = TypeOf(expr)->UnwrapPtrIfNeeded();
|
||||||
|
auto* expected = params.create_sem_type(ty);
|
||||||
|
|
||||||
|
EXPECT_EQ(got, expected) << "got: " << FriendlyName(got) << "\n"
|
||||||
|
<< "expected: " << FriendlyName(expected) << "\n";
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
|
INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
|
||||||
CanonicalTest,
|
CanonicalTest,
|
||||||
|
@ -529,26 +538,26 @@ INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
|
||||||
testing::ValuesIn(dimension_cases));
|
testing::ValuesIn(dimension_cases));
|
||||||
|
|
||||||
struct TypeParams {
|
struct TypeParams {
|
||||||
create_type_func_ptr type_func;
|
create_ast_type_func_ptr type_func;
|
||||||
bool is_valid;
|
bool is_valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr TypeParams type_cases[] = {
|
static constexpr TypeParams type_cases[] = {
|
||||||
TypeParams{ty_bool_, false},
|
TypeParams{ast_bool, false},
|
||||||
TypeParams{ty_i32, true},
|
TypeParams{ast_i32, true},
|
||||||
TypeParams{ty_u32, true},
|
TypeParams{ast_u32, true},
|
||||||
TypeParams{ty_f32, true},
|
TypeParams{ast_f32, true},
|
||||||
|
|
||||||
TypeParams{ty_alias<ty_bool_>, false},
|
TypeParams{ast_alias<ast_bool>, false},
|
||||||
TypeParams{ty_alias<ty_i32>, true},
|
TypeParams{ast_alias<ast_i32>, true},
|
||||||
TypeParams{ty_alias<ty_u32>, true},
|
TypeParams{ast_alias<ast_u32>, true},
|
||||||
TypeParams{ty_alias<ty_f32>, true},
|
TypeParams{ast_alias<ast_f32>, true},
|
||||||
|
|
||||||
TypeParams{ty_vec3<ty_f32>, false},
|
TypeParams{ast_vec3<ast_f32>, false},
|
||||||
TypeParams{ty_mat3x3<ty_f32>, false},
|
TypeParams{ast_mat3x3<ast_f32>, false},
|
||||||
|
|
||||||
TypeParams{ty_alias<ty_vec3<ty_f32>>, false},
|
TypeParams{ast_alias<ast_vec3<ast_f32>>, false},
|
||||||
TypeParams{ty_alias<ty_mat3x3<ty_f32>>, false}};
|
TypeParams{ast_alias<ast_mat3x3<ast_f32>>, false}};
|
||||||
|
|
||||||
using MultisampledTextureTypeTest = ResolverTestWithParam<TypeParams>;
|
using MultisampledTextureTypeTest = ResolverTestWithParam<TypeParams>;
|
||||||
TEST_P(MultisampledTextureTypeTest, All) {
|
TEST_P(MultisampledTextureTypeTest, All) {
|
||||||
|
|
|
@ -2041,9 +2041,10 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Success) {
|
||||||
TEST_F(ResolverValidationTest, Expr_MatrixConstructor_ArgumentTypeAlias_Error) {
|
TEST_F(ResolverValidationTest, Expr_MatrixConstructor_ArgumentTypeAlias_Error) {
|
||||||
auto alias = ty.alias("VectorUnsigned2", ty.vec2<u32>());
|
auto alias = ty.alias("VectorUnsigned2", ty.vec2<u32>());
|
||||||
AST().AddConstructedType(alias);
|
AST().AddConstructedType(alias);
|
||||||
auto* tc = mat2x2<f32>(create<ast::TypeConstructorExpression>(
|
auto* tc = mat2x2<f32>(
|
||||||
Source{{12, 34}}, alias, ExprList()),
|
create<ast::TypeConstructorExpression>(
|
||||||
vec2<f32>());
|
Source{{12, 34}}, ty.MaybeCreateTypename(alias), ExprList()),
|
||||||
|
vec2<f32>());
|
||||||
WrapInFunction(tc);
|
WrapInFunction(tc);
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
@ -2062,7 +2063,7 @@ TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentTypeAlias_Success) {
|
||||||
ast::ExpressionList args;
|
ast::ExpressionList args;
|
||||||
for (uint32_t i = 1; i <= param.columns; i++) {
|
for (uint32_t i = 1; i <= param.columns; i++) {
|
||||||
args.push_back(create<ast::TypeConstructorExpression>(
|
args.push_back(create<ast::TypeConstructorExpression>(
|
||||||
Source{{12, i}}, vec_alias, ExprList()));
|
Source{{12, i}}, ty.MaybeCreateTypename(vec_alias), ExprList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* tc = create<ast::TypeConstructorExpression>(Source{}, matrix_type,
|
auto* tc = create<ast::TypeConstructorExpression>(Source{}, matrix_type,
|
||||||
|
|
|
@ -28,12 +28,11 @@ namespace sem {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
ParameterList GetParameters(ast::Function* ast) {
|
ParameterList GetParameters(const std::vector<const Variable*>& params) {
|
||||||
ParameterList parameters;
|
ParameterList parameters;
|
||||||
parameters.reserve(ast->params().size());
|
parameters.reserve(params.size());
|
||||||
for (auto* param : ast->params()) {
|
for (auto* param : params) {
|
||||||
parameters.emplace_back(
|
parameters.emplace_back(Parameter{param->Type(), Parameter::Usage::kNone});
|
||||||
Parameter{param->declared_type(), Parameter::Usage::kNone});
|
|
||||||
}
|
}
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
@ -47,7 +46,7 @@ Function::Function(ast::Function* declaration,
|
||||||
std::vector<const Variable*> local_referenced_module_vars,
|
std::vector<const Variable*> local_referenced_module_vars,
|
||||||
std::vector<const ast::ReturnStatement*> return_statements,
|
std::vector<const ast::ReturnStatement*> return_statements,
|
||||||
std::vector<Symbol> ancestor_entry_points)
|
std::vector<Symbol> ancestor_entry_points)
|
||||||
: Base(return_type, GetParameters(declaration)),
|
: Base(return_type, GetParameters(parameters)),
|
||||||
declaration_(declaration),
|
declaration_(declaration),
|
||||||
parameters_(std::move(parameters)),
|
parameters_(std::move(parameters)),
|
||||||
referenced_module_vars_(std::move(referenced_module_vars)),
|
referenced_module_vars_(std::move(referenced_module_vars)),
|
||||||
|
|
|
@ -30,10 +30,6 @@ Variable::Variable(const ast::Variable* declaration,
|
||||||
|
|
||||||
Variable::~Variable() = default;
|
Variable::~Variable() = default;
|
||||||
|
|
||||||
sem::Type* Variable::DeclaredType() const {
|
|
||||||
return declaration_->declared_type();
|
|
||||||
}
|
|
||||||
|
|
||||||
VariableUser::VariableUser(ast::IdentifierExpression* declaration,
|
VariableUser::VariableUser(ast::IdentifierExpression* declaration,
|
||||||
const sem::Type* type,
|
const sem::Type* type,
|
||||||
Statement* statement,
|
Statement* statement,
|
||||||
|
|
|
@ -54,9 +54,6 @@ class Variable : public Castable<Variable, Node> {
|
||||||
/// @returns the canonical type for the variable
|
/// @returns the canonical type for the variable
|
||||||
sem::Type* Type() const { return const_cast<sem::Type*>(type_); }
|
sem::Type* Type() const { return const_cast<sem::Type*>(type_); }
|
||||||
|
|
||||||
/// @returns the AST node's type. May be nullptr.
|
|
||||||
sem::Type* DeclaredType() const;
|
|
||||||
|
|
||||||
/// @returns the storage class for the variable
|
/// @returns the storage class for the variable
|
||||||
ast::StorageClass StorageClass() const { return storage_class_; }
|
ast::StorageClass StorageClass() const { return storage_class_; }
|
||||||
|
|
||||||
|
|
|
@ -65,13 +65,13 @@ Output BindingRemapper::Run(const Program* in, const DataMap& datamap) {
|
||||||
if (ac_it != remappings->access_controls.end()) {
|
if (ac_it != remappings->access_controls.end()) {
|
||||||
ast::AccessControl::Access ac = ac_it->second;
|
ast::AccessControl::Access ac = ac_it->second;
|
||||||
auto* ty = in->Sem().Get(var)->Type();
|
auto* ty = in->Sem().Get(var)->Type();
|
||||||
sem::Type* inner_ty = nullptr;
|
ast::Type* inner_ty = nullptr;
|
||||||
if (auto* old_ac = ty->As<sem::AccessControl>()) {
|
if (auto* old_ac = ty->As<sem::AccessControl>()) {
|
||||||
inner_ty = ctx.Clone(old_ac->type());
|
inner_ty = CreateASTTypeFor(&ctx, old_ac->type());
|
||||||
} else {
|
} else {
|
||||||
inner_ty = ctx.Clone(ty);
|
inner_ty = CreateASTTypeFor(&ctx, ty);
|
||||||
}
|
}
|
||||||
auto* new_ty = ctx.dst->create<sem::AccessControl>(ac, inner_ty);
|
auto* new_ty = ctx.dst->create<ast::AccessControl>(ac, inner_ty);
|
||||||
auto* new_var = ctx.dst->create<ast::Variable>(
|
auto* new_var = ctx.dst->create<ast::Variable>(
|
||||||
ctx.Clone(var->source()), ctx.Clone(var->symbol()),
|
ctx.Clone(var->source()), ctx.Clone(var->symbol()),
|
||||||
var->declared_storage_class(), new_ty, var->is_const(),
|
var->declared_storage_class(), new_ty, var->is_const(),
|
||||||
|
|
|
@ -81,6 +81,8 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
||||||
auto get_buffer_size_intrinsic = [&](sem::StructType* buffer_type) {
|
auto get_buffer_size_intrinsic = [&](sem::StructType* buffer_type) {
|
||||||
return utils::GetOrCreate(buffer_size_intrinsics, buffer_type, [&] {
|
return utils::GetOrCreate(buffer_size_intrinsics, buffer_type, [&] {
|
||||||
auto name = ctx.dst->Sym();
|
auto name = ctx.dst->Sym();
|
||||||
|
auto* buffer_typename =
|
||||||
|
ctx.dst->ty.type_name(ctx.Clone(buffer_type->impl()->name()));
|
||||||
auto* func = ctx.dst->create<ast::Function>(
|
auto* func = ctx.dst->create<ast::Function>(
|
||||||
name,
|
name,
|
||||||
ast::VariableList{
|
ast::VariableList{
|
||||||
|
@ -88,7 +90,7 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
||||||
// in order for HLSL to emit this as a ByteAddressBuffer.
|
// in order for HLSL to emit this as a ByteAddressBuffer.
|
||||||
ctx.dst->create<ast::Variable>(
|
ctx.dst->create<ast::Variable>(
|
||||||
ctx.dst->Sym("buffer"), ast::StorageClass::kStorage,
|
ctx.dst->Sym("buffer"), ast::StorageClass::kStorage,
|
||||||
ctx.Clone(buffer_type), true, nullptr, ast::DecorationList{}),
|
buffer_typename, true, nullptr, ast::DecorationList{}),
|
||||||
ctx.dst->Param("result",
|
ctx.dst->Param("result",
|
||||||
ctx.dst->ty.pointer(ctx.dst->ty.u32(),
|
ctx.dst->ty.pointer(ctx.dst->ty.u32(),
|
||||||
ast::StorageClass::kFunction)),
|
ast::StorageClass::kFunction)),
|
||||||
|
@ -98,7 +100,8 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
||||||
ctx.dst->ASTNodes().Create<BufferSizeIntrinsic>(ctx.dst->ID()),
|
ctx.dst->ASTNodes().Create<BufferSizeIntrinsic>(ctx.dst->ID()),
|
||||||
},
|
},
|
||||||
ast::DecorationList{});
|
ast::DecorationList{});
|
||||||
ctx.InsertAfter(ctx.src->AST().GlobalDeclarations(), buffer_type, func);
|
ctx.InsertAfter(ctx.src->AST().GlobalDeclarations(), buffer_type->impl(),
|
||||||
|
func);
|
||||||
return name;
|
return name;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "src/program_builder.h"
|
#include "src/program_builder.h"
|
||||||
#include "src/sem/function.h"
|
#include "src/sem/function.h"
|
||||||
#include "src/sem/statement.h"
|
#include "src/sem/statement.h"
|
||||||
|
#include "src/sem/struct.h"
|
||||||
#include "src/sem/variable.h"
|
#include "src/sem/variable.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -65,11 +66,11 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
||||||
|
|
||||||
// Strip entry point IO decorations from struct declarations.
|
// Strip entry point IO decorations from struct declarations.
|
||||||
// TODO(jrprice): This code is duplicated with the SPIR-V transform.
|
// TODO(jrprice): This code is duplicated with the SPIR-V transform.
|
||||||
for (auto ty : ctx.src->AST().ConstructedTypes()) {
|
for (auto* ty : ctx.src->AST().ConstructedTypes()) {
|
||||||
if (auto* struct_ty = ty->As<sem::StructType>()) {
|
if (auto* struct_ty = ty->As<ast::Struct>()) {
|
||||||
// Build new list of struct members without entry point IO decorations.
|
// Build new list of struct members without entry point IO decorations.
|
||||||
ast::StructMemberList new_struct_members;
|
ast::StructMemberList new_struct_members;
|
||||||
for (auto* member : struct_ty->impl()->members()) {
|
for (auto* member : struct_ty->members()) {
|
||||||
ast::DecorationList new_decorations = RemoveDecorations(
|
ast::DecorationList new_decorations = RemoveDecorations(
|
||||||
&ctx, member->decorations(), [](const ast::Decoration* deco) {
|
&ctx, member->decorations(), [](const ast::Decoration* deco) {
|
||||||
return deco
|
return deco
|
||||||
|
@ -81,49 +82,53 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redeclare the struct.
|
// Redeclare the struct.
|
||||||
auto new_struct_name = ctx.Clone(struct_ty->impl()->name());
|
auto new_struct_name = ctx.Clone(struct_ty->name());
|
||||||
auto* new_struct =
|
auto* new_struct =
|
||||||
ctx.dst->create<sem::StructType>(ctx.dst->create<ast::Struct>(
|
ctx.dst->create<ast::Struct>(new_struct_name, new_struct_members,
|
||||||
new_struct_name, new_struct_members,
|
ctx.Clone(struct_ty->decorations()));
|
||||||
ctx.Clone(struct_ty->impl()->decorations())));
|
|
||||||
ctx.Replace(struct_ty, new_struct);
|
ctx.Replace(struct_ty, new_struct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* func : ctx.src->AST().Functions()) {
|
for (auto* func_ast : ctx.src->AST().Functions()) {
|
||||||
if (!func->IsEntryPoint()) {
|
if (!func_ast->IsEntryPoint()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* func = ctx.src->Sem().Get(func_ast);
|
||||||
|
|
||||||
ast::VariableList new_parameters;
|
ast::VariableList new_parameters;
|
||||||
|
|
||||||
if (!func->params().empty()) {
|
if (!func->Parameters().empty()) {
|
||||||
// Collect all parameters and build a list of new struct members.
|
// Collect all parameters and build a list of new struct members.
|
||||||
auto new_struct_param_symbol = ctx.dst->Sym();
|
auto new_struct_param_symbol = ctx.dst->Sym();
|
||||||
ast::StructMemberList new_struct_members;
|
ast::StructMemberList new_struct_members;
|
||||||
for (auto* param : func->params()) {
|
for (auto* param : func->Parameters()) {
|
||||||
auto param_name = ctx.Clone(param->symbol());
|
auto param_name = ctx.Clone(param->Declaration()->symbol());
|
||||||
auto* param_ty = ctx.src->Sem().Get(param)->Type();
|
auto* param_ty = param->Type();
|
||||||
auto* param_declared_ty = ctx.src->Sem().Get(param)->DeclaredType();
|
auto* param_declared_ty = param->Declaration()->type();
|
||||||
|
|
||||||
std::function<ast::Expression*()> func_const_initializer;
|
std::function<ast::Expression*()> func_const_initializer;
|
||||||
|
|
||||||
if (auto* struct_ty = param_ty->As<sem::StructType>()) {
|
if (auto* struct_ty = param_ty->As<sem::StructType>()) {
|
||||||
|
auto* str = ctx.src->Sem().Get(struct_ty);
|
||||||
// Pull out all struct members and build initializer list.
|
// Pull out all struct members and build initializer list.
|
||||||
std::vector<Symbol> member_names;
|
std::vector<Symbol> member_names;
|
||||||
for (auto* member : struct_ty->impl()->members()) {
|
for (auto* member : str->Members()) {
|
||||||
if (member->type()->UnwrapAll()->Is<sem::StructType>()) {
|
if (member->Type()->UnwrapAll()->Is<sem::StructType>()) {
|
||||||
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
|
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::DecorationList new_decorations = RemoveDecorations(
|
ast::DecorationList new_decorations = RemoveDecorations(
|
||||||
&ctx, member->decorations(), [](const ast::Decoration* deco) {
|
&ctx, member->Declaration()->decorations(),
|
||||||
|
[](const ast::Decoration* deco) {
|
||||||
return !deco->IsAnyOf<ast::BuiltinDecoration,
|
return !deco->IsAnyOf<ast::BuiltinDecoration,
|
||||||
ast::LocationDecoration>();
|
ast::LocationDecoration>();
|
||||||
});
|
});
|
||||||
auto member_name = ctx.Clone(member->symbol());
|
auto member_name = ctx.Clone(member->Declaration()->symbol());
|
||||||
new_struct_members.push_back(ctx.dst->Member(
|
auto* member_type = ctx.Clone(member->Declaration()->type());
|
||||||
member_name, ctx.Clone(member->type()), new_decorations));
|
new_struct_members.push_back(
|
||||||
|
ctx.dst->Member(member_name, member_type, new_decorations));
|
||||||
member_names.emplace_back(member_name);
|
member_names.emplace_back(member_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +144,8 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
ast::DecorationList new_decorations = RemoveDecorations(
|
ast::DecorationList new_decorations = RemoveDecorations(
|
||||||
&ctx, param->decorations(), [](const ast::Decoration* deco) {
|
&ctx, param->Declaration()->decorations(),
|
||||||
|
[](const ast::Decoration* deco) {
|
||||||
return !deco->IsAnyOf<ast::BuiltinDecoration,
|
return !deco->IsAnyOf<ast::BuiltinDecoration,
|
||||||
ast::LocationDecoration>();
|
ast::LocationDecoration>();
|
||||||
});
|
});
|
||||||
|
@ -151,7 +157,7 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func->body()->empty()) {
|
if (func_ast->body()->empty()) {
|
||||||
// Don't generate a function-scope const if the function is empty.
|
// Don't generate a function-scope const if the function is empty.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -160,11 +166,12 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
||||||
// Initialize it with the value extracted from the new struct parameter.
|
// Initialize it with the value extracted from the new struct parameter.
|
||||||
auto* func_const = ctx.dst->Const(
|
auto* func_const = ctx.dst->Const(
|
||||||
param_name, ctx.Clone(param_declared_ty), func_const_initializer());
|
param_name, ctx.Clone(param_declared_ty), func_const_initializer());
|
||||||
ctx.InsertBefore(func->body()->statements(), *func->body()->begin(),
|
ctx.InsertBefore(func_ast->body()->statements(),
|
||||||
|
*func_ast->body()->begin(),
|
||||||
ctx.dst->WrapInStatement(func_const));
|
ctx.dst->WrapInStatement(func_const));
|
||||||
|
|
||||||
// Replace all uses of the function parameter with the function const.
|
// Replace all uses of the function parameter with the function const.
|
||||||
for (auto* user : ctx.src->Sem().Get(param)->Users()) {
|
for (auto* user : param->Users()) {
|
||||||
ctx.Replace<ast::Expression>(user->Declaration(),
|
ctx.Replace<ast::Expression>(user->Declaration(),
|
||||||
ctx.dst->Expr(param_name));
|
ctx.dst->Expr(param_name));
|
||||||
}
|
}
|
||||||
|
@ -176,44 +183,49 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
||||||
|
|
||||||
// Create the new struct type.
|
// Create the new struct type.
|
||||||
auto in_struct_name = ctx.dst->Sym();
|
auto in_struct_name = ctx.dst->Sym();
|
||||||
auto* in_struct =
|
auto* in_struct = ctx.dst->create<ast::Struct>(
|
||||||
ctx.dst->create<sem::StructType>(ctx.dst->create<ast::Struct>(
|
in_struct_name, new_struct_members, ast::DecorationList{});
|
||||||
in_struct_name, new_struct_members, ast::DecorationList{}));
|
ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast,
|
||||||
ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func, in_struct);
|
in_struct);
|
||||||
|
|
||||||
// Create a new function parameter using this struct type.
|
// Create a new function parameter using this struct type.
|
||||||
auto* struct_param = ctx.dst->Param(new_struct_param_symbol, in_struct);
|
auto* struct_param = ctx.dst->Param(
|
||||||
|
new_struct_param_symbol, ctx.dst->ty.type_name(in_struct_name));
|
||||||
new_parameters.push_back(struct_param);
|
new_parameters.push_back(struct_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle return type.
|
// Handle return type.
|
||||||
auto* ret_type = func->return_type()->UnwrapAliasIfNeeded();
|
auto* ret_type = func->ReturnType()->UnwrapAliasIfNeeded();
|
||||||
sem::Type* new_ret_type;
|
std::function<ast::Type*()> new_ret_type;
|
||||||
if (ret_type->Is<sem::Void>()) {
|
if (ret_type->Is<sem::Void>()) {
|
||||||
new_ret_type = ctx.dst->ty.void_();
|
new_ret_type = [&ctx] { return ctx.dst->ty.void_(); };
|
||||||
} else {
|
} else {
|
||||||
ast::StructMemberList new_struct_members;
|
ast::StructMemberList new_struct_members;
|
||||||
|
|
||||||
if (auto* struct_ty = ret_type->As<sem::StructType>()) {
|
if (auto* struct_ty = ret_type->As<sem::StructType>()) {
|
||||||
|
auto* str = ctx.src->Sem().Get(struct_ty);
|
||||||
// Rebuild struct with only the entry point IO attributes.
|
// Rebuild struct with only the entry point IO attributes.
|
||||||
for (auto* member : struct_ty->impl()->members()) {
|
for (auto* member : str->Members()) {
|
||||||
if (member->type()->UnwrapAll()->Is<sem::StructType>()) {
|
if (member->Type()->UnwrapAll()->Is<sem::StructType>()) {
|
||||||
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
|
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::DecorationList new_decorations = RemoveDecorations(
|
ast::DecorationList new_decorations = RemoveDecorations(
|
||||||
&ctx, member->decorations(), [](const ast::Decoration* deco) {
|
&ctx, member->Declaration()->decorations(),
|
||||||
|
[](const ast::Decoration* deco) {
|
||||||
return !deco->IsAnyOf<ast::BuiltinDecoration,
|
return !deco->IsAnyOf<ast::BuiltinDecoration,
|
||||||
ast::LocationDecoration>();
|
ast::LocationDecoration>();
|
||||||
});
|
});
|
||||||
|
auto symbol = ctx.Clone(member->Declaration()->symbol());
|
||||||
|
auto* member_ty = ctx.Clone(member->Declaration()->type());
|
||||||
new_struct_members.push_back(
|
new_struct_members.push_back(
|
||||||
ctx.dst->Member(ctx.Clone(member->symbol()),
|
ctx.dst->Member(symbol, member_ty, new_decorations));
|
||||||
ctx.Clone(member->type()), new_decorations));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
auto* member_ty = ctx.Clone(func->Declaration()->return_type());
|
||||||
|
auto decos = ctx.Clone(func_ast->return_type_decorations());
|
||||||
new_struct_members.push_back(
|
new_struct_members.push_back(
|
||||||
ctx.dst->Member("value", ctx.Clone(ret_type),
|
ctx.dst->Member("value", member_ty, std::move(decos)));
|
||||||
ctx.Clone(func->return_type_decorations())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort struct members to satisfy HLSL interfacing matching rules.
|
// Sort struct members to satisfy HLSL interfacing matching rules.
|
||||||
|
@ -222,15 +234,16 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
||||||
|
|
||||||
// Create the new struct type.
|
// Create the new struct type.
|
||||||
auto out_struct_name = ctx.dst->Sym();
|
auto out_struct_name = ctx.dst->Sym();
|
||||||
auto* out_struct =
|
auto* out_struct = ctx.dst->create<ast::Struct>(
|
||||||
ctx.dst->create<sem::StructType>(ctx.dst->create<ast::Struct>(
|
out_struct_name, new_struct_members, ast::DecorationList{});
|
||||||
out_struct_name, new_struct_members, ast::DecorationList{}));
|
ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast,
|
||||||
ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func, out_struct);
|
out_struct);
|
||||||
new_ret_type = out_struct;
|
new_ret_type = [out_struct_name, &ctx] {
|
||||||
|
return ctx.dst->ty.type_name(out_struct_name);
|
||||||
|
};
|
||||||
|
|
||||||
// Replace all return statements.
|
// Replace all return statements.
|
||||||
auto* sem_func = ctx.src->Sem().Get(func);
|
for (auto* ret : func->ReturnStatements()) {
|
||||||
for (auto* ret : sem_func->ReturnStatements()) {
|
|
||||||
auto* ret_sem = ctx.src->Sem().Get(ret);
|
auto* ret_sem = ctx.src->Sem().Get(ret);
|
||||||
// Reconstruct the return value using the newly created struct.
|
// Reconstruct the return value using the newly created struct.
|
||||||
std::function<ast::Expression*()> new_ret_value = [&ctx, ret] {
|
std::function<ast::Expression*()> new_ret_value = [&ctx, ret] {
|
||||||
|
@ -243,8 +256,9 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
||||||
// Create a const to hold the return value expression to avoid
|
// Create a const to hold the return value expression to avoid
|
||||||
// re-evaluating it multiple times.
|
// re-evaluating it multiple times.
|
||||||
auto temp = ctx.dst->Sym();
|
auto temp = ctx.dst->Sym();
|
||||||
auto* temp_var = ctx.dst->Decl(
|
auto* ty = CreateASTTypeFor(&ctx, ret_type);
|
||||||
ctx.dst->Const(temp, ctx.Clone(ret_type), new_ret_value()));
|
auto* temp_var =
|
||||||
|
ctx.dst->Decl(ctx.dst->Const(temp, ty, new_ret_value()));
|
||||||
ctx.InsertBefore(ret_sem->Block()->statements(), ret, temp_var);
|
ctx.InsertBefore(ret_sem->Block()->statements(), ret, temp_var);
|
||||||
new_ret_value = [&ctx, temp] { return ctx.dst->Expr(temp); };
|
new_ret_value = [&ctx, temp] { return ctx.dst->Expr(temp); };
|
||||||
}
|
}
|
||||||
|
@ -258,17 +272,17 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* new_ret =
|
auto* new_ret =
|
||||||
ctx.dst->Return(ctx.dst->Construct(new_ret_type, ret_values));
|
ctx.dst->Return(ctx.dst->Construct(new_ret_type(), ret_values));
|
||||||
ctx.Replace(ret, new_ret);
|
ctx.Replace(ret, new_ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite the function header with the new parameters.
|
// Rewrite the function header with the new parameters.
|
||||||
auto* new_func = ctx.dst->create<ast::Function>(
|
auto* new_func = ctx.dst->create<ast::Function>(
|
||||||
func->source(), ctx.Clone(func->symbol()), new_parameters, new_ret_type,
|
func_ast->source(), ctx.Clone(func_ast->symbol()), new_parameters,
|
||||||
ctx.Clone(func->body()), ctx.Clone(func->decorations()),
|
new_ret_type(), ctx.Clone(func_ast->body()),
|
||||||
ast::DecorationList{});
|
ctx.Clone(func_ast->decorations()), ast::DecorationList{});
|
||||||
ctx.Replace(func, new_func);
|
ctx.Replace(func_ast, new_func);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Clone();
|
ctx.Clone();
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "src/ast/assignment_statement.h"
|
#include "src/ast/assignment_statement.h"
|
||||||
#include "src/ast/call_statement.h"
|
#include "src/ast/call_statement.h"
|
||||||
#include "src/ast/scalar_constructor_expression.h"
|
#include "src/ast/scalar_constructor_expression.h"
|
||||||
|
#include "src/ast/type_name.h"
|
||||||
#include "src/program_builder.h"
|
#include "src/program_builder.h"
|
||||||
#include "src/sem/access_control_type.h"
|
#include "src/sem/access_control_type.h"
|
||||||
#include "src/sem/array.h"
|
#include "src/sem/array.h"
|
||||||
|
@ -318,7 +319,9 @@ DecomposeStorageAccess::Intrinsic* IntrinsicStoreFor(ProgramBuilder* builder,
|
||||||
/// Inserts `node` before `insert_after` in the global declarations of
|
/// Inserts `node` before `insert_after` in the global declarations of
|
||||||
/// `ctx.dst`. If `insert_after` is nullptr, then `node` is inserted at the top
|
/// `ctx.dst`. If `insert_after` is nullptr, then `node` is inserted at the top
|
||||||
/// of the module.
|
/// of the module.
|
||||||
void InsertGlobal(CloneContext& ctx, Cloneable* insert_after, Cloneable* node) {
|
void InsertGlobal(CloneContext& ctx,
|
||||||
|
const Cloneable* insert_after,
|
||||||
|
Cloneable* node) {
|
||||||
auto& globals = ctx.src->AST().GlobalDeclarations();
|
auto& globals = ctx.src->AST().GlobalDeclarations();
|
||||||
if (insert_after) {
|
if (insert_after) {
|
||||||
ctx.InsertAfter(globals, insert_after, node);
|
ctx.InsertAfter(globals, insert_after, node);
|
||||||
|
@ -328,7 +331,7 @@ void InsertGlobal(CloneContext& ctx, Cloneable* insert_after, Cloneable* node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the unwrapped, user-declared constructed type of ty.
|
/// @returns the unwrapped, user-declared constructed type of ty.
|
||||||
sem::Type* ConstructedTypeOf(sem::Type* ty) {
|
ast::NamedType* ConstructedTypeOf(sem::Type* ty) {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (auto* ptr = ty->As<sem::Pointer>()) {
|
if (auto* ptr = ty->As<sem::Pointer>()) {
|
||||||
ty = ptr->type();
|
ty = ptr->type();
|
||||||
|
@ -338,11 +341,8 @@ sem::Type* ConstructedTypeOf(sem::Type* ty) {
|
||||||
ty = access->type();
|
ty = access->type();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (auto* alias = ty->As<sem::Alias>()) {
|
|
||||||
return alias;
|
|
||||||
}
|
|
||||||
if (auto* str = ty->As<sem::StructType>()) {
|
if (auto* str = ty->As<sem::StructType>()) {
|
||||||
return str;
|
return str->impl();
|
||||||
}
|
}
|
||||||
// Not a constructed type
|
// Not a constructed type
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -368,8 +368,10 @@ struct Store {
|
||||||
StorageBufferAccess target; // The target for the write
|
StorageBufferAccess target; // The target for the write
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
/// State holds the current transform state
|
/// State holds the current transform state
|
||||||
struct State {
|
struct DecomposeStorageAccess::State {
|
||||||
/// Map of AST expression to storage buffer access
|
/// Map of AST expression to storage buffer access
|
||||||
/// This map has entries added when encountered, and removed when outer
|
/// This map has entries added when encountered, and removed when outer
|
||||||
/// expressions chain the access.
|
/// expressions chain the access.
|
||||||
|
@ -385,9 +387,12 @@ struct State {
|
||||||
/// List of storage buffer writes
|
/// List of storage buffer writes
|
||||||
std::vector<Store> stores;
|
std::vector<Store> stores;
|
||||||
|
|
||||||
/// AddAccesss() adds the `expr -> access` map item to #accesses, and `expr`
|
/// AddAccess() adds the `expr -> access` map item to #accesses, and `expr`
|
||||||
/// to #expression_order.
|
/// to #expression_order.
|
||||||
void AddAccesss(ast::Expression* expr, StorageBufferAccess&& access) {
|
/// @param expr the expression that performs the access
|
||||||
|
/// @param access the access
|
||||||
|
void AddAccess(ast::Expression* expr, StorageBufferAccess&& access) {
|
||||||
|
TINT_ASSERT(access.type);
|
||||||
accesses.emplace(expr, std::move(access));
|
accesses.emplace(expr, std::move(access));
|
||||||
expression_order.emplace_back(expr);
|
expression_order.emplace_back(expr);
|
||||||
}
|
}
|
||||||
|
@ -395,6 +400,8 @@ struct State {
|
||||||
/// TakeAccess() removes the `node` item from #accesses (if it exists),
|
/// TakeAccess() removes the `node` item from #accesses (if it exists),
|
||||||
/// returning the StorageBufferAccess. If #accesses does not hold an item for
|
/// returning the StorageBufferAccess. If #accesses does not hold an item for
|
||||||
/// `node`, an invalid StorageBufferAccess is returned.
|
/// `node`, an invalid StorageBufferAccess is returned.
|
||||||
|
/// @param node the expression that performed an access
|
||||||
|
/// @return the StorageBufferAccess for the given expression
|
||||||
StorageBufferAccess TakeAccess(ast::Expression* node) {
|
StorageBufferAccess TakeAccess(ast::Expression* node) {
|
||||||
auto lhs_it = accesses.find(node);
|
auto lhs_it = accesses.find(node);
|
||||||
if (lhs_it == accesses.end()) {
|
if (lhs_it == accesses.end()) {
|
||||||
|
@ -408,24 +415,31 @@ struct State {
|
||||||
/// LoadFunc() returns a symbol to an intrinsic function that loads an element
|
/// LoadFunc() returns a symbol to an intrinsic function that loads an element
|
||||||
/// of type `el_ty` from a storage buffer of type `buf_ty`. The function has
|
/// of type `el_ty` from a storage buffer of type `buf_ty`. The function has
|
||||||
/// the signature: `fn load(buf : buf_ty, offset : u32) -> el_ty`
|
/// the signature: `fn load(buf : buf_ty, offset : u32) -> el_ty`
|
||||||
|
/// @param ctx the CloneContext
|
||||||
|
/// @param insert_after the user-declared type to insert the function after
|
||||||
|
/// @param buf_ty the storage buffer type
|
||||||
|
/// @param el_ty the storage buffer element type
|
||||||
|
/// @return the name of the function that performs the load
|
||||||
Symbol LoadFunc(CloneContext& ctx,
|
Symbol LoadFunc(CloneContext& ctx,
|
||||||
Cloneable* insert_after,
|
ast::NamedType* insert_after,
|
||||||
sem::Type* buf_ty,
|
sem::Type* buf_ty,
|
||||||
sem::Type* el_ty) {
|
sem::Type* el_ty) {
|
||||||
return utils::GetOrCreate(load_funcs, TypePair{buf_ty, el_ty}, [&] {
|
return utils::GetOrCreate(load_funcs, TypePair{buf_ty, el_ty}, [&] {
|
||||||
|
auto* buf_ast_ty = CreateASTTypeFor(&ctx, buf_ty);
|
||||||
ast::VariableList params = {
|
ast::VariableList params = {
|
||||||
// Note: The buffer parameter requires the kStorage StorageClass in
|
// Note: The buffer parameter requires the kStorage StorageClass in
|
||||||
// order for HLSL to emit this as a ByteAddressBuffer.
|
// order for HLSL to emit this as a ByteAddressBuffer.
|
||||||
ctx.dst->create<ast::Variable>(
|
ctx.dst->create<ast::Variable>(
|
||||||
ctx.dst->Sym("buffer"), ast::StorageClass::kStorage,
|
ctx.dst->Sym("buffer"), ast::StorageClass::kStorage, buf_ast_ty,
|
||||||
ctx.Clone(buf_ty), true, nullptr, ast::DecorationList{}),
|
true, nullptr, ast::DecorationList{}),
|
||||||
ctx.dst->Param("offset", ctx.dst->ty.u32()),
|
ctx.dst->Param("offset", ctx.dst->ty.u32()),
|
||||||
};
|
};
|
||||||
|
|
||||||
ast::Function* func = nullptr;
|
ast::Function* func = nullptr;
|
||||||
if (auto* intrinsic = IntrinsicLoadFor(ctx.dst, el_ty)) {
|
if (auto* intrinsic = IntrinsicLoadFor(ctx.dst, el_ty)) {
|
||||||
|
auto* el_ast_ty = CreateASTTypeFor(&ctx, el_ty);
|
||||||
func = ctx.dst->create<ast::Function>(
|
func = ctx.dst->create<ast::Function>(
|
||||||
ctx.dst->Sym(), params, ctx.Clone(el_ty), nullptr,
|
ctx.dst->Sym(), params, el_ast_ty, nullptr,
|
||||||
ast::DecorationList{intrinsic}, ast::DecorationList{});
|
ast::DecorationList{intrinsic}, ast::DecorationList{});
|
||||||
} else {
|
} else {
|
||||||
ast::ExpressionList values;
|
ast::ExpressionList values;
|
||||||
|
@ -444,7 +458,7 @@ struct State {
|
||||||
for (auto* member : str->Members()) {
|
for (auto* member : str->Members()) {
|
||||||
auto* offset = ctx.dst->Add("offset", member->Offset());
|
auto* offset = ctx.dst->Add("offset", member->Offset());
|
||||||
Symbol load = LoadFunc(ctx, insert_after, buf_ty,
|
Symbol load = LoadFunc(ctx, insert_after, buf_ty,
|
||||||
member->Declaration()->type()->UnwrapAll());
|
member->Type()->UnwrapAll());
|
||||||
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
|
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
|
||||||
}
|
}
|
||||||
} else if (auto* arr_ty = el_ty->As<sem::ArrayType>()) {
|
} else if (auto* arr_ty = el_ty->As<sem::ArrayType>()) {
|
||||||
|
@ -457,11 +471,12 @@ struct State {
|
||||||
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
|
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
auto* el_ast_ty = CreateASTTypeFor(&ctx, el_ty);
|
||||||
func = ctx.dst->create<ast::Function>(
|
func = ctx.dst->create<ast::Function>(
|
||||||
ctx.dst->Sym(), params, ctx.Clone(el_ty),
|
ctx.dst->Sym(), params, el_ast_ty,
|
||||||
ctx.dst->Block(
|
ctx.dst->Block(
|
||||||
ctx.dst->Return(ctx.dst->create<ast::TypeConstructorExpression>(
|
ctx.dst->Return(ctx.dst->create<ast::TypeConstructorExpression>(
|
||||||
ctx.Clone(el_ty), values))),
|
CreateASTTypeFor(&ctx, el_ty), values))),
|
||||||
ast::DecorationList{}, ast::DecorationList{});
|
ast::DecorationList{}, ast::DecorationList{});
|
||||||
}
|
}
|
||||||
InsertGlobal(ctx, insert_after, func);
|
InsertGlobal(ctx, insert_after, func);
|
||||||
|
@ -472,19 +487,26 @@ struct State {
|
||||||
/// StoreFunc() returns a symbol to an intrinsic function that stores an
|
/// StoreFunc() returns a symbol to an intrinsic function that stores an
|
||||||
/// element of type `el_ty` to a storage buffer of type `buf_ty`. The function
|
/// element of type `el_ty` to a storage buffer of type `buf_ty`. The function
|
||||||
/// has the signature: `fn store(buf : buf_ty, offset : u32, value : el_ty)`
|
/// has the signature: `fn store(buf : buf_ty, offset : u32, value : el_ty)`
|
||||||
|
/// @param ctx the CloneContext
|
||||||
|
/// @param insert_after the user-declared type to insert the function after
|
||||||
|
/// @param buf_ty the storage buffer type
|
||||||
|
/// @param el_ty the storage buffer element type
|
||||||
|
/// @return the name of the function that performs the store
|
||||||
Symbol StoreFunc(CloneContext& ctx,
|
Symbol StoreFunc(CloneContext& ctx,
|
||||||
Cloneable* insert_after,
|
ast::NamedType* insert_after,
|
||||||
sem::Type* buf_ty,
|
sem::Type* buf_ty,
|
||||||
sem::Type* el_ty) {
|
sem::Type* el_ty) {
|
||||||
return utils::GetOrCreate(store_funcs, TypePair{buf_ty, el_ty}, [&] {
|
return utils::GetOrCreate(store_funcs, TypePair{buf_ty, el_ty}, [&] {
|
||||||
|
auto* buf_ast_ty = CreateASTTypeFor(&ctx, buf_ty);
|
||||||
|
auto* el_ast_ty = CreateASTTypeFor(&ctx, el_ty);
|
||||||
ast::VariableList params{
|
ast::VariableList params{
|
||||||
// Note: The buffer parameter requires the kStorage StorageClass in
|
// Note: The buffer parameter requires the kStorage StorageClass in
|
||||||
// order for HLSL to emit this as a ByteAddressBuffer.
|
// order for HLSL to emit this as a ByteAddressBuffer.
|
||||||
ctx.dst->create<ast::Variable>(
|
ctx.dst->create<ast::Variable>(
|
||||||
ctx.dst->Sym("buffer"), ast::StorageClass::kStorage,
|
ctx.dst->Sym("buffer"), ast::StorageClass::kStorage, buf_ast_ty,
|
||||||
ctx.Clone(buf_ty), true, nullptr, ast::DecorationList{}),
|
true, nullptr, ast::DecorationList{}),
|
||||||
ctx.dst->Param("offset", ctx.dst->ty.u32()),
|
ctx.dst->Param("offset", ctx.dst->ty.u32()),
|
||||||
ctx.dst->Param("value", ctx.Clone(el_ty)),
|
ctx.dst->Param("value", el_ast_ty),
|
||||||
};
|
};
|
||||||
ast::Function* func = nullptr;
|
ast::Function* func = nullptr;
|
||||||
if (auto* intrinsic = IntrinsicStoreFor(ctx.dst, el_ty)) {
|
if (auto* intrinsic = IntrinsicStoreFor(ctx.dst, el_ty)) {
|
||||||
|
@ -512,9 +534,8 @@ struct State {
|
||||||
auto* offset = ctx.dst->Add("offset", member->Offset());
|
auto* offset = ctx.dst->Add("offset", member->Offset());
|
||||||
auto* access = ctx.dst->MemberAccessor(
|
auto* access = ctx.dst->MemberAccessor(
|
||||||
"value", ctx.Clone(member->Declaration()->symbol()));
|
"value", ctx.Clone(member->Declaration()->symbol()));
|
||||||
Symbol store =
|
Symbol store = StoreFunc(ctx, insert_after, buf_ty,
|
||||||
StoreFunc(ctx, insert_after, buf_ty,
|
member->Type()->UnwrapAll());
|
||||||
member->Declaration()->type()->UnwrapAll());
|
|
||||||
auto* call = ctx.dst->Call(store, "buffer", offset, access);
|
auto* call = ctx.dst->Call(store, "buffer", offset, access);
|
||||||
body.emplace_back(ctx.dst->create<ast::CallStatement>(call));
|
body.emplace_back(ctx.dst->create<ast::CallStatement>(call));
|
||||||
}
|
}
|
||||||
|
@ -541,8 +562,6 @@ struct State {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
DecomposeStorageAccess::Intrinsic::Intrinsic(ProgramID program_id, Type ty)
|
DecomposeStorageAccess::Intrinsic::Intrinsic(ProgramID program_id, Type ty)
|
||||||
: Base(program_id), type(ty) {}
|
: Base(program_id), type(ty) {}
|
||||||
DecomposeStorageAccess::Intrinsic::~Intrinsic() = default;
|
DecomposeStorageAccess::Intrinsic::~Intrinsic() = default;
|
||||||
|
@ -630,11 +649,11 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
|
||||||
if (auto* var = sem.Get<sem::VariableUser>(ident)) {
|
if (auto* var = sem.Get<sem::VariableUser>(ident)) {
|
||||||
if (var->Variable()->StorageClass() == ast::StorageClass::kStorage) {
|
if (var->Variable()->StorageClass() == ast::StorageClass::kStorage) {
|
||||||
// Variable to a storage buffer
|
// Variable to a storage buffer
|
||||||
state.AddAccesss(ident, {
|
state.AddAccess(ident, {
|
||||||
var,
|
var,
|
||||||
ToOffset(0u),
|
ToOffset(0u),
|
||||||
var->Type()->UnwrapAll(),
|
var->Type()->UnwrapAll(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -649,7 +668,7 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
|
||||||
auto* vec_ty = access.type->As<sem::Vector>();
|
auto* vec_ty = access.type->As<sem::Vector>();
|
||||||
auto offset =
|
auto offset =
|
||||||
Mul(ScalarSize(vec_ty->type()), swizzle->Indices()[0]);
|
Mul(ScalarSize(vec_ty->type()), swizzle->Indices()[0]);
|
||||||
state.AddAccesss(
|
state.AddAccess(
|
||||||
accessor, {
|
accessor, {
|
||||||
access.var,
|
access.var,
|
||||||
Add(std::move(access.offset), std::move(offset)),
|
Add(std::move(access.offset), std::move(offset)),
|
||||||
|
@ -663,12 +682,12 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
|
||||||
auto* member =
|
auto* member =
|
||||||
sem.Get(str_ty)->FindMember(accessor->member()->symbol());
|
sem.Get(str_ty)->FindMember(accessor->member()->symbol());
|
||||||
auto offset = member->Offset();
|
auto offset = member->Offset();
|
||||||
state.AddAccesss(accessor,
|
state.AddAccess(accessor,
|
||||||
{
|
{
|
||||||
access.var,
|
access.var,
|
||||||
Add(std::move(access.offset), std::move(offset)),
|
Add(std::move(access.offset), std::move(offset)),
|
||||||
member->Declaration()->type()->UnwrapAll(),
|
member->Type()->UnwrapAll(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -680,34 +699,34 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
|
||||||
if (auto* arr_ty = access.type->As<sem::ArrayType>()) {
|
if (auto* arr_ty = access.type->As<sem::ArrayType>()) {
|
||||||
auto stride = sem.Get(arr_ty)->Stride();
|
auto stride = sem.Get(arr_ty)->Stride();
|
||||||
auto offset = Mul(stride, accessor->idx_expr());
|
auto offset = Mul(stride, accessor->idx_expr());
|
||||||
state.AddAccesss(accessor,
|
state.AddAccess(accessor,
|
||||||
{
|
{
|
||||||
access.var,
|
access.var,
|
||||||
Add(std::move(access.offset), std::move(offset)),
|
Add(std::move(access.offset), std::move(offset)),
|
||||||
arr_ty->type()->UnwrapAll(),
|
arr_ty->type()->UnwrapAll(),
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (auto* vec_ty = access.type->As<sem::Vector>()) {
|
if (auto* vec_ty = access.type->As<sem::Vector>()) {
|
||||||
auto offset = Mul(ScalarSize(vec_ty->type()), accessor->idx_expr());
|
auto offset = Mul(ScalarSize(vec_ty->type()), accessor->idx_expr());
|
||||||
state.AddAccesss(accessor,
|
state.AddAccess(accessor,
|
||||||
{
|
{
|
||||||
access.var,
|
access.var,
|
||||||
Add(std::move(access.offset), std::move(offset)),
|
Add(std::move(access.offset), std::move(offset)),
|
||||||
vec_ty->type()->UnwrapAll(),
|
vec_ty->type()->UnwrapAll(),
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (auto* mat_ty = access.type->As<sem::Matrix>()) {
|
if (auto* mat_ty = access.type->As<sem::Matrix>()) {
|
||||||
auto offset = Mul(MatrixColumnStride(mat_ty), accessor->idx_expr());
|
auto offset = Mul(MatrixColumnStride(mat_ty), accessor->idx_expr());
|
||||||
auto* vec_ty = ctx.dst->create<sem::Vector>(
|
auto* vec_ty = ctx.dst->create<sem::Vector>(
|
||||||
ctx.Clone(mat_ty->type()->UnwrapAll()), mat_ty->rows());
|
ctx.Clone(mat_ty->type()->UnwrapAll()), mat_ty->rows());
|
||||||
state.AddAccesss(accessor,
|
state.AddAccess(accessor,
|
||||||
{
|
{
|
||||||
access.var,
|
access.var,
|
||||||
Add(std::move(access.offset), std::move(offset)),
|
Add(std::move(access.offset), std::move(offset)),
|
||||||
vec_ty,
|
vec_ty,
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,8 @@ class DecomposeStorageAccess : public Transform {
|
||||||
/// @param data optional extra transform-specific data
|
/// @param data optional extra transform-specific data
|
||||||
/// @returns the transformation result
|
/// @returns the transformation result
|
||||||
Output Run(const Program* program, const DataMap& data = {}) override;
|
Output Run(const Program* program, const DataMap& data = {}) override;
|
||||||
|
|
||||||
|
struct State;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace transform
|
} // namespace transform
|
||||||
|
|
|
@ -100,7 +100,7 @@ void Hlsl::PromoteInitializersToConstVar(CloneContext& ctx) const {
|
||||||
// Create a new symbol for the constant
|
// Create a new symbol for the constant
|
||||||
auto dst_symbol = ctx.dst->Sym();
|
auto dst_symbol = ctx.dst->Sym();
|
||||||
// Clone the type
|
// Clone the type
|
||||||
auto* dst_ty = ctx.Clone(src_ty);
|
auto* dst_ty = ctx.Clone(src_init->type());
|
||||||
// Clone the initializer
|
// Clone the initializer
|
||||||
auto* dst_init = ctx.Clone(src_init);
|
auto* dst_init = ctx.Clone(src_init);
|
||||||
// Construct the constant that holds the hoisted initializer
|
// Construct the constant that holds the hoisted initializer
|
||||||
|
|
|
@ -69,7 +69,7 @@ Output SingleEntryPoint::Run(const Program* in, const DataMap& data) {
|
||||||
// Clone any module-scope variables, types, and functions that are statically
|
// Clone any module-scope variables, types, and functions that are statically
|
||||||
// referenced by the target entry point.
|
// referenced by the target entry point.
|
||||||
for (auto* decl : in->AST().GlobalDeclarations()) {
|
for (auto* decl : in->AST().GlobalDeclarations()) {
|
||||||
if (auto* ty = decl->As<sem::Type>()) {
|
if (auto* ty = decl->As<ast::NamedType>()) {
|
||||||
// TODO(jrprice): Strip unused types.
|
// TODO(jrprice): Strip unused types.
|
||||||
out.AST().AddConstructedType(ctx.Clone(ty));
|
out.AST().AddConstructedType(ctx.Clone(ty));
|
||||||
} else if (auto* var = decl->As<ast::Variable>()) {
|
} else if (auto* var = decl->As<ast::Variable>()) {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "src/program_builder.h"
|
#include "src/program_builder.h"
|
||||||
#include "src/sem/function.h"
|
#include "src/sem/function.h"
|
||||||
#include "src/sem/statement.h"
|
#include "src/sem/statement.h"
|
||||||
|
#include "src/sem/struct.h"
|
||||||
#include "src/sem/variable.h"
|
#include "src/sem/variable.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -110,11 +111,11 @@ void Spirv::HandleEntryPointIOTypes(CloneContext& ctx) const {
|
||||||
// ```
|
// ```
|
||||||
|
|
||||||
// Strip entry point IO decorations from struct declarations.
|
// Strip entry point IO decorations from struct declarations.
|
||||||
for (auto ty : ctx.src->AST().ConstructedTypes()) {
|
for (auto* ty : ctx.src->AST().ConstructedTypes()) {
|
||||||
if (auto* struct_ty = ty->As<sem::StructType>()) {
|
if (auto* struct_ty = ty->As<ast::Struct>()) {
|
||||||
// Build new list of struct members without entry point IO decorations.
|
// Build new list of struct members without entry point IO decorations.
|
||||||
ast::StructMemberList new_struct_members;
|
ast::StructMemberList new_struct_members;
|
||||||
for (auto* member : struct_ty->impl()->members()) {
|
for (auto* member : struct_ty->members()) {
|
||||||
ast::DecorationList new_decorations = RemoveDecorations(
|
ast::DecorationList new_decorations = RemoveDecorations(
|
||||||
&ctx, member->decorations(), [](const ast::Decoration* deco) {
|
&ctx, member->decorations(), [](const ast::Decoration* deco) {
|
||||||
return deco
|
return deco
|
||||||
|
@ -126,52 +127,52 @@ void Spirv::HandleEntryPointIOTypes(CloneContext& ctx) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redeclare the struct.
|
// Redeclare the struct.
|
||||||
auto new_struct_name = ctx.Clone(struct_ty->impl()->name());
|
auto new_struct_name = ctx.Clone(struct_ty->name());
|
||||||
auto* new_struct =
|
auto* new_struct =
|
||||||
ctx.dst->create<sem::StructType>(ctx.dst->create<ast::Struct>(
|
ctx.dst->create<ast::Struct>(new_struct_name, new_struct_members,
|
||||||
new_struct_name, new_struct_members,
|
ctx.Clone(struct_ty->decorations()));
|
||||||
ctx.Clone(struct_ty->impl()->decorations())));
|
|
||||||
ctx.Replace(struct_ty, new_struct);
|
ctx.Replace(struct_ty, new_struct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* func : ctx.src->AST().Functions()) {
|
for (auto* func_ast : ctx.src->AST().Functions()) {
|
||||||
if (!func->IsEntryPoint()) {
|
if (!func_ast->IsEntryPoint()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
auto* func = ctx.src->Sem().Get(func_ast);
|
||||||
|
|
||||||
for (auto* param : func->params()) {
|
for (auto* param : func->Parameters()) {
|
||||||
Symbol new_var = HoistToInputVariables(
|
Symbol new_var = HoistToInputVariables(
|
||||||
ctx, func, ctx.src->Sem().Get(param)->Type(),
|
ctx, func_ast, param->Type(), param->Declaration()->type(),
|
||||||
ctx.src->Sem().Get(param)->DeclaredType(), param->decorations());
|
param->Declaration()->decorations());
|
||||||
|
|
||||||
// Replace all uses of the function parameter with the new variable.
|
// Replace all uses of the function parameter with the new variable.
|
||||||
for (auto* user : ctx.src->Sem().Get(param)->Users()) {
|
for (auto* user : param->Users()) {
|
||||||
ctx.Replace<ast::Expression>(user->Declaration(),
|
ctx.Replace<ast::Expression>(user->Declaration(),
|
||||||
ctx.dst->Expr(new_var));
|
ctx.dst->Expr(new_var));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!func->return_type()->Is<sem::Void>()) {
|
if (!func->ReturnType()->Is<sem::Void>()) {
|
||||||
ast::StatementList stores;
|
ast::StatementList stores;
|
||||||
auto store_value_symbol = ctx.dst->Sym();
|
auto store_value_symbol = ctx.dst->Sym();
|
||||||
HoistToOutputVariables(
|
HoistToOutputVariables(
|
||||||
ctx, func, func->return_type(), func->return_type(),
|
ctx, func_ast, func->ReturnType(), func_ast->return_type(),
|
||||||
func->return_type_decorations(), {}, store_value_symbol, stores);
|
func_ast->return_type_decorations(), {}, store_value_symbol, stores);
|
||||||
|
|
||||||
// Create a function that writes a return value to all output variables.
|
// Create a function that writes a return value to all output variables.
|
||||||
auto* store_value =
|
auto* store_value = ctx.dst->Param(store_value_symbol,
|
||||||
ctx.dst->Param(store_value_symbol, ctx.Clone(func->return_type()));
|
ctx.Clone(func_ast->return_type()));
|
||||||
auto return_func_symbol = ctx.dst->Sym();
|
auto return_func_symbol = ctx.dst->Sym();
|
||||||
auto* return_func = ctx.dst->create<ast::Function>(
|
auto* return_func = ctx.dst->create<ast::Function>(
|
||||||
return_func_symbol, ast::VariableList{store_value},
|
return_func_symbol, ast::VariableList{store_value},
|
||||||
ctx.dst->ty.void_(), ctx.dst->create<ast::BlockStatement>(stores),
|
ctx.dst->ty.void_(), ctx.dst->create<ast::BlockStatement>(stores),
|
||||||
ast::DecorationList{}, ast::DecorationList{});
|
ast::DecorationList{}, ast::DecorationList{});
|
||||||
ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func, return_func);
|
ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast,
|
||||||
|
return_func);
|
||||||
|
|
||||||
// Replace all return statements with calls to the output function.
|
// Replace all return statements with calls to the output function.
|
||||||
auto* sem_func = ctx.src->Sem().Get(func);
|
for (auto* ret : func->ReturnStatements()) {
|
||||||
for (auto* ret : sem_func->ReturnStatements()) {
|
|
||||||
auto* ret_sem = ctx.src->Sem().Get(ret);
|
auto* ret_sem = ctx.src->Sem().Get(ret);
|
||||||
auto* call = ctx.dst->Call(return_func_symbol, ctx.Clone(ret->value()));
|
auto* call = ctx.dst->Call(return_func_symbol, ctx.Clone(ret->value()));
|
||||||
ctx.InsertBefore(ret_sem->Block()->statements(), ret,
|
ctx.InsertBefore(ret_sem->Block()->statements(), ret,
|
||||||
|
@ -181,11 +182,13 @@ void Spirv::HandleEntryPointIOTypes(CloneContext& ctx) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite the function header to remove the parameters and return value.
|
// Rewrite the function header to remove the parameters and return value.
|
||||||
|
auto name = ctx.Clone(func_ast->symbol());
|
||||||
|
auto* body = ctx.Clone(func_ast->body());
|
||||||
|
auto decos = ctx.Clone(func_ast->decorations());
|
||||||
auto* new_func = ctx.dst->create<ast::Function>(
|
auto* new_func = ctx.dst->create<ast::Function>(
|
||||||
func->source(), ctx.Clone(func->symbol()), ast::VariableList{},
|
func_ast->source(), name, ast::VariableList{}, ctx.dst->ty.void_(),
|
||||||
ctx.dst->ty.void_(), ctx.Clone(func->body()),
|
body, decos, ast::DecorationList{});
|
||||||
ctx.Clone(func->decorations()), ast::DecorationList{});
|
ctx.Replace(func_ast, new_func);
|
||||||
ctx.Replace(func, new_func);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,7 +256,7 @@ Symbol Spirv::HoistToInputVariables(
|
||||||
CloneContext& ctx,
|
CloneContext& ctx,
|
||||||
const ast::Function* func,
|
const ast::Function* func,
|
||||||
sem::Type* ty,
|
sem::Type* ty,
|
||||||
sem::Type* declared_ty,
|
ast::Type* declared_ty,
|
||||||
const ast::DecorationList& decorations) const {
|
const ast::DecorationList& decorations) const {
|
||||||
if (!ty->Is<sem::StructType>()) {
|
if (!ty->Is<sem::StructType>()) {
|
||||||
// Base case: create a global variable and return.
|
// Base case: create a global variable and return.
|
||||||
|
@ -273,9 +276,10 @@ Symbol Spirv::HoistToInputVariables(
|
||||||
// Recurse into struct members and build the initializer list.
|
// Recurse into struct members and build the initializer list.
|
||||||
std::vector<Symbol> init_value_names;
|
std::vector<Symbol> init_value_names;
|
||||||
auto* struct_ty = ty->As<sem::StructType>();
|
auto* struct_ty = ty->As<sem::StructType>();
|
||||||
for (auto* member : struct_ty->impl()->members()) {
|
for (auto* member : ctx.src->Sem().Get(struct_ty)->Members()) {
|
||||||
auto member_var = HoistToInputVariables(
|
auto member_var = HoistToInputVariables(
|
||||||
ctx, func, member->type(), member->type(), member->decorations());
|
ctx, func, member->Type(), member->Declaration()->type(),
|
||||||
|
member->Declaration()->decorations());
|
||||||
init_value_names.emplace_back(member_var);
|
init_value_names.emplace_back(member_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +306,7 @@ Symbol Spirv::HoistToInputVariables(
|
||||||
void Spirv::HoistToOutputVariables(CloneContext& ctx,
|
void Spirv::HoistToOutputVariables(CloneContext& ctx,
|
||||||
const ast::Function* func,
|
const ast::Function* func,
|
||||||
sem::Type* ty,
|
sem::Type* ty,
|
||||||
sem::Type* declared_ty,
|
ast::Type* declared_ty,
|
||||||
const ast::DecorationList& decorations,
|
const ast::DecorationList& decorations,
|
||||||
std::vector<Symbol> member_accesses,
|
std::vector<Symbol> member_accesses,
|
||||||
Symbol store_value,
|
Symbol store_value,
|
||||||
|
@ -333,11 +337,12 @@ void Spirv::HoistToOutputVariables(CloneContext& ctx,
|
||||||
|
|
||||||
// Recurse into struct members.
|
// Recurse into struct members.
|
||||||
auto* struct_ty = ty->As<sem::StructType>();
|
auto* struct_ty = ty->As<sem::StructType>();
|
||||||
for (auto* member : struct_ty->impl()->members()) {
|
for (auto* member : ctx.src->Sem().Get(struct_ty)->Members()) {
|
||||||
member_accesses.push_back(ctx.Clone(member->symbol()));
|
member_accesses.push_back(ctx.Clone(member->Declaration()->symbol()));
|
||||||
HoistToOutputVariables(ctx, func, member->type(), member->type(),
|
HoistToOutputVariables(ctx, func, member->Type(),
|
||||||
member->decorations(), member_accesses, store_value,
|
member->Declaration()->type(),
|
||||||
stores);
|
member->Declaration()->decorations(),
|
||||||
|
member_accesses, store_value, stores);
|
||||||
member_accesses.pop_back();
|
member_accesses.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ class Spirv : public Transform {
|
||||||
Symbol HoistToInputVariables(CloneContext& ctx,
|
Symbol HoistToInputVariables(CloneContext& ctx,
|
||||||
const ast::Function* func,
|
const ast::Function* func,
|
||||||
sem::Type* ty,
|
sem::Type* ty,
|
||||||
sem::Type* declared_ty,
|
ast::Type* declared_ty,
|
||||||
const ast::DecorationList& decorations) const;
|
const ast::DecorationList& decorations) const;
|
||||||
|
|
||||||
/// Recursively create module-scope output variables for `ty` and build a list
|
/// Recursively create module-scope output variables for `ty` and build a list
|
||||||
|
@ -74,7 +74,7 @@ class Spirv : public Transform {
|
||||||
void HoistToOutputVariables(CloneContext& ctx,
|
void HoistToOutputVariables(CloneContext& ctx,
|
||||||
const ast::Function* func,
|
const ast::Function* func,
|
||||||
sem::Type* ty,
|
sem::Type* ty,
|
||||||
sem::Type* declared_ty,
|
ast::Type* declared_ty,
|
||||||
const ast::DecorationList& decorations,
|
const ast::DecorationList& decorations,
|
||||||
std::vector<Symbol> member_accesses,
|
std::vector<Symbol> member_accesses,
|
||||||
Symbol store_value,
|
Symbol store_value,
|
||||||
|
|
|
@ -49,7 +49,7 @@ ast::Function* Transform::CloneWithStatementsAtStart(
|
||||||
auto source = ctx->Clone(in->source());
|
auto source = ctx->Clone(in->source());
|
||||||
auto symbol = ctx->Clone(in->symbol());
|
auto symbol = ctx->Clone(in->symbol());
|
||||||
auto params = ctx->Clone(in->params());
|
auto params = ctx->Clone(in->params());
|
||||||
auto return_type = ctx->Clone(in->return_type());
|
auto* return_type = ctx->Clone(in->return_type());
|
||||||
auto* body = ctx->dst->create<ast::BlockStatement>(
|
auto* body = ctx->dst->create<ast::BlockStatement>(
|
||||||
ctx->Clone(in->body()->source()), statements);
|
ctx->Clone(in->body()->source()), statements);
|
||||||
auto decos = ctx->Clone(in->decorations());
|
auto decos = ctx->Clone(in->decorations());
|
||||||
|
|
|
@ -184,7 +184,7 @@ struct State {
|
||||||
// identifier strings instead of pointers, so we don't need to update
|
// identifier strings instead of pointers, so we don't need to update
|
||||||
// any other place in the AST.
|
// any other place in the AST.
|
||||||
auto name = ctx.Clone(v->symbol());
|
auto name = ctx.Clone(v->symbol());
|
||||||
auto* replacement = ctx.dst->Var(name, ctx.Clone(v->declared_type()),
|
auto* replacement = ctx.dst->Var(name, ctx.Clone(v->type()),
|
||||||
ast::StorageClass::kPrivate);
|
ast::StorageClass::kPrivate);
|
||||||
location_to_expr[location] = [this, name]() {
|
location_to_expr[location] = [this, name]() {
|
||||||
return ctx.dst->Expr(name);
|
return ctx.dst->Expr(name);
|
||||||
|
@ -212,9 +212,9 @@ struct State {
|
||||||
{
|
{
|
||||||
ctx.dst->create<ast::StructBlockDecoration>(),
|
ctx.dst->create<ast::StructBlockDecoration>(),
|
||||||
});
|
});
|
||||||
auto access =
|
|
||||||
ctx.dst->ty.access(ast::AccessControl::kReadOnly, struct_type);
|
|
||||||
for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) {
|
for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) {
|
||||||
|
auto access =
|
||||||
|
ctx.dst->ty.access(ast::AccessControl::kReadOnly, struct_type);
|
||||||
// The decorated variable with struct type
|
// The decorated variable with struct type
|
||||||
ctx.dst->Global(
|
ctx.dst->Global(
|
||||||
GetVertexBufferName(i), access, ast::StorageClass::kStorage, nullptr,
|
GetVertexBufferName(i), access, ast::StorageClass::kStorage, nullptr,
|
||||||
|
@ -369,7 +369,7 @@ struct State {
|
||||||
/// @param count how many elements the vector has
|
/// @param count how many elements the vector has
|
||||||
ast::Expression* AccessVec(uint32_t buffer,
|
ast::Expression* AccessVec(uint32_t buffer,
|
||||||
uint32_t element_stride,
|
uint32_t element_stride,
|
||||||
sem::Type* base_type,
|
ast::Type* base_type,
|
||||||
VertexFormat base_format,
|
VertexFormat base_format,
|
||||||
uint32_t count) {
|
uint32_t count) {
|
||||||
ast::ExpressionList expr_list;
|
ast::ExpressionList expr_list;
|
||||||
|
@ -381,7 +381,7 @@ struct State {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.dst->create<ast::TypeConstructorExpression>(
|
return ctx.dst->create<ast::TypeConstructorExpression>(
|
||||||
ctx.dst->create<sem::Vector>(base_type, count), std::move(expr_list));
|
ctx.dst->create<ast::Vector>(base_type, count), std::move(expr_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process a non-struct entry point parameter.
|
/// Process a non-struct entry point parameter.
|
||||||
|
@ -394,7 +394,7 @@ struct State {
|
||||||
ast::GetDecoration<ast::LocationDecoration>(param->decorations())) {
|
ast::GetDecoration<ast::LocationDecoration>(param->decorations())) {
|
||||||
// Create a function-scope variable to replace the parameter.
|
// Create a function-scope variable to replace the parameter.
|
||||||
auto func_var_sym = ctx.Clone(param->symbol());
|
auto func_var_sym = ctx.Clone(param->symbol());
|
||||||
auto* func_var_type = ctx.Clone(param->declared_type());
|
auto* func_var_type = ctx.Clone(param->type());
|
||||||
auto* func_var = ctx.dst->Var(func_var_sym, func_var_type,
|
auto* func_var = ctx.dst->Var(func_var_sym, func_var_type,
|
||||||
ast::StorageClass::kFunction);
|
ast::StorageClass::kFunction);
|
||||||
ctx.InsertBefore(func->body()->statements(), *func->body()->begin(),
|
ctx.InsertBefore(func->body()->statements(), *func->body()->begin(),
|
||||||
|
@ -428,18 +428,16 @@ struct State {
|
||||||
/// instance_index builtins.
|
/// instance_index builtins.
|
||||||
/// @param func the entry point function
|
/// @param func the entry point function
|
||||||
/// @param param the parameter to process
|
/// @param param the parameter to process
|
||||||
void ProcessStructParameter(ast::Function* func, ast::Variable* param) {
|
/// @param struct_ty the structure type
|
||||||
auto* struct_ty = param->declared_type()->As<sem::StructType>();
|
void ProcessStructParameter(ast::Function* func,
|
||||||
if (!struct_ty) {
|
ast::Variable* param,
|
||||||
TINT_ICE(ctx.dst->Diagnostics()) << "Invalid struct parameter";
|
ast::Struct* struct_ty) {
|
||||||
}
|
|
||||||
|
|
||||||
auto param_sym = ctx.Clone(param->symbol());
|
auto param_sym = ctx.Clone(param->symbol());
|
||||||
|
|
||||||
// Process the struct members.
|
// Process the struct members.
|
||||||
bool has_locations = false;
|
bool has_locations = false;
|
||||||
ast::StructMemberList members_to_clone;
|
ast::StructMemberList members_to_clone;
|
||||||
for (auto* member : struct_ty->impl()->members()) {
|
for (auto* member : struct_ty->members()) {
|
||||||
auto member_sym = ctx.Clone(member->symbol());
|
auto member_sym = ctx.Clone(member->symbol());
|
||||||
std::function<ast::Expression*()> member_expr = [this, param_sym,
|
std::function<ast::Expression*()> member_expr = [this, param_sym,
|
||||||
member_sym]() {
|
member_sym]() {
|
||||||
|
@ -472,7 +470,7 @@ struct State {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a function-scope variable to replace the parameter.
|
// Create a function-scope variable to replace the parameter.
|
||||||
auto* func_var = ctx.dst->Var(param_sym, ctx.Clone(param->declared_type()),
|
auto* func_var = ctx.dst->Var(param_sym, ctx.Clone(param->type()),
|
||||||
ast::StorageClass::kFunction);
|
ast::StorageClass::kFunction);
|
||||||
ctx.InsertBefore(func->body()->statements(), *func->body()->begin(),
|
ctx.InsertBefore(func->body()->statements(), *func->body()->begin(),
|
||||||
ctx.dst->Decl(func_var));
|
ctx.dst->Decl(func_var));
|
||||||
|
@ -482,7 +480,7 @@ struct State {
|
||||||
ast::StructMemberList new_members;
|
ast::StructMemberList new_members;
|
||||||
for (auto* member : members_to_clone) {
|
for (auto* member : members_to_clone) {
|
||||||
auto member_sym = ctx.Clone(member->symbol());
|
auto member_sym = ctx.Clone(member->symbol());
|
||||||
auto member_type = ctx.Clone(member->type());
|
auto* member_type = ctx.Clone(member->type());
|
||||||
auto member_decos = ctx.Clone(member->decorations());
|
auto member_decos = ctx.Clone(member->decorations());
|
||||||
new_members.push_back(
|
new_members.push_back(
|
||||||
ctx.dst->Member(member_sym, member_type, std::move(member_decos)));
|
ctx.dst->Member(member_sym, member_type, std::move(member_decos)));
|
||||||
|
@ -514,8 +512,8 @@ struct State {
|
||||||
// Process entry point parameters.
|
// Process entry point parameters.
|
||||||
for (auto* param : func->params()) {
|
for (auto* param : func->params()) {
|
||||||
auto* sem = ctx.src->Sem().Get(param);
|
auto* sem = ctx.src->Sem().Get(param);
|
||||||
if (sem->Type()->Is<sem::StructType>()) {
|
if (auto* str = sem->Type()->As<sem::StructType>()) {
|
||||||
ProcessStructParameter(func, param);
|
ProcessStructParameter(func, param, str->impl());
|
||||||
} else {
|
} else {
|
||||||
ProcessNonStructParameter(func, param);
|
ProcessNonStructParameter(func, param);
|
||||||
}
|
}
|
||||||
|
@ -553,7 +551,7 @@ struct State {
|
||||||
|
|
||||||
// Rewrite the function header with the new parameters.
|
// Rewrite the function header with the new parameters.
|
||||||
auto func_sym = ctx.Clone(func->symbol());
|
auto func_sym = ctx.Clone(func->symbol());
|
||||||
auto ret_type = ctx.Clone(func->return_type());
|
auto* ret_type = ctx.Clone(func->return_type());
|
||||||
auto* body = ctx.Clone(func->body());
|
auto* body = ctx.Clone(func->body());
|
||||||
auto decos = ctx.Clone(func->decorations());
|
auto decos = ctx.Clone(func->decorations());
|
||||||
auto ret_decos = ctx.Clone(func->return_type_decorations());
|
auto ret_decos = ctx.Clone(func->return_type_decorations());
|
||||||
|
|
|
@ -23,9 +23,10 @@ namespace writer {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
ast::TypeConstructorExpression* AsVectorConstructor(ast::Expression* expr) {
|
ast::TypeConstructorExpression* AsVectorConstructor(ProgramBuilder* b,
|
||||||
|
ast::Expression* expr) {
|
||||||
if (auto* constructor = expr->As<ast::TypeConstructorExpression>()) {
|
if (auto* constructor = expr->As<ast::TypeConstructorExpression>()) {
|
||||||
if (constructor->type()->Is<sem::Vector>()) {
|
if (b->TypeOf(constructor)->Is<sem::Vector>()) {
|
||||||
return constructor;
|
return constructor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,42 +39,52 @@ ast::TypeConstructorExpression* AppendVector(ProgramBuilder* b,
|
||||||
ast::Expression* vector,
|
ast::Expression* vector,
|
||||||
ast::Expression* scalar) {
|
ast::Expression* scalar) {
|
||||||
uint32_t packed_size;
|
uint32_t packed_size;
|
||||||
sem::Type* packed_el_ty; // Currently must be f32.
|
sem::Type* packed_el_sem_ty;
|
||||||
auto* vector_sem = b->Sem().Get(vector);
|
auto* vector_sem = b->Sem().Get(vector);
|
||||||
auto* vector_ty = vector_sem->Type()->UnwrapPtrIfNeeded();
|
auto* vector_ty = vector_sem->Type()->UnwrapPtrIfNeeded();
|
||||||
if (auto* vec = vector_ty->As<sem::Vector>()) {
|
if (auto* vec = vector_ty->As<sem::Vector>()) {
|
||||||
packed_size = vec->size() + 1;
|
packed_size = vec->size() + 1;
|
||||||
packed_el_ty = vec->type();
|
packed_el_sem_ty = vec->type();
|
||||||
} else {
|
} else {
|
||||||
packed_size = 2;
|
packed_size = 2;
|
||||||
packed_el_ty = vector_ty;
|
packed_el_sem_ty = vector_ty;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::Type* packed_el_ty = nullptr;
|
||||||
|
if (packed_el_sem_ty->Is<sem::I32>()) {
|
||||||
|
packed_el_ty = b->create<ast::I32>();
|
||||||
|
} else if (packed_el_sem_ty->Is<sem::U32>()) {
|
||||||
|
packed_el_ty = b->create<ast::U32>();
|
||||||
|
} else if (packed_el_sem_ty->Is<sem::F32>()) {
|
||||||
|
packed_el_ty = b->create<ast::F32>();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* statement = vector_sem->Stmt();
|
auto* statement = vector_sem->Stmt();
|
||||||
|
|
||||||
auto* packed_ty = b->create<sem::Vector>(packed_el_ty, packed_size);
|
auto* packed_ty = b->create<ast::Vector>(packed_el_ty, packed_size);
|
||||||
|
auto* packed_sem_ty = b->create<sem::Vector>(packed_el_sem_ty, packed_size);
|
||||||
|
|
||||||
// If the coordinates are already passed in a vector constructor, extract
|
// If the coordinates are already passed in a vector constructor, extract
|
||||||
// the elements into the new vector instead of nesting a vector-in-vector.
|
// the elements into the new vector instead of nesting a vector-in-vector.
|
||||||
ast::ExpressionList packed;
|
ast::ExpressionList packed;
|
||||||
if (auto* vc = AsVectorConstructor(vector)) {
|
if (auto* vc = AsVectorConstructor(b, vector)) {
|
||||||
packed = vc->values();
|
packed = vc->values();
|
||||||
} else {
|
} else {
|
||||||
packed.emplace_back(vector);
|
packed.emplace_back(vector);
|
||||||
}
|
}
|
||||||
if (packed_el_ty != b->Sem().Get(scalar)->Type()->UnwrapPtrIfNeeded()) {
|
if (packed_el_sem_ty != b->TypeOf(scalar)->UnwrapPtrIfNeeded()) {
|
||||||
// Cast scalar to the vector element type
|
// Cast scalar to the vector element type
|
||||||
auto* scalar_cast = b->Construct(packed_el_ty, scalar);
|
auto* scalar_cast = b->Construct(packed_el_ty, scalar);
|
||||||
b->Sem().Add(scalar_cast, b->create<sem::Expression>(
|
b->Sem().Add(scalar_cast, b->create<sem::Expression>(
|
||||||
scalar_cast, packed_el_ty, statement));
|
scalar_cast, packed_el_sem_ty, statement));
|
||||||
packed.emplace_back(scalar_cast);
|
packed.emplace_back(scalar_cast);
|
||||||
} else {
|
} else {
|
||||||
packed.emplace_back(scalar);
|
packed.emplace_back(scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* constructor = b->Construct(packed_ty, std::move(packed));
|
auto* constructor = b->Construct(packed_ty, std::move(packed));
|
||||||
b->Sem().Add(constructor,
|
b->Sem().Add(constructor, b->create<sem::Expression>(
|
||||||
b->create<sem::Expression>(constructor, packed_ty, statement));
|
constructor, packed_sem_ty, statement));
|
||||||
|
|
||||||
return constructor;
|
return constructor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,8 +119,11 @@ bool GeneratorImpl::Generate(std::ostream& out) {
|
||||||
register_global(global);
|
register_global(global);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const ty : builder_.AST().ConstructedTypes()) {
|
for (auto* const ty : builder_.AST().ConstructedTypes()) {
|
||||||
if (!EmitConstructedType(out, ty)) {
|
if (ty->Is<ast::Alias>()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!EmitConstructedType(out, TypeOf(ty))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2012,7 +2015,7 @@ bool GeneratorImpl::EmitEntryPointFunction(std::ostream& out,
|
||||||
bool has_outdata = outdata != ep_sym_to_out_data_.end();
|
bool has_outdata = outdata != ep_sym_to_out_data_.end();
|
||||||
if (has_outdata) {
|
if (has_outdata) {
|
||||||
// TODO(crbug.com/tint/697): Remove this.
|
// TODO(crbug.com/tint/697): Remove this.
|
||||||
if (!func->return_type()->Is<sem::Void>()) {
|
if (!func->return_type()->Is<ast::Void>()) {
|
||||||
TINT_ICE(diagnostics_) << "Mixing module-scope variables and return "
|
TINT_ICE(diagnostics_) << "Mixing module-scope variables and return "
|
||||||
"types for shader outputs";
|
"types for shader outputs";
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,7 +381,7 @@ class GeneratorImpl : public TextGenerator {
|
||||||
|
|
||||||
/// @returns the resolved type of the ast::Type `type`
|
/// @returns the resolved type of the ast::Type `type`
|
||||||
/// @param type the type
|
/// @param type the type
|
||||||
const sem::Type* TypeOf(ast::Type* type) const {
|
const sem::Type* TypeOf(const ast::Type* type) const {
|
||||||
return builder_.TypeOf(type);
|
return builder_.TypeOf(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "src/ast/sint_literal.h"
|
#include "src/ast/sint_literal.h"
|
||||||
#include "src/ast/uint_literal.h"
|
#include "src/ast/uint_literal.h"
|
||||||
#include "src/ast/variable_decl_statement.h"
|
#include "src/ast/variable_decl_statement.h"
|
||||||
|
#include "src/ast/void.h"
|
||||||
#include "src/sem/access_control_type.h"
|
#include "src/sem/access_control_type.h"
|
||||||
#include "src/sem/alias_type.h"
|
#include "src/sem/alias_type.h"
|
||||||
#include "src/sem/array.h"
|
#include "src/sem/array.h"
|
||||||
|
@ -86,8 +87,8 @@ bool GeneratorImpl::Generate() {
|
||||||
global_variables_.set(global->symbol(), sem);
|
global_variables_.set(global->symbol(), sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const ty : program_->AST().ConstructedTypes()) {
|
for (auto* const ty : program_->AST().ConstructedTypes()) {
|
||||||
if (!EmitConstructedType(ty)) {
|
if (!EmitConstructedType(TypeOf(ty))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1400,7 +1401,7 @@ bool GeneratorImpl::EmitEntryPointFunction(ast::Function* func) {
|
||||||
bool has_out_data = out_data != ep_sym_to_out_data_.end();
|
bool has_out_data = out_data != ep_sym_to_out_data_.end();
|
||||||
if (has_out_data) {
|
if (has_out_data) {
|
||||||
// TODO(crbug.com/tint/697): Remove this.
|
// TODO(crbug.com/tint/697): Remove this.
|
||||||
if (!func->return_type()->Is<sem::Void>()) {
|
if (!func->return_type()->Is<ast::Void>()) {
|
||||||
TINT_ICE(diagnostics_) << "Mixing module-scope variables and return "
|
TINT_ICE(diagnostics_) << "Mixing module-scope variables and return "
|
||||||
"types for shader outputs";
|
"types for shader outputs";
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,7 +275,7 @@ class GeneratorImpl : public TextGenerator {
|
||||||
|
|
||||||
/// @returns the resolved type of the ast::Type `type`
|
/// @returns the resolved type of the ast::Type `type`
|
||||||
/// @param type the type
|
/// @param type the type
|
||||||
const sem::Type* TypeOf(ast::Type* type) const {
|
const sem::Type* TypeOf(const ast::Type* type) const {
|
||||||
return program_->TypeOf(type);
|
return program_->TypeOf(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -842,9 +842,8 @@ TEST_F(BuilderTest_Type, SampledTexture_Generate_CubeArray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type, StorageTexture_Generate_1d) {
|
TEST_F(BuilderTest_Type, StorageTexture_Generate_1d) {
|
||||||
auto* s = create<sem::StorageTexture>(
|
auto s = ty.storage_texture(ast::TextureDimension::k1d,
|
||||||
ast::TextureDimension::k1d, ast::ImageFormat::kR32Float,
|
ast::ImageFormat::kR32Float);
|
||||||
sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR32Float, Types()));
|
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kInput);
|
||||||
|
@ -859,9 +858,8 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_1d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type, StorageTexture_Generate_2d) {
|
TEST_F(BuilderTest_Type, StorageTexture_Generate_2d) {
|
||||||
auto* s = create<sem::StorageTexture>(
|
auto s = ty.storage_texture(ast::TextureDimension::k2d,
|
||||||
ast::TextureDimension::k2d, ast::ImageFormat::kR32Float,
|
ast::ImageFormat::kR32Float);
|
||||||
sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR32Float, Types()));
|
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kInput);
|
||||||
|
@ -876,9 +874,8 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_2d) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type, StorageTexture_Generate_2dArray) {
|
TEST_F(BuilderTest_Type, StorageTexture_Generate_2dArray) {
|
||||||
auto* s = create<sem::StorageTexture>(
|
auto s = ty.storage_texture(ast::TextureDimension::k2dArray,
|
||||||
ast::TextureDimension::k2dArray, ast::ImageFormat::kR32Float,
|
ast::ImageFormat::kR32Float);
|
||||||
sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR32Float, Types()));
|
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kInput);
|
||||||
|
@ -893,9 +890,8 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_2dArray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type, StorageTexture_Generate_3d) {
|
TEST_F(BuilderTest_Type, StorageTexture_Generate_3d) {
|
||||||
auto* s = create<sem::StorageTexture>(
|
auto s = ty.storage_texture(ast::TextureDimension::k3d,
|
||||||
ast::TextureDimension::k3d, ast::ImageFormat::kR32Float,
|
ast::ImageFormat::kR32Float);
|
||||||
sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR32Float, Types()));
|
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kInput);
|
||||||
|
@ -911,9 +907,8 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_3d) {
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type,
|
TEST_F(BuilderTest_Type,
|
||||||
StorageTexture_Generate_SampledTypeFloat_Format_r32float) {
|
StorageTexture_Generate_SampledTypeFloat_Format_r32float) {
|
||||||
auto* s = create<sem::StorageTexture>(
|
auto s = ty.storage_texture(ast::TextureDimension::k2d,
|
||||||
ast::TextureDimension::k2d, ast::ImageFormat::kR32Float,
|
ast::ImageFormat::kR32Float);
|
||||||
sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR32Float, Types()));
|
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kInput);
|
||||||
|
@ -929,9 +924,8 @@ TEST_F(BuilderTest_Type,
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type,
|
TEST_F(BuilderTest_Type,
|
||||||
StorageTexture_Generate_SampledTypeSint_Format_r32sint) {
|
StorageTexture_Generate_SampledTypeSint_Format_r32sint) {
|
||||||
auto* s = create<sem::StorageTexture>(
|
auto s = ty.storage_texture(ast::TextureDimension::k2d,
|
||||||
ast::TextureDimension::k2d, ast::ImageFormat::kR32Sint,
|
ast::ImageFormat::kR32Sint);
|
||||||
sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR32Sint, Types()));
|
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kInput);
|
||||||
|
@ -947,9 +941,8 @@ TEST_F(BuilderTest_Type,
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type,
|
TEST_F(BuilderTest_Type,
|
||||||
StorageTexture_Generate_SampledTypeUint_Format_r32uint) {
|
StorageTexture_Generate_SampledTypeUint_Format_r32uint) {
|
||||||
auto* s = create<sem::StorageTexture>(
|
auto s = ty.storage_texture(ast::TextureDimension::k2d,
|
||||||
ast::TextureDimension::k2d, ast::ImageFormat::kR32Uint,
|
ast::ImageFormat::kR32Uint);
|
||||||
sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR32Uint, Types()));
|
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kInput);
|
||||||
|
|
|
@ -83,10 +83,6 @@ bool GeneratorImpl::Generate(const ast::Function* entry) {
|
||||||
if (!EmitConstructedType(ty)) {
|
if (!EmitConstructedType(ty)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (auto* sem_ty = decl->As<sem::Type>()) {
|
|
||||||
if (!EmitConstructedType(sem_ty)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (auto* func = decl->As<ast::Function>()) {
|
} else if (auto* func = decl->As<ast::Function>()) {
|
||||||
if (entry && func != entry) {
|
if (entry && func != entry) {
|
||||||
// Skip functions that are not reachable by the target entry point.
|
// Skip functions that are not reachable by the target entry point.
|
||||||
|
@ -363,8 +359,7 @@ bool GeneratorImpl::EmitFunction(ast::Function* func) {
|
||||||
|
|
||||||
out_ << ")";
|
out_ << ")";
|
||||||
|
|
||||||
if (!(Is<ast::Void>(func->return_type().ast) ||
|
if (!func->return_type()->Is<ast::Void>() ||
|
||||||
Is<sem::Void>(func->return_type().sem)) ||
|
|
||||||
!func->return_type_decorations().empty()) {
|
!func->return_type_decorations().empty()) {
|
||||||
out_ << " -> ";
|
out_ << " -> ";
|
||||||
|
|
||||||
|
@ -776,9 +771,9 @@ bool GeneratorImpl::EmitVariable(ast::Variable* var) {
|
||||||
|
|
||||||
out_ << " " << program_->Symbols().NameFor(var->symbol());
|
out_ << " " << program_->Symbols().NameFor(var->symbol());
|
||||||
|
|
||||||
if (var->type().ast || var->type().sem) {
|
if (auto* ty = var->type()) {
|
||||||
out_ << " : ";
|
out_ << " : ";
|
||||||
if (!EmitType(var->type())) {
|
if (!EmitType(ty)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,8 @@ TEST_P(WgslUnaryOpTest, Emit) {
|
||||||
auto params = GetParam();
|
auto params = GetParam();
|
||||||
|
|
||||||
auto* type = (params.op == ast::UnaryOp::kNot)
|
auto* type = (params.op == ast::UnaryOp::kNot)
|
||||||
? static_cast<sem::Type*>(ty.bool_())
|
? static_cast<ast::Type*>(ty.bool_())
|
||||||
: static_cast<sem::Type*>(ty.i32());
|
: static_cast<ast::Type*>(ty.i32());
|
||||||
Global("expr", type, ast::StorageClass::kPrivate);
|
Global("expr", type, ast::StorageClass::kPrivate);
|
||||||
|
|
||||||
auto* op = create<ast::UnaryOpExpression>(params.op, Expr("expr"));
|
auto* op = create<ast::UnaryOpExpression>(params.op, Expr("expr"));
|
||||||
|
|
Loading…
Reference in New Issue