sem: Fold together sem::Struct and sem::StructType

There's now no need to have both.
Removes a whole bunch of Sem().Get() smell, and simplifies the resolver.

Bug: tint:724
Fixed: tint:761
Change-Id: I756a32680ac52441fd6eebf6fc53dd507ef5e538
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/49961
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2021-05-07 14:49:34 +00:00 committed by Commit Bot service account
parent 33d0f6aa08
commit ba6ab5e6bd
86 changed files with 962 additions and 1313 deletions

View File

@ -480,8 +480,6 @@ libtint_source_set("libtint_core_all_src") {
"sem/sampler_type.h", "sem/sampler_type.h",
"sem/storage_texture_type.cc", "sem/storage_texture_type.cc",
"sem/storage_texture_type.h", "sem/storage_texture_type.h",
"sem/struct_type.cc",
"sem/struct_type.h",
"sem/texture_type.cc", "sem/texture_type.cc",
"sem/texture_type.h", "sem/texture_type.h",
"sem/type.cc", "sem/type.cc",

View File

@ -313,8 +313,6 @@ set(TINT_LIB_SRCS
sem/sampler_type.h sem/sampler_type.h
sem/storage_texture_type.cc sem/storage_texture_type.cc
sem/storage_texture_type.h sem/storage_texture_type.h
sem/struct_type.cc
sem/struct_type.h
sem/texture_type.cc sem/texture_type.cc
sem/texture_type.h sem/texture_type.h
sem/type.cc sem/type.cc
@ -581,8 +579,8 @@ if(${TINT_BUILD_TESTS})
sem/pointer_type_test.cc sem/pointer_type_test.cc
sem/sampled_texture_type_test.cc sem/sampled_texture_type_test.cc
sem/sampler_type_test.cc sem/sampler_type_test.cc
sem/sem_struct_test.cc
sem/storage_texture_type_test.cc sem/storage_texture_type_test.cc
sem/struct_type_test.cc
sem/texture_type_test.cc sem/texture_type_test.cc
sem/type_manager_test.cc sem/type_manager_test.cc
sem/u32_type_test.cc sem/u32_type_test.cc
@ -809,7 +807,6 @@ if(${TINT_BUILD_TESTS})
if(${TINT_BUILD_MSL_WRITER}) if(${TINT_BUILD_MSL_WRITER})
list(APPEND TINT_TEST_SRCS list(APPEND TINT_TEST_SRCS
writer/msl/generator_impl_alias_type_test.cc
writer/msl/generator_impl_array_accessor_test.cc writer/msl/generator_impl_array_accessor_test.cc
writer/msl/generator_impl_assign_test.cc writer/msl/generator_impl_assign_test.cc
writer/msl/generator_impl_binary_test.cc writer/msl/generator_impl_binary_test.cc
@ -846,7 +843,6 @@ if(${TINT_BUILD_TESTS})
if (${TINT_BUILD_HLSL_WRITER}) if (${TINT_BUILD_HLSL_WRITER})
list(APPEND TINT_TEST_SRCS list(APPEND TINT_TEST_SRCS
transform/hlsl_test.cc transform/hlsl_test.cc
writer/hlsl/generator_impl_alias_type_test.cc
writer/hlsl/generator_impl_array_accessor_test.cc writer/hlsl/generator_impl_array_accessor_test.cc
writer/hlsl/generator_impl_assign_test.cc writer/hlsl/generator_impl_assign_test.cc
writer/hlsl/generator_impl_binary_test.cc writer/hlsl/generator_impl_binary_test.cc

View File

@ -33,7 +33,6 @@
#include "src/sem/sampled_texture_type.h" #include "src/sem/sampled_texture_type.h"
#include "src/sem/storage_texture_type.h" #include "src/sem/storage_texture_type.h"
#include "src/sem/struct.h" #include "src/sem/struct.h"
#include "src/sem/struct_type.h"
#include "src/sem/u32_type.h" #include "src/sem/u32_type.h"
#include "src/sem/variable.h" #include "src/sem/variable.h"
#include "src/sem/vector_type.h" #include "src/sem/vector_type.h"
@ -389,7 +388,7 @@ std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
auto binding_info = ruv.second; auto binding_info = ruv.second;
auto* unwrapped_type = var->Type()->UnwrapIfNeeded(); auto* unwrapped_type = var->Type()->UnwrapIfNeeded();
auto* str = unwrapped_type->As<sem::StructType>(); auto* str = unwrapped_type->As<sem::Struct>();
if (str == nullptr) { if (str == nullptr) {
continue; continue;
} }
@ -398,19 +397,12 @@ std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
continue; continue;
} }
auto* sem = program_->Sem().Get(str);
if (!sem) {
error_ = "Missing semantic information for structure " +
program_->Symbols().NameFor(str->impl()->name());
continue;
}
ResourceBinding entry; ResourceBinding entry;
entry.resource_type = ResourceBinding::ResourceType::kUniformBuffer; entry.resource_type = ResourceBinding::ResourceType::kUniformBuffer;
entry.bind_group = binding_info.group->value(); entry.bind_group = binding_info.group->value();
entry.binding = binding_info.binding->value(); entry.binding = binding_info.binding->value();
entry.size = sem->Size(); entry.size = str->Size();
entry.size_no_padding = sem->SizeNoPadding(); entry.size_no_padding = str->SizeNoPadding();
result.push_back(entry); result.push_back(entry);
} }
@ -554,10 +546,9 @@ void Inspector::AddEntryPointInOutVariables(
auto* unwrapped_type = type->UnwrapAll(); auto* unwrapped_type = type->UnwrapAll();
if (auto* struct_ty = unwrapped_type->As<sem::StructType>()) { if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {
// Recurse into members. // Recurse into members.
auto* sem = program_->Sem().Get(struct_ty); for (auto* member : struct_ty->Members()) {
for (auto* member : sem->Members()) {
AddEntryPointInOutVariables( AddEntryPointInOutVariables(
name + "." + name + "." +
program_->Symbols().NameFor(member->Declaration()->symbol()), program_->Symbols().NameFor(member->Declaration()->symbol()),
@ -611,26 +602,19 @@ std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindingsImpl(
continue; continue;
} }
auto* str = var->Type()->UnwrapIfNeeded()->As<sem::StructType>(); auto* str = var->Type()->UnwrapIfNeeded()->As<sem::Struct>();
if (!str) { if (!str) {
continue; continue;
} }
auto* sem = program_->Sem().Get(str);
if (!sem) {
error_ = "Missing semantic information for structure " +
program_->Symbols().NameFor(str->impl()->name());
continue;
}
ResourceBinding entry; ResourceBinding entry;
entry.resource_type = entry.resource_type =
read_only ? ResourceBinding::ResourceType::kReadOnlyStorageBuffer read_only ? ResourceBinding::ResourceType::kReadOnlyStorageBuffer
: ResourceBinding::ResourceType::kStorageBuffer; : ResourceBinding::ResourceType::kStorageBuffer;
entry.bind_group = binding_info.group->value(); entry.bind_group = binding_info.group->value();
entry.binding = binding_info.binding->value(); entry.binding = binding_info.binding->value();
entry.size = sem->Size(); entry.size = str->Size();
entry.size_no_padding = sem->SizeNoPadding(); entry.size_no_padding = str->SizeNoPadding();
result.push_back(entry); result.push_back(entry);
} }

View File

@ -80,7 +80,7 @@ void ProgramBuilder::MarkAsMoved() {
void ProgramBuilder::AssertNotMoved() const { void ProgramBuilder::AssertNotMoved() const {
if (moved_) { if (moved_) {
TINT_ICE(const_cast<ProgramBuilder*>(this)->Diagnostics()) TINT_ICE(const_cast<ProgramBuilder*>(this)->diagnostics_)
<< "Attempting to use ProgramBuilder after it has been moved"; << "Attempting to use ProgramBuilder after it has been moved";
} }
} }

View File

@ -72,7 +72,7 @@
#include "src/sem/pointer_type.h" #include "src/sem/pointer_type.h"
#include "src/sem/sampled_texture_type.h" #include "src/sem/sampled_texture_type.h"
#include "src/sem/storage_texture_type.h" #include "src/sem/storage_texture_type.h"
#include "src/sem/struct_type.h" #include "src/sem/struct.h"
#include "src/sem/u32_type.h" #include "src/sem/u32_type.h"
#include "src/sem/vector_type.h" #include "src/sem/vector_type.h"
#include "src/sem/void_type.h" #include "src/sem/void_type.h"
@ -772,12 +772,6 @@ class ProgramBuilder {
return pointer(Of<T>(), storage_class); return pointer(Of<T>(), storage_class);
} }
/// @param impl the struct implementation
/// @returns a struct pointer
typ::Struct struct_(ast::Struct* impl) const {
return {impl, builder->create<sem::StructType>(impl)};
}
/// @param kind the kind of sampler /// @param kind the kind of sampler
/// @returns the sampler /// @returns the sampler
typ::Sampler sampler(ast::SamplerKind kind) const { typ::Sampler sampler(ast::SamplerKind kind) const {
@ -1544,40 +1538,36 @@ class ProgramBuilder {
return create<ast::ReturnStatement>(Expr(std::forward<EXPR>(val))); return create<ast::ReturnStatement>(Expr(std::forward<EXPR>(val)));
} }
/// Creates a ast::Struct and sem::StructType, registering the /// Creates a ast::Struct registering it with the AST().ConstructedTypes().
/// sem::StructType with the AST().ConstructedTypes().
/// @param source the source information /// @param source the source information
/// @param name the struct name /// @param name the struct name
/// @param members the struct members /// @param members the struct members
/// @param decorations the optional struct decorations /// @param decorations the optional struct decorations
/// @returns the struct type /// @returns the struct type
template <typename NAME> template <typename NAME>
typ::Struct Structure(const Source& source, ast::Struct* Structure(const Source& source,
NAME&& name, NAME&& name,
ast::StructMemberList members, ast::StructMemberList members,
ast::DecorationList decorations = {}) { ast::DecorationList decorations = {}) {
auto sym = Sym(std::forward<NAME>(name)); auto sym = Sym(std::forward<NAME>(name));
auto* impl = create<ast::Struct>(source, sym, std::move(members), auto* type = create<ast::Struct>(source, sym, std::move(members),
std::move(decorations)); std::move(decorations));
auto type = ty.struct_(impl);
AST().AddConstructedType(type); AST().AddConstructedType(type);
return type; return type;
} }
/// Creates a ast::Struct and sem::StructType, registering the /// Creates a ast::Struct registering it with the AST().ConstructedTypes().
/// sem::StructType with the AST().ConstructedTypes().
/// @param name the struct name /// @param name the struct name
/// @param members the struct members /// @param members the struct members
/// @param decorations the optional struct decorations /// @param decorations the optional struct decorations
/// @returns the struct type /// @returns the struct type
template <typename NAME> template <typename NAME>
typ::Struct Structure(NAME&& name, ast::Struct* Structure(NAME&& name,
ast::StructMemberList members, ast::StructMemberList members,
ast::DecorationList decorations = {}) { ast::DecorationList decorations = {}) {
auto sym = Sym(std::forward<NAME>(name)); auto sym = Sym(std::forward<NAME>(name));
auto* impl = auto* type =
create<ast::Struct>(sym, std::move(members), std::move(decorations)); create<ast::Struct>(sym, std::move(members), std::move(decorations));
auto type = ty.struct_(impl);
AST().AddConstructedType(type); AST().AddConstructedType(type);
return type; return type;
} }

View File

@ -414,14 +414,14 @@ class ParserImpl : Reader {
const spvtools::opt::Instruction& inst, const spvtools::opt::Instruction& inst,
ast::Type* first_operand_type); ast::Type* first_operand_type);
/// Returns the given expression, but ensuring it's an unsigned type of the /// @returns the given expression, but ensuring it's an unsigned type of the
/// same shape as the operand. Wraps the expresison with a bitcast if needed. /// same shape as the operand. Wraps the expresion with a bitcast if needed.
/// Assumes the given expresion is a integer scalar or vector. /// Assumes the given expresion is a integer scalar or vector.
/// @param expr an integer scalar or integer vector expression. /// @param expr an integer scalar or integer vector expression.
TypedExpression AsUnsigned(TypedExpression expr); TypedExpression AsUnsigned(TypedExpression expr);
/// Returns the given expression, but ensuring it's a signed type of the /// @returns the given expression, but ensuring it's a signed type of the
/// same shape as the operand. Wraps the expresison with a bitcast if needed. /// same shape as the operand. Wraps the expresion with a bitcast if needed.
/// Assumes the given expresion is a integer scalar or vector. /// Assumes the given expresion is a integer scalar or vector.
/// @param expr an integer scalar or integer vector expression. /// @param expr an integer scalar or integer vector expression.
TypedExpression AsSigned(TypedExpression expr); TypedExpression AsSigned(TypedExpression expr);

View File

@ -37,7 +37,7 @@ TEST_F(ParserImplTest, TypeDecl_ParsesType) {
TEST_F(ParserImplTest, TypeDecl_ParsesStruct_Ident) { TEST_F(ParserImplTest, TypeDecl_ParsesStruct_Ident) {
auto p = parser("type a = B"); auto p = parser("type a = B");
auto str = p->builder().Structure(p->builder().Symbols().Register("B"), {}); auto* str = p->builder().Structure(p->builder().Symbols().Register("B"), {});
p->register_constructed("B", str); p->register_constructed("B", str);
auto t = p->type_alias(); auto t = p->type_alias();

View File

@ -113,7 +113,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_ParsesWithAccessDeco_Read) {
ast::DecorationList decos; ast::DecorationList decos;
decos.push_back(block_deco); decos.push_back(block_deco);
auto s = Structure(Sym("S"), members, decos); auto* s = Structure(Sym("S"), members, decos);
p->register_constructed("S", s); p->register_constructed("S", s);
@ -137,7 +137,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_ParsesWithAccessDeco_ReadWrite) {
ast::DecorationList decos; ast::DecorationList decos;
decos.push_back(block_deco); decos.push_back(block_deco);
auto s = Structure(Sym("S"), members, decos); auto* s = Structure(Sym("S"), members, decos);
p->register_constructed("S", s); p->register_constructed("S", s);
@ -161,7 +161,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_MultipleAccessDecoFail) {
ast::DecorationList decos; ast::DecorationList decos;
decos.push_back(block_deco); decos.push_back(block_deco);
auto s = Structure(Sym("S"), members, decos); auto* s = Structure(Sym("S"), members, decos);
p->register_constructed("S", s); p->register_constructed("S", s);
@ -182,7 +182,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_MultipleAccessDeco_MultiBlock_Fail) {
ast::DecorationList decos; ast::DecorationList decos;
decos.push_back(block_deco); decos.push_back(block_deco);
auto s = Structure(Sym("S"), members, decos); auto* s = Structure(Sym("S"), members, decos);
p->register_constructed("S", s); p->register_constructed("S", s);
@ -219,7 +219,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_NonAccessDecoFail) {
ast::DecorationList decos; ast::DecorationList decos;
decos.push_back(block_deco); decos.push_back(block_deco);
auto s = Structure(Sym("S"), members, decos); auto* s = Structure(Sym("S"), members, decos);
p->register_constructed("S", s); p->register_constructed("S", s);

View File

@ -466,7 +466,7 @@ namespace {
using StructBlockTest = ResolverTest; using StructBlockTest = ResolverTest;
TEST_F(StructBlockTest, StructUsedAsArrayElement) { TEST_F(StructBlockTest, StructUsedAsArrayElement) {
auto s = Structure("S", {Member("x", ty.i32())}, auto* s = Structure("S", {Member("x", ty.i32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto a = ty.array(s, 4); auto a = ty.array(s, 4);
Global("G", a, ast::StorageClass::kPrivate); Global("G", a, ast::StorageClass::kPrivate);

View File

@ -85,7 +85,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Struct) {
// fn main() -> [[location(0)]] Output { // fn main() -> [[location(0)]] Output {
// return Output(); // return Output();
// } // }
auto output = Structure("Output", {}); auto* output = Structure("Output", {});
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))}, Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
{Stage(ast::PipelineStage::kVertex)}, {Location(Source{{13, 43}}, 0)}); {Stage(ast::PipelineStage::kVertex)}, {Location(Source{{13, 43}}, 0)});
@ -105,7 +105,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_Valid) {
// fn main() -> Output { // fn main() -> Output {
// return Output(); // return Output();
// } // }
auto output = Structure( auto* output = Structure(
"Output", {Member("a", ty.f32(), {Location(0)}), "Output", {Member("a", ty.f32(), {Location(0)}),
Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})}); Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))}, Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
@ -123,7 +123,7 @@ TEST_F(ResolverEntryPointValidationTest,
// fn main() -> Output { // fn main() -> Output {
// return Output(); // return Output();
// } // }
auto output = Structure( auto* output = Structure(
"Output", "Output",
{Member("a", ty.f32(), {Member("a", ty.f32(),
{Location(Source{{13, 43}}, 0), {Location(Source{{13, 43}}, 0),
@ -147,7 +147,7 @@ TEST_F(ResolverEntryPointValidationTest,
// fn main() -> Output { // fn main() -> Output {
// return Output(); // return Output();
// } // }
auto output = Structure( auto* output = Structure(
"Output", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}), "Output", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
Member(Source{{14, 52}}, "b", ty.f32(), {})}); Member(Source{{14, 52}}, "b", ty.f32(), {})});
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))}, Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
@ -170,9 +170,9 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_NestedStruct) {
// fn main() -> Output { // fn main() -> Output {
// return Output(); // return Output();
// } // }
auto inner = Structure( auto* inner = Structure(
"Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})}); "Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
auto output = Structure( auto* output = Structure(
"Output", {Member(Source{{14, 52}}, "a", inner, {Location(0)})}); "Output", {Member(Source{{14, 52}}, "a", inner, {Location(0)})});
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))}, Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
{Stage(ast::PipelineStage::kFragment)}); {Stage(ast::PipelineStage::kFragment)});
@ -193,7 +193,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_RuntimeArray) {
// fn main() -> Output { // fn main() -> Output {
// return Output(); // return Output();
// } // }
auto output = Structure( auto* output = Structure(
"Output", "Output",
{Member(Source{{13, 43}}, "a", ty.array<float>(), {Location(0)})}, {Member(Source{{13, 43}}, "a", ty.array<float>(), {Location(0)})},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
@ -216,7 +216,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateBuiltins) {
// fn main() -> Output { // fn main() -> Output {
// return Output(); // return Output();
// } // }
auto output = Structure( auto* output = Structure(
"Output", {Member("a", ty.f32(), {Builtin(ast::Builtin::kFragDepth)}), "Output", {Member("a", ty.f32(), {Builtin(ast::Builtin::kFragDepth)}),
Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})}); Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))}, Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
@ -238,7 +238,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateLocation) {
// fn main() -> Output { // fn main() -> Output {
// return Output(); // return Output();
// } // }
auto output = Structure("Output", {Member("a", ty.f32(), {Location(1)}), auto* output = Structure("Output", {Member("a", ty.f32(), {Location(1)}),
Member("b", ty.f32(), {Location(1)})}); Member("b", ty.f32(), {Location(1)})});
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))}, Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
{Stage(ast::PipelineStage::kFragment)}); {Stage(ast::PipelineStage::kFragment)});
@ -302,7 +302,7 @@ TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Struct) {
// }; // };
// [[stage(fragment)]] // [[stage(fragment)]]
// fn main([[location(0)]] param : Input) {} // fn main([[location(0)]] param : Input) {}
auto input = Structure("Input", {}); auto* input = Structure("Input", {});
auto* param = Param("param", input, {Location(Source{{13, 43}}, 0)}); auto* param = Param("param", input, {Location(Source{{13, 43}}, 0)});
Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
{Stage(ast::PipelineStage::kFragment)}); {Stage(ast::PipelineStage::kFragment)});
@ -321,7 +321,7 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_Valid) {
// }; // };
// [[stage(fragment)]] // [[stage(fragment)]]
// fn main(param : Input) {} // fn main(param : Input) {}
auto input = Structure( auto* input = Structure(
"Input", {Member("a", ty.f32(), {Location(0)}), "Input", {Member("a", ty.f32(), {Location(0)}),
Member("b", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})}); Member("b", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
auto* param = Param("param", input); auto* param = Param("param", input);
@ -338,7 +338,7 @@ TEST_F(ResolverEntryPointValidationTest,
// }; // };
// [[stage(fragment)]] // [[stage(fragment)]]
// fn main(param : Input) {} // fn main(param : Input) {}
auto input = Structure( auto* input = Structure(
"Input", "Input",
{Member("a", ty.f32(), {Member("a", ty.f32(),
{Location(Source{{13, 43}}, 0), {Location(Source{{13, 43}}, 0),
@ -361,7 +361,7 @@ TEST_F(ResolverEntryPointValidationTest,
// }; // };
// [[stage(fragment)]] // [[stage(fragment)]]
// fn main(param : Input) {} // fn main(param : Input) {}
auto input = Structure( auto* input = Structure(
"Input", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}), "Input", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
Member(Source{{14, 52}}, "b", ty.f32(), {})}); Member(Source{{14, 52}}, "b", ty.f32(), {})});
auto* param = Param("param", input); auto* param = Param("param", input);
@ -382,9 +382,9 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_NestedStruct) {
// }; // };
// [[stage(fragment)]] // [[stage(fragment)]]
// fn main(param : Input) {} // fn main(param : Input) {}
auto inner = Structure( auto* inner = Structure(
"Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})}); "Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
auto input = auto* input =
Structure("Input", {Member(Source{{14, 52}}, "a", inner, {Location(0)})}); Structure("Input", {Member(Source{{14, 52}}, "a", inner, {Location(0)})});
auto* param = Param("param", input); auto* param = Param("param", input);
Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
@ -404,7 +404,7 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_RuntimeArray) {
// }; // };
// [[stage(fragment)]] // [[stage(fragment)]]
// fn main(param : Input) {} // fn main(param : Input) {}
auto input = Structure( auto* input = Structure(
"Input", "Input",
{Member(Source{{13, 43}}, "a", ty.array<float>(), {Location(0)})}, {Member(Source{{13, 43}}, "a", ty.array<float>(), {Location(0)})},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
@ -446,9 +446,9 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateBuiltins) {
// }; // };
// [[stage(fragment)]] // [[stage(fragment)]]
// fn main(param_a : InputA, param_b : InputB) {} // fn main(param_a : InputA, param_b : InputB) {}
auto input_a = Structure( auto* input_a = Structure(
"InputA", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})}); "InputA", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
auto input_b = Structure( auto* input_b = Structure(
"InputB", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})}); "InputB", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
auto* param_a = Param("param_a", input_a); auto* param_a = Param("param_a", input_a);
auto* param_b = Param("param_b", input_b); auto* param_b = Param("param_b", input_b);
@ -486,8 +486,8 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateLocation) {
// }; // };
// [[stage(fragment)]] // [[stage(fragment)]]
// fn main(param_a : InputA, param_b : InputB) {} // fn main(param_a : InputA, param_b : InputB) {}
auto input_a = Structure("InputA", {Member("a", ty.f32(), {Location(1)})}); auto* input_a = Structure("InputA", {Member("a", ty.f32(), {Location(1)})});
auto input_b = Structure("InputB", {Member("a", ty.f32(), {Location(1)})}); auto* input_b = Structure("InputB", {Member("a", ty.f32(), {Location(1)})});
auto* param_a = Param("param_a", input_a); auto* param_a = Param("param_a", input_a);
auto* param_b = Param("param_b", input_b); auto* param_b = Param("param_b", input_b);
Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {}, Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},

View File

@ -27,7 +27,7 @@ namespace {
using ResolverHostShareableValidationTest = ResolverTest; using ResolverHostShareableValidationTest = ResolverTest;
TEST_F(ResolverHostShareableValidationTest, BoolMember) { TEST_F(ResolverHostShareableValidationTest, BoolMember) {
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.bool_())}, auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.bool_())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto a = ty.access(ast::AccessControl::kReadOnly, s); auto a = ty.access(ast::AccessControl::kReadOnly, s);
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage); Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
@ -42,7 +42,7 @@ TEST_F(ResolverHostShareableValidationTest, BoolMember) {
} }
TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) { TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.vec3<bool>())}, auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.vec3<bool>())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto a = ty.access(ast::AccessControl::kReadOnly, s); auto a = ty.access(ast::AccessControl::kReadOnly, s);
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage); Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
@ -59,7 +59,7 @@ TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
TEST_F(ResolverHostShareableValidationTest, Aliases) { TEST_F(ResolverHostShareableValidationTest, Aliases) {
auto a1 = ty.alias("a1", ty.bool_()); auto a1 = ty.alias("a1", ty.bool_());
AST().AddConstructedType(a1); AST().AddConstructedType(a1);
auto s = Structure("S", {Member(Source{{12, 34}}, "x", a1)}, auto* s = Structure("S", {Member(Source{{12, 34}}, "x", a1)},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadOnly, s); auto ac = ty.access(ast::AccessControl::kReadOnly, s);
auto a2 = ty.alias("a2", ac); auto a2 = ty.alias("a2", ac);
@ -76,11 +76,11 @@ TEST_F(ResolverHostShareableValidationTest, Aliases) {
} }
TEST_F(ResolverHostShareableValidationTest, NestedStructures) { TEST_F(ResolverHostShareableValidationTest, NestedStructures) {
auto i1 = Structure("I1", {Member(Source{{1, 2}}, "x", ty.bool_())}); auto* i1 = Structure("I1", {Member(Source{{1, 2}}, "x", ty.bool_())});
auto i2 = Structure("I2", {Member(Source{{3, 4}}, "y", i1)}); auto* i2 = Structure("I2", {Member(Source{{3, 4}}, "y", i1)});
auto i3 = Structure("I3", {Member(Source{{5, 6}}, "z", i2)}); auto* i3 = Structure("I3", {Member(Source{{5, 6}}, "z", i2)});
auto s = Structure("S", {Member(Source{{7, 8}}, "m", i3)}, auto* s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto a = ty.access(ast::AccessControl::kReadOnly, s); auto a = ty.access(ast::AccessControl::kReadOnly, s);
Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage); Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage);
@ -98,7 +98,7 @@ TEST_F(ResolverHostShareableValidationTest, NestedStructures) {
} }
TEST_F(ResolverHostShareableValidationTest, NoError) { TEST_F(ResolverHostShareableValidationTest, NoError) {
auto i1 = auto* i1 =
Structure("I1", { Structure("I1", {
Member(Source{{1, 1}}, "x1", ty.f32()), Member(Source{{1, 1}}, "x1", ty.f32()),
Member(Source{{2, 1}}, "y1", ty.vec3<f32>()), Member(Source{{2, 1}}, "y1", ty.vec3<f32>()),
@ -106,20 +106,20 @@ TEST_F(ResolverHostShareableValidationTest, NoError) {
}); });
auto a1 = ty.alias("a1", i1); auto a1 = ty.alias("a1", i1);
AST().AddConstructedType(a1); AST().AddConstructedType(a1);
auto i2 = Structure("I2", { auto* i2 = Structure("I2", {
Member(Source{{4, 1}}, "x2", ty.mat2x2<f32>()), Member(Source{{4, 1}}, "x2", ty.mat2x2<f32>()),
Member(Source{{5, 1}}, "y2", i1), Member(Source{{5, 1}}, "y2", i1),
Member(Source{{6, 1}}, "z2", ty.mat3x2<i32>()), Member(Source{{6, 1}}, "z2", ty.mat3x2<i32>()),
}); });
auto a2 = ty.alias("a2", i2); auto a2 = ty.alias("a2", i2);
AST().AddConstructedType(a2); AST().AddConstructedType(a2);
auto i3 = Structure("I3", { auto* i3 = Structure("I3", {
Member(Source{{4, 1}}, "x3", a1), Member(Source{{4, 1}}, "x3", a1),
Member(Source{{5, 1}}, "y3", i2), Member(Source{{5, 1}}, "y3", i2),
Member(Source{{6, 1}}, "z3", a2), Member(Source{{6, 1}}, "z3", a2),
}); });
auto s = Structure("S", {Member(Source{{7, 8}}, "m", i3)}, auto* s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto a = ty.access(ast::AccessControl::kReadOnly, s); auto a = ty.access(ast::AccessControl::kReadOnly, s);
Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage); Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage);

View File

@ -757,7 +757,7 @@ using ResolverIntrinsicDataTest = ResolverTest;
TEST_F(ResolverIntrinsicDataTest, ArrayLength_Vector) { TEST_F(ResolverIntrinsicDataTest, ArrayLength_Vector) {
auto ary = ty.array<i32>(); auto ary = ty.array<i32>();
auto str = Structure("S", {Member("x", ary)}, auto* str = Structure("S", {Member("x", ary)},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadOnly, str); auto ac = ty.access(ast::AccessControl::kReadOnly, str);
Global("a", ac, ast::StorageClass::kStorage); Global("a", ac, ast::StorageClass::kStorage);

View File

@ -105,46 +105,7 @@ TEST_F(ResolverIsHostShareable, ArrayUnsizedOfHostShareable) {
EXPECT_TRUE(r()->IsHostShareable(ty.array<i32>())); EXPECT_TRUE(r()->IsHostShareable(ty.array<i32>()));
} }
TEST_F(ResolverIsHostShareable, Struct_AllMembersHostShareable) { // Note: Structure tests covered in host_shareable_validation_test.cc
EXPECT_TRUE(r()->IsHostShareable(Structure("S", {
Member("a", ty.i32()),
Member("b", ty.f32()),
})));
}
TEST_F(ResolverIsHostShareable, Struct_SomeMembersNonHostShareable) {
auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->IsHostShareable(Structure("S", {
Member("a", ty.i32()),
Member("b", ptr_ty),
})));
}
TEST_F(ResolverIsHostShareable, Struct_NestedHostShareable) {
auto host_shareable = Structure("S", {
Member("a", ty.i32()),
Member("b", ty.f32()),
});
EXPECT_TRUE(
r()->IsHostShareable(Structure("S", {
Member("a", ty.i32()),
Member("b", host_shareable),
})));
}
TEST_F(ResolverIsHostShareable, Struct_NestedNonHostShareable) {
auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
auto non_host_shareable =
Structure("non_host_shareable", {
Member("a", ty.i32()),
Member("b", ptr_ty),
});
EXPECT_FALSE(
r()->IsHostShareable(Structure("S", {
Member("a", ty.i32()),
Member("b", non_host_shareable),
})));
}
} // namespace } // namespace
} // namespace resolver } // namespace resolver

View File

@ -90,41 +90,55 @@ TEST_F(ResolverIsStorableTest, ArrayUnsizedOfStorable) {
} }
TEST_F(ResolverIsStorableTest, Struct_AllMembersStorable) { TEST_F(ResolverIsStorableTest, Struct_AllMembersStorable) {
EXPECT_TRUE(r()->IsStorable(Structure("S", { Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}))); });
ASSERT_TRUE(r()->Resolve()) << r()->error();
} }
TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) { TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate); auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->IsStorable(Structure("S", { Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ptr_ty), Member("b", ptr_ty),
}))); });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(error: ptr<private, i32> cannot be used as the type of a structure member)");
} }
TEST_F(ResolverIsStorableTest, Struct_NestedStorable) { TEST_F(ResolverIsStorableTest, Struct_NestedStorable) {
auto storable = Structure("S", { auto* storable = Structure("Storable", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
EXPECT_TRUE(r()->IsStorable(Structure("S", { Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", storable), Member("b", storable),
}))); });
ASSERT_TRUE(r()->Resolve()) << r()->error();
} }
TEST_F(ResolverIsStorableTest, Struct_NestedNonStorable) { TEST_F(ResolverIsStorableTest, Struct_NestedNonStorable) {
auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate); auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
auto non_storable = Structure("nonstorable", { auto* non_storable = Structure("nonstorable", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ptr_ty), Member("b", ptr_ty),
}); });
EXPECT_FALSE(r()->IsStorable(Structure("S", { Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", non_storable), Member("b", non_storable),
}))); });
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
R"(error: ptr<private, i32> cannot be used as the type of a structure member)");
} }
} // namespace } // namespace

View File

@ -181,16 +181,14 @@ 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_ty = type->As<sem::StructType>()) { if (auto* str = type->As<sem::Struct>()) {
if (auto* str = Structure(str_ty)) { for (const auto* member : str->Members()) {
for (const auto* member : str->members) {
if (!IsStorable(member->Type())) { if (!IsStorable(member->Type())) {
return false; return false;
} }
} }
return true; return true;
} }
}
return false; return false;
} }
@ -209,12 +207,8 @@ bool Resolver::IsHostShareable(const sem::Type* type) {
if (auto* arr = type->As<sem::ArrayType>()) { if (auto* arr = type->As<sem::ArrayType>()) {
return IsHostShareable(arr->type()); return IsHostShareable(arr->type());
} }
if (auto* str = type->As<sem::StructType>()) { if (auto* str = type->As<sem::Struct>()) {
auto* info = Structure(str); for (auto* member : str->Members()) {
if (!info) {
return false;
}
for (auto* member : info->members) {
if (!IsHostShareable(member->Type())) { if (!IsHostShareable(member->Type())) {
return false; return false;
} }
@ -243,7 +237,7 @@ 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, auto register_named_type = [this](Symbol name, sem::Type* type,
const Source& source) { const Source& source) {
auto added = named_types_.emplace(name, type).second; auto added = named_types_.emplace(name, type).second;
if (!added) { if (!added) {
@ -312,9 +306,9 @@ bool Resolver::ResolveInternal() {
return result; return result;
} }
const sem::Type* Resolver::Type(const ast::Type* ty) { sem::Type* Resolver::Type(const ast::Type* ty) {
Mark(ty); Mark(ty);
auto* s = [&]() -> const sem::Type* { auto* s = [&]() -> sem::Type* {
if (ty->Is<ast::Void>()) { if (ty->Is<ast::Void>()) {
return builder_->create<sem::Void>(); return builder_->create<sem::Void>();
} }
@ -357,8 +351,11 @@ const sem::Type* Resolver::Type(const ast::Type* ty) {
} }
if (auto* t = ty->As<ast::Array>()) { if (auto* t = ty->As<ast::Array>()) {
if (auto* el = Type(t->type())) { if (auto* el = Type(t->type())) {
return builder_->create<sem::ArrayType>(const_cast<sem::Type*>(el), auto* sem = builder_->create<sem::ArrayType>(
t->size(), t->decorations()); const_cast<sem::Type*>(el), t->size(), t->decorations());
if (Array(sem, ty->source())) {
return sem;
}
} }
return nullptr; return nullptr;
} }
@ -370,7 +367,7 @@ const sem::Type* Resolver::Type(const ast::Type* ty) {
return nullptr; return nullptr;
} }
if (auto* t = ty->As<ast::Struct>()) { if (auto* t = ty->As<ast::Struct>()) {
return builder_->create<sem::StructType>(const_cast<ast::Struct*>(t)); return Structure(t);
} }
if (auto* t = ty->As<ast::Sampler>()) { if (auto* t = ty->As<ast::Sampler>()) {
return builder_->create<sem::Sampler>(t->kind()); return builder_->create<sem::Sampler>(t->kind());
@ -417,34 +414,14 @@ const sem::Type* Resolver::Type(const ast::Type* ty) {
return nullptr; return nullptr;
}(); }();
if (s == nullptr) { if (s) {
return nullptr;
}
if (!Type(s, ty->source())) {
return nullptr;
}
builder_->Sem().Add(ty, s); builder_->Sem().Add(ty, s);
}
return s; return s;
} }
// TODO(crbug.com/tint/724): This method should be merged into Type(ast::Type*) Resolver::VariableInfo* Resolver::Variable(ast::Variable* var,
bool Resolver::Type(const sem::Type* ty, const Source& source /* = {} */) { sem::Type* type, /* = nullptr */
ty = ty->UnwrapAliasIfNeeded();
if (auto* str = ty->As<sem::StructType>()) {
if (!Structure(str)) {
return false;
}
} else if (auto* arr = ty->As<sem::ArrayType>()) {
if (!Array(arr, source)) {
return false;
}
}
return true;
}
Resolver::VariableInfo* Resolver::Variable(
ast::Variable* var,
const sem::Type* type, /* = nullptr */
std::string type_name /* = "" */) { 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()) {
@ -561,7 +538,7 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
// attribute, satisfying the storage class constraints. // attribute, satisfying the storage class constraints.
auto* access = info->type->As<sem::AccessControl>(); auto* access = info->type->As<sem::AccessControl>();
auto* str = access ? access->type()->As<sem::StructType>() : nullptr; auto* str = access ? access->type()->As<sem::Struct>() : nullptr;
if (!str) { if (!str) {
diagnostics_.add_error( diagnostics_.add_error(
"variables declared in the <storage> storage class must be of an " "variables declared in the <storage> storage class must be of an "
@ -574,7 +551,7 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
diagnostics_.add_error( diagnostics_.add_error(
"structure used as a storage buffer must be declared with the " "structure used as a storage buffer must be declared with the "
"[[block]] decoration", "[[block]] decoration",
str->impl()->source()); str->Declaration()->source());
if (info->declaration->source().range.begin.line) { if (info->declaration->source().range.begin.line) {
diagnostics_.add_note("structure used as storage buffer here", diagnostics_.add_note("structure used as storage buffer here",
info->declaration->source()); info->declaration->source());
@ -588,7 +565,7 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
// A variable in the uniform storage class is a uniform buffer variable. // A variable in the uniform storage class is a uniform buffer variable.
// Its store type must be a host-shareable structure type with block // Its store type must be a host-shareable structure type with block
// attribute, satisfying the storage class constraints. // attribute, satisfying the storage class constraints.
auto* str = info->type->As<sem::StructType>(); auto* str = info->type->As<sem::Struct>();
if (!str) { if (!str) {
diagnostics_.add_error( diagnostics_.add_error(
"variables declared in the <uniform> storage class must be of a " "variables declared in the <uniform> storage class must be of a "
@ -601,7 +578,7 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
diagnostics_.add_error( diagnostics_.add_error(
"structure used as a uniform buffer must be declared with the " "structure used as a uniform buffer must be declared with the "
"[[block]] decoration", "[[block]] decoration",
str->impl()->source()); str->Declaration()->source());
if (info->declaration->source().range.begin.line) { if (info->declaration->source().range.begin.line) {
diagnostics_.add_note("structure used as uniform buffer here", diagnostics_.add_note("structure used as uniform buffer here",
info->declaration->source()); info->declaration->source());
@ -781,7 +758,7 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
}; };
// Inner lambda that is applied to a type and all of its members. // Inner lambda that is applied to a type and all of its members.
auto validate_entry_point_decorations_inner = auto validate_entry_point_decorations_inner =
[&](const ast::DecorationList& decos, const sem::Type* ty, Source source, [&](const ast::DecorationList& decos, sem::Type* ty, Source source,
ParamOrRetType param_or_ret, bool is_struct_member) { ParamOrRetType param_or_ret, bool is_struct_member) {
// Scan decorations for pipeline IO attributes. // Scan decorations for pipeline IO attributes.
// Check for overlap with attributes that have been seen previously. // Check for overlap with attributes that have been seen previously.
@ -834,7 +811,7 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
} }
// Check that we saw a pipeline IO attribute iff we need one. // Check that we saw a pipeline IO attribute iff we need one.
if (Canonical(ty)->Is<sem::StructType>()) { if (Canonical(ty)->Is<sem::Struct>()) {
if (pipeline_io_attribute) { if (pipeline_io_attribute) {
diagnostics_.add_error( diagnostics_.add_error(
"entry point IO attributes must not be used on structure " + "entry point IO attributes must not be used on structure " +
@ -862,8 +839,7 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
// Outer lambda for validating the entry point decorations for a type. // Outer lambda for validating the entry point decorations for a type.
auto validate_entry_point_decorations = [&](const ast::DecorationList& decos, auto validate_entry_point_decorations = [&](const ast::DecorationList& decos,
const sem::Type* ty, sem::Type* ty, Source source,
Source source,
ParamOrRetType param_or_ret) { ParamOrRetType param_or_ret) {
// Validate the decorations for the type. // Validate the decorations for the type.
if (!validate_entry_point_decorations_inner(decos, ty, source, param_or_ret, if (!validate_entry_point_decorations_inner(decos, ty, source, param_or_ret,
@ -871,12 +847,12 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
return false; return false;
} }
if (auto* struct_ty = Canonical(ty)->As<sem::StructType>()) { if (auto* str = Canonical(ty)->As<sem::Struct>()) {
// 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 : Structure(struct_ty)->members) { for (auto* member : str->Members()) {
auto* member_ty = Canonical(member->Type()); auto* member_ty = Canonical(member->Type());
if (member_ty->Is<sem::StructType>()) { if (member_ty->Is<sem::Struct>()) {
diagnostics_.add_error( diagnostics_.add_error(
"entry point IO types cannot contain nested structures", "entry point IO types cannot contain nested structures",
member->Declaration()->source()); member->Declaration()->source());
@ -988,23 +964,16 @@ bool Resolver::Function(ast::Function* func) {
return false; return false;
} }
if (auto* str = param_info->type->As<sem::StructType>()) { if (auto* str = param_info->type->As<sem::Struct>()) {
auto* str_info = Structure(str);
if (!str_info) {
return false;
}
switch (func->pipeline_stage()) { switch (func->pipeline_stage()) {
case ast::PipelineStage::kVertex: case ast::PipelineStage::kVertex:
str_info->pipeline_stage_uses.emplace( str->AddUsage(sem::PipelineStageUsage::kVertexInput);
sem::PipelineStageUsage::kVertexInput);
break; break;
case ast::PipelineStage::kFragment: case ast::PipelineStage::kFragment:
str_info->pipeline_stage_uses.emplace( str->AddUsage(sem::PipelineStageUsage::kFragmentInput);
sem::PipelineStageUsage::kFragmentInput);
break; break;
case ast::PipelineStage::kCompute: case ast::PipelineStage::kCompute:
str_info->pipeline_stage_uses.emplace( str->AddUsage(sem::PipelineStageUsage::kComputeInput);
sem::PipelineStageUsage::kComputeInput);
break; break;
case ast::PipelineStage::kNone: case ast::PipelineStage::kNone:
break; break;
@ -1026,7 +995,7 @@ bool Resolver::Function(ast::Function* func) {
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::Struct>()) {
if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, str, if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, str,
func->source())) { func->source())) {
diagnostics_.add_note("while instantiating return type for " + diagnostics_.add_note("while instantiating return type for " +
@ -1035,22 +1004,15 @@ bool Resolver::Function(ast::Function* func) {
return false; return false;
} }
auto* str_info = Structure(str);
if (!str_info) {
return false;
}
switch (func->pipeline_stage()) { switch (func->pipeline_stage()) {
case ast::PipelineStage::kVertex: case ast::PipelineStage::kVertex:
str_info->pipeline_stage_uses.emplace( str->AddUsage(sem::PipelineStageUsage::kVertexOutput);
sem::PipelineStageUsage::kVertexOutput);
break; break;
case ast::PipelineStage::kFragment: case ast::PipelineStage::kFragment:
str_info->pipeline_stage_uses.emplace( str->AddUsage(sem::PipelineStageUsage::kFragmentOutput);
sem::PipelineStageUsage::kFragmentOutput);
break; break;
case ast::PipelineStage::kCompute: case ast::PipelineStage::kCompute:
str_info->pipeline_stage_uses.emplace( str->AddUsage(sem::PipelineStageUsage::kComputeOutput);
sem::PipelineStageUsage::kComputeOutput);
break; break;
case ast::PipelineStage::kNone: case ast::PipelineStage::kNone:
break; break;
@ -1659,13 +1621,12 @@ bool Resolver::MemberAccessor(ast::MemberAccessorExpression* expr) {
sem::Type* ret = nullptr; sem::Type* ret = nullptr;
std::vector<uint32_t> swizzle; std::vector<uint32_t> swizzle;
if (auto* ty = data_type->As<sem::StructType>()) { if (auto* str = data_type->As<sem::Struct>()) {
Mark(expr->member()); Mark(expr->member());
auto symbol = expr->member()->symbol(); auto symbol = expr->member()->symbol();
auto* str = Structure(ty);
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->Type(); ret = m->Type();
member = m; member = m;
@ -1689,11 +1650,11 @@ bool Resolver::MemberAccessor(ast::MemberAccessorExpression* expr) {
expr, ret, current_statement_, member)); expr, ret, current_statement_, member));
} else if (auto* vec = data_type->As<sem::Vector>()) { } else if (auto* vec = data_type->As<sem::Vector>()) {
Mark(expr->member()); Mark(expr->member());
std::string str = builder_->Symbols().NameFor(expr->member()->symbol()); std::string s = builder_->Symbols().NameFor(expr->member()->symbol());
auto size = str.size(); auto size = s.size();
swizzle.reserve(str.size()); swizzle.reserve(s.size());
for (auto c : str) { for (auto c : s) {
switch (c) { switch (c) {
case 'x': case 'x':
case 'r': case 'r':
@ -1732,8 +1693,8 @@ bool Resolver::MemberAccessor(ast::MemberAccessorExpression* expr) {
auto is_xyzw = [](char c) { auto is_xyzw = [](char c) {
return c == 'x' || c == 'y' || c == 'z' || c == 'w'; return c == 'x' || c == 'y' || c == 'z' || c == 'w';
}; };
if (!std::all_of(str.begin(), str.end(), is_rgba) && if (!std::all_of(s.begin(), s.end(), is_rgba) &&
!std::all_of(str.begin(), str.end(), is_xyzw)) { !std::all_of(s.begin(), s.end(), is_xyzw)) {
diagnostics_.add_error( diagnostics_.add_error(
"invalid mixing of vector swizzle characters rgba with xyzw", "invalid mixing of vector swizzle characters rgba with xyzw",
expr->member()->source()); expr->member()->source());
@ -2032,7 +1993,7 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
// If the variable has a declared type, resolve it. // If the variable has a declared type, resolve it.
std::string type_name; std::string type_name;
const sem::Type* type = nullptr; sem::Type* type = nullptr;
if (auto* ast_ty = var->type()) { if (auto* ast_ty = var->type()) {
type_name = ast_ty->FriendlyName(builder_->Symbols()); type_name = ast_ty->FriendlyName(builder_->Symbols());
type = Type(ast_ty); type = Type(ast_ty);
@ -2122,7 +2083,7 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
return true; return true;
} }
const sem::Type* Resolver::TypeOf(const ast::Expression* expr) { sem::Type* Resolver::TypeOf(const ast::Expression* expr) {
auto it = expr_info_.find(expr); auto it = expr_info_.find(expr);
if (it != expr_info_.end()) { if (it != expr_info_.end()) {
return it->second.type; return it->second.type;
@ -2138,7 +2099,7 @@ std::string Resolver::TypeNameOf(const ast::Expression* expr) {
return ""; return "";
} }
const sem::Type* Resolver::TypeOf(const ast::Literal* lit) { sem::Type* Resolver::TypeOf(const ast::Literal* lit) {
if (lit->Is<ast::SintLiteral>()) { if (lit->Is<ast::SintLiteral>()) {
return builder_->create<sem::I32>(); return builder_->create<sem::I32>();
} }
@ -2273,17 +2234,6 @@ void Resolver::CreateSemanticNodes() const {
builder_->create<sem::Expression>( builder_->create<sem::Expression>(
const_cast<ast::Expression*>(expr), info.type, info.statement)); const_cast<ast::Expression*>(expr), info.type, info.statement));
} }
// Create semantic nodes for all structs
for (auto it : struct_info_) {
auto* str = it.first;
auto* info = it.second;
builder_->Sem().Add(
str, builder_->create<sem::Struct>(
const_cast<sem::StructType*>(str), std::move(info->members),
info->align, info->size, info->size_no_padding,
info->storage_class_usage, info->pipeline_stage_uses));
}
} }
bool Resolver::DefaultAlignAndSize(const sem::Type* ty, bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
@ -2305,7 +2255,7 @@ bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
/*vec4*/ 16, /*vec4*/ 16,
}; };
auto* cty = Canonical(ty); auto* cty = Canonical(const_cast<sem::Type*>(ty));
if (cty->is_scalar()) { if (cty->is_scalar()) {
// Note: Also captures booleans, but these are not host-shareable. // Note: Also captures booleans, but these are not host-shareable.
align = 4; align = 4;
@ -2330,13 +2280,10 @@ bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
align = vector_align[mat->rows()]; align = vector_align[mat->rows()];
size = vector_align[mat->rows()] * mat->columns(); size = vector_align[mat->rows()] * mat->columns();
return true; return true;
} else if (auto* s = cty->As<sem::StructType>()) { } else if (auto* s = cty->As<sem::Struct>()) {
if (auto* si = Structure(s)) { align = s->Align();
align = si->align; size = s->Size();
size = si->size;
return true; return true;
}
return false;
} else if (cty->Is<sem::ArrayType>()) { } else if (cty->Is<sem::ArrayType>()) {
if (auto* sem = if (auto* sem =
Array(ty->UnwrapAliasIfNeeded()->As<sem::ArrayType>(), source)) { Array(ty->UnwrapAliasIfNeeded()->As<sem::ArrayType>(), source)) {
@ -2416,8 +2363,8 @@ bool Resolver::ValidateArray(const sem::ArrayType* arr, const Source& source) {
return false; return false;
} }
if (auto* el_str = el_ty->As<sem::StructType>()) { if (auto* el_str = el_ty->As<sem::Struct>()) {
if (el_str->impl()->IsBlockDecorated()) { if (el_str->IsBlockDecorated()) {
// https://gpuweb.github.io/gpuweb/wgsl/#attributes // https://gpuweb.github.io/gpuweb/wgsl/#attributes
// A structure type with the block attribute must not be: // A structure type with the block attribute must not be:
// * the element type of an array type // * the element type of an array type
@ -2454,23 +2401,23 @@ bool Resolver::ValidateArrayStrideDecoration(const ast::StrideDecoration* deco,
return true; return true;
} }
bool Resolver::ValidateStructure(const StructInfo* st) { bool Resolver::ValidateStructure(const sem::Struct* str) {
for (auto* member : st->members) { for (auto* member : str->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->members.back()) { if (member != str->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->Declaration()->source()); member->Declaration()->source());
return false; return false;
} }
if (!st->type->impl()->IsBlockDecorated()) { if (!str->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->type->impl()->name()) + "'", builder_->Symbols().NameFor(str->Declaration()->name()) + "'",
member->Declaration()->source()); member->Declaration()->source());
return false; return false;
} }
@ -2498,7 +2445,7 @@ bool Resolver::ValidateStructure(const StructInfo* st) {
} }
} }
for (auto* deco : st->type->impl()->decorations()) { for (auto* deco : str->Declaration()->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());
@ -2509,19 +2456,13 @@ bool Resolver::ValidateStructure(const StructInfo* st) {
return true; return true;
} }
Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) { sem::Struct* Resolver::Structure(const ast::Struct* str) {
auto info_it = struct_info_.find(str); for (auto* deco : str->decorations()) {
if (info_it != struct_info_.end()) {
// StructInfo already resolved for this structure type
return info_it->second;
}
for (auto* deco : str->impl()->decorations()) {
Mark(deco); Mark(deco);
} }
sem::StructMemberList sem_members; sem::StructMemberList sem_members;
sem_members.reserve(str->impl()->members().size()); sem_members.reserve(str->members().size());
// Calculate the effective size and alignment of each field, and the overall // Calculate the effective size and alignment of each field, and the overall
// size of the structure. // size of the structure.
@ -2537,7 +2478,7 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
uint32_t struct_size = 0; uint32_t struct_size = 0;
uint32_t struct_align = 1; uint32_t struct_align = 1;
for (auto* member : str->impl()->members()) { for (auto* member : str->members()) {
Mark(member); Mark(member);
// Resolve member type // Resolve member type
@ -2548,7 +2489,7 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
// Validate member type // Validate member type
if (!IsStorable(type)) { if (!IsStorable(type)) {
builder_->Diagnostics().add_error( diagnostics_.add_error(
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;
@ -2620,19 +2561,14 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
auto size_no_padding = struct_size; auto size_no_padding = struct_size;
struct_size = utils::RoundUp(struct_align, struct_size); struct_size = utils::RoundUp(struct_align, struct_size);
auto* info = struct_infos_.Create(); auto* out = builder_->create<sem::Struct>(
info->type = str; str, std::move(sem_members), struct_align, struct_size, size_no_padding);
info->members = std::move(sem_members);
info->align = struct_align;
info->size = struct_size;
info->size_no_padding = size_no_padding;
struct_info_.emplace(str, info);
if (!ValidateStructure(info)) { if (!ValidateStructure(out)) {
return nullptr; return nullptr;
} }
return info; return out;
} }
bool Resolver::ValidateReturn(const ast::ReturnStatement* ret) { bool Resolver::ValidateReturn(const ast::ReturnStatement* ret) {
@ -2828,20 +2764,18 @@ bool Resolver::Assignment(ast::AssignmentStatement* a) {
} }
bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc, bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
const sem::Type* ty, sem::Type* ty,
const Source& usage) { const Source& usage) {
ty = ty->UnwrapIfNeeded(); ty = ty->UnwrapIfNeeded();
if (auto* str = ty->As<sem::StructType>()) { if (auto* str = ty->As<sem::Struct>()) {
auto* info = Structure(str); if (str->StorageClassUsage().count(sc)) {
if (!info) {
return false;
}
if (info->storage_class_usage.count(sc)) {
return true; // Already applied return true; // Already applied
} }
info->storage_class_usage.emplace(sc);
for (auto* member : info->members) { str->AddUsage(sc);
for (auto* member : str->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 "
@ -2887,7 +2821,7 @@ std::string Resolver::VectorPretty(uint32_t size, sem::Type* element_type) {
return vec_type.FriendlyName(builder_->Symbols()); return vec_type.FriendlyName(builder_->Symbols());
} }
const sem::Type* Resolver::Canonical(const sem::Type* type) { sem::Type* Resolver::Canonical(sem::Type* type) {
using AccessControl = sem::AccessControl; using AccessControl = sem::AccessControl;
using Alias = sem::Alias; using Alias = sem::Alias;
using Matrix = sem::Matrix; using Matrix = sem::Matrix;
@ -2899,17 +2833,16 @@ const sem::Type* Resolver::Canonical(const sem::Type* type) {
return nullptr; return nullptr;
} }
std::function<const Type*(const Type*)> make_canonical; std::function<Type*(Type*)> make_canonical;
make_canonical = [&](const Type* t) -> const sem::Type* { make_canonical = [&](Type* t) -> sem::Type* {
// Unwrap alias sequence // Unwrap alias sequence
const Type* ct = t; Type* ct = t;
while (auto* p = ct->As<Alias>()) { while (auto* p = ct->As<Alias>()) {
ct = p->type(); ct = p->type();
} }
if (auto* v = ct->As<Vector>()) { if (auto* v = ct->As<Vector>()) {
return builder_->create<Vector>( return builder_->create<Vector>(make_canonical(v->type()), v->size());
const_cast<sem::Type*>(make_canonical(v->type())), v->size());
} }
if (auto* m = ct->As<Matrix>()) { if (auto* m = ct->As<Matrix>()) {
auto* column_type = auto* column_type =
@ -2943,7 +2876,7 @@ void Resolver::Mark(const ast::Node* node) {
} }
Resolver::VariableInfo::VariableInfo(const ast::Variable* decl, Resolver::VariableInfo::VariableInfo(const ast::Variable* decl,
const sem::Type* ctype, sem::Type* ctype,
const std::string& tn) const std::string& tn)
: declaration(decl), : declaration(decl),
type(ctype), type(ctype),
@ -2955,8 +2888,5 @@ Resolver::VariableInfo::~VariableInfo() = default;
Resolver::FunctionInfo::FunctionInfo(ast::Function* decl) : declaration(decl) {} Resolver::FunctionInfo::FunctionInfo(ast::Function* decl) : declaration(decl) {}
Resolver::FunctionInfo::~FunctionInfo() = default; Resolver::FunctionInfo::~FunctionInfo() = default;
Resolver::StructInfo::StructInfo() = default;
Resolver::StructInfo::~StructInfo() = default;
} // namespace resolver } // namespace resolver
} // namespace tint } // namespace tint

View File

@ -49,9 +49,6 @@ namespace sem {
class Array; class Array;
class Statement; class Statement;
} // namespace sem } // namespace sem
namespace sem {
class StructType;
} // namespace sem
namespace resolver { namespace resolver {
@ -90,19 +87,19 @@ class Resolver {
/// @returns the canonical type for `type`; that is, a type with all aliases /// @returns the canonical type for `type`; that is, a type with all aliases
/// removed. For example, `Canonical(alias<alias<vec3<alias<f32>>>>)` is /// removed. For example, `Canonical(alias<alias<vec3<alias<f32>>>>)` is
/// `vec3<f32>`. /// `vec3<f32>`.
const sem::Type* Canonical(const sem::Type* type); sem::Type* Canonical(sem::Type* type);
private: private:
/// Structure holding semantic information about a variable. /// Structure holding semantic information about a variable.
/// Used to build the sem::Variable nodes at the end of resolving. /// Used to build the sem::Variable nodes at the end of resolving.
struct VariableInfo { struct VariableInfo {
VariableInfo(const ast::Variable* decl, VariableInfo(const ast::Variable* decl,
const sem::Type* type, sem::Type* type,
const std::string& type_name); const std::string& type_name);
~VariableInfo(); ~VariableInfo();
ast::Variable const* const declaration; ast::Variable const* const declaration;
sem::Type const* type; sem::Type* type;
std::string const type_name; std::string const type_name;
ast::StorageClass storage_class; ast::StorageClass storage_class;
std::vector<ast::IdentifierExpression*> users; std::vector<ast::IdentifierExpression*> users;
@ -119,7 +116,7 @@ class Resolver {
UniqueVector<VariableInfo*> referenced_module_vars; UniqueVector<VariableInfo*> referenced_module_vars;
UniqueVector<VariableInfo*> local_referenced_module_vars; UniqueVector<VariableInfo*> local_referenced_module_vars;
std::vector<const ast::ReturnStatement*> return_statements; std::vector<const ast::ReturnStatement*> return_statements;
sem::Type const* return_type = nullptr; sem::Type* return_type = nullptr;
std::string return_type_name; std::string return_type_name;
// List of transitive calls this function makes // List of transitive calls this function makes
@ -129,7 +126,7 @@ class Resolver {
/// Structure holding semantic information about an expression. /// Structure holding semantic information about an expression.
/// Used to build the sem::Expression nodes at the end of resolving. /// Used to build the sem::Expression nodes at the end of resolving.
struct ExpressionInfo { struct ExpressionInfo {
sem::Type const* type; sem::Type* type;
std::string const type_name; // Declared type name std::string const type_name; // Declared type name
sem::Statement* statement; sem::Statement* statement;
}; };
@ -142,21 +139,6 @@ class Resolver {
sem::Statement* statement; sem::Statement* statement;
}; };
/// Structure holding semantic information about a struct.
/// Used to build the sem::Struct nodes at the end of resolving.
struct StructInfo {
StructInfo();
~StructInfo();
sem::StructType const* type = nullptr;
std::vector<const sem::StructMember*> members;
uint32_t align = 0;
uint32_t size = 0;
uint32_t size_no_padding = 0;
std::unordered_set<ast::StorageClass> storage_class_usage;
std::unordered_set<sem::PipelineStageUsage> pipeline_stage_uses;
};
/// Structure holding semantic information about a block (i.e. scope), such as /// Structure holding semantic information about a block (i.e. scope), such as
/// parent block and variables declared in the block. /// parent block and variables declared in the block.
/// Used to validate variable scoping rules. /// Used to validate variable scoping rules.
@ -237,7 +219,6 @@ class Resolver {
bool Statement(ast::Statement*); bool Statement(ast::Statement*);
bool Statements(const ast::StatementList&); bool Statements(const ast::StatementList&);
bool Switch(ast::SwitchStatement* s); bool Switch(ast::SwitchStatement* s);
bool Type(const sem::Type* ty, const Source& source = {});
bool UnaryOp(ast::UnaryOpExpression*); bool UnaryOp(ast::UnaryOpExpression*);
bool VariableDeclStatement(const ast::VariableDeclStatement*); bool VariableDeclStatement(const ast::VariableDeclStatement*);
@ -257,7 +238,7 @@ class Resolver {
const sem::Matrix* matrix_type); const sem::Matrix* matrix_type);
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 StructInfo* st); bool ValidateStructure(const sem::Struct* str);
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,
@ -267,7 +248,7 @@ class Resolver {
/// hasn't been constructed already. If an error is raised, nullptr is /// hasn't been constructed already. If an error is raised, nullptr is
/// returned. /// returned.
/// @param ty the ast::Type /// @param ty the ast::Type
const sem::Type* Type(const ast::Type* ty); sem::Type* Type(const ast::Type* ty);
/// @returns the semantic information for the array `arr`, building it if it /// @returns the semantic information for the array `arr`, 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
@ -276,9 +257,9 @@ class Resolver {
/// @param source the Source of the ast node with this array as its type /// @param source the Source of the ast node with this array as its type
const sem::Array* Array(const sem::ArrayType* arr, const Source& source); const sem::Array* Array(const sem::ArrayType* arr, const Source& source);
/// @returns the StructInfo for the structure `str`, building it if it hasn't /// @returns the sem::Struct for the AST structure `str`. If an error is
/// been constructed already. If an error is raised, nullptr is returned. /// raised, nullptr is returned.
StructInfo* Structure(const sem::StructType* str); sem::Struct* Structure(const ast::Struct* str);
/// @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.
@ -287,7 +268,7 @@ class Resolver {
/// @param type_name optional type name of `var` to use instead of /// @param type_name optional type name of `var` to use instead of
/// `var->type()->FriendlyName()`. /// `var->type()->FriendlyName()`.
VariableInfo* Variable(ast::Variable* var, VariableInfo* Variable(ast::Variable* var,
const sem::Type* type = nullptr, sem::Type* type = nullptr,
std::string type_name = ""); 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
@ -299,7 +280,7 @@ class Resolver {
/// given type and storage class. Used for generating sensible error messages. /// given type and storage class. Used for generating sensible error messages.
/// @returns true on success, false on error /// @returns true on success, false on error
bool ApplyStorageClassUsageToType(ast::StorageClass sc, bool ApplyStorageClassUsageToType(ast::StorageClass sc,
const sem::Type* ty, sem::Type* ty,
const Source& usage); const Source& usage);
/// @param align the output default alignment in bytes for the type `ty` /// @param align the output default alignment in bytes for the type `ty`
@ -313,7 +294,7 @@ class Resolver {
/// @returns the resolved type of the ast::Expression `expr` /// @returns the resolved type of the ast::Expression `expr`
/// @param expr the expression /// @param expr the expression
const sem::Type* TypeOf(const ast::Expression* expr); sem::Type* TypeOf(const ast::Expression* expr);
/// @returns the declared type name of the ast::Expression `expr` /// @returns the declared type name of the ast::Expression `expr`
/// @param expr the type name /// @param expr the type name
@ -321,7 +302,7 @@ class Resolver {
/// @returns the semantic type of the AST literal `lit` /// @returns the semantic type of the AST literal `lit`
/// @param lit the literal /// @param lit the literal
const sem::Type* TypeOf(const ast::Literal* lit); sem::Type* TypeOf(const ast::Literal* lit);
/// Creates a sem::Expression node with the resolved type `type`, and /// Creates a sem::Expression node with the resolved type `type`, and
/// assigns this semantic node to the expression `expr`. /// assigns this semantic node to the expression `expr`.
@ -369,15 +350,13 @@ class Resolver {
std::unordered_map<const ast::Variable*, VariableInfo*> variable_to_info_; std::unordered_map<const ast::Variable*, VariableInfo*> variable_to_info_;
std::unordered_map<ast::CallExpression*, FunctionCallInfo> function_calls_; std::unordered_map<ast::CallExpression*, FunctionCallInfo> function_calls_;
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<sem::Type*, sem::Type*> type_to_canonical_;
std::unordered_map<const sem::Type*, const sem::Type*> type_to_canonical_; std::unordered_map<Symbol, sem::Type*> named_types_;
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;
BlockAllocator<VariableInfo> variable_infos_; BlockAllocator<VariableInfo> variable_infos_;
BlockAllocator<FunctionInfo> function_infos_; BlockAllocator<FunctionInfo> function_infos_;
BlockAllocator<StructInfo> struct_infos_;
}; };
} // namespace resolver } // namespace resolver

View File

@ -764,7 +764,7 @@ TEST_F(ResolverTest, Function_Parameters) {
} }
TEST_F(ResolverTest, Function_RegisterInputOutputVariables) { TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
auto s = Structure("S", {Member("m", ty.u32())}, auto* s = Structure("S", {Member("m", ty.u32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto a = ty.access(ast::AccessControl::kReadOnly, s); auto a = ty.access(ast::AccessControl::kReadOnly, s);
@ -800,7 +800,7 @@ TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
} }
TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) { TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
auto s = Structure("S", {Member("m", ty.u32())}, auto* s = Structure("S", {Member("m", ty.u32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto a = ty.access(ast::AccessControl::kReadOnly, s); auto a = ty.access(ast::AccessControl::kReadOnly, s);
@ -884,7 +884,7 @@ TEST_F(ResolverTest, Function_ReturnStatements) {
} }
TEST_F(ResolverTest, Expr_MemberAccessor_Struct) { TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
auto st = Structure("S", {Member("first_member", ty.i32()), auto* st = Structure("S", {Member("first_member", ty.i32()),
Member("second_member", ty.f32())}); Member("second_member", ty.f32())});
Global("my_struct", st, ast::StorageClass::kInput); Global("my_struct", st, ast::StorageClass::kInput);
@ -906,7 +906,7 @@ TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
} }
TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) { TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
auto st = Structure("S", {Member("first_member", ty.i32()), auto* st = Structure("S", {Member("first_member", ty.i32()),
Member("second_member", ty.f32())}); Member("second_member", ty.f32())});
auto alias = ty.alias("alias", st); auto alias = ty.alias("alias", st);
AST().AddConstructedType(alias); AST().AddConstructedType(alias);
@ -987,8 +987,8 @@ TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
// } // }
// //
auto stB = Structure("B", {Member("foo", ty.vec4<f32>())}); auto* stB = Structure("B", {Member("foo", ty.vec4<f32>())});
auto stA = Structure("A", {Member("mem", ty.vec(stB, 3))}); auto* stA = Structure("A", {Member("mem", ty.vec(stB, 3))});
Global("c", stA, ast::StorageClass::kInput); Global("c", stA, ast::StorageClass::kInput);
auto* mem = MemberAccessor( auto* mem = MemberAccessor(
@ -1006,7 +1006,7 @@ TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
} }
TEST_F(ResolverTest, Expr_MemberAccessor_InBinaryOp) { TEST_F(ResolverTest, Expr_MemberAccessor_InBinaryOp) {
auto st = Structure("S", {Member("first_member", ty.f32()), auto* st = Structure("S", {Member("first_member", ty.f32()),
Member("second_member", ty.f32())}); Member("second_member", ty.f32())});
Global("my_struct", st, ast::StorageClass::kInput); Global("my_struct", st, ast::StorageClass::kInput);

View File

@ -60,7 +60,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) { TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) {
// var<storage> g : [[access(read)]] array<S, 3>; // var<storage> g : [[access(read)]] array<S, 3>;
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
auto a = ty.array(s, 3); auto a = ty.array(s, 3);
auto ac = ty.access(ast::AccessControl::kReadOnly, a); auto ac = ty.access(ast::AccessControl::kReadOnly, a);
Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kStorage); Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kStorage);
@ -88,7 +88,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferBoolAlias) {
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoAccessControl) { TEST_F(ResolverStorageClassValidationTest, StorageBufferNoAccessControl) {
// var<storage> g : S; // var<storage> g : S;
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())}); auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage); Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage);
ASSERT_FALSE(r()->Resolve()); ASSERT_FALSE(r()->Resolve());
@ -101,7 +101,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoAccessControl) {
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoBlockDecoration) { TEST_F(ResolverStorageClassValidationTest, StorageBufferNoBlockDecoration) {
// struct S { x : i32 }; // struct S { x : i32 };
// var<storage> g : [[access(read)]] S; // var<storage> g : [[access(read)]] S;
auto s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())}); auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
auto a = ty.access(ast::AccessControl::kReadOnly, s); auto a = ty.access(ast::AccessControl::kReadOnly, s);
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage); Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
@ -116,7 +116,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoBlockDecoration) {
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Basic) { TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Basic) {
// [[block]] struct S { x : i32 }; // [[block]] struct S { x : i32 };
// var<storage> g : [[access(read)]] S; // var<storage> g : [[access(read)]] S;
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())}, auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto a = ty.access(ast::AccessControl::kReadOnly, s); auto a = ty.access(ast::AccessControl::kReadOnly, s);
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage); Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
@ -129,7 +129,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) {
// type a1 = S; // type a1 = S;
// type a2 = [[access(read)]] a1; // type a2 = [[access(read)]] a1;
// var<storage> g : a2; // var<storage> g : a2;
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())}, auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto a1 = ty.alias("a1", s); auto a1 = ty.alias("a1", s);
AST().AddConstructedType(a1); AST().AddConstructedType(a1);
@ -168,7 +168,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) { TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
// var<uniform> g : [[access(read)]] array<S, 3>; // var<uniform> g : [[access(read)]] array<S, 3>;
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
auto a = ty.array(s, 3); auto a = ty.array(s, 3);
auto ac = ty.access(ast::AccessControl::kReadOnly, a); auto ac = ty.access(ast::AccessControl::kReadOnly, a);
Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform); Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform);
@ -197,7 +197,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoBlockDecoration) { TEST_F(ResolverStorageClassValidationTest, UniformBufferNoBlockDecoration) {
// struct S { x : i32 }; // struct S { x : i32 };
// var<uniform> g : S; // var<uniform> g : S;
auto s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())}); auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform); Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform);
ASSERT_FALSE(r()->Resolve()); ASSERT_FALSE(r()->Resolve());
@ -211,7 +211,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferNoBlockDecoration) {
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Basic) { TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Basic) {
// [[block]] struct S { x : i32 }; // [[block]] struct S { x : i32 };
// var<uniform> g : S; // var<uniform> g : S;
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())}, auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform); Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform);
@ -222,7 +222,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Aliases) {
// [[block]] struct S { x : i32 }; // [[block]] struct S { x : i32 };
// type a1 = S; // type a1 = S;
// var<uniform> g : a1; // var<uniform> g : a1;
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())}, auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto a1 = ty.alias("a1", s); auto a1 = ty.alias("a1", s);
AST().AddConstructedType(a1); AST().AddConstructedType(a1);

View File

@ -26,7 +26,7 @@ namespace {
using ResolverStructLayoutTest = ResolverTest; using ResolverStructLayoutTest = ResolverTest;
TEST_F(ResolverStructLayoutTest, Scalars) { TEST_F(ResolverStructLayoutTest, Scalars) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.u32()), Member("b", ty.u32()),
Member("c", ty.i32()), Member("c", ty.i32()),
@ -34,7 +34,7 @@ TEST_F(ResolverStructLayoutTest, Scalars) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 12u); EXPECT_EQ(sem->Size(), 12u);
EXPECT_EQ(sem->SizeNoPadding(), 12u); EXPECT_EQ(sem->SizeNoPadding(), 12u);
@ -57,14 +57,14 @@ TEST_F(ResolverStructLayoutTest, Alias) {
auto alias_b = ty.alias("b", ty.f32()); auto alias_b = ty.alias("b", ty.f32());
AST().AddConstructedType(alias_b); AST().AddConstructedType(alias_b);
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", alias_a), Member("a", alias_a),
Member("b", alias_b), Member("b", alias_b),
}); });
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 8u); EXPECT_EQ(sem->Size(), 8u);
EXPECT_EQ(sem->SizeNoPadding(), 8u); EXPECT_EQ(sem->SizeNoPadding(), 8u);
@ -79,7 +79,7 @@ TEST_F(ResolverStructLayoutTest, Alias) {
} }
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) { TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.array<i32, 3>()), Member("a", ty.array<i32, 3>()),
Member("b", ty.array<f32, 5>()), Member("b", ty.array<f32, 5>()),
Member("c", ty.array<f32, 1>()), Member("c", ty.array<f32, 1>()),
@ -87,7 +87,7 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 36u); EXPECT_EQ(sem->Size(), 36u);
EXPECT_EQ(sem->SizeNoPadding(), 36u); EXPECT_EQ(sem->SizeNoPadding(), 36u);
@ -105,7 +105,7 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
} }
TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) { TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.array<i32, 3>(/*stride*/ 8)), Member("a", ty.array<i32, 3>(/*stride*/ 8)),
Member("b", ty.array<f32, 5>(/*stride*/ 16)), Member("b", ty.array<f32, 5>(/*stride*/ 16)),
Member("c", ty.array<f32, 1>(/*stride*/ 32)), Member("c", ty.array<f32, 1>(/*stride*/ 32)),
@ -113,7 +113,7 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 136u); EXPECT_EQ(sem->Size(), 136u);
EXPECT_EQ(sem->SizeNoPadding(), 136u); EXPECT_EQ(sem->SizeNoPadding(), 136u);
@ -131,7 +131,8 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
} }
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) { TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
auto s = Structure("S", auto* s =
Structure("S",
{ {
Member("c", ty.array<f32>()), Member("c", ty.array<f32>()),
}, },
@ -139,7 +140,7 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 4u); EXPECT_EQ(sem->Size(), 4u);
EXPECT_EQ(sem->SizeNoPadding(), 4u); EXPECT_EQ(sem->SizeNoPadding(), 4u);
@ -151,7 +152,8 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
} }
TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) { TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
auto s = Structure("S", auto* s =
Structure("S",
{ {
Member("c", ty.array<f32>(/*stride*/ 32)), Member("c", ty.array<f32>(/*stride*/ 32)),
}, },
@ -159,7 +161,7 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 32u); EXPECT_EQ(sem->Size(), 32u);
EXPECT_EQ(sem->SizeNoPadding(), 32u); EXPECT_EQ(sem->SizeNoPadding(), 32u);
@ -173,13 +175,13 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) { TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) {
auto inner = ty.array<i32, 2>(/*stride*/ 16); // size: 32 auto inner = ty.array<i32, 2>(/*stride*/ 16); // size: 32
auto outer = ty.array(inner, 12); // size: 12 * 32 auto outer = ty.array(inner, 12); // size: 12 * 32
auto s = Structure("S", { auto* s = Structure("S", {
Member("c", outer), Member("c", outer),
}); });
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 384u); EXPECT_EQ(sem->Size(), 384u);
EXPECT_EQ(sem->SizeNoPadding(), 384u); EXPECT_EQ(sem->SizeNoPadding(), 384u);
@ -191,19 +193,19 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) {
} }
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfStructure) { TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfStructure) {
auto inner = Structure("Inner", { auto* inner = Structure("Inner", {
Member("a", ty.vec2<i32>()), Member("a", ty.vec2<i32>()),
Member("b", ty.vec3<i32>()), Member("b", ty.vec3<i32>()),
Member("c", ty.vec4<i32>()), Member("c", ty.vec4<i32>()),
}); // size: 48 }); // size: 48
auto outer = ty.array(inner, 12); // size: 12 * 48 auto outer = ty.array(inner, 12); // size: 12 * 48
auto s = Structure("S", { auto* s = Structure("S", {
Member("c", outer), Member("c", outer),
}); });
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 576u); EXPECT_EQ(sem->Size(), 576u);
EXPECT_EQ(sem->SizeNoPadding(), 576u); EXPECT_EQ(sem->SizeNoPadding(), 576u);
@ -215,7 +217,7 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfStructure) {
} }
TEST_F(ResolverStructLayoutTest, Vector) { TEST_F(ResolverStructLayoutTest, Vector) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.vec2<i32>()), Member("a", ty.vec2<i32>()),
Member("b", ty.vec3<i32>()), Member("b", ty.vec3<i32>()),
Member("c", ty.vec4<i32>()), Member("c", ty.vec4<i32>()),
@ -223,7 +225,7 @@ TEST_F(ResolverStructLayoutTest, Vector) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 48u); EXPECT_EQ(sem->Size(), 48u);
EXPECT_EQ(sem->SizeNoPadding(), 48u); EXPECT_EQ(sem->SizeNoPadding(), 48u);
@ -241,7 +243,7 @@ TEST_F(ResolverStructLayoutTest, Vector) {
} }
TEST_F(ResolverStructLayoutTest, Matrix) { TEST_F(ResolverStructLayoutTest, Matrix) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.mat2x2<i32>()), Member("a", ty.mat2x2<i32>()),
Member("b", ty.mat2x3<i32>()), Member("b", ty.mat2x3<i32>()),
Member("c", ty.mat2x4<i32>()), Member("c", ty.mat2x4<i32>()),
@ -255,7 +257,7 @@ TEST_F(ResolverStructLayoutTest, Matrix) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 368u); EXPECT_EQ(sem->Size(), 368u);
EXPECT_EQ(sem->SizeNoPadding(), 368u); EXPECT_EQ(sem->SizeNoPadding(), 368u);
@ -291,10 +293,10 @@ TEST_F(ResolverStructLayoutTest, Matrix) {
} }
TEST_F(ResolverStructLayoutTest, NestedStruct) { TEST_F(ResolverStructLayoutTest, NestedStruct) {
auto inner = Structure("Inner", { auto* inner = Structure("Inner", {
Member("a", ty.mat3x3<i32>()), Member("a", ty.mat3x3<i32>()),
}); });
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", inner), Member("b", inner),
Member("c", ty.i32()), Member("c", ty.i32()),
@ -302,7 +304,7 @@ TEST_F(ResolverStructLayoutTest, NestedStruct) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 80u); EXPECT_EQ(sem->Size(), 80u);
EXPECT_EQ(sem->SizeNoPadding(), 68u); EXPECT_EQ(sem->SizeNoPadding(), 68u);
@ -320,12 +322,12 @@ TEST_F(ResolverStructLayoutTest, NestedStruct) {
} }
TEST_F(ResolverStructLayoutTest, SizeDecorations) { TEST_F(ResolverStructLayoutTest, SizeDecorations) {
auto inner = Structure("Inner", { auto* inner = Structure("Inner", {
Member("a", ty.f32(), {MemberSize(8)}), Member("a", ty.f32(), {MemberSize(8)}),
Member("b", ty.f32(), {MemberSize(16)}), Member("b", ty.f32(), {MemberSize(16)}),
Member("c", ty.f32(), {MemberSize(8)}), Member("c", ty.f32(), {MemberSize(8)}),
}); });
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.f32(), {MemberSize(4)}), Member("a", ty.f32(), {MemberSize(4)}),
Member("b", ty.u32(), {MemberSize(8)}), Member("b", ty.u32(), {MemberSize(8)}),
Member("c", inner), Member("c", inner),
@ -334,7 +336,7 @@ TEST_F(ResolverStructLayoutTest, SizeDecorations) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 76u); EXPECT_EQ(sem->Size(), 76u);
EXPECT_EQ(sem->SizeNoPadding(), 76u); EXPECT_EQ(sem->SizeNoPadding(), 76u);
@ -355,12 +357,12 @@ TEST_F(ResolverStructLayoutTest, SizeDecorations) {
} }
TEST_F(ResolverStructLayoutTest, AlignDecorations) { TEST_F(ResolverStructLayoutTest, AlignDecorations) {
auto inner = Structure("Inner", { auto* inner = Structure("Inner", {
Member("a", ty.f32(), {MemberAlign(8)}), Member("a", ty.f32(), {MemberAlign(8)}),
Member("b", ty.f32(), {MemberAlign(16)}), Member("b", ty.f32(), {MemberAlign(16)}),
Member("c", ty.f32(), {MemberAlign(4)}), Member("c", ty.f32(), {MemberAlign(4)}),
}); });
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.f32(), {MemberAlign(4)}), Member("a", ty.f32(), {MemberAlign(4)}),
Member("b", ty.u32(), {MemberAlign(8)}), Member("b", ty.u32(), {MemberAlign(8)}),
Member("c", inner), Member("c", inner),
@ -369,7 +371,7 @@ TEST_F(ResolverStructLayoutTest, AlignDecorations) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 96u); EXPECT_EQ(sem->Size(), 96u);
EXPECT_EQ(sem->SizeNoPadding(), 68u); EXPECT_EQ(sem->SizeNoPadding(), 68u);
@ -390,13 +392,13 @@ TEST_F(ResolverStructLayoutTest, AlignDecorations) {
} }
TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) { TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.i32(), {MemberAlign(1024)}), Member("a", ty.i32(), {MemberAlign(1024)}),
}); });
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_EQ(sem->Size(), 1024u); EXPECT_EQ(sem->Size(), 1024u);
EXPECT_EQ(sem->SizeNoPadding(), 4u); EXPECT_EQ(sem->SizeNoPadding(), 4u);

View File

@ -28,41 +28,41 @@ namespace {
using ResolverPipelineStageUseTest = ResolverTest; using ResolverPipelineStageUseTest = ResolverTest;
TEST_F(ResolverPipelineStageUseTest, UnusedStruct) { TEST_F(ResolverPipelineStageUseTest, UnusedStruct) {
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})}); auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_TRUE(sem->PipelineStageUses().empty()); EXPECT_TRUE(sem->PipelineStageUses().empty());
} }
TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointParam) { TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointParam) {
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})}); auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
Func("foo", {Param("param", s)}, ty.void_(), {}, {}); Func("foo", {Param("param", s)}, ty.void_(), {}, {});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_TRUE(sem->PipelineStageUses().empty()); EXPECT_TRUE(sem->PipelineStageUses().empty());
} }
TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointReturnType) { TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointReturnType) {
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})}); auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
Func("foo", {}, s, {Return(Construct(s, Expr(0.f)))}, {}); Func("foo", {}, s, {Return(Construct(s, Expr(0.f)))}, {});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_TRUE(sem->PipelineStageUses().empty()); EXPECT_TRUE(sem->PipelineStageUses().empty());
} }
TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderParam) { TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderParam) {
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})}); auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
Func("main", {Param("param", s)}, ty.vec4<f32>(), Func("main", {Param("param", s)}, ty.vec4<f32>(),
{Return(Construct(ty.vec4<f32>()))}, {Return(Construct(ty.vec4<f32>()))},
@ -71,14 +71,14 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderParam) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(), EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(sem::PipelineStageUsage::kVertexInput)); UnorderedElementsAre(sem::PipelineStageUsage::kVertexInput));
} }
TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) { TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) {
auto s = Structure( auto* s = Structure(
"S", {Member("a", ty.f32(), {Builtin(ast::Builtin::kPosition)})}); "S", {Member("a", ty.f32(), {Builtin(ast::Builtin::kPosition)})});
Func("main", {}, s, {Return(Construct(s, Expr(0.f)))}, Func("main", {}, s, {Return(Construct(s, Expr(0.f)))},
@ -86,42 +86,42 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(), EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(sem::PipelineStageUsage::kVertexOutput)); UnorderedElementsAre(sem::PipelineStageUsage::kVertexOutput));
} }
TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderParam) { TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderParam) {
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})}); auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
Func("main", {Param("param", s)}, ty.void_(), {}, Func("main", {Param("param", s)}, ty.void_(), {},
{Stage(ast::PipelineStage::kFragment)}); {Stage(ast::PipelineStage::kFragment)});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(), EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput)); UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput));
} }
TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderReturnType) { TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderReturnType) {
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})}); auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
Func("main", {}, s, {Return(Construct(s, Expr(0.f)))}, Func("main", {}, s, {Return(Construct(s, Expr(0.f)))},
{Stage(ast::PipelineStage::kFragment)}); {Stage(ast::PipelineStage::kFragment)});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(), EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput)); UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput));
} }
TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) { TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) {
auto s = Structure( auto* s = Structure(
"S", "S",
{Member("a", ty.u32(), {Builtin(ast::Builtin::kLocalInvocationIndex)})}); {Member("a", ty.u32(), {Builtin(ast::Builtin::kLocalInvocationIndex)})});
@ -130,14 +130,14 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(), EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(sem::PipelineStageUsage::kComputeInput)); UnorderedElementsAre(sem::PipelineStageUsage::kComputeInput));
} }
TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) { TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
auto s = Structure( auto* s = Structure(
"S", {Member("a", ty.f32(), {Builtin(ast::Builtin::kPosition)})}); "S", {Member("a", ty.f32(), {Builtin(ast::Builtin::kPosition)})});
Func("vert_main", {Param("param", s)}, s, {Return(Construct(s, Expr(0.f)))}, Func("vert_main", {Param("param", s)}, s, {Return(Construct(s, Expr(0.f)))},
@ -148,7 +148,7 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(), EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(sem::PipelineStageUsage::kVertexInput, UnorderedElementsAre(sem::PipelineStageUsage::kVertexInput,
@ -157,7 +157,7 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
} }
TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamViaAlias) { TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamViaAlias) {
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})}); auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
auto s_alias = ty.alias("S_alias", s); auto s_alias = ty.alias("S_alias", s);
AST().AddConstructedType(s_alias); AST().AddConstructedType(s_alias);
@ -166,14 +166,14 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamViaAlias) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(), EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput)); UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput));
} }
TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderReturnTypeViaAlias) { TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderReturnTypeViaAlias) {
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})}); auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
auto s_alias = ty.alias("S_alias", s); auto s_alias = ty.alias("S_alias", s);
AST().AddConstructedType(s_alias); AST().AddConstructedType(s_alias);
@ -182,7 +182,7 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderReturnTypeViaAlias) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->PipelineStageUses(), EXPECT_THAT(sem->PipelineStageUses(),
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput)); UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput));

View File

@ -28,149 +28,149 @@ namespace {
using ResolverStorageClassUseTest = ResolverTest; using ResolverStorageClassUseTest = ResolverTest;
TEST_F(ResolverStorageClassUseTest, UnreachableStruct) { TEST_F(ResolverStorageClassUseTest, UnreachableStruct) {
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_TRUE(sem->StorageClassUsage().empty()); EXPECT_TRUE(sem->StorageClassUsage().empty());
} }
TEST_F(ResolverStorageClassUseTest, StructReachableFromParameter) { TEST_F(ResolverStorageClassUseTest, StructReachableFromParameter) {
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
Func("f", {Param("param", s)}, ty.void_(), {}, {}); Func("f", {Param("param", s)}, ty.void_(), {}, {});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(), EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kNone)); UnorderedElementsAre(ast::StorageClass::kNone));
} }
TEST_F(ResolverStorageClassUseTest, StructReachableFromReturnType) { TEST_F(ResolverStorageClassUseTest, StructReachableFromReturnType) {
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
Func("f", {}, s, {Return(Construct(s))}, {}); Func("f", {}, s, {Return(Construct(s))}, {});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(), EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kNone)); UnorderedElementsAre(ast::StorageClass::kNone));
} }
TEST_F(ResolverStorageClassUseTest, StructReachableFromGlobal) { TEST_F(ResolverStorageClassUseTest, StructReachableFromGlobal) {
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
Global("g", s, ast::StorageClass::kPrivate); Global("g", s, ast::StorageClass::kPrivate);
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(), EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kPrivate)); UnorderedElementsAre(ast::StorageClass::kPrivate));
} }
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalAlias) { TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalAlias) {
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
auto a = ty.alias("A", s); auto a = ty.alias("A", s);
AST().AddConstructedType(a); AST().AddConstructedType(a);
Global("g", a, ast::StorageClass::kPrivate); Global("g", a, ast::StorageClass::kPrivate);
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(), EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kPrivate)); UnorderedElementsAre(ast::StorageClass::kPrivate));
} }
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalStruct) { TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalStruct) {
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
auto o = Structure("O", {Member("a", s)}); auto* o = Structure("O", {Member("a", s)});
Global("g", o, ast::StorageClass::kPrivate); Global("g", o, ast::StorageClass::kPrivate);
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(), EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kPrivate)); UnorderedElementsAre(ast::StorageClass::kPrivate));
} }
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalArray) { TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalArray) {
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
auto a = ty.array(s, 3); auto a = ty.array(s, 3);
Global("g", a, ast::StorageClass::kPrivate); Global("g", a, ast::StorageClass::kPrivate);
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(), EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kPrivate)); UnorderedElementsAre(ast::StorageClass::kPrivate));
} }
TEST_F(ResolverStorageClassUseTest, StructReachableFromLocal) { TEST_F(ResolverStorageClassUseTest, StructReachableFromLocal) {
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
WrapInFunction(Var("g", s, ast::StorageClass::kFunction)); WrapInFunction(Var("g", s, ast::StorageClass::kFunction));
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(), EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kFunction)); UnorderedElementsAre(ast::StorageClass::kFunction));
} }
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalAlias) { TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalAlias) {
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
auto a = ty.alias("A", s); auto a = ty.alias("A", s);
AST().AddConstructedType(a); AST().AddConstructedType(a);
WrapInFunction(Var("g", a, ast::StorageClass::kFunction)); WrapInFunction(Var("g", a, ast::StorageClass::kFunction));
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(), EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kFunction)); UnorderedElementsAre(ast::StorageClass::kFunction));
} }
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalStruct) { TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalStruct) {
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
auto o = Structure("O", {Member("a", s)}); auto* o = Structure("O", {Member("a", s)});
WrapInFunction(Var("g", o, ast::StorageClass::kFunction)); WrapInFunction(Var("g", o, ast::StorageClass::kFunction));
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(), EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kFunction)); UnorderedElementsAre(ast::StorageClass::kFunction));
} }
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalArray) { TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalArray) {
auto s = Structure("S", {Member("a", ty.f32())}); auto* s = Structure("S", {Member("a", ty.f32())});
auto a = ty.array(s, 3); auto a = ty.array(s, 3);
WrapInFunction(Var("g", a, ast::StorageClass::kFunction)); WrapInFunction(Var("g", a, ast::StorageClass::kFunction));
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(), EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kFunction)); UnorderedElementsAre(ast::StorageClass::kFunction));
} }
TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) { TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
auto s = Structure("S", {Member("a", ty.f32())}, auto* s = Structure("S", {Member("a", ty.f32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadOnly, s); auto ac = ty.access(ast::AccessControl::kReadOnly, s);
Global("x", s, ast::StorageClass::kUniform); Global("x", s, ast::StorageClass::kUniform);
@ -179,7 +179,7 @@ TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();
auto* sem = Sem().Get(s.sem); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
EXPECT_THAT(sem->StorageClassUsage(), EXPECT_THAT(sem->StorageClassUsage(),
UnorderedElementsAre(ast::StorageClass::kUniform, UnorderedElementsAre(ast::StorageClass::kUniform,

View File

@ -44,7 +44,7 @@ TEST_F(AccessControlTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>()); EXPECT_FALSE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -40,7 +40,7 @@ TEST_F(AliasTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>()); EXPECT_FALSE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -54,7 +54,7 @@ TEST_F(ArrayTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>()); EXPECT_FALSE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -34,7 +34,7 @@ TEST_F(BoolTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>()); EXPECT_FALSE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -39,7 +39,7 @@ TEST_F(DepthTextureTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_TRUE(ty->Is<Texture>()); EXPECT_TRUE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -40,7 +40,7 @@ TEST_F(ExternalTextureTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_TRUE(ty->Is<Texture>()); EXPECT_TRUE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -34,7 +34,7 @@ TEST_F(F32Test, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>()); EXPECT_FALSE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -34,7 +34,7 @@ TEST_F(I32Test, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>()); EXPECT_FALSE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -45,7 +45,7 @@ TEST_F(MatrixTest, Is) {
EXPECT_TRUE(ty->Is<Matrix>()); EXPECT_TRUE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>()); EXPECT_FALSE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -40,7 +40,7 @@ TEST_F(MultisampledTextureTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_TRUE(ty->Is<Texture>()); EXPECT_TRUE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -42,7 +42,7 @@ TEST_F(PointerTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_TRUE(ty->Is<Pointer>()); EXPECT_TRUE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>()); EXPECT_FALSE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -39,7 +39,7 @@ TEST_F(SampledTextureTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_TRUE(ty->Is<Texture>()); EXPECT_TRUE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -45,7 +45,7 @@ TEST_F(SamplerTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_TRUE(ty->Is<Sampler>()); EXPECT_TRUE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>()); EXPECT_FALSE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
#include "src/sem/access_control_type.h" #include "src/sem/access_control_type.h"
#include "src/sem/struct.h"
#include "src/sem/test_helper.h" #include "src/sem/test_helper.h"
#include "src/sem/texture_type.h" #include "src/sem/texture_type.h"
@ -20,22 +21,27 @@ namespace tint {
namespace sem { namespace sem {
namespace { namespace {
using StructTypeTest = TestHelper; using StructTest = TestHelper;
TEST_F(StructTypeTest, Creation) { TEST_F(StructTest, Creation) {
auto name = Sym("S"); auto name = Sym("S");
auto* impl = auto* impl =
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{}); create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
auto* ptr = impl; auto* ptr = impl;
auto s = ty.struct_(impl); auto* s = create<sem::Struct>(impl, StructMemberList{}, 4 /* align */,
EXPECT_EQ(s->impl(), ptr); 8 /* size */, 16 /* size_no_padding */);
EXPECT_EQ(s->Declaration(), ptr);
EXPECT_EQ(s->Align(), 4u);
EXPECT_EQ(s->Size(), 8u);
EXPECT_EQ(s->SizeNoPadding(), 16u);
} }
TEST_F(StructTypeTest, Is) { TEST_F(StructTest, Is) {
auto name = Sym("S"); auto name = Sym("S");
auto* impl = auto* impl =
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{}); create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
auto s = ty.struct_(impl); auto* s = create<sem::Struct>(impl, StructMemberList{}, 4 /* align */,
4 /* size */, 4 /* size_no_padding */);
sem::Type* ty = s; sem::Type* ty = s;
EXPECT_FALSE(ty->Is<AccessControl>()); EXPECT_FALSE(ty->Is<AccessControl>());
EXPECT_FALSE(ty->Is<Alias>()); EXPECT_FALSE(ty->Is<Alias>());
@ -46,25 +52,27 @@ TEST_F(StructTypeTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_TRUE(ty->Is<StructType>()); EXPECT_TRUE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>()); EXPECT_FALSE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());
} }
TEST_F(StructTypeTest, TypeName) { TEST_F(StructTest, TypeName) {
auto name = Sym("my_struct"); auto name = Sym("my_struct");
auto* impl = auto* impl =
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{}); create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
auto s = ty.struct_(impl); auto* s = create<sem::Struct>(impl, StructMemberList{}, 4 /* align */,
4 /* size */, 4 /* size_no_padding */);
EXPECT_EQ(s->type_name(), "__struct_$1"); EXPECT_EQ(s->type_name(), "__struct_$1");
} }
TEST_F(StructTypeTest, FriendlyName) { TEST_F(StructTest, FriendlyName) {
auto name = Sym("my_struct"); auto name = Sym("my_struct");
auto* impl = auto* impl =
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{}); create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
auto s = ty.struct_(impl); auto* s = create<sem::Struct>(impl, StructMemberList{}, 4 /* align */,
4 /* size */, 4 /* size_no_padding */);
EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct"); EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct");
} }

View File

@ -41,7 +41,7 @@ TEST_F(StorageTextureTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_TRUE(ty->Is<Texture>()); EXPECT_TRUE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -15,6 +15,7 @@
#include "src/sem/struct.h" #include "src/sem/struct.h"
#include "src/ast/struct_member.h" #include "src/ast/struct_member.h"
#include <string>
#include <utility> #include <utility>
TINT_INSTANTIATE_TYPEINFO(tint::sem::Struct); TINT_INSTANTIATE_TYPEINFO(tint::sem::Struct);
@ -23,20 +24,16 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::StructMember);
namespace tint { namespace tint {
namespace sem { namespace sem {
Struct::Struct(sem::StructType* type, Struct::Struct(const ast::Struct* declaration,
StructMemberList members, StructMemberList members,
uint32_t align, uint32_t align,
uint32_t size, uint32_t size,
uint32_t size_no_padding, uint32_t size_no_padding)
std::unordered_set<ast::StorageClass> storage_class_usage, : declaration_(declaration),
std::unordered_set<PipelineStageUsage> pipeline_stage_uses)
: type_(type),
members_(std::move(members)), members_(std::move(members)),
align_(align), align_(align),
size_(size), size_(size),
size_no_padding_(size_no_padding), size_no_padding_(size_no_padding) {}
storage_class_usage_(std::move(storage_class_usage)),
pipeline_stage_uses_(std::move(pipeline_stage_uses)) {}
Struct::~Struct() = default; Struct::~Struct() = default;
@ -49,6 +46,14 @@ const StructMember* Struct::FindMember(Symbol name) const {
return nullptr; return nullptr;
} }
std::string Struct::type_name() const {
return declaration_->type_name();
}
std::string Struct::FriendlyName(const SymbolTable& symbols) const {
return declaration_->FriendlyName(symbols);
}
StructMember::StructMember(ast::StructMember* declaration, StructMember::StructMember(ast::StructMember* declaration,
sem::Type* type, sem::Type* type,
uint32_t offset, uint32_t offset,

View File

@ -17,11 +17,14 @@
#include <stdint.h> #include <stdint.h>
#include <string>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
#include "src/ast/storage_class.h" #include "src/ast/storage_class.h"
#include "src/ast/struct.h"
#include "src/sem/node.h" #include "src/sem/node.h"
#include "src/sem/type.h"
#include "src/symbol.h" #include "src/symbol.h"
namespace tint { namespace tint {
@ -34,7 +37,6 @@ class StructMember;
namespace sem { namespace sem {
// Forward declarations // Forward declarations
class StructType;
class StructMember; class StructMember;
class Type; class Type;
@ -52,30 +54,26 @@ enum class PipelineStageUsage {
}; };
/// Struct holds the semantic information for structures. /// Struct holds the semantic information for structures.
class Struct : public Castable<Struct, Node> { class Struct : public Castable<Struct, Type> {
public: public:
/// Constructor /// Constructor
/// @param type the structure type /// @param declaration the AST structure declaration
/// @param members the structure members /// @param members the structure members
/// @param align the byte alignment of the structure /// @param align the byte alignment of the structure
/// @param size the byte size of the structure /// @param size the byte size of the structure
/// @param size_no_padding size of the members without the end of structure /// @param size_no_padding size of the members without the end of structure
/// alignment padding /// alignment padding
/// @param storage_class_usage a set of all the storage class usages Struct(const ast::Struct* declaration,
/// @param pipeline_stage_uses a set of all the pipeline stage uses
Struct(sem::StructType* type,
StructMemberList members, StructMemberList members,
uint32_t align, uint32_t align,
uint32_t size, uint32_t size,
uint32_t size_no_padding, uint32_t size_no_padding);
std::unordered_set<ast::StorageClass> storage_class_usage,
std::unordered_set<PipelineStageUsage> pipeline_stage_uses);
/// Destructor /// Destructor
~Struct() override; ~Struct() override;
/// @returns the structure type /// @returns the struct
sem::StructType* Type() const { return type_; } const ast::Struct* Declaration() const { return declaration_; }
/// @returns the members of the structure /// @returns the members of the structure
const StructMemberList& Members() const { return members_; } const StructMemberList& Members() const { return members_; }
@ -100,6 +98,12 @@ class Struct : public Castable<Struct, Node> {
/// alignment padding /// alignment padding
uint32_t SizeNoPadding() const { return size_no_padding_; } uint32_t SizeNoPadding() const { return size_no_padding_; }
/// Adds the StorageClass usage to the structure.
/// @param usage the storage usage
void AddUsage(ast::StorageClass usage) {
storage_class_usage_.emplace(usage);
}
/// @returns the set of storage class uses of this structure /// @returns the set of storage class uses of this structure
const std::unordered_set<ast::StorageClass>& StorageClassUsage() const { const std::unordered_set<ast::StorageClass>& StorageClassUsage() const {
return storage_class_usage_; return storage_class_usage_;
@ -122,19 +126,38 @@ class Struct : public Castable<Struct, Node> {
return false; return false;
} }
/// Adds the pipeline stage usage to the structure.
/// @param usage the storage usage
void AddUsage(PipelineStageUsage usage) {
pipeline_stage_uses_.emplace(usage);
}
/// @returns the set of entry point uses of this structure /// @returns the set of entry point uses of this structure
const std::unordered_set<PipelineStageUsage>& PipelineStageUses() const { const std::unordered_set<PipelineStageUsage>& PipelineStageUses() const {
return pipeline_stage_uses_; return pipeline_stage_uses_;
} }
/// @returns true if the struct has a block decoration
bool IsBlockDecorated() const { return declaration_->IsBlockDecorated(); }
/// @returns the name for the type
std::string type_name() const override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
private: private:
sem::StructType* const type_; uint64_t LargestMemberBaseAlignment(MemoryLayout mem_layout) const;
ast::Struct const* const declaration_;
StructMemberList const members_; StructMemberList const members_;
uint32_t const align_; uint32_t const align_;
uint32_t const size_; uint32_t const size_;
uint32_t const size_no_padding_; uint32_t const size_no_padding_;
std::unordered_set<ast::StorageClass> const storage_class_usage_; std::unordered_set<ast::StorageClass> storage_class_usage_;
std::unordered_set<PipelineStageUsage> const pipeline_stage_uses_; std::unordered_set<PipelineStageUsage> pipeline_stage_uses_;
}; };
/// StructMember holds the semantic information for structure members. /// StructMember holds the semantic information for structure members.

View File

@ -1,41 +0,0 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/sem/struct_type.h"
#include <cmath>
#include "src/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::sem::StructType);
namespace tint {
namespace sem {
StructType::StructType(ast::Struct* impl) : struct_(impl) {}
StructType::StructType(StructType&&) = default;
StructType::~StructType() = default;
std::string StructType::type_name() const {
return impl()->type_name();
}
std::string StructType::FriendlyName(const SymbolTable& symbols) const {
return impl()->FriendlyName(symbols);
}
} // namespace sem
} // namespace tint

View File

@ -1,59 +0,0 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_SEM_STRUCT_TYPE_H_
#define SRC_SEM_STRUCT_TYPE_H_
#include <string>
#include "src/ast/struct.h"
#include "src/sem/type.h"
namespace tint {
namespace sem {
/// A structure type
class StructType : public Castable<StructType, Type> {
public:
/// Constructor
/// @param impl the struct data
explicit StructType(ast::Struct* impl);
/// Move constructor
StructType(StructType&&);
~StructType() override;
/// @returns true if the struct has a block decoration
bool IsBlockDecorated() const { return struct_->IsBlockDecorated(); }
/// @returns the struct
ast::Struct* impl() const { return struct_; }
/// @returns the name for the type
std::string type_name() const override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
private:
ast::Struct* const struct_;
uint64_t LargestMemberBaseAlignment(MemoryLayout mem_layout) const;
};
} // namespace sem
} // namespace tint
#endif // SRC_SEM_STRUCT_TYPE_H_

View File

@ -41,7 +41,6 @@ class Function;
class MemberAccessorExpression; class MemberAccessorExpression;
class Statement; class Statement;
class Struct; class Struct;
class StructType;
class StructMember; class StructMember;
class Type; class Type;
class Variable; class Variable;
@ -58,7 +57,6 @@ struct TypeMappings {
Function* operator()(ast::Function*); Function* operator()(ast::Function*);
MemberAccessorExpression* operator()(ast::MemberAccessorExpression*); MemberAccessorExpression* operator()(ast::MemberAccessorExpression*);
Statement* operator()(ast::Statement*); Statement* operator()(ast::Statement*);
Struct* operator()(sem::StructType*);
StructMember* operator()(ast::StructMember*); StructMember* operator()(ast::StructMember*);
Type* operator()(ast::Type*); Type* operator()(ast::Type*);
Variable* operator()(ast::Variable*); Variable* operator()(ast::Variable*);

View File

@ -34,7 +34,7 @@ TEST_F(U32Test, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>()); EXPECT_FALSE(ty->Is<Texture>());
EXPECT_TRUE(ty->Is<U32>()); EXPECT_TRUE(ty->Is<U32>());
EXPECT_FALSE(ty->Is<Vector>()); EXPECT_FALSE(ty->Is<Vector>());

View File

@ -42,7 +42,7 @@ TEST_F(VectorTest, Is) {
EXPECT_FALSE(ty->Is<Matrix>()); EXPECT_FALSE(ty->Is<Matrix>());
EXPECT_FALSE(ty->Is<Pointer>()); EXPECT_FALSE(ty->Is<Pointer>());
EXPECT_FALSE(ty->Is<Sampler>()); EXPECT_FALSE(ty->Is<Sampler>());
EXPECT_FALSE(ty->Is<StructType>()); EXPECT_FALSE(ty->Is<Struct>());
EXPECT_FALSE(ty->Is<Texture>()); EXPECT_FALSE(ty->Is<Texture>());
EXPECT_FALSE(ty->Is<U32>()); EXPECT_FALSE(ty->Is<U32>());
EXPECT_TRUE(ty->Is<Vector>()); EXPECT_TRUE(ty->Is<Vector>());

View File

@ -77,12 +77,12 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
// get_buffer_size_intrinsic() emits the function decorated with // get_buffer_size_intrinsic() emits the function decorated with
// BufferSizeIntrinsic that is transformed by the HLSL writer into a call to // BufferSizeIntrinsic that is transformed by the HLSL writer into a call to
// [RW]ByteAddressBuffer.GetDimensions(). // [RW]ByteAddressBuffer.GetDimensions().
std::unordered_map<sem::StructType*, Symbol> buffer_size_intrinsics; std::unordered_map<sem::Struct*, Symbol> buffer_size_intrinsics;
auto get_buffer_size_intrinsic = [&](sem::StructType* buffer_type) { auto get_buffer_size_intrinsic = [&](sem::Struct* 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 = auto* buffer_typename =
ctx.dst->ty.type_name(ctx.Clone(buffer_type->impl()->name())); ctx.dst->ty.type_name(ctx.Clone(buffer_type->Declaration()->name()));
auto* func = ctx.dst->create<ast::Function>( auto* func = ctx.dst->create<ast::Function>(
name, name,
ast::VariableList{ ast::VariableList{
@ -100,8 +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->impl(), ctx.InsertAfter(ctx.src->AST().GlobalDeclarations(),
func); buffer_type->Declaration(), func);
return name; return name;
}); });
}; };
@ -141,7 +141,7 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
auto* storage_buffer_expr = accessor->structure(); auto* storage_buffer_expr = accessor->structure();
auto* storage_buffer_sem = sem.Get(storage_buffer_expr); auto* storage_buffer_sem = sem.Get(storage_buffer_expr);
auto* storage_buffer_type = auto* storage_buffer_type =
storage_buffer_sem->Type()->UnwrapAll()->As<sem::StructType>(); storage_buffer_sem->Type()->UnwrapAll()->As<sem::Struct>();
// Generate BufferSizeIntrinsic for this storage type if we haven't // Generate BufferSizeIntrinsic for this storage type if we haven't
// already // already
@ -149,7 +149,7 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
if (!storage_buffer_type) { if (!storage_buffer_type) {
TINT_ICE(ctx.dst->Diagnostics()) TINT_ICE(ctx.dst->Diagnostics())
<< "arrayLength(X.Y) expected X to be sem::StructType, got " << "arrayLength(X.Y) expected X to be sem::Struct, got "
<< storage_buffer_type->FriendlyName(ctx.src->Symbols()); << storage_buffer_type->FriendlyName(ctx.src->Symbols());
break; break;
} }
@ -176,12 +176,8 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
// First time this array length is used for this block. // First time this array length is used for this block.
// Let's calculate it. // Let's calculate it.
// Semantic info for the storage buffer structure
auto* storage_buffer_type_sem =
ctx.src->Sem().Get(storage_buffer_type);
// Semantic info for the runtime array structure member // Semantic info for the runtime array structure member
auto* array_member_sem = auto* array_member_sem = storage_buffer_type->Members().back();
storage_buffer_type_sem->Members().back();
// Construct the variable that'll hold the result of // Construct the variable that'll hold the result of
// RWByteAddressBuffer.GetDimensions() // RWByteAddressBuffer.GetDimensions()

View File

@ -110,12 +110,11 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
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* str = param_ty->As<sem::Struct>()) {
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 : str->Members()) { for (auto* member : str->Members()) {
if (member->Type()->UnwrapAll()->Is<sem::StructType>()) { if (member->Type()->UnwrapAll()->Is<sem::Struct>()) {
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct"; TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
} }
@ -202,11 +201,10 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
} else { } else {
ast::StructMemberList new_struct_members; ast::StructMemberList new_struct_members;
if (auto* struct_ty = ret_type->As<sem::StructType>()) { if (auto* str = ret_type->As<sem::Struct>()) {
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 : str->Members()) { for (auto* member : str->Members()) {
if (member->Type()->UnwrapAll()->Is<sem::StructType>()) { if (member->Type()->UnwrapAll()->Is<sem::Struct>()) {
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct"; TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
} }
@ -251,7 +249,7 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
}; };
ast::ExpressionList ret_values; ast::ExpressionList ret_values;
if (ret_type->Is<sem::StructType>()) { if (ret_type->Is<sem::Struct>()) {
if (!ret->value()->Is<ast::IdentifierExpression>()) { if (!ret->value()->Is<ast::IdentifierExpression>()) {
// 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.

View File

@ -331,7 +331,7 @@ void InsertGlobal(CloneContext& ctx,
} }
/// @returns the unwrapped, user-declared constructed type of ty. /// @returns the unwrapped, user-declared constructed type of ty.
ast::NamedType* ConstructedTypeOf(sem::Type* ty) { const 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();
@ -341,8 +341,8 @@ ast::NamedType* ConstructedTypeOf(sem::Type* ty) {
ty = access->type(); ty = access->type();
continue; continue;
} }
if (auto* str = ty->As<sem::StructType>()) { if (auto* str = ty->As<sem::Struct>()) {
return str->impl(); return str->Declaration();
} }
// Not a constructed type // Not a constructed type
return nullptr; return nullptr;
@ -421,7 +421,7 @@ struct DecomposeStorageAccess::State {
/// @param el_ty the storage buffer element type /// @param el_ty the storage buffer element type
/// @return the name of the function that performs the load /// @return the name of the function that performs the load
Symbol LoadFunc(CloneContext& ctx, Symbol LoadFunc(CloneContext& ctx,
ast::NamedType* insert_after, const 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}, [&] {
@ -451,9 +451,7 @@ struct DecomposeStorageAccess::State {
ctx.dst->Add("offset", i * MatrixColumnStride(mat_ty)); ctx.dst->Add("offset", i * MatrixColumnStride(mat_ty));
values.emplace_back(ctx.dst->Call(load, "buffer", offset)); values.emplace_back(ctx.dst->Call(load, "buffer", offset));
} }
} else if (auto* str_ty = el_ty->As<sem::StructType>()) { } else if (auto* str = el_ty->As<sem::Struct>()) {
auto& sem = ctx.src->Sem();
auto* str = sem.Get(str_ty);
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,
@ -492,7 +490,7 @@ struct DecomposeStorageAccess::State {
/// @param el_ty the storage buffer element type /// @param el_ty the storage buffer element type
/// @return the name of the function that performs the store /// @return the name of the function that performs the store
Symbol StoreFunc(CloneContext& ctx, Symbol StoreFunc(CloneContext& ctx,
ast::NamedType* insert_after, const 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}, [&] {
@ -525,9 +523,7 @@ struct DecomposeStorageAccess::State {
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));
} }
} else if (auto* str_ty = el_ty->As<sem::StructType>()) { } else if (auto* str = el_ty->As<sem::Struct>()) {
auto& sem = ctx.src->Sem();
auto* str = sem.Get(str_ty);
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());
auto* access = ctx.dst->MemberAccessor( auto* access = ctx.dst->MemberAccessor(
@ -676,9 +672,8 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
} }
} else { } else {
if (auto access = state.TakeAccess(accessor->structure())) { if (auto access = state.TakeAccess(accessor->structure())) {
auto* str_ty = access.type->As<sem::StructType>(); auto* str_ty = access.type->As<sem::Struct>();
auto* member = auto* member = str_ty->FindMember(accessor->member()->symbol());
sem.Get(str_ty)->FindMember(accessor->member()->symbol());
auto offset = member->Offset(); auto offset = member->Offset();
state.AddAccess(accessor, state.AddAccess(accessor,
{ {

View File

@ -133,7 +133,7 @@ Output FirstIndexOffset::Run(const Program* in, const DataMap& data) {
instance_index_offset = offset; instance_index_offset = offset;
offset += 4; offset += 4;
} }
auto struct_type = auto* struct_type =
ctx.dst->Structure(ctx.dst->Sym(), std::move(members), ctx.dst->Structure(ctx.dst->Sym(), std::move(members),
{ctx.dst->create<ast::StructBlockDecoration>()}); {ctx.dst->create<ast::StructBlockDecoration>()});

View File

@ -96,7 +96,7 @@ void Hlsl::PromoteInitializersToConstVar(CloneContext& ctx) const {
} }
auto* src_ty = src_sem_expr->Type(); auto* src_ty = src_sem_expr->Type();
if (src_ty->IsAnyOf<sem::ArrayType, sem::StructType>()) { if (src_ty->IsAnyOf<sem::ArrayType, sem::Struct>()) {
// 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

View File

@ -288,7 +288,7 @@ Symbol Spirv::HoistToInputVariables(
sem::Type* ty, sem::Type* ty,
ast::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::Struct>()) {
// Base case: create a global variable and return. // Base case: create a global variable and return.
ast::DecorationList new_decorations = ast::DecorationList new_decorations =
RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) { RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) {
@ -305,8 +305,8 @@ 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::Struct>();
for (auto* member : ctx.src->Sem().Get(struct_ty)->Members()) { for (auto* member : struct_ty->Members()) {
auto member_var = HoistToInputVariables( auto member_var = HoistToInputVariables(
ctx, func, member->Type(), member->Declaration()->type(), ctx, func, member->Type(), member->Declaration()->type(),
member->Declaration()->decorations()); member->Declaration()->decorations());
@ -342,7 +342,7 @@ void Spirv::HoistToOutputVariables(CloneContext& ctx,
Symbol store_value, Symbol store_value,
ast::StatementList& stores) const { ast::StatementList& stores) const {
// Base case. // Base case.
if (!ty->Is<sem::StructType>()) { if (!ty->Is<sem::Struct>()) {
// Create a global variable. // Create a global variable.
ast::DecorationList new_decorations = ast::DecorationList new_decorations =
RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) { RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) {
@ -366,8 +366,8 @@ 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::Struct>();
for (auto* member : ctx.src->Sem().Get(struct_ty)->Members()) { for (auto* member : struct_ty->Members()) {
member_accesses.push_back(ctx.Clone(member->Declaration()->symbol())); member_accesses.push_back(ctx.Clone(member->Declaration()->symbol()));
HoistToOutputVariables(ctx, func, member->Type(), HoistToOutputVariables(ctx, func, member->Type(),
member->Declaration()->type(), member->Declaration()->type(),

View File

@ -107,8 +107,9 @@ ast::Type* Transform::CreateASTTypeFor(CloneContext* ctx, const sem::Type* ty) {
if (auto* a = ty->As<sem::Alias>()) { if (auto* a = ty->As<sem::Alias>()) {
return ctx->dst->create<ast::TypeName>(ctx->Clone(a->symbol())); return ctx->dst->create<ast::TypeName>(ctx->Clone(a->symbol()));
} }
if (auto* s = ty->As<sem::StructType>()) { if (auto* s = ty->As<sem::Struct>()) {
return ctx->dst->create<ast::TypeName>(ctx->Clone(s->impl()->name())); return ctx->dst->create<ast::TypeName>(
ctx->Clone(s->Declaration()->name()));
} }
TINT_UNREACHABLE(ctx->dst->Diagnostics()) TINT_UNREACHABLE(ctx->dst->Diagnostics())
<< "Unhandled type: " << ty->TypeInfo().name; << "Unhandled type: " << ty->TypeInfo().name;

View File

@ -98,7 +98,10 @@ TEST_F(CreateASTTypeForTest, Array) {
TEST_F(CreateASTTypeForTest, AccessControl) { TEST_F(CreateASTTypeForTest, AccessControl) {
auto* ac = create([](ProgramBuilder& b) { auto* ac = create([](ProgramBuilder& b) {
auto str = b.Structure("S", {}, {}); auto* decl = b.Structure("S", {}, {});
auto* str =
b.create<sem::Struct>(decl, sem::StructMemberList{}, 4 /* align */,
4 /* size */, 4 /* size_no_padding */);
return b.create<sem::AccessControl>(ast::AccessControl::kReadOnly, str); return b.create<sem::AccessControl>(ast::AccessControl::kReadOnly, str);
}); });
ASSERT_TRUE(ac->Is<ast::AccessControl>()); ASSERT_TRUE(ac->Is<ast::AccessControl>());
@ -109,8 +112,9 @@ TEST_F(CreateASTTypeForTest, AccessControl) {
TEST_F(CreateASTTypeForTest, Struct) { TEST_F(CreateASTTypeForTest, Struct) {
auto* str = create([](ProgramBuilder& b) { auto* str = create([](ProgramBuilder& b) {
auto* impl = b.Structure("S", {}, {}).ast; auto* decl = b.Structure("S", {}, {});
return b.create<sem::StructType>(const_cast<ast::Struct*>(impl)); return b.create<sem::Struct>(decl, sem::StructMemberList{}, 4 /* align */,
4 /* size */, 4 /* size_no_padding */);
}); });
ASSERT_TRUE(str->Is<ast::TypeName>()); ASSERT_TRUE(str->Is<ast::TypeName>());
EXPECT_EQ( EXPECT_EQ(

View File

@ -204,7 +204,7 @@ struct State {
// Creating the struct type // Creating the struct type
static const char kStructName[] = "TintVertexData"; static const char kStructName[] = "TintVertexData";
auto struct_type = ctx.dst->Structure( auto* struct_type = ctx.dst->Structure(
ctx.dst->Symbols().New(kStructName), ctx.dst->Symbols().New(kStructName),
{ {
ctx.dst->Member(GetStructBufferName(), ctx.dst->Member(GetStructBufferName(),
@ -432,7 +432,7 @@ struct State {
/// @param struct_ty the structure type /// @param struct_ty the structure type
void ProcessStructParameter(ast::Function* func, void ProcessStructParameter(ast::Function* func,
ast::Variable* param, ast::Variable* param,
ast::Struct* struct_ty) { const 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.
@ -486,7 +486,7 @@ struct State {
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)));
} }
auto new_struct = ctx.dst->Structure(ctx.dst->Sym(), new_members); auto* new_struct = ctx.dst->Structure(ctx.dst->Sym(), new_members);
// Create a new function parameter with this struct. // Create a new function parameter with this struct.
auto* new_param = ctx.dst->Param(ctx.dst->Sym(), new_struct); auto* new_param = ctx.dst->Param(ctx.dst->Sym(), new_struct);
@ -513,8 +513,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 (auto* str = sem->Type()->As<sem::StructType>()) { if (auto* str = sem->Type()->As<sem::Struct>()) {
ProcessStructParameter(func, param, str->impl()); ProcessStructParameter(func, param, str->Declaration());
} else { } else {
ProcessNonStructParameter(func, param); ProcessNonStructParameter(func, param);
} }

View File

@ -69,7 +69,7 @@ class Pointer;
class Sampler; class Sampler;
class SampledTexture; class SampledTexture;
class StorageTexture; class StorageTexture;
class StructType; class Struct;
class Texture; class Texture;
class Type; class Type;
class U32; class U32;
@ -254,7 +254,7 @@ using Pointer = TypePair<ast::Pointer, sem::Pointer>;
using Sampler = TypePair<ast::Sampler, sem::Sampler>; using Sampler = TypePair<ast::Sampler, sem::Sampler>;
using SampledTexture = TypePair<ast::SampledTexture, sem::SampledTexture>; using SampledTexture = TypePair<ast::SampledTexture, sem::SampledTexture>;
using StorageTexture = TypePair<ast::StorageTexture, sem::StorageTexture>; using StorageTexture = TypePair<ast::StorageTexture, sem::StorageTexture>;
using Struct = TypePair<ast::Struct, sem::StructType>; using Struct = TypePair<ast::Struct, sem::Struct>;
using Texture = TypePair<ast::Texture, sem::Texture>; using Texture = TypePair<ast::Texture, sem::Texture>;
using U32 = TypePair<ast::U32, sem::U32>; using U32 = TypePair<ast::U32, sem::U32>;
using Vector = TypePair<ast::Vector, sem::Vector>; using Vector = TypePair<ast::Vector, sem::Vector>;
@ -271,7 +271,6 @@ inline auto MakeTypePair(AST* ast, SEM* sem) {
return TypePair<AST, SEM>{ast, sem}; return TypePair<AST, SEM>{ast, sem};
} }
} // namespace typ } // namespace typ
} // namespace tint } // namespace tint

View File

@ -210,7 +210,7 @@ bool GeneratorImpl::EmitConstructedType(std::ostream& out,
if (auto* alias = ty->As<sem::Alias>()) { if (auto* alias = ty->As<sem::Alias>()) {
// HLSL typedef is for intrinsic types only. For an alias'd struct, // HLSL typedef is for intrinsic types only. For an alias'd struct,
// generate a secondary struct with the new name. // generate a secondary struct with the new name.
if (auto* str = alias->type()->As<sem::StructType>()) { if (auto* str = alias->type()->As<sem::Struct>()) {
if (!EmitStructType(out, str, if (!EmitStructType(out, str,
builder_.Symbols().NameFor(alias->symbol()))) { builder_.Symbols().NameFor(alias->symbol()))) {
return false; return false;
@ -223,9 +223,9 @@ bool GeneratorImpl::EmitConstructedType(std::ostream& out,
} }
out << " " << builder_.Symbols().NameFor(alias->symbol()) << ";" out << " " << builder_.Symbols().NameFor(alias->symbol()) << ";"
<< std::endl; << std::endl;
} else if (auto* str = ty->As<sem::StructType>()) { } else if (auto* str = ty->As<sem::Struct>()) {
if (!EmitStructType(out, str, if (!EmitStructType(
builder_.Symbols().NameFor(str->impl()->name()))) { out, str, builder_.Symbols().NameFor(str->Declaration()->name()))) {
return false; return false;
} }
} else { } else {
@ -1325,7 +1325,7 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre,
} }
bool brackets = bool brackets =
type->UnwrapAliasIfNeeded()->IsAnyOf<sem::ArrayType, sem::StructType>(); type->UnwrapAliasIfNeeded()->IsAnyOf<sem::ArrayType, sem::Struct>();
if (brackets) { if (brackets) {
out << "{"; out << "{";
@ -1715,9 +1715,9 @@ bool GeneratorImpl::EmitEntryPointData(
} }
auto* type = var->Type()->UnwrapIfNeeded(); auto* type = var->Type()->UnwrapIfNeeded();
if (auto* strct = type->As<sem::StructType>()) { if (auto* strct = type->As<sem::Struct>()) {
out << "ConstantBuffer<" out << "ConstantBuffer<"
<< builder_.Symbols().NameFor(strct->impl()->name()) << "> " << builder_.Symbols().NameFor(strct->Declaration()->name()) << "> "
<< builder_.Symbols().NameFor(decl->symbol()) << builder_.Symbols().NameFor(decl->symbol())
<< RegisterAndSpace('b', binding_point) << ";" << std::endl; << RegisterAndSpace('b', binding_point) << ";" << std::endl;
} else { } else {
@ -2038,7 +2038,7 @@ bool GeneratorImpl::EmitEntryPointFunction(std::ostream& out,
for (auto* var : func->params()) { for (auto* var : func->params()) {
auto* sem = builder_.Sem().Get(var); auto* sem = builder_.Sem().Get(var);
auto* type = sem->Type(); auto* type = sem->Type();
if (!type->Is<sem::StructType>()) { if (!type->Is<sem::Struct>()) {
TINT_ICE(diagnostics_) << "Unsupported non-struct entry point parameter"; TINT_ICE(diagnostics_) << "Unsupported non-struct entry point parameter";
} }
@ -2140,10 +2140,10 @@ bool GeneratorImpl::EmitZeroValue(std::ostream& out, sem::Type* type) {
return false; return false;
} }
} }
} else if (auto* str = type->As<sem::StructType>()) { } else if (auto* str = type->As<sem::Struct>()) {
out << "{"; out << "{";
bool first = true; bool first = true;
for (auto* member : builder_.Sem().Get(str)->Members()) { for (auto* member : str->Members()) {
if (!first) { if (!first) {
out << ", "; out << ", ";
} }
@ -2383,7 +2383,7 @@ bool GeneratorImpl::EmitSwitch(std::ostream& out, ast::SwitchStatement* stmt) {
} }
bool GeneratorImpl::EmitType(std::ostream& out, bool GeneratorImpl::EmitType(std::ostream& out,
sem::Type* type, const sem::Type* type,
ast::StorageClass storage_class, ast::StorageClass storage_class,
const std::string& name) { const std::string& name) {
auto* access = type->As<sem::AccessControl>(); auto* access = type->As<sem::AccessControl>();
@ -2407,7 +2407,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
if (auto* alias = type->As<sem::Alias>()) { if (auto* alias = type->As<sem::Alias>()) {
out << builder_.Symbols().NameFor(alias->symbol()); out << builder_.Symbols().NameFor(alias->symbol());
} else if (auto* ary = type->As<sem::ArrayType>()) { } else if (auto* ary = type->As<sem::ArrayType>()) {
sem::Type* base_type = ary; const sem::Type* base_type = ary;
std::vector<uint32_t> sizes; std::vector<uint32_t> sizes;
while (auto* arr = base_type->As<sem::ArrayType>()) { while (auto* arr = base_type->As<sem::ArrayType>()) {
if (arr->IsRuntimeArray()) { if (arr->IsRuntimeArray()) {
@ -2457,8 +2457,8 @@ bool GeneratorImpl::EmitType(std::ostream& out,
out << "Comparison"; out << "Comparison";
} }
out << "State"; out << "State";
} else if (auto* str = type->As<sem::StructType>()) { } else if (auto* str = type->As<sem::Struct>()) {
out << builder_.Symbols().NameFor(str->impl()->name()); out << builder_.Symbols().NameFor(str->Declaration()->name());
} else if (auto* tex = type->As<sem::Texture>()) { } else if (auto* tex = type->As<sem::Texture>()) {
auto* storage = tex->As<sem::StorageTexture>(); auto* storage = tex->As<sem::StorageTexture>();
auto* multism = tex->As<sem::MultisampledTexture>(); auto* multism = tex->As<sem::MultisampledTexture>();
@ -2547,11 +2547,9 @@ bool GeneratorImpl::EmitType(std::ostream& out,
} }
bool GeneratorImpl::EmitStructType(std::ostream& out, bool GeneratorImpl::EmitStructType(std::ostream& out,
const sem::StructType* str, const sem::Struct* str,
const std::string& name) { const std::string& name) {
auto* sem_str = builder_.Sem().Get(str); auto storage_class_uses = str->StorageClassUsage();
auto storage_class_uses = sem_str->StorageClassUsage();
if (storage_class_uses.size() == if (storage_class_uses.size() ==
storage_class_uses.count(ast::StorageClass::kStorage)) { storage_class_uses.count(ast::StorageClass::kStorage)) {
// The only use of the structure is as a storage buffer. // The only use of the structure is as a storage buffer.
@ -2563,7 +2561,7 @@ bool GeneratorImpl::EmitStructType(std::ostream& out,
out << "struct " << name << " {" << std::endl; out << "struct " << name << " {" << std::endl;
increment_indent(); increment_indent();
for (auto* mem : sem_str->Members()) { for (auto* mem : str->Members()) {
make_indent(out); make_indent(out);
// TODO(dsinclair): Handle [[offset]] annotation on structs // TODO(dsinclair): Handle [[offset]] annotation on structs
// https://bugs.chromium.org/p/tint/issues/detail?id=184 // https://bugs.chromium.org/p/tint/issues/detail?id=184
@ -2579,8 +2577,7 @@ bool GeneratorImpl::EmitStructType(std::ostream& out,
for (auto* deco : mem->Declaration()->decorations()) { for (auto* deco : mem->Declaration()->decorations()) {
if (auto* location = deco->As<ast::LocationDecoration>()) { if (auto* location = deco->As<ast::LocationDecoration>()) {
auto& pipeline_stage_uses = auto& pipeline_stage_uses = str->PipelineStageUses();
builder_.Sem().Get(str)->PipelineStageUses();
if (pipeline_stage_uses.size() != 1) { if (pipeline_stage_uses.size() != 1) {
TINT_ICE(diagnostics_) << "invalid entry point IO struct uses"; TINT_ICE(diagnostics_) << "invalid entry point IO struct uses";
} }

View File

@ -290,7 +290,7 @@ class GeneratorImpl : public TextGenerator {
/// @param name the name of the variable, only used for array emission /// @param name the name of the variable, only used for array emission
/// @returns true if the type is emitted /// @returns true if the type is emitted
bool EmitType(std::ostream& out, bool EmitType(std::ostream& out,
sem::Type* type, const sem::Type* type,
ast::StorageClass storage_class, ast::StorageClass storage_class,
const std::string& name); const std::string& name);
/// Handles generating a structure declaration /// Handles generating a structure declaration
@ -299,7 +299,7 @@ class GeneratorImpl : public TextGenerator {
/// @param name the struct name /// @param name the struct name
/// @returns true if the struct is emitted /// @returns true if the struct is emitted
bool EmitStructType(std::ostream& out, bool EmitStructType(std::ostream& out,
const sem::StructType* ty, const sem::Struct* ty,
const std::string& name); const std::string& name);
/// Handles a unary op expression /// Handles a unary op expression
/// @param pre the preamble for the expression stream /// @param pre the preamble for the expression stream

View File

@ -1,59 +0,0 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "gmock/gmock.h"
#include "src/writer/hlsl/test_helper.h"
namespace tint {
namespace writer {
namespace hlsl {
namespace {
using ::testing::HasSubstr;
using HlslGeneratorImplTest_Alias = TestHelper;
TEST_F(HlslGeneratorImplTest_Alias, EmitAlias_F32) {
auto alias = ty.alias("a", ty.f32());
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitConstructedType(out, alias)) << gen.error();
EXPECT_EQ(result(), R"(typedef float a;
)");
}
TEST_F(HlslGeneratorImplTest_Alias, EmitAlias_Struct) {
auto s = Structure("A", {
Member("a", ty.f32()),
Member("b", ty.i32()),
});
auto alias = ty.alias("B", s);
AST().AddConstructedType(alias);
Global("g", alias, ast::StorageClass::kPrivate);
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitConstructedType(out, alias)) << gen.error();
EXPECT_EQ(result(), R"(struct B {
float a;
int b;
};
)");
}
} // namespace
} // namespace hlsl
} // namespace writer
} // namespace tint

View File

@ -195,7 +195,7 @@ TEST_F(HlslGeneratorImplTest_Constructor,
} }
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) { TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
auto str = Structure("S", { auto* str = Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
Member("c", ty.vec3<i32>()), Member("c", ty.vec3<i32>()),
@ -212,7 +212,7 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
} }
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct_Empty) { TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct_Empty) {
auto str = Structure("S", { auto* str = Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
Member("c", ty.vec3<i32>()), Member("c", ty.vec3<i32>()),

View File

@ -179,7 +179,7 @@ TEST_F(HlslGeneratorImplTest_Function,
// const g = inputs.col2; // const g = inputs.col2;
// const p = inputs.pos; // const p = inputs.pos;
// } // }
auto interface_struct = Structure( auto* interface_struct = Structure(
"Interface", "Interface",
{ {
Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}), Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
@ -252,7 +252,7 @@ TEST_F(HlslGeneratorImplTest_Function,
// fn vert_main2() -> VertexOutput { // fn vert_main2() -> VertexOutput {
// return foo(0.25); // return foo(0.25);
// } // }
auto vertex_output_struct = Structure( auto* vertex_output_struct = Structure(
"VertexOutput", "VertexOutput",
{Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})}); {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
@ -307,7 +307,7 @@ tint_symbol_2 vert_main2() {
TEST_F(HlslGeneratorImplTest_Function, TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_EntryPoint_With_Uniform) { Emit_Decoration_EntryPoint_With_Uniform) {
auto ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())}, auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto* ubo = Global( auto* ubo = Global(
"ubo", ubo_ty, ast::StorageClass::kUniform, nullptr, "ubo", ubo_ty, ast::StorageClass::kUniform, nullptr,
@ -359,7 +359,7 @@ void frag_main() {
TEST_F(HlslGeneratorImplTest_Function, TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_EntryPoint_With_UniformStruct) { Emit_Decoration_EntryPoint_With_UniformStruct) {
auto s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())}, auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
Global("uniforms", s, ast::StorageClass::kUniform, nullptr, Global("uniforms", s, ast::StorageClass::kUniform, nullptr,
@ -401,7 +401,7 @@ void frag_main() {
TEST_F(HlslGeneratorImplTest_Function, TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_EntryPoint_With_RW_StorageBuffer_Read) { Emit_Decoration_EntryPoint_With_RW_StorageBuffer_Read) {
auto s = Structure("Data", auto* s = Structure("Data",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
@ -447,7 +447,7 @@ void frag_main() {
TEST_F(HlslGeneratorImplTest_Function, TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_EntryPoint_With_RO_StorageBuffer_Read) { Emit_Decoration_EntryPoint_With_RO_StorageBuffer_Read) {
auto s = Structure("Data", auto* s = Structure("Data",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
@ -493,7 +493,7 @@ void frag_main() {
TEST_F(HlslGeneratorImplTest_Function, TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_EntryPoint_With_WO_StorageBuffer_Store) { Emit_Decoration_EntryPoint_With_WO_StorageBuffer_Store) {
auto s = Structure("Data", auto* s = Structure("Data",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
@ -536,7 +536,7 @@ void frag_main() {
TEST_F(HlslGeneratorImplTest_Function, TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_EntryPoint_With_StorageBuffer_Store) { Emit_Decoration_EntryPoint_With_StorageBuffer_Store) {
auto s = Structure("Data", auto* s = Structure("Data",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
@ -742,7 +742,7 @@ ep_1_out ep_1(ep_1_in tint_in) {
TEST_F(HlslGeneratorImplTest_Function, TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_Called_By_EntryPoint_With_Uniform) { Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
auto s = Structure("S", {Member("x", ty.f32())}, auto* s = Structure("S", {Member("x", ty.f32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
Global("coord", s, ast::StorageClass::kUniform, nullptr, Global("coord", s, ast::StorageClass::kUniform, nullptr,
{ {
@ -792,7 +792,7 @@ void frag_main() {
TEST_F(HlslGeneratorImplTest_Function, TEST_F(HlslGeneratorImplTest_Function,
Emit_Decoration_Called_By_EntryPoint_With_StorageBuffer) { Emit_Decoration_Called_By_EntryPoint_With_StorageBuffer) {
auto s = Structure("S", {Member("x", ty.f32())}, auto* s = Structure("S", {Member("x", ty.f32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadWrite, s); auto ac = ty.access(ast::AccessControl::kReadWrite, s);
Global("coord", ac, ast::StorageClass::kStorage, nullptr, Global("coord", ac, ast::StorageClass::kStorage, nullptr,
@ -981,7 +981,7 @@ TEST_F(HlslGeneratorImplTest_Function,
// return; // return;
// } // }
auto s = Structure("Data", {Member("d", ty.f32())}, auto* s = Structure("Data", {Member("d", ty.f32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadWrite, s); auto ac = ty.access(ast::AccessControl::kReadWrite, s);

View File

@ -96,7 +96,7 @@ class HlslGeneratorImplTest_MemberAccessorBase : public BASE {
void SetupStorageBuffer(ast::StructMemberList members) { void SetupStorageBuffer(ast::StructMemberList members) {
ProgramBuilder& b = *this; ProgramBuilder& b = *this;
auto s = auto* s =
b.Structure("Data", members, {b.create<ast::StructBlockDecoration>()}); b.Structure("Data", members, {b.create<ast::StructBlockDecoration>()});
auto ac_ty = b.ty.access(ast::AccessControl::kReadWrite, s); auto ac_ty = b.ty.access(ast::AccessControl::kReadWrite, s);
@ -125,7 +125,7 @@ using HlslGeneratorImplTest_MemberAccessorWithParam =
HlslGeneratorImplTest_MemberAccessorBase<TestParamHelper<T>>; HlslGeneratorImplTest_MemberAccessorBase<TestParamHelper<T>>;
TEST_F(HlslGeneratorImplTest_MemberAccessor, EmitExpression_MemberAccessor) { TEST_F(HlslGeneratorImplTest_MemberAccessor, EmitExpression_MemberAccessor) {
auto s = Structure("Data", {Member("mem", ty.f32())}); auto* s = Structure("Data", {Member("mem", ty.f32())});
Global("str", s, ast::StorageClass::kPrivate); Global("str", s, ast::StorageClass::kPrivate);
auto* expr = MemberAccessor("str", "mem"); auto* expr = MemberAccessor("str", "mem");
@ -522,7 +522,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel) {
// var<storage> data : Pre; // var<storage> data : Pre;
// data.c[2].b // data.c[2].b
auto inner = Structure("Inner", { auto* inner = Structure("Inner", {
Member("a", ty.vec3<f32>()), Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()), Member("b", ty.vec3<f32>()),
}); });
@ -568,7 +568,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
// var<storage> data : Pre; // var<storage> data : Pre;
// data.c[2].b.xy // data.c[2].b.xy
auto inner = Structure("Inner", { auto* inner = Structure("Inner", {
Member("a", ty.vec3<f32>()), Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()), Member("b", ty.vec3<f32>()),
}); });
@ -616,7 +616,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
// var<storage> data : Pre; // var<storage> data : Pre;
// data.c[2].b.g // data.c[2].b.g
auto inner = Structure("Inner", { auto* inner = Structure("Inner", {
Member("a", ty.vec3<f32>()), Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()), Member("b", ty.vec3<f32>()),
}); });
@ -664,7 +664,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
// var<storage> data : Pre; // var<storage> data : Pre;
// data.c[2].b[1] // data.c[2].b[1]
auto inner = Structure("Inner", { auto* inner = Structure("Inner", {
Member("a", ty.vec3<f32>()), Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()), Member("b", ty.vec3<f32>()),
}); });
@ -711,7 +711,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_MultiLevel) {
// var<storage> data : Pre; // var<storage> data : Pre;
// data.c[2].b = vec3<f32>(1.f, 2.f, 3.f); // data.c[2].b = vec3<f32>(1.f, 2.f, 3.f);
auto inner = Structure("Inner", { auto* inner = Structure("Inner", {
Member("a", ty.vec3<f32>()), Member("a", ty.vec3<f32>()),
Member("b", ty.vec3<f32>()), Member("b", ty.vec3<f32>()),
}); });
@ -756,7 +756,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
// var<storage> data : Pre; // var<storage> data : Pre;
// data.c[2].b.y = 1.f; // data.c[2].b.y = 1.f;
auto inner = Structure("Inner", { auto* inner = Structure("Inner", {
Member("a", ty.vec3<i32>()), Member("a", ty.vec3<i32>()),
Member("b", ty.vec3<f32>()), Member("b", ty.vec3<f32>()),
}); });

View File

@ -26,7 +26,7 @@ namespace {
using HlslSanitizerTest = TestHelper; using HlslSanitizerTest = TestHelper;
TEST_F(HlslSanitizerTest, ArrayLength) { TEST_F(HlslSanitizerTest, ArrayLength) {
auto sb_ty = Structure("SB", auto* sb_ty = Structure("SB",
{ {
Member("x", ty.f32()), Member("x", ty.f32()),
Member("arr", ty.array(ty.vec4<f32>())), Member("arr", ty.array(ty.vec4<f32>())),
@ -100,7 +100,7 @@ TEST_F(HlslSanitizerTest, PromoteArrayInitializerToConstVar) {
} }
TEST_F(HlslSanitizerTest, PromoteStructInitializerToConstVar) { TEST_F(HlslSanitizerTest, PromoteStructInitializerToConstVar) {
auto str = Structure("S", { auto* str = Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.vec3<f32>()), Member("b", ty.vec3<f32>()),
Member("c", ty.i32()), Member("c", ty.i32()),

View File

@ -156,7 +156,7 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Pointer) {
} }
TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) { TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
@ -164,7 +164,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(out, s, "S")) << gen.error(); auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitStructType(out, sem_s, "S")) << gen.error();
EXPECT_EQ(result(), R"(struct S { EXPECT_EQ(result(), R"(struct S {
int a; int a;
float b; float b;
@ -173,7 +174,7 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
} }
TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl_OmittedIfStorageBuffer) { TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl_OmittedIfStorageBuffer) {
auto s = Structure("S", auto* s = Structure("S",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
@ -184,12 +185,13 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl_OmittedIfStorageBuffer) {
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(out, s, "S")) << gen.error(); auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitStructType(out, sem_s, "S")) << gen.error();
EXPECT_EQ(result(), ""); EXPECT_EQ(result(), "");
} }
TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) { TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
@ -197,7 +199,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitType(out, s, ast::StorageClass::kNone, "")) auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone, ""))
<< gen.error(); << gen.error();
EXPECT_EQ(result(), "S"); EXPECT_EQ(result(), "S");
} }
@ -205,7 +208,7 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
/// TODO(bclayton): Enable this, fix it, add tests for vector, matrix, array and /// TODO(bclayton): Enable this, fix it, add tests for vector, matrix, array and
/// nested structures. /// nested structures.
TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) { TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) {
auto s = Structure( auto* s = Structure(
"S", { "S", {
Member("a", ty.i32(), {MemberSize(32)}), Member("a", ty.i32(), {MemberSize(32)}),
Member("b", ty.f32()), Member("b", ty.f32()),
@ -215,7 +218,8 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) {
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitType(out, s, ast::StorageClass::kNone, "")) auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone, ""))
<< gen.error(); << gen.error();
EXPECT_EQ(gen.result(), R"(struct S { EXPECT_EQ(gen.result(), R"(struct S {
int a; int a;
@ -229,7 +233,7 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) {
} }
TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) { TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("double", ty.i32()), Member("double", ty.i32()),
Member("float", ty.f32()), Member("float", ty.f32()),
}); });
@ -247,7 +251,7 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
// TODO(dsinclair): How to translate [[block]] // TODO(dsinclair): How to translate [[block]]
TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_WithDecoration) { TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_WithDecoration) {
auto s = Structure("S", auto* s = Structure("S",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
@ -257,7 +261,8 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_WithDecoration) {
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(out, s, "B")) << gen.error(); auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitStructType(out, sem_s, "B")) << gen.error();
EXPECT_EQ(result(), R"(struct B { EXPECT_EQ(result(), R"(struct B {
int a; int a;
float b; float b;

View File

@ -156,7 +156,7 @@ bool GeneratorImpl::EmitConstructedType(const sem::Type* ty) {
} }
out_ << " " << program_->Symbols().NameFor(alias->symbol()) << ";" out_ << " " << program_->Symbols().NameFor(alias->symbol()) << ";"
<< std::endl; << std::endl;
} else if (auto* str = ty->As<sem::StructType>()) { } else if (auto* str = ty->As<sem::Struct>()) {
if (!EmitStructType(str)) { if (!EmitStructType(str)) {
return false; return false;
} }
@ -889,7 +889,7 @@ bool GeneratorImpl::EmitContinue(ast::ContinueStatement*) {
bool GeneratorImpl::EmitTypeConstructor(ast::TypeConstructorExpression* expr) { bool GeneratorImpl::EmitTypeConstructor(ast::TypeConstructorExpression* expr) {
auto* type = TypeOf(expr); auto* type = TypeOf(expr);
if (type->IsAnyOf<sem::ArrayType, sem::StructType>()) { if (type->IsAnyOf<sem::ArrayType, sem::Struct>()) {
out_ << "{"; out_ << "{";
} else { } else {
if (!EmitType(type, "")) { if (!EmitType(type, "")) {
@ -918,7 +918,7 @@ bool GeneratorImpl::EmitTypeConstructor(ast::TypeConstructorExpression* expr) {
} }
} }
if (type->IsAnyOf<sem::ArrayType, sem::StructType>()) { if (type->IsAnyOf<sem::ArrayType, sem::Struct>()) {
out_ << "}"; out_ << "}";
} else { } else {
out_ << ")"; out_ << ")";
@ -948,7 +948,7 @@ bool GeneratorImpl::EmitZeroValue(typ::Type type) {
return false; return false;
} }
out_ << "}"; out_ << "}";
} else if (type->As<sem::StructType>()) { } else if (type->As<sem::Struct>()) {
out_ << "{}"; out_ << "{}";
} else { } else {
diagnostics_.add_error("Invalid type for zero emission: " + diagnostics_.add_error("Invalid type for zero emission: " +
@ -1435,7 +1435,7 @@ bool GeneratorImpl::EmitEntryPointFunction(ast::Function* func) {
out_ << " " << program_->Symbols().NameFor(var->symbol()); out_ << " " << program_->Symbols().NameFor(var->symbol());
if (type->Is<sem::StructType>()) { if (type->Is<sem::Struct>()) {
out_ << " [[stage_in]]"; out_ << " [[stage_in]]";
} else { } else {
auto& decos = var->decorations(); auto& decos = var->decorations();
@ -1957,10 +1957,10 @@ bool GeneratorImpl::EmitType(typ::Type type, const std::string& name) {
out_ << "*"; out_ << "*";
} else if (type->Is<sem::Sampler>()) { } else if (type->Is<sem::Sampler>()) {
out_ << "sampler"; out_ << "sampler";
} else if (auto* str = type->As<sem::StructType>()) { } else if (auto* str = type->As<sem::Struct>()) {
// The struct type emits as just the name. The declaration would be emitted // The struct type emits as just the name. The declaration would be emitted
// as part of emitting the constructed types. // as part of emitting the constructed types.
out_ << program_->Symbols().NameFor(str->impl()->name()); out_ << program_->Symbols().NameFor(str->Declaration()->name());
} else if (auto* tex = type->As<sem::Texture>()) { } else if (auto* tex = type->As<sem::Texture>()) {
if (tex->Is<sem::DepthTexture>()) { if (tex->Is<sem::DepthTexture>()) {
out_ << "depth"; out_ << "depth";
@ -2056,20 +2056,14 @@ bool GeneratorImpl::EmitPackedType(typ::Type type, const std::string& name) {
return EmitType(type, name); return EmitType(type, name);
} }
bool GeneratorImpl::EmitStructType(const sem::StructType* str) { bool GeneratorImpl::EmitStructType(const sem::Struct* str) {
// TODO(dsinclair): Block decoration? // TODO(dsinclair): Block decoration?
// if (str->impl()->decoration() != ast::Decoration::kNone) { // if (str->impl()->decoration() != ast::Decoration::kNone) {
// } // }
out_ << "struct " << program_->Symbols().NameFor(str->impl()->name()) << " {" out_ << "struct " << program_->Symbols().NameFor(str->Declaration()->name())
<< std::endl; << " {" << std::endl;
auto* sem_str = program_->Sem().Get(str); bool is_host_shareable = str->IsHostShareable();
if (!sem_str) {
TINT_ICE(diagnostics_) << "struct missing semantic info";
return false;
}
bool is_host_shareable = sem_str->IsHostShareable();
// Emits a `/* 0xnnnn */` byte offset comment for a struct member. // Emits a `/* 0xnnnn */` byte offset comment for a struct member.
auto add_byte_offset_comment = [&](uint32_t offset) { auto add_byte_offset_comment = [&](uint32_t offset) {
@ -2084,14 +2078,14 @@ bool GeneratorImpl::EmitStructType(const sem::StructType* str) {
std::string name; std::string name;
do { do {
name = "tint_pad_" + std::to_string(pad_count++); name = "tint_pad_" + std::to_string(pad_count++);
} while (sem_str->FindMember(program_->Symbols().Get(name))); } while (str->FindMember(program_->Symbols().Get(name)));
out_ << "int8_t " << name << "[" << size << "];" << std::endl; out_ << "int8_t " << name << "[" << size << "];" << std::endl;
}; };
increment_indent(); increment_indent();
uint32_t msl_offset = 0; uint32_t msl_offset = 0;
for (auto* mem : sem_str->Members()) { for (auto* mem : str->Members()) {
make_indent(); make_indent();
auto name = program_->Symbols().NameFor(mem->Declaration()->symbol()); auto name = program_->Symbols().NameFor(mem->Declaration()->symbol());
@ -2142,8 +2136,7 @@ bool GeneratorImpl::EmitStructType(const sem::StructType* str) {
} }
out_ << " [[" << attr << "]]"; out_ << " [[" << attr << "]]";
} else if (auto* loc = deco->As<ast::LocationDecoration>()) { } else if (auto* loc = deco->As<ast::LocationDecoration>()) {
auto& pipeline_stage_uses = auto& pipeline_stage_uses = str->PipelineStageUses();
program_->Sem().Get(str)->PipelineStageUses();
if (pipeline_stage_uses.size() != 1) { if (pipeline_stage_uses.size() != 1) {
TINT_ICE(diagnostics_) << "invalid entry point IO struct uses"; TINT_ICE(diagnostics_) << "invalid entry point IO struct uses";
} }
@ -2180,10 +2173,10 @@ bool GeneratorImpl::EmitStructType(const sem::StructType* str) {
} }
} }
if (is_host_shareable && sem_str->Size() != msl_offset) { if (is_host_shareable && str->Size() != msl_offset) {
make_indent(); make_indent();
add_byte_offset_comment(msl_offset); add_byte_offset_comment(msl_offset);
add_padding(sem_str->Size() - msl_offset); add_padding(str->Size() - msl_offset);
} }
decrement_indent(); decrement_indent();
@ -2353,15 +2346,10 @@ GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(
return SizeAndAlign{el_size_align.size * num_els, el_size_align.align}; return SizeAndAlign{el_size_align.size * num_els, el_size_align.align};
} }
if (auto* str = ty->As<sem::StructType>()) { if (auto* str = ty->As<sem::Struct>()) {
// TODO(crbug.com/tint/650): There's an assumption here that MSL's default // TODO(crbug.com/tint/650): There's an assumption here that MSL's default
// structure size and alignment matches WGSL's. We need to confirm this. // structure size and alignment matches WGSL's. We need to confirm this.
auto* sem = program_->Sem().Get(str); return SizeAndAlign{str->Size(), str->Align()};
if (!sem) {
TINT_ICE(diagnostics_) << "Array missing semantic info";
return {};
}
return SizeAndAlign{sem->Size(), sem->Align()};
} }
TINT_UNREACHABLE(diagnostics_) << "Unhandled type " << ty->TypeInfo().name; TINT_UNREACHABLE(diagnostics_) << "Unhandled type " << ty->TypeInfo().name;

View File

@ -35,7 +35,7 @@
#include "src/ast/unary_op_expression.h" #include "src/ast/unary_op_expression.h"
#include "src/program.h" #include "src/program.h"
#include "src/scope_stack.h" #include "src/scope_stack.h"
#include "src/sem/struct_type.h" #include "src/sem/struct.h"
#include "src/writer/text_generator.h" #include "src/writer/text_generator.h"
namespace tint { namespace tint {
@ -206,7 +206,7 @@ class GeneratorImpl : public TextGenerator {
/// Handles generating a struct declaration /// Handles generating a struct declaration
/// @param str the struct to generate /// @param str the struct to generate
/// @returns true if the struct is emitted /// @returns true if the struct is emitted
bool EmitStructType(const sem::StructType* str); bool EmitStructType(const sem::Struct* str);
/// Handles emitting a type constructor /// Handles emitting a type constructor
/// @param expr the type constructor expression /// @param expr the type constructor expression
/// @returns true if the constructor is emitted /// @returns true if the constructor is emitted

View File

@ -1,68 +0,0 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/writer/msl/test_helper.h"
namespace tint {
namespace writer {
namespace msl {
namespace {
using MslGeneratorImplTest = TestHelper;
TEST_F(MslGeneratorImplTest, EmitConstructedType_F32) {
auto alias = ty.alias("a", ty.f32());
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitConstructedType(alias)) << gen.error();
EXPECT_EQ(gen.result(), R"(typedef float a;
)");
}
TEST_F(MslGeneratorImplTest, EmitConstructedType_Struct) {
auto s = Structure("a", {
Member("a", ty.f32()),
Member("b", ty.i32()),
});
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitConstructedType(s)) << gen.error();
EXPECT_EQ(gen.result(), R"(struct a {
float a;
int b;
};
)");
}
TEST_F(MslGeneratorImplTest, EmitConstructedType_AliasStructIdent) {
auto s = Structure("b", {
Member("a", ty.f32()),
Member("b", ty.i32()),
});
auto alias = ty.alias("a", s);
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitConstructedType(alias)) << gen.error();
EXPECT_EQ(gen.result(), R"(typedef b a;
)");
}
} // namespace
} // namespace msl
} // namespace writer
} // namespace tint

View File

@ -145,7 +145,7 @@ TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Array) {
} }
TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Struct) { TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Struct) {
auto str = Structure("S", { auto* str = Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
Member("c", ty.vec3<i32>()), Member("c", ty.vec3<i32>()),

View File

@ -170,7 +170,7 @@ TEST_F(MslGeneratorImplTest,
// const r = colors.col1; // const r = colors.col1;
// const g = colors.col2; // const g = colors.col2;
// } // }
auto interface_struct = Structure( auto* interface_struct = Structure(
"Interface", "Interface",
{ {
Member("col1", ty.f32(), {Location(1)}), Member("col1", ty.f32(), {Location(1)}),
@ -245,7 +245,7 @@ TEST_F(MslGeneratorImplTest,
// fn vert_main2() -> VertexOutput { // fn vert_main2() -> VertexOutput {
// return foo(0.25); // return foo(0.25);
// } // }
auto vertex_output_struct = Structure( auto* vertex_output_struct = Structure(
"VertexOutput", "VertexOutput",
{Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})}); {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
@ -300,7 +300,7 @@ vertex tint_symbol_2 vert_main2() {
TEST_F(MslGeneratorImplTest, TEST_F(MslGeneratorImplTest,
Emit_FunctionDecoration_EntryPoint_With_RW_StorageBuffer) { Emit_FunctionDecoration_EntryPoint_With_RW_StorageBuffer) {
auto s = Structure("Data", auto* s = Structure("Data",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
@ -345,7 +345,7 @@ fragment void frag_main(device Data& coord [[buffer(0)]]) {
TEST_F(MslGeneratorImplTest, TEST_F(MslGeneratorImplTest,
Emit_FunctionDecoration_EntryPoint_With_RO_StorageBuffer) { Emit_FunctionDecoration_EntryPoint_With_RO_StorageBuffer) {
auto s = Structure("Data", auto* s = Structure("Data",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
@ -550,7 +550,7 @@ fragment ep_1_out ep_1(float4 coord [[position]]) {
TEST_F(MslGeneratorImplTest, TEST_F(MslGeneratorImplTest,
Emit_Decoration_Called_By_EntryPoint_With_Uniform) { Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
auto ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())}, auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto* ubo = Global( auto* ubo = Global(
"ubo", ubo_ty, ast::StorageClass::kUniform, nullptr, "ubo", ubo_ty, ast::StorageClass::kUniform, nullptr,
@ -601,7 +601,7 @@ fragment void frag_main(constant UBO& ubo [[buffer(0)]]) {
TEST_F(MslGeneratorImplTest, TEST_F(MslGeneratorImplTest,
Emit_FunctionDecoration_Called_By_EntryPoint_With_RW_StorageBuffer) { Emit_FunctionDecoration_Called_By_EntryPoint_With_RW_StorageBuffer) {
auto s = Structure("Data", auto* s = Structure("Data",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
@ -657,7 +657,7 @@ fragment void frag_main(device Data& coord [[buffer(0)]]) {
TEST_F(MslGeneratorImplTest, TEST_F(MslGeneratorImplTest,
Emit_FunctionDecoration_Called_By_EntryPoint_With_RO_StorageBuffer) { Emit_FunctionDecoration_Called_By_EntryPoint_With_RO_StorageBuffer) {
auto s = Structure("Data", auto* s = Structure("Data",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
@ -796,7 +796,7 @@ TEST_F(MslGeneratorImplTest,
// return; // return;
// } // }
auto s = Structure("Data", {Member("d", ty.f32())}, auto* s = Structure("Data", {Member("d", ty.f32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadWrite, s); auto ac = ty.access(ast::AccessControl::kReadWrite, s);

View File

@ -173,7 +173,7 @@ TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Pointer) {
} }
TEST_F(MslGeneratorImplTest, EmitType_Struct) { TEST_F(MslGeneratorImplTest, EmitType_Struct) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
@ -185,14 +185,15 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct) {
} }
TEST_F(MslGeneratorImplTest, EmitType_StructDecl) { TEST_F(MslGeneratorImplTest, EmitType_StructDecl) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error(); auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitStructType(sem_s)) << gen.error();
EXPECT_EQ(gen.result(), R"(struct S { EXPECT_EQ(gen.result(), R"(struct S {
int a; int a;
float b; float b;
@ -201,7 +202,7 @@ TEST_F(MslGeneratorImplTest, EmitType_StructDecl) {
} }
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) { TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
auto s = auto* s =
Structure("S", Structure("S",
{ {
Member("a", ty.i32(), {MemberSize(32)}), Member("a", ty.i32(), {MemberSize(32)}),
@ -238,7 +239,8 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error(); auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitStructType(sem_s)) << gen.error();
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX) // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
// for each field of the structure s. // for each field of the structure s.
@ -315,20 +317,20 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) { TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
// inner_x: size(1024), align(512) // inner_x: size(1024), align(512)
auto inner_x = auto* inner_x =
Structure("inner_x", { Structure("inner_x", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32(), {MemberAlign(512)}), Member("b", ty.f32(), {MemberAlign(512)}),
}); });
// inner_y: size(516), align(4) // inner_y: size(516), align(4)
auto inner_y = auto* inner_y =
Structure("inner_y", { Structure("inner_y", {
Member("a", ty.i32(), {MemberSize(512)}), Member("a", ty.i32(), {MemberSize(512)}),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
auto s = Structure("S", auto* s = Structure("S",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", inner_x), Member("b", inner_x),
@ -343,7 +345,8 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error(); auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitStructType(sem_s)) << gen.error();
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX) // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
// for each field of the structure s. // for each field of the structure s.
@ -401,7 +404,8 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) { TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
// inner: size(1024), align(512) // inner: size(1024), align(512)
auto inner = Structure("inner", { auto* inner =
Structure("inner", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32(), {MemberAlign(512)}), Member("b", ty.f32(), {MemberAlign(512)}),
}); });
@ -415,7 +419,8 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
// array_z: size(4), align(4) // array_z: size(4), align(4)
auto array_z = ty.array<f32>(); auto array_z = ty.array<f32>();
auto s = Structure("S", auto* s =
Structure("S",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", array_x), Member("b", array_x),
@ -431,7 +436,8 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error(); auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitStructType(sem_s)) << gen.error();
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX) // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
// for each field of the structure s. // for each field of the structure s.
@ -495,7 +501,7 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
} }
TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) { TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
auto s = Structure( auto* s = Structure(
"S", "S",
{ {
// uses symbols tint_pad_[0..9] and tint_pad_[20..35] // uses symbols tint_pad_[0..9] and tint_pad_[20..35]
@ -533,7 +539,8 @@ TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error(); auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
ASSERT_TRUE(gen.EmitStructType(sem_s)) << gen.error();
EXPECT_EQ(gen.result(), R"(struct S { EXPECT_EQ(gen.result(), R"(struct S {
/* 0x0000 */ int tint_pad_2; /* 0x0000 */ int tint_pad_2;
/* 0x0004 */ int8_t tint_pad_10[124]; /* 0x0004 */ int8_t tint_pad_10[124];
@ -582,7 +589,7 @@ TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
// TODO(dsinclair): How to translate [[block]] // TODO(dsinclair): How to translate [[block]]
TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Struct_WithDecoration) { TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Struct_WithDecoration) {
auto s = Structure("S", auto* s = Structure("S",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),

View File

@ -65,7 +65,7 @@ TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Array) {
} }
TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Struct) { TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Struct) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });

View File

@ -886,13 +886,13 @@ bool Builder::GenerateMemberAccessor(ast::MemberAccessorExpression* expr,
// If the data_type is a structure we're accessing a member, if it's a // If the data_type is a structure we're accessing a member, if it's a
// vector we're accessing a swizzle. // vector we're accessing a swizzle.
if (data_type->Is<sem::StructType>()) { if (auto* str = data_type->As<sem::Struct>()) {
auto* strct = data_type->As<sem::StructType>()->impl(); auto* impl = str->Declaration();
auto symbol = expr->member()->symbol(); auto symbol = expr->member()->symbol();
uint32_t idx = 0; uint32_t idx = 0;
for (; idx < strct->members().size(); ++idx) { for (; idx < impl->members().size(); ++idx) {
auto* member = strct->members()[idx]; auto* member = impl->members()[idx];
if (member->symbol() == symbol) { if (member->symbol() == symbol) {
break; break;
} }
@ -1294,8 +1294,8 @@ bool Builder::is_constructor_const(ast::Expression* expr, bool is_global_init) {
subtype = mat->type()->UnwrapAll(); subtype = mat->type()->UnwrapAll();
} else if (auto* arr = subtype->As<sem::ArrayType>()) { } else if (auto* arr = subtype->As<sem::ArrayType>()) {
subtype = arr->type()->UnwrapAll(); subtype = arr->type()->UnwrapAll();
} else if (auto* str = subtype->As<sem::StructType>()) { } else if (auto* str = subtype->As<sem::Struct>()) {
subtype = builder_.Sem().Get(str)->Members()[i]->Type()->UnwrapAll(); subtype = str->Members()[i]->Type()->UnwrapAll();
} }
if (subtype != TypeOf(sc)->UnwrapAll()) { if (subtype != TypeOf(sc)->UnwrapAll()) {
return false; return false;
@ -1373,8 +1373,7 @@ uint32_t Builder::GenerateTypeConstructorExpression(
// If the result is not a vector then we should have validated that the // If the result is not a vector then we should have validated that the
// value type is a correctly sized vector so we can just use it directly. // value type is a correctly sized vector so we can just use it directly.
if (result_type == value_type || result_type->Is<sem::Matrix>() || if (result_type == value_type || result_type->Is<sem::Matrix>() ||
result_type->Is<sem::ArrayType>() || result_type->Is<sem::ArrayType>() || result_type->Is<sem::Struct>()) {
result_type->Is<sem::StructType>()) {
out << "_" << id; out << "_" << id;
ops.push_back(Operand::Int(id)); ops.push_back(Operand::Int(id));
@ -2024,14 +2023,14 @@ uint32_t Builder::GenerateIntrinsic(ast::CallExpression* call,
params.push_back(Operand::Int(struct_id)); params.push_back(Operand::Int(struct_id));
auto* type = TypeOf(accessor->structure())->UnwrapAll(); auto* type = TypeOf(accessor->structure())->UnwrapAll();
if (!type->Is<sem::StructType>()) { if (!type->Is<sem::Struct>()) {
error_ = error_ =
"invalid type (" + type->type_name() + ") for runtime array length"; "invalid type (" + type->type_name() + ") for runtime array length";
return 0; return 0;
} }
// Runtime array must be the last member in the structure // Runtime array must be the last member in the structure
params.push_back(Operand::Int( params.push_back(Operand::Int(uint32_t(
uint32_t(type->As<sem::StructType>()->impl()->members().size() - 1))); type->As<sem::Struct>()->Declaration()->members().size() - 1)));
if (!push_function_inst(spv::Op::OpArrayLength, params)) { if (!push_function_inst(spv::Op::OpArrayLength, params)) {
return 0; return 0;
@ -2978,7 +2977,7 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
return GenerateTypeIfNeeded(alias->type()); return GenerateTypeIfNeeded(alias->type());
} }
if (auto* ac = type->As<sem::AccessControl>()) { if (auto* ac = type->As<sem::AccessControl>()) {
if (!ac->type()->UnwrapIfNeeded()->Is<sem::StructType>()) { if (!ac->type()->UnwrapIfNeeded()->Is<sem::Struct>()) {
return GenerateTypeIfNeeded(ac->type()); return GenerateTypeIfNeeded(ac->type());
} }
} }
@ -2993,8 +2992,8 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
if (auto* ac = type->As<sem::AccessControl>()) { if (auto* ac = type->As<sem::AccessControl>()) {
// The non-struct case was handled above. // The non-struct case was handled above.
auto* subtype = ac->type()->UnwrapIfNeeded(); auto* subtype = ac->type()->UnwrapIfNeeded();
if (!GenerateStructType(subtype->As<sem::StructType>(), if (!GenerateStructType(subtype->As<sem::Struct>(), ac->access_control(),
ac->access_control(), result)) { result)) {
return 0; return 0;
} }
} else if (auto* arr = type->As<sem::ArrayType>()) { } else if (auto* arr = type->As<sem::ArrayType>()) {
@ -3015,7 +3014,7 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
if (!GeneratePointerType(ptr, result)) { if (!GeneratePointerType(ptr, result)) {
return 0; return 0;
} }
} else if (auto* str = type->As<sem::StructType>()) { } else if (auto* str = type->As<sem::Struct>()) {
if (!GenerateStructType(str, ast::AccessControl::kReadWrite, result)) { if (!GenerateStructType(str, ast::AccessControl::kReadWrite, result)) {
return 0; return 0;
} }
@ -3190,16 +3189,16 @@ bool Builder::GeneratePointerType(const sem::Pointer* ptr,
return true; return true;
} }
bool Builder::GenerateStructType(const sem::StructType* struct_type, bool Builder::GenerateStructType(const sem::Struct* struct_type,
ast::AccessControl::Access access_control, ast::AccessControl::Access access_control,
const Operand& result) { const Operand& result) {
auto struct_id = result.to_i(); auto struct_id = result.to_i();
auto* impl = struct_type->impl(); auto* impl = struct_type->Declaration();
if (struct_type->impl()->name().IsValid()) { if (impl->name().IsValid()) {
push_debug(spv::Op::OpName, {Operand::Int(struct_id), push_debug(spv::Op::OpName,
Operand::String(builder_.Symbols().NameFor( {Operand::Int(struct_id),
struct_type->impl()->name()))}); Operand::String(builder_.Symbols().NameFor(impl->name()))});
} }
OperandList ops; OperandList ops;

View File

@ -449,7 +449,7 @@ class Builder {
/// @param access_control the access controls to assign to the struct /// @param access_control the access controls to assign to the struct
/// @param result the result operand /// @param result the result operand
/// @returns true if the vector was successfully generated /// @returns true if the vector was successfully generated
bool GenerateStructType(const sem::StructType* struct_type, bool GenerateStructType(const sem::Struct* struct_type,
ast::AccessControl::Access access_control, ast::AccessControl::Access access_control,
const Operand& result); const Operand& result);
/// Generates a struct member /// Generates a struct member

View File

@ -219,7 +219,7 @@ TEST_F(BuilderTest, MemberAccessor) {
// var ident : my_struct // var ident : my_struct
// ident.b // ident.b
auto s = Structure("my_struct", { auto* s = Structure("my_struct", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
@ -263,12 +263,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested) {
// //
// var ident : my_struct // var ident : my_struct
// ident.inner.a // ident.inner.a
auto inner_struct = Structure("Inner", { auto* inner_struct = Structure("Inner", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
auto s_type = Structure("my_struct", {Member("inner", inner_struct)}); auto* s_type = Structure("my_struct", {Member("inner", inner_struct)});
auto* var = Global("ident", s_type, ast::StorageClass::kFunction); auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b"); auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
@ -307,7 +307,7 @@ TEST_F(BuilderTest, MemberAccessor_NonPointer) {
// let ident : my_struct = my_struct(); // let ident : my_struct = my_struct();
// ident.b // ident.b
auto s = Structure("my_struct", { auto* s = Structure("my_struct", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
@ -345,12 +345,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested_NonPointer) {
// //
// let ident : my_struct = my_struct(); // let ident : my_struct = my_struct();
// ident.inner.a // ident.inner.a
auto inner_struct = Structure("Inner", { auto* inner_struct = Structure("Inner", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
auto s_type = Structure("my_struct", {Member("inner", inner_struct)}); auto* s_type = Structure("my_struct", {Member("inner", inner_struct)});
auto* var = GlobalConst("ident", s_type, auto* var = GlobalConst("ident", s_type,
Construct(s_type, Construct(inner_struct, 0.f, 0.f))); Construct(s_type, Construct(inner_struct, 0.f, 0.f)));
@ -388,13 +388,13 @@ TEST_F(BuilderTest, MemberAccessor_Nested_WithAlias) {
// //
// var ident : my_struct // var ident : my_struct
// ident.inner.a // ident.inner.a
auto inner_struct = Structure("Inner", { auto* inner_struct = Structure("Inner", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
auto alias = ty.alias("Inner", inner_struct); auto alias = ty.alias("Inner", inner_struct);
auto s_type = Structure("Outer", {Member("inner", alias)}); auto* s_type = Structure("Outer", {Member("inner", alias)});
auto* var = Global("ident", s_type, ast::StorageClass::kFunction); auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "a"); auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "a");
@ -434,12 +434,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_LHS) {
// //
// var ident : my_struct // var ident : my_struct
// ident.inner.a = 2.0f; // ident.inner.a = 2.0f;
auto inner_struct = Structure("Inner", { auto* inner_struct = Structure("Inner", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
auto s_type = Structure("my_struct", {Member("inner", inner_struct)}); auto* s_type = Structure("my_struct", {Member("inner", inner_struct)});
auto* var = Global("ident", s_type, ast::StorageClass::kFunction); auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
auto* expr = auto* expr =
@ -483,12 +483,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_RHS) {
// var ident : my_struct // var ident : my_struct
// var store : f32 = ident.inner.a // var store : f32 = ident.inner.a
auto inner_struct = Structure("Inner", { auto* inner_struct = Structure("Inner", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
auto s_type = Structure("my_struct", {Member("inner", inner_struct)}); auto* s_type = Structure("my_struct", {Member("inner", inner_struct)});
auto* var = Global("ident", s_type, ast::StorageClass::kFunction); auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
auto* store = Global("store", ty.f32(), ast::StorageClass::kFunction); auto* store = Global("store", ty.f32(), ast::StorageClass::kFunction);
@ -693,11 +693,11 @@ TEST_F(BuilderTest, Accessor_Mixed_ArrayAndMember) {
// var index : array<A, 2> // var index : array<A, 2>
// index[0].foo[2].bar.baz.yx // index[0].foo[2].bar.baz.yx
auto c_type = Structure("C", {Member("baz", ty.vec3<f32>())}); auto* c_type = Structure("C", {Member("baz", ty.vec3<f32>())});
auto b_type = Structure("B", {Member("bar", c_type)}); auto* b_type = Structure("B", {Member("bar", c_type)});
auto b_ary_type = ty.array(b_type, 3); auto b_ary_type = ty.array(b_type, 3);
auto a_type = Structure("A", {Member("foo", b_ary_type)}); auto* a_type = Structure("A", {Member("foo", b_ary_type)});
auto a_ary_type = ty.array(a_type, 2); auto a_ary_type = ty.array(a_type, 2);
auto* var = Global("index", a_ary_type, ast::StorageClass::kFunction); auto* var = Global("index", a_ary_type, ast::StorageClass::kFunction);

View File

@ -176,7 +176,7 @@ TEST_F(BuilderTest, Assign_StructMember) {
// var ident : my_struct // var ident : my_struct
// ident.b = 4.0; // ident.b = 4.0;
auto s = Structure("my_struct", { auto* s = Structure("my_struct", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });

View File

@ -1052,7 +1052,7 @@ TEST_F(SpvBuilderConstructorTest, CommonInitializer_Array_VecArray) {
} }
TEST_F(SpvBuilderConstructorTest, Type_Struct) { TEST_F(SpvBuilderConstructorTest, Type_Struct) {
auto s = Structure("my_struct", { auto* s = Structure("my_struct", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.vec3<f32>()), Member("b", ty.vec3<f32>()),
}); });
@ -1202,7 +1202,7 @@ TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Array) {
} }
TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Struct) { TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Struct) {
auto s = Structure("my_struct", {Member("a", ty.f32())}); auto* s = Structure("my_struct", {Member("a", ty.f32())});
auto* t = Construct(s); auto* t = Construct(s);
WrapInFunction(t); WrapInFunction(t);
@ -1622,7 +1622,7 @@ TEST_F(SpvBuilderConstructorTest, IsConstructorConst_BitCastScalars) {
} }
TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct) { TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct) {
auto s = Structure("my_struct", { auto* s = Structure("my_struct", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.vec3<f32>()), Member("b", ty.vec3<f32>()),
}); });
@ -1638,7 +1638,7 @@ TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct) {
TEST_F(SpvBuilderConstructorTest, TEST_F(SpvBuilderConstructorTest,
IsConstructorConst_Struct_WithIdentSubExpression) { IsConstructorConst_Struct_WithIdentSubExpression) {
auto s = Structure("my_struct", { auto* s = Structure("my_struct", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.vec3<f32>()), Member("b", ty.vec3<f32>()),
}); });

View File

@ -188,7 +188,7 @@ TEST_F(BuilderTest, EntryPoint_SharedStruct) {
// return inputs.value; // return inputs.value;
// } // }
auto interface = Structure( auto* interface = Structure(
"Interface", "Interface",
{ {
Member("value", ty.f32(), ast::DecorationList{Location(1u)}), Member("value", ty.f32(), ast::DecorationList{Location(1u)}),

View File

@ -201,7 +201,7 @@ TEST_F(BuilderTest, Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
// return; // return;
// } // }
auto s = Structure("Data", {Member("d", ty.f32())}, auto* s = Structure("Data", {Member("d", ty.f32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadWrite, s); auto ac = ty.access(ast::AccessControl::kReadWrite, s);

View File

@ -376,7 +376,7 @@ TEST_F(BuilderTest, GlobalVar_DeclReadOnly) {
// }; // };
// var b : [[access(read)]] A // var b : [[access(read)]] A
auto A = Structure("A", auto* A = Structure("A",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.i32()), Member("b", ty.i32()),
@ -415,7 +415,7 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasDeclReadOnly) {
// type B = A; // type B = A;
// var b : [[access(read)]] B // var b : [[access(read)]] B
auto A = Structure("A", {Member("a", ty.i32())}, auto* A = Structure("A", {Member("a", ty.i32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto B = ty.alias("B", A); auto B = ty.alias("B", A);
AST().AddConstructedType(B); AST().AddConstructedType(B);
@ -448,7 +448,7 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasAssignReadOnly) {
// type B = [[access(read)]] A; // type B = [[access(read)]] A;
// var b : B // var b : B
auto A = Structure("A", {Member("a", ty.i32())}, auto* A = Structure("A", {Member("a", ty.i32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadOnly, A); auto ac = ty.access(ast::AccessControl::kReadOnly, A);
auto B = ty.alias("B", ac); auto B = ty.alias("B", ac);
@ -481,7 +481,7 @@ TEST_F(BuilderTest, GlobalVar_TwoVarDeclReadOnly) {
// var b : [[access(read)]] A // var b : [[access(read)]] A
// var c : [[access(read_write)]] A // var c : [[access(read_write)]] A
auto A = Structure("A", {Member("a", ty.i32())}, auto* A = Structure("A", {Member("a", ty.i32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto read = ty.access(ast::AccessControl::kReadOnly, A); auto read = ty.access(ast::AccessControl::kReadOnly, A);
auto rw = ty.access(ast::AccessControl::kReadWrite, A); auto rw = ty.access(ast::AccessControl::kReadWrite, A);

View File

@ -1379,7 +1379,7 @@ OpFunctionEnd
} }
TEST_F(IntrinsicBuilderTest, Call_ArrayLength) { TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
auto s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))}, auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadOnly, s); auto ac = ty.access(ast::AccessControl::kReadOnly, s);
Global("b", ac, ast::StorageClass::kStorage, nullptr, Global("b", ac, ast::StorageClass::kStorage, nullptr,
@ -1425,7 +1425,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
} }
TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) { TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
auto s = Structure("my_struct", auto* s = Structure("my_struct",
{ {
Member(0, "z", ty.f32()), Member(0, "z", ty.f32()),
Member(4, "a", ty.array<f32>(4)), Member(4, "a", ty.array<f32>(4)),

View File

@ -59,7 +59,7 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedAlias) {
TEST_F(BuilderTest_Type, GenerateRuntimeArray) { TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
auto ary = ty.array(ty.i32(), 0); auto ary = ty.array(ty.i32(), 0);
auto str = Structure("S", {Member("x", ary)}, auto* str = Structure("S", {Member("x", ary)},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadOnly, str); auto ac = ty.access(ast::AccessControl::kReadOnly, str);
Global("a", ac, ast::StorageClass::kStorage); Global("a", ac, ast::StorageClass::kStorage);
@ -77,7 +77,7 @@ TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) { TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) {
auto ary = ty.array(ty.i32(), 0); auto ary = ty.array(ty.i32(), 0);
auto str = Structure("S", {Member("x", ary)}, auto* str = Structure("S", {Member("x", ary)},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadOnly, str); auto ac = ty.access(ast::AccessControl::kReadOnly, str);
Global("a", ac, ast::StorageClass::kStorage); Global("a", ac, ast::StorageClass::kStorage);
@ -285,11 +285,11 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedPtr) {
} }
TEST_F(BuilderTest_Type, GenerateStruct_Empty) { TEST_F(BuilderTest_Type, GenerateStruct_Empty) {
auto s = Structure("S", {}); auto* s = Structure("S", {});
spirv::Builder& b = Build(); spirv::Builder& b = Build();
auto id = b.GenerateTypeIfNeeded(s); auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
ASSERT_FALSE(b.has_error()) << b.error(); ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(id, 1u); EXPECT_EQ(id, 1u);
@ -301,11 +301,11 @@ TEST_F(BuilderTest_Type, GenerateStruct_Empty) {
} }
TEST_F(BuilderTest_Type, GenerateStruct) { TEST_F(BuilderTest_Type, GenerateStruct) {
auto s = Structure("my_struct", {Member("a", ty.f32())}); auto* s = Structure("my_struct", {Member("a", ty.f32())});
spirv::Builder& b = Build(); spirv::Builder& b = Build();
auto id = b.GenerateTypeIfNeeded(s); auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
ASSERT_FALSE(b.has_error()) << b.error(); ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(id, 1u); EXPECT_EQ(id, 1u);
@ -318,12 +318,12 @@ OpMemberName %1 0 "a"
} }
TEST_F(BuilderTest_Type, GenerateStruct_Decorated) { TEST_F(BuilderTest_Type, GenerateStruct_Decorated) {
auto s = Structure("my_struct", {Member("a", ty.f32())}, auto* s = Structure("my_struct", {Member("a", ty.f32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
spirv::Builder& b = Build(); spirv::Builder& b = Build();
auto id = b.GenerateTypeIfNeeded(s); auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
ASSERT_FALSE(b.has_error()) << b.error(); ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(id, 1u); EXPECT_EQ(id, 1u);
@ -339,14 +339,14 @@ OpMemberDecorate %1 0 Offset 0
} }
TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) { TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.f32(), {MemberAlign(8)}), Member("b", ty.f32(), {MemberAlign(8)}),
}); });
spirv::Builder& b = Build(); spirv::Builder& b = Build();
auto id = b.GenerateTypeIfNeeded(s); auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
ASSERT_FALSE(b.has_error()) << b.error(); ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(id, 1u); EXPECT_EQ(id, 1u);
@ -363,7 +363,7 @@ OpMemberDecorate %1 1 Offset 8
} }
TEST_F(BuilderTest_Type, GenerateStruct_NonLayout_Matrix) { TEST_F(BuilderTest_Type, GenerateStruct_NonLayout_Matrix) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.mat2x2<f32>()), Member("a", ty.mat2x2<f32>()),
Member("b", ty.mat2x3<f32>()), Member("b", ty.mat2x3<f32>()),
Member("c", ty.mat4x4<f32>()), Member("c", ty.mat4x4<f32>()),
@ -371,7 +371,7 @@ TEST_F(BuilderTest_Type, GenerateStruct_NonLayout_Matrix) {
spirv::Builder& b = Build(); spirv::Builder& b = Build();
auto id = b.GenerateTypeIfNeeded(s); auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
ASSERT_FALSE(b.has_error()) << b.error(); ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(id, 1u); EXPECT_EQ(id, 1u);
@ -403,7 +403,7 @@ OpMemberDecorate %1 2 MatrixStride 16
TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutMatrix) { TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutMatrix) {
// We have to infer layout for matrix when it also has an offset. // We have to infer layout for matrix when it also has an offset.
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.mat2x2<f32>()), Member("a", ty.mat2x2<f32>()),
Member("b", ty.mat2x3<f32>()), Member("b", ty.mat2x3<f32>()),
Member("c", ty.mat4x4<f32>()), Member("c", ty.mat4x4<f32>()),
@ -411,7 +411,7 @@ TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutMatrix) {
spirv::Builder& b = Build(); spirv::Builder& b = Build();
auto id = b.GenerateTypeIfNeeded(s); auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
ASSERT_FALSE(b.has_error()) << b.error(); ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(id, 1u); EXPECT_EQ(id, 1u);
@ -449,7 +449,8 @@ TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutArraysOfMatrix) {
auto arr_arr_mat2x3 = ty.array(ty.mat2x3<f32>(), 1); // Doubly nested array auto arr_arr_mat2x3 = ty.array(ty.mat2x3<f32>(), 1); // Doubly nested array
auto rtarr_mat4x4 = ty.array(ty.mat4x4<f32>(), 0); // Runtime array auto rtarr_mat4x4 = ty.array(ty.mat4x4<f32>(), 0); // Runtime array
auto s = Structure("S", auto* s =
Structure("S",
{ {
Member("a", arr_mat2x2), Member("a", arr_mat2x2),
Member("b", arr_arr_mat2x3), Member("b", arr_arr_mat2x3),
@ -459,7 +460,7 @@ TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutArraysOfMatrix) {
spirv::Builder& b = Build(); spirv::Builder& b = Build();
auto id = b.GenerateTypeIfNeeded(s); auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
ASSERT_FALSE(b.has_error()) << b.error(); ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(id, 1u); EXPECT_EQ(id, 1u);

View File

@ -147,8 +147,8 @@ bool GeneratorImpl::EmitConstructedType(typ::Type type) {
return false; return false;
} }
out_ << ";" << std::endl; out_ << ";" << std::endl;
} else if (auto* str = ty->As<sem::StructType>()) { } else if (auto* str = ty->As<sem::Struct>()) {
if (!EmitStructType(str->impl())) { if (!EmitStructType(str->Declaration())) {
return false; return false;
} }
} else { } else {
@ -599,10 +599,10 @@ bool GeneratorImpl::EmitType(typ::Type type) {
if (sampler->IsComparison()) { if (sampler->IsComparison()) {
out_ << "_comparison"; out_ << "_comparison";
} }
} else if (auto* str = ty->As<sem::StructType>()) { } else if (auto* str = ty->As<sem::Struct>()) {
// The struct, as a type, is just the name. We should have already emitted // The struct, as a type, is just the name. We should have already emitted
// the declaration through a call to |EmitStructType| earlier. // the declaration through a call to |EmitStructType| earlier.
out_ << program_->Symbols().NameFor(str->impl()->name()); out_ << program_->Symbols().NameFor(str->Declaration()->name());
} else if (auto* texture = ty->As<sem::Texture>()) { } else if (auto* texture = ty->As<sem::Texture>()) {
out_ << "texture_"; out_ << "texture_";
if (texture->Is<sem::DepthTexture>()) { if (texture->Is<sem::DepthTexture>()) {

View File

@ -35,7 +35,7 @@
#include "src/ast/unary_op_expression.h" #include "src/ast/unary_op_expression.h"
#include "src/program.h" #include "src/program.h"
#include "src/sem/storage_texture_type.h" #include "src/sem/storage_texture_type.h"
#include "src/sem/struct_type.h" #include "src/sem/struct.h"
#include "src/writer/text_generator.h" #include "src/writer/text_generator.h"
namespace tint { namespace tint {

View File

@ -31,7 +31,7 @@ TEST_F(WgslGeneratorImplTest, EmitAlias_F32) {
} }
TEST_F(WgslGeneratorImplTest, EmitConstructedType_Struct) { TEST_F(WgslGeneratorImplTest, EmitConstructedType_Struct) {
auto s = Structure("A", { auto* s = Structure("A", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.i32()), Member("b", ty.i32()),
}); });
@ -51,7 +51,7 @@ type B = A;
} }
TEST_F(WgslGeneratorImplTest, EmitAlias_ToStruct) { TEST_F(WgslGeneratorImplTest, EmitAlias_ToStruct) {
auto s = Structure("A", { auto* s = Structure("A", {
Member("a", ty.f32()), Member("a", ty.f32()),
Member("b", ty.i32()), Member("b", ty.i32()),
}); });

View File

@ -202,7 +202,7 @@ TEST_F(WgslGeneratorImplTest,
// return; // return;
// } // }
auto s = Structure("Data", {Member("d", ty.f32())}, auto* s = Structure("Data", {Member("d", ty.f32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto ac = ty.access(ast::AccessControl::kReadWrite, s); auto ac = ty.access(ast::AccessControl::kReadWrite, s);

View File

@ -48,7 +48,7 @@ TEST_F(WgslGeneratorImplTest, Emit_GlobalDeclAfterFunction) {
TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) { TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
Global("a0", ty.f32(), ast::StorageClass::kPrivate); Global("a0", ty.f32(), ast::StorageClass::kPrivate);
auto s0 = Structure("S0", {Member("a", ty.i32())}); auto* s0 = Structure("S0", {Member("a", ty.i32())});
Func("func", ast::VariableList{}, ty.f32(), Func("func", ast::VariableList{}, ty.f32(),
ast::StatementList{ ast::StatementList{
@ -58,7 +58,7 @@ TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
Global("a1", ty.f32(), ast::StorageClass::kOutput); Global("a1", ty.f32(), ast::StorageClass::kOutput);
auto s1 = Structure("S1", {Member("a", ty.i32())}); auto* s1 = Structure("S1", {Member("a", ty.i32())});
Func("main", ast::VariableList{}, ty.void_(), Func("main", ast::VariableList{}, ty.void_(),
ast::StatementList{ ast::StatementList{

View File

@ -22,7 +22,7 @@ namespace {
using WgslGeneratorImplTest = TestHelper; using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor) { TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor) {
auto s = Structure("Data", {Member("mem", ty.f32())}); auto* s = Structure("Data", {Member("mem", ty.f32())});
Global("str", s, ast::StorageClass::kPrivate); Global("str", s, ast::StorageClass::kPrivate);
auto* expr = MemberAccessor("str", "mem"); auto* expr = MemberAccessor("str", "mem");

View File

@ -47,7 +47,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_Array) {
} }
TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_Read) { TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_Read) {
auto s = Structure("S", {Member("a", ty.i32())}, auto* s = Structure("S", {Member("a", ty.i32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto a = ty.access(ast::AccessControl::kReadOnly, s); auto a = ty.access(ast::AccessControl::kReadOnly, s);
@ -60,7 +60,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_Read) {
} }
TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_ReadWrite) { TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_ReadWrite) {
auto s = Structure("S", {Member("a", ty.i32())}, auto* s = Structure("S", {Member("a", ty.i32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto a = ty.access(ast::AccessControl::kReadWrite, s); auto a = ty.access(ast::AccessControl::kReadWrite, s);
@ -143,7 +143,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_Pointer) {
} }
TEST_F(WgslGeneratorImplTest, EmitType_Struct) { TEST_F(WgslGeneratorImplTest, EmitType_Struct) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32()), Member("b", ty.f32()),
}); });
@ -155,7 +155,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_Struct) {
} }
TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl) { TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.i32(), {MemberOffset(8)}), Member("a", ty.i32(), {MemberOffset(8)}),
Member("b", ty.f32(), {MemberOffset(16)}), Member("b", ty.f32(), {MemberOffset(16)}),
}); });
@ -175,7 +175,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl) {
} }
TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) { TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) {
auto s = auto* s =
Structure("S", { Structure("S", {
Member("tint_0_padding", ty.i32(), {MemberOffset(8)}), Member("tint_0_padding", ty.i32(), {MemberOffset(8)}),
Member("tint_2_padding", ty.f32(), {MemberOffset(16)}), Member("tint_2_padding", ty.f32(), {MemberOffset(16)}),
@ -196,7 +196,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) {
} }
TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) { TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.i32(), {MemberAlign(8)}), Member("a", ty.i32(), {MemberAlign(8)}),
Member("b", ty.f32(), {MemberAlign(16)}), Member("b", ty.f32(), {MemberAlign(16)}),
}); });
@ -214,7 +214,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) {
} }
TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) { TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) {
auto s = Structure("S", { auto* s = Structure("S", {
Member("a", ty.i32(), {MemberSize(16)}), Member("a", ty.i32(), {MemberSize(16)}),
Member("b", ty.f32(), {MemberSize(32)}), Member("b", ty.f32(), {MemberSize(32)}),
}); });
@ -232,7 +232,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) {
} }
TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithDecoration) { TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithDecoration) {
auto s = Structure("S", auto* s = Structure("S",
{ {
Member("a", ty.i32()), Member("a", ty.i32()),
Member("b", ty.f32(), {MemberAlign(8)}), Member("b", ty.f32(), {MemberAlign(8)}),
@ -255,7 +255,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithEntryPointDecorations) {
ast::DecorationList decos; ast::DecorationList decos;
decos.push_back(create<ast::StructBlockDecoration>()); decos.push_back(create<ast::StructBlockDecoration>());
auto s = Structure( auto* s = Structure(
"S", "S",
ast::StructMemberList{ ast::StructMemberList{
Member("a", ty.u32(), {Builtin(ast::Builtin::kVertexIndex)}), Member("a", ty.u32(), {Builtin(ast::Builtin::kVertexIndex)}),

View File

@ -281,8 +281,8 @@ tint_unittests_source_set("tint_unittests_core_src") {
"../src/sem/pointer_type_test.cc", "../src/sem/pointer_type_test.cc",
"../src/sem/sampled_texture_type_test.cc", "../src/sem/sampled_texture_type_test.cc",
"../src/sem/sampler_type_test.cc", "../src/sem/sampler_type_test.cc",
"../src/sem/sem_struct_test.cc",
"../src/sem/storage_texture_type_test.cc", "../src/sem/storage_texture_type_test.cc",
"../src/sem/struct_type_test.cc",
"../src/sem/texture_type_test.cc", "../src/sem/texture_type_test.cc",
"../src/sem/type_manager_test.cc", "../src/sem/type_manager_test.cc",
"../src/sem/u32_type_test.cc", "../src/sem/u32_type_test.cc",
@ -521,7 +521,6 @@ tint_unittests_source_set("tint_unittests_wgsl_writer_src") {
tint_unittests_source_set("tint_unittests_msl_writer_src") { tint_unittests_source_set("tint_unittests_msl_writer_src") {
sources = [ sources = [
"../src/transform/msl_test.cc", "../src/transform/msl_test.cc",
"../src/writer/msl/generator_impl_alias_type_test.cc",
"../src/writer/msl/generator_impl_array_accessor_test.cc", "../src/writer/msl/generator_impl_array_accessor_test.cc",
"../src/writer/msl/generator_impl_assign_test.cc", "../src/writer/msl/generator_impl_assign_test.cc",
"../src/writer/msl/generator_impl_binary_test.cc", "../src/writer/msl/generator_impl_binary_test.cc",
@ -560,7 +559,6 @@ tint_unittests_source_set("tint_unittests_msl_writer_src") {
tint_unittests_source_set("tint_unittests_hlsl_writer_src") { tint_unittests_source_set("tint_unittests_hlsl_writer_src") {
sources = [ sources = [
"../src/transform/hlsl_test.cc", "../src/transform/hlsl_test.cc",
"../src/writer/hlsl/generator_impl_alias_type_test.cc",
"../src/writer/hlsl/generator_impl_array_accessor_test.cc", "../src/writer/hlsl/generator_impl_array_accessor_test.cc",
"../src/writer/hlsl/generator_impl_assign_test.cc", "../src/writer/hlsl/generator_impl_assign_test.cc",
"../src/writer/hlsl/generator_impl_binary_test.cc", "../src/writer/hlsl/generator_impl_binary_test.cc",