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:
parent
33d0f6aa08
commit
ba6ab5e6bd
|
@ -480,8 +480,6 @@ libtint_source_set("libtint_core_all_src") {
|
|||
"sem/sampler_type.h",
|
||||
"sem/storage_texture_type.cc",
|
||||
"sem/storage_texture_type.h",
|
||||
"sem/struct_type.cc",
|
||||
"sem/struct_type.h",
|
||||
"sem/texture_type.cc",
|
||||
"sem/texture_type.h",
|
||||
"sem/type.cc",
|
||||
|
|
|
@ -313,8 +313,6 @@ set(TINT_LIB_SRCS
|
|||
sem/sampler_type.h
|
||||
sem/storage_texture_type.cc
|
||||
sem/storage_texture_type.h
|
||||
sem/struct_type.cc
|
||||
sem/struct_type.h
|
||||
sem/texture_type.cc
|
||||
sem/texture_type.h
|
||||
sem/type.cc
|
||||
|
@ -581,8 +579,8 @@ if(${TINT_BUILD_TESTS})
|
|||
sem/pointer_type_test.cc
|
||||
sem/sampled_texture_type_test.cc
|
||||
sem/sampler_type_test.cc
|
||||
sem/sem_struct_test.cc
|
||||
sem/storage_texture_type_test.cc
|
||||
sem/struct_type_test.cc
|
||||
sem/texture_type_test.cc
|
||||
sem/type_manager_test.cc
|
||||
sem/u32_type_test.cc
|
||||
|
@ -809,7 +807,6 @@ if(${TINT_BUILD_TESTS})
|
|||
|
||||
if(${TINT_BUILD_MSL_WRITER})
|
||||
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_assign_test.cc
|
||||
writer/msl/generator_impl_binary_test.cc
|
||||
|
@ -846,7 +843,6 @@ if(${TINT_BUILD_TESTS})
|
|||
if (${TINT_BUILD_HLSL_WRITER})
|
||||
list(APPEND TINT_TEST_SRCS
|
||||
transform/hlsl_test.cc
|
||||
writer/hlsl/generator_impl_alias_type_test.cc
|
||||
writer/hlsl/generator_impl_array_accessor_test.cc
|
||||
writer/hlsl/generator_impl_assign_test.cc
|
||||
writer/hlsl/generator_impl_binary_test.cc
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#include "src/sem/sampled_texture_type.h"
|
||||
#include "src/sem/storage_texture_type.h"
|
||||
#include "src/sem/struct.h"
|
||||
#include "src/sem/struct_type.h"
|
||||
#include "src/sem/u32_type.h"
|
||||
#include "src/sem/variable.h"
|
||||
#include "src/sem/vector_type.h"
|
||||
|
@ -389,7 +388,7 @@ std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
|
|||
auto binding_info = ruv.second;
|
||||
|
||||
auto* unwrapped_type = var->Type()->UnwrapIfNeeded();
|
||||
auto* str = unwrapped_type->As<sem::StructType>();
|
||||
auto* str = unwrapped_type->As<sem::Struct>();
|
||||
if (str == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
@ -398,19 +397,12 @@ std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
|
|||
continue;
|
||||
}
|
||||
|
||||
auto* sem = program_->Sem().Get(str);
|
||||
if (!sem) {
|
||||
error_ = "Missing semantic information for structure " +
|
||||
program_->Symbols().NameFor(str->impl()->name());
|
||||
continue;
|
||||
}
|
||||
|
||||
ResourceBinding entry;
|
||||
entry.resource_type = ResourceBinding::ResourceType::kUniformBuffer;
|
||||
entry.bind_group = binding_info.group->value();
|
||||
entry.binding = binding_info.binding->value();
|
||||
entry.size = sem->Size();
|
||||
entry.size_no_padding = sem->SizeNoPadding();
|
||||
entry.size = str->Size();
|
||||
entry.size_no_padding = str->SizeNoPadding();
|
||||
|
||||
result.push_back(entry);
|
||||
}
|
||||
|
@ -554,10 +546,9 @@ void Inspector::AddEntryPointInOutVariables(
|
|||
|
||||
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.
|
||||
auto* sem = program_->Sem().Get(struct_ty);
|
||||
for (auto* member : sem->Members()) {
|
||||
for (auto* member : struct_ty->Members()) {
|
||||
AddEntryPointInOutVariables(
|
||||
name + "." +
|
||||
program_->Symbols().NameFor(member->Declaration()->symbol()),
|
||||
|
@ -611,26 +602,19 @@ std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindingsImpl(
|
|||
continue;
|
||||
}
|
||||
|
||||
auto* str = var->Type()->UnwrapIfNeeded()->As<sem::StructType>();
|
||||
auto* str = var->Type()->UnwrapIfNeeded()->As<sem::Struct>();
|
||||
if (!str) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* sem = program_->Sem().Get(str);
|
||||
if (!sem) {
|
||||
error_ = "Missing semantic information for structure " +
|
||||
program_->Symbols().NameFor(str->impl()->name());
|
||||
continue;
|
||||
}
|
||||
|
||||
ResourceBinding entry;
|
||||
entry.resource_type =
|
||||
read_only ? ResourceBinding::ResourceType::kReadOnlyStorageBuffer
|
||||
: ResourceBinding::ResourceType::kStorageBuffer;
|
||||
entry.bind_group = binding_info.group->value();
|
||||
entry.binding = binding_info.binding->value();
|
||||
entry.size = sem->Size();
|
||||
entry.size_no_padding = sem->SizeNoPadding();
|
||||
entry.size = str->Size();
|
||||
entry.size_no_padding = str->SizeNoPadding();
|
||||
|
||||
result.push_back(entry);
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ void ProgramBuilder::MarkAsMoved() {
|
|||
|
||||
void ProgramBuilder::AssertNotMoved() const {
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
#include "src/sem/pointer_type.h"
|
||||
#include "src/sem/sampled_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/vector_type.h"
|
||||
#include "src/sem/void_type.h"
|
||||
|
@ -772,12 +772,6 @@ class ProgramBuilder {
|
|||
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
|
||||
/// @returns the sampler
|
||||
typ::Sampler sampler(ast::SamplerKind kind) const {
|
||||
|
@ -1544,40 +1538,36 @@ class ProgramBuilder {
|
|||
return create<ast::ReturnStatement>(Expr(std::forward<EXPR>(val)));
|
||||
}
|
||||
|
||||
/// Creates a ast::Struct and sem::StructType, registering the
|
||||
/// sem::StructType with the AST().ConstructedTypes().
|
||||
/// Creates a ast::Struct registering it with the AST().ConstructedTypes().
|
||||
/// @param source the source information
|
||||
/// @param name the struct name
|
||||
/// @param members the struct members
|
||||
/// @param decorations the optional struct decorations
|
||||
/// @returns the struct type
|
||||
template <typename NAME>
|
||||
typ::Struct Structure(const Source& source,
|
||||
NAME&& name,
|
||||
ast::StructMemberList members,
|
||||
ast::DecorationList decorations = {}) {
|
||||
ast::Struct* Structure(const Source& source,
|
||||
NAME&& name,
|
||||
ast::StructMemberList members,
|
||||
ast::DecorationList decorations = {}) {
|
||||
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));
|
||||
auto type = ty.struct_(impl);
|
||||
AST().AddConstructedType(type);
|
||||
return type;
|
||||
}
|
||||
|
||||
/// Creates a ast::Struct and sem::StructType, registering the
|
||||
/// sem::StructType with the AST().ConstructedTypes().
|
||||
/// Creates a ast::Struct registering it with the AST().ConstructedTypes().
|
||||
/// @param name the struct name
|
||||
/// @param members the struct members
|
||||
/// @param decorations the optional struct decorations
|
||||
/// @returns the struct type
|
||||
template <typename NAME>
|
||||
typ::Struct Structure(NAME&& name,
|
||||
ast::StructMemberList members,
|
||||
ast::DecorationList decorations = {}) {
|
||||
ast::Struct* Structure(NAME&& name,
|
||||
ast::StructMemberList members,
|
||||
ast::DecorationList decorations = {}) {
|
||||
auto sym = Sym(std::forward<NAME>(name));
|
||||
auto* impl =
|
||||
auto* type =
|
||||
create<ast::Struct>(sym, std::move(members), std::move(decorations));
|
||||
auto type = ty.struct_(impl);
|
||||
AST().AddConstructedType(type);
|
||||
return type;
|
||||
}
|
||||
|
|
|
@ -414,14 +414,14 @@ class ParserImpl : Reader {
|
|||
const spvtools::opt::Instruction& inst,
|
||||
ast::Type* first_operand_type);
|
||||
|
||||
/// 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.
|
||||
/// @returns the given expression, but ensuring it's an unsigned type of the
|
||||
/// same shape as the operand. Wraps the expresion with a bitcast if needed.
|
||||
/// Assumes the given expresion is a integer scalar or vector.
|
||||
/// @param expr an integer scalar or integer vector expression.
|
||||
TypedExpression AsUnsigned(TypedExpression expr);
|
||||
|
||||
/// 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.
|
||||
/// @returns the given expression, but ensuring it's a signed type of the
|
||||
/// same shape as the operand. Wraps the expresion with a bitcast if needed.
|
||||
/// Assumes the given expresion is a integer scalar or vector.
|
||||
/// @param expr an integer scalar or integer vector expression.
|
||||
TypedExpression AsSigned(TypedExpression expr);
|
||||
|
|
|
@ -37,7 +37,7 @@ TEST_F(ParserImplTest, TypeDecl_ParsesType) {
|
|||
TEST_F(ParserImplTest, TypeDecl_ParsesStruct_Ident) {
|
||||
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);
|
||||
|
||||
auto t = p->type_alias();
|
||||
|
|
|
@ -113,7 +113,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_ParsesWithAccessDeco_Read) {
|
|||
ast::DecorationList decos;
|
||||
decos.push_back(block_deco);
|
||||
|
||||
auto s = Structure(Sym("S"), members, decos);
|
||||
auto* s = Structure(Sym("S"), members, decos);
|
||||
|
||||
p->register_constructed("S", s);
|
||||
|
||||
|
@ -137,7 +137,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_ParsesWithAccessDeco_ReadWrite) {
|
|||
ast::DecorationList decos;
|
||||
decos.push_back(block_deco);
|
||||
|
||||
auto s = Structure(Sym("S"), members, decos);
|
||||
auto* s = Structure(Sym("S"), members, decos);
|
||||
|
||||
p->register_constructed("S", s);
|
||||
|
||||
|
@ -161,7 +161,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_MultipleAccessDecoFail) {
|
|||
ast::DecorationList decos;
|
||||
decos.push_back(block_deco);
|
||||
|
||||
auto s = Structure(Sym("S"), members, decos);
|
||||
auto* s = Structure(Sym("S"), members, decos);
|
||||
|
||||
p->register_constructed("S", s);
|
||||
|
||||
|
@ -182,7 +182,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_MultipleAccessDeco_MultiBlock_Fail) {
|
|||
ast::DecorationList decos;
|
||||
decos.push_back(block_deco);
|
||||
|
||||
auto s = Structure(Sym("S"), members, decos);
|
||||
auto* s = Structure(Sym("S"), members, decos);
|
||||
|
||||
p->register_constructed("S", s);
|
||||
|
||||
|
@ -219,7 +219,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_NonAccessDecoFail) {
|
|||
ast::DecorationList decos;
|
||||
decos.push_back(block_deco);
|
||||
|
||||
auto s = Structure(Sym("S"), members, decos);
|
||||
auto* s = Structure(Sym("S"), members, decos);
|
||||
|
||||
p->register_constructed("S", s);
|
||||
|
||||
|
|
|
@ -466,8 +466,8 @@ namespace {
|
|||
|
||||
using StructBlockTest = ResolverTest;
|
||||
TEST_F(StructBlockTest, StructUsedAsArrayElement) {
|
||||
auto s = Structure("S", {Member("x", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member("x", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.array(s, 4);
|
||||
Global("G", a, ast::StorageClass::kPrivate);
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Struct) {
|
|||
// fn main() -> [[location(0)]] Output {
|
||||
// return Output();
|
||||
// }
|
||||
auto output = Structure("Output", {});
|
||||
auto* output = Structure("Output", {});
|
||||
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
||||
{Stage(ast::PipelineStage::kVertex)}, {Location(Source{{13, 43}}, 0)});
|
||||
|
||||
|
@ -105,7 +105,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_Valid) {
|
|||
// fn main() -> Output {
|
||||
// return Output();
|
||||
// }
|
||||
auto output = Structure(
|
||||
auto* output = Structure(
|
||||
"Output", {Member("a", ty.f32(), {Location(0)}),
|
||||
Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
|
||||
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
||||
|
@ -123,7 +123,7 @@ TEST_F(ResolverEntryPointValidationTest,
|
|||
// fn main() -> Output {
|
||||
// return Output();
|
||||
// }
|
||||
auto output = Structure(
|
||||
auto* output = Structure(
|
||||
"Output",
|
||||
{Member("a", ty.f32(),
|
||||
{Location(Source{{13, 43}}, 0),
|
||||
|
@ -147,7 +147,7 @@ TEST_F(ResolverEntryPointValidationTest,
|
|||
// fn main() -> Output {
|
||||
// return Output();
|
||||
// }
|
||||
auto output = Structure(
|
||||
auto* output = Structure(
|
||||
"Output", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
|
||||
Member(Source{{14, 52}}, "b", ty.f32(), {})});
|
||||
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
||||
|
@ -170,9 +170,9 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_NestedStruct) {
|
|||
// fn main() -> Output {
|
||||
// return Output();
|
||||
// }
|
||||
auto inner = Structure(
|
||||
auto* inner = Structure(
|
||||
"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)})});
|
||||
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
||||
{Stage(ast::PipelineStage::kFragment)});
|
||||
|
@ -193,7 +193,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_RuntimeArray) {
|
|||
// fn main() -> Output {
|
||||
// return Output();
|
||||
// }
|
||||
auto output = Structure(
|
||||
auto* output = Structure(
|
||||
"Output",
|
||||
{Member(Source{{13, 43}}, "a", ty.array<float>(), {Location(0)})},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
@ -216,7 +216,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateBuiltins) {
|
|||
// fn main() -> Output {
|
||||
// return Output();
|
||||
// }
|
||||
auto output = Structure(
|
||||
auto* output = Structure(
|
||||
"Output", {Member("a", ty.f32(), {Builtin(ast::Builtin::kFragDepth)}),
|
||||
Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
|
||||
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
||||
|
@ -238,8 +238,8 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateLocation) {
|
|||
// fn main() -> Output {
|
||||
// return Output();
|
||||
// }
|
||||
auto output = Structure("Output", {Member("a", ty.f32(), {Location(1)}),
|
||||
Member("b", ty.f32(), {Location(1)})});
|
||||
auto* output = Structure("Output", {Member("a", ty.f32(), {Location(1)}),
|
||||
Member("b", ty.f32(), {Location(1)})});
|
||||
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
||||
{Stage(ast::PipelineStage::kFragment)});
|
||||
|
||||
|
@ -302,7 +302,7 @@ TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Struct) {
|
|||
// };
|
||||
// [[stage(fragment)]]
|
||||
// fn main([[location(0)]] param : Input) {}
|
||||
auto input = Structure("Input", {});
|
||||
auto* input = Structure("Input", {});
|
||||
auto* param = Param("param", input, {Location(Source{{13, 43}}, 0)});
|
||||
Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
|
||||
{Stage(ast::PipelineStage::kFragment)});
|
||||
|
@ -321,7 +321,7 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_Valid) {
|
|||
// };
|
||||
// [[stage(fragment)]]
|
||||
// fn main(param : Input) {}
|
||||
auto input = Structure(
|
||||
auto* input = Structure(
|
||||
"Input", {Member("a", ty.f32(), {Location(0)}),
|
||||
Member("b", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
|
||||
auto* param = Param("param", input);
|
||||
|
@ -338,7 +338,7 @@ TEST_F(ResolverEntryPointValidationTest,
|
|||
// };
|
||||
// [[stage(fragment)]]
|
||||
// fn main(param : Input) {}
|
||||
auto input = Structure(
|
||||
auto* input = Structure(
|
||||
"Input",
|
||||
{Member("a", ty.f32(),
|
||||
{Location(Source{{13, 43}}, 0),
|
||||
|
@ -361,7 +361,7 @@ TEST_F(ResolverEntryPointValidationTest,
|
|||
// };
|
||||
// [[stage(fragment)]]
|
||||
// fn main(param : Input) {}
|
||||
auto input = Structure(
|
||||
auto* input = Structure(
|
||||
"Input", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
|
||||
Member(Source{{14, 52}}, "b", ty.f32(), {})});
|
||||
auto* param = Param("param", input);
|
||||
|
@ -382,9 +382,9 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_NestedStruct) {
|
|||
// };
|
||||
// [[stage(fragment)]]
|
||||
// fn main(param : Input) {}
|
||||
auto inner = Structure(
|
||||
auto* inner = Structure(
|
||||
"Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
|
||||
auto input =
|
||||
auto* input =
|
||||
Structure("Input", {Member(Source{{14, 52}}, "a", inner, {Location(0)})});
|
||||
auto* param = Param("param", input);
|
||||
Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
|
||||
|
@ -404,7 +404,7 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_RuntimeArray) {
|
|||
// };
|
||||
// [[stage(fragment)]]
|
||||
// fn main(param : Input) {}
|
||||
auto input = Structure(
|
||||
auto* input = Structure(
|
||||
"Input",
|
||||
{Member(Source{{13, 43}}, "a", ty.array<float>(), {Location(0)})},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
@ -446,9 +446,9 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateBuiltins) {
|
|||
// };
|
||||
// [[stage(fragment)]]
|
||||
// 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)})});
|
||||
auto input_b = Structure(
|
||||
auto* input_b = Structure(
|
||||
"InputB", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
|
||||
auto* param_a = Param("param_a", input_a);
|
||||
auto* param_b = Param("param_b", input_b);
|
||||
|
@ -486,8 +486,8 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateLocation) {
|
|||
// };
|
||||
// [[stage(fragment)]]
|
||||
// fn main(param_a : InputA, param_b : InputB) {}
|
||||
auto input_a = Structure("InputA", {Member("a", ty.f32(), {Location(1)})});
|
||||
auto input_b = Structure("InputB", {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* param_a = Param("param_a", input_a);
|
||||
auto* param_b = Param("param_b", input_b);
|
||||
Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
|
||||
|
|
|
@ -27,8 +27,8 @@ namespace {
|
|||
using ResolverHostShareableValidationTest = ResolverTest;
|
||||
|
||||
TEST_F(ResolverHostShareableValidationTest, BoolMember) {
|
||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.bool_())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.bool_())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
|
||||
|
||||
|
@ -42,8 +42,8 @@ TEST_F(ResolverHostShareableValidationTest, BoolMember) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
|
||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.vec3<bool>())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.vec3<bool>())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
|
||||
|
||||
|
@ -59,8 +59,8 @@ TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
|
|||
TEST_F(ResolverHostShareableValidationTest, Aliases) {
|
||||
auto a1 = ty.alias("a1", ty.bool_());
|
||||
AST().AddConstructedType(a1);
|
||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", a1)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", a1)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
auto a2 = ty.alias("a2", ac);
|
||||
AST().AddConstructedType(a2);
|
||||
|
@ -76,12 +76,12 @@ TEST_F(ResolverHostShareableValidationTest, Aliases) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverHostShareableValidationTest, NestedStructures) {
|
||||
auto i1 = Structure("I1", {Member(Source{{1, 2}}, "x", ty.bool_())});
|
||||
auto i2 = Structure("I2", {Member(Source{{3, 4}}, "y", i1)});
|
||||
auto i3 = Structure("I3", {Member(Source{{5, 6}}, "z", i2)});
|
||||
auto* i1 = Structure("I1", {Member(Source{{1, 2}}, "x", ty.bool_())});
|
||||
auto* i2 = Structure("I2", {Member(Source{{3, 4}}, "y", i1)});
|
||||
auto* i3 = Structure("I3", {Member(Source{{5, 6}}, "z", i2)});
|
||||
|
||||
auto s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage);
|
||||
|
||||
|
@ -98,7 +98,7 @@ TEST_F(ResolverHostShareableValidationTest, NestedStructures) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverHostShareableValidationTest, NoError) {
|
||||
auto i1 =
|
||||
auto* i1 =
|
||||
Structure("I1", {
|
||||
Member(Source{{1, 1}}, "x1", ty.f32()),
|
||||
Member(Source{{2, 1}}, "y1", ty.vec3<f32>()),
|
||||
|
@ -106,21 +106,21 @@ TEST_F(ResolverHostShareableValidationTest, NoError) {
|
|||
});
|
||||
auto a1 = ty.alias("a1", i1);
|
||||
AST().AddConstructedType(a1);
|
||||
auto i2 = Structure("I2", {
|
||||
Member(Source{{4, 1}}, "x2", ty.mat2x2<f32>()),
|
||||
Member(Source{{5, 1}}, "y2", i1),
|
||||
Member(Source{{6, 1}}, "z2", ty.mat3x2<i32>()),
|
||||
});
|
||||
auto* i2 = Structure("I2", {
|
||||
Member(Source{{4, 1}}, "x2", ty.mat2x2<f32>()),
|
||||
Member(Source{{5, 1}}, "y2", i1),
|
||||
Member(Source{{6, 1}}, "z2", ty.mat3x2<i32>()),
|
||||
});
|
||||
auto a2 = ty.alias("a2", i2);
|
||||
AST().AddConstructedType(a2);
|
||||
auto i3 = Structure("I3", {
|
||||
Member(Source{{4, 1}}, "x3", a1),
|
||||
Member(Source{{5, 1}}, "y3", i2),
|
||||
Member(Source{{6, 1}}, "z3", a2),
|
||||
});
|
||||
auto* i3 = Structure("I3", {
|
||||
Member(Source{{4, 1}}, "x3", a1),
|
||||
Member(Source{{5, 1}}, "y3", i2),
|
||||
Member(Source{{6, 1}}, "z3", a2),
|
||||
});
|
||||
|
||||
auto s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage);
|
||||
|
||||
|
|
|
@ -757,8 +757,8 @@ using ResolverIntrinsicDataTest = ResolverTest;
|
|||
|
||||
TEST_F(ResolverIntrinsicDataTest, ArrayLength_Vector) {
|
||||
auto ary = ty.array<i32>();
|
||||
auto str = Structure("S", {Member("x", ary)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* str = Structure("S", {Member("x", ary)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, str);
|
||||
Global("a", ac, ast::StorageClass::kStorage);
|
||||
|
||||
|
|
|
@ -105,46 +105,7 @@ TEST_F(ResolverIsHostShareable, ArrayUnsizedOfHostShareable) {
|
|||
EXPECT_TRUE(r()->IsHostShareable(ty.array<i32>()));
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsHostShareable, Struct_AllMembersHostShareable) {
|
||||
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),
|
||||
})));
|
||||
}
|
||||
// Note: Structure tests covered in host_shareable_validation_test.cc
|
||||
|
||||
} // namespace
|
||||
} // namespace resolver
|
||||
|
|
|
@ -90,41 +90,55 @@ TEST_F(ResolverIsStorableTest, ArrayUnsizedOfStorable) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverIsStorableTest, Struct_AllMembersStorable) {
|
||||
EXPECT_TRUE(r()->IsStorable(Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
})));
|
||||
Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
|
||||
auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
|
||||
EXPECT_FALSE(r()->IsStorable(Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ptr_ty),
|
||||
})));
|
||||
Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
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) {
|
||||
auto storable = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
EXPECT_TRUE(r()->IsStorable(Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", storable),
|
||||
})));
|
||||
auto* storable = Structure("Storable", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", storable),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsStorableTest, Struct_NestedNonStorable) {
|
||||
auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
|
||||
auto non_storable = Structure("nonstorable", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ptr_ty),
|
||||
});
|
||||
EXPECT_FALSE(r()->IsStorable(Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", non_storable),
|
||||
})));
|
||||
auto* non_storable = Structure("nonstorable", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ptr_ty),
|
||||
});
|
||||
Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
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
|
||||
|
|
|
@ -181,15 +181,13 @@ bool Resolver::IsStorable(const sem::Type* type) {
|
|||
if (auto* arr = type->As<sem::ArrayType>()) {
|
||||
return IsStorable(arr->type());
|
||||
}
|
||||
if (auto* str_ty = type->As<sem::StructType>()) {
|
||||
if (auto* str = Structure(str_ty)) {
|
||||
for (const auto* member : str->members) {
|
||||
if (!IsStorable(member->Type())) {
|
||||
return false;
|
||||
}
|
||||
if (auto* str = type->As<sem::Struct>()) {
|
||||
for (const auto* member : str->Members()) {
|
||||
if (!IsStorable(member->Type())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -209,12 +207,8 @@ bool Resolver::IsHostShareable(const sem::Type* type) {
|
|||
if (auto* arr = type->As<sem::ArrayType>()) {
|
||||
return IsHostShareable(arr->type());
|
||||
}
|
||||
if (auto* str = type->As<sem::StructType>()) {
|
||||
auto* info = Structure(str);
|
||||
if (!info) {
|
||||
return false;
|
||||
}
|
||||
for (auto* member : info->members) {
|
||||
if (auto* str = type->As<sem::Struct>()) {
|
||||
for (auto* member : str->Members()) {
|
||||
if (!IsHostShareable(member->Type())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -243,7 +237,7 @@ bool Resolver::IsValidAssignment(const sem::Type* lhs, const sem::Type* rhs) {
|
|||
bool Resolver::ResolveInternal() {
|
||||
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) {
|
||||
auto added = named_types_.emplace(name, type).second;
|
||||
if (!added) {
|
||||
|
@ -312,9 +306,9 @@ bool Resolver::ResolveInternal() {
|
|||
return result;
|
||||
}
|
||||
|
||||
const sem::Type* Resolver::Type(const ast::Type* ty) {
|
||||
sem::Type* Resolver::Type(const ast::Type* ty) {
|
||||
Mark(ty);
|
||||
auto* s = [&]() -> const sem::Type* {
|
||||
auto* s = [&]() -> sem::Type* {
|
||||
if (ty->Is<ast::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* el = Type(t->type())) {
|
||||
return builder_->create<sem::ArrayType>(const_cast<sem::Type*>(el),
|
||||
t->size(), t->decorations());
|
||||
auto* sem = builder_->create<sem::ArrayType>(
|
||||
const_cast<sem::Type*>(el), t->size(), t->decorations());
|
||||
if (Array(sem, ty->source())) {
|
||||
return sem;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -370,7 +367,7 @@ const sem::Type* Resolver::Type(const ast::Type* ty) {
|
|||
return nullptr;
|
||||
}
|
||||
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>()) {
|
||||
return builder_->create<sem::Sampler>(t->kind());
|
||||
|
@ -417,35 +414,15 @@ const sem::Type* Resolver::Type(const ast::Type* ty) {
|
|||
return nullptr;
|
||||
}();
|
||||
|
||||
if (s == nullptr) {
|
||||
return nullptr;
|
||||
if (s) {
|
||||
builder_->Sem().Add(ty, s);
|
||||
}
|
||||
if (!Type(s, ty->source())) {
|
||||
return nullptr;
|
||||
}
|
||||
builder_->Sem().Add(ty, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
// TODO(crbug.com/tint/724): This method should be merged into Type(ast::Type*)
|
||||
bool Resolver::Type(const sem::Type* ty, const Source& source /* = {} */) {
|
||||
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 /* = "" */) {
|
||||
Resolver::VariableInfo* Resolver::Variable(ast::Variable* var,
|
||||
sem::Type* type, /* = nullptr */
|
||||
std::string type_name /* = "" */) {
|
||||
auto it = variable_to_info_.find(var);
|
||||
if (it != variable_to_info_.end()) {
|
||||
return it->second;
|
||||
|
@ -561,7 +538,7 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
|
|||
// attribute, satisfying the storage class constraints.
|
||||
|
||||
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) {
|
||||
diagnostics_.add_error(
|
||||
"variables declared in the <storage> storage class must be of an "
|
||||
|
@ -574,7 +551,7 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
|
|||
diagnostics_.add_error(
|
||||
"structure used as a storage buffer must be declared with the "
|
||||
"[[block]] decoration",
|
||||
str->impl()->source());
|
||||
str->Declaration()->source());
|
||||
if (info->declaration->source().range.begin.line) {
|
||||
diagnostics_.add_note("structure used as storage buffer here",
|
||||
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.
|
||||
// Its store type must be a host-shareable structure type with block
|
||||
// attribute, satisfying the storage class constraints.
|
||||
auto* str = info->type->As<sem::StructType>();
|
||||
auto* str = info->type->As<sem::Struct>();
|
||||
if (!str) {
|
||||
diagnostics_.add_error(
|
||||
"variables declared in the <uniform> storage class must be of a "
|
||||
|
@ -601,7 +578,7 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
|
|||
diagnostics_.add_error(
|
||||
"structure used as a uniform buffer must be declared with the "
|
||||
"[[block]] decoration",
|
||||
str->impl()->source());
|
||||
str->Declaration()->source());
|
||||
if (info->declaration->source().range.begin.line) {
|
||||
diagnostics_.add_note("structure used as uniform buffer here",
|
||||
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.
|
||||
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) {
|
||||
// Scan decorations for pipeline IO attributes.
|
||||
// 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.
|
||||
if (Canonical(ty)->Is<sem::StructType>()) {
|
||||
if (Canonical(ty)->Is<sem::Struct>()) {
|
||||
if (pipeline_io_attribute) {
|
||||
diagnostics_.add_error(
|
||||
"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.
|
||||
auto validate_entry_point_decorations = [&](const ast::DecorationList& decos,
|
||||
const sem::Type* ty,
|
||||
Source source,
|
||||
sem::Type* ty, Source source,
|
||||
ParamOrRetType param_or_ret) {
|
||||
// Validate the decorations for the type.
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
// invalid member types.
|
||||
for (auto* member : Structure(struct_ty)->members) {
|
||||
for (auto* member : str->Members()) {
|
||||
auto* member_ty = Canonical(member->Type());
|
||||
if (member_ty->Is<sem::StructType>()) {
|
||||
if (member_ty->Is<sem::Struct>()) {
|
||||
diagnostics_.add_error(
|
||||
"entry point IO types cannot contain nested structures",
|
||||
member->Declaration()->source());
|
||||
|
@ -988,23 +964,16 @@ bool Resolver::Function(ast::Function* func) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (auto* str = param_info->type->As<sem::StructType>()) {
|
||||
auto* str_info = Structure(str);
|
||||
if (!str_info) {
|
||||
return false;
|
||||
}
|
||||
if (auto* str = param_info->type->As<sem::Struct>()) {
|
||||
switch (func->pipeline_stage()) {
|
||||
case ast::PipelineStage::kVertex:
|
||||
str_info->pipeline_stage_uses.emplace(
|
||||
sem::PipelineStageUsage::kVertexInput);
|
||||
str->AddUsage(sem::PipelineStageUsage::kVertexInput);
|
||||
break;
|
||||
case ast::PipelineStage::kFragment:
|
||||
str_info->pipeline_stage_uses.emplace(
|
||||
sem::PipelineStageUsage::kFragmentInput);
|
||||
str->AddUsage(sem::PipelineStageUsage::kFragmentInput);
|
||||
break;
|
||||
case ast::PipelineStage::kCompute:
|
||||
str_info->pipeline_stage_uses.emplace(
|
||||
sem::PipelineStageUsage::kComputeInput);
|
||||
str->AddUsage(sem::PipelineStageUsage::kComputeInput);
|
||||
break;
|
||||
case ast::PipelineStage::kNone:
|
||||
break;
|
||||
|
@ -1026,7 +995,7 @@ bool Resolver::Function(ast::Function* func) {
|
|||
|
||||
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,
|
||||
func->source())) {
|
||||
diagnostics_.add_note("while instantiating return type for " +
|
||||
|
@ -1035,22 +1004,15 @@ bool Resolver::Function(ast::Function* func) {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto* str_info = Structure(str);
|
||||
if (!str_info) {
|
||||
return false;
|
||||
}
|
||||
switch (func->pipeline_stage()) {
|
||||
case ast::PipelineStage::kVertex:
|
||||
str_info->pipeline_stage_uses.emplace(
|
||||
sem::PipelineStageUsage::kVertexOutput);
|
||||
str->AddUsage(sem::PipelineStageUsage::kVertexOutput);
|
||||
break;
|
||||
case ast::PipelineStage::kFragment:
|
||||
str_info->pipeline_stage_uses.emplace(
|
||||
sem::PipelineStageUsage::kFragmentOutput);
|
||||
str->AddUsage(sem::PipelineStageUsage::kFragmentOutput);
|
||||
break;
|
||||
case ast::PipelineStage::kCompute:
|
||||
str_info->pipeline_stage_uses.emplace(
|
||||
sem::PipelineStageUsage::kComputeOutput);
|
||||
str->AddUsage(sem::PipelineStageUsage::kComputeOutput);
|
||||
break;
|
||||
case ast::PipelineStage::kNone:
|
||||
break;
|
||||
|
@ -1659,13 +1621,12 @@ bool Resolver::MemberAccessor(ast::MemberAccessorExpression* expr) {
|
|||
sem::Type* ret = nullptr;
|
||||
std::vector<uint32_t> swizzle;
|
||||
|
||||
if (auto* ty = data_type->As<sem::StructType>()) {
|
||||
if (auto* str = data_type->As<sem::Struct>()) {
|
||||
Mark(expr->member());
|
||||
auto symbol = expr->member()->symbol();
|
||||
auto* str = Structure(ty);
|
||||
|
||||
const sem::StructMember* member = nullptr;
|
||||
for (auto* m : str->members) {
|
||||
for (auto* m : str->Members()) {
|
||||
if (m->Declaration()->symbol() == symbol) {
|
||||
ret = m->Type();
|
||||
member = m;
|
||||
|
@ -1689,11 +1650,11 @@ bool Resolver::MemberAccessor(ast::MemberAccessorExpression* expr) {
|
|||
expr, ret, current_statement_, member));
|
||||
} else if (auto* vec = data_type->As<sem::Vector>()) {
|
||||
Mark(expr->member());
|
||||
std::string str = builder_->Symbols().NameFor(expr->member()->symbol());
|
||||
auto size = str.size();
|
||||
swizzle.reserve(str.size());
|
||||
std::string s = builder_->Symbols().NameFor(expr->member()->symbol());
|
||||
auto size = s.size();
|
||||
swizzle.reserve(s.size());
|
||||
|
||||
for (auto c : str) {
|
||||
for (auto c : s) {
|
||||
switch (c) {
|
||||
case 'x':
|
||||
case 'r':
|
||||
|
@ -1732,8 +1693,8 @@ bool Resolver::MemberAccessor(ast::MemberAccessorExpression* expr) {
|
|||
auto is_xyzw = [](char c) {
|
||||
return c == 'x' || c == 'y' || c == 'z' || c == 'w';
|
||||
};
|
||||
if (!std::all_of(str.begin(), str.end(), is_rgba) &&
|
||||
!std::all_of(str.begin(), str.end(), is_xyzw)) {
|
||||
if (!std::all_of(s.begin(), s.end(), is_rgba) &&
|
||||
!std::all_of(s.begin(), s.end(), is_xyzw)) {
|
||||
diagnostics_.add_error(
|
||||
"invalid mixing of vector swizzle characters rgba with xyzw",
|
||||
expr->member()->source());
|
||||
|
@ -2032,7 +1993,7 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
|||
|
||||
// If the variable has a declared type, resolve it.
|
||||
std::string type_name;
|
||||
const sem::Type* type = nullptr;
|
||||
sem::Type* type = nullptr;
|
||||
if (auto* ast_ty = var->type()) {
|
||||
type_name = ast_ty->FriendlyName(builder_->Symbols());
|
||||
type = Type(ast_ty);
|
||||
|
@ -2122,7 +2083,7 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
|||
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);
|
||||
if (it != expr_info_.end()) {
|
||||
return it->second.type;
|
||||
|
@ -2138,7 +2099,7 @@ std::string Resolver::TypeNameOf(const ast::Expression* expr) {
|
|||
return "";
|
||||
}
|
||||
|
||||
const sem::Type* Resolver::TypeOf(const ast::Literal* lit) {
|
||||
sem::Type* Resolver::TypeOf(const ast::Literal* lit) {
|
||||
if (lit->Is<ast::SintLiteral>()) {
|
||||
return builder_->create<sem::I32>();
|
||||
}
|
||||
|
@ -2273,17 +2234,6 @@ void Resolver::CreateSemanticNodes() const {
|
|||
builder_->create<sem::Expression>(
|
||||
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,
|
||||
|
@ -2305,7 +2255,7 @@ bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
|
|||
/*vec4*/ 16,
|
||||
};
|
||||
|
||||
auto* cty = Canonical(ty);
|
||||
auto* cty = Canonical(const_cast<sem::Type*>(ty));
|
||||
if (cty->is_scalar()) {
|
||||
// Note: Also captures booleans, but these are not host-shareable.
|
||||
align = 4;
|
||||
|
@ -2330,13 +2280,10 @@ bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
|
|||
align = vector_align[mat->rows()];
|
||||
size = vector_align[mat->rows()] * mat->columns();
|
||||
return true;
|
||||
} else if (auto* s = cty->As<sem::StructType>()) {
|
||||
if (auto* si = Structure(s)) {
|
||||
align = si->align;
|
||||
size = si->size;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (auto* s = cty->As<sem::Struct>()) {
|
||||
align = s->Align();
|
||||
size = s->Size();
|
||||
return true;
|
||||
} else if (cty->Is<sem::ArrayType>()) {
|
||||
if (auto* sem =
|
||||
Array(ty->UnwrapAliasIfNeeded()->As<sem::ArrayType>(), source)) {
|
||||
|
@ -2416,8 +2363,8 @@ bool Resolver::ValidateArray(const sem::ArrayType* arr, const Source& source) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (auto* el_str = el_ty->As<sem::StructType>()) {
|
||||
if (el_str->impl()->IsBlockDecorated()) {
|
||||
if (auto* el_str = el_ty->As<sem::Struct>()) {
|
||||
if (el_str->IsBlockDecorated()) {
|
||||
// https://gpuweb.github.io/gpuweb/wgsl/#attributes
|
||||
// A structure type with the block attribute must not be:
|
||||
// * the element type of an array type
|
||||
|
@ -2454,23 +2401,23 @@ bool Resolver::ValidateArrayStrideDecoration(const ast::StrideDecoration* deco,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Resolver::ValidateStructure(const StructInfo* st) {
|
||||
for (auto* member : st->members) {
|
||||
bool Resolver::ValidateStructure(const sem::Struct* str) {
|
||||
for (auto* member : str->Members()) {
|
||||
if (auto* r = member->Type()->UnwrapAll()->As<sem::ArrayType>()) {
|
||||
if (r->IsRuntimeArray()) {
|
||||
if (member != st->members.back()) {
|
||||
if (member != str->Members().back()) {
|
||||
diagnostics_.add_error(
|
||||
"v-0015",
|
||||
"runtime arrays may only appear as the last member of a struct",
|
||||
member->Declaration()->source());
|
||||
return false;
|
||||
}
|
||||
if (!st->type->impl()->IsBlockDecorated()) {
|
||||
if (!str->IsBlockDecorated()) {
|
||||
diagnostics_.add_error(
|
||||
"v-0015",
|
||||
"a struct containing a runtime-sized array "
|
||||
"requires the [[block]] attribute: '" +
|
||||
builder_->Symbols().NameFor(st->type->impl()->name()) + "'",
|
||||
builder_->Symbols().NameFor(str->Declaration()->name()) + "'",
|
||||
member->Declaration()->source());
|
||||
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>())) {
|
||||
diagnostics_.add_error("decoration is not valid for struct declarations",
|
||||
deco->source());
|
||||
|
@ -2509,19 +2456,13 @@ bool Resolver::ValidateStructure(const StructInfo* st) {
|
|||
return true;
|
||||
}
|
||||
|
||||
Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
|
||||
auto info_it = struct_info_.find(str);
|
||||
if (info_it != struct_info_.end()) {
|
||||
// StructInfo already resolved for this structure type
|
||||
return info_it->second;
|
||||
}
|
||||
|
||||
for (auto* deco : str->impl()->decorations()) {
|
||||
sem::Struct* Resolver::Structure(const ast::Struct* str) {
|
||||
for (auto* deco : str->decorations()) {
|
||||
Mark(deco);
|
||||
}
|
||||
|
||||
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
|
||||
// size of the structure.
|
||||
|
@ -2537,7 +2478,7 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
|
|||
uint32_t struct_size = 0;
|
||||
uint32_t struct_align = 1;
|
||||
|
||||
for (auto* member : str->impl()->members()) {
|
||||
for (auto* member : str->members()) {
|
||||
Mark(member);
|
||||
|
||||
// Resolve member type
|
||||
|
@ -2548,7 +2489,7 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
|
|||
|
||||
// Validate member type
|
||||
if (!IsStorable(type)) {
|
||||
builder_->Diagnostics().add_error(
|
||||
diagnostics_.add_error(
|
||||
type->FriendlyName(builder_->Symbols()) +
|
||||
" cannot be used as the type of a structure member");
|
||||
return nullptr;
|
||||
|
@ -2620,19 +2561,14 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
|
|||
auto size_no_padding = struct_size;
|
||||
struct_size = utils::RoundUp(struct_align, struct_size);
|
||||
|
||||
auto* info = struct_infos_.Create();
|
||||
info->type = str;
|
||||
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);
|
||||
auto* out = builder_->create<sem::Struct>(
|
||||
str, std::move(sem_members), struct_align, struct_size, size_no_padding);
|
||||
|
||||
if (!ValidateStructure(info)) {
|
||||
if (!ValidateStructure(out)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return info;
|
||||
return out;
|
||||
}
|
||||
|
||||
bool Resolver::ValidateReturn(const ast::ReturnStatement* ret) {
|
||||
|
@ -2828,20 +2764,18 @@ bool Resolver::Assignment(ast::AssignmentStatement* a) {
|
|||
}
|
||||
|
||||
bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
|
||||
const sem::Type* ty,
|
||||
sem::Type* ty,
|
||||
const Source& usage) {
|
||||
ty = ty->UnwrapIfNeeded();
|
||||
|
||||
if (auto* str = ty->As<sem::StructType>()) {
|
||||
auto* info = Structure(str);
|
||||
if (!info) {
|
||||
return false;
|
||||
}
|
||||
if (info->storage_class_usage.count(sc)) {
|
||||
if (auto* str = ty->As<sem::Struct>()) {
|
||||
if (str->StorageClassUsage().count(sc)) {
|
||||
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)) {
|
||||
std::stringstream err;
|
||||
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());
|
||||
}
|
||||
|
||||
const sem::Type* Resolver::Canonical(const sem::Type* type) {
|
||||
sem::Type* Resolver::Canonical(sem::Type* type) {
|
||||
using AccessControl = sem::AccessControl;
|
||||
using Alias = sem::Alias;
|
||||
using Matrix = sem::Matrix;
|
||||
|
@ -2899,17 +2833,16 @@ const sem::Type* Resolver::Canonical(const sem::Type* type) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::function<const Type*(const Type*)> make_canonical;
|
||||
make_canonical = [&](const Type* t) -> const sem::Type* {
|
||||
std::function<Type*(Type*)> make_canonical;
|
||||
make_canonical = [&](Type* t) -> sem::Type* {
|
||||
// Unwrap alias sequence
|
||||
const Type* ct = t;
|
||||
Type* ct = t;
|
||||
while (auto* p = ct->As<Alias>()) {
|
||||
ct = p->type();
|
||||
}
|
||||
|
||||
if (auto* v = ct->As<Vector>()) {
|
||||
return builder_->create<Vector>(
|
||||
const_cast<sem::Type*>(make_canonical(v->type())), v->size());
|
||||
return builder_->create<Vector>(make_canonical(v->type()), v->size());
|
||||
}
|
||||
if (auto* m = ct->As<Matrix>()) {
|
||||
auto* column_type =
|
||||
|
@ -2943,7 +2876,7 @@ void Resolver::Mark(const ast::Node* node) {
|
|||
}
|
||||
|
||||
Resolver::VariableInfo::VariableInfo(const ast::Variable* decl,
|
||||
const sem::Type* ctype,
|
||||
sem::Type* ctype,
|
||||
const std::string& tn)
|
||||
: declaration(decl),
|
||||
type(ctype),
|
||||
|
@ -2955,8 +2888,5 @@ Resolver::VariableInfo::~VariableInfo() = default;
|
|||
Resolver::FunctionInfo::FunctionInfo(ast::Function* decl) : declaration(decl) {}
|
||||
Resolver::FunctionInfo::~FunctionInfo() = default;
|
||||
|
||||
Resolver::StructInfo::StructInfo() = default;
|
||||
Resolver::StructInfo::~StructInfo() = default;
|
||||
|
||||
} // namespace resolver
|
||||
} // namespace tint
|
||||
|
|
|
@ -49,9 +49,6 @@ namespace sem {
|
|||
class Array;
|
||||
class Statement;
|
||||
} // namespace sem
|
||||
namespace sem {
|
||||
class StructType;
|
||||
} // namespace sem
|
||||
|
||||
namespace resolver {
|
||||
|
||||
|
@ -90,19 +87,19 @@ class Resolver {
|
|||
/// @returns the canonical type for `type`; that is, a type with all aliases
|
||||
/// removed. For example, `Canonical(alias<alias<vec3<alias<f32>>>>)` is
|
||||
/// `vec3<f32>`.
|
||||
const sem::Type* Canonical(const sem::Type* type);
|
||||
sem::Type* Canonical(sem::Type* type);
|
||||
|
||||
private:
|
||||
/// Structure holding semantic information about a variable.
|
||||
/// Used to build the sem::Variable nodes at the end of resolving.
|
||||
struct VariableInfo {
|
||||
VariableInfo(const ast::Variable* decl,
|
||||
const sem::Type* type,
|
||||
sem::Type* type,
|
||||
const std::string& type_name);
|
||||
~VariableInfo();
|
||||
|
||||
ast::Variable const* const declaration;
|
||||
sem::Type const* type;
|
||||
sem::Type* type;
|
||||
std::string const type_name;
|
||||
ast::StorageClass storage_class;
|
||||
std::vector<ast::IdentifierExpression*> users;
|
||||
|
@ -119,7 +116,7 @@ class Resolver {
|
|||
UniqueVector<VariableInfo*> referenced_module_vars;
|
||||
UniqueVector<VariableInfo*> local_referenced_module_vars;
|
||||
std::vector<const ast::ReturnStatement*> return_statements;
|
||||
sem::Type const* return_type = nullptr;
|
||||
sem::Type* return_type = nullptr;
|
||||
std::string return_type_name;
|
||||
|
||||
// List of transitive calls this function makes
|
||||
|
@ -129,7 +126,7 @@ class Resolver {
|
|||
/// Structure holding semantic information about an expression.
|
||||
/// Used to build the sem::Expression nodes at the end of resolving.
|
||||
struct ExpressionInfo {
|
||||
sem::Type const* type;
|
||||
sem::Type* type;
|
||||
std::string const type_name; // Declared type name
|
||||
sem::Statement* statement;
|
||||
};
|
||||
|
@ -142,21 +139,6 @@ class Resolver {
|
|||
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
|
||||
/// parent block and variables declared in the block.
|
||||
/// Used to validate variable scoping rules.
|
||||
|
@ -237,7 +219,6 @@ class Resolver {
|
|||
bool Statement(ast::Statement*);
|
||||
bool Statements(const ast::StatementList&);
|
||||
bool Switch(ast::SwitchStatement* s);
|
||||
bool Type(const sem::Type* ty, const Source& source = {});
|
||||
bool UnaryOp(ast::UnaryOpExpression*);
|
||||
bool VariableDeclStatement(const ast::VariableDeclStatement*);
|
||||
|
||||
|
@ -257,7 +238,7 @@ class Resolver {
|
|||
const sem::Matrix* matrix_type);
|
||||
bool ValidateParameter(const ast::Variable* param);
|
||||
bool ValidateReturn(const ast::ReturnStatement* ret);
|
||||
bool ValidateStructure(const StructInfo* st);
|
||||
bool ValidateStructure(const sem::Struct* str);
|
||||
bool ValidateSwitch(const ast::SwitchStatement* s);
|
||||
bool ValidateVariable(const ast::Variable* param);
|
||||
bool ValidateVectorConstructor(const ast::TypeConstructorExpression* ctor,
|
||||
|
@ -267,7 +248,7 @@ class Resolver {
|
|||
/// hasn't been constructed already. If an error is raised, nullptr is
|
||||
/// returned.
|
||||
/// @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
|
||||
/// 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
|
||||
const sem::Array* Array(const sem::ArrayType* arr, const Source& source);
|
||||
|
||||
/// @returns the StructInfo for the structure `str`, building it if it hasn't
|
||||
/// been constructed already. If an error is raised, nullptr is returned.
|
||||
StructInfo* Structure(const sem::StructType* str);
|
||||
/// @returns the sem::Struct for the AST structure `str`. If an error is
|
||||
/// raised, nullptr is returned.
|
||||
sem::Struct* Structure(const ast::Struct* str);
|
||||
|
||||
/// @returns the VariableInfo for the variable `var`, building it if it hasn't
|
||||
/// 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
|
||||
/// `var->type()->FriendlyName()`.
|
||||
VariableInfo* Variable(ast::Variable* var,
|
||||
const sem::Type* type = nullptr,
|
||||
sem::Type* type = nullptr,
|
||||
std::string type_name = "");
|
||||
|
||||
/// 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.
|
||||
/// @returns true on success, false on error
|
||||
bool ApplyStorageClassUsageToType(ast::StorageClass sc,
|
||||
const sem::Type* ty,
|
||||
sem::Type* ty,
|
||||
const Source& usage);
|
||||
|
||||
/// @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`
|
||||
/// @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`
|
||||
/// @param expr the type name
|
||||
|
@ -321,7 +302,7 @@ class Resolver {
|
|||
|
||||
/// @returns the semantic type of the AST literal `lit`
|
||||
/// @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
|
||||
/// 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<ast::CallExpression*, FunctionCallInfo> function_calls_;
|
||||
std::unordered_map<const ast::Expression*, ExpressionInfo> expr_info_;
|
||||
std::unordered_map<const sem::StructType*, StructInfo*> struct_info_;
|
||||
std::unordered_map<const sem::Type*, const sem::Type*> type_to_canonical_;
|
||||
std::unordered_map<Symbol, const sem::Type*> named_types_;
|
||||
std::unordered_map<sem::Type*, sem::Type*> type_to_canonical_;
|
||||
std::unordered_map<Symbol, sem::Type*> named_types_;
|
||||
std::unordered_set<const ast::Node*> marked_;
|
||||
FunctionInfo* current_function_ = nullptr;
|
||||
sem::Statement* current_statement_ = nullptr;
|
||||
BlockAllocator<VariableInfo> variable_infos_;
|
||||
BlockAllocator<FunctionInfo> function_infos_;
|
||||
BlockAllocator<StructInfo> struct_infos_;
|
||||
};
|
||||
|
||||
} // namespace resolver
|
||||
|
|
|
@ -764,8 +764,8 @@ TEST_F(ResolverTest, Function_Parameters) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
|
||||
auto s = Structure("S", {Member("m", ty.u32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member("m", ty.u32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
auto* in_var = Global("in_var", ty.f32(), ast::StorageClass::kInput);
|
||||
|
@ -800,8 +800,8 @@ TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
|
||||
auto s = Structure("S", {Member("m", ty.u32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member("m", ty.u32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
auto* in_var = Global("in_var", ty.f32(), ast::StorageClass::kInput);
|
||||
|
@ -884,8 +884,8 @@ TEST_F(ResolverTest, Function_ReturnStatements) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
|
||||
auto st = Structure("S", {Member("first_member", ty.i32()),
|
||||
Member("second_member", ty.f32())});
|
||||
auto* st = Structure("S", {Member("first_member", ty.i32()),
|
||||
Member("second_member", ty.f32())});
|
||||
Global("my_struct", st, ast::StorageClass::kInput);
|
||||
|
||||
auto* mem = MemberAccessor("my_struct", "second_member");
|
||||
|
@ -906,8 +906,8 @@ TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
|
||||
auto st = Structure("S", {Member("first_member", ty.i32()),
|
||||
Member("second_member", ty.f32())});
|
||||
auto* st = Structure("S", {Member("first_member", ty.i32()),
|
||||
Member("second_member", ty.f32())});
|
||||
auto alias = ty.alias("alias", st);
|
||||
AST().AddConstructedType(alias);
|
||||
Global("my_struct", alias, ast::StorageClass::kInput);
|
||||
|
@ -987,8 +987,8 @@ TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
|
|||
// }
|
||||
//
|
||||
|
||||
auto stB = Structure("B", {Member("foo", ty.vec4<f32>())});
|
||||
auto stA = Structure("A", {Member("mem", ty.vec(stB, 3))});
|
||||
auto* stB = Structure("B", {Member("foo", ty.vec4<f32>())});
|
||||
auto* stA = Structure("A", {Member("mem", ty.vec(stB, 3))});
|
||||
Global("c", stA, ast::StorageClass::kInput);
|
||||
|
||||
auto* mem = MemberAccessor(
|
||||
|
@ -1006,8 +1006,8 @@ TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverTest, Expr_MemberAccessor_InBinaryOp) {
|
||||
auto st = Structure("S", {Member("first_member", ty.f32()),
|
||||
Member("second_member", ty.f32())});
|
||||
auto* st = Structure("S", {Member("first_member", ty.f32()),
|
||||
Member("second_member", ty.f32())});
|
||||
Global("my_struct", st, ast::StorageClass::kInput);
|
||||
|
||||
auto* expr = Add(MemberAccessor("my_struct", "first_member"),
|
||||
|
|
|
@ -60,7 +60,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
|
|||
|
||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) {
|
||||
// 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 ac = ty.access(ast::AccessControl::kReadOnly, a);
|
||||
Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kStorage);
|
||||
|
@ -88,7 +88,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferBoolAlias) {
|
|||
|
||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoAccessControl) {
|
||||
// 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);
|
||||
|
||||
ASSERT_FALSE(r()->Resolve());
|
||||
|
@ -101,7 +101,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoAccessControl) {
|
|||
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoBlockDecoration) {
|
||||
// struct S { x : i32 };
|
||||
// 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);
|
||||
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
|
||||
|
||||
|
@ -116,8 +116,8 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoBlockDecoration) {
|
|||
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Basic) {
|
||||
// [[block]] struct S { x : i32 };
|
||||
// var<storage> g : [[access(read)]] S;
|
||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
|
||||
|
||||
|
@ -129,8 +129,8 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) {
|
|||
// type a1 = S;
|
||||
// type a2 = [[access(read)]] a1;
|
||||
// var<storage> g : a2;
|
||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a1 = ty.alias("a1", s);
|
||||
AST().AddConstructedType(a1);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, a1);
|
||||
|
@ -168,7 +168,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
|
|||
|
||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
|
||||
// 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 ac = ty.access(ast::AccessControl::kReadOnly, a);
|
||||
Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform);
|
||||
|
@ -197,7 +197,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
|
|||
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoBlockDecoration) {
|
||||
// struct S { x : i32 };
|
||||
// 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);
|
||||
|
||||
ASSERT_FALSE(r()->Resolve());
|
||||
|
@ -211,8 +211,8 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferNoBlockDecoration) {
|
|||
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Basic) {
|
||||
// [[block]] struct S { x : i32 };
|
||||
// var<uniform> g : S;
|
||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform);
|
||||
|
||||
ASSERT_TRUE(r()->Resolve());
|
||||
|
@ -222,8 +222,8 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Aliases) {
|
|||
// [[block]] struct S { x : i32 };
|
||||
// type a1 = S;
|
||||
// var<uniform> g : a1;
|
||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto a1 = ty.alias("a1", s);
|
||||
AST().AddConstructedType(a1);
|
||||
Global(Source{{56, 78}}, "g", a1, ast::StorageClass::kUniform);
|
||||
|
|
|
@ -26,15 +26,15 @@ namespace {
|
|||
using ResolverStructLayoutTest = ResolverTest;
|
||||
|
||||
TEST_F(ResolverStructLayoutTest, Scalars) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.u32()),
|
||||
Member("c", ty.i32()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.u32()),
|
||||
Member("c", ty.i32()),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 12u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 12u);
|
||||
|
@ -57,14 +57,14 @@ TEST_F(ResolverStructLayoutTest, Alias) {
|
|||
auto alias_b = ty.alias("b", ty.f32());
|
||||
AST().AddConstructedType(alias_b);
|
||||
|
||||
auto s = Structure("S", {
|
||||
Member("a", alias_a),
|
||||
Member("b", alias_b),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", alias_a),
|
||||
Member("b", alias_b),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 8u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 8u);
|
||||
|
@ -79,15 +79,15 @@ TEST_F(ResolverStructLayoutTest, Alias) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.array<i32, 3>()),
|
||||
Member("b", ty.array<f32, 5>()),
|
||||
Member("c", ty.array<f32, 1>()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.array<i32, 3>()),
|
||||
Member("b", ty.array<f32, 5>()),
|
||||
Member("c", ty.array<f32, 1>()),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 36u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 36u);
|
||||
|
@ -105,15 +105,15 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.array<i32, 3>(/*stride*/ 8)),
|
||||
Member("b", ty.array<f32, 5>(/*stride*/ 16)),
|
||||
Member("c", ty.array<f32, 1>(/*stride*/ 32)),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.array<i32, 3>(/*stride*/ 8)),
|
||||
Member("b", ty.array<f32, 5>(/*stride*/ 16)),
|
||||
Member("c", ty.array<f32, 1>(/*stride*/ 32)),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 136u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 136u);
|
||||
|
@ -131,15 +131,16 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
|
||||
auto s = Structure("S",
|
||||
{
|
||||
Member("c", ty.array<f32>()),
|
||||
},
|
||||
ast::DecorationList{create<ast::StructBlockDecoration>()});
|
||||
auto* s =
|
||||
Structure("S",
|
||||
{
|
||||
Member("c", ty.array<f32>()),
|
||||
},
|
||||
ast::DecorationList{create<ast::StructBlockDecoration>()});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 4u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 4u);
|
||||
|
@ -151,15 +152,16 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
|
||||
auto s = Structure("S",
|
||||
{
|
||||
Member("c", ty.array<f32>(/*stride*/ 32)),
|
||||
},
|
||||
ast::DecorationList{create<ast::StructBlockDecoration>()});
|
||||
auto* s =
|
||||
Structure("S",
|
||||
{
|
||||
Member("c", ty.array<f32>(/*stride*/ 32)),
|
||||
},
|
||||
ast::DecorationList{create<ast::StructBlockDecoration>()});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 32u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 32u);
|
||||
|
@ -173,13 +175,13 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
|
|||
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) {
|
||||
auto inner = ty.array<i32, 2>(/*stride*/ 16); // size: 32
|
||||
auto outer = ty.array(inner, 12); // size: 12 * 32
|
||||
auto s = Structure("S", {
|
||||
Member("c", outer),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("c", outer),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 384u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 384u);
|
||||
|
@ -191,19 +193,19 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfStructure) {
|
||||
auto inner = Structure("Inner", {
|
||||
Member("a", ty.vec2<i32>()),
|
||||
Member("b", ty.vec3<i32>()),
|
||||
Member("c", ty.vec4<i32>()),
|
||||
}); // size: 48
|
||||
auto outer = ty.array(inner, 12); // size: 12 * 48
|
||||
auto s = Structure("S", {
|
||||
Member("c", outer),
|
||||
});
|
||||
auto* inner = Structure("Inner", {
|
||||
Member("a", ty.vec2<i32>()),
|
||||
Member("b", ty.vec3<i32>()),
|
||||
Member("c", ty.vec4<i32>()),
|
||||
}); // size: 48
|
||||
auto outer = ty.array(inner, 12); // size: 12 * 48
|
||||
auto* s = Structure("S", {
|
||||
Member("c", outer),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 576u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 576u);
|
||||
|
@ -215,15 +217,15 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfStructure) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverStructLayoutTest, Vector) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.vec2<i32>()),
|
||||
Member("b", ty.vec3<i32>()),
|
||||
Member("c", ty.vec4<i32>()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.vec2<i32>()),
|
||||
Member("b", ty.vec3<i32>()),
|
||||
Member("c", ty.vec4<i32>()),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 48u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 48u);
|
||||
|
@ -241,21 +243,21 @@ TEST_F(ResolverStructLayoutTest, Vector) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverStructLayoutTest, Matrix) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.mat2x2<i32>()),
|
||||
Member("b", ty.mat2x3<i32>()),
|
||||
Member("c", ty.mat2x4<i32>()),
|
||||
Member("d", ty.mat3x2<i32>()),
|
||||
Member("e", ty.mat3x3<i32>()),
|
||||
Member("f", ty.mat3x4<i32>()),
|
||||
Member("g", ty.mat4x2<i32>()),
|
||||
Member("h", ty.mat4x3<i32>()),
|
||||
Member("i", ty.mat4x4<i32>()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.mat2x2<i32>()),
|
||||
Member("b", ty.mat2x3<i32>()),
|
||||
Member("c", ty.mat2x4<i32>()),
|
||||
Member("d", ty.mat3x2<i32>()),
|
||||
Member("e", ty.mat3x3<i32>()),
|
||||
Member("f", ty.mat3x4<i32>()),
|
||||
Member("g", ty.mat4x2<i32>()),
|
||||
Member("h", ty.mat4x3<i32>()),
|
||||
Member("i", ty.mat4x4<i32>()),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 368u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 368u);
|
||||
|
@ -291,18 +293,18 @@ TEST_F(ResolverStructLayoutTest, Matrix) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverStructLayoutTest, NestedStruct) {
|
||||
auto inner = Structure("Inner", {
|
||||
Member("a", ty.mat3x3<i32>()),
|
||||
});
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", inner),
|
||||
Member("c", ty.i32()),
|
||||
});
|
||||
auto* inner = Structure("Inner", {
|
||||
Member("a", ty.mat3x3<i32>()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", inner),
|
||||
Member("c", ty.i32()),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 80u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 68u);
|
||||
|
@ -320,21 +322,21 @@ TEST_F(ResolverStructLayoutTest, NestedStruct) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverStructLayoutTest, SizeDecorations) {
|
||||
auto inner = Structure("Inner", {
|
||||
Member("a", ty.f32(), {MemberSize(8)}),
|
||||
Member("b", ty.f32(), {MemberSize(16)}),
|
||||
Member("c", ty.f32(), {MemberSize(8)}),
|
||||
});
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.f32(), {MemberSize(4)}),
|
||||
Member("b", ty.u32(), {MemberSize(8)}),
|
||||
Member("c", inner),
|
||||
Member("d", ty.i32(), {MemberSize(32)}),
|
||||
});
|
||||
auto* inner = Structure("Inner", {
|
||||
Member("a", ty.f32(), {MemberSize(8)}),
|
||||
Member("b", ty.f32(), {MemberSize(16)}),
|
||||
Member("c", ty.f32(), {MemberSize(8)}),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.f32(), {MemberSize(4)}),
|
||||
Member("b", ty.u32(), {MemberSize(8)}),
|
||||
Member("c", inner),
|
||||
Member("d", ty.i32(), {MemberSize(32)}),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 76u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 76u);
|
||||
|
@ -355,21 +357,21 @@ TEST_F(ResolverStructLayoutTest, SizeDecorations) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverStructLayoutTest, AlignDecorations) {
|
||||
auto inner = Structure("Inner", {
|
||||
Member("a", ty.f32(), {MemberAlign(8)}),
|
||||
Member("b", ty.f32(), {MemberAlign(16)}),
|
||||
Member("c", ty.f32(), {MemberAlign(4)}),
|
||||
});
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.f32(), {MemberAlign(4)}),
|
||||
Member("b", ty.u32(), {MemberAlign(8)}),
|
||||
Member("c", inner),
|
||||
Member("d", ty.i32(), {MemberAlign(32)}),
|
||||
});
|
||||
auto* inner = Structure("Inner", {
|
||||
Member("a", ty.f32(), {MemberAlign(8)}),
|
||||
Member("b", ty.f32(), {MemberAlign(16)}),
|
||||
Member("c", ty.f32(), {MemberAlign(4)}),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.f32(), {MemberAlign(4)}),
|
||||
Member("b", ty.u32(), {MemberAlign(8)}),
|
||||
Member("c", inner),
|
||||
Member("d", ty.i32(), {MemberAlign(32)}),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 96u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 68u);
|
||||
|
@ -390,13 +392,13 @@ TEST_F(ResolverStructLayoutTest, AlignDecorations) {
|
|||
}
|
||||
|
||||
TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.i32(), {MemberAlign(1024)}),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.i32(), {MemberAlign(1024)}),
|
||||
});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_EQ(sem->Size(), 1024u);
|
||||
EXPECT_EQ(sem->SizeNoPadding(), 4u);
|
||||
|
|
|
@ -28,41 +28,41 @@ namespace {
|
|||
using ResolverPipelineStageUseTest = ResolverTest;
|
||||
|
||||
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();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_TRUE(sem->PipelineStageUses().empty());
|
||||
}
|
||||
|
||||
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_(), {}, {});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_TRUE(sem->PipelineStageUses().empty());
|
||||
}
|
||||
|
||||
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)))}, {});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_TRUE(sem->PipelineStageUses().empty());
|
||||
}
|
||||
|
||||
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>(),
|
||||
{Return(Construct(ty.vec4<f32>()))},
|
||||
|
@ -71,14 +71,14 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderParam) {
|
|||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->PipelineStageUses(),
|
||||
UnorderedElementsAre(sem::PipelineStageUsage::kVertexInput));
|
||||
}
|
||||
|
||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) {
|
||||
auto s = Structure(
|
||||
auto* s = Structure(
|
||||
"S", {Member("a", ty.f32(), {Builtin(ast::Builtin::kPosition)})});
|
||||
|
||||
Func("main", {}, s, {Return(Construct(s, Expr(0.f)))},
|
||||
|
@ -86,42 +86,42 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) {
|
|||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->PipelineStageUses(),
|
||||
UnorderedElementsAre(sem::PipelineStageUsage::kVertexOutput));
|
||||
}
|
||||
|
||||
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_(), {},
|
||||
{Stage(ast::PipelineStage::kFragment)});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->PipelineStageUses(),
|
||||
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput));
|
||||
}
|
||||
|
||||
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)))},
|
||||
{Stage(ast::PipelineStage::kFragment)});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->PipelineStageUses(),
|
||||
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput));
|
||||
}
|
||||
|
||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) {
|
||||
auto s = Structure(
|
||||
auto* s = Structure(
|
||||
"S",
|
||||
{Member("a", ty.u32(), {Builtin(ast::Builtin::kLocalInvocationIndex)})});
|
||||
|
||||
|
@ -130,14 +130,14 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) {
|
|||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->PipelineStageUses(),
|
||||
UnorderedElementsAre(sem::PipelineStageUsage::kComputeInput));
|
||||
}
|
||||
|
||||
TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
|
||||
auto s = Structure(
|
||||
auto* s = Structure(
|
||||
"S", {Member("a", ty.f32(), {Builtin(ast::Builtin::kPosition)})});
|
||||
|
||||
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();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->PipelineStageUses(),
|
||||
UnorderedElementsAre(sem::PipelineStageUsage::kVertexInput,
|
||||
|
@ -157,7 +157,7 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
|
|||
}
|
||||
|
||||
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);
|
||||
AST().AddConstructedType(s_alias);
|
||||
|
||||
|
@ -166,14 +166,14 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamViaAlias) {
|
|||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->PipelineStageUses(),
|
||||
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput));
|
||||
}
|
||||
|
||||
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);
|
||||
AST().AddConstructedType(s_alias);
|
||||
|
||||
|
@ -182,7 +182,7 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderReturnTypeViaAlias) {
|
|||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->PipelineStageUses(),
|
||||
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput));
|
||||
|
|
|
@ -28,150 +28,150 @@ namespace {
|
|||
using ResolverStorageClassUseTest = ResolverTest;
|
||||
|
||||
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();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_TRUE(sem->StorageClassUsage().empty());
|
||||
}
|
||||
|
||||
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_(), {}, {});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->StorageClassUsage(),
|
||||
UnorderedElementsAre(ast::StorageClass::kNone));
|
||||
}
|
||||
|
||||
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))}, {});
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->StorageClassUsage(),
|
||||
UnorderedElementsAre(ast::StorageClass::kNone));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->StorageClassUsage(),
|
||||
UnorderedElementsAre(ast::StorageClass::kPrivate));
|
||||
}
|
||||
|
||||
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);
|
||||
AST().AddConstructedType(a);
|
||||
Global("g", a, ast::StorageClass::kPrivate);
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->StorageClassUsage(),
|
||||
UnorderedElementsAre(ast::StorageClass::kPrivate));
|
||||
}
|
||||
|
||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalStruct) {
|
||||
auto s = Structure("S", {Member("a", ty.f32())});
|
||||
auto o = Structure("O", {Member("a", s)});
|
||||
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||
auto* o = Structure("O", {Member("a", s)});
|
||||
Global("g", o, ast::StorageClass::kPrivate);
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->StorageClassUsage(),
|
||||
UnorderedElementsAre(ast::StorageClass::kPrivate));
|
||||
}
|
||||
|
||||
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);
|
||||
Global("g", a, ast::StorageClass::kPrivate);
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->StorageClassUsage(),
|
||||
UnorderedElementsAre(ast::StorageClass::kPrivate));
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->StorageClassUsage(),
|
||||
UnorderedElementsAre(ast::StorageClass::kFunction));
|
||||
}
|
||||
|
||||
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);
|
||||
AST().AddConstructedType(a);
|
||||
WrapInFunction(Var("g", a, ast::StorageClass::kFunction));
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->StorageClassUsage(),
|
||||
UnorderedElementsAre(ast::StorageClass::kFunction));
|
||||
}
|
||||
|
||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalStruct) {
|
||||
auto s = Structure("S", {Member("a", ty.f32())});
|
||||
auto o = Structure("O", {Member("a", s)});
|
||||
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||
auto* o = Structure("O", {Member("a", s)});
|
||||
WrapInFunction(Var("g", o, ast::StorageClass::kFunction));
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->StorageClassUsage(),
|
||||
UnorderedElementsAre(ast::StorageClass::kFunction));
|
||||
}
|
||||
|
||||
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);
|
||||
WrapInFunction(Var("g", a, ast::StorageClass::kFunction));
|
||||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->StorageClassUsage(),
|
||||
UnorderedElementsAre(ast::StorageClass::kFunction));
|
||||
}
|
||||
|
||||
TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
|
||||
auto s = Structure("S", {Member("a", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member("a", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global("x", s, ast::StorageClass::kUniform);
|
||||
Global("y", ac, ast::StorageClass::kStorage);
|
||||
|
@ -179,7 +179,7 @@ TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
|
|||
|
||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||
|
||||
auto* sem = Sem().Get(s.sem);
|
||||
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||
ASSERT_NE(sem, nullptr);
|
||||
EXPECT_THAT(sem->StorageClassUsage(),
|
||||
UnorderedElementsAre(ast::StorageClass::kUniform,
|
||||
|
|
|
@ -44,7 +44,7 @@ TEST_F(AccessControlTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_FALSE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -40,7 +40,7 @@ TEST_F(AliasTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_FALSE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -54,7 +54,7 @@ TEST_F(ArrayTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_FALSE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -34,7 +34,7 @@ TEST_F(BoolTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_FALSE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -39,7 +39,7 @@ TEST_F(DepthTextureTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_TRUE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -40,7 +40,7 @@ TEST_F(ExternalTextureTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_TRUE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -34,7 +34,7 @@ TEST_F(F32Test, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_FALSE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -34,7 +34,7 @@ TEST_F(I32Test, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_FALSE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -45,7 +45,7 @@ TEST_F(MatrixTest, Is) {
|
|||
EXPECT_TRUE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_FALSE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -40,7 +40,7 @@ TEST_F(MultisampledTextureTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_TRUE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -42,7 +42,7 @@ TEST_F(PointerTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_TRUE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_FALSE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -39,7 +39,7 @@ TEST_F(SampledTextureTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_TRUE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -45,7 +45,7 @@ TEST_F(SamplerTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_TRUE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_FALSE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
#include "src/sem/access_control_type.h"
|
||||
#include "src/sem/struct.h"
|
||||
#include "src/sem/test_helper.h"
|
||||
#include "src/sem/texture_type.h"
|
||||
|
||||
|
@ -20,22 +21,27 @@ namespace tint {
|
|||
namespace sem {
|
||||
namespace {
|
||||
|
||||
using StructTypeTest = TestHelper;
|
||||
using StructTest = TestHelper;
|
||||
|
||||
TEST_F(StructTypeTest, Creation) {
|
||||
TEST_F(StructTest, Creation) {
|
||||
auto name = Sym("S");
|
||||
auto* impl =
|
||||
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
|
||||
auto* ptr = impl;
|
||||
auto s = ty.struct_(impl);
|
||||
EXPECT_EQ(s->impl(), ptr);
|
||||
auto* s = create<sem::Struct>(impl, StructMemberList{}, 4 /* align */,
|
||||
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* impl =
|
||||
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;
|
||||
EXPECT_FALSE(ty->Is<AccessControl>());
|
||||
EXPECT_FALSE(ty->Is<Alias>());
|
||||
|
@ -46,25 +52,27 @@ TEST_F(StructTypeTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_TRUE(ty->Is<StructType>());
|
||||
EXPECT_TRUE(ty->Is<Struct>());
|
||||
EXPECT_FALSE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
}
|
||||
|
||||
TEST_F(StructTypeTest, TypeName) {
|
||||
TEST_F(StructTest, TypeName) {
|
||||
auto name = Sym("my_struct");
|
||||
auto* impl =
|
||||
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");
|
||||
}
|
||||
|
||||
TEST_F(StructTypeTest, FriendlyName) {
|
||||
TEST_F(StructTest, FriendlyName) {
|
||||
auto name = Sym("my_struct");
|
||||
auto* impl =
|
||||
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");
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ TEST_F(StorageTextureTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_TRUE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "src/sem/struct.h"
|
||||
#include "src/ast/struct_member.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::sem::Struct);
|
||||
|
@ -23,20 +24,16 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::StructMember);
|
|||
namespace tint {
|
||||
namespace sem {
|
||||
|
||||
Struct::Struct(sem::StructType* type,
|
||||
Struct::Struct(const ast::Struct* declaration,
|
||||
StructMemberList members,
|
||||
uint32_t align,
|
||||
uint32_t size,
|
||||
uint32_t size_no_padding,
|
||||
std::unordered_set<ast::StorageClass> storage_class_usage,
|
||||
std::unordered_set<PipelineStageUsage> pipeline_stage_uses)
|
||||
: type_(type),
|
||||
uint32_t size_no_padding)
|
||||
: declaration_(declaration),
|
||||
members_(std::move(members)),
|
||||
align_(align),
|
||||
size_(size),
|
||||
size_no_padding_(size_no_padding),
|
||||
storage_class_usage_(std::move(storage_class_usage)),
|
||||
pipeline_stage_uses_(std::move(pipeline_stage_uses)) {}
|
||||
size_no_padding_(size_no_padding) {}
|
||||
|
||||
Struct::~Struct() = default;
|
||||
|
||||
|
@ -49,6 +46,14 @@ const StructMember* Struct::FindMember(Symbol name) const {
|
|||
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,
|
||||
sem::Type* type,
|
||||
uint32_t offset,
|
||||
|
|
|
@ -17,11 +17,14 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "src/ast/storage_class.h"
|
||||
#include "src/ast/struct.h"
|
||||
#include "src/sem/node.h"
|
||||
#include "src/sem/type.h"
|
||||
#include "src/symbol.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -34,7 +37,6 @@ class StructMember;
|
|||
namespace sem {
|
||||
|
||||
// Forward declarations
|
||||
class StructType;
|
||||
class StructMember;
|
||||
class Type;
|
||||
|
||||
|
@ -52,30 +54,26 @@ enum class PipelineStageUsage {
|
|||
};
|
||||
|
||||
/// Struct holds the semantic information for structures.
|
||||
class Struct : public Castable<Struct, Node> {
|
||||
class Struct : public Castable<Struct, Type> {
|
||||
public:
|
||||
/// Constructor
|
||||
/// @param type the structure type
|
||||
/// @param declaration the AST structure declaration
|
||||
/// @param members the structure members
|
||||
/// @param align the byte alignment of the structure
|
||||
/// @param size the byte size of the structure
|
||||
/// @param size_no_padding size of the members without the end of structure
|
||||
/// alignment padding
|
||||
/// @param storage_class_usage a set of all the storage class usages
|
||||
/// @param pipeline_stage_uses a set of all the pipeline stage uses
|
||||
Struct(sem::StructType* type,
|
||||
Struct(const ast::Struct* declaration,
|
||||
StructMemberList members,
|
||||
uint32_t align,
|
||||
uint32_t size,
|
||||
uint32_t size_no_padding,
|
||||
std::unordered_set<ast::StorageClass> storage_class_usage,
|
||||
std::unordered_set<PipelineStageUsage> pipeline_stage_uses);
|
||||
uint32_t size_no_padding);
|
||||
|
||||
/// Destructor
|
||||
~Struct() override;
|
||||
|
||||
/// @returns the structure type
|
||||
sem::StructType* Type() const { return type_; }
|
||||
/// @returns the struct
|
||||
const ast::Struct* Declaration() const { return declaration_; }
|
||||
|
||||
/// @returns the members of the structure
|
||||
const StructMemberList& Members() const { return members_; }
|
||||
|
@ -100,6 +98,12 @@ class Struct : public Castable<Struct, Node> {
|
|||
/// alignment 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
|
||||
const std::unordered_set<ast::StorageClass>& StorageClassUsage() const {
|
||||
return storage_class_usage_;
|
||||
|
@ -122,19 +126,38 @@ class Struct : public Castable<Struct, Node> {
|
|||
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
|
||||
const std::unordered_set<PipelineStageUsage>& PipelineStageUses() const {
|
||||
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:
|
||||
sem::StructType* const type_;
|
||||
uint64_t LargestMemberBaseAlignment(MemoryLayout mem_layout) const;
|
||||
|
||||
ast::Struct const* const declaration_;
|
||||
StructMemberList const members_;
|
||||
uint32_t const align_;
|
||||
uint32_t const size_;
|
||||
uint32_t const size_no_padding_;
|
||||
std::unordered_set<ast::StorageClass> const storage_class_usage_;
|
||||
std::unordered_set<PipelineStageUsage> const pipeline_stage_uses_;
|
||||
std::unordered_set<ast::StorageClass> storage_class_usage_;
|
||||
std::unordered_set<PipelineStageUsage> pipeline_stage_uses_;
|
||||
};
|
||||
|
||||
/// StructMember holds the semantic information for structure members.
|
||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -41,7 +41,6 @@ class Function;
|
|||
class MemberAccessorExpression;
|
||||
class Statement;
|
||||
class Struct;
|
||||
class StructType;
|
||||
class StructMember;
|
||||
class Type;
|
||||
class Variable;
|
||||
|
@ -58,7 +57,6 @@ struct TypeMappings {
|
|||
Function* operator()(ast::Function*);
|
||||
MemberAccessorExpression* operator()(ast::MemberAccessorExpression*);
|
||||
Statement* operator()(ast::Statement*);
|
||||
Struct* operator()(sem::StructType*);
|
||||
StructMember* operator()(ast::StructMember*);
|
||||
Type* operator()(ast::Type*);
|
||||
Variable* operator()(ast::Variable*);
|
||||
|
|
|
@ -34,7 +34,7 @@ TEST_F(U32Test, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_FALSE(ty->Is<Texture>());
|
||||
EXPECT_TRUE(ty->Is<U32>());
|
||||
EXPECT_FALSE(ty->Is<Vector>());
|
||||
|
|
|
@ -42,7 +42,7 @@ TEST_F(VectorTest, Is) {
|
|||
EXPECT_FALSE(ty->Is<Matrix>());
|
||||
EXPECT_FALSE(ty->Is<Pointer>());
|
||||
EXPECT_FALSE(ty->Is<Sampler>());
|
||||
EXPECT_FALSE(ty->Is<StructType>());
|
||||
EXPECT_FALSE(ty->Is<Struct>());
|
||||
EXPECT_FALSE(ty->Is<Texture>());
|
||||
EXPECT_FALSE(ty->Is<U32>());
|
||||
EXPECT_TRUE(ty->Is<Vector>());
|
||||
|
|
|
@ -77,12 +77,12 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
|||
// get_buffer_size_intrinsic() emits the function decorated with
|
||||
// BufferSizeIntrinsic that is transformed by the HLSL writer into a call to
|
||||
// [RW]ByteAddressBuffer.GetDimensions().
|
||||
std::unordered_map<sem::StructType*, Symbol> buffer_size_intrinsics;
|
||||
auto get_buffer_size_intrinsic = [&](sem::StructType* buffer_type) {
|
||||
std::unordered_map<sem::Struct*, Symbol> buffer_size_intrinsics;
|
||||
auto get_buffer_size_intrinsic = [&](sem::Struct* buffer_type) {
|
||||
return utils::GetOrCreate(buffer_size_intrinsics, buffer_type, [&] {
|
||||
auto name = ctx.dst->Sym();
|
||||
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>(
|
||||
name,
|
||||
ast::VariableList{
|
||||
|
@ -100,8 +100,8 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
|||
ctx.dst->ASTNodes().Create<BufferSizeIntrinsic>(ctx.dst->ID()),
|
||||
},
|
||||
ast::DecorationList{});
|
||||
ctx.InsertAfter(ctx.src->AST().GlobalDeclarations(), buffer_type->impl(),
|
||||
func);
|
||||
ctx.InsertAfter(ctx.src->AST().GlobalDeclarations(),
|
||||
buffer_type->Declaration(), func);
|
||||
return name;
|
||||
});
|
||||
};
|
||||
|
@ -141,7 +141,7 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
|||
auto* storage_buffer_expr = accessor->structure();
|
||||
auto* storage_buffer_sem = sem.Get(storage_buffer_expr);
|
||||
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
|
||||
// already
|
||||
|
@ -149,7 +149,7 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
|||
|
||||
if (!storage_buffer_type) {
|
||||
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());
|
||||
break;
|
||||
}
|
||||
|
@ -176,12 +176,8 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
|||
// First time this array length is used for this block.
|
||||
// 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
|
||||
auto* array_member_sem =
|
||||
storage_buffer_type_sem->Members().back();
|
||||
auto* array_member_sem = storage_buffer_type->Members().back();
|
||||
|
||||
// Construct the variable that'll hold the result of
|
||||
// RWByteAddressBuffer.GetDimensions()
|
||||
|
|
|
@ -110,12 +110,11 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
|||
|
||||
std::function<ast::Expression*()> func_const_initializer;
|
||||
|
||||
if (auto* struct_ty = param_ty->As<sem::StructType>()) {
|
||||
auto* str = ctx.src->Sem().Get(struct_ty);
|
||||
if (auto* str = param_ty->As<sem::Struct>()) {
|
||||
// Pull out all struct members and build initializer list.
|
||||
std::vector<Symbol> member_names;
|
||||
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";
|
||||
}
|
||||
|
||||
|
@ -202,11 +201,10 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
|||
} else {
|
||||
ast::StructMemberList new_struct_members;
|
||||
|
||||
if (auto* struct_ty = ret_type->As<sem::StructType>()) {
|
||||
auto* str = ctx.src->Sem().Get(struct_ty);
|
||||
if (auto* str = ret_type->As<sem::Struct>()) {
|
||||
// Rebuild struct with only the entry point IO attributes.
|
||||
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";
|
||||
}
|
||||
|
||||
|
@ -251,7 +249,7 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
|||
};
|
||||
|
||||
ast::ExpressionList ret_values;
|
||||
if (ret_type->Is<sem::StructType>()) {
|
||||
if (ret_type->Is<sem::Struct>()) {
|
||||
if (!ret->value()->Is<ast::IdentifierExpression>()) {
|
||||
// Create a const to hold the return value expression to avoid
|
||||
// re-evaluating it multiple times.
|
||||
|
|
|
@ -331,7 +331,7 @@ void InsertGlobal(CloneContext& ctx,
|
|||
}
|
||||
|
||||
/// @returns the unwrapped, user-declared constructed type of ty.
|
||||
ast::NamedType* ConstructedTypeOf(sem::Type* ty) {
|
||||
const ast::NamedType* ConstructedTypeOf(sem::Type* ty) {
|
||||
while (true) {
|
||||
if (auto* ptr = ty->As<sem::Pointer>()) {
|
||||
ty = ptr->type();
|
||||
|
@ -341,8 +341,8 @@ ast::NamedType* ConstructedTypeOf(sem::Type* ty) {
|
|||
ty = access->type();
|
||||
continue;
|
||||
}
|
||||
if (auto* str = ty->As<sem::StructType>()) {
|
||||
return str->impl();
|
||||
if (auto* str = ty->As<sem::Struct>()) {
|
||||
return str->Declaration();
|
||||
}
|
||||
// Not a constructed type
|
||||
return nullptr;
|
||||
|
@ -421,7 +421,7 @@ struct DecomposeStorageAccess::State {
|
|||
/// @param el_ty the storage buffer element type
|
||||
/// @return the name of the function that performs the load
|
||||
Symbol LoadFunc(CloneContext& ctx,
|
||||
ast::NamedType* insert_after,
|
||||
const ast::NamedType* insert_after,
|
||||
sem::Type* buf_ty,
|
||||
sem::Type* 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));
|
||||
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
|
||||
}
|
||||
} else if (auto* str_ty = el_ty->As<sem::StructType>()) {
|
||||
auto& sem = ctx.src->Sem();
|
||||
auto* str = sem.Get(str_ty);
|
||||
} else if (auto* str = el_ty->As<sem::Struct>()) {
|
||||
for (auto* member : str->Members()) {
|
||||
auto* offset = ctx.dst->Add("offset", member->Offset());
|
||||
Symbol load = LoadFunc(ctx, insert_after, buf_ty,
|
||||
|
@ -492,7 +490,7 @@ struct DecomposeStorageAccess::State {
|
|||
/// @param el_ty the storage buffer element type
|
||||
/// @return the name of the function that performs the store
|
||||
Symbol StoreFunc(CloneContext& ctx,
|
||||
ast::NamedType* insert_after,
|
||||
const ast::NamedType* insert_after,
|
||||
sem::Type* buf_ty,
|
||||
sem::Type* 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);
|
||||
body.emplace_back(ctx.dst->create<ast::CallStatement>(call));
|
||||
}
|
||||
} else if (auto* str_ty = el_ty->As<sem::StructType>()) {
|
||||
auto& sem = ctx.src->Sem();
|
||||
auto* str = sem.Get(str_ty);
|
||||
} else if (auto* str = el_ty->As<sem::Struct>()) {
|
||||
for (auto* member : str->Members()) {
|
||||
auto* offset = ctx.dst->Add("offset", member->Offset());
|
||||
auto* access = ctx.dst->MemberAccessor(
|
||||
|
@ -676,9 +672,8 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
|
|||
}
|
||||
} else {
|
||||
if (auto access = state.TakeAccess(accessor->structure())) {
|
||||
auto* str_ty = access.type->As<sem::StructType>();
|
||||
auto* member =
|
||||
sem.Get(str_ty)->FindMember(accessor->member()->symbol());
|
||||
auto* str_ty = access.type->As<sem::Struct>();
|
||||
auto* member = str_ty->FindMember(accessor->member()->symbol());
|
||||
auto offset = member->Offset();
|
||||
state.AddAccess(accessor,
|
||||
{
|
||||
|
|
|
@ -133,7 +133,7 @@ Output FirstIndexOffset::Run(const Program* in, const DataMap& data) {
|
|||
instance_index_offset = offset;
|
||||
offset += 4;
|
||||
}
|
||||
auto struct_type =
|
||||
auto* struct_type =
|
||||
ctx.dst->Structure(ctx.dst->Sym(), std::move(members),
|
||||
{ctx.dst->create<ast::StructBlockDecoration>()});
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ void Hlsl::PromoteInitializersToConstVar(CloneContext& ctx) const {
|
|||
}
|
||||
|
||||
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
|
||||
auto dst_symbol = ctx.dst->Sym();
|
||||
// Clone the type
|
||||
|
|
|
@ -288,7 +288,7 @@ Symbol Spirv::HoistToInputVariables(
|
|||
sem::Type* ty,
|
||||
ast::Type* declared_ty,
|
||||
const ast::DecorationList& decorations) const {
|
||||
if (!ty->Is<sem::StructType>()) {
|
||||
if (!ty->Is<sem::Struct>()) {
|
||||
// Base case: create a global variable and return.
|
||||
ast::DecorationList new_decorations =
|
||||
RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) {
|
||||
|
@ -305,8 +305,8 @@ Symbol Spirv::HoistToInputVariables(
|
|||
|
||||
// Recurse into struct members and build the initializer list.
|
||||
std::vector<Symbol> init_value_names;
|
||||
auto* struct_ty = ty->As<sem::StructType>();
|
||||
for (auto* member : ctx.src->Sem().Get(struct_ty)->Members()) {
|
||||
auto* struct_ty = ty->As<sem::Struct>();
|
||||
for (auto* member : struct_ty->Members()) {
|
||||
auto member_var = HoistToInputVariables(
|
||||
ctx, func, member->Type(), member->Declaration()->type(),
|
||||
member->Declaration()->decorations());
|
||||
|
@ -342,7 +342,7 @@ void Spirv::HoistToOutputVariables(CloneContext& ctx,
|
|||
Symbol store_value,
|
||||
ast::StatementList& stores) const {
|
||||
// Base case.
|
||||
if (!ty->Is<sem::StructType>()) {
|
||||
if (!ty->Is<sem::Struct>()) {
|
||||
// Create a global variable.
|
||||
ast::DecorationList new_decorations =
|
||||
RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) {
|
||||
|
@ -366,8 +366,8 @@ void Spirv::HoistToOutputVariables(CloneContext& ctx,
|
|||
}
|
||||
|
||||
// Recurse into struct members.
|
||||
auto* struct_ty = ty->As<sem::StructType>();
|
||||
for (auto* member : ctx.src->Sem().Get(struct_ty)->Members()) {
|
||||
auto* struct_ty = ty->As<sem::Struct>();
|
||||
for (auto* member : struct_ty->Members()) {
|
||||
member_accesses.push_back(ctx.Clone(member->Declaration()->symbol()));
|
||||
HoistToOutputVariables(ctx, func, member->Type(),
|
||||
member->Declaration()->type(),
|
||||
|
|
|
@ -107,8 +107,9 @@ ast::Type* Transform::CreateASTTypeFor(CloneContext* ctx, const sem::Type* ty) {
|
|||
if (auto* a = ty->As<sem::Alias>()) {
|
||||
return ctx->dst->create<ast::TypeName>(ctx->Clone(a->symbol()));
|
||||
}
|
||||
if (auto* s = ty->As<sem::StructType>()) {
|
||||
return ctx->dst->create<ast::TypeName>(ctx->Clone(s->impl()->name()));
|
||||
if (auto* s = ty->As<sem::Struct>()) {
|
||||
return ctx->dst->create<ast::TypeName>(
|
||||
ctx->Clone(s->Declaration()->name()));
|
||||
}
|
||||
TINT_UNREACHABLE(ctx->dst->Diagnostics())
|
||||
<< "Unhandled type: " << ty->TypeInfo().name;
|
||||
|
|
|
@ -98,7 +98,10 @@ TEST_F(CreateASTTypeForTest, Array) {
|
|||
|
||||
TEST_F(CreateASTTypeForTest, AccessControl) {
|
||||
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);
|
||||
});
|
||||
ASSERT_TRUE(ac->Is<ast::AccessControl>());
|
||||
|
@ -109,8 +112,9 @@ TEST_F(CreateASTTypeForTest, AccessControl) {
|
|||
|
||||
TEST_F(CreateASTTypeForTest, Struct) {
|
||||
auto* str = create([](ProgramBuilder& b) {
|
||||
auto* impl = b.Structure("S", {}, {}).ast;
|
||||
return b.create<sem::StructType>(const_cast<ast::Struct*>(impl));
|
||||
auto* decl = b.Structure("S", {}, {});
|
||||
return b.create<sem::Struct>(decl, sem::StructMemberList{}, 4 /* align */,
|
||||
4 /* size */, 4 /* size_no_padding */);
|
||||
});
|
||||
ASSERT_TRUE(str->Is<ast::TypeName>());
|
||||
EXPECT_EQ(
|
||||
|
|
|
@ -204,7 +204,7 @@ struct State {
|
|||
|
||||
// Creating the struct type
|
||||
static const char kStructName[] = "TintVertexData";
|
||||
auto struct_type = ctx.dst->Structure(
|
||||
auto* struct_type = ctx.dst->Structure(
|
||||
ctx.dst->Symbols().New(kStructName),
|
||||
{
|
||||
ctx.dst->Member(GetStructBufferName(),
|
||||
|
@ -432,7 +432,7 @@ struct State {
|
|||
/// @param struct_ty the structure type
|
||||
void ProcessStructParameter(ast::Function* func,
|
||||
ast::Variable* param,
|
||||
ast::Struct* struct_ty) {
|
||||
const ast::Struct* struct_ty) {
|
||||
auto param_sym = ctx.Clone(param->symbol());
|
||||
|
||||
// Process the struct members.
|
||||
|
@ -486,7 +486,7 @@ struct State {
|
|||
new_members.push_back(
|
||||
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.
|
||||
auto* new_param = ctx.dst->Param(ctx.dst->Sym(), new_struct);
|
||||
|
@ -513,8 +513,8 @@ struct State {
|
|||
// Process entry point parameters.
|
||||
for (auto* param : func->params()) {
|
||||
auto* sem = ctx.src->Sem().Get(param);
|
||||
if (auto* str = sem->Type()->As<sem::StructType>()) {
|
||||
ProcessStructParameter(func, param, str->impl());
|
||||
if (auto* str = sem->Type()->As<sem::Struct>()) {
|
||||
ProcessStructParameter(func, param, str->Declaration());
|
||||
} else {
|
||||
ProcessNonStructParameter(func, param);
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ class Pointer;
|
|||
class Sampler;
|
||||
class SampledTexture;
|
||||
class StorageTexture;
|
||||
class StructType;
|
||||
class Struct;
|
||||
class Texture;
|
||||
class Type;
|
||||
class U32;
|
||||
|
@ -254,7 +254,7 @@ using Pointer = TypePair<ast::Pointer, sem::Pointer>;
|
|||
using Sampler = TypePair<ast::Sampler, sem::Sampler>;
|
||||
using SampledTexture = TypePair<ast::SampledTexture, sem::SampledTexture>;
|
||||
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 U32 = TypePair<ast::U32, sem::U32>;
|
||||
using Vector = TypePair<ast::Vector, sem::Vector>;
|
||||
|
@ -271,7 +271,6 @@ inline auto MakeTypePair(AST* ast, SEM* sem) {
|
|||
return TypePair<AST, SEM>{ast, sem};
|
||||
}
|
||||
|
||||
|
||||
} // namespace typ
|
||||
|
||||
} // namespace tint
|
||||
|
|
|
@ -210,7 +210,7 @@ bool GeneratorImpl::EmitConstructedType(std::ostream& out,
|
|||
if (auto* alias = ty->As<sem::Alias>()) {
|
||||
// HLSL typedef is for intrinsic types only. For an alias'd struct,
|
||||
// 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,
|
||||
builder_.Symbols().NameFor(alias->symbol()))) {
|
||||
return false;
|
||||
|
@ -223,9 +223,9 @@ bool GeneratorImpl::EmitConstructedType(std::ostream& out,
|
|||
}
|
||||
out << " " << builder_.Symbols().NameFor(alias->symbol()) << ";"
|
||||
<< std::endl;
|
||||
} else if (auto* str = ty->As<sem::StructType>()) {
|
||||
if (!EmitStructType(out, str,
|
||||
builder_.Symbols().NameFor(str->impl()->name()))) {
|
||||
} else if (auto* str = ty->As<sem::Struct>()) {
|
||||
if (!EmitStructType(
|
||||
out, str, builder_.Symbols().NameFor(str->Declaration()->name()))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -1325,7 +1325,7 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre,
|
|||
}
|
||||
|
||||
bool brackets =
|
||||
type->UnwrapAliasIfNeeded()->IsAnyOf<sem::ArrayType, sem::StructType>();
|
||||
type->UnwrapAliasIfNeeded()->IsAnyOf<sem::ArrayType, sem::Struct>();
|
||||
|
||||
if (brackets) {
|
||||
out << "{";
|
||||
|
@ -1715,9 +1715,9 @@ bool GeneratorImpl::EmitEntryPointData(
|
|||
}
|
||||
|
||||
auto* type = var->Type()->UnwrapIfNeeded();
|
||||
if (auto* strct = type->As<sem::StructType>()) {
|
||||
if (auto* strct = type->As<sem::Struct>()) {
|
||||
out << "ConstantBuffer<"
|
||||
<< builder_.Symbols().NameFor(strct->impl()->name()) << "> "
|
||||
<< builder_.Symbols().NameFor(strct->Declaration()->name()) << "> "
|
||||
<< builder_.Symbols().NameFor(decl->symbol())
|
||||
<< RegisterAndSpace('b', binding_point) << ";" << std::endl;
|
||||
} else {
|
||||
|
@ -2038,7 +2038,7 @@ bool GeneratorImpl::EmitEntryPointFunction(std::ostream& out,
|
|||
for (auto* var : func->params()) {
|
||||
auto* sem = builder_.Sem().Get(var);
|
||||
auto* type = sem->Type();
|
||||
if (!type->Is<sem::StructType>()) {
|
||||
if (!type->Is<sem::Struct>()) {
|
||||
TINT_ICE(diagnostics_) << "Unsupported non-struct entry point parameter";
|
||||
}
|
||||
|
||||
|
@ -2140,10 +2140,10 @@ bool GeneratorImpl::EmitZeroValue(std::ostream& out, sem::Type* type) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
} else if (auto* str = type->As<sem::StructType>()) {
|
||||
} else if (auto* str = type->As<sem::Struct>()) {
|
||||
out << "{";
|
||||
bool first = true;
|
||||
for (auto* member : builder_.Sem().Get(str)->Members()) {
|
||||
for (auto* member : str->Members()) {
|
||||
if (!first) {
|
||||
out << ", ";
|
||||
}
|
||||
|
@ -2383,7 +2383,7 @@ bool GeneratorImpl::EmitSwitch(std::ostream& out, ast::SwitchStatement* stmt) {
|
|||
}
|
||||
|
||||
bool GeneratorImpl::EmitType(std::ostream& out,
|
||||
sem::Type* type,
|
||||
const sem::Type* type,
|
||||
ast::StorageClass storage_class,
|
||||
const std::string& name) {
|
||||
auto* access = type->As<sem::AccessControl>();
|
||||
|
@ -2407,7 +2407,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
|
|||
if (auto* alias = type->As<sem::Alias>()) {
|
||||
out << builder_.Symbols().NameFor(alias->symbol());
|
||||
} else if (auto* ary = type->As<sem::ArrayType>()) {
|
||||
sem::Type* base_type = ary;
|
||||
const sem::Type* base_type = ary;
|
||||
std::vector<uint32_t> sizes;
|
||||
while (auto* arr = base_type->As<sem::ArrayType>()) {
|
||||
if (arr->IsRuntimeArray()) {
|
||||
|
@ -2457,8 +2457,8 @@ bool GeneratorImpl::EmitType(std::ostream& out,
|
|||
out << "Comparison";
|
||||
}
|
||||
out << "State";
|
||||
} else if (auto* str = type->As<sem::StructType>()) {
|
||||
out << builder_.Symbols().NameFor(str->impl()->name());
|
||||
} else if (auto* str = type->As<sem::Struct>()) {
|
||||
out << builder_.Symbols().NameFor(str->Declaration()->name());
|
||||
} else if (auto* tex = type->As<sem::Texture>()) {
|
||||
auto* storage = tex->As<sem::StorageTexture>();
|
||||
auto* multism = tex->As<sem::MultisampledTexture>();
|
||||
|
@ -2547,11 +2547,9 @@ bool GeneratorImpl::EmitType(std::ostream& out,
|
|||
}
|
||||
|
||||
bool GeneratorImpl::EmitStructType(std::ostream& out,
|
||||
const sem::StructType* str,
|
||||
const sem::Struct* str,
|
||||
const std::string& name) {
|
||||
auto* sem_str = builder_.Sem().Get(str);
|
||||
|
||||
auto storage_class_uses = sem_str->StorageClassUsage();
|
||||
auto storage_class_uses = str->StorageClassUsage();
|
||||
if (storage_class_uses.size() ==
|
||||
storage_class_uses.count(ast::StorageClass::kStorage)) {
|
||||
// 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;
|
||||
|
||||
increment_indent();
|
||||
for (auto* mem : sem_str->Members()) {
|
||||
for (auto* mem : str->Members()) {
|
||||
make_indent(out);
|
||||
// TODO(dsinclair): Handle [[offset]] annotation on structs
|
||||
// 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()) {
|
||||
if (auto* location = deco->As<ast::LocationDecoration>()) {
|
||||
auto& pipeline_stage_uses =
|
||||
builder_.Sem().Get(str)->PipelineStageUses();
|
||||
auto& pipeline_stage_uses = str->PipelineStageUses();
|
||||
if (pipeline_stage_uses.size() != 1) {
|
||||
TINT_ICE(diagnostics_) << "invalid entry point IO struct uses";
|
||||
}
|
||||
|
|
|
@ -290,7 +290,7 @@ class GeneratorImpl : public TextGenerator {
|
|||
/// @param name the name of the variable, only used for array emission
|
||||
/// @returns true if the type is emitted
|
||||
bool EmitType(std::ostream& out,
|
||||
sem::Type* type,
|
||||
const sem::Type* type,
|
||||
ast::StorageClass storage_class,
|
||||
const std::string& name);
|
||||
/// Handles generating a structure declaration
|
||||
|
@ -299,7 +299,7 @@ class GeneratorImpl : public TextGenerator {
|
|||
/// @param name the struct name
|
||||
/// @returns true if the struct is emitted
|
||||
bool EmitStructType(std::ostream& out,
|
||||
const sem::StructType* ty,
|
||||
const sem::Struct* ty,
|
||||
const std::string& name);
|
||||
/// Handles a unary op expression
|
||||
/// @param pre the preamble for the expression stream
|
||||
|
|
|
@ -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
|
|
@ -195,11 +195,11 @@ TEST_F(HlslGeneratorImplTest_Constructor,
|
|||
}
|
||||
|
||||
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
|
||||
auto str = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
Member("c", ty.vec3<i32>()),
|
||||
});
|
||||
auto* str = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
Member("c", ty.vec3<i32>()),
|
||||
});
|
||||
|
||||
WrapInFunction(Construct(str, 1, 2.0f, vec3<i32>(3, 4, 5)));
|
||||
|
||||
|
@ -212,11 +212,11 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
|
|||
}
|
||||
|
||||
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct_Empty) {
|
||||
auto str = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
Member("c", ty.vec3<i32>()),
|
||||
});
|
||||
auto* str = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
Member("c", ty.vec3<i32>()),
|
||||
});
|
||||
|
||||
WrapInFunction(Construct(str));
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ TEST_F(HlslGeneratorImplTest_Function,
|
|||
// const g = inputs.col2;
|
||||
// const p = inputs.pos;
|
||||
// }
|
||||
auto interface_struct = Structure(
|
||||
auto* interface_struct = Structure(
|
||||
"Interface",
|
||||
{
|
||||
Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
|
||||
|
@ -252,7 +252,7 @@ TEST_F(HlslGeneratorImplTest_Function,
|
|||
// fn vert_main2() -> VertexOutput {
|
||||
// return foo(0.25);
|
||||
// }
|
||||
auto vertex_output_struct = Structure(
|
||||
auto* vertex_output_struct = Structure(
|
||||
"VertexOutput",
|
||||
{Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
|
||||
|
||||
|
@ -307,8 +307,8 @@ tint_symbol_2 vert_main2() {
|
|||
|
||||
TEST_F(HlslGeneratorImplTest_Function,
|
||||
Emit_Decoration_EntryPoint_With_Uniform) {
|
||||
auto ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* ubo = Global(
|
||||
"ubo", ubo_ty, ast::StorageClass::kUniform, nullptr,
|
||||
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
|
||||
|
@ -359,8 +359,8 @@ void frag_main() {
|
|||
|
||||
TEST_F(HlslGeneratorImplTest_Function,
|
||||
Emit_Decoration_EntryPoint_With_UniformStruct) {
|
||||
auto s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
Global("uniforms", s, ast::StorageClass::kUniform, nullptr,
|
||||
{
|
||||
|
@ -401,12 +401,12 @@ void frag_main() {
|
|||
|
||||
TEST_F(HlslGeneratorImplTest_Function,
|
||||
Emit_Decoration_EntryPoint_With_RW_StorageBuffer_Read) {
|
||||
auto s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
|
@ -447,12 +447,12 @@ void frag_main() {
|
|||
|
||||
TEST_F(HlslGeneratorImplTest_Function,
|
||||
Emit_Decoration_EntryPoint_With_RO_StorageBuffer_Read) {
|
||||
auto s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
|
@ -493,12 +493,12 @@ void frag_main() {
|
|||
|
||||
TEST_F(HlslGeneratorImplTest_Function,
|
||||
Emit_Decoration_EntryPoint_With_WO_StorageBuffer_Store) {
|
||||
auto s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kWriteOnly, s);
|
||||
|
||||
|
@ -536,12 +536,12 @@ void frag_main() {
|
|||
|
||||
TEST_F(HlslGeneratorImplTest_Function,
|
||||
Emit_Decoration_EntryPoint_With_StorageBuffer_Store) {
|
||||
auto s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
|
@ -742,8 +742,8 @@ ep_1_out ep_1(ep_1_in tint_in) {
|
|||
|
||||
TEST_F(HlslGeneratorImplTest_Function,
|
||||
Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
|
||||
auto s = Structure("S", {Member("x", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member("x", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
Global("coord", s, ast::StorageClass::kUniform, nullptr,
|
||||
{
|
||||
create<ast::BindingDecoration>(0),
|
||||
|
@ -792,8 +792,8 @@ void frag_main() {
|
|||
|
||||
TEST_F(HlslGeneratorImplTest_Function,
|
||||
Emit_Decoration_Called_By_EntryPoint_With_StorageBuffer) {
|
||||
auto s = Structure("S", {Member("x", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member("x", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
|
||||
{
|
||||
|
@ -981,8 +981,8 @@ TEST_F(HlslGeneratorImplTest_Function,
|
|||
// return;
|
||||
// }
|
||||
|
||||
auto s = Structure("Data", {Member("d", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Data", {Member("d", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ class HlslGeneratorImplTest_MemberAccessorBase : public BASE {
|
|||
void SetupStorageBuffer(ast::StructMemberList members) {
|
||||
ProgramBuilder& b = *this;
|
||||
|
||||
auto s =
|
||||
auto* s =
|
||||
b.Structure("Data", members, {b.create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac_ty = b.ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
@ -125,7 +125,7 @@ using HlslGeneratorImplTest_MemberAccessorWithParam =
|
|||
HlslGeneratorImplTest_MemberAccessorBase<TestParamHelper<T>>;
|
||||
|
||||
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);
|
||||
|
||||
auto* expr = MemberAccessor("str", "mem");
|
||||
|
@ -522,10 +522,10 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel) {
|
|||
// var<storage> data : Pre;
|
||||
// data.c[2].b
|
||||
|
||||
auto inner = Structure("Inner", {
|
||||
Member("a", ty.vec3<f32>()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
auto* inner = Structure("Inner", {
|
||||
Member("a", ty.vec3<f32>()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
|
||||
SetupStorageBuffer({
|
||||
Member("c", ty.array(inner, 4, 32)),
|
||||
|
@ -568,10 +568,10 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
|||
// var<storage> data : Pre;
|
||||
// data.c[2].b.xy
|
||||
|
||||
auto inner = Structure("Inner", {
|
||||
Member("a", ty.vec3<f32>()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
auto* inner = Structure("Inner", {
|
||||
Member("a", ty.vec3<f32>()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
|
||||
SetupStorageBuffer({
|
||||
Member("c", ty.array(inner, 4, 32)),
|
||||
|
@ -616,10 +616,10 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
|||
// var<storage> data : Pre;
|
||||
// data.c[2].b.g
|
||||
|
||||
auto inner = Structure("Inner", {
|
||||
Member("a", ty.vec3<f32>()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
auto* inner = Structure("Inner", {
|
||||
Member("a", ty.vec3<f32>()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
|
||||
SetupStorageBuffer({
|
||||
Member("c", ty.array(inner, 4, 32)),
|
||||
|
@ -664,10 +664,10 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
|||
// var<storage> data : Pre;
|
||||
// data.c[2].b[1]
|
||||
|
||||
auto inner = Structure("Inner", {
|
||||
Member("a", ty.vec3<f32>()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
auto* inner = Structure("Inner", {
|
||||
Member("a", ty.vec3<f32>()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
|
||||
SetupStorageBuffer({
|
||||
Member("c", ty.array(inner, 4, 32)),
|
||||
|
@ -711,10 +711,10 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_MultiLevel) {
|
|||
// var<storage> data : Pre;
|
||||
// data.c[2].b = vec3<f32>(1.f, 2.f, 3.f);
|
||||
|
||||
auto inner = Structure("Inner", {
|
||||
Member("a", ty.vec3<f32>()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
auto* inner = Structure("Inner", {
|
||||
Member("a", ty.vec3<f32>()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
|
||||
SetupStorageBuffer({
|
||||
Member("c", ty.array(inner, 4, 32)),
|
||||
|
@ -756,10 +756,10 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
|||
// var<storage> data : Pre;
|
||||
// data.c[2].b.y = 1.f;
|
||||
|
||||
auto inner = Structure("Inner", {
|
||||
Member("a", ty.vec3<i32>()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
auto* inner = Structure("Inner", {
|
||||
Member("a", ty.vec3<i32>()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
|
||||
SetupStorageBuffer({
|
||||
Member("c", ty.array(inner, 4, 32)),
|
||||
|
|
|
@ -26,14 +26,14 @@ namespace {
|
|||
using HlslSanitizerTest = TestHelper;
|
||||
|
||||
TEST_F(HlslSanitizerTest, ArrayLength) {
|
||||
auto sb_ty = Structure("SB",
|
||||
{
|
||||
Member("x", ty.f32()),
|
||||
Member("arr", ty.array(ty.vec4<f32>())),
|
||||
},
|
||||
{
|
||||
create<ast::StructBlockDecoration>(),
|
||||
});
|
||||
auto* sb_ty = Structure("SB",
|
||||
{
|
||||
Member("x", ty.f32()),
|
||||
Member("arr", ty.array(ty.vec4<f32>())),
|
||||
},
|
||||
{
|
||||
create<ast::StructBlockDecoration>(),
|
||||
});
|
||||
auto ac_ty = ty.access(ast::AccessControl::kReadOnly, sb_ty);
|
||||
|
||||
Global("sb", ac_ty, ast::StorageClass::kStorage, nullptr,
|
||||
|
@ -100,11 +100,11 @@ TEST_F(HlslSanitizerTest, PromoteArrayInitializerToConstVar) {
|
|||
}
|
||||
|
||||
TEST_F(HlslSanitizerTest, PromoteStructInitializerToConstVar) {
|
||||
auto str = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
Member("c", ty.i32()),
|
||||
});
|
||||
auto* str = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
Member("c", ty.i32()),
|
||||
});
|
||||
auto* struct_init = Construct(str, 1, vec3<f32>(2.f, 3.f, 4.f), 4);
|
||||
auto* struct_access = MemberAccessor(struct_init, "b");
|
||||
auto* pos =
|
||||
|
|
|
@ -156,15 +156,16 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Pointer) {
|
|||
}
|
||||
|
||||
TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
Global("g", s, ast::StorageClass::kPrivate);
|
||||
|
||||
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 {
|
||||
int a;
|
||||
float b;
|
||||
|
@ -173,31 +174,33 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
|
|||
}
|
||||
|
||||
TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl_OmittedIfStorageBuffer) {
|
||||
auto s = Structure("S",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
Global("g", ty.access(ast::AccessControl::kReadWrite, s),
|
||||
ast::StorageClass::kStorage);
|
||||
|
||||
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(), "");
|
||||
}
|
||||
|
||||
TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
Global("g", s, ast::StorageClass::kPrivate);
|
||||
|
||||
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();
|
||||
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
|
||||
/// nested structures.
|
||||
TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) {
|
||||
auto s = Structure(
|
||||
auto* s = Structure(
|
||||
"S", {
|
||||
Member("a", ty.i32(), {MemberSize(32)}),
|
||||
Member("b", ty.f32()),
|
||||
|
@ -215,7 +218,8 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) {
|
|||
|
||||
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();
|
||||
EXPECT_EQ(gen.result(), R"(struct S {
|
||||
int a;
|
||||
|
@ -229,10 +233,10 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) {
|
|||
}
|
||||
|
||||
TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
|
||||
auto s = Structure("S", {
|
||||
Member("double", ty.i32()),
|
||||
Member("float", ty.f32()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("double", ty.i32()),
|
||||
Member("float", ty.f32()),
|
||||
});
|
||||
Global("g", s, ast::StorageClass::kPrivate);
|
||||
|
||||
GeneratorImpl& gen = SanitizeAndBuild();
|
||||
|
@ -247,17 +251,18 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
|
|||
|
||||
// TODO(dsinclair): How to translate [[block]]
|
||||
TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_WithDecoration) {
|
||||
auto s = Structure("S",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
Global("g", s, ast::StorageClass::kPrivate);
|
||||
|
||||
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 {
|
||||
int a;
|
||||
float b;
|
||||
|
|
|
@ -156,7 +156,7 @@ bool GeneratorImpl::EmitConstructedType(const sem::Type* ty) {
|
|||
}
|
||||
out_ << " " << program_->Symbols().NameFor(alias->symbol()) << ";"
|
||||
<< std::endl;
|
||||
} else if (auto* str = ty->As<sem::StructType>()) {
|
||||
} else if (auto* str = ty->As<sem::Struct>()) {
|
||||
if (!EmitStructType(str)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -889,7 +889,7 @@ bool GeneratorImpl::EmitContinue(ast::ContinueStatement*) {
|
|||
bool GeneratorImpl::EmitTypeConstructor(ast::TypeConstructorExpression* expr) {
|
||||
auto* type = TypeOf(expr);
|
||||
|
||||
if (type->IsAnyOf<sem::ArrayType, sem::StructType>()) {
|
||||
if (type->IsAnyOf<sem::ArrayType, sem::Struct>()) {
|
||||
out_ << "{";
|
||||
} else {
|
||||
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_ << "}";
|
||||
} else {
|
||||
out_ << ")";
|
||||
|
@ -948,7 +948,7 @@ bool GeneratorImpl::EmitZeroValue(typ::Type type) {
|
|||
return false;
|
||||
}
|
||||
out_ << "}";
|
||||
} else if (type->As<sem::StructType>()) {
|
||||
} else if (type->As<sem::Struct>()) {
|
||||
out_ << "{}";
|
||||
} else {
|
||||
diagnostics_.add_error("Invalid type for zero emission: " +
|
||||
|
@ -1435,7 +1435,7 @@ bool GeneratorImpl::EmitEntryPointFunction(ast::Function* func) {
|
|||
|
||||
out_ << " " << program_->Symbols().NameFor(var->symbol());
|
||||
|
||||
if (type->Is<sem::StructType>()) {
|
||||
if (type->Is<sem::Struct>()) {
|
||||
out_ << " [[stage_in]]";
|
||||
} else {
|
||||
auto& decos = var->decorations();
|
||||
|
@ -1957,10 +1957,10 @@ bool GeneratorImpl::EmitType(typ::Type type, const std::string& name) {
|
|||
out_ << "*";
|
||||
} else if (type->Is<sem::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
|
||||
// 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>()) {
|
||||
if (tex->Is<sem::DepthTexture>()) {
|
||||
out_ << "depth";
|
||||
|
@ -2056,20 +2056,14 @@ bool GeneratorImpl::EmitPackedType(typ::Type type, const std::string& name) {
|
|||
return EmitType(type, name);
|
||||
}
|
||||
|
||||
bool GeneratorImpl::EmitStructType(const sem::StructType* str) {
|
||||
bool GeneratorImpl::EmitStructType(const sem::Struct* str) {
|
||||
// TODO(dsinclair): Block decoration?
|
||||
// if (str->impl()->decoration() != ast::Decoration::kNone) {
|
||||
// }
|
||||
out_ << "struct " << program_->Symbols().NameFor(str->impl()->name()) << " {"
|
||||
<< std::endl;
|
||||
out_ << "struct " << program_->Symbols().NameFor(str->Declaration()->name())
|
||||
<< " {" << std::endl;
|
||||
|
||||
auto* sem_str = program_->Sem().Get(str);
|
||||
if (!sem_str) {
|
||||
TINT_ICE(diagnostics_) << "struct missing semantic info";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_host_shareable = sem_str->IsHostShareable();
|
||||
bool is_host_shareable = str->IsHostShareable();
|
||||
|
||||
// Emits a `/* 0xnnnn */` byte offset comment for a struct member.
|
||||
auto add_byte_offset_comment = [&](uint32_t offset) {
|
||||
|
@ -2084,14 +2078,14 @@ bool GeneratorImpl::EmitStructType(const sem::StructType* str) {
|
|||
std::string name;
|
||||
do {
|
||||
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;
|
||||
};
|
||||
|
||||
increment_indent();
|
||||
uint32_t msl_offset = 0;
|
||||
for (auto* mem : sem_str->Members()) {
|
||||
for (auto* mem : str->Members()) {
|
||||
make_indent();
|
||||
|
||||
auto name = program_->Symbols().NameFor(mem->Declaration()->symbol());
|
||||
|
@ -2142,8 +2136,7 @@ bool GeneratorImpl::EmitStructType(const sem::StructType* str) {
|
|||
}
|
||||
out_ << " [[" << attr << "]]";
|
||||
} else if (auto* loc = deco->As<ast::LocationDecoration>()) {
|
||||
auto& pipeline_stage_uses =
|
||||
program_->Sem().Get(str)->PipelineStageUses();
|
||||
auto& pipeline_stage_uses = str->PipelineStageUses();
|
||||
if (pipeline_stage_uses.size() != 1) {
|
||||
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();
|
||||
add_byte_offset_comment(msl_offset);
|
||||
add_padding(sem_str->Size() - msl_offset);
|
||||
add_padding(str->Size() - msl_offset);
|
||||
}
|
||||
|
||||
decrement_indent();
|
||||
|
@ -2353,15 +2346,10 @@ GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(
|
|||
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
|
||||
// structure size and alignment matches WGSL's. We need to confirm this.
|
||||
auto* sem = program_->Sem().Get(str);
|
||||
if (!sem) {
|
||||
TINT_ICE(diagnostics_) << "Array missing semantic info";
|
||||
return {};
|
||||
}
|
||||
return SizeAndAlign{sem->Size(), sem->Align()};
|
||||
return SizeAndAlign{str->Size(), str->Align()};
|
||||
}
|
||||
|
||||
TINT_UNREACHABLE(diagnostics_) << "Unhandled type " << ty->TypeInfo().name;
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "src/ast/unary_op_expression.h"
|
||||
#include "src/program.h"
|
||||
#include "src/scope_stack.h"
|
||||
#include "src/sem/struct_type.h"
|
||||
#include "src/sem/struct.h"
|
||||
#include "src/writer/text_generator.h"
|
||||
|
||||
namespace tint {
|
||||
|
@ -206,7 +206,7 @@ class GeneratorImpl : public TextGenerator {
|
|||
/// Handles generating a struct declaration
|
||||
/// @param str the struct to generate
|
||||
/// @returns true if the struct is emitted
|
||||
bool EmitStructType(const sem::StructType* str);
|
||||
bool EmitStructType(const sem::Struct* str);
|
||||
/// Handles emitting a type constructor
|
||||
/// @param expr the type constructor expression
|
||||
/// @returns true if the constructor is emitted
|
||||
|
|
|
@ -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
|
|
@ -145,7 +145,7 @@ TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Array) {
|
|||
}
|
||||
|
||||
TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Struct) {
|
||||
auto str = Structure("S", {
|
||||
auto* str = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
Member("c", ty.vec3<i32>()),
|
||||
|
|
|
@ -170,7 +170,7 @@ TEST_F(MslGeneratorImplTest,
|
|||
// const r = colors.col1;
|
||||
// const g = colors.col2;
|
||||
// }
|
||||
auto interface_struct = Structure(
|
||||
auto* interface_struct = Structure(
|
||||
"Interface",
|
||||
{
|
||||
Member("col1", ty.f32(), {Location(1)}),
|
||||
|
@ -245,7 +245,7 @@ TEST_F(MslGeneratorImplTest,
|
|||
// fn vert_main2() -> VertexOutput {
|
||||
// return foo(0.25);
|
||||
// }
|
||||
auto vertex_output_struct = Structure(
|
||||
auto* vertex_output_struct = Structure(
|
||||
"VertexOutput",
|
||||
{Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
|
||||
|
||||
|
@ -300,12 +300,12 @@ vertex tint_symbol_2 vert_main2() {
|
|||
|
||||
TEST_F(MslGeneratorImplTest,
|
||||
Emit_FunctionDecoration_EntryPoint_With_RW_StorageBuffer) {
|
||||
auto s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
|
@ -345,12 +345,12 @@ fragment void frag_main(device Data& coord [[buffer(0)]]) {
|
|||
|
||||
TEST_F(MslGeneratorImplTest,
|
||||
Emit_FunctionDecoration_EntryPoint_With_RO_StorageBuffer) {
|
||||
auto s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
|
@ -550,8 +550,8 @@ fragment ep_1_out ep_1(float4 coord [[position]]) {
|
|||
|
||||
TEST_F(MslGeneratorImplTest,
|
||||
Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
|
||||
auto ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* ubo = Global(
|
||||
"ubo", ubo_ty, ast::StorageClass::kUniform, nullptr,
|
||||
{create<ast::BindingDecoration>(0), create<ast::GroupDecoration>(1)});
|
||||
|
@ -601,12 +601,12 @@ fragment void frag_main(constant UBO& ubo [[buffer(0)]]) {
|
|||
|
||||
TEST_F(MslGeneratorImplTest,
|
||||
Emit_FunctionDecoration_Called_By_EntryPoint_With_RW_StorageBuffer) {
|
||||
auto s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
|
@ -657,12 +657,12 @@ fragment void frag_main(device Data& coord [[buffer(0)]]) {
|
|||
|
||||
TEST_F(MslGeneratorImplTest,
|
||||
Emit_FunctionDecoration_Called_By_EntryPoint_With_RO_StorageBuffer) {
|
||||
auto s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Data",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
|
||||
|
@ -796,8 +796,8 @@ TEST_F(MslGeneratorImplTest,
|
|||
// return;
|
||||
// }
|
||||
|
||||
auto s = Structure("Data", {Member("d", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Data", {Member("d", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
|
|
|
@ -173,10 +173,10 @@ TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Pointer) {
|
|||
}
|
||||
|
||||
TEST_F(MslGeneratorImplTest, EmitType_Struct) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
|
@ -185,14 +185,15 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct) {
|
|||
}
|
||||
|
||||
TEST_F(MslGeneratorImplTest, EmitType_StructDecl) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
|
||||
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 {
|
||||
int a;
|
||||
float b;
|
||||
|
@ -201,7 +202,7 @@ TEST_F(MslGeneratorImplTest, EmitType_StructDecl) {
|
|||
}
|
||||
|
||||
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
|
||||
auto s =
|
||||
auto* s =
|
||||
Structure("S",
|
||||
{
|
||||
Member("a", ty.i32(), {MemberSize(32)}),
|
||||
|
@ -238,7 +239,8 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
|
|||
|
||||
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)
|
||||
// for each field of the structure s.
|
||||
|
@ -315,35 +317,36 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
|
|||
|
||||
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
|
||||
// inner_x: size(1024), align(512)
|
||||
auto inner_x =
|
||||
auto* inner_x =
|
||||
Structure("inner_x", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32(), {MemberAlign(512)}),
|
||||
});
|
||||
|
||||
// inner_y: size(516), align(4)
|
||||
auto inner_y =
|
||||
auto* inner_y =
|
||||
Structure("inner_y", {
|
||||
Member("a", ty.i32(), {MemberSize(512)}),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
|
||||
auto s = Structure("S",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", inner_x),
|
||||
Member("c", ty.f32()),
|
||||
Member("d", inner_y),
|
||||
Member("e", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", inner_x),
|
||||
Member("c", ty.f32()),
|
||||
Member("d", inner_y),
|
||||
Member("e", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
Global("G", ty.access(ast::AccessControl::kReadOnly, s),
|
||||
ast::StorageClass::kStorage);
|
||||
|
||||
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)
|
||||
// for each field of the structure s.
|
||||
|
@ -401,10 +404,11 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
|
|||
|
||||
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
|
||||
// inner: size(1024), align(512)
|
||||
auto inner = Structure("inner", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32(), {MemberAlign(512)}),
|
||||
});
|
||||
auto* inner =
|
||||
Structure("inner", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32(), {MemberAlign(512)}),
|
||||
});
|
||||
|
||||
// array_x: size(28), align(4)
|
||||
auto array_x = ty.array<f32, 7>();
|
||||
|
@ -415,23 +419,25 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
|
|||
// array_z: size(4), align(4)
|
||||
auto array_z = ty.array<f32>();
|
||||
|
||||
auto s = Structure("S",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", array_x),
|
||||
Member("c", ty.f32()),
|
||||
Member("d", array_y),
|
||||
Member("e", ty.f32()),
|
||||
Member("f", array_z),
|
||||
},
|
||||
ast::DecorationList{create<ast::StructBlockDecoration>()});
|
||||
auto* s =
|
||||
Structure("S",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", array_x),
|
||||
Member("c", ty.f32()),
|
||||
Member("d", array_y),
|
||||
Member("e", ty.f32()),
|
||||
Member("f", array_z),
|
||||
},
|
||||
ast::DecorationList{create<ast::StructBlockDecoration>()});
|
||||
|
||||
Global("G", ty.access(ast::AccessControl::kReadOnly, s),
|
||||
ast::StorageClass::kStorage);
|
||||
|
||||
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)
|
||||
// for each field of the structure s.
|
||||
|
@ -495,7 +501,7 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
|
|||
}
|
||||
|
||||
TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
|
||||
auto s = Structure(
|
||||
auto* s = Structure(
|
||||
"S",
|
||||
{
|
||||
// uses symbols tint_pad_[0..9] and tint_pad_[20..35]
|
||||
|
@ -533,7 +539,8 @@ TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
|
|||
|
||||
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 {
|
||||
/* 0x0000 */ int tint_pad_2;
|
||||
/* 0x0004 */ int8_t tint_pad_10[124];
|
||||
|
@ -582,12 +589,12 @@ TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
|
|||
|
||||
// TODO(dsinclair): How to translate [[block]]
|
||||
TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Struct_WithDecoration) {
|
||||
auto s = Structure("S",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
Global("G", ty.access(ast::AccessControl::kReadOnly, s),
|
||||
ast::StorageClass::kStorage);
|
||||
|
|
|
@ -65,10 +65,10 @@ TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Array) {
|
|||
}
|
||||
|
||||
TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Struct) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
|
||||
auto* var = Var("a", s, ast::StorageClass::kNone);
|
||||
auto* stmt = Decl(var);
|
||||
|
|
|
@ -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
|
||||
// vector we're accessing a swizzle.
|
||||
if (data_type->Is<sem::StructType>()) {
|
||||
auto* strct = data_type->As<sem::StructType>()->impl();
|
||||
if (auto* str = data_type->As<sem::Struct>()) {
|
||||
auto* impl = str->Declaration();
|
||||
auto symbol = expr->member()->symbol();
|
||||
|
||||
uint32_t idx = 0;
|
||||
for (; idx < strct->members().size(); ++idx) {
|
||||
auto* member = strct->members()[idx];
|
||||
for (; idx < impl->members().size(); ++idx) {
|
||||
auto* member = impl->members()[idx];
|
||||
if (member->symbol() == symbol) {
|
||||
break;
|
||||
}
|
||||
|
@ -1294,8 +1294,8 @@ bool Builder::is_constructor_const(ast::Expression* expr, bool is_global_init) {
|
|||
subtype = mat->type()->UnwrapAll();
|
||||
} else if (auto* arr = subtype->As<sem::ArrayType>()) {
|
||||
subtype = arr->type()->UnwrapAll();
|
||||
} else if (auto* str = subtype->As<sem::StructType>()) {
|
||||
subtype = builder_.Sem().Get(str)->Members()[i]->Type()->UnwrapAll();
|
||||
} else if (auto* str = subtype->As<sem::Struct>()) {
|
||||
subtype = str->Members()[i]->Type()->UnwrapAll();
|
||||
}
|
||||
if (subtype != TypeOf(sc)->UnwrapAll()) {
|
||||
return false;
|
||||
|
@ -1373,8 +1373,7 @@ uint32_t Builder::GenerateTypeConstructorExpression(
|
|||
// 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.
|
||||
if (result_type == value_type || result_type->Is<sem::Matrix>() ||
|
||||
result_type->Is<sem::ArrayType>() ||
|
||||
result_type->Is<sem::StructType>()) {
|
||||
result_type->Is<sem::ArrayType>() || result_type->Is<sem::Struct>()) {
|
||||
out << "_" << 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));
|
||||
|
||||
auto* type = TypeOf(accessor->structure())->UnwrapAll();
|
||||
if (!type->Is<sem::StructType>()) {
|
||||
if (!type->Is<sem::Struct>()) {
|
||||
error_ =
|
||||
"invalid type (" + type->type_name() + ") for runtime array length";
|
||||
return 0;
|
||||
}
|
||||
// Runtime array must be the last member in the structure
|
||||
params.push_back(Operand::Int(
|
||||
uint32_t(type->As<sem::StructType>()->impl()->members().size() - 1)));
|
||||
params.push_back(Operand::Int(uint32_t(
|
||||
type->As<sem::Struct>()->Declaration()->members().size() - 1)));
|
||||
|
||||
if (!push_function_inst(spv::Op::OpArrayLength, params)) {
|
||||
return 0;
|
||||
|
@ -2978,7 +2977,7 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
|
|||
return GenerateTypeIfNeeded(alias->type());
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -2993,8 +2992,8 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
|
|||
if (auto* ac = type->As<sem::AccessControl>()) {
|
||||
// The non-struct case was handled above.
|
||||
auto* subtype = ac->type()->UnwrapIfNeeded();
|
||||
if (!GenerateStructType(subtype->As<sem::StructType>(),
|
||||
ac->access_control(), result)) {
|
||||
if (!GenerateStructType(subtype->As<sem::Struct>(), ac->access_control(),
|
||||
result)) {
|
||||
return 0;
|
||||
}
|
||||
} else if (auto* arr = type->As<sem::ArrayType>()) {
|
||||
|
@ -3015,7 +3014,7 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
|
|||
if (!GeneratePointerType(ptr, result)) {
|
||||
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)) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -3190,16 +3189,16 @@ bool Builder::GeneratePointerType(const sem::Pointer* ptr,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Builder::GenerateStructType(const sem::StructType* struct_type,
|
||||
bool Builder::GenerateStructType(const sem::Struct* struct_type,
|
||||
ast::AccessControl::Access access_control,
|
||||
const Operand& result) {
|
||||
auto struct_id = result.to_i();
|
||||
auto* impl = struct_type->impl();
|
||||
auto* impl = struct_type->Declaration();
|
||||
|
||||
if (struct_type->impl()->name().IsValid()) {
|
||||
push_debug(spv::Op::OpName, {Operand::Int(struct_id),
|
||||
Operand::String(builder_.Symbols().NameFor(
|
||||
struct_type->impl()->name()))});
|
||||
if (impl->name().IsValid()) {
|
||||
push_debug(spv::Op::OpName,
|
||||
{Operand::Int(struct_id),
|
||||
Operand::String(builder_.Symbols().NameFor(impl->name()))});
|
||||
}
|
||||
|
||||
OperandList ops;
|
||||
|
|
|
@ -449,7 +449,7 @@ class Builder {
|
|||
/// @param access_control the access controls to assign to the struct
|
||||
/// @param result the result operand
|
||||
/// @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,
|
||||
const Operand& result);
|
||||
/// Generates a struct member
|
||||
|
|
|
@ -219,10 +219,10 @@ TEST_F(BuilderTest, MemberAccessor) {
|
|||
// var ident : my_struct
|
||||
// ident.b
|
||||
|
||||
auto s = Structure("my_struct", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* s = Structure("my_struct", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
|
||||
auto* var = Global("ident", s, ast::StorageClass::kFunction);
|
||||
|
||||
|
@ -263,12 +263,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested) {
|
|||
//
|
||||
// var ident : my_struct
|
||||
// ident.inner.a
|
||||
auto inner_struct = Structure("Inner", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* inner_struct = Structure("Inner", {
|
||||
Member("a", 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* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
|
||||
|
@ -307,10 +307,10 @@ TEST_F(BuilderTest, MemberAccessor_NonPointer) {
|
|||
// let ident : my_struct = my_struct();
|
||||
// ident.b
|
||||
|
||||
auto s = Structure("my_struct", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* s = Structure("my_struct", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
|
||||
auto* var = GlobalConst("ident", s, Construct(s, 0.f, 0.f));
|
||||
|
||||
|
@ -345,12 +345,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested_NonPointer) {
|
|||
//
|
||||
// let ident : my_struct = my_struct();
|
||||
// ident.inner.a
|
||||
auto inner_struct = Structure("Inner", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* inner_struct = Structure("Inner", {
|
||||
Member("a", 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,
|
||||
Construct(s_type, Construct(inner_struct, 0.f, 0.f)));
|
||||
|
@ -388,13 +388,13 @@ TEST_F(BuilderTest, MemberAccessor_Nested_WithAlias) {
|
|||
//
|
||||
// var ident : my_struct
|
||||
// ident.inner.a
|
||||
auto inner_struct = Structure("Inner", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* inner_struct = Structure("Inner", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
|
||||
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* expr = MemberAccessor(MemberAccessor("ident", "inner"), "a");
|
||||
|
@ -434,12 +434,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_LHS) {
|
|||
//
|
||||
// var ident : my_struct
|
||||
// ident.inner.a = 2.0f;
|
||||
auto inner_struct = Structure("Inner", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* inner_struct = Structure("Inner", {
|
||||
Member("a", 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* expr =
|
||||
|
@ -483,12 +483,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_RHS) {
|
|||
// var ident : my_struct
|
||||
// var store : f32 = ident.inner.a
|
||||
|
||||
auto inner_struct = Structure("Inner", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* inner_struct = Structure("Inner", {
|
||||
Member("a", 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* store = Global("store", ty.f32(), ast::StorageClass::kFunction);
|
||||
|
@ -693,11 +693,11 @@ TEST_F(BuilderTest, Accessor_Mixed_ArrayAndMember) {
|
|||
// var index : array<A, 2>
|
||||
// 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 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* var = Global("index", a_ary_type, ast::StorageClass::kFunction);
|
||||
|
|
|
@ -176,10 +176,10 @@ TEST_F(BuilderTest, Assign_StructMember) {
|
|||
// var ident : my_struct
|
||||
// ident.b = 4.0;
|
||||
|
||||
auto s = Structure("my_struct", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* s = Structure("my_struct", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
|
||||
auto* v = Global("ident", s, ast::StorageClass::kFunction);
|
||||
|
||||
|
|
|
@ -1052,10 +1052,10 @@ TEST_F(SpvBuilderConstructorTest, CommonInitializer_Array_VecArray) {
|
|||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, Type_Struct) {
|
||||
auto s = Structure("my_struct", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
auto* s = Structure("my_struct", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
|
||||
auto* t = Construct(s, 2.0f, vec3<f32>(2.0f, 2.0f, 2.0f));
|
||||
WrapInFunction(t);
|
||||
|
@ -1202,7 +1202,7 @@ TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Array) {
|
|||
}
|
||||
|
||||
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);
|
||||
WrapInFunction(t);
|
||||
|
||||
|
@ -1622,10 +1622,10 @@ TEST_F(SpvBuilderConstructorTest, IsConstructorConst_BitCastScalars) {
|
|||
}
|
||||
|
||||
TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct) {
|
||||
auto s = Structure("my_struct", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
auto* s = Structure("my_struct", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
|
||||
auto* t = Construct(s, 2.f, vec3<f32>(2.f, 2.f, 2.f));
|
||||
WrapInFunction(t);
|
||||
|
@ -1638,10 +1638,10 @@ TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct) {
|
|||
|
||||
TEST_F(SpvBuilderConstructorTest,
|
||||
IsConstructorConst_Struct_WithIdentSubExpression) {
|
||||
auto s = Structure("my_struct", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
auto* s = Structure("my_struct", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.vec3<f32>()),
|
||||
});
|
||||
|
||||
Global("a", ty.f32(), ast::StorageClass::kPrivate);
|
||||
Global("b", ty.f32(), ast::StorageClass::kPrivate);
|
||||
|
|
|
@ -188,7 +188,7 @@ TEST_F(BuilderTest, EntryPoint_SharedStruct) {
|
|||
// return inputs.value;
|
||||
// }
|
||||
|
||||
auto interface = Structure(
|
||||
auto* interface = Structure(
|
||||
"Interface",
|
||||
{
|
||||
Member("value", ty.f32(), ast::DecorationList{Location(1u)}),
|
||||
|
|
|
@ -201,8 +201,8 @@ TEST_F(BuilderTest, Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
|
|||
// return;
|
||||
// }
|
||||
|
||||
auto s = Structure("Data", {Member("d", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Data", {Member("d", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
|
|
|
@ -376,12 +376,12 @@ TEST_F(BuilderTest, GlobalVar_DeclReadOnly) {
|
|||
// };
|
||||
// var b : [[access(read)]] A
|
||||
|
||||
auto A = Structure("A",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.i32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* A = Structure("A",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.i32()),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, A);
|
||||
|
||||
auto* var = Global("b", ac, ast::StorageClass::kStorage);
|
||||
|
@ -415,8 +415,8 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasDeclReadOnly) {
|
|||
// type B = A;
|
||||
// var b : [[access(read)]] B
|
||||
|
||||
auto A = Structure("A", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* A = Structure("A", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto B = ty.alias("B", A);
|
||||
AST().AddConstructedType(B);
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, B);
|
||||
|
@ -448,8 +448,8 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasAssignReadOnly) {
|
|||
// type B = [[access(read)]] A;
|
||||
// var b : B
|
||||
|
||||
auto A = Structure("A", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* A = Structure("A", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, A);
|
||||
auto B = ty.alias("B", ac);
|
||||
AST().AddConstructedType(B);
|
||||
|
@ -481,8 +481,8 @@ TEST_F(BuilderTest, GlobalVar_TwoVarDeclReadOnly) {
|
|||
// var b : [[access(read)]] A
|
||||
// var c : [[access(read_write)]] A
|
||||
|
||||
auto A = Structure("A", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* A = Structure("A", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto read = ty.access(ast::AccessControl::kReadOnly, A);
|
||||
auto rw = ty.access(ast::AccessControl::kReadWrite, A);
|
||||
|
||||
|
|
|
@ -1379,8 +1379,8 @@ OpFunctionEnd
|
|||
}
|
||||
|
||||
TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
|
||||
auto s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global("b", ac, ast::StorageClass::kStorage, nullptr,
|
||||
ast::DecorationList{
|
||||
|
@ -1425,12 +1425,12 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
|
|||
}
|
||||
|
||||
TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
|
||||
auto s = Structure("my_struct",
|
||||
{
|
||||
Member(0, "z", ty.f32()),
|
||||
Member(4, "a", ty.array<f32>(4)),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("my_struct",
|
||||
{
|
||||
Member(0, "z", ty.f32()),
|
||||
Member(4, "a", ty.array<f32>(4)),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
Global("b", ac, ast::StorageClass::kStorage, nullptr,
|
||||
ast::DecorationList{
|
||||
|
|
|
@ -59,8 +59,8 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedAlias) {
|
|||
|
||||
TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
|
||||
auto ary = ty.array(ty.i32(), 0);
|
||||
auto str = Structure("S", {Member("x", ary)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* str = Structure("S", {Member("x", ary)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, str);
|
||||
Global("a", ac, ast::StorageClass::kStorage);
|
||||
|
||||
|
@ -77,8 +77,8 @@ TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
|
|||
|
||||
TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) {
|
||||
auto ary = ty.array(ty.i32(), 0);
|
||||
auto str = Structure("S", {Member("x", ary)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* str = Structure("S", {Member("x", ary)},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto ac = ty.access(ast::AccessControl::kReadOnly, str);
|
||||
Global("a", ac, ast::StorageClass::kStorage);
|
||||
|
||||
|
@ -285,11 +285,11 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedPtr) {
|
|||
}
|
||||
|
||||
TEST_F(BuilderTest_Type, GenerateStruct_Empty) {
|
||||
auto s = Structure("S", {});
|
||||
auto* s = Structure("S", {});
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
auto id = b.GenerateTypeIfNeeded(s);
|
||||
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||
ASSERT_FALSE(b.has_error()) << b.error();
|
||||
EXPECT_EQ(id, 1u);
|
||||
|
||||
|
@ -301,11 +301,11 @@ TEST_F(BuilderTest_Type, GenerateStruct_Empty) {
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
auto id = b.GenerateTypeIfNeeded(s);
|
||||
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||
ASSERT_FALSE(b.has_error()) << b.error();
|
||||
EXPECT_EQ(id, 1u);
|
||||
|
||||
|
@ -318,12 +318,12 @@ OpMemberName %1 0 "a"
|
|||
}
|
||||
|
||||
TEST_F(BuilderTest_Type, GenerateStruct_Decorated) {
|
||||
auto s = Structure("my_struct", {Member("a", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("my_struct", {Member("a", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
auto id = b.GenerateTypeIfNeeded(s);
|
||||
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||
ASSERT_FALSE(b.has_error()) << b.error();
|
||||
EXPECT_EQ(id, 1u);
|
||||
|
||||
|
@ -339,14 +339,14 @@ OpMemberDecorate %1 0 Offset 0
|
|||
}
|
||||
|
||||
TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32(), {MemberAlign(8)}),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.f32(), {MemberAlign(8)}),
|
||||
});
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
auto id = b.GenerateTypeIfNeeded(s);
|
||||
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||
ASSERT_FALSE(b.has_error()) << b.error();
|
||||
EXPECT_EQ(id, 1u);
|
||||
|
||||
|
@ -363,15 +363,15 @@ OpMemberDecorate %1 1 Offset 8
|
|||
}
|
||||
|
||||
TEST_F(BuilderTest_Type, GenerateStruct_NonLayout_Matrix) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.mat2x2<f32>()),
|
||||
Member("b", ty.mat2x3<f32>()),
|
||||
Member("c", ty.mat4x4<f32>()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.mat2x2<f32>()),
|
||||
Member("b", ty.mat2x3<f32>()),
|
||||
Member("c", ty.mat4x4<f32>()),
|
||||
});
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
auto id = b.GenerateTypeIfNeeded(s);
|
||||
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||
ASSERT_FALSE(b.has_error()) << b.error();
|
||||
EXPECT_EQ(id, 1u);
|
||||
|
||||
|
@ -403,15 +403,15 @@ OpMemberDecorate %1 2 MatrixStride 16
|
|||
|
||||
TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutMatrix) {
|
||||
// We have to infer layout for matrix when it also has an offset.
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.mat2x2<f32>()),
|
||||
Member("b", ty.mat2x3<f32>()),
|
||||
Member("c", ty.mat4x4<f32>()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.mat2x2<f32>()),
|
||||
Member("b", ty.mat2x3<f32>()),
|
||||
Member("c", ty.mat4x4<f32>()),
|
||||
});
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
auto id = b.GenerateTypeIfNeeded(s);
|
||||
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||
ASSERT_FALSE(b.has_error()) << b.error();
|
||||
EXPECT_EQ(id, 1u);
|
||||
|
||||
|
@ -449,17 +449,18 @@ TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutArraysOfMatrix) {
|
|||
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 s = Structure("S",
|
||||
{
|
||||
Member("a", arr_mat2x2),
|
||||
Member("b", arr_arr_mat2x3),
|
||||
Member("c", rtarr_mat4x4),
|
||||
},
|
||||
ast::DecorationList{create<ast::StructBlockDecoration>()});
|
||||
auto* s =
|
||||
Structure("S",
|
||||
{
|
||||
Member("a", arr_mat2x2),
|
||||
Member("b", arr_arr_mat2x3),
|
||||
Member("c", rtarr_mat4x4),
|
||||
},
|
||||
ast::DecorationList{create<ast::StructBlockDecoration>()});
|
||||
|
||||
spirv::Builder& b = Build();
|
||||
|
||||
auto id = b.GenerateTypeIfNeeded(s);
|
||||
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||
ASSERT_FALSE(b.has_error()) << b.error();
|
||||
EXPECT_EQ(id, 1u);
|
||||
|
||||
|
|
|
@ -147,8 +147,8 @@ bool GeneratorImpl::EmitConstructedType(typ::Type type) {
|
|||
return false;
|
||||
}
|
||||
out_ << ";" << std::endl;
|
||||
} else if (auto* str = ty->As<sem::StructType>()) {
|
||||
if (!EmitStructType(str->impl())) {
|
||||
} else if (auto* str = ty->As<sem::Struct>()) {
|
||||
if (!EmitStructType(str->Declaration())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -599,10 +599,10 @@ bool GeneratorImpl::EmitType(typ::Type type) {
|
|||
if (sampler->IsComparison()) {
|
||||
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 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>()) {
|
||||
out_ << "texture_";
|
||||
if (texture->Is<sem::DepthTexture>()) {
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "src/ast/unary_op_expression.h"
|
||||
#include "src/program.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"
|
||||
|
||||
namespace tint {
|
||||
|
|
|
@ -31,10 +31,10 @@ TEST_F(WgslGeneratorImplTest, EmitAlias_F32) {
|
|||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitConstructedType_Struct) {
|
||||
auto s = Structure("A", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.i32()),
|
||||
});
|
||||
auto* s = Structure("A", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.i32()),
|
||||
});
|
||||
|
||||
auto alias = ty.alias("B", s);
|
||||
|
||||
|
@ -51,10 +51,10 @@ type B = A;
|
|||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitAlias_ToStruct) {
|
||||
auto s = Structure("A", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.i32()),
|
||||
});
|
||||
auto* s = Structure("A", {
|
||||
Member("a", ty.f32()),
|
||||
Member("b", ty.i32()),
|
||||
});
|
||||
|
||||
auto alias = ty.alias("B", s);
|
||||
|
||||
|
|
|
@ -202,8 +202,8 @@ TEST_F(WgslGeneratorImplTest,
|
|||
// return;
|
||||
// }
|
||||
|
||||
auto s = Structure("Data", {Member("d", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("Data", {Member("d", ty.f32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ TEST_F(WgslGeneratorImplTest, Emit_GlobalDeclAfterFunction) {
|
|||
TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
|
||||
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(),
|
||||
ast::StatementList{
|
||||
|
@ -58,7 +58,7 @@ TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
|
|||
|
||||
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_(),
|
||||
ast::StatementList{
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace {
|
|||
using WgslGeneratorImplTest = TestHelper;
|
||||
|
||||
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);
|
||||
|
||||
auto* expr = MemberAccessor("str", "mem");
|
||||
|
|
|
@ -47,8 +47,8 @@ TEST_F(WgslGeneratorImplTest, EmitType_Array) {
|
|||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_Read) {
|
||||
auto s = Structure("S", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||
AST().AddConstructedType(ty.alias("make_type_reachable", a));
|
||||
|
@ -60,8 +60,8 @@ TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_Read) {
|
|||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_ReadWrite) {
|
||||
auto s = Structure("S", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S", {Member("a", ty.i32())},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
auto a = ty.access(ast::AccessControl::kReadWrite, s);
|
||||
AST().AddConstructedType(ty.alias("make_type_reachable", a));
|
||||
|
@ -143,10 +143,10 @@ TEST_F(WgslGeneratorImplTest, EmitType_Pointer) {
|
|||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_Struct) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32()),
|
||||
});
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
|
@ -155,10 +155,10 @@ TEST_F(WgslGeneratorImplTest, EmitType_Struct) {
|
|||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.i32(), {MemberOffset(8)}),
|
||||
Member("b", ty.f32(), {MemberOffset(16)}),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.i32(), {MemberOffset(8)}),
|
||||
Member("b", ty.f32(), {MemberOffset(16)}),
|
||||
});
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
|
@ -175,7 +175,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl) {
|
|||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) {
|
||||
auto s =
|
||||
auto* s =
|
||||
Structure("S", {
|
||||
Member("tint_0_padding", ty.i32(), {MemberOffset(8)}),
|
||||
Member("tint_2_padding", ty.f32(), {MemberOffset(16)}),
|
||||
|
@ -196,10 +196,10 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) {
|
|||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.i32(), {MemberAlign(8)}),
|
||||
Member("b", ty.f32(), {MemberAlign(16)}),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.i32(), {MemberAlign(8)}),
|
||||
Member("b", ty.f32(), {MemberAlign(16)}),
|
||||
});
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
|
@ -214,10 +214,10 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) {
|
|||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) {
|
||||
auto s = Structure("S", {
|
||||
Member("a", ty.i32(), {MemberSize(16)}),
|
||||
Member("b", ty.f32(), {MemberSize(32)}),
|
||||
});
|
||||
auto* s = Structure("S", {
|
||||
Member("a", ty.i32(), {MemberSize(16)}),
|
||||
Member("b", ty.f32(), {MemberSize(32)}),
|
||||
});
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
|
@ -232,12 +232,12 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) {
|
|||
}
|
||||
|
||||
TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithDecoration) {
|
||||
auto s = Structure("S",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32(), {MemberAlign(8)}),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* s = Structure("S",
|
||||
{
|
||||
Member("a", ty.i32()),
|
||||
Member("b", ty.f32(), {MemberAlign(8)}),
|
||||
},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
|
||||
GeneratorImpl& gen = Build();
|
||||
|
||||
|
@ -255,7 +255,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithEntryPointDecorations) {
|
|||
ast::DecorationList decos;
|
||||
decos.push_back(create<ast::StructBlockDecoration>());
|
||||
|
||||
auto s = Structure(
|
||||
auto* s = Structure(
|
||||
"S",
|
||||
ast::StructMemberList{
|
||||
Member("a", ty.u32(), {Builtin(ast::Builtin::kVertexIndex)}),
|
||||
|
|
|
@ -281,8 +281,8 @@ tint_unittests_source_set("tint_unittests_core_src") {
|
|||
"../src/sem/pointer_type_test.cc",
|
||||
"../src/sem/sampled_texture_type_test.cc",
|
||||
"../src/sem/sampler_type_test.cc",
|
||||
"../src/sem/sem_struct_test.cc",
|
||||
"../src/sem/storage_texture_type_test.cc",
|
||||
"../src/sem/struct_type_test.cc",
|
||||
"../src/sem/texture_type_test.cc",
|
||||
"../src/sem/type_manager_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") {
|
||||
sources = [
|
||||
"../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_assign_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") {
|
||||
sources = [
|
||||
"../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_assign_test.cc",
|
||||
"../src/writer/hlsl/generator_impl_binary_test.cc",
|
||||
|
|
Loading…
Reference in New Issue