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/sampler_type.h",
|
||||||
"sem/storage_texture_type.cc",
|
"sem/storage_texture_type.cc",
|
||||||
"sem/storage_texture_type.h",
|
"sem/storage_texture_type.h",
|
||||||
"sem/struct_type.cc",
|
|
||||||
"sem/struct_type.h",
|
|
||||||
"sem/texture_type.cc",
|
"sem/texture_type.cc",
|
||||||
"sem/texture_type.h",
|
"sem/texture_type.h",
|
||||||
"sem/type.cc",
|
"sem/type.cc",
|
||||||
|
|
|
@ -313,8 +313,6 @@ set(TINT_LIB_SRCS
|
||||||
sem/sampler_type.h
|
sem/sampler_type.h
|
||||||
sem/storage_texture_type.cc
|
sem/storage_texture_type.cc
|
||||||
sem/storage_texture_type.h
|
sem/storage_texture_type.h
|
||||||
sem/struct_type.cc
|
|
||||||
sem/struct_type.h
|
|
||||||
sem/texture_type.cc
|
sem/texture_type.cc
|
||||||
sem/texture_type.h
|
sem/texture_type.h
|
||||||
sem/type.cc
|
sem/type.cc
|
||||||
|
@ -581,8 +579,8 @@ if(${TINT_BUILD_TESTS})
|
||||||
sem/pointer_type_test.cc
|
sem/pointer_type_test.cc
|
||||||
sem/sampled_texture_type_test.cc
|
sem/sampled_texture_type_test.cc
|
||||||
sem/sampler_type_test.cc
|
sem/sampler_type_test.cc
|
||||||
|
sem/sem_struct_test.cc
|
||||||
sem/storage_texture_type_test.cc
|
sem/storage_texture_type_test.cc
|
||||||
sem/struct_type_test.cc
|
|
||||||
sem/texture_type_test.cc
|
sem/texture_type_test.cc
|
||||||
sem/type_manager_test.cc
|
sem/type_manager_test.cc
|
||||||
sem/u32_type_test.cc
|
sem/u32_type_test.cc
|
||||||
|
@ -809,7 +807,6 @@ if(${TINT_BUILD_TESTS})
|
||||||
|
|
||||||
if(${TINT_BUILD_MSL_WRITER})
|
if(${TINT_BUILD_MSL_WRITER})
|
||||||
list(APPEND TINT_TEST_SRCS
|
list(APPEND TINT_TEST_SRCS
|
||||||
writer/msl/generator_impl_alias_type_test.cc
|
|
||||||
writer/msl/generator_impl_array_accessor_test.cc
|
writer/msl/generator_impl_array_accessor_test.cc
|
||||||
writer/msl/generator_impl_assign_test.cc
|
writer/msl/generator_impl_assign_test.cc
|
||||||
writer/msl/generator_impl_binary_test.cc
|
writer/msl/generator_impl_binary_test.cc
|
||||||
|
@ -846,7 +843,6 @@ if(${TINT_BUILD_TESTS})
|
||||||
if (${TINT_BUILD_HLSL_WRITER})
|
if (${TINT_BUILD_HLSL_WRITER})
|
||||||
list(APPEND TINT_TEST_SRCS
|
list(APPEND TINT_TEST_SRCS
|
||||||
transform/hlsl_test.cc
|
transform/hlsl_test.cc
|
||||||
writer/hlsl/generator_impl_alias_type_test.cc
|
|
||||||
writer/hlsl/generator_impl_array_accessor_test.cc
|
writer/hlsl/generator_impl_array_accessor_test.cc
|
||||||
writer/hlsl/generator_impl_assign_test.cc
|
writer/hlsl/generator_impl_assign_test.cc
|
||||||
writer/hlsl/generator_impl_binary_test.cc
|
writer/hlsl/generator_impl_binary_test.cc
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#include "src/sem/sampled_texture_type.h"
|
#include "src/sem/sampled_texture_type.h"
|
||||||
#include "src/sem/storage_texture_type.h"
|
#include "src/sem/storage_texture_type.h"
|
||||||
#include "src/sem/struct.h"
|
#include "src/sem/struct.h"
|
||||||
#include "src/sem/struct_type.h"
|
|
||||||
#include "src/sem/u32_type.h"
|
#include "src/sem/u32_type.h"
|
||||||
#include "src/sem/variable.h"
|
#include "src/sem/variable.h"
|
||||||
#include "src/sem/vector_type.h"
|
#include "src/sem/vector_type.h"
|
||||||
|
@ -389,7 +388,7 @@ std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
|
||||||
auto binding_info = ruv.second;
|
auto binding_info = ruv.second;
|
||||||
|
|
||||||
auto* unwrapped_type = var->Type()->UnwrapIfNeeded();
|
auto* unwrapped_type = var->Type()->UnwrapIfNeeded();
|
||||||
auto* str = unwrapped_type->As<sem::StructType>();
|
auto* str = unwrapped_type->As<sem::Struct>();
|
||||||
if (str == nullptr) {
|
if (str == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -398,19 +397,12 @@ std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* sem = program_->Sem().Get(str);
|
|
||||||
if (!sem) {
|
|
||||||
error_ = "Missing semantic information for structure " +
|
|
||||||
program_->Symbols().NameFor(str->impl()->name());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceBinding entry;
|
ResourceBinding entry;
|
||||||
entry.resource_type = ResourceBinding::ResourceType::kUniformBuffer;
|
entry.resource_type = ResourceBinding::ResourceType::kUniformBuffer;
|
||||||
entry.bind_group = binding_info.group->value();
|
entry.bind_group = binding_info.group->value();
|
||||||
entry.binding = binding_info.binding->value();
|
entry.binding = binding_info.binding->value();
|
||||||
entry.size = sem->Size();
|
entry.size = str->Size();
|
||||||
entry.size_no_padding = sem->SizeNoPadding();
|
entry.size_no_padding = str->SizeNoPadding();
|
||||||
|
|
||||||
result.push_back(entry);
|
result.push_back(entry);
|
||||||
}
|
}
|
||||||
|
@ -554,10 +546,9 @@ void Inspector::AddEntryPointInOutVariables(
|
||||||
|
|
||||||
auto* unwrapped_type = type->UnwrapAll();
|
auto* unwrapped_type = type->UnwrapAll();
|
||||||
|
|
||||||
if (auto* struct_ty = unwrapped_type->As<sem::StructType>()) {
|
if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {
|
||||||
// Recurse into members.
|
// Recurse into members.
|
||||||
auto* sem = program_->Sem().Get(struct_ty);
|
for (auto* member : struct_ty->Members()) {
|
||||||
for (auto* member : sem->Members()) {
|
|
||||||
AddEntryPointInOutVariables(
|
AddEntryPointInOutVariables(
|
||||||
name + "." +
|
name + "." +
|
||||||
program_->Symbols().NameFor(member->Declaration()->symbol()),
|
program_->Symbols().NameFor(member->Declaration()->symbol()),
|
||||||
|
@ -611,26 +602,19 @@ std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindingsImpl(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* str = var->Type()->UnwrapIfNeeded()->As<sem::StructType>();
|
auto* str = var->Type()->UnwrapIfNeeded()->As<sem::Struct>();
|
||||||
if (!str) {
|
if (!str) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* sem = program_->Sem().Get(str);
|
|
||||||
if (!sem) {
|
|
||||||
error_ = "Missing semantic information for structure " +
|
|
||||||
program_->Symbols().NameFor(str->impl()->name());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceBinding entry;
|
ResourceBinding entry;
|
||||||
entry.resource_type =
|
entry.resource_type =
|
||||||
read_only ? ResourceBinding::ResourceType::kReadOnlyStorageBuffer
|
read_only ? ResourceBinding::ResourceType::kReadOnlyStorageBuffer
|
||||||
: ResourceBinding::ResourceType::kStorageBuffer;
|
: ResourceBinding::ResourceType::kStorageBuffer;
|
||||||
entry.bind_group = binding_info.group->value();
|
entry.bind_group = binding_info.group->value();
|
||||||
entry.binding = binding_info.binding->value();
|
entry.binding = binding_info.binding->value();
|
||||||
entry.size = sem->Size();
|
entry.size = str->Size();
|
||||||
entry.size_no_padding = sem->SizeNoPadding();
|
entry.size_no_padding = str->SizeNoPadding();
|
||||||
|
|
||||||
result.push_back(entry);
|
result.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ void ProgramBuilder::MarkAsMoved() {
|
||||||
|
|
||||||
void ProgramBuilder::AssertNotMoved() const {
|
void ProgramBuilder::AssertNotMoved() const {
|
||||||
if (moved_) {
|
if (moved_) {
|
||||||
TINT_ICE(const_cast<ProgramBuilder*>(this)->Diagnostics())
|
TINT_ICE(const_cast<ProgramBuilder*>(this)->diagnostics_)
|
||||||
<< "Attempting to use ProgramBuilder after it has been moved";
|
<< "Attempting to use ProgramBuilder after it has been moved";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
#include "src/sem/pointer_type.h"
|
#include "src/sem/pointer_type.h"
|
||||||
#include "src/sem/sampled_texture_type.h"
|
#include "src/sem/sampled_texture_type.h"
|
||||||
#include "src/sem/storage_texture_type.h"
|
#include "src/sem/storage_texture_type.h"
|
||||||
#include "src/sem/struct_type.h"
|
#include "src/sem/struct.h"
|
||||||
#include "src/sem/u32_type.h"
|
#include "src/sem/u32_type.h"
|
||||||
#include "src/sem/vector_type.h"
|
#include "src/sem/vector_type.h"
|
||||||
#include "src/sem/void_type.h"
|
#include "src/sem/void_type.h"
|
||||||
|
@ -772,12 +772,6 @@ class ProgramBuilder {
|
||||||
return pointer(Of<T>(), storage_class);
|
return pointer(Of<T>(), storage_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param impl the struct implementation
|
|
||||||
/// @returns a struct pointer
|
|
||||||
typ::Struct struct_(ast::Struct* impl) const {
|
|
||||||
return {impl, builder->create<sem::StructType>(impl)};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @param kind the kind of sampler
|
/// @param kind the kind of sampler
|
||||||
/// @returns the sampler
|
/// @returns the sampler
|
||||||
typ::Sampler sampler(ast::SamplerKind kind) const {
|
typ::Sampler sampler(ast::SamplerKind kind) const {
|
||||||
|
@ -1544,40 +1538,36 @@ class ProgramBuilder {
|
||||||
return create<ast::ReturnStatement>(Expr(std::forward<EXPR>(val)));
|
return create<ast::ReturnStatement>(Expr(std::forward<EXPR>(val)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a ast::Struct and sem::StructType, registering the
|
/// Creates a ast::Struct registering it with the AST().ConstructedTypes().
|
||||||
/// sem::StructType with the AST().ConstructedTypes().
|
|
||||||
/// @param source the source information
|
/// @param source the source information
|
||||||
/// @param name the struct name
|
/// @param name the struct name
|
||||||
/// @param members the struct members
|
/// @param members the struct members
|
||||||
/// @param decorations the optional struct decorations
|
/// @param decorations the optional struct decorations
|
||||||
/// @returns the struct type
|
/// @returns the struct type
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
typ::Struct Structure(const Source& source,
|
ast::Struct* Structure(const Source& source,
|
||||||
NAME&& name,
|
NAME&& name,
|
||||||
ast::StructMemberList members,
|
ast::StructMemberList members,
|
||||||
ast::DecorationList decorations = {}) {
|
ast::DecorationList decorations = {}) {
|
||||||
auto sym = Sym(std::forward<NAME>(name));
|
auto sym = Sym(std::forward<NAME>(name));
|
||||||
auto* impl = create<ast::Struct>(source, sym, std::move(members),
|
auto* type = create<ast::Struct>(source, sym, std::move(members),
|
||||||
std::move(decorations));
|
std::move(decorations));
|
||||||
auto type = ty.struct_(impl);
|
|
||||||
AST().AddConstructedType(type);
|
AST().AddConstructedType(type);
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a ast::Struct and sem::StructType, registering the
|
/// Creates a ast::Struct registering it with the AST().ConstructedTypes().
|
||||||
/// sem::StructType with the AST().ConstructedTypes().
|
|
||||||
/// @param name the struct name
|
/// @param name the struct name
|
||||||
/// @param members the struct members
|
/// @param members the struct members
|
||||||
/// @param decorations the optional struct decorations
|
/// @param decorations the optional struct decorations
|
||||||
/// @returns the struct type
|
/// @returns the struct type
|
||||||
template <typename NAME>
|
template <typename NAME>
|
||||||
typ::Struct Structure(NAME&& name,
|
ast::Struct* Structure(NAME&& name,
|
||||||
ast::StructMemberList members,
|
ast::StructMemberList members,
|
||||||
ast::DecorationList decorations = {}) {
|
ast::DecorationList decorations = {}) {
|
||||||
auto sym = Sym(std::forward<NAME>(name));
|
auto sym = Sym(std::forward<NAME>(name));
|
||||||
auto* impl =
|
auto* type =
|
||||||
create<ast::Struct>(sym, std::move(members), std::move(decorations));
|
create<ast::Struct>(sym, std::move(members), std::move(decorations));
|
||||||
auto type = ty.struct_(impl);
|
|
||||||
AST().AddConstructedType(type);
|
AST().AddConstructedType(type);
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -414,14 +414,14 @@ class ParserImpl : Reader {
|
||||||
const spvtools::opt::Instruction& inst,
|
const spvtools::opt::Instruction& inst,
|
||||||
ast::Type* first_operand_type);
|
ast::Type* first_operand_type);
|
||||||
|
|
||||||
/// Returns the given expression, but ensuring it's an unsigned type of the
|
/// @returns the given expression, but ensuring it's an unsigned type of the
|
||||||
/// same shape as the operand. Wraps the expresison with a bitcast if needed.
|
/// same shape as the operand. Wraps the expresion with a bitcast if needed.
|
||||||
/// Assumes the given expresion is a integer scalar or vector.
|
/// Assumes the given expresion is a integer scalar or vector.
|
||||||
/// @param expr an integer scalar or integer vector expression.
|
/// @param expr an integer scalar or integer vector expression.
|
||||||
TypedExpression AsUnsigned(TypedExpression expr);
|
TypedExpression AsUnsigned(TypedExpression expr);
|
||||||
|
|
||||||
/// Returns the given expression, but ensuring it's a signed type of the
|
/// @returns the given expression, but ensuring it's a signed type of the
|
||||||
/// same shape as the operand. Wraps the expresison with a bitcast if needed.
|
/// same shape as the operand. Wraps the expresion with a bitcast if needed.
|
||||||
/// Assumes the given expresion is a integer scalar or vector.
|
/// Assumes the given expresion is a integer scalar or vector.
|
||||||
/// @param expr an integer scalar or integer vector expression.
|
/// @param expr an integer scalar or integer vector expression.
|
||||||
TypedExpression AsSigned(TypedExpression expr);
|
TypedExpression AsSigned(TypedExpression expr);
|
||||||
|
|
|
@ -37,7 +37,7 @@ TEST_F(ParserImplTest, TypeDecl_ParsesType) {
|
||||||
TEST_F(ParserImplTest, TypeDecl_ParsesStruct_Ident) {
|
TEST_F(ParserImplTest, TypeDecl_ParsesStruct_Ident) {
|
||||||
auto p = parser("type a = B");
|
auto p = parser("type a = B");
|
||||||
|
|
||||||
auto str = p->builder().Structure(p->builder().Symbols().Register("B"), {});
|
auto* str = p->builder().Structure(p->builder().Symbols().Register("B"), {});
|
||||||
p->register_constructed("B", str);
|
p->register_constructed("B", str);
|
||||||
|
|
||||||
auto t = p->type_alias();
|
auto t = p->type_alias();
|
||||||
|
|
|
@ -113,7 +113,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_ParsesWithAccessDeco_Read) {
|
||||||
ast::DecorationList decos;
|
ast::DecorationList decos;
|
||||||
decos.push_back(block_deco);
|
decos.push_back(block_deco);
|
||||||
|
|
||||||
auto s = Structure(Sym("S"), members, decos);
|
auto* s = Structure(Sym("S"), members, decos);
|
||||||
|
|
||||||
p->register_constructed("S", s);
|
p->register_constructed("S", s);
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_ParsesWithAccessDeco_ReadWrite) {
|
||||||
ast::DecorationList decos;
|
ast::DecorationList decos;
|
||||||
decos.push_back(block_deco);
|
decos.push_back(block_deco);
|
||||||
|
|
||||||
auto s = Structure(Sym("S"), members, decos);
|
auto* s = Structure(Sym("S"), members, decos);
|
||||||
|
|
||||||
p->register_constructed("S", s);
|
p->register_constructed("S", s);
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_MultipleAccessDecoFail) {
|
||||||
ast::DecorationList decos;
|
ast::DecorationList decos;
|
||||||
decos.push_back(block_deco);
|
decos.push_back(block_deco);
|
||||||
|
|
||||||
auto s = Structure(Sym("S"), members, decos);
|
auto* s = Structure(Sym("S"), members, decos);
|
||||||
|
|
||||||
p->register_constructed("S", s);
|
p->register_constructed("S", s);
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_MultipleAccessDeco_MultiBlock_Fail) {
|
||||||
ast::DecorationList decos;
|
ast::DecorationList decos;
|
||||||
decos.push_back(block_deco);
|
decos.push_back(block_deco);
|
||||||
|
|
||||||
auto s = Structure(Sym("S"), members, decos);
|
auto* s = Structure(Sym("S"), members, decos);
|
||||||
|
|
||||||
p->register_constructed("S", s);
|
p->register_constructed("S", s);
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ TEST_F(ParserImplTest, VariableIdentDecl_NonAccessDecoFail) {
|
||||||
ast::DecorationList decos;
|
ast::DecorationList decos;
|
||||||
decos.push_back(block_deco);
|
decos.push_back(block_deco);
|
||||||
|
|
||||||
auto s = Structure(Sym("S"), members, decos);
|
auto* s = Structure(Sym("S"), members, decos);
|
||||||
|
|
||||||
p->register_constructed("S", s);
|
p->register_constructed("S", s);
|
||||||
|
|
||||||
|
|
|
@ -466,7 +466,7 @@ namespace {
|
||||||
|
|
||||||
using StructBlockTest = ResolverTest;
|
using StructBlockTest = ResolverTest;
|
||||||
TEST_F(StructBlockTest, StructUsedAsArrayElement) {
|
TEST_F(StructBlockTest, StructUsedAsArrayElement) {
|
||||||
auto s = Structure("S", {Member("x", ty.i32())},
|
auto* s = Structure("S", {Member("x", ty.i32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto a = ty.array(s, 4);
|
auto a = ty.array(s, 4);
|
||||||
Global("G", a, ast::StorageClass::kPrivate);
|
Global("G", a, ast::StorageClass::kPrivate);
|
||||||
|
|
|
@ -85,7 +85,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Struct) {
|
||||||
// fn main() -> [[location(0)]] Output {
|
// fn main() -> [[location(0)]] Output {
|
||||||
// return Output();
|
// return Output();
|
||||||
// }
|
// }
|
||||||
auto output = Structure("Output", {});
|
auto* output = Structure("Output", {});
|
||||||
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
||||||
{Stage(ast::PipelineStage::kVertex)}, {Location(Source{{13, 43}}, 0)});
|
{Stage(ast::PipelineStage::kVertex)}, {Location(Source{{13, 43}}, 0)});
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_Valid) {
|
||||||
// fn main() -> Output {
|
// fn main() -> Output {
|
||||||
// return Output();
|
// return Output();
|
||||||
// }
|
// }
|
||||||
auto output = Structure(
|
auto* output = Structure(
|
||||||
"Output", {Member("a", ty.f32(), {Location(0)}),
|
"Output", {Member("a", ty.f32(), {Location(0)}),
|
||||||
Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
|
Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
|
||||||
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
||||||
|
@ -123,7 +123,7 @@ TEST_F(ResolverEntryPointValidationTest,
|
||||||
// fn main() -> Output {
|
// fn main() -> Output {
|
||||||
// return Output();
|
// return Output();
|
||||||
// }
|
// }
|
||||||
auto output = Structure(
|
auto* output = Structure(
|
||||||
"Output",
|
"Output",
|
||||||
{Member("a", ty.f32(),
|
{Member("a", ty.f32(),
|
||||||
{Location(Source{{13, 43}}, 0),
|
{Location(Source{{13, 43}}, 0),
|
||||||
|
@ -147,7 +147,7 @@ TEST_F(ResolverEntryPointValidationTest,
|
||||||
// fn main() -> Output {
|
// fn main() -> Output {
|
||||||
// return Output();
|
// return Output();
|
||||||
// }
|
// }
|
||||||
auto output = Structure(
|
auto* output = Structure(
|
||||||
"Output", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
|
"Output", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
|
||||||
Member(Source{{14, 52}}, "b", ty.f32(), {})});
|
Member(Source{{14, 52}}, "b", ty.f32(), {})});
|
||||||
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
||||||
|
@ -170,9 +170,9 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_NestedStruct) {
|
||||||
// fn main() -> Output {
|
// fn main() -> Output {
|
||||||
// return Output();
|
// return Output();
|
||||||
// }
|
// }
|
||||||
auto inner = Structure(
|
auto* inner = Structure(
|
||||||
"Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
|
"Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
|
||||||
auto output = Structure(
|
auto* output = Structure(
|
||||||
"Output", {Member(Source{{14, 52}}, "a", inner, {Location(0)})});
|
"Output", {Member(Source{{14, 52}}, "a", inner, {Location(0)})});
|
||||||
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
||||||
{Stage(ast::PipelineStage::kFragment)});
|
{Stage(ast::PipelineStage::kFragment)});
|
||||||
|
@ -193,7 +193,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_RuntimeArray) {
|
||||||
// fn main() -> Output {
|
// fn main() -> Output {
|
||||||
// return Output();
|
// return Output();
|
||||||
// }
|
// }
|
||||||
auto output = Structure(
|
auto* output = Structure(
|
||||||
"Output",
|
"Output",
|
||||||
{Member(Source{{13, 43}}, "a", ty.array<float>(), {Location(0)})},
|
{Member(Source{{13, 43}}, "a", ty.array<float>(), {Location(0)})},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
@ -216,7 +216,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateBuiltins) {
|
||||||
// fn main() -> Output {
|
// fn main() -> Output {
|
||||||
// return Output();
|
// return Output();
|
||||||
// }
|
// }
|
||||||
auto output = Structure(
|
auto* output = Structure(
|
||||||
"Output", {Member("a", ty.f32(), {Builtin(ast::Builtin::kFragDepth)}),
|
"Output", {Member("a", ty.f32(), {Builtin(ast::Builtin::kFragDepth)}),
|
||||||
Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
|
Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
|
||||||
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
||||||
|
@ -238,7 +238,7 @@ TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateLocation) {
|
||||||
// fn main() -> Output {
|
// fn main() -> Output {
|
||||||
// return Output();
|
// return Output();
|
||||||
// }
|
// }
|
||||||
auto output = Structure("Output", {Member("a", ty.f32(), {Location(1)}),
|
auto* output = Structure("Output", {Member("a", ty.f32(), {Location(1)}),
|
||||||
Member("b", ty.f32(), {Location(1)})});
|
Member("b", ty.f32(), {Location(1)})});
|
||||||
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
Func(Source{{12, 34}}, "main", {}, output, {Return(Construct(output))},
|
||||||
{Stage(ast::PipelineStage::kFragment)});
|
{Stage(ast::PipelineStage::kFragment)});
|
||||||
|
@ -302,7 +302,7 @@ TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Struct) {
|
||||||
// };
|
// };
|
||||||
// [[stage(fragment)]]
|
// [[stage(fragment)]]
|
||||||
// fn main([[location(0)]] param : Input) {}
|
// fn main([[location(0)]] param : Input) {}
|
||||||
auto input = Structure("Input", {});
|
auto* input = Structure("Input", {});
|
||||||
auto* param = Param("param", input, {Location(Source{{13, 43}}, 0)});
|
auto* param = Param("param", input, {Location(Source{{13, 43}}, 0)});
|
||||||
Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
|
Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
|
||||||
{Stage(ast::PipelineStage::kFragment)});
|
{Stage(ast::PipelineStage::kFragment)});
|
||||||
|
@ -321,7 +321,7 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_Valid) {
|
||||||
// };
|
// };
|
||||||
// [[stage(fragment)]]
|
// [[stage(fragment)]]
|
||||||
// fn main(param : Input) {}
|
// fn main(param : Input) {}
|
||||||
auto input = Structure(
|
auto* input = Structure(
|
||||||
"Input", {Member("a", ty.f32(), {Location(0)}),
|
"Input", {Member("a", ty.f32(), {Location(0)}),
|
||||||
Member("b", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
|
Member("b", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
|
||||||
auto* param = Param("param", input);
|
auto* param = Param("param", input);
|
||||||
|
@ -338,7 +338,7 @@ TEST_F(ResolverEntryPointValidationTest,
|
||||||
// };
|
// };
|
||||||
// [[stage(fragment)]]
|
// [[stage(fragment)]]
|
||||||
// fn main(param : Input) {}
|
// fn main(param : Input) {}
|
||||||
auto input = Structure(
|
auto* input = Structure(
|
||||||
"Input",
|
"Input",
|
||||||
{Member("a", ty.f32(),
|
{Member("a", ty.f32(),
|
||||||
{Location(Source{{13, 43}}, 0),
|
{Location(Source{{13, 43}}, 0),
|
||||||
|
@ -361,7 +361,7 @@ TEST_F(ResolverEntryPointValidationTest,
|
||||||
// };
|
// };
|
||||||
// [[stage(fragment)]]
|
// [[stage(fragment)]]
|
||||||
// fn main(param : Input) {}
|
// fn main(param : Input) {}
|
||||||
auto input = Structure(
|
auto* input = Structure(
|
||||||
"Input", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
|
"Input", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
|
||||||
Member(Source{{14, 52}}, "b", ty.f32(), {})});
|
Member(Source{{14, 52}}, "b", ty.f32(), {})});
|
||||||
auto* param = Param("param", input);
|
auto* param = Param("param", input);
|
||||||
|
@ -382,9 +382,9 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_NestedStruct) {
|
||||||
// };
|
// };
|
||||||
// [[stage(fragment)]]
|
// [[stage(fragment)]]
|
||||||
// fn main(param : Input) {}
|
// fn main(param : Input) {}
|
||||||
auto inner = Structure(
|
auto* inner = Structure(
|
||||||
"Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
|
"Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
|
||||||
auto input =
|
auto* input =
|
||||||
Structure("Input", {Member(Source{{14, 52}}, "a", inner, {Location(0)})});
|
Structure("Input", {Member(Source{{14, 52}}, "a", inner, {Location(0)})});
|
||||||
auto* param = Param("param", input);
|
auto* param = Param("param", input);
|
||||||
Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
|
Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
|
||||||
|
@ -404,7 +404,7 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_RuntimeArray) {
|
||||||
// };
|
// };
|
||||||
// [[stage(fragment)]]
|
// [[stage(fragment)]]
|
||||||
// fn main(param : Input) {}
|
// fn main(param : Input) {}
|
||||||
auto input = Structure(
|
auto* input = Structure(
|
||||||
"Input",
|
"Input",
|
||||||
{Member(Source{{13, 43}}, "a", ty.array<float>(), {Location(0)})},
|
{Member(Source{{13, 43}}, "a", ty.array<float>(), {Location(0)})},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
@ -446,9 +446,9 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateBuiltins) {
|
||||||
// };
|
// };
|
||||||
// [[stage(fragment)]]
|
// [[stage(fragment)]]
|
||||||
// fn main(param_a : InputA, param_b : InputB) {}
|
// fn main(param_a : InputA, param_b : InputB) {}
|
||||||
auto input_a = Structure(
|
auto* input_a = Structure(
|
||||||
"InputA", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
|
"InputA", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
|
||||||
auto input_b = Structure(
|
auto* input_b = Structure(
|
||||||
"InputB", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
|
"InputB", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
|
||||||
auto* param_a = Param("param_a", input_a);
|
auto* param_a = Param("param_a", input_a);
|
||||||
auto* param_b = Param("param_b", input_b);
|
auto* param_b = Param("param_b", input_b);
|
||||||
|
@ -486,8 +486,8 @@ TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateLocation) {
|
||||||
// };
|
// };
|
||||||
// [[stage(fragment)]]
|
// [[stage(fragment)]]
|
||||||
// fn main(param_a : InputA, param_b : InputB) {}
|
// fn main(param_a : InputA, param_b : InputB) {}
|
||||||
auto input_a = Structure("InputA", {Member("a", ty.f32(), {Location(1)})});
|
auto* input_a = Structure("InputA", {Member("a", ty.f32(), {Location(1)})});
|
||||||
auto input_b = Structure("InputB", {Member("a", ty.f32(), {Location(1)})});
|
auto* input_b = Structure("InputB", {Member("a", ty.f32(), {Location(1)})});
|
||||||
auto* param_a = Param("param_a", input_a);
|
auto* param_a = Param("param_a", input_a);
|
||||||
auto* param_b = Param("param_b", input_b);
|
auto* param_b = Param("param_b", input_b);
|
||||||
Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
|
Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace {
|
||||||
using ResolverHostShareableValidationTest = ResolverTest;
|
using ResolverHostShareableValidationTest = ResolverTest;
|
||||||
|
|
||||||
TEST_F(ResolverHostShareableValidationTest, BoolMember) {
|
TEST_F(ResolverHostShareableValidationTest, BoolMember) {
|
||||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.bool_())},
|
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.bool_())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
|
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
|
||||||
|
@ -42,7 +42,7 @@ TEST_F(ResolverHostShareableValidationTest, BoolMember) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
|
TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
|
||||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.vec3<bool>())},
|
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.vec3<bool>())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
|
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
|
||||||
|
@ -59,7 +59,7 @@ TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
|
||||||
TEST_F(ResolverHostShareableValidationTest, Aliases) {
|
TEST_F(ResolverHostShareableValidationTest, Aliases) {
|
||||||
auto a1 = ty.alias("a1", ty.bool_());
|
auto a1 = ty.alias("a1", ty.bool_());
|
||||||
AST().AddConstructedType(a1);
|
AST().AddConstructedType(a1);
|
||||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", a1)},
|
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", a1)},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
auto a2 = ty.alias("a2", ac);
|
auto a2 = ty.alias("a2", ac);
|
||||||
|
@ -76,11 +76,11 @@ TEST_F(ResolverHostShareableValidationTest, Aliases) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverHostShareableValidationTest, NestedStructures) {
|
TEST_F(ResolverHostShareableValidationTest, NestedStructures) {
|
||||||
auto i1 = Structure("I1", {Member(Source{{1, 2}}, "x", ty.bool_())});
|
auto* i1 = Structure("I1", {Member(Source{{1, 2}}, "x", ty.bool_())});
|
||||||
auto i2 = Structure("I2", {Member(Source{{3, 4}}, "y", i1)});
|
auto* i2 = Structure("I2", {Member(Source{{3, 4}}, "y", i1)});
|
||||||
auto i3 = Structure("I3", {Member(Source{{5, 6}}, "z", i2)});
|
auto* i3 = Structure("I3", {Member(Source{{5, 6}}, "z", i2)});
|
||||||
|
|
||||||
auto s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
|
auto* s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage);
|
Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage);
|
||||||
|
@ -98,7 +98,7 @@ TEST_F(ResolverHostShareableValidationTest, NestedStructures) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverHostShareableValidationTest, NoError) {
|
TEST_F(ResolverHostShareableValidationTest, NoError) {
|
||||||
auto i1 =
|
auto* i1 =
|
||||||
Structure("I1", {
|
Structure("I1", {
|
||||||
Member(Source{{1, 1}}, "x1", ty.f32()),
|
Member(Source{{1, 1}}, "x1", ty.f32()),
|
||||||
Member(Source{{2, 1}}, "y1", ty.vec3<f32>()),
|
Member(Source{{2, 1}}, "y1", ty.vec3<f32>()),
|
||||||
|
@ -106,20 +106,20 @@ TEST_F(ResolverHostShareableValidationTest, NoError) {
|
||||||
});
|
});
|
||||||
auto a1 = ty.alias("a1", i1);
|
auto a1 = ty.alias("a1", i1);
|
||||||
AST().AddConstructedType(a1);
|
AST().AddConstructedType(a1);
|
||||||
auto i2 = Structure("I2", {
|
auto* i2 = Structure("I2", {
|
||||||
Member(Source{{4, 1}}, "x2", ty.mat2x2<f32>()),
|
Member(Source{{4, 1}}, "x2", ty.mat2x2<f32>()),
|
||||||
Member(Source{{5, 1}}, "y2", i1),
|
Member(Source{{5, 1}}, "y2", i1),
|
||||||
Member(Source{{6, 1}}, "z2", ty.mat3x2<i32>()),
|
Member(Source{{6, 1}}, "z2", ty.mat3x2<i32>()),
|
||||||
});
|
});
|
||||||
auto a2 = ty.alias("a2", i2);
|
auto a2 = ty.alias("a2", i2);
|
||||||
AST().AddConstructedType(a2);
|
AST().AddConstructedType(a2);
|
||||||
auto i3 = Structure("I3", {
|
auto* i3 = Structure("I3", {
|
||||||
Member(Source{{4, 1}}, "x3", a1),
|
Member(Source{{4, 1}}, "x3", a1),
|
||||||
Member(Source{{5, 1}}, "y3", i2),
|
Member(Source{{5, 1}}, "y3", i2),
|
||||||
Member(Source{{6, 1}}, "z3", a2),
|
Member(Source{{6, 1}}, "z3", a2),
|
||||||
});
|
});
|
||||||
|
|
||||||
auto s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
|
auto* s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage);
|
Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage);
|
||||||
|
|
|
@ -757,7 +757,7 @@ using ResolverIntrinsicDataTest = ResolverTest;
|
||||||
|
|
||||||
TEST_F(ResolverIntrinsicDataTest, ArrayLength_Vector) {
|
TEST_F(ResolverIntrinsicDataTest, ArrayLength_Vector) {
|
||||||
auto ary = ty.array<i32>();
|
auto ary = ty.array<i32>();
|
||||||
auto str = Structure("S", {Member("x", ary)},
|
auto* str = Structure("S", {Member("x", ary)},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, str);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, str);
|
||||||
Global("a", ac, ast::StorageClass::kStorage);
|
Global("a", ac, ast::StorageClass::kStorage);
|
||||||
|
|
|
@ -105,46 +105,7 @@ TEST_F(ResolverIsHostShareable, ArrayUnsizedOfHostShareable) {
|
||||||
EXPECT_TRUE(r()->IsHostShareable(ty.array<i32>()));
|
EXPECT_TRUE(r()->IsHostShareable(ty.array<i32>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIsHostShareable, Struct_AllMembersHostShareable) {
|
// Note: Structure tests covered in host_shareable_validation_test.cc
|
||||||
EXPECT_TRUE(r()->IsHostShareable(Structure("S", {
|
|
||||||
Member("a", ty.i32()),
|
|
||||||
Member("b", ty.f32()),
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ResolverIsHostShareable, Struct_SomeMembersNonHostShareable) {
|
|
||||||
auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
|
|
||||||
EXPECT_FALSE(r()->IsHostShareable(Structure("S", {
|
|
||||||
Member("a", ty.i32()),
|
|
||||||
Member("b", ptr_ty),
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ResolverIsHostShareable, Struct_NestedHostShareable) {
|
|
||||||
auto host_shareable = Structure("S", {
|
|
||||||
Member("a", ty.i32()),
|
|
||||||
Member("b", ty.f32()),
|
|
||||||
});
|
|
||||||
EXPECT_TRUE(
|
|
||||||
r()->IsHostShareable(Structure("S", {
|
|
||||||
Member("a", ty.i32()),
|
|
||||||
Member("b", host_shareable),
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ResolverIsHostShareable, Struct_NestedNonHostShareable) {
|
|
||||||
auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
|
|
||||||
auto non_host_shareable =
|
|
||||||
Structure("non_host_shareable", {
|
|
||||||
Member("a", ty.i32()),
|
|
||||||
Member("b", ptr_ty),
|
|
||||||
});
|
|
||||||
EXPECT_FALSE(
|
|
||||||
r()->IsHostShareable(Structure("S", {
|
|
||||||
Member("a", ty.i32()),
|
|
||||||
Member("b", non_host_shareable),
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace resolver
|
} // namespace resolver
|
||||||
|
|
|
@ -90,41 +90,55 @@ TEST_F(ResolverIsStorableTest, ArrayUnsizedOfStorable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIsStorableTest, Struct_AllMembersStorable) {
|
TEST_F(ResolverIsStorableTest, Struct_AllMembersStorable) {
|
||||||
EXPECT_TRUE(r()->IsStorable(Structure("S", {
|
Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
})));
|
});
|
||||||
|
|
||||||
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
|
TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
|
||||||
auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
|
auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
|
||||||
EXPECT_FALSE(r()->IsStorable(Structure("S", {
|
Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ptr_ty),
|
Member("b", ptr_ty),
|
||||||
})));
|
});
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(
|
||||||
|
r()->error(),
|
||||||
|
R"(error: ptr<private, i32> cannot be used as the type of a structure member)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIsStorableTest, Struct_NestedStorable) {
|
TEST_F(ResolverIsStorableTest, Struct_NestedStorable) {
|
||||||
auto storable = Structure("S", {
|
auto* storable = Structure("Storable", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
EXPECT_TRUE(r()->IsStorable(Structure("S", {
|
Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", storable),
|
Member("b", storable),
|
||||||
})));
|
});
|
||||||
|
|
||||||
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverIsStorableTest, Struct_NestedNonStorable) {
|
TEST_F(ResolverIsStorableTest, Struct_NestedNonStorable) {
|
||||||
auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
|
auto ptr_ty = ty.pointer<i32>(ast::StorageClass::kPrivate);
|
||||||
auto non_storable = Structure("nonstorable", {
|
auto* non_storable = Structure("nonstorable", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ptr_ty),
|
Member("b", ptr_ty),
|
||||||
});
|
});
|
||||||
EXPECT_FALSE(r()->IsStorable(Structure("S", {
|
Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", non_storable),
|
Member("b", non_storable),
|
||||||
})));
|
});
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(
|
||||||
|
r()->error(),
|
||||||
|
R"(error: ptr<private, i32> cannot be used as the type of a structure member)");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -181,16 +181,14 @@ bool Resolver::IsStorable(const sem::Type* type) {
|
||||||
if (auto* arr = type->As<sem::ArrayType>()) {
|
if (auto* arr = type->As<sem::ArrayType>()) {
|
||||||
return IsStorable(arr->type());
|
return IsStorable(arr->type());
|
||||||
}
|
}
|
||||||
if (auto* str_ty = type->As<sem::StructType>()) {
|
if (auto* str = type->As<sem::Struct>()) {
|
||||||
if (auto* str = Structure(str_ty)) {
|
for (const auto* member : str->Members()) {
|
||||||
for (const auto* member : str->members) {
|
|
||||||
if (!IsStorable(member->Type())) {
|
if (!IsStorable(member->Type())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,12 +207,8 @@ bool Resolver::IsHostShareable(const sem::Type* type) {
|
||||||
if (auto* arr = type->As<sem::ArrayType>()) {
|
if (auto* arr = type->As<sem::ArrayType>()) {
|
||||||
return IsHostShareable(arr->type());
|
return IsHostShareable(arr->type());
|
||||||
}
|
}
|
||||||
if (auto* str = type->As<sem::StructType>()) {
|
if (auto* str = type->As<sem::Struct>()) {
|
||||||
auto* info = Structure(str);
|
for (auto* member : str->Members()) {
|
||||||
if (!info) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (auto* member : info->members) {
|
|
||||||
if (!IsHostShareable(member->Type())) {
|
if (!IsHostShareable(member->Type())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -243,7 +237,7 @@ bool Resolver::IsValidAssignment(const sem::Type* lhs, const sem::Type* rhs) {
|
||||||
bool Resolver::ResolveInternal() {
|
bool Resolver::ResolveInternal() {
|
||||||
Mark(&builder_->AST());
|
Mark(&builder_->AST());
|
||||||
|
|
||||||
auto register_named_type = [this](Symbol name, const sem::Type* type,
|
auto register_named_type = [this](Symbol name, sem::Type* type,
|
||||||
const Source& source) {
|
const Source& source) {
|
||||||
auto added = named_types_.emplace(name, type).second;
|
auto added = named_types_.emplace(name, type).second;
|
||||||
if (!added) {
|
if (!added) {
|
||||||
|
@ -312,9 +306,9 @@ bool Resolver::ResolveInternal() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sem::Type* Resolver::Type(const ast::Type* ty) {
|
sem::Type* Resolver::Type(const ast::Type* ty) {
|
||||||
Mark(ty);
|
Mark(ty);
|
||||||
auto* s = [&]() -> const sem::Type* {
|
auto* s = [&]() -> sem::Type* {
|
||||||
if (ty->Is<ast::Void>()) {
|
if (ty->Is<ast::Void>()) {
|
||||||
return builder_->create<sem::Void>();
|
return builder_->create<sem::Void>();
|
||||||
}
|
}
|
||||||
|
@ -357,8 +351,11 @@ const sem::Type* Resolver::Type(const ast::Type* ty) {
|
||||||
}
|
}
|
||||||
if (auto* t = ty->As<ast::Array>()) {
|
if (auto* t = ty->As<ast::Array>()) {
|
||||||
if (auto* el = Type(t->type())) {
|
if (auto* el = Type(t->type())) {
|
||||||
return builder_->create<sem::ArrayType>(const_cast<sem::Type*>(el),
|
auto* sem = builder_->create<sem::ArrayType>(
|
||||||
t->size(), t->decorations());
|
const_cast<sem::Type*>(el), t->size(), t->decorations());
|
||||||
|
if (Array(sem, ty->source())) {
|
||||||
|
return sem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -370,7 +367,7 @@ const sem::Type* Resolver::Type(const ast::Type* ty) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (auto* t = ty->As<ast::Struct>()) {
|
if (auto* t = ty->As<ast::Struct>()) {
|
||||||
return builder_->create<sem::StructType>(const_cast<ast::Struct*>(t));
|
return Structure(t);
|
||||||
}
|
}
|
||||||
if (auto* t = ty->As<ast::Sampler>()) {
|
if (auto* t = ty->As<ast::Sampler>()) {
|
||||||
return builder_->create<sem::Sampler>(t->kind());
|
return builder_->create<sem::Sampler>(t->kind());
|
||||||
|
@ -417,34 +414,14 @@ const sem::Type* Resolver::Type(const ast::Type* ty) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
if (s == nullptr) {
|
if (s) {
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!Type(s, ty->source())) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
builder_->Sem().Add(ty, s);
|
builder_->Sem().Add(ty, s);
|
||||||
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(crbug.com/tint/724): This method should be merged into Type(ast::Type*)
|
Resolver::VariableInfo* Resolver::Variable(ast::Variable* var,
|
||||||
bool Resolver::Type(const sem::Type* ty, const Source& source /* = {} */) {
|
sem::Type* type, /* = nullptr */
|
||||||
ty = ty->UnwrapAliasIfNeeded();
|
|
||||||
if (auto* str = ty->As<sem::StructType>()) {
|
|
||||||
if (!Structure(str)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (auto* arr = ty->As<sem::ArrayType>()) {
|
|
||||||
if (!Array(arr, source)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Resolver::VariableInfo* Resolver::Variable(
|
|
||||||
ast::Variable* var,
|
|
||||||
const sem::Type* type, /* = nullptr */
|
|
||||||
std::string type_name /* = "" */) {
|
std::string type_name /* = "" */) {
|
||||||
auto it = variable_to_info_.find(var);
|
auto it = variable_to_info_.find(var);
|
||||||
if (it != variable_to_info_.end()) {
|
if (it != variable_to_info_.end()) {
|
||||||
|
@ -561,7 +538,7 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
|
||||||
// attribute, satisfying the storage class constraints.
|
// attribute, satisfying the storage class constraints.
|
||||||
|
|
||||||
auto* access = info->type->As<sem::AccessControl>();
|
auto* access = info->type->As<sem::AccessControl>();
|
||||||
auto* str = access ? access->type()->As<sem::StructType>() : nullptr;
|
auto* str = access ? access->type()->As<sem::Struct>() : nullptr;
|
||||||
if (!str) {
|
if (!str) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"variables declared in the <storage> storage class must be of an "
|
"variables declared in the <storage> storage class must be of an "
|
||||||
|
@ -574,7 +551,7 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"structure used as a storage buffer must be declared with the "
|
"structure used as a storage buffer must be declared with the "
|
||||||
"[[block]] decoration",
|
"[[block]] decoration",
|
||||||
str->impl()->source());
|
str->Declaration()->source());
|
||||||
if (info->declaration->source().range.begin.line) {
|
if (info->declaration->source().range.begin.line) {
|
||||||
diagnostics_.add_note("structure used as storage buffer here",
|
diagnostics_.add_note("structure used as storage buffer here",
|
||||||
info->declaration->source());
|
info->declaration->source());
|
||||||
|
@ -588,7 +565,7 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
|
||||||
// A variable in the uniform storage class is a uniform buffer variable.
|
// A variable in the uniform storage class is a uniform buffer variable.
|
||||||
// Its store type must be a host-shareable structure type with block
|
// Its store type must be a host-shareable structure type with block
|
||||||
// attribute, satisfying the storage class constraints.
|
// attribute, satisfying the storage class constraints.
|
||||||
auto* str = info->type->As<sem::StructType>();
|
auto* str = info->type->As<sem::Struct>();
|
||||||
if (!str) {
|
if (!str) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"variables declared in the <uniform> storage class must be of a "
|
"variables declared in the <uniform> storage class must be of a "
|
||||||
|
@ -601,7 +578,7 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"structure used as a uniform buffer must be declared with the "
|
"structure used as a uniform buffer must be declared with the "
|
||||||
"[[block]] decoration",
|
"[[block]] decoration",
|
||||||
str->impl()->source());
|
str->Declaration()->source());
|
||||||
if (info->declaration->source().range.begin.line) {
|
if (info->declaration->source().range.begin.line) {
|
||||||
diagnostics_.add_note("structure used as uniform buffer here",
|
diagnostics_.add_note("structure used as uniform buffer here",
|
||||||
info->declaration->source());
|
info->declaration->source());
|
||||||
|
@ -781,7 +758,7 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
|
||||||
};
|
};
|
||||||
// Inner lambda that is applied to a type and all of its members.
|
// Inner lambda that is applied to a type and all of its members.
|
||||||
auto validate_entry_point_decorations_inner =
|
auto validate_entry_point_decorations_inner =
|
||||||
[&](const ast::DecorationList& decos, const sem::Type* ty, Source source,
|
[&](const ast::DecorationList& decos, sem::Type* ty, Source source,
|
||||||
ParamOrRetType param_or_ret, bool is_struct_member) {
|
ParamOrRetType param_or_ret, bool is_struct_member) {
|
||||||
// Scan decorations for pipeline IO attributes.
|
// Scan decorations for pipeline IO attributes.
|
||||||
// Check for overlap with attributes that have been seen previously.
|
// Check for overlap with attributes that have been seen previously.
|
||||||
|
@ -834,7 +811,7 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that we saw a pipeline IO attribute iff we need one.
|
// Check that we saw a pipeline IO attribute iff we need one.
|
||||||
if (Canonical(ty)->Is<sem::StructType>()) {
|
if (Canonical(ty)->Is<sem::Struct>()) {
|
||||||
if (pipeline_io_attribute) {
|
if (pipeline_io_attribute) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"entry point IO attributes must not be used on structure " +
|
"entry point IO attributes must not be used on structure " +
|
||||||
|
@ -862,8 +839,7 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
|
||||||
|
|
||||||
// Outer lambda for validating the entry point decorations for a type.
|
// Outer lambda for validating the entry point decorations for a type.
|
||||||
auto validate_entry_point_decorations = [&](const ast::DecorationList& decos,
|
auto validate_entry_point_decorations = [&](const ast::DecorationList& decos,
|
||||||
const sem::Type* ty,
|
sem::Type* ty, Source source,
|
||||||
Source source,
|
|
||||||
ParamOrRetType param_or_ret) {
|
ParamOrRetType param_or_ret) {
|
||||||
// Validate the decorations for the type.
|
// Validate the decorations for the type.
|
||||||
if (!validate_entry_point_decorations_inner(decos, ty, source, param_or_ret,
|
if (!validate_entry_point_decorations_inner(decos, ty, source, param_or_ret,
|
||||||
|
@ -871,12 +847,12 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto* struct_ty = Canonical(ty)->As<sem::StructType>()) {
|
if (auto* str = Canonical(ty)->As<sem::Struct>()) {
|
||||||
// Validate the decorations for each struct members, and also check for
|
// Validate the decorations for each struct members, and also check for
|
||||||
// invalid member types.
|
// invalid member types.
|
||||||
for (auto* member : Structure(struct_ty)->members) {
|
for (auto* member : str->Members()) {
|
||||||
auto* member_ty = Canonical(member->Type());
|
auto* member_ty = Canonical(member->Type());
|
||||||
if (member_ty->Is<sem::StructType>()) {
|
if (member_ty->Is<sem::Struct>()) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"entry point IO types cannot contain nested structures",
|
"entry point IO types cannot contain nested structures",
|
||||||
member->Declaration()->source());
|
member->Declaration()->source());
|
||||||
|
@ -988,23 +964,16 @@ bool Resolver::Function(ast::Function* func) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto* str = param_info->type->As<sem::StructType>()) {
|
if (auto* str = param_info->type->As<sem::Struct>()) {
|
||||||
auto* str_info = Structure(str);
|
|
||||||
if (!str_info) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
switch (func->pipeline_stage()) {
|
switch (func->pipeline_stage()) {
|
||||||
case ast::PipelineStage::kVertex:
|
case ast::PipelineStage::kVertex:
|
||||||
str_info->pipeline_stage_uses.emplace(
|
str->AddUsage(sem::PipelineStageUsage::kVertexInput);
|
||||||
sem::PipelineStageUsage::kVertexInput);
|
|
||||||
break;
|
break;
|
||||||
case ast::PipelineStage::kFragment:
|
case ast::PipelineStage::kFragment:
|
||||||
str_info->pipeline_stage_uses.emplace(
|
str->AddUsage(sem::PipelineStageUsage::kFragmentInput);
|
||||||
sem::PipelineStageUsage::kFragmentInput);
|
|
||||||
break;
|
break;
|
||||||
case ast::PipelineStage::kCompute:
|
case ast::PipelineStage::kCompute:
|
||||||
str_info->pipeline_stage_uses.emplace(
|
str->AddUsage(sem::PipelineStageUsage::kComputeInput);
|
||||||
sem::PipelineStageUsage::kComputeInput);
|
|
||||||
break;
|
break;
|
||||||
case ast::PipelineStage::kNone:
|
case ast::PipelineStage::kNone:
|
||||||
break;
|
break;
|
||||||
|
@ -1026,7 +995,7 @@ bool Resolver::Function(ast::Function* func) {
|
||||||
|
|
||||||
info->return_type = Canonical(info->return_type);
|
info->return_type = Canonical(info->return_type);
|
||||||
|
|
||||||
if (auto* str = info->return_type->As<sem::StructType>()) {
|
if (auto* str = info->return_type->As<sem::Struct>()) {
|
||||||
if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, str,
|
if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, str,
|
||||||
func->source())) {
|
func->source())) {
|
||||||
diagnostics_.add_note("while instantiating return type for " +
|
diagnostics_.add_note("while instantiating return type for " +
|
||||||
|
@ -1035,22 +1004,15 @@ bool Resolver::Function(ast::Function* func) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* str_info = Structure(str);
|
|
||||||
if (!str_info) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
switch (func->pipeline_stage()) {
|
switch (func->pipeline_stage()) {
|
||||||
case ast::PipelineStage::kVertex:
|
case ast::PipelineStage::kVertex:
|
||||||
str_info->pipeline_stage_uses.emplace(
|
str->AddUsage(sem::PipelineStageUsage::kVertexOutput);
|
||||||
sem::PipelineStageUsage::kVertexOutput);
|
|
||||||
break;
|
break;
|
||||||
case ast::PipelineStage::kFragment:
|
case ast::PipelineStage::kFragment:
|
||||||
str_info->pipeline_stage_uses.emplace(
|
str->AddUsage(sem::PipelineStageUsage::kFragmentOutput);
|
||||||
sem::PipelineStageUsage::kFragmentOutput);
|
|
||||||
break;
|
break;
|
||||||
case ast::PipelineStage::kCompute:
|
case ast::PipelineStage::kCompute:
|
||||||
str_info->pipeline_stage_uses.emplace(
|
str->AddUsage(sem::PipelineStageUsage::kComputeOutput);
|
||||||
sem::PipelineStageUsage::kComputeOutput);
|
|
||||||
break;
|
break;
|
||||||
case ast::PipelineStage::kNone:
|
case ast::PipelineStage::kNone:
|
||||||
break;
|
break;
|
||||||
|
@ -1659,13 +1621,12 @@ bool Resolver::MemberAccessor(ast::MemberAccessorExpression* expr) {
|
||||||
sem::Type* ret = nullptr;
|
sem::Type* ret = nullptr;
|
||||||
std::vector<uint32_t> swizzle;
|
std::vector<uint32_t> swizzle;
|
||||||
|
|
||||||
if (auto* ty = data_type->As<sem::StructType>()) {
|
if (auto* str = data_type->As<sem::Struct>()) {
|
||||||
Mark(expr->member());
|
Mark(expr->member());
|
||||||
auto symbol = expr->member()->symbol();
|
auto symbol = expr->member()->symbol();
|
||||||
auto* str = Structure(ty);
|
|
||||||
|
|
||||||
const sem::StructMember* member = nullptr;
|
const sem::StructMember* member = nullptr;
|
||||||
for (auto* m : str->members) {
|
for (auto* m : str->Members()) {
|
||||||
if (m->Declaration()->symbol() == symbol) {
|
if (m->Declaration()->symbol() == symbol) {
|
||||||
ret = m->Type();
|
ret = m->Type();
|
||||||
member = m;
|
member = m;
|
||||||
|
@ -1689,11 +1650,11 @@ bool Resolver::MemberAccessor(ast::MemberAccessorExpression* expr) {
|
||||||
expr, ret, current_statement_, member));
|
expr, ret, current_statement_, member));
|
||||||
} else if (auto* vec = data_type->As<sem::Vector>()) {
|
} else if (auto* vec = data_type->As<sem::Vector>()) {
|
||||||
Mark(expr->member());
|
Mark(expr->member());
|
||||||
std::string str = builder_->Symbols().NameFor(expr->member()->symbol());
|
std::string s = builder_->Symbols().NameFor(expr->member()->symbol());
|
||||||
auto size = str.size();
|
auto size = s.size();
|
||||||
swizzle.reserve(str.size());
|
swizzle.reserve(s.size());
|
||||||
|
|
||||||
for (auto c : str) {
|
for (auto c : s) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'r':
|
case 'r':
|
||||||
|
@ -1732,8 +1693,8 @@ bool Resolver::MemberAccessor(ast::MemberAccessorExpression* expr) {
|
||||||
auto is_xyzw = [](char c) {
|
auto is_xyzw = [](char c) {
|
||||||
return c == 'x' || c == 'y' || c == 'z' || c == 'w';
|
return c == 'x' || c == 'y' || c == 'z' || c == 'w';
|
||||||
};
|
};
|
||||||
if (!std::all_of(str.begin(), str.end(), is_rgba) &&
|
if (!std::all_of(s.begin(), s.end(), is_rgba) &&
|
||||||
!std::all_of(str.begin(), str.end(), is_xyzw)) {
|
!std::all_of(s.begin(), s.end(), is_xyzw)) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"invalid mixing of vector swizzle characters rgba with xyzw",
|
"invalid mixing of vector swizzle characters rgba with xyzw",
|
||||||
expr->member()->source());
|
expr->member()->source());
|
||||||
|
@ -2032,7 +1993,7 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
||||||
|
|
||||||
// If the variable has a declared type, resolve it.
|
// If the variable has a declared type, resolve it.
|
||||||
std::string type_name;
|
std::string type_name;
|
||||||
const sem::Type* type = nullptr;
|
sem::Type* type = nullptr;
|
||||||
if (auto* ast_ty = var->type()) {
|
if (auto* ast_ty = var->type()) {
|
||||||
type_name = ast_ty->FriendlyName(builder_->Symbols());
|
type_name = ast_ty->FriendlyName(builder_->Symbols());
|
||||||
type = Type(ast_ty);
|
type = Type(ast_ty);
|
||||||
|
@ -2122,7 +2083,7 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sem::Type* Resolver::TypeOf(const ast::Expression* expr) {
|
sem::Type* Resolver::TypeOf(const ast::Expression* expr) {
|
||||||
auto it = expr_info_.find(expr);
|
auto it = expr_info_.find(expr);
|
||||||
if (it != expr_info_.end()) {
|
if (it != expr_info_.end()) {
|
||||||
return it->second.type;
|
return it->second.type;
|
||||||
|
@ -2138,7 +2099,7 @@ std::string Resolver::TypeNameOf(const ast::Expression* expr) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const sem::Type* Resolver::TypeOf(const ast::Literal* lit) {
|
sem::Type* Resolver::TypeOf(const ast::Literal* lit) {
|
||||||
if (lit->Is<ast::SintLiteral>()) {
|
if (lit->Is<ast::SintLiteral>()) {
|
||||||
return builder_->create<sem::I32>();
|
return builder_->create<sem::I32>();
|
||||||
}
|
}
|
||||||
|
@ -2273,17 +2234,6 @@ void Resolver::CreateSemanticNodes() const {
|
||||||
builder_->create<sem::Expression>(
|
builder_->create<sem::Expression>(
|
||||||
const_cast<ast::Expression*>(expr), info.type, info.statement));
|
const_cast<ast::Expression*>(expr), info.type, info.statement));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create semantic nodes for all structs
|
|
||||||
for (auto it : struct_info_) {
|
|
||||||
auto* str = it.first;
|
|
||||||
auto* info = it.second;
|
|
||||||
builder_->Sem().Add(
|
|
||||||
str, builder_->create<sem::Struct>(
|
|
||||||
const_cast<sem::StructType*>(str), std::move(info->members),
|
|
||||||
info->align, info->size, info->size_no_padding,
|
|
||||||
info->storage_class_usage, info->pipeline_stage_uses));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
|
bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
|
||||||
|
@ -2305,7 +2255,7 @@ bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
|
||||||
/*vec4*/ 16,
|
/*vec4*/ 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
auto* cty = Canonical(ty);
|
auto* cty = Canonical(const_cast<sem::Type*>(ty));
|
||||||
if (cty->is_scalar()) {
|
if (cty->is_scalar()) {
|
||||||
// Note: Also captures booleans, but these are not host-shareable.
|
// Note: Also captures booleans, but these are not host-shareable.
|
||||||
align = 4;
|
align = 4;
|
||||||
|
@ -2330,13 +2280,10 @@ bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
|
||||||
align = vector_align[mat->rows()];
|
align = vector_align[mat->rows()];
|
||||||
size = vector_align[mat->rows()] * mat->columns();
|
size = vector_align[mat->rows()] * mat->columns();
|
||||||
return true;
|
return true;
|
||||||
} else if (auto* s = cty->As<sem::StructType>()) {
|
} else if (auto* s = cty->As<sem::Struct>()) {
|
||||||
if (auto* si = Structure(s)) {
|
align = s->Align();
|
||||||
align = si->align;
|
size = s->Size();
|
||||||
size = si->size;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else if (cty->Is<sem::ArrayType>()) {
|
} else if (cty->Is<sem::ArrayType>()) {
|
||||||
if (auto* sem =
|
if (auto* sem =
|
||||||
Array(ty->UnwrapAliasIfNeeded()->As<sem::ArrayType>(), source)) {
|
Array(ty->UnwrapAliasIfNeeded()->As<sem::ArrayType>(), source)) {
|
||||||
|
@ -2416,8 +2363,8 @@ bool Resolver::ValidateArray(const sem::ArrayType* arr, const Source& source) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto* el_str = el_ty->As<sem::StructType>()) {
|
if (auto* el_str = el_ty->As<sem::Struct>()) {
|
||||||
if (el_str->impl()->IsBlockDecorated()) {
|
if (el_str->IsBlockDecorated()) {
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#attributes
|
// https://gpuweb.github.io/gpuweb/wgsl/#attributes
|
||||||
// A structure type with the block attribute must not be:
|
// A structure type with the block attribute must not be:
|
||||||
// * the element type of an array type
|
// * the element type of an array type
|
||||||
|
@ -2454,23 +2401,23 @@ bool Resolver::ValidateArrayStrideDecoration(const ast::StrideDecoration* deco,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::ValidateStructure(const StructInfo* st) {
|
bool Resolver::ValidateStructure(const sem::Struct* str) {
|
||||||
for (auto* member : st->members) {
|
for (auto* member : str->Members()) {
|
||||||
if (auto* r = member->Type()->UnwrapAll()->As<sem::ArrayType>()) {
|
if (auto* r = member->Type()->UnwrapAll()->As<sem::ArrayType>()) {
|
||||||
if (r->IsRuntimeArray()) {
|
if (r->IsRuntimeArray()) {
|
||||||
if (member != st->members.back()) {
|
if (member != str->Members().back()) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"v-0015",
|
"v-0015",
|
||||||
"runtime arrays may only appear as the last member of a struct",
|
"runtime arrays may only appear as the last member of a struct",
|
||||||
member->Declaration()->source());
|
member->Declaration()->source());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!st->type->impl()->IsBlockDecorated()) {
|
if (!str->IsBlockDecorated()) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
"v-0015",
|
"v-0015",
|
||||||
"a struct containing a runtime-sized array "
|
"a struct containing a runtime-sized array "
|
||||||
"requires the [[block]] attribute: '" +
|
"requires the [[block]] attribute: '" +
|
||||||
builder_->Symbols().NameFor(st->type->impl()->name()) + "'",
|
builder_->Symbols().NameFor(str->Declaration()->name()) + "'",
|
||||||
member->Declaration()->source());
|
member->Declaration()->source());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2498,7 +2445,7 @@ bool Resolver::ValidateStructure(const StructInfo* st) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* deco : st->type->impl()->decorations()) {
|
for (auto* deco : str->Declaration()->decorations()) {
|
||||||
if (!(deco->Is<ast::StructBlockDecoration>())) {
|
if (!(deco->Is<ast::StructBlockDecoration>())) {
|
||||||
diagnostics_.add_error("decoration is not valid for struct declarations",
|
diagnostics_.add_error("decoration is not valid for struct declarations",
|
||||||
deco->source());
|
deco->source());
|
||||||
|
@ -2509,19 +2456,13 @@ bool Resolver::ValidateStructure(const StructInfo* st) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
|
sem::Struct* Resolver::Structure(const ast::Struct* str) {
|
||||||
auto info_it = struct_info_.find(str);
|
for (auto* deco : str->decorations()) {
|
||||||
if (info_it != struct_info_.end()) {
|
|
||||||
// StructInfo already resolved for this structure type
|
|
||||||
return info_it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto* deco : str->impl()->decorations()) {
|
|
||||||
Mark(deco);
|
Mark(deco);
|
||||||
}
|
}
|
||||||
|
|
||||||
sem::StructMemberList sem_members;
|
sem::StructMemberList sem_members;
|
||||||
sem_members.reserve(str->impl()->members().size());
|
sem_members.reserve(str->members().size());
|
||||||
|
|
||||||
// Calculate the effective size and alignment of each field, and the overall
|
// Calculate the effective size and alignment of each field, and the overall
|
||||||
// size of the structure.
|
// size of the structure.
|
||||||
|
@ -2537,7 +2478,7 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
|
||||||
uint32_t struct_size = 0;
|
uint32_t struct_size = 0;
|
||||||
uint32_t struct_align = 1;
|
uint32_t struct_align = 1;
|
||||||
|
|
||||||
for (auto* member : str->impl()->members()) {
|
for (auto* member : str->members()) {
|
||||||
Mark(member);
|
Mark(member);
|
||||||
|
|
||||||
// Resolve member type
|
// Resolve member type
|
||||||
|
@ -2548,7 +2489,7 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
|
||||||
|
|
||||||
// Validate member type
|
// Validate member type
|
||||||
if (!IsStorable(type)) {
|
if (!IsStorable(type)) {
|
||||||
builder_->Diagnostics().add_error(
|
diagnostics_.add_error(
|
||||||
type->FriendlyName(builder_->Symbols()) +
|
type->FriendlyName(builder_->Symbols()) +
|
||||||
" cannot be used as the type of a structure member");
|
" cannot be used as the type of a structure member");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -2620,19 +2561,14 @@ Resolver::StructInfo* Resolver::Structure(const sem::StructType* str) {
|
||||||
auto size_no_padding = struct_size;
|
auto size_no_padding = struct_size;
|
||||||
struct_size = utils::RoundUp(struct_align, struct_size);
|
struct_size = utils::RoundUp(struct_align, struct_size);
|
||||||
|
|
||||||
auto* info = struct_infos_.Create();
|
auto* out = builder_->create<sem::Struct>(
|
||||||
info->type = str;
|
str, std::move(sem_members), struct_align, struct_size, size_no_padding);
|
||||||
info->members = std::move(sem_members);
|
|
||||||
info->align = struct_align;
|
|
||||||
info->size = struct_size;
|
|
||||||
info->size_no_padding = size_no_padding;
|
|
||||||
struct_info_.emplace(str, info);
|
|
||||||
|
|
||||||
if (!ValidateStructure(info)) {
|
if (!ValidateStructure(out)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return info;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::ValidateReturn(const ast::ReturnStatement* ret) {
|
bool Resolver::ValidateReturn(const ast::ReturnStatement* ret) {
|
||||||
|
@ -2828,20 +2764,18 @@ bool Resolver::Assignment(ast::AssignmentStatement* a) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
|
bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
|
||||||
const sem::Type* ty,
|
sem::Type* ty,
|
||||||
const Source& usage) {
|
const Source& usage) {
|
||||||
ty = ty->UnwrapIfNeeded();
|
ty = ty->UnwrapIfNeeded();
|
||||||
|
|
||||||
if (auto* str = ty->As<sem::StructType>()) {
|
if (auto* str = ty->As<sem::Struct>()) {
|
||||||
auto* info = Structure(str);
|
if (str->StorageClassUsage().count(sc)) {
|
||||||
if (!info) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (info->storage_class_usage.count(sc)) {
|
|
||||||
return true; // Already applied
|
return true; // Already applied
|
||||||
}
|
}
|
||||||
info->storage_class_usage.emplace(sc);
|
|
||||||
for (auto* member : info->members) {
|
str->AddUsage(sc);
|
||||||
|
|
||||||
|
for (auto* member : str->Members()) {
|
||||||
if (!ApplyStorageClassUsageToType(sc, member->Type(), usage)) {
|
if (!ApplyStorageClassUsageToType(sc, member->Type(), usage)) {
|
||||||
std::stringstream err;
|
std::stringstream err;
|
||||||
err << "while analysing structure member "
|
err << "while analysing structure member "
|
||||||
|
@ -2887,7 +2821,7 @@ std::string Resolver::VectorPretty(uint32_t size, sem::Type* element_type) {
|
||||||
return vec_type.FriendlyName(builder_->Symbols());
|
return vec_type.FriendlyName(builder_->Symbols());
|
||||||
}
|
}
|
||||||
|
|
||||||
const sem::Type* Resolver::Canonical(const sem::Type* type) {
|
sem::Type* Resolver::Canonical(sem::Type* type) {
|
||||||
using AccessControl = sem::AccessControl;
|
using AccessControl = sem::AccessControl;
|
||||||
using Alias = sem::Alias;
|
using Alias = sem::Alias;
|
||||||
using Matrix = sem::Matrix;
|
using Matrix = sem::Matrix;
|
||||||
|
@ -2899,17 +2833,16 @@ const sem::Type* Resolver::Canonical(const sem::Type* type) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<const Type*(const Type*)> make_canonical;
|
std::function<Type*(Type*)> make_canonical;
|
||||||
make_canonical = [&](const Type* t) -> const sem::Type* {
|
make_canonical = [&](Type* t) -> sem::Type* {
|
||||||
// Unwrap alias sequence
|
// Unwrap alias sequence
|
||||||
const Type* ct = t;
|
Type* ct = t;
|
||||||
while (auto* p = ct->As<Alias>()) {
|
while (auto* p = ct->As<Alias>()) {
|
||||||
ct = p->type();
|
ct = p->type();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto* v = ct->As<Vector>()) {
|
if (auto* v = ct->As<Vector>()) {
|
||||||
return builder_->create<Vector>(
|
return builder_->create<Vector>(make_canonical(v->type()), v->size());
|
||||||
const_cast<sem::Type*>(make_canonical(v->type())), v->size());
|
|
||||||
}
|
}
|
||||||
if (auto* m = ct->As<Matrix>()) {
|
if (auto* m = ct->As<Matrix>()) {
|
||||||
auto* column_type =
|
auto* column_type =
|
||||||
|
@ -2943,7 +2876,7 @@ void Resolver::Mark(const ast::Node* node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Resolver::VariableInfo::VariableInfo(const ast::Variable* decl,
|
Resolver::VariableInfo::VariableInfo(const ast::Variable* decl,
|
||||||
const sem::Type* ctype,
|
sem::Type* ctype,
|
||||||
const std::string& tn)
|
const std::string& tn)
|
||||||
: declaration(decl),
|
: declaration(decl),
|
||||||
type(ctype),
|
type(ctype),
|
||||||
|
@ -2955,8 +2888,5 @@ Resolver::VariableInfo::~VariableInfo() = default;
|
||||||
Resolver::FunctionInfo::FunctionInfo(ast::Function* decl) : declaration(decl) {}
|
Resolver::FunctionInfo::FunctionInfo(ast::Function* decl) : declaration(decl) {}
|
||||||
Resolver::FunctionInfo::~FunctionInfo() = default;
|
Resolver::FunctionInfo::~FunctionInfo() = default;
|
||||||
|
|
||||||
Resolver::StructInfo::StructInfo() = default;
|
|
||||||
Resolver::StructInfo::~StructInfo() = default;
|
|
||||||
|
|
||||||
} // namespace resolver
|
} // namespace resolver
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -49,9 +49,6 @@ namespace sem {
|
||||||
class Array;
|
class Array;
|
||||||
class Statement;
|
class Statement;
|
||||||
} // namespace sem
|
} // namespace sem
|
||||||
namespace sem {
|
|
||||||
class StructType;
|
|
||||||
} // namespace sem
|
|
||||||
|
|
||||||
namespace resolver {
|
namespace resolver {
|
||||||
|
|
||||||
|
@ -90,19 +87,19 @@ class Resolver {
|
||||||
/// @returns the canonical type for `type`; that is, a type with all aliases
|
/// @returns the canonical type for `type`; that is, a type with all aliases
|
||||||
/// removed. For example, `Canonical(alias<alias<vec3<alias<f32>>>>)` is
|
/// removed. For example, `Canonical(alias<alias<vec3<alias<f32>>>>)` is
|
||||||
/// `vec3<f32>`.
|
/// `vec3<f32>`.
|
||||||
const sem::Type* Canonical(const sem::Type* type);
|
sem::Type* Canonical(sem::Type* type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Structure holding semantic information about a variable.
|
/// Structure holding semantic information about a variable.
|
||||||
/// Used to build the sem::Variable nodes at the end of resolving.
|
/// Used to build the sem::Variable nodes at the end of resolving.
|
||||||
struct VariableInfo {
|
struct VariableInfo {
|
||||||
VariableInfo(const ast::Variable* decl,
|
VariableInfo(const ast::Variable* decl,
|
||||||
const sem::Type* type,
|
sem::Type* type,
|
||||||
const std::string& type_name);
|
const std::string& type_name);
|
||||||
~VariableInfo();
|
~VariableInfo();
|
||||||
|
|
||||||
ast::Variable const* const declaration;
|
ast::Variable const* const declaration;
|
||||||
sem::Type const* type;
|
sem::Type* type;
|
||||||
std::string const type_name;
|
std::string const type_name;
|
||||||
ast::StorageClass storage_class;
|
ast::StorageClass storage_class;
|
||||||
std::vector<ast::IdentifierExpression*> users;
|
std::vector<ast::IdentifierExpression*> users;
|
||||||
|
@ -119,7 +116,7 @@ class Resolver {
|
||||||
UniqueVector<VariableInfo*> referenced_module_vars;
|
UniqueVector<VariableInfo*> referenced_module_vars;
|
||||||
UniqueVector<VariableInfo*> local_referenced_module_vars;
|
UniqueVector<VariableInfo*> local_referenced_module_vars;
|
||||||
std::vector<const ast::ReturnStatement*> return_statements;
|
std::vector<const ast::ReturnStatement*> return_statements;
|
||||||
sem::Type const* return_type = nullptr;
|
sem::Type* return_type = nullptr;
|
||||||
std::string return_type_name;
|
std::string return_type_name;
|
||||||
|
|
||||||
// List of transitive calls this function makes
|
// List of transitive calls this function makes
|
||||||
|
@ -129,7 +126,7 @@ class Resolver {
|
||||||
/// Structure holding semantic information about an expression.
|
/// Structure holding semantic information about an expression.
|
||||||
/// Used to build the sem::Expression nodes at the end of resolving.
|
/// Used to build the sem::Expression nodes at the end of resolving.
|
||||||
struct ExpressionInfo {
|
struct ExpressionInfo {
|
||||||
sem::Type const* type;
|
sem::Type* type;
|
||||||
std::string const type_name; // Declared type name
|
std::string const type_name; // Declared type name
|
||||||
sem::Statement* statement;
|
sem::Statement* statement;
|
||||||
};
|
};
|
||||||
|
@ -142,21 +139,6 @@ class Resolver {
|
||||||
sem::Statement* statement;
|
sem::Statement* statement;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Structure holding semantic information about a struct.
|
|
||||||
/// Used to build the sem::Struct nodes at the end of resolving.
|
|
||||||
struct StructInfo {
|
|
||||||
StructInfo();
|
|
||||||
~StructInfo();
|
|
||||||
|
|
||||||
sem::StructType const* type = nullptr;
|
|
||||||
std::vector<const sem::StructMember*> members;
|
|
||||||
uint32_t align = 0;
|
|
||||||
uint32_t size = 0;
|
|
||||||
uint32_t size_no_padding = 0;
|
|
||||||
std::unordered_set<ast::StorageClass> storage_class_usage;
|
|
||||||
std::unordered_set<sem::PipelineStageUsage> pipeline_stage_uses;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Structure holding semantic information about a block (i.e. scope), such as
|
/// Structure holding semantic information about a block (i.e. scope), such as
|
||||||
/// parent block and variables declared in the block.
|
/// parent block and variables declared in the block.
|
||||||
/// Used to validate variable scoping rules.
|
/// Used to validate variable scoping rules.
|
||||||
|
@ -237,7 +219,6 @@ class Resolver {
|
||||||
bool Statement(ast::Statement*);
|
bool Statement(ast::Statement*);
|
||||||
bool Statements(const ast::StatementList&);
|
bool Statements(const ast::StatementList&);
|
||||||
bool Switch(ast::SwitchStatement* s);
|
bool Switch(ast::SwitchStatement* s);
|
||||||
bool Type(const sem::Type* ty, const Source& source = {});
|
|
||||||
bool UnaryOp(ast::UnaryOpExpression*);
|
bool UnaryOp(ast::UnaryOpExpression*);
|
||||||
bool VariableDeclStatement(const ast::VariableDeclStatement*);
|
bool VariableDeclStatement(const ast::VariableDeclStatement*);
|
||||||
|
|
||||||
|
@ -257,7 +238,7 @@ class Resolver {
|
||||||
const sem::Matrix* matrix_type);
|
const sem::Matrix* matrix_type);
|
||||||
bool ValidateParameter(const ast::Variable* param);
|
bool ValidateParameter(const ast::Variable* param);
|
||||||
bool ValidateReturn(const ast::ReturnStatement* ret);
|
bool ValidateReturn(const ast::ReturnStatement* ret);
|
||||||
bool ValidateStructure(const StructInfo* st);
|
bool ValidateStructure(const sem::Struct* str);
|
||||||
bool ValidateSwitch(const ast::SwitchStatement* s);
|
bool ValidateSwitch(const ast::SwitchStatement* s);
|
||||||
bool ValidateVariable(const ast::Variable* param);
|
bool ValidateVariable(const ast::Variable* param);
|
||||||
bool ValidateVectorConstructor(const ast::TypeConstructorExpression* ctor,
|
bool ValidateVectorConstructor(const ast::TypeConstructorExpression* ctor,
|
||||||
|
@ -267,7 +248,7 @@ class Resolver {
|
||||||
/// hasn't been constructed already. If an error is raised, nullptr is
|
/// hasn't been constructed already. If an error is raised, nullptr is
|
||||||
/// returned.
|
/// returned.
|
||||||
/// @param ty the ast::Type
|
/// @param ty the ast::Type
|
||||||
const sem::Type* Type(const ast::Type* ty);
|
sem::Type* Type(const ast::Type* ty);
|
||||||
|
|
||||||
/// @returns the semantic information for the array `arr`, building it if it
|
/// @returns the semantic information for the array `arr`, building it if it
|
||||||
/// hasn't been constructed already. If an error is raised, nullptr is
|
/// hasn't been constructed already. If an error is raised, nullptr is
|
||||||
|
@ -276,9 +257,9 @@ class Resolver {
|
||||||
/// @param source the Source of the ast node with this array as its type
|
/// @param source the Source of the ast node with this array as its type
|
||||||
const sem::Array* Array(const sem::ArrayType* arr, const Source& source);
|
const sem::Array* Array(const sem::ArrayType* arr, const Source& source);
|
||||||
|
|
||||||
/// @returns the StructInfo for the structure `str`, building it if it hasn't
|
/// @returns the sem::Struct for the AST structure `str`. If an error is
|
||||||
/// been constructed already. If an error is raised, nullptr is returned.
|
/// raised, nullptr is returned.
|
||||||
StructInfo* Structure(const sem::StructType* str);
|
sem::Struct* Structure(const ast::Struct* str);
|
||||||
|
|
||||||
/// @returns the VariableInfo for the variable `var`, building it if it hasn't
|
/// @returns the VariableInfo for the variable `var`, building it if it hasn't
|
||||||
/// been constructed already. If an error is raised, nullptr is returned.
|
/// been constructed already. If an error is raised, nullptr is returned.
|
||||||
|
@ -287,7 +268,7 @@ class Resolver {
|
||||||
/// @param type_name optional type name of `var` to use instead of
|
/// @param type_name optional type name of `var` to use instead of
|
||||||
/// `var->type()->FriendlyName()`.
|
/// `var->type()->FriendlyName()`.
|
||||||
VariableInfo* Variable(ast::Variable* var,
|
VariableInfo* Variable(ast::Variable* var,
|
||||||
const sem::Type* type = nullptr,
|
sem::Type* type = nullptr,
|
||||||
std::string type_name = "");
|
std::string type_name = "");
|
||||||
|
|
||||||
/// Records the storage class usage for the given type, and any transient
|
/// Records the storage class usage for the given type, and any transient
|
||||||
|
@ -299,7 +280,7 @@ class Resolver {
|
||||||
/// given type and storage class. Used for generating sensible error messages.
|
/// given type and storage class. Used for generating sensible error messages.
|
||||||
/// @returns true on success, false on error
|
/// @returns true on success, false on error
|
||||||
bool ApplyStorageClassUsageToType(ast::StorageClass sc,
|
bool ApplyStorageClassUsageToType(ast::StorageClass sc,
|
||||||
const sem::Type* ty,
|
sem::Type* ty,
|
||||||
const Source& usage);
|
const Source& usage);
|
||||||
|
|
||||||
/// @param align the output default alignment in bytes for the type `ty`
|
/// @param align the output default alignment in bytes for the type `ty`
|
||||||
|
@ -313,7 +294,7 @@ class Resolver {
|
||||||
|
|
||||||
/// @returns the resolved type of the ast::Expression `expr`
|
/// @returns the resolved type of the ast::Expression `expr`
|
||||||
/// @param expr the expression
|
/// @param expr the expression
|
||||||
const sem::Type* TypeOf(const ast::Expression* expr);
|
sem::Type* TypeOf(const ast::Expression* expr);
|
||||||
|
|
||||||
/// @returns the declared type name of the ast::Expression `expr`
|
/// @returns the declared type name of the ast::Expression `expr`
|
||||||
/// @param expr the type name
|
/// @param expr the type name
|
||||||
|
@ -321,7 +302,7 @@ class Resolver {
|
||||||
|
|
||||||
/// @returns the semantic type of the AST literal `lit`
|
/// @returns the semantic type of the AST literal `lit`
|
||||||
/// @param lit the literal
|
/// @param lit the literal
|
||||||
const sem::Type* TypeOf(const ast::Literal* lit);
|
sem::Type* TypeOf(const ast::Literal* lit);
|
||||||
|
|
||||||
/// Creates a sem::Expression node with the resolved type `type`, and
|
/// Creates a sem::Expression node with the resolved type `type`, and
|
||||||
/// assigns this semantic node to the expression `expr`.
|
/// assigns this semantic node to the expression `expr`.
|
||||||
|
@ -369,15 +350,13 @@ class Resolver {
|
||||||
std::unordered_map<const ast::Variable*, VariableInfo*> variable_to_info_;
|
std::unordered_map<const ast::Variable*, VariableInfo*> variable_to_info_;
|
||||||
std::unordered_map<ast::CallExpression*, FunctionCallInfo> function_calls_;
|
std::unordered_map<ast::CallExpression*, FunctionCallInfo> function_calls_;
|
||||||
std::unordered_map<const ast::Expression*, ExpressionInfo> expr_info_;
|
std::unordered_map<const ast::Expression*, ExpressionInfo> expr_info_;
|
||||||
std::unordered_map<const sem::StructType*, StructInfo*> struct_info_;
|
std::unordered_map<sem::Type*, sem::Type*> type_to_canonical_;
|
||||||
std::unordered_map<const sem::Type*, const sem::Type*> type_to_canonical_;
|
std::unordered_map<Symbol, sem::Type*> named_types_;
|
||||||
std::unordered_map<Symbol, const sem::Type*> named_types_;
|
|
||||||
std::unordered_set<const ast::Node*> marked_;
|
std::unordered_set<const ast::Node*> marked_;
|
||||||
FunctionInfo* current_function_ = nullptr;
|
FunctionInfo* current_function_ = nullptr;
|
||||||
sem::Statement* current_statement_ = nullptr;
|
sem::Statement* current_statement_ = nullptr;
|
||||||
BlockAllocator<VariableInfo> variable_infos_;
|
BlockAllocator<VariableInfo> variable_infos_;
|
||||||
BlockAllocator<FunctionInfo> function_infos_;
|
BlockAllocator<FunctionInfo> function_infos_;
|
||||||
BlockAllocator<StructInfo> struct_infos_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace resolver
|
} // namespace resolver
|
||||||
|
|
|
@ -764,7 +764,7 @@ TEST_F(ResolverTest, Function_Parameters) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
|
TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
|
||||||
auto s = Structure("S", {Member("m", ty.u32())},
|
auto* s = Structure("S", {Member("m", ty.u32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
|
@ -800,7 +800,7 @@ TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
|
TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
|
||||||
auto s = Structure("S", {Member("m", ty.u32())},
|
auto* s = Structure("S", {Member("m", ty.u32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
|
@ -884,7 +884,7 @@ TEST_F(ResolverTest, Function_ReturnStatements) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
|
TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
|
||||||
auto st = Structure("S", {Member("first_member", ty.i32()),
|
auto* st = Structure("S", {Member("first_member", ty.i32()),
|
||||||
Member("second_member", ty.f32())});
|
Member("second_member", ty.f32())});
|
||||||
Global("my_struct", st, ast::StorageClass::kInput);
|
Global("my_struct", st, ast::StorageClass::kInput);
|
||||||
|
|
||||||
|
@ -906,7 +906,7 @@ TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
|
TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
|
||||||
auto st = Structure("S", {Member("first_member", ty.i32()),
|
auto* st = Structure("S", {Member("first_member", ty.i32()),
|
||||||
Member("second_member", ty.f32())});
|
Member("second_member", ty.f32())});
|
||||||
auto alias = ty.alias("alias", st);
|
auto alias = ty.alias("alias", st);
|
||||||
AST().AddConstructedType(alias);
|
AST().AddConstructedType(alias);
|
||||||
|
@ -987,8 +987,8 @@ TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
|
||||||
auto stB = Structure("B", {Member("foo", ty.vec4<f32>())});
|
auto* stB = Structure("B", {Member("foo", ty.vec4<f32>())});
|
||||||
auto stA = Structure("A", {Member("mem", ty.vec(stB, 3))});
|
auto* stA = Structure("A", {Member("mem", ty.vec(stB, 3))});
|
||||||
Global("c", stA, ast::StorageClass::kInput);
|
Global("c", stA, ast::StorageClass::kInput);
|
||||||
|
|
||||||
auto* mem = MemberAccessor(
|
auto* mem = MemberAccessor(
|
||||||
|
@ -1006,7 +1006,7 @@ TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, Expr_MemberAccessor_InBinaryOp) {
|
TEST_F(ResolverTest, Expr_MemberAccessor_InBinaryOp) {
|
||||||
auto st = Structure("S", {Member("first_member", ty.f32()),
|
auto* st = Structure("S", {Member("first_member", ty.f32()),
|
||||||
Member("second_member", ty.f32())});
|
Member("second_member", ty.f32())});
|
||||||
Global("my_struct", st, ast::StorageClass::kInput);
|
Global("my_struct", st, ast::StorageClass::kInput);
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) {
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) {
|
||||||
// var<storage> g : [[access(read)]] array<S, 3>;
|
// var<storage> g : [[access(read)]] array<S, 3>;
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
auto a = ty.array(s, 3);
|
auto a = ty.array(s, 3);
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, a);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, a);
|
||||||
Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kStorage);
|
Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kStorage);
|
||||||
|
@ -88,7 +88,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferBoolAlias) {
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoAccessControl) {
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoAccessControl) {
|
||||||
// var<storage> g : S;
|
// var<storage> g : S;
|
||||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
|
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
|
||||||
Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage);
|
Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage);
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
@ -101,7 +101,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoAccessControl) {
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoBlockDecoration) {
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoBlockDecoration) {
|
||||||
// struct S { x : i32 };
|
// struct S { x : i32 };
|
||||||
// var<storage> g : [[access(read)]] S;
|
// var<storage> g : [[access(read)]] S;
|
||||||
auto s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
|
auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
|
||||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
|
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoBlockDecoration) {
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Basic) {
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Basic) {
|
||||||
// [[block]] struct S { x : i32 };
|
// [[block]] struct S { x : i32 };
|
||||||
// var<storage> g : [[access(read)]] S;
|
// var<storage> g : [[access(read)]] S;
|
||||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
|
Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage);
|
||||||
|
@ -129,7 +129,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) {
|
||||||
// type a1 = S;
|
// type a1 = S;
|
||||||
// type a2 = [[access(read)]] a1;
|
// type a2 = [[access(read)]] a1;
|
||||||
// var<storage> g : a2;
|
// var<storage> g : a2;
|
||||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto a1 = ty.alias("a1", s);
|
auto a1 = ty.alias("a1", s);
|
||||||
AST().AddConstructedType(a1);
|
AST().AddConstructedType(a1);
|
||||||
|
@ -168,7 +168,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
|
||||||
// var<uniform> g : [[access(read)]] array<S, 3>;
|
// var<uniform> g : [[access(read)]] array<S, 3>;
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
auto a = ty.array(s, 3);
|
auto a = ty.array(s, 3);
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, a);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, a);
|
||||||
Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform);
|
Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform);
|
||||||
|
@ -197,7 +197,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoBlockDecoration) {
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoBlockDecoration) {
|
||||||
// struct S { x : i32 };
|
// struct S { x : i32 };
|
||||||
// var<uniform> g : S;
|
// var<uniform> g : S;
|
||||||
auto s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
|
auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
|
||||||
Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform);
|
Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform);
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
@ -211,7 +211,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferNoBlockDecoration) {
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Basic) {
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Basic) {
|
||||||
// [[block]] struct S { x : i32 };
|
// [[block]] struct S { x : i32 };
|
||||||
// var<uniform> g : S;
|
// var<uniform> g : S;
|
||||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform);
|
Global(Source{{56, 78}}, "g", s, ast::StorageClass::kUniform);
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Aliases) {
|
||||||
// [[block]] struct S { x : i32 };
|
// [[block]] struct S { x : i32 };
|
||||||
// type a1 = S;
|
// type a1 = S;
|
||||||
// var<uniform> g : a1;
|
// var<uniform> g : a1;
|
||||||
auto s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto a1 = ty.alias("a1", s);
|
auto a1 = ty.alias("a1", s);
|
||||||
AST().AddConstructedType(a1);
|
AST().AddConstructedType(a1);
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace {
|
||||||
using ResolverStructLayoutTest = ResolverTest;
|
using ResolverStructLayoutTest = ResolverTest;
|
||||||
|
|
||||||
TEST_F(ResolverStructLayoutTest, Scalars) {
|
TEST_F(ResolverStructLayoutTest, Scalars) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.u32()),
|
Member("b", ty.u32()),
|
||||||
Member("c", ty.i32()),
|
Member("c", ty.i32()),
|
||||||
|
@ -34,7 +34,7 @@ TEST_F(ResolverStructLayoutTest, Scalars) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 12u);
|
EXPECT_EQ(sem->Size(), 12u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 12u);
|
EXPECT_EQ(sem->SizeNoPadding(), 12u);
|
||||||
|
@ -57,14 +57,14 @@ TEST_F(ResolverStructLayoutTest, Alias) {
|
||||||
auto alias_b = ty.alias("b", ty.f32());
|
auto alias_b = ty.alias("b", ty.f32());
|
||||||
AST().AddConstructedType(alias_b);
|
AST().AddConstructedType(alias_b);
|
||||||
|
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", alias_a),
|
Member("a", alias_a),
|
||||||
Member("b", alias_b),
|
Member("b", alias_b),
|
||||||
});
|
});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 8u);
|
EXPECT_EQ(sem->Size(), 8u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 8u);
|
EXPECT_EQ(sem->SizeNoPadding(), 8u);
|
||||||
|
@ -79,7 +79,7 @@ TEST_F(ResolverStructLayoutTest, Alias) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
|
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.array<i32, 3>()),
|
Member("a", ty.array<i32, 3>()),
|
||||||
Member("b", ty.array<f32, 5>()),
|
Member("b", ty.array<f32, 5>()),
|
||||||
Member("c", ty.array<f32, 1>()),
|
Member("c", ty.array<f32, 1>()),
|
||||||
|
@ -87,7 +87,7 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 36u);
|
EXPECT_EQ(sem->Size(), 36u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 36u);
|
EXPECT_EQ(sem->SizeNoPadding(), 36u);
|
||||||
|
@ -105,7 +105,7 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
|
TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.array<i32, 3>(/*stride*/ 8)),
|
Member("a", ty.array<i32, 3>(/*stride*/ 8)),
|
||||||
Member("b", ty.array<f32, 5>(/*stride*/ 16)),
|
Member("b", ty.array<f32, 5>(/*stride*/ 16)),
|
||||||
Member("c", ty.array<f32, 1>(/*stride*/ 32)),
|
Member("c", ty.array<f32, 1>(/*stride*/ 32)),
|
||||||
|
@ -113,7 +113,7 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 136u);
|
EXPECT_EQ(sem->Size(), 136u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 136u);
|
EXPECT_EQ(sem->SizeNoPadding(), 136u);
|
||||||
|
@ -131,7 +131,8 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
|
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
|
||||||
auto s = Structure("S",
|
auto* s =
|
||||||
|
Structure("S",
|
||||||
{
|
{
|
||||||
Member("c", ty.array<f32>()),
|
Member("c", ty.array<f32>()),
|
||||||
},
|
},
|
||||||
|
@ -139,7 +140,7 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 4u);
|
EXPECT_EQ(sem->Size(), 4u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 4u);
|
EXPECT_EQ(sem->SizeNoPadding(), 4u);
|
||||||
|
@ -151,7 +152,8 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
|
TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
|
||||||
auto s = Structure("S",
|
auto* s =
|
||||||
|
Structure("S",
|
||||||
{
|
{
|
||||||
Member("c", ty.array<f32>(/*stride*/ 32)),
|
Member("c", ty.array<f32>(/*stride*/ 32)),
|
||||||
},
|
},
|
||||||
|
@ -159,7 +161,7 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 32u);
|
EXPECT_EQ(sem->Size(), 32u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 32u);
|
EXPECT_EQ(sem->SizeNoPadding(), 32u);
|
||||||
|
@ -173,13 +175,13 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
|
||||||
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) {
|
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) {
|
||||||
auto inner = ty.array<i32, 2>(/*stride*/ 16); // size: 32
|
auto inner = ty.array<i32, 2>(/*stride*/ 16); // size: 32
|
||||||
auto outer = ty.array(inner, 12); // size: 12 * 32
|
auto outer = ty.array(inner, 12); // size: 12 * 32
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("c", outer),
|
Member("c", outer),
|
||||||
});
|
});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 384u);
|
EXPECT_EQ(sem->Size(), 384u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 384u);
|
EXPECT_EQ(sem->SizeNoPadding(), 384u);
|
||||||
|
@ -191,19 +193,19 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfStructure) {
|
TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfStructure) {
|
||||||
auto inner = Structure("Inner", {
|
auto* inner = Structure("Inner", {
|
||||||
Member("a", ty.vec2<i32>()),
|
Member("a", ty.vec2<i32>()),
|
||||||
Member("b", ty.vec3<i32>()),
|
Member("b", ty.vec3<i32>()),
|
||||||
Member("c", ty.vec4<i32>()),
|
Member("c", ty.vec4<i32>()),
|
||||||
}); // size: 48
|
}); // size: 48
|
||||||
auto outer = ty.array(inner, 12); // size: 12 * 48
|
auto outer = ty.array(inner, 12); // size: 12 * 48
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("c", outer),
|
Member("c", outer),
|
||||||
});
|
});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 576u);
|
EXPECT_EQ(sem->Size(), 576u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 576u);
|
EXPECT_EQ(sem->SizeNoPadding(), 576u);
|
||||||
|
@ -215,7 +217,7 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfStructure) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStructLayoutTest, Vector) {
|
TEST_F(ResolverStructLayoutTest, Vector) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.vec2<i32>()),
|
Member("a", ty.vec2<i32>()),
|
||||||
Member("b", ty.vec3<i32>()),
|
Member("b", ty.vec3<i32>()),
|
||||||
Member("c", ty.vec4<i32>()),
|
Member("c", ty.vec4<i32>()),
|
||||||
|
@ -223,7 +225,7 @@ TEST_F(ResolverStructLayoutTest, Vector) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 48u);
|
EXPECT_EQ(sem->Size(), 48u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 48u);
|
EXPECT_EQ(sem->SizeNoPadding(), 48u);
|
||||||
|
@ -241,7 +243,7 @@ TEST_F(ResolverStructLayoutTest, Vector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStructLayoutTest, Matrix) {
|
TEST_F(ResolverStructLayoutTest, Matrix) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.mat2x2<i32>()),
|
Member("a", ty.mat2x2<i32>()),
|
||||||
Member("b", ty.mat2x3<i32>()),
|
Member("b", ty.mat2x3<i32>()),
|
||||||
Member("c", ty.mat2x4<i32>()),
|
Member("c", ty.mat2x4<i32>()),
|
||||||
|
@ -255,7 +257,7 @@ TEST_F(ResolverStructLayoutTest, Matrix) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 368u);
|
EXPECT_EQ(sem->Size(), 368u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 368u);
|
EXPECT_EQ(sem->SizeNoPadding(), 368u);
|
||||||
|
@ -291,10 +293,10 @@ TEST_F(ResolverStructLayoutTest, Matrix) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStructLayoutTest, NestedStruct) {
|
TEST_F(ResolverStructLayoutTest, NestedStruct) {
|
||||||
auto inner = Structure("Inner", {
|
auto* inner = Structure("Inner", {
|
||||||
Member("a", ty.mat3x3<i32>()),
|
Member("a", ty.mat3x3<i32>()),
|
||||||
});
|
});
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", inner),
|
Member("b", inner),
|
||||||
Member("c", ty.i32()),
|
Member("c", ty.i32()),
|
||||||
|
@ -302,7 +304,7 @@ TEST_F(ResolverStructLayoutTest, NestedStruct) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 80u);
|
EXPECT_EQ(sem->Size(), 80u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 68u);
|
EXPECT_EQ(sem->SizeNoPadding(), 68u);
|
||||||
|
@ -320,12 +322,12 @@ TEST_F(ResolverStructLayoutTest, NestedStruct) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStructLayoutTest, SizeDecorations) {
|
TEST_F(ResolverStructLayoutTest, SizeDecorations) {
|
||||||
auto inner = Structure("Inner", {
|
auto* inner = Structure("Inner", {
|
||||||
Member("a", ty.f32(), {MemberSize(8)}),
|
Member("a", ty.f32(), {MemberSize(8)}),
|
||||||
Member("b", ty.f32(), {MemberSize(16)}),
|
Member("b", ty.f32(), {MemberSize(16)}),
|
||||||
Member("c", ty.f32(), {MemberSize(8)}),
|
Member("c", ty.f32(), {MemberSize(8)}),
|
||||||
});
|
});
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.f32(), {MemberSize(4)}),
|
Member("a", ty.f32(), {MemberSize(4)}),
|
||||||
Member("b", ty.u32(), {MemberSize(8)}),
|
Member("b", ty.u32(), {MemberSize(8)}),
|
||||||
Member("c", inner),
|
Member("c", inner),
|
||||||
|
@ -334,7 +336,7 @@ TEST_F(ResolverStructLayoutTest, SizeDecorations) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 76u);
|
EXPECT_EQ(sem->Size(), 76u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 76u);
|
EXPECT_EQ(sem->SizeNoPadding(), 76u);
|
||||||
|
@ -355,12 +357,12 @@ TEST_F(ResolverStructLayoutTest, SizeDecorations) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStructLayoutTest, AlignDecorations) {
|
TEST_F(ResolverStructLayoutTest, AlignDecorations) {
|
||||||
auto inner = Structure("Inner", {
|
auto* inner = Structure("Inner", {
|
||||||
Member("a", ty.f32(), {MemberAlign(8)}),
|
Member("a", ty.f32(), {MemberAlign(8)}),
|
||||||
Member("b", ty.f32(), {MemberAlign(16)}),
|
Member("b", ty.f32(), {MemberAlign(16)}),
|
||||||
Member("c", ty.f32(), {MemberAlign(4)}),
|
Member("c", ty.f32(), {MemberAlign(4)}),
|
||||||
});
|
});
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.f32(), {MemberAlign(4)}),
|
Member("a", ty.f32(), {MemberAlign(4)}),
|
||||||
Member("b", ty.u32(), {MemberAlign(8)}),
|
Member("b", ty.u32(), {MemberAlign(8)}),
|
||||||
Member("c", inner),
|
Member("c", inner),
|
||||||
|
@ -369,7 +371,7 @@ TEST_F(ResolverStructLayoutTest, AlignDecorations) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 96u);
|
EXPECT_EQ(sem->Size(), 96u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 68u);
|
EXPECT_EQ(sem->SizeNoPadding(), 68u);
|
||||||
|
@ -390,13 +392,13 @@ TEST_F(ResolverStructLayoutTest, AlignDecorations) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) {
|
TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.i32(), {MemberAlign(1024)}),
|
Member("a", ty.i32(), {MemberAlign(1024)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_EQ(sem->Size(), 1024u);
|
EXPECT_EQ(sem->Size(), 1024u);
|
||||||
EXPECT_EQ(sem->SizeNoPadding(), 4u);
|
EXPECT_EQ(sem->SizeNoPadding(), 4u);
|
||||||
|
|
|
@ -28,41 +28,41 @@ namespace {
|
||||||
using ResolverPipelineStageUseTest = ResolverTest;
|
using ResolverPipelineStageUseTest = ResolverTest;
|
||||||
|
|
||||||
TEST_F(ResolverPipelineStageUseTest, UnusedStruct) {
|
TEST_F(ResolverPipelineStageUseTest, UnusedStruct) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_TRUE(sem->PipelineStageUses().empty());
|
EXPECT_TRUE(sem->PipelineStageUses().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointParam) {
|
TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointParam) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
||||||
|
|
||||||
Func("foo", {Param("param", s)}, ty.void_(), {}, {});
|
Func("foo", {Param("param", s)}, ty.void_(), {}, {});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_TRUE(sem->PipelineStageUses().empty());
|
EXPECT_TRUE(sem->PipelineStageUses().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointReturnType) {
|
TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointReturnType) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
||||||
|
|
||||||
Func("foo", {}, s, {Return(Construct(s, Expr(0.f)))}, {});
|
Func("foo", {}, s, {Return(Construct(s, Expr(0.f)))}, {});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_TRUE(sem->PipelineStageUses().empty());
|
EXPECT_TRUE(sem->PipelineStageUses().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderParam) {
|
TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderParam) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
||||||
|
|
||||||
Func("main", {Param("param", s)}, ty.vec4<f32>(),
|
Func("main", {Param("param", s)}, ty.vec4<f32>(),
|
||||||
{Return(Construct(ty.vec4<f32>()))},
|
{Return(Construct(ty.vec4<f32>()))},
|
||||||
|
@ -71,14 +71,14 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderParam) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->PipelineStageUses(),
|
EXPECT_THAT(sem->PipelineStageUses(),
|
||||||
UnorderedElementsAre(sem::PipelineStageUsage::kVertexInput));
|
UnorderedElementsAre(sem::PipelineStageUsage::kVertexInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) {
|
TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) {
|
||||||
auto s = Structure(
|
auto* s = Structure(
|
||||||
"S", {Member("a", ty.f32(), {Builtin(ast::Builtin::kPosition)})});
|
"S", {Member("a", ty.f32(), {Builtin(ast::Builtin::kPosition)})});
|
||||||
|
|
||||||
Func("main", {}, s, {Return(Construct(s, Expr(0.f)))},
|
Func("main", {}, s, {Return(Construct(s, Expr(0.f)))},
|
||||||
|
@ -86,42 +86,42 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderReturnType) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->PipelineStageUses(),
|
EXPECT_THAT(sem->PipelineStageUses(),
|
||||||
UnorderedElementsAre(sem::PipelineStageUsage::kVertexOutput));
|
UnorderedElementsAre(sem::PipelineStageUsage::kVertexOutput));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderParam) {
|
TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderParam) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
||||||
|
|
||||||
Func("main", {Param("param", s)}, ty.void_(), {},
|
Func("main", {Param("param", s)}, ty.void_(), {},
|
||||||
{Stage(ast::PipelineStage::kFragment)});
|
{Stage(ast::PipelineStage::kFragment)});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->PipelineStageUses(),
|
EXPECT_THAT(sem->PipelineStageUses(),
|
||||||
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput));
|
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderReturnType) {
|
TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderReturnType) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
||||||
|
|
||||||
Func("main", {}, s, {Return(Construct(s, Expr(0.f)))},
|
Func("main", {}, s, {Return(Construct(s, Expr(0.f)))},
|
||||||
{Stage(ast::PipelineStage::kFragment)});
|
{Stage(ast::PipelineStage::kFragment)});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->PipelineStageUses(),
|
EXPECT_THAT(sem->PipelineStageUses(),
|
||||||
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput));
|
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) {
|
TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) {
|
||||||
auto s = Structure(
|
auto* s = Structure(
|
||||||
"S",
|
"S",
|
||||||
{Member("a", ty.u32(), {Builtin(ast::Builtin::kLocalInvocationIndex)})});
|
{Member("a", ty.u32(), {Builtin(ast::Builtin::kLocalInvocationIndex)})});
|
||||||
|
|
||||||
|
@ -130,14 +130,14 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsComputeShaderParam) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->PipelineStageUses(),
|
EXPECT_THAT(sem->PipelineStageUses(),
|
||||||
UnorderedElementsAre(sem::PipelineStageUsage::kComputeInput));
|
UnorderedElementsAre(sem::PipelineStageUsage::kComputeInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
|
TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
|
||||||
auto s = Structure(
|
auto* s = Structure(
|
||||||
"S", {Member("a", ty.f32(), {Builtin(ast::Builtin::kPosition)})});
|
"S", {Member("a", ty.f32(), {Builtin(ast::Builtin::kPosition)})});
|
||||||
|
|
||||||
Func("vert_main", {Param("param", s)}, s, {Return(Construct(s, Expr(0.f)))},
|
Func("vert_main", {Param("param", s)}, s, {Return(Construct(s, Expr(0.f)))},
|
||||||
|
@ -148,7 +148,7 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->PipelineStageUses(),
|
EXPECT_THAT(sem->PipelineStageUses(),
|
||||||
UnorderedElementsAre(sem::PipelineStageUsage::kVertexInput,
|
UnorderedElementsAre(sem::PipelineStageUsage::kVertexInput,
|
||||||
|
@ -157,7 +157,7 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedMultipleStages) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamViaAlias) {
|
TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamViaAlias) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
||||||
auto s_alias = ty.alias("S_alias", s);
|
auto s_alias = ty.alias("S_alias", s);
|
||||||
AST().AddConstructedType(s_alias);
|
AST().AddConstructedType(s_alias);
|
||||||
|
|
||||||
|
@ -166,14 +166,14 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamViaAlias) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->PipelineStageUses(),
|
EXPECT_THAT(sem->PipelineStageUses(),
|
||||||
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput));
|
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderReturnTypeViaAlias) {
|
TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderReturnTypeViaAlias) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
|
||||||
auto s_alias = ty.alias("S_alias", s);
|
auto s_alias = ty.alias("S_alias", s);
|
||||||
AST().AddConstructedType(s_alias);
|
AST().AddConstructedType(s_alias);
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderReturnTypeViaAlias) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->PipelineStageUses(),
|
EXPECT_THAT(sem->PipelineStageUses(),
|
||||||
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput));
|
UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput));
|
||||||
|
|
|
@ -28,149 +28,149 @@ namespace {
|
||||||
using ResolverStorageClassUseTest = ResolverTest;
|
using ResolverStorageClassUseTest = ResolverTest;
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, UnreachableStruct) {
|
TEST_F(ResolverStorageClassUseTest, UnreachableStruct) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_TRUE(sem->StorageClassUsage().empty());
|
EXPECT_TRUE(sem->StorageClassUsage().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableFromParameter) {
|
TEST_F(ResolverStorageClassUseTest, StructReachableFromParameter) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
|
|
||||||
Func("f", {Param("param", s)}, ty.void_(), {}, {});
|
Func("f", {Param("param", s)}, ty.void_(), {}, {});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(),
|
EXPECT_THAT(sem->StorageClassUsage(),
|
||||||
UnorderedElementsAre(ast::StorageClass::kNone));
|
UnorderedElementsAre(ast::StorageClass::kNone));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableFromReturnType) {
|
TEST_F(ResolverStorageClassUseTest, StructReachableFromReturnType) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
|
|
||||||
Func("f", {}, s, {Return(Construct(s))}, {});
|
Func("f", {}, s, {Return(Construct(s))}, {});
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(),
|
EXPECT_THAT(sem->StorageClassUsage(),
|
||||||
UnorderedElementsAre(ast::StorageClass::kNone));
|
UnorderedElementsAre(ast::StorageClass::kNone));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableFromGlobal) {
|
TEST_F(ResolverStorageClassUseTest, StructReachableFromGlobal) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
|
|
||||||
Global("g", s, ast::StorageClass::kPrivate);
|
Global("g", s, ast::StorageClass::kPrivate);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(),
|
EXPECT_THAT(sem->StorageClassUsage(),
|
||||||
UnorderedElementsAre(ast::StorageClass::kPrivate));
|
UnorderedElementsAre(ast::StorageClass::kPrivate));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalAlias) {
|
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalAlias) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
auto a = ty.alias("A", s);
|
auto a = ty.alias("A", s);
|
||||||
AST().AddConstructedType(a);
|
AST().AddConstructedType(a);
|
||||||
Global("g", a, ast::StorageClass::kPrivate);
|
Global("g", a, ast::StorageClass::kPrivate);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(),
|
EXPECT_THAT(sem->StorageClassUsage(),
|
||||||
UnorderedElementsAre(ast::StorageClass::kPrivate));
|
UnorderedElementsAre(ast::StorageClass::kPrivate));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalStruct) {
|
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalStruct) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
auto o = Structure("O", {Member("a", s)});
|
auto* o = Structure("O", {Member("a", s)});
|
||||||
Global("g", o, ast::StorageClass::kPrivate);
|
Global("g", o, ast::StorageClass::kPrivate);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(),
|
EXPECT_THAT(sem->StorageClassUsage(),
|
||||||
UnorderedElementsAre(ast::StorageClass::kPrivate));
|
UnorderedElementsAre(ast::StorageClass::kPrivate));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalArray) {
|
TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalArray) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
auto a = ty.array(s, 3);
|
auto a = ty.array(s, 3);
|
||||||
Global("g", a, ast::StorageClass::kPrivate);
|
Global("g", a, ast::StorageClass::kPrivate);
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(),
|
EXPECT_THAT(sem->StorageClassUsage(),
|
||||||
UnorderedElementsAre(ast::StorageClass::kPrivate));
|
UnorderedElementsAre(ast::StorageClass::kPrivate));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableFromLocal) {
|
TEST_F(ResolverStorageClassUseTest, StructReachableFromLocal) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
|
|
||||||
WrapInFunction(Var("g", s, ast::StorageClass::kFunction));
|
WrapInFunction(Var("g", s, ast::StorageClass::kFunction));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(),
|
EXPECT_THAT(sem->StorageClassUsage(),
|
||||||
UnorderedElementsAre(ast::StorageClass::kFunction));
|
UnorderedElementsAre(ast::StorageClass::kFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalAlias) {
|
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalAlias) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
auto a = ty.alias("A", s);
|
auto a = ty.alias("A", s);
|
||||||
AST().AddConstructedType(a);
|
AST().AddConstructedType(a);
|
||||||
WrapInFunction(Var("g", a, ast::StorageClass::kFunction));
|
WrapInFunction(Var("g", a, ast::StorageClass::kFunction));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(),
|
EXPECT_THAT(sem->StorageClassUsage(),
|
||||||
UnorderedElementsAre(ast::StorageClass::kFunction));
|
UnorderedElementsAre(ast::StorageClass::kFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalStruct) {
|
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalStruct) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
auto o = Structure("O", {Member("a", s)});
|
auto* o = Structure("O", {Member("a", s)});
|
||||||
WrapInFunction(Var("g", o, ast::StorageClass::kFunction));
|
WrapInFunction(Var("g", o, ast::StorageClass::kFunction));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(),
|
EXPECT_THAT(sem->StorageClassUsage(),
|
||||||
UnorderedElementsAre(ast::StorageClass::kFunction));
|
UnorderedElementsAre(ast::StorageClass::kFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalArray) {
|
TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalArray) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
auto a = ty.array(s, 3);
|
auto a = ty.array(s, 3);
|
||||||
WrapInFunction(Var("g", a, ast::StorageClass::kFunction));
|
WrapInFunction(Var("g", a, ast::StorageClass::kFunction));
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(),
|
EXPECT_THAT(sem->StorageClassUsage(),
|
||||||
UnorderedElementsAre(ast::StorageClass::kFunction));
|
UnorderedElementsAre(ast::StorageClass::kFunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
|
TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
|
||||||
auto s = Structure("S", {Member("a", ty.f32())},
|
auto* s = Structure("S", {Member("a", ty.f32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
Global("x", s, ast::StorageClass::kUniform);
|
Global("x", s, ast::StorageClass::kUniform);
|
||||||
|
@ -179,7 +179,7 @@ TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
|
||||||
|
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
auto* sem = Sem().Get(s.sem);
|
auto* sem = TypeOf(s)->As<sem::Struct>();
|
||||||
ASSERT_NE(sem, nullptr);
|
ASSERT_NE(sem, nullptr);
|
||||||
EXPECT_THAT(sem->StorageClassUsage(),
|
EXPECT_THAT(sem->StorageClassUsage(),
|
||||||
UnorderedElementsAre(ast::StorageClass::kUniform,
|
UnorderedElementsAre(ast::StorageClass::kUniform,
|
||||||
|
|
|
@ -44,7 +44,7 @@ TEST_F(AccessControlTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_FALSE(ty->Is<Texture>());
|
EXPECT_FALSE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -40,7 +40,7 @@ TEST_F(AliasTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_FALSE(ty->Is<Texture>());
|
EXPECT_FALSE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -54,7 +54,7 @@ TEST_F(ArrayTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_FALSE(ty->Is<Texture>());
|
EXPECT_FALSE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -34,7 +34,7 @@ TEST_F(BoolTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_FALSE(ty->Is<Texture>());
|
EXPECT_FALSE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -39,7 +39,7 @@ TEST_F(DepthTextureTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_TRUE(ty->Is<Texture>());
|
EXPECT_TRUE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -40,7 +40,7 @@ TEST_F(ExternalTextureTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_TRUE(ty->Is<Texture>());
|
EXPECT_TRUE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -34,7 +34,7 @@ TEST_F(F32Test, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_FALSE(ty->Is<Texture>());
|
EXPECT_FALSE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -34,7 +34,7 @@ TEST_F(I32Test, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_FALSE(ty->Is<Texture>());
|
EXPECT_FALSE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -45,7 +45,7 @@ TEST_F(MatrixTest, Is) {
|
||||||
EXPECT_TRUE(ty->Is<Matrix>());
|
EXPECT_TRUE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_FALSE(ty->Is<Texture>());
|
EXPECT_FALSE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -40,7 +40,7 @@ TEST_F(MultisampledTextureTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_TRUE(ty->Is<Texture>());
|
EXPECT_TRUE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -42,7 +42,7 @@ TEST_F(PointerTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_TRUE(ty->Is<Pointer>());
|
EXPECT_TRUE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_FALSE(ty->Is<Texture>());
|
EXPECT_FALSE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -39,7 +39,7 @@ TEST_F(SampledTextureTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_TRUE(ty->Is<Texture>());
|
EXPECT_TRUE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -45,7 +45,7 @@ TEST_F(SamplerTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_TRUE(ty->Is<Sampler>());
|
EXPECT_TRUE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_FALSE(ty->Is<Texture>());
|
EXPECT_FALSE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "src/sem/access_control_type.h"
|
#include "src/sem/access_control_type.h"
|
||||||
|
#include "src/sem/struct.h"
|
||||||
#include "src/sem/test_helper.h"
|
#include "src/sem/test_helper.h"
|
||||||
#include "src/sem/texture_type.h"
|
#include "src/sem/texture_type.h"
|
||||||
|
|
||||||
|
@ -20,22 +21,27 @@ namespace tint {
|
||||||
namespace sem {
|
namespace sem {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using StructTypeTest = TestHelper;
|
using StructTest = TestHelper;
|
||||||
|
|
||||||
TEST_F(StructTypeTest, Creation) {
|
TEST_F(StructTest, Creation) {
|
||||||
auto name = Sym("S");
|
auto name = Sym("S");
|
||||||
auto* impl =
|
auto* impl =
|
||||||
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
|
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
|
||||||
auto* ptr = impl;
|
auto* ptr = impl;
|
||||||
auto s = ty.struct_(impl);
|
auto* s = create<sem::Struct>(impl, StructMemberList{}, 4 /* align */,
|
||||||
EXPECT_EQ(s->impl(), ptr);
|
8 /* size */, 16 /* size_no_padding */);
|
||||||
|
EXPECT_EQ(s->Declaration(), ptr);
|
||||||
|
EXPECT_EQ(s->Align(), 4u);
|
||||||
|
EXPECT_EQ(s->Size(), 8u);
|
||||||
|
EXPECT_EQ(s->SizeNoPadding(), 16u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StructTypeTest, Is) {
|
TEST_F(StructTest, Is) {
|
||||||
auto name = Sym("S");
|
auto name = Sym("S");
|
||||||
auto* impl =
|
auto* impl =
|
||||||
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
|
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
|
||||||
auto s = ty.struct_(impl);
|
auto* s = create<sem::Struct>(impl, StructMemberList{}, 4 /* align */,
|
||||||
|
4 /* size */, 4 /* size_no_padding */);
|
||||||
sem::Type* ty = s;
|
sem::Type* ty = s;
|
||||||
EXPECT_FALSE(ty->Is<AccessControl>());
|
EXPECT_FALSE(ty->Is<AccessControl>());
|
||||||
EXPECT_FALSE(ty->Is<Alias>());
|
EXPECT_FALSE(ty->Is<Alias>());
|
||||||
|
@ -46,25 +52,27 @@ TEST_F(StructTypeTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_TRUE(ty->Is<StructType>());
|
EXPECT_TRUE(ty->Is<Struct>());
|
||||||
EXPECT_FALSE(ty->Is<Texture>());
|
EXPECT_FALSE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StructTypeTest, TypeName) {
|
TEST_F(StructTest, TypeName) {
|
||||||
auto name = Sym("my_struct");
|
auto name = Sym("my_struct");
|
||||||
auto* impl =
|
auto* impl =
|
||||||
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
|
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
|
||||||
auto s = ty.struct_(impl);
|
auto* s = create<sem::Struct>(impl, StructMemberList{}, 4 /* align */,
|
||||||
|
4 /* size */, 4 /* size_no_padding */);
|
||||||
EXPECT_EQ(s->type_name(), "__struct_$1");
|
EXPECT_EQ(s->type_name(), "__struct_$1");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(StructTypeTest, FriendlyName) {
|
TEST_F(StructTest, FriendlyName) {
|
||||||
auto name = Sym("my_struct");
|
auto name = Sym("my_struct");
|
||||||
auto* impl =
|
auto* impl =
|
||||||
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
|
create<ast::Struct>(name, ast::StructMemberList{}, ast::DecorationList{});
|
||||||
auto s = ty.struct_(impl);
|
auto* s = create<sem::Struct>(impl, StructMemberList{}, 4 /* align */,
|
||||||
|
4 /* size */, 4 /* size_no_padding */);
|
||||||
EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct");
|
EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct");
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ TEST_F(StorageTextureTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_TRUE(ty->Is<Texture>());
|
EXPECT_TRUE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "src/sem/struct.h"
|
#include "src/sem/struct.h"
|
||||||
#include "src/ast/struct_member.h"
|
#include "src/ast/struct_member.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
TINT_INSTANTIATE_TYPEINFO(tint::sem::Struct);
|
TINT_INSTANTIATE_TYPEINFO(tint::sem::Struct);
|
||||||
|
@ -23,20 +24,16 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::StructMember);
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace sem {
|
namespace sem {
|
||||||
|
|
||||||
Struct::Struct(sem::StructType* type,
|
Struct::Struct(const ast::Struct* declaration,
|
||||||
StructMemberList members,
|
StructMemberList members,
|
||||||
uint32_t align,
|
uint32_t align,
|
||||||
uint32_t size,
|
uint32_t size,
|
||||||
uint32_t size_no_padding,
|
uint32_t size_no_padding)
|
||||||
std::unordered_set<ast::StorageClass> storage_class_usage,
|
: declaration_(declaration),
|
||||||
std::unordered_set<PipelineStageUsage> pipeline_stage_uses)
|
|
||||||
: type_(type),
|
|
||||||
members_(std::move(members)),
|
members_(std::move(members)),
|
||||||
align_(align),
|
align_(align),
|
||||||
size_(size),
|
size_(size),
|
||||||
size_no_padding_(size_no_padding),
|
size_no_padding_(size_no_padding) {}
|
||||||
storage_class_usage_(std::move(storage_class_usage)),
|
|
||||||
pipeline_stage_uses_(std::move(pipeline_stage_uses)) {}
|
|
||||||
|
|
||||||
Struct::~Struct() = default;
|
Struct::~Struct() = default;
|
||||||
|
|
||||||
|
@ -49,6 +46,14 @@ const StructMember* Struct::FindMember(Symbol name) const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Struct::type_name() const {
|
||||||
|
return declaration_->type_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Struct::FriendlyName(const SymbolTable& symbols) const {
|
||||||
|
return declaration_->FriendlyName(symbols);
|
||||||
|
}
|
||||||
|
|
||||||
StructMember::StructMember(ast::StructMember* declaration,
|
StructMember::StructMember(ast::StructMember* declaration,
|
||||||
sem::Type* type,
|
sem::Type* type,
|
||||||
uint32_t offset,
|
uint32_t offset,
|
||||||
|
|
|
@ -17,11 +17,14 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "src/ast/storage_class.h"
|
#include "src/ast/storage_class.h"
|
||||||
|
#include "src/ast/struct.h"
|
||||||
#include "src/sem/node.h"
|
#include "src/sem/node.h"
|
||||||
|
#include "src/sem/type.h"
|
||||||
#include "src/symbol.h"
|
#include "src/symbol.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -34,7 +37,6 @@ class StructMember;
|
||||||
namespace sem {
|
namespace sem {
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
class StructType;
|
|
||||||
class StructMember;
|
class StructMember;
|
||||||
class Type;
|
class Type;
|
||||||
|
|
||||||
|
@ -52,30 +54,26 @@ enum class PipelineStageUsage {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Struct holds the semantic information for structures.
|
/// Struct holds the semantic information for structures.
|
||||||
class Struct : public Castable<Struct, Node> {
|
class Struct : public Castable<Struct, Type> {
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param type the structure type
|
/// @param declaration the AST structure declaration
|
||||||
/// @param members the structure members
|
/// @param members the structure members
|
||||||
/// @param align the byte alignment of the structure
|
/// @param align the byte alignment of the structure
|
||||||
/// @param size the byte size of the structure
|
/// @param size the byte size of the structure
|
||||||
/// @param size_no_padding size of the members without the end of structure
|
/// @param size_no_padding size of the members without the end of structure
|
||||||
/// alignment padding
|
/// alignment padding
|
||||||
/// @param storage_class_usage a set of all the storage class usages
|
Struct(const ast::Struct* declaration,
|
||||||
/// @param pipeline_stage_uses a set of all the pipeline stage uses
|
|
||||||
Struct(sem::StructType* type,
|
|
||||||
StructMemberList members,
|
StructMemberList members,
|
||||||
uint32_t align,
|
uint32_t align,
|
||||||
uint32_t size,
|
uint32_t size,
|
||||||
uint32_t size_no_padding,
|
uint32_t size_no_padding);
|
||||||
std::unordered_set<ast::StorageClass> storage_class_usage,
|
|
||||||
std::unordered_set<PipelineStageUsage> pipeline_stage_uses);
|
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Struct() override;
|
~Struct() override;
|
||||||
|
|
||||||
/// @returns the structure type
|
/// @returns the struct
|
||||||
sem::StructType* Type() const { return type_; }
|
const ast::Struct* Declaration() const { return declaration_; }
|
||||||
|
|
||||||
/// @returns the members of the structure
|
/// @returns the members of the structure
|
||||||
const StructMemberList& Members() const { return members_; }
|
const StructMemberList& Members() const { return members_; }
|
||||||
|
@ -100,6 +98,12 @@ class Struct : public Castable<Struct, Node> {
|
||||||
/// alignment padding
|
/// alignment padding
|
||||||
uint32_t SizeNoPadding() const { return size_no_padding_; }
|
uint32_t SizeNoPadding() const { return size_no_padding_; }
|
||||||
|
|
||||||
|
/// Adds the StorageClass usage to the structure.
|
||||||
|
/// @param usage the storage usage
|
||||||
|
void AddUsage(ast::StorageClass usage) {
|
||||||
|
storage_class_usage_.emplace(usage);
|
||||||
|
}
|
||||||
|
|
||||||
/// @returns the set of storage class uses of this structure
|
/// @returns the set of storage class uses of this structure
|
||||||
const std::unordered_set<ast::StorageClass>& StorageClassUsage() const {
|
const std::unordered_set<ast::StorageClass>& StorageClassUsage() const {
|
||||||
return storage_class_usage_;
|
return storage_class_usage_;
|
||||||
|
@ -122,19 +126,38 @@ class Struct : public Castable<Struct, Node> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds the pipeline stage usage to the structure.
|
||||||
|
/// @param usage the storage usage
|
||||||
|
void AddUsage(PipelineStageUsage usage) {
|
||||||
|
pipeline_stage_uses_.emplace(usage);
|
||||||
|
}
|
||||||
|
|
||||||
/// @returns the set of entry point uses of this structure
|
/// @returns the set of entry point uses of this structure
|
||||||
const std::unordered_set<PipelineStageUsage>& PipelineStageUses() const {
|
const std::unordered_set<PipelineStageUsage>& PipelineStageUses() const {
|
||||||
return pipeline_stage_uses_;
|
return pipeline_stage_uses_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @returns true if the struct has a block decoration
|
||||||
|
bool IsBlockDecorated() const { return declaration_->IsBlockDecorated(); }
|
||||||
|
|
||||||
|
/// @returns the name for the type
|
||||||
|
std::string type_name() const override;
|
||||||
|
|
||||||
|
/// @param symbols the program's symbol table
|
||||||
|
/// @returns the name for this type that closely resembles how it would be
|
||||||
|
/// declared in WGSL.
|
||||||
|
std::string FriendlyName(const SymbolTable& symbols) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sem::StructType* const type_;
|
uint64_t LargestMemberBaseAlignment(MemoryLayout mem_layout) const;
|
||||||
|
|
||||||
|
ast::Struct const* const declaration_;
|
||||||
StructMemberList const members_;
|
StructMemberList const members_;
|
||||||
uint32_t const align_;
|
uint32_t const align_;
|
||||||
uint32_t const size_;
|
uint32_t const size_;
|
||||||
uint32_t const size_no_padding_;
|
uint32_t const size_no_padding_;
|
||||||
std::unordered_set<ast::StorageClass> const storage_class_usage_;
|
std::unordered_set<ast::StorageClass> storage_class_usage_;
|
||||||
std::unordered_set<PipelineStageUsage> const pipeline_stage_uses_;
|
std::unordered_set<PipelineStageUsage> pipeline_stage_uses_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// StructMember holds the semantic information for structure members.
|
/// StructMember holds the semantic information for structure members.
|
||||||
|
|
|
@ -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 MemberAccessorExpression;
|
||||||
class Statement;
|
class Statement;
|
||||||
class Struct;
|
class Struct;
|
||||||
class StructType;
|
|
||||||
class StructMember;
|
class StructMember;
|
||||||
class Type;
|
class Type;
|
||||||
class Variable;
|
class Variable;
|
||||||
|
@ -58,7 +57,6 @@ struct TypeMappings {
|
||||||
Function* operator()(ast::Function*);
|
Function* operator()(ast::Function*);
|
||||||
MemberAccessorExpression* operator()(ast::MemberAccessorExpression*);
|
MemberAccessorExpression* operator()(ast::MemberAccessorExpression*);
|
||||||
Statement* operator()(ast::Statement*);
|
Statement* operator()(ast::Statement*);
|
||||||
Struct* operator()(sem::StructType*);
|
|
||||||
StructMember* operator()(ast::StructMember*);
|
StructMember* operator()(ast::StructMember*);
|
||||||
Type* operator()(ast::Type*);
|
Type* operator()(ast::Type*);
|
||||||
Variable* operator()(ast::Variable*);
|
Variable* operator()(ast::Variable*);
|
||||||
|
|
|
@ -34,7 +34,7 @@ TEST_F(U32Test, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_FALSE(ty->Is<Texture>());
|
EXPECT_FALSE(ty->Is<Texture>());
|
||||||
EXPECT_TRUE(ty->Is<U32>());
|
EXPECT_TRUE(ty->Is<U32>());
|
||||||
EXPECT_FALSE(ty->Is<Vector>());
|
EXPECT_FALSE(ty->Is<Vector>());
|
||||||
|
|
|
@ -42,7 +42,7 @@ TEST_F(VectorTest, Is) {
|
||||||
EXPECT_FALSE(ty->Is<Matrix>());
|
EXPECT_FALSE(ty->Is<Matrix>());
|
||||||
EXPECT_FALSE(ty->Is<Pointer>());
|
EXPECT_FALSE(ty->Is<Pointer>());
|
||||||
EXPECT_FALSE(ty->Is<Sampler>());
|
EXPECT_FALSE(ty->Is<Sampler>());
|
||||||
EXPECT_FALSE(ty->Is<StructType>());
|
EXPECT_FALSE(ty->Is<Struct>());
|
||||||
EXPECT_FALSE(ty->Is<Texture>());
|
EXPECT_FALSE(ty->Is<Texture>());
|
||||||
EXPECT_FALSE(ty->Is<U32>());
|
EXPECT_FALSE(ty->Is<U32>());
|
||||||
EXPECT_TRUE(ty->Is<Vector>());
|
EXPECT_TRUE(ty->Is<Vector>());
|
||||||
|
|
|
@ -77,12 +77,12 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
||||||
// get_buffer_size_intrinsic() emits the function decorated with
|
// get_buffer_size_intrinsic() emits the function decorated with
|
||||||
// BufferSizeIntrinsic that is transformed by the HLSL writer into a call to
|
// BufferSizeIntrinsic that is transformed by the HLSL writer into a call to
|
||||||
// [RW]ByteAddressBuffer.GetDimensions().
|
// [RW]ByteAddressBuffer.GetDimensions().
|
||||||
std::unordered_map<sem::StructType*, Symbol> buffer_size_intrinsics;
|
std::unordered_map<sem::Struct*, Symbol> buffer_size_intrinsics;
|
||||||
auto get_buffer_size_intrinsic = [&](sem::StructType* buffer_type) {
|
auto get_buffer_size_intrinsic = [&](sem::Struct* buffer_type) {
|
||||||
return utils::GetOrCreate(buffer_size_intrinsics, buffer_type, [&] {
|
return utils::GetOrCreate(buffer_size_intrinsics, buffer_type, [&] {
|
||||||
auto name = ctx.dst->Sym();
|
auto name = ctx.dst->Sym();
|
||||||
auto* buffer_typename =
|
auto* buffer_typename =
|
||||||
ctx.dst->ty.type_name(ctx.Clone(buffer_type->impl()->name()));
|
ctx.dst->ty.type_name(ctx.Clone(buffer_type->Declaration()->name()));
|
||||||
auto* func = ctx.dst->create<ast::Function>(
|
auto* func = ctx.dst->create<ast::Function>(
|
||||||
name,
|
name,
|
||||||
ast::VariableList{
|
ast::VariableList{
|
||||||
|
@ -100,8 +100,8 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
||||||
ctx.dst->ASTNodes().Create<BufferSizeIntrinsic>(ctx.dst->ID()),
|
ctx.dst->ASTNodes().Create<BufferSizeIntrinsic>(ctx.dst->ID()),
|
||||||
},
|
},
|
||||||
ast::DecorationList{});
|
ast::DecorationList{});
|
||||||
ctx.InsertAfter(ctx.src->AST().GlobalDeclarations(), buffer_type->impl(),
|
ctx.InsertAfter(ctx.src->AST().GlobalDeclarations(),
|
||||||
func);
|
buffer_type->Declaration(), func);
|
||||||
return name;
|
return name;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -141,7 +141,7 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
||||||
auto* storage_buffer_expr = accessor->structure();
|
auto* storage_buffer_expr = accessor->structure();
|
||||||
auto* storage_buffer_sem = sem.Get(storage_buffer_expr);
|
auto* storage_buffer_sem = sem.Get(storage_buffer_expr);
|
||||||
auto* storage_buffer_type =
|
auto* storage_buffer_type =
|
||||||
storage_buffer_sem->Type()->UnwrapAll()->As<sem::StructType>();
|
storage_buffer_sem->Type()->UnwrapAll()->As<sem::Struct>();
|
||||||
|
|
||||||
// Generate BufferSizeIntrinsic for this storage type if we haven't
|
// Generate BufferSizeIntrinsic for this storage type if we haven't
|
||||||
// already
|
// already
|
||||||
|
@ -149,7 +149,7 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
||||||
|
|
||||||
if (!storage_buffer_type) {
|
if (!storage_buffer_type) {
|
||||||
TINT_ICE(ctx.dst->Diagnostics())
|
TINT_ICE(ctx.dst->Diagnostics())
|
||||||
<< "arrayLength(X.Y) expected X to be sem::StructType, got "
|
<< "arrayLength(X.Y) expected X to be sem::Struct, got "
|
||||||
<< storage_buffer_type->FriendlyName(ctx.src->Symbols());
|
<< storage_buffer_type->FriendlyName(ctx.src->Symbols());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -176,12 +176,8 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
|
||||||
// First time this array length is used for this block.
|
// First time this array length is used for this block.
|
||||||
// Let's calculate it.
|
// Let's calculate it.
|
||||||
|
|
||||||
// Semantic info for the storage buffer structure
|
|
||||||
auto* storage_buffer_type_sem =
|
|
||||||
ctx.src->Sem().Get(storage_buffer_type);
|
|
||||||
// Semantic info for the runtime array structure member
|
// Semantic info for the runtime array structure member
|
||||||
auto* array_member_sem =
|
auto* array_member_sem = storage_buffer_type->Members().back();
|
||||||
storage_buffer_type_sem->Members().back();
|
|
||||||
|
|
||||||
// Construct the variable that'll hold the result of
|
// Construct the variable that'll hold the result of
|
||||||
// RWByteAddressBuffer.GetDimensions()
|
// RWByteAddressBuffer.GetDimensions()
|
||||||
|
|
|
@ -110,12 +110,11 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
||||||
|
|
||||||
std::function<ast::Expression*()> func_const_initializer;
|
std::function<ast::Expression*()> func_const_initializer;
|
||||||
|
|
||||||
if (auto* struct_ty = param_ty->As<sem::StructType>()) {
|
if (auto* str = param_ty->As<sem::Struct>()) {
|
||||||
auto* str = ctx.src->Sem().Get(struct_ty);
|
|
||||||
// Pull out all struct members and build initializer list.
|
// Pull out all struct members and build initializer list.
|
||||||
std::vector<Symbol> member_names;
|
std::vector<Symbol> member_names;
|
||||||
for (auto* member : str->Members()) {
|
for (auto* member : str->Members()) {
|
||||||
if (member->Type()->UnwrapAll()->Is<sem::StructType>()) {
|
if (member->Type()->UnwrapAll()->Is<sem::Struct>()) {
|
||||||
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
|
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,11 +201,10 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
||||||
} else {
|
} else {
|
||||||
ast::StructMemberList new_struct_members;
|
ast::StructMemberList new_struct_members;
|
||||||
|
|
||||||
if (auto* struct_ty = ret_type->As<sem::StructType>()) {
|
if (auto* str = ret_type->As<sem::Struct>()) {
|
||||||
auto* str = ctx.src->Sem().Get(struct_ty);
|
|
||||||
// Rebuild struct with only the entry point IO attributes.
|
// Rebuild struct with only the entry point IO attributes.
|
||||||
for (auto* member : str->Members()) {
|
for (auto* member : str->Members()) {
|
||||||
if (member->Type()->UnwrapAll()->Is<sem::StructType>()) {
|
if (member->Type()->UnwrapAll()->Is<sem::Struct>()) {
|
||||||
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
|
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +249,7 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
|
||||||
};
|
};
|
||||||
|
|
||||||
ast::ExpressionList ret_values;
|
ast::ExpressionList ret_values;
|
||||||
if (ret_type->Is<sem::StructType>()) {
|
if (ret_type->Is<sem::Struct>()) {
|
||||||
if (!ret->value()->Is<ast::IdentifierExpression>()) {
|
if (!ret->value()->Is<ast::IdentifierExpression>()) {
|
||||||
// Create a const to hold the return value expression to avoid
|
// Create a const to hold the return value expression to avoid
|
||||||
// re-evaluating it multiple times.
|
// re-evaluating it multiple times.
|
||||||
|
|
|
@ -331,7 +331,7 @@ void InsertGlobal(CloneContext& ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns the unwrapped, user-declared constructed type of ty.
|
/// @returns the unwrapped, user-declared constructed type of ty.
|
||||||
ast::NamedType* ConstructedTypeOf(sem::Type* ty) {
|
const ast::NamedType* ConstructedTypeOf(sem::Type* ty) {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (auto* ptr = ty->As<sem::Pointer>()) {
|
if (auto* ptr = ty->As<sem::Pointer>()) {
|
||||||
ty = ptr->type();
|
ty = ptr->type();
|
||||||
|
@ -341,8 +341,8 @@ ast::NamedType* ConstructedTypeOf(sem::Type* ty) {
|
||||||
ty = access->type();
|
ty = access->type();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (auto* str = ty->As<sem::StructType>()) {
|
if (auto* str = ty->As<sem::Struct>()) {
|
||||||
return str->impl();
|
return str->Declaration();
|
||||||
}
|
}
|
||||||
// Not a constructed type
|
// Not a constructed type
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -421,7 +421,7 @@ struct DecomposeStorageAccess::State {
|
||||||
/// @param el_ty the storage buffer element type
|
/// @param el_ty the storage buffer element type
|
||||||
/// @return the name of the function that performs the load
|
/// @return the name of the function that performs the load
|
||||||
Symbol LoadFunc(CloneContext& ctx,
|
Symbol LoadFunc(CloneContext& ctx,
|
||||||
ast::NamedType* insert_after,
|
const ast::NamedType* insert_after,
|
||||||
sem::Type* buf_ty,
|
sem::Type* buf_ty,
|
||||||
sem::Type* el_ty) {
|
sem::Type* el_ty) {
|
||||||
return utils::GetOrCreate(load_funcs, TypePair{buf_ty, el_ty}, [&] {
|
return utils::GetOrCreate(load_funcs, TypePair{buf_ty, el_ty}, [&] {
|
||||||
|
@ -451,9 +451,7 @@ struct DecomposeStorageAccess::State {
|
||||||
ctx.dst->Add("offset", i * MatrixColumnStride(mat_ty));
|
ctx.dst->Add("offset", i * MatrixColumnStride(mat_ty));
|
||||||
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
|
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
|
||||||
}
|
}
|
||||||
} else if (auto* str_ty = el_ty->As<sem::StructType>()) {
|
} else if (auto* str = el_ty->As<sem::Struct>()) {
|
||||||
auto& sem = ctx.src->Sem();
|
|
||||||
auto* str = sem.Get(str_ty);
|
|
||||||
for (auto* member : str->Members()) {
|
for (auto* member : str->Members()) {
|
||||||
auto* offset = ctx.dst->Add("offset", member->Offset());
|
auto* offset = ctx.dst->Add("offset", member->Offset());
|
||||||
Symbol load = LoadFunc(ctx, insert_after, buf_ty,
|
Symbol load = LoadFunc(ctx, insert_after, buf_ty,
|
||||||
|
@ -492,7 +490,7 @@ struct DecomposeStorageAccess::State {
|
||||||
/// @param el_ty the storage buffer element type
|
/// @param el_ty the storage buffer element type
|
||||||
/// @return the name of the function that performs the store
|
/// @return the name of the function that performs the store
|
||||||
Symbol StoreFunc(CloneContext& ctx,
|
Symbol StoreFunc(CloneContext& ctx,
|
||||||
ast::NamedType* insert_after,
|
const ast::NamedType* insert_after,
|
||||||
sem::Type* buf_ty,
|
sem::Type* buf_ty,
|
||||||
sem::Type* el_ty) {
|
sem::Type* el_ty) {
|
||||||
return utils::GetOrCreate(store_funcs, TypePair{buf_ty, el_ty}, [&] {
|
return utils::GetOrCreate(store_funcs, TypePair{buf_ty, el_ty}, [&] {
|
||||||
|
@ -525,9 +523,7 @@ struct DecomposeStorageAccess::State {
|
||||||
auto* call = ctx.dst->Call(store, "buffer", offset, access);
|
auto* call = ctx.dst->Call(store, "buffer", offset, access);
|
||||||
body.emplace_back(ctx.dst->create<ast::CallStatement>(call));
|
body.emplace_back(ctx.dst->create<ast::CallStatement>(call));
|
||||||
}
|
}
|
||||||
} else if (auto* str_ty = el_ty->As<sem::StructType>()) {
|
} else if (auto* str = el_ty->As<sem::Struct>()) {
|
||||||
auto& sem = ctx.src->Sem();
|
|
||||||
auto* str = sem.Get(str_ty);
|
|
||||||
for (auto* member : str->Members()) {
|
for (auto* member : str->Members()) {
|
||||||
auto* offset = ctx.dst->Add("offset", member->Offset());
|
auto* offset = ctx.dst->Add("offset", member->Offset());
|
||||||
auto* access = ctx.dst->MemberAccessor(
|
auto* access = ctx.dst->MemberAccessor(
|
||||||
|
@ -676,9 +672,8 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (auto access = state.TakeAccess(accessor->structure())) {
|
if (auto access = state.TakeAccess(accessor->structure())) {
|
||||||
auto* str_ty = access.type->As<sem::StructType>();
|
auto* str_ty = access.type->As<sem::Struct>();
|
||||||
auto* member =
|
auto* member = str_ty->FindMember(accessor->member()->symbol());
|
||||||
sem.Get(str_ty)->FindMember(accessor->member()->symbol());
|
|
||||||
auto offset = member->Offset();
|
auto offset = member->Offset();
|
||||||
state.AddAccess(accessor,
|
state.AddAccess(accessor,
|
||||||
{
|
{
|
||||||
|
|
|
@ -133,7 +133,7 @@ Output FirstIndexOffset::Run(const Program* in, const DataMap& data) {
|
||||||
instance_index_offset = offset;
|
instance_index_offset = offset;
|
||||||
offset += 4;
|
offset += 4;
|
||||||
}
|
}
|
||||||
auto struct_type =
|
auto* struct_type =
|
||||||
ctx.dst->Structure(ctx.dst->Sym(), std::move(members),
|
ctx.dst->Structure(ctx.dst->Sym(), std::move(members),
|
||||||
{ctx.dst->create<ast::StructBlockDecoration>()});
|
{ctx.dst->create<ast::StructBlockDecoration>()});
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ void Hlsl::PromoteInitializersToConstVar(CloneContext& ctx) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* src_ty = src_sem_expr->Type();
|
auto* src_ty = src_sem_expr->Type();
|
||||||
if (src_ty->IsAnyOf<sem::ArrayType, sem::StructType>()) {
|
if (src_ty->IsAnyOf<sem::ArrayType, sem::Struct>()) {
|
||||||
// Create a new symbol for the constant
|
// Create a new symbol for the constant
|
||||||
auto dst_symbol = ctx.dst->Sym();
|
auto dst_symbol = ctx.dst->Sym();
|
||||||
// Clone the type
|
// Clone the type
|
||||||
|
|
|
@ -288,7 +288,7 @@ Symbol Spirv::HoistToInputVariables(
|
||||||
sem::Type* ty,
|
sem::Type* ty,
|
||||||
ast::Type* declared_ty,
|
ast::Type* declared_ty,
|
||||||
const ast::DecorationList& decorations) const {
|
const ast::DecorationList& decorations) const {
|
||||||
if (!ty->Is<sem::StructType>()) {
|
if (!ty->Is<sem::Struct>()) {
|
||||||
// Base case: create a global variable and return.
|
// Base case: create a global variable and return.
|
||||||
ast::DecorationList new_decorations =
|
ast::DecorationList new_decorations =
|
||||||
RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) {
|
RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) {
|
||||||
|
@ -305,8 +305,8 @@ Symbol Spirv::HoistToInputVariables(
|
||||||
|
|
||||||
// Recurse into struct members and build the initializer list.
|
// Recurse into struct members and build the initializer list.
|
||||||
std::vector<Symbol> init_value_names;
|
std::vector<Symbol> init_value_names;
|
||||||
auto* struct_ty = ty->As<sem::StructType>();
|
auto* struct_ty = ty->As<sem::Struct>();
|
||||||
for (auto* member : ctx.src->Sem().Get(struct_ty)->Members()) {
|
for (auto* member : struct_ty->Members()) {
|
||||||
auto member_var = HoistToInputVariables(
|
auto member_var = HoistToInputVariables(
|
||||||
ctx, func, member->Type(), member->Declaration()->type(),
|
ctx, func, member->Type(), member->Declaration()->type(),
|
||||||
member->Declaration()->decorations());
|
member->Declaration()->decorations());
|
||||||
|
@ -342,7 +342,7 @@ void Spirv::HoistToOutputVariables(CloneContext& ctx,
|
||||||
Symbol store_value,
|
Symbol store_value,
|
||||||
ast::StatementList& stores) const {
|
ast::StatementList& stores) const {
|
||||||
// Base case.
|
// Base case.
|
||||||
if (!ty->Is<sem::StructType>()) {
|
if (!ty->Is<sem::Struct>()) {
|
||||||
// Create a global variable.
|
// Create a global variable.
|
||||||
ast::DecorationList new_decorations =
|
ast::DecorationList new_decorations =
|
||||||
RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) {
|
RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) {
|
||||||
|
@ -366,8 +366,8 @@ void Spirv::HoistToOutputVariables(CloneContext& ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurse into struct members.
|
// Recurse into struct members.
|
||||||
auto* struct_ty = ty->As<sem::StructType>();
|
auto* struct_ty = ty->As<sem::Struct>();
|
||||||
for (auto* member : ctx.src->Sem().Get(struct_ty)->Members()) {
|
for (auto* member : struct_ty->Members()) {
|
||||||
member_accesses.push_back(ctx.Clone(member->Declaration()->symbol()));
|
member_accesses.push_back(ctx.Clone(member->Declaration()->symbol()));
|
||||||
HoistToOutputVariables(ctx, func, member->Type(),
|
HoistToOutputVariables(ctx, func, member->Type(),
|
||||||
member->Declaration()->type(),
|
member->Declaration()->type(),
|
||||||
|
|
|
@ -107,8 +107,9 @@ ast::Type* Transform::CreateASTTypeFor(CloneContext* ctx, const sem::Type* ty) {
|
||||||
if (auto* a = ty->As<sem::Alias>()) {
|
if (auto* a = ty->As<sem::Alias>()) {
|
||||||
return ctx->dst->create<ast::TypeName>(ctx->Clone(a->symbol()));
|
return ctx->dst->create<ast::TypeName>(ctx->Clone(a->symbol()));
|
||||||
}
|
}
|
||||||
if (auto* s = ty->As<sem::StructType>()) {
|
if (auto* s = ty->As<sem::Struct>()) {
|
||||||
return ctx->dst->create<ast::TypeName>(ctx->Clone(s->impl()->name()));
|
return ctx->dst->create<ast::TypeName>(
|
||||||
|
ctx->Clone(s->Declaration()->name()));
|
||||||
}
|
}
|
||||||
TINT_UNREACHABLE(ctx->dst->Diagnostics())
|
TINT_UNREACHABLE(ctx->dst->Diagnostics())
|
||||||
<< "Unhandled type: " << ty->TypeInfo().name;
|
<< "Unhandled type: " << ty->TypeInfo().name;
|
||||||
|
|
|
@ -98,7 +98,10 @@ TEST_F(CreateASTTypeForTest, Array) {
|
||||||
|
|
||||||
TEST_F(CreateASTTypeForTest, AccessControl) {
|
TEST_F(CreateASTTypeForTest, AccessControl) {
|
||||||
auto* ac = create([](ProgramBuilder& b) {
|
auto* ac = create([](ProgramBuilder& b) {
|
||||||
auto str = b.Structure("S", {}, {});
|
auto* decl = b.Structure("S", {}, {});
|
||||||
|
auto* str =
|
||||||
|
b.create<sem::Struct>(decl, sem::StructMemberList{}, 4 /* align */,
|
||||||
|
4 /* size */, 4 /* size_no_padding */);
|
||||||
return b.create<sem::AccessControl>(ast::AccessControl::kReadOnly, str);
|
return b.create<sem::AccessControl>(ast::AccessControl::kReadOnly, str);
|
||||||
});
|
});
|
||||||
ASSERT_TRUE(ac->Is<ast::AccessControl>());
|
ASSERT_TRUE(ac->Is<ast::AccessControl>());
|
||||||
|
@ -109,8 +112,9 @@ TEST_F(CreateASTTypeForTest, AccessControl) {
|
||||||
|
|
||||||
TEST_F(CreateASTTypeForTest, Struct) {
|
TEST_F(CreateASTTypeForTest, Struct) {
|
||||||
auto* str = create([](ProgramBuilder& b) {
|
auto* str = create([](ProgramBuilder& b) {
|
||||||
auto* impl = b.Structure("S", {}, {}).ast;
|
auto* decl = b.Structure("S", {}, {});
|
||||||
return b.create<sem::StructType>(const_cast<ast::Struct*>(impl));
|
return b.create<sem::Struct>(decl, sem::StructMemberList{}, 4 /* align */,
|
||||||
|
4 /* size */, 4 /* size_no_padding */);
|
||||||
});
|
});
|
||||||
ASSERT_TRUE(str->Is<ast::TypeName>());
|
ASSERT_TRUE(str->Is<ast::TypeName>());
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
|
|
|
@ -204,7 +204,7 @@ struct State {
|
||||||
|
|
||||||
// Creating the struct type
|
// Creating the struct type
|
||||||
static const char kStructName[] = "TintVertexData";
|
static const char kStructName[] = "TintVertexData";
|
||||||
auto struct_type = ctx.dst->Structure(
|
auto* struct_type = ctx.dst->Structure(
|
||||||
ctx.dst->Symbols().New(kStructName),
|
ctx.dst->Symbols().New(kStructName),
|
||||||
{
|
{
|
||||||
ctx.dst->Member(GetStructBufferName(),
|
ctx.dst->Member(GetStructBufferName(),
|
||||||
|
@ -432,7 +432,7 @@ struct State {
|
||||||
/// @param struct_ty the structure type
|
/// @param struct_ty the structure type
|
||||||
void ProcessStructParameter(ast::Function* func,
|
void ProcessStructParameter(ast::Function* func,
|
||||||
ast::Variable* param,
|
ast::Variable* param,
|
||||||
ast::Struct* struct_ty) {
|
const ast::Struct* struct_ty) {
|
||||||
auto param_sym = ctx.Clone(param->symbol());
|
auto param_sym = ctx.Clone(param->symbol());
|
||||||
|
|
||||||
// Process the struct members.
|
// Process the struct members.
|
||||||
|
@ -486,7 +486,7 @@ struct State {
|
||||||
new_members.push_back(
|
new_members.push_back(
|
||||||
ctx.dst->Member(member_sym, member_type, std::move(member_decos)));
|
ctx.dst->Member(member_sym, member_type, std::move(member_decos)));
|
||||||
}
|
}
|
||||||
auto new_struct = ctx.dst->Structure(ctx.dst->Sym(), new_members);
|
auto* new_struct = ctx.dst->Structure(ctx.dst->Sym(), new_members);
|
||||||
|
|
||||||
// Create a new function parameter with this struct.
|
// Create a new function parameter with this struct.
|
||||||
auto* new_param = ctx.dst->Param(ctx.dst->Sym(), new_struct);
|
auto* new_param = ctx.dst->Param(ctx.dst->Sym(), new_struct);
|
||||||
|
@ -513,8 +513,8 @@ struct State {
|
||||||
// Process entry point parameters.
|
// Process entry point parameters.
|
||||||
for (auto* param : func->params()) {
|
for (auto* param : func->params()) {
|
||||||
auto* sem = ctx.src->Sem().Get(param);
|
auto* sem = ctx.src->Sem().Get(param);
|
||||||
if (auto* str = sem->Type()->As<sem::StructType>()) {
|
if (auto* str = sem->Type()->As<sem::Struct>()) {
|
||||||
ProcessStructParameter(func, param, str->impl());
|
ProcessStructParameter(func, param, str->Declaration());
|
||||||
} else {
|
} else {
|
||||||
ProcessNonStructParameter(func, param);
|
ProcessNonStructParameter(func, param);
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ class Pointer;
|
||||||
class Sampler;
|
class Sampler;
|
||||||
class SampledTexture;
|
class SampledTexture;
|
||||||
class StorageTexture;
|
class StorageTexture;
|
||||||
class StructType;
|
class Struct;
|
||||||
class Texture;
|
class Texture;
|
||||||
class Type;
|
class Type;
|
||||||
class U32;
|
class U32;
|
||||||
|
@ -254,7 +254,7 @@ using Pointer = TypePair<ast::Pointer, sem::Pointer>;
|
||||||
using Sampler = TypePair<ast::Sampler, sem::Sampler>;
|
using Sampler = TypePair<ast::Sampler, sem::Sampler>;
|
||||||
using SampledTexture = TypePair<ast::SampledTexture, sem::SampledTexture>;
|
using SampledTexture = TypePair<ast::SampledTexture, sem::SampledTexture>;
|
||||||
using StorageTexture = TypePair<ast::StorageTexture, sem::StorageTexture>;
|
using StorageTexture = TypePair<ast::StorageTexture, sem::StorageTexture>;
|
||||||
using Struct = TypePair<ast::Struct, sem::StructType>;
|
using Struct = TypePair<ast::Struct, sem::Struct>;
|
||||||
using Texture = TypePair<ast::Texture, sem::Texture>;
|
using Texture = TypePair<ast::Texture, sem::Texture>;
|
||||||
using U32 = TypePair<ast::U32, sem::U32>;
|
using U32 = TypePair<ast::U32, sem::U32>;
|
||||||
using Vector = TypePair<ast::Vector, sem::Vector>;
|
using Vector = TypePair<ast::Vector, sem::Vector>;
|
||||||
|
@ -271,7 +271,6 @@ inline auto MakeTypePair(AST* ast, SEM* sem) {
|
||||||
return TypePair<AST, SEM>{ast, sem};
|
return TypePair<AST, SEM>{ast, sem};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace typ
|
} // namespace typ
|
||||||
|
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -210,7 +210,7 @@ bool GeneratorImpl::EmitConstructedType(std::ostream& out,
|
||||||
if (auto* alias = ty->As<sem::Alias>()) {
|
if (auto* alias = ty->As<sem::Alias>()) {
|
||||||
// HLSL typedef is for intrinsic types only. For an alias'd struct,
|
// HLSL typedef is for intrinsic types only. For an alias'd struct,
|
||||||
// generate a secondary struct with the new name.
|
// generate a secondary struct with the new name.
|
||||||
if (auto* str = alias->type()->As<sem::StructType>()) {
|
if (auto* str = alias->type()->As<sem::Struct>()) {
|
||||||
if (!EmitStructType(out, str,
|
if (!EmitStructType(out, str,
|
||||||
builder_.Symbols().NameFor(alias->symbol()))) {
|
builder_.Symbols().NameFor(alias->symbol()))) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -223,9 +223,9 @@ bool GeneratorImpl::EmitConstructedType(std::ostream& out,
|
||||||
}
|
}
|
||||||
out << " " << builder_.Symbols().NameFor(alias->symbol()) << ";"
|
out << " " << builder_.Symbols().NameFor(alias->symbol()) << ";"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
} else if (auto* str = ty->As<sem::StructType>()) {
|
} else if (auto* str = ty->As<sem::Struct>()) {
|
||||||
if (!EmitStructType(out, str,
|
if (!EmitStructType(
|
||||||
builder_.Symbols().NameFor(str->impl()->name()))) {
|
out, str, builder_.Symbols().NameFor(str->Declaration()->name()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1325,7 +1325,7 @@ bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool brackets =
|
bool brackets =
|
||||||
type->UnwrapAliasIfNeeded()->IsAnyOf<sem::ArrayType, sem::StructType>();
|
type->UnwrapAliasIfNeeded()->IsAnyOf<sem::ArrayType, sem::Struct>();
|
||||||
|
|
||||||
if (brackets) {
|
if (brackets) {
|
||||||
out << "{";
|
out << "{";
|
||||||
|
@ -1715,9 +1715,9 @@ bool GeneratorImpl::EmitEntryPointData(
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* type = var->Type()->UnwrapIfNeeded();
|
auto* type = var->Type()->UnwrapIfNeeded();
|
||||||
if (auto* strct = type->As<sem::StructType>()) {
|
if (auto* strct = type->As<sem::Struct>()) {
|
||||||
out << "ConstantBuffer<"
|
out << "ConstantBuffer<"
|
||||||
<< builder_.Symbols().NameFor(strct->impl()->name()) << "> "
|
<< builder_.Symbols().NameFor(strct->Declaration()->name()) << "> "
|
||||||
<< builder_.Symbols().NameFor(decl->symbol())
|
<< builder_.Symbols().NameFor(decl->symbol())
|
||||||
<< RegisterAndSpace('b', binding_point) << ";" << std::endl;
|
<< RegisterAndSpace('b', binding_point) << ";" << std::endl;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2038,7 +2038,7 @@ bool GeneratorImpl::EmitEntryPointFunction(std::ostream& out,
|
||||||
for (auto* var : func->params()) {
|
for (auto* var : func->params()) {
|
||||||
auto* sem = builder_.Sem().Get(var);
|
auto* sem = builder_.Sem().Get(var);
|
||||||
auto* type = sem->Type();
|
auto* type = sem->Type();
|
||||||
if (!type->Is<sem::StructType>()) {
|
if (!type->Is<sem::Struct>()) {
|
||||||
TINT_ICE(diagnostics_) << "Unsupported non-struct entry point parameter";
|
TINT_ICE(diagnostics_) << "Unsupported non-struct entry point parameter";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2140,10 +2140,10 @@ bool GeneratorImpl::EmitZeroValue(std::ostream& out, sem::Type* type) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (auto* str = type->As<sem::StructType>()) {
|
} else if (auto* str = type->As<sem::Struct>()) {
|
||||||
out << "{";
|
out << "{";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto* member : builder_.Sem().Get(str)->Members()) {
|
for (auto* member : str->Members()) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
out << ", ";
|
out << ", ";
|
||||||
}
|
}
|
||||||
|
@ -2383,7 +2383,7 @@ bool GeneratorImpl::EmitSwitch(std::ostream& out, ast::SwitchStatement* stmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneratorImpl::EmitType(std::ostream& out,
|
bool GeneratorImpl::EmitType(std::ostream& out,
|
||||||
sem::Type* type,
|
const sem::Type* type,
|
||||||
ast::StorageClass storage_class,
|
ast::StorageClass storage_class,
|
||||||
const std::string& name) {
|
const std::string& name) {
|
||||||
auto* access = type->As<sem::AccessControl>();
|
auto* access = type->As<sem::AccessControl>();
|
||||||
|
@ -2407,7 +2407,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
|
||||||
if (auto* alias = type->As<sem::Alias>()) {
|
if (auto* alias = type->As<sem::Alias>()) {
|
||||||
out << builder_.Symbols().NameFor(alias->symbol());
|
out << builder_.Symbols().NameFor(alias->symbol());
|
||||||
} else if (auto* ary = type->As<sem::ArrayType>()) {
|
} else if (auto* ary = type->As<sem::ArrayType>()) {
|
||||||
sem::Type* base_type = ary;
|
const sem::Type* base_type = ary;
|
||||||
std::vector<uint32_t> sizes;
|
std::vector<uint32_t> sizes;
|
||||||
while (auto* arr = base_type->As<sem::ArrayType>()) {
|
while (auto* arr = base_type->As<sem::ArrayType>()) {
|
||||||
if (arr->IsRuntimeArray()) {
|
if (arr->IsRuntimeArray()) {
|
||||||
|
@ -2457,8 +2457,8 @@ bool GeneratorImpl::EmitType(std::ostream& out,
|
||||||
out << "Comparison";
|
out << "Comparison";
|
||||||
}
|
}
|
||||||
out << "State";
|
out << "State";
|
||||||
} else if (auto* str = type->As<sem::StructType>()) {
|
} else if (auto* str = type->As<sem::Struct>()) {
|
||||||
out << builder_.Symbols().NameFor(str->impl()->name());
|
out << builder_.Symbols().NameFor(str->Declaration()->name());
|
||||||
} else if (auto* tex = type->As<sem::Texture>()) {
|
} else if (auto* tex = type->As<sem::Texture>()) {
|
||||||
auto* storage = tex->As<sem::StorageTexture>();
|
auto* storage = tex->As<sem::StorageTexture>();
|
||||||
auto* multism = tex->As<sem::MultisampledTexture>();
|
auto* multism = tex->As<sem::MultisampledTexture>();
|
||||||
|
@ -2547,11 +2547,9 @@ bool GeneratorImpl::EmitType(std::ostream& out,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneratorImpl::EmitStructType(std::ostream& out,
|
bool GeneratorImpl::EmitStructType(std::ostream& out,
|
||||||
const sem::StructType* str,
|
const sem::Struct* str,
|
||||||
const std::string& name) {
|
const std::string& name) {
|
||||||
auto* sem_str = builder_.Sem().Get(str);
|
auto storage_class_uses = str->StorageClassUsage();
|
||||||
|
|
||||||
auto storage_class_uses = sem_str->StorageClassUsage();
|
|
||||||
if (storage_class_uses.size() ==
|
if (storage_class_uses.size() ==
|
||||||
storage_class_uses.count(ast::StorageClass::kStorage)) {
|
storage_class_uses.count(ast::StorageClass::kStorage)) {
|
||||||
// The only use of the structure is as a storage buffer.
|
// The only use of the structure is as a storage buffer.
|
||||||
|
@ -2563,7 +2561,7 @@ bool GeneratorImpl::EmitStructType(std::ostream& out,
|
||||||
out << "struct " << name << " {" << std::endl;
|
out << "struct " << name << " {" << std::endl;
|
||||||
|
|
||||||
increment_indent();
|
increment_indent();
|
||||||
for (auto* mem : sem_str->Members()) {
|
for (auto* mem : str->Members()) {
|
||||||
make_indent(out);
|
make_indent(out);
|
||||||
// TODO(dsinclair): Handle [[offset]] annotation on structs
|
// TODO(dsinclair): Handle [[offset]] annotation on structs
|
||||||
// https://bugs.chromium.org/p/tint/issues/detail?id=184
|
// https://bugs.chromium.org/p/tint/issues/detail?id=184
|
||||||
|
@ -2579,8 +2577,7 @@ bool GeneratorImpl::EmitStructType(std::ostream& out,
|
||||||
|
|
||||||
for (auto* deco : mem->Declaration()->decorations()) {
|
for (auto* deco : mem->Declaration()->decorations()) {
|
||||||
if (auto* location = deco->As<ast::LocationDecoration>()) {
|
if (auto* location = deco->As<ast::LocationDecoration>()) {
|
||||||
auto& pipeline_stage_uses =
|
auto& pipeline_stage_uses = str->PipelineStageUses();
|
||||||
builder_.Sem().Get(str)->PipelineStageUses();
|
|
||||||
if (pipeline_stage_uses.size() != 1) {
|
if (pipeline_stage_uses.size() != 1) {
|
||||||
TINT_ICE(diagnostics_) << "invalid entry point IO struct uses";
|
TINT_ICE(diagnostics_) << "invalid entry point IO struct uses";
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,7 +290,7 @@ class GeneratorImpl : public TextGenerator {
|
||||||
/// @param name the name of the variable, only used for array emission
|
/// @param name the name of the variable, only used for array emission
|
||||||
/// @returns true if the type is emitted
|
/// @returns true if the type is emitted
|
||||||
bool EmitType(std::ostream& out,
|
bool EmitType(std::ostream& out,
|
||||||
sem::Type* type,
|
const sem::Type* type,
|
||||||
ast::StorageClass storage_class,
|
ast::StorageClass storage_class,
|
||||||
const std::string& name);
|
const std::string& name);
|
||||||
/// Handles generating a structure declaration
|
/// Handles generating a structure declaration
|
||||||
|
@ -299,7 +299,7 @@ class GeneratorImpl : public TextGenerator {
|
||||||
/// @param name the struct name
|
/// @param name the struct name
|
||||||
/// @returns true if the struct is emitted
|
/// @returns true if the struct is emitted
|
||||||
bool EmitStructType(std::ostream& out,
|
bool EmitStructType(std::ostream& out,
|
||||||
const sem::StructType* ty,
|
const sem::Struct* ty,
|
||||||
const std::string& name);
|
const std::string& name);
|
||||||
/// Handles a unary op expression
|
/// Handles a unary op expression
|
||||||
/// @param pre the preamble for the expression stream
|
/// @param pre the preamble for the expression stream
|
||||||
|
|
|
@ -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,7 +195,7 @@ TEST_F(HlslGeneratorImplTest_Constructor,
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
|
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
|
||||||
auto str = Structure("S", {
|
auto* str = Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
Member("c", ty.vec3<i32>()),
|
Member("c", ty.vec3<i32>()),
|
||||||
|
@ -212,7 +212,7 @@ TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct_Empty) {
|
TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct_Empty) {
|
||||||
auto str = Structure("S", {
|
auto* str = Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
Member("c", ty.vec3<i32>()),
|
Member("c", ty.vec3<i32>()),
|
||||||
|
|
|
@ -179,7 +179,7 @@ TEST_F(HlslGeneratorImplTest_Function,
|
||||||
// const g = inputs.col2;
|
// const g = inputs.col2;
|
||||||
// const p = inputs.pos;
|
// const p = inputs.pos;
|
||||||
// }
|
// }
|
||||||
auto interface_struct = Structure(
|
auto* interface_struct = Structure(
|
||||||
"Interface",
|
"Interface",
|
||||||
{
|
{
|
||||||
Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
|
Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
|
||||||
|
@ -252,7 +252,7 @@ TEST_F(HlslGeneratorImplTest_Function,
|
||||||
// fn vert_main2() -> VertexOutput {
|
// fn vert_main2() -> VertexOutput {
|
||||||
// return foo(0.25);
|
// return foo(0.25);
|
||||||
// }
|
// }
|
||||||
auto vertex_output_struct = Structure(
|
auto* vertex_output_struct = Structure(
|
||||||
"VertexOutput",
|
"VertexOutput",
|
||||||
{Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
|
{Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
|
||||||
|
|
||||||
|
@ -307,7 +307,7 @@ tint_symbol_2 vert_main2() {
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Function,
|
TEST_F(HlslGeneratorImplTest_Function,
|
||||||
Emit_Decoration_EntryPoint_With_Uniform) {
|
Emit_Decoration_EntryPoint_With_Uniform) {
|
||||||
auto ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
|
auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto* ubo = Global(
|
auto* ubo = Global(
|
||||||
"ubo", ubo_ty, ast::StorageClass::kUniform, nullptr,
|
"ubo", ubo_ty, ast::StorageClass::kUniform, nullptr,
|
||||||
|
@ -359,7 +359,7 @@ void frag_main() {
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Function,
|
TEST_F(HlslGeneratorImplTest_Function,
|
||||||
Emit_Decoration_EntryPoint_With_UniformStruct) {
|
Emit_Decoration_EntryPoint_With_UniformStruct) {
|
||||||
auto s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())},
|
auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
|
||||||
Global("uniforms", s, ast::StorageClass::kUniform, nullptr,
|
Global("uniforms", s, ast::StorageClass::kUniform, nullptr,
|
||||||
|
@ -401,7 +401,7 @@ void frag_main() {
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Function,
|
TEST_F(HlslGeneratorImplTest_Function,
|
||||||
Emit_Decoration_EntryPoint_With_RW_StorageBuffer_Read) {
|
Emit_Decoration_EntryPoint_With_RW_StorageBuffer_Read) {
|
||||||
auto s = Structure("Data",
|
auto* s = Structure("Data",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
|
@ -447,7 +447,7 @@ void frag_main() {
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Function,
|
TEST_F(HlslGeneratorImplTest_Function,
|
||||||
Emit_Decoration_EntryPoint_With_RO_StorageBuffer_Read) {
|
Emit_Decoration_EntryPoint_With_RO_StorageBuffer_Read) {
|
||||||
auto s = Structure("Data",
|
auto* s = Structure("Data",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
|
@ -493,7 +493,7 @@ void frag_main() {
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Function,
|
TEST_F(HlslGeneratorImplTest_Function,
|
||||||
Emit_Decoration_EntryPoint_With_WO_StorageBuffer_Store) {
|
Emit_Decoration_EntryPoint_With_WO_StorageBuffer_Store) {
|
||||||
auto s = Structure("Data",
|
auto* s = Structure("Data",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
|
@ -536,7 +536,7 @@ void frag_main() {
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Function,
|
TEST_F(HlslGeneratorImplTest_Function,
|
||||||
Emit_Decoration_EntryPoint_With_StorageBuffer_Store) {
|
Emit_Decoration_EntryPoint_With_StorageBuffer_Store) {
|
||||||
auto s = Structure("Data",
|
auto* s = Structure("Data",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
|
@ -742,7 +742,7 @@ ep_1_out ep_1(ep_1_in tint_in) {
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Function,
|
TEST_F(HlslGeneratorImplTest_Function,
|
||||||
Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
|
Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
|
||||||
auto s = Structure("S", {Member("x", ty.f32())},
|
auto* s = Structure("S", {Member("x", ty.f32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
Global("coord", s, ast::StorageClass::kUniform, nullptr,
|
Global("coord", s, ast::StorageClass::kUniform, nullptr,
|
||||||
{
|
{
|
||||||
|
@ -792,7 +792,7 @@ void frag_main() {
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Function,
|
TEST_F(HlslGeneratorImplTest_Function,
|
||||||
Emit_Decoration_Called_By_EntryPoint_With_StorageBuffer) {
|
Emit_Decoration_Called_By_EntryPoint_With_StorageBuffer) {
|
||||||
auto s = Structure("S", {Member("x", ty.f32())},
|
auto* s = Structure("S", {Member("x", ty.f32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||||
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
|
Global("coord", ac, ast::StorageClass::kStorage, nullptr,
|
||||||
|
@ -981,7 +981,7 @@ TEST_F(HlslGeneratorImplTest_Function,
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
auto s = Structure("Data", {Member("d", ty.f32())},
|
auto* s = Structure("Data", {Member("d", ty.f32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
|
||||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||||
|
|
|
@ -96,7 +96,7 @@ class HlslGeneratorImplTest_MemberAccessorBase : public BASE {
|
||||||
void SetupStorageBuffer(ast::StructMemberList members) {
|
void SetupStorageBuffer(ast::StructMemberList members) {
|
||||||
ProgramBuilder& b = *this;
|
ProgramBuilder& b = *this;
|
||||||
|
|
||||||
auto s =
|
auto* s =
|
||||||
b.Structure("Data", members, {b.create<ast::StructBlockDecoration>()});
|
b.Structure("Data", members, {b.create<ast::StructBlockDecoration>()});
|
||||||
|
|
||||||
auto ac_ty = b.ty.access(ast::AccessControl::kReadWrite, s);
|
auto ac_ty = b.ty.access(ast::AccessControl::kReadWrite, s);
|
||||||
|
@ -125,7 +125,7 @@ using HlslGeneratorImplTest_MemberAccessorWithParam =
|
||||||
HlslGeneratorImplTest_MemberAccessorBase<TestParamHelper<T>>;
|
HlslGeneratorImplTest_MemberAccessorBase<TestParamHelper<T>>;
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_MemberAccessor, EmitExpression_MemberAccessor) {
|
TEST_F(HlslGeneratorImplTest_MemberAccessor, EmitExpression_MemberAccessor) {
|
||||||
auto s = Structure("Data", {Member("mem", ty.f32())});
|
auto* s = Structure("Data", {Member("mem", ty.f32())});
|
||||||
Global("str", s, ast::StorageClass::kPrivate);
|
Global("str", s, ast::StorageClass::kPrivate);
|
||||||
|
|
||||||
auto* expr = MemberAccessor("str", "mem");
|
auto* expr = MemberAccessor("str", "mem");
|
||||||
|
@ -522,7 +522,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel) {
|
||||||
// var<storage> data : Pre;
|
// var<storage> data : Pre;
|
||||||
// data.c[2].b
|
// data.c[2].b
|
||||||
|
|
||||||
auto inner = Structure("Inner", {
|
auto* inner = Structure("Inner", {
|
||||||
Member("a", ty.vec3<f32>()),
|
Member("a", ty.vec3<f32>()),
|
||||||
Member("b", ty.vec3<f32>()),
|
Member("b", ty.vec3<f32>()),
|
||||||
});
|
});
|
||||||
|
@ -568,7 +568,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
||||||
// var<storage> data : Pre;
|
// var<storage> data : Pre;
|
||||||
// data.c[2].b.xy
|
// data.c[2].b.xy
|
||||||
|
|
||||||
auto inner = Structure("Inner", {
|
auto* inner = Structure("Inner", {
|
||||||
Member("a", ty.vec3<f32>()),
|
Member("a", ty.vec3<f32>()),
|
||||||
Member("b", ty.vec3<f32>()),
|
Member("b", ty.vec3<f32>()),
|
||||||
});
|
});
|
||||||
|
@ -616,7 +616,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
||||||
// var<storage> data : Pre;
|
// var<storage> data : Pre;
|
||||||
// data.c[2].b.g
|
// data.c[2].b.g
|
||||||
|
|
||||||
auto inner = Structure("Inner", {
|
auto* inner = Structure("Inner", {
|
||||||
Member("a", ty.vec3<f32>()),
|
Member("a", ty.vec3<f32>()),
|
||||||
Member("b", ty.vec3<f32>()),
|
Member("b", ty.vec3<f32>()),
|
||||||
});
|
});
|
||||||
|
@ -664,7 +664,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
||||||
// var<storage> data : Pre;
|
// var<storage> data : Pre;
|
||||||
// data.c[2].b[1]
|
// data.c[2].b[1]
|
||||||
|
|
||||||
auto inner = Structure("Inner", {
|
auto* inner = Structure("Inner", {
|
||||||
Member("a", ty.vec3<f32>()),
|
Member("a", ty.vec3<f32>()),
|
||||||
Member("b", ty.vec3<f32>()),
|
Member("b", ty.vec3<f32>()),
|
||||||
});
|
});
|
||||||
|
@ -711,7 +711,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_MultiLevel) {
|
||||||
// var<storage> data : Pre;
|
// var<storage> data : Pre;
|
||||||
// data.c[2].b = vec3<f32>(1.f, 2.f, 3.f);
|
// data.c[2].b = vec3<f32>(1.f, 2.f, 3.f);
|
||||||
|
|
||||||
auto inner = Structure("Inner", {
|
auto* inner = Structure("Inner", {
|
||||||
Member("a", ty.vec3<f32>()),
|
Member("a", ty.vec3<f32>()),
|
||||||
Member("b", ty.vec3<f32>()),
|
Member("b", ty.vec3<f32>()),
|
||||||
});
|
});
|
||||||
|
@ -756,7 +756,7 @@ TEST_F(HlslGeneratorImplTest_MemberAccessor,
|
||||||
// var<storage> data : Pre;
|
// var<storage> data : Pre;
|
||||||
// data.c[2].b.y = 1.f;
|
// data.c[2].b.y = 1.f;
|
||||||
|
|
||||||
auto inner = Structure("Inner", {
|
auto* inner = Structure("Inner", {
|
||||||
Member("a", ty.vec3<i32>()),
|
Member("a", ty.vec3<i32>()),
|
||||||
Member("b", ty.vec3<f32>()),
|
Member("b", ty.vec3<f32>()),
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace {
|
||||||
using HlslSanitizerTest = TestHelper;
|
using HlslSanitizerTest = TestHelper;
|
||||||
|
|
||||||
TEST_F(HlslSanitizerTest, ArrayLength) {
|
TEST_F(HlslSanitizerTest, ArrayLength) {
|
||||||
auto sb_ty = Structure("SB",
|
auto* sb_ty = Structure("SB",
|
||||||
{
|
{
|
||||||
Member("x", ty.f32()),
|
Member("x", ty.f32()),
|
||||||
Member("arr", ty.array(ty.vec4<f32>())),
|
Member("arr", ty.array(ty.vec4<f32>())),
|
||||||
|
@ -100,7 +100,7 @@ TEST_F(HlslSanitizerTest, PromoteArrayInitializerToConstVar) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslSanitizerTest, PromoteStructInitializerToConstVar) {
|
TEST_F(HlslSanitizerTest, PromoteStructInitializerToConstVar) {
|
||||||
auto str = Structure("S", {
|
auto* str = Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.vec3<f32>()),
|
Member("b", ty.vec3<f32>()),
|
||||||
Member("c", ty.i32()),
|
Member("c", ty.i32()),
|
||||||
|
|
|
@ -156,7 +156,7 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Pointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
|
TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
@ -164,7 +164,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitStructType(out, s, "S")) << gen.error();
|
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
|
||||||
|
ASSERT_TRUE(gen.EmitStructType(out, sem_s, "S")) << gen.error();
|
||||||
EXPECT_EQ(result(), R"(struct S {
|
EXPECT_EQ(result(), R"(struct S {
|
||||||
int a;
|
int a;
|
||||||
float b;
|
float b;
|
||||||
|
@ -173,7 +174,7 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl_OmittedIfStorageBuffer) {
|
TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl_OmittedIfStorageBuffer) {
|
||||||
auto s = Structure("S",
|
auto* s = Structure("S",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
|
@ -184,12 +185,13 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl_OmittedIfStorageBuffer) {
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitStructType(out, s, "S")) << gen.error();
|
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
|
||||||
|
ASSERT_TRUE(gen.EmitStructType(out, sem_s, "S")) << gen.error();
|
||||||
EXPECT_EQ(result(), "");
|
EXPECT_EQ(result(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
|
TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
@ -197,7 +199,8 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitType(out, s, ast::StorageClass::kNone, ""))
|
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
|
||||||
|
ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone, ""))
|
||||||
<< gen.error();
|
<< gen.error();
|
||||||
EXPECT_EQ(result(), "S");
|
EXPECT_EQ(result(), "S");
|
||||||
}
|
}
|
||||||
|
@ -205,7 +208,7 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
|
||||||
/// TODO(bclayton): Enable this, fix it, add tests for vector, matrix, array and
|
/// TODO(bclayton): Enable this, fix it, add tests for vector, matrix, array and
|
||||||
/// nested structures.
|
/// nested structures.
|
||||||
TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) {
|
TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) {
|
||||||
auto s = Structure(
|
auto* s = Structure(
|
||||||
"S", {
|
"S", {
|
||||||
Member("a", ty.i32(), {MemberSize(32)}),
|
Member("a", ty.i32(), {MemberSize(32)}),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
|
@ -215,7 +218,8 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) {
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitType(out, s, ast::StorageClass::kNone, ""))
|
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
|
||||||
|
ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone, ""))
|
||||||
<< gen.error();
|
<< gen.error();
|
||||||
EXPECT_EQ(gen.result(), R"(struct S {
|
EXPECT_EQ(gen.result(), R"(struct S {
|
||||||
int a;
|
int a;
|
||||||
|
@ -229,7 +233,7 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
|
TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("double", ty.i32()),
|
Member("double", ty.i32()),
|
||||||
Member("float", ty.f32()),
|
Member("float", ty.f32()),
|
||||||
});
|
});
|
||||||
|
@ -247,7 +251,7 @@ TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
|
||||||
|
|
||||||
// TODO(dsinclair): How to translate [[block]]
|
// TODO(dsinclair): How to translate [[block]]
|
||||||
TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_WithDecoration) {
|
TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_WithDecoration) {
|
||||||
auto s = Structure("S",
|
auto* s = Structure("S",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
|
@ -257,7 +261,8 @@ TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_WithDecoration) {
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitStructType(out, s, "B")) << gen.error();
|
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
|
||||||
|
ASSERT_TRUE(gen.EmitStructType(out, sem_s, "B")) << gen.error();
|
||||||
EXPECT_EQ(result(), R"(struct B {
|
EXPECT_EQ(result(), R"(struct B {
|
||||||
int a;
|
int a;
|
||||||
float b;
|
float b;
|
||||||
|
|
|
@ -156,7 +156,7 @@ bool GeneratorImpl::EmitConstructedType(const sem::Type* ty) {
|
||||||
}
|
}
|
||||||
out_ << " " << program_->Symbols().NameFor(alias->symbol()) << ";"
|
out_ << " " << program_->Symbols().NameFor(alias->symbol()) << ";"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
} else if (auto* str = ty->As<sem::StructType>()) {
|
} else if (auto* str = ty->As<sem::Struct>()) {
|
||||||
if (!EmitStructType(str)) {
|
if (!EmitStructType(str)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -889,7 +889,7 @@ bool GeneratorImpl::EmitContinue(ast::ContinueStatement*) {
|
||||||
bool GeneratorImpl::EmitTypeConstructor(ast::TypeConstructorExpression* expr) {
|
bool GeneratorImpl::EmitTypeConstructor(ast::TypeConstructorExpression* expr) {
|
||||||
auto* type = TypeOf(expr);
|
auto* type = TypeOf(expr);
|
||||||
|
|
||||||
if (type->IsAnyOf<sem::ArrayType, sem::StructType>()) {
|
if (type->IsAnyOf<sem::ArrayType, sem::Struct>()) {
|
||||||
out_ << "{";
|
out_ << "{";
|
||||||
} else {
|
} else {
|
||||||
if (!EmitType(type, "")) {
|
if (!EmitType(type, "")) {
|
||||||
|
@ -918,7 +918,7 @@ bool GeneratorImpl::EmitTypeConstructor(ast::TypeConstructorExpression* expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type->IsAnyOf<sem::ArrayType, sem::StructType>()) {
|
if (type->IsAnyOf<sem::ArrayType, sem::Struct>()) {
|
||||||
out_ << "}";
|
out_ << "}";
|
||||||
} else {
|
} else {
|
||||||
out_ << ")";
|
out_ << ")";
|
||||||
|
@ -948,7 +948,7 @@ bool GeneratorImpl::EmitZeroValue(typ::Type type) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out_ << "}";
|
out_ << "}";
|
||||||
} else if (type->As<sem::StructType>()) {
|
} else if (type->As<sem::Struct>()) {
|
||||||
out_ << "{}";
|
out_ << "{}";
|
||||||
} else {
|
} else {
|
||||||
diagnostics_.add_error("Invalid type for zero emission: " +
|
diagnostics_.add_error("Invalid type for zero emission: " +
|
||||||
|
@ -1435,7 +1435,7 @@ bool GeneratorImpl::EmitEntryPointFunction(ast::Function* func) {
|
||||||
|
|
||||||
out_ << " " << program_->Symbols().NameFor(var->symbol());
|
out_ << " " << program_->Symbols().NameFor(var->symbol());
|
||||||
|
|
||||||
if (type->Is<sem::StructType>()) {
|
if (type->Is<sem::Struct>()) {
|
||||||
out_ << " [[stage_in]]";
|
out_ << " [[stage_in]]";
|
||||||
} else {
|
} else {
|
||||||
auto& decos = var->decorations();
|
auto& decos = var->decorations();
|
||||||
|
@ -1957,10 +1957,10 @@ bool GeneratorImpl::EmitType(typ::Type type, const std::string& name) {
|
||||||
out_ << "*";
|
out_ << "*";
|
||||||
} else if (type->Is<sem::Sampler>()) {
|
} else if (type->Is<sem::Sampler>()) {
|
||||||
out_ << "sampler";
|
out_ << "sampler";
|
||||||
} else if (auto* str = type->As<sem::StructType>()) {
|
} else if (auto* str = type->As<sem::Struct>()) {
|
||||||
// The struct type emits as just the name. The declaration would be emitted
|
// The struct type emits as just the name. The declaration would be emitted
|
||||||
// as part of emitting the constructed types.
|
// as part of emitting the constructed types.
|
||||||
out_ << program_->Symbols().NameFor(str->impl()->name());
|
out_ << program_->Symbols().NameFor(str->Declaration()->name());
|
||||||
} else if (auto* tex = type->As<sem::Texture>()) {
|
} else if (auto* tex = type->As<sem::Texture>()) {
|
||||||
if (tex->Is<sem::DepthTexture>()) {
|
if (tex->Is<sem::DepthTexture>()) {
|
||||||
out_ << "depth";
|
out_ << "depth";
|
||||||
|
@ -2056,20 +2056,14 @@ bool GeneratorImpl::EmitPackedType(typ::Type type, const std::string& name) {
|
||||||
return EmitType(type, name);
|
return EmitType(type, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneratorImpl::EmitStructType(const sem::StructType* str) {
|
bool GeneratorImpl::EmitStructType(const sem::Struct* str) {
|
||||||
// TODO(dsinclair): Block decoration?
|
// TODO(dsinclair): Block decoration?
|
||||||
// if (str->impl()->decoration() != ast::Decoration::kNone) {
|
// if (str->impl()->decoration() != ast::Decoration::kNone) {
|
||||||
// }
|
// }
|
||||||
out_ << "struct " << program_->Symbols().NameFor(str->impl()->name()) << " {"
|
out_ << "struct " << program_->Symbols().NameFor(str->Declaration()->name())
|
||||||
<< std::endl;
|
<< " {" << std::endl;
|
||||||
|
|
||||||
auto* sem_str = program_->Sem().Get(str);
|
bool is_host_shareable = str->IsHostShareable();
|
||||||
if (!sem_str) {
|
|
||||||
TINT_ICE(diagnostics_) << "struct missing semantic info";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_host_shareable = sem_str->IsHostShareable();
|
|
||||||
|
|
||||||
// Emits a `/* 0xnnnn */` byte offset comment for a struct member.
|
// Emits a `/* 0xnnnn */` byte offset comment for a struct member.
|
||||||
auto add_byte_offset_comment = [&](uint32_t offset) {
|
auto add_byte_offset_comment = [&](uint32_t offset) {
|
||||||
|
@ -2084,14 +2078,14 @@ bool GeneratorImpl::EmitStructType(const sem::StructType* str) {
|
||||||
std::string name;
|
std::string name;
|
||||||
do {
|
do {
|
||||||
name = "tint_pad_" + std::to_string(pad_count++);
|
name = "tint_pad_" + std::to_string(pad_count++);
|
||||||
} while (sem_str->FindMember(program_->Symbols().Get(name)));
|
} while (str->FindMember(program_->Symbols().Get(name)));
|
||||||
|
|
||||||
out_ << "int8_t " << name << "[" << size << "];" << std::endl;
|
out_ << "int8_t " << name << "[" << size << "];" << std::endl;
|
||||||
};
|
};
|
||||||
|
|
||||||
increment_indent();
|
increment_indent();
|
||||||
uint32_t msl_offset = 0;
|
uint32_t msl_offset = 0;
|
||||||
for (auto* mem : sem_str->Members()) {
|
for (auto* mem : str->Members()) {
|
||||||
make_indent();
|
make_indent();
|
||||||
|
|
||||||
auto name = program_->Symbols().NameFor(mem->Declaration()->symbol());
|
auto name = program_->Symbols().NameFor(mem->Declaration()->symbol());
|
||||||
|
@ -2142,8 +2136,7 @@ bool GeneratorImpl::EmitStructType(const sem::StructType* str) {
|
||||||
}
|
}
|
||||||
out_ << " [[" << attr << "]]";
|
out_ << " [[" << attr << "]]";
|
||||||
} else if (auto* loc = deco->As<ast::LocationDecoration>()) {
|
} else if (auto* loc = deco->As<ast::LocationDecoration>()) {
|
||||||
auto& pipeline_stage_uses =
|
auto& pipeline_stage_uses = str->PipelineStageUses();
|
||||||
program_->Sem().Get(str)->PipelineStageUses();
|
|
||||||
if (pipeline_stage_uses.size() != 1) {
|
if (pipeline_stage_uses.size() != 1) {
|
||||||
TINT_ICE(diagnostics_) << "invalid entry point IO struct uses";
|
TINT_ICE(diagnostics_) << "invalid entry point IO struct uses";
|
||||||
}
|
}
|
||||||
|
@ -2180,10 +2173,10 @@ bool GeneratorImpl::EmitStructType(const sem::StructType* str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_host_shareable && sem_str->Size() != msl_offset) {
|
if (is_host_shareable && str->Size() != msl_offset) {
|
||||||
make_indent();
|
make_indent();
|
||||||
add_byte_offset_comment(msl_offset);
|
add_byte_offset_comment(msl_offset);
|
||||||
add_padding(sem_str->Size() - msl_offset);
|
add_padding(str->Size() - msl_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
decrement_indent();
|
decrement_indent();
|
||||||
|
@ -2353,15 +2346,10 @@ GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(
|
||||||
return SizeAndAlign{el_size_align.size * num_els, el_size_align.align};
|
return SizeAndAlign{el_size_align.size * num_els, el_size_align.align};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto* str = ty->As<sem::StructType>()) {
|
if (auto* str = ty->As<sem::Struct>()) {
|
||||||
// TODO(crbug.com/tint/650): There's an assumption here that MSL's default
|
// TODO(crbug.com/tint/650): There's an assumption here that MSL's default
|
||||||
// structure size and alignment matches WGSL's. We need to confirm this.
|
// structure size and alignment matches WGSL's. We need to confirm this.
|
||||||
auto* sem = program_->Sem().Get(str);
|
return SizeAndAlign{str->Size(), str->Align()};
|
||||||
if (!sem) {
|
|
||||||
TINT_ICE(diagnostics_) << "Array missing semantic info";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return SizeAndAlign{sem->Size(), sem->Align()};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TINT_UNREACHABLE(diagnostics_) << "Unhandled type " << ty->TypeInfo().name;
|
TINT_UNREACHABLE(diagnostics_) << "Unhandled type " << ty->TypeInfo().name;
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#include "src/ast/unary_op_expression.h"
|
#include "src/ast/unary_op_expression.h"
|
||||||
#include "src/program.h"
|
#include "src/program.h"
|
||||||
#include "src/scope_stack.h"
|
#include "src/scope_stack.h"
|
||||||
#include "src/sem/struct_type.h"
|
#include "src/sem/struct.h"
|
||||||
#include "src/writer/text_generator.h"
|
#include "src/writer/text_generator.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
@ -206,7 +206,7 @@ class GeneratorImpl : public TextGenerator {
|
||||||
/// Handles generating a struct declaration
|
/// Handles generating a struct declaration
|
||||||
/// @param str the struct to generate
|
/// @param str the struct to generate
|
||||||
/// @returns true if the struct is emitted
|
/// @returns true if the struct is emitted
|
||||||
bool EmitStructType(const sem::StructType* str);
|
bool EmitStructType(const sem::Struct* str);
|
||||||
/// Handles emitting a type constructor
|
/// Handles emitting a type constructor
|
||||||
/// @param expr the type constructor expression
|
/// @param expr the type constructor expression
|
||||||
/// @returns true if the constructor is emitted
|
/// @returns true if the constructor is emitted
|
||||||
|
|
|
@ -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) {
|
TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Struct) {
|
||||||
auto str = Structure("S", {
|
auto* str = Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
Member("c", ty.vec3<i32>()),
|
Member("c", ty.vec3<i32>()),
|
||||||
|
|
|
@ -170,7 +170,7 @@ TEST_F(MslGeneratorImplTest,
|
||||||
// const r = colors.col1;
|
// const r = colors.col1;
|
||||||
// const g = colors.col2;
|
// const g = colors.col2;
|
||||||
// }
|
// }
|
||||||
auto interface_struct = Structure(
|
auto* interface_struct = Structure(
|
||||||
"Interface",
|
"Interface",
|
||||||
{
|
{
|
||||||
Member("col1", ty.f32(), {Location(1)}),
|
Member("col1", ty.f32(), {Location(1)}),
|
||||||
|
@ -245,7 +245,7 @@ TEST_F(MslGeneratorImplTest,
|
||||||
// fn vert_main2() -> VertexOutput {
|
// fn vert_main2() -> VertexOutput {
|
||||||
// return foo(0.25);
|
// return foo(0.25);
|
||||||
// }
|
// }
|
||||||
auto vertex_output_struct = Structure(
|
auto* vertex_output_struct = Structure(
|
||||||
"VertexOutput",
|
"VertexOutput",
|
||||||
{Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
|
{Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ vertex tint_symbol_2 vert_main2() {
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest,
|
TEST_F(MslGeneratorImplTest,
|
||||||
Emit_FunctionDecoration_EntryPoint_With_RW_StorageBuffer) {
|
Emit_FunctionDecoration_EntryPoint_With_RW_StorageBuffer) {
|
||||||
auto s = Structure("Data",
|
auto* s = Structure("Data",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
|
@ -345,7 +345,7 @@ fragment void frag_main(device Data& coord [[buffer(0)]]) {
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest,
|
TEST_F(MslGeneratorImplTest,
|
||||||
Emit_FunctionDecoration_EntryPoint_With_RO_StorageBuffer) {
|
Emit_FunctionDecoration_EntryPoint_With_RO_StorageBuffer) {
|
||||||
auto s = Structure("Data",
|
auto* s = Structure("Data",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
|
@ -550,7 +550,7 @@ fragment ep_1_out ep_1(float4 coord [[position]]) {
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest,
|
TEST_F(MslGeneratorImplTest,
|
||||||
Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
|
Emit_Decoration_Called_By_EntryPoint_With_Uniform) {
|
||||||
auto ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
|
auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto* ubo = Global(
|
auto* ubo = Global(
|
||||||
"ubo", ubo_ty, ast::StorageClass::kUniform, nullptr,
|
"ubo", ubo_ty, ast::StorageClass::kUniform, nullptr,
|
||||||
|
@ -601,7 +601,7 @@ fragment void frag_main(constant UBO& ubo [[buffer(0)]]) {
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest,
|
TEST_F(MslGeneratorImplTest,
|
||||||
Emit_FunctionDecoration_Called_By_EntryPoint_With_RW_StorageBuffer) {
|
Emit_FunctionDecoration_Called_By_EntryPoint_With_RW_StorageBuffer) {
|
||||||
auto s = Structure("Data",
|
auto* s = Structure("Data",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
|
@ -657,7 +657,7 @@ fragment void frag_main(device Data& coord [[buffer(0)]]) {
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest,
|
TEST_F(MslGeneratorImplTest,
|
||||||
Emit_FunctionDecoration_Called_By_EntryPoint_With_RO_StorageBuffer) {
|
Emit_FunctionDecoration_Called_By_EntryPoint_With_RO_StorageBuffer) {
|
||||||
auto s = Structure("Data",
|
auto* s = Structure("Data",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
|
@ -796,7 +796,7 @@ TEST_F(MslGeneratorImplTest,
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
auto s = Structure("Data", {Member("d", ty.f32())},
|
auto* s = Structure("Data", {Member("d", ty.f32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
|
||||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||||
|
|
|
@ -173,7 +173,7 @@ TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Pointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, EmitType_Struct) {
|
TEST_F(MslGeneratorImplTest, EmitType_Struct) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
@ -185,14 +185,15 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, EmitType_StructDecl) {
|
TEST_F(MslGeneratorImplTest, EmitType_StructDecl) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
|
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
|
||||||
|
ASSERT_TRUE(gen.EmitStructType(sem_s)) << gen.error();
|
||||||
EXPECT_EQ(gen.result(), R"(struct S {
|
EXPECT_EQ(gen.result(), R"(struct S {
|
||||||
int a;
|
int a;
|
||||||
float b;
|
float b;
|
||||||
|
@ -201,7 +202,7 @@ TEST_F(MslGeneratorImplTest, EmitType_StructDecl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
|
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
|
||||||
auto s =
|
auto* s =
|
||||||
Structure("S",
|
Structure("S",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32(), {MemberSize(32)}),
|
Member("a", ty.i32(), {MemberSize(32)}),
|
||||||
|
@ -238,7 +239,8 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
|
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
|
||||||
|
ASSERT_TRUE(gen.EmitStructType(sem_s)) << gen.error();
|
||||||
|
|
||||||
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
|
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
|
||||||
// for each field of the structure s.
|
// for each field of the structure s.
|
||||||
|
@ -315,20 +317,20 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
|
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
|
||||||
// inner_x: size(1024), align(512)
|
// inner_x: size(1024), align(512)
|
||||||
auto inner_x =
|
auto* inner_x =
|
||||||
Structure("inner_x", {
|
Structure("inner_x", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32(), {MemberAlign(512)}),
|
Member("b", ty.f32(), {MemberAlign(512)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
// inner_y: size(516), align(4)
|
// inner_y: size(516), align(4)
|
||||||
auto inner_y =
|
auto* inner_y =
|
||||||
Structure("inner_y", {
|
Structure("inner_y", {
|
||||||
Member("a", ty.i32(), {MemberSize(512)}),
|
Member("a", ty.i32(), {MemberSize(512)}),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
auto s = Structure("S",
|
auto* s = Structure("S",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", inner_x),
|
Member("b", inner_x),
|
||||||
|
@ -343,7 +345,8 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
|
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
|
||||||
|
ASSERT_TRUE(gen.EmitStructType(sem_s)) << gen.error();
|
||||||
|
|
||||||
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
|
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
|
||||||
// for each field of the structure s.
|
// for each field of the structure s.
|
||||||
|
@ -401,7 +404,8 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
|
TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
|
||||||
// inner: size(1024), align(512)
|
// inner: size(1024), align(512)
|
||||||
auto inner = Structure("inner", {
|
auto* inner =
|
||||||
|
Structure("inner", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32(), {MemberAlign(512)}),
|
Member("b", ty.f32(), {MemberAlign(512)}),
|
||||||
});
|
});
|
||||||
|
@ -415,7 +419,8 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
|
||||||
// array_z: size(4), align(4)
|
// array_z: size(4), align(4)
|
||||||
auto array_z = ty.array<f32>();
|
auto array_z = ty.array<f32>();
|
||||||
|
|
||||||
auto s = Structure("S",
|
auto* s =
|
||||||
|
Structure("S",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", array_x),
|
Member("b", array_x),
|
||||||
|
@ -431,7 +436,8 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
|
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
|
||||||
|
ASSERT_TRUE(gen.EmitStructType(sem_s)) << gen.error();
|
||||||
|
|
||||||
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
|
// ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
|
||||||
// for each field of the structure s.
|
// for each field of the structure s.
|
||||||
|
@ -495,7 +501,7 @@ TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
|
TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
|
||||||
auto s = Structure(
|
auto* s = Structure(
|
||||||
"S",
|
"S",
|
||||||
{
|
{
|
||||||
// uses symbols tint_pad_[0..9] and tint_pad_[20..35]
|
// uses symbols tint_pad_[0..9] and tint_pad_[20..35]
|
||||||
|
@ -533,7 +539,8 @@ TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
|
auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
|
||||||
|
ASSERT_TRUE(gen.EmitStructType(sem_s)) << gen.error();
|
||||||
EXPECT_EQ(gen.result(), R"(struct S {
|
EXPECT_EQ(gen.result(), R"(struct S {
|
||||||
/* 0x0000 */ int tint_pad_2;
|
/* 0x0000 */ int tint_pad_2;
|
||||||
/* 0x0004 */ int8_t tint_pad_10[124];
|
/* 0x0004 */ int8_t tint_pad_10[124];
|
||||||
|
@ -582,7 +589,7 @@ TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
|
||||||
|
|
||||||
// TODO(dsinclair): How to translate [[block]]
|
// TODO(dsinclair): How to translate [[block]]
|
||||||
TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Struct_WithDecoration) {
|
TEST_F(MslGeneratorImplTest, DISABLED_EmitType_Struct_WithDecoration) {
|
||||||
auto s = Structure("S",
|
auto* s = Structure("S",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
|
|
|
@ -65,7 +65,7 @@ TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Array) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Struct) {
|
TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Struct) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
|
|
@ -886,13 +886,13 @@ bool Builder::GenerateMemberAccessor(ast::MemberAccessorExpression* expr,
|
||||||
|
|
||||||
// If the data_type is a structure we're accessing a member, if it's a
|
// If the data_type is a structure we're accessing a member, if it's a
|
||||||
// vector we're accessing a swizzle.
|
// vector we're accessing a swizzle.
|
||||||
if (data_type->Is<sem::StructType>()) {
|
if (auto* str = data_type->As<sem::Struct>()) {
|
||||||
auto* strct = data_type->As<sem::StructType>()->impl();
|
auto* impl = str->Declaration();
|
||||||
auto symbol = expr->member()->symbol();
|
auto symbol = expr->member()->symbol();
|
||||||
|
|
||||||
uint32_t idx = 0;
|
uint32_t idx = 0;
|
||||||
for (; idx < strct->members().size(); ++idx) {
|
for (; idx < impl->members().size(); ++idx) {
|
||||||
auto* member = strct->members()[idx];
|
auto* member = impl->members()[idx];
|
||||||
if (member->symbol() == symbol) {
|
if (member->symbol() == symbol) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1294,8 +1294,8 @@ bool Builder::is_constructor_const(ast::Expression* expr, bool is_global_init) {
|
||||||
subtype = mat->type()->UnwrapAll();
|
subtype = mat->type()->UnwrapAll();
|
||||||
} else if (auto* arr = subtype->As<sem::ArrayType>()) {
|
} else if (auto* arr = subtype->As<sem::ArrayType>()) {
|
||||||
subtype = arr->type()->UnwrapAll();
|
subtype = arr->type()->UnwrapAll();
|
||||||
} else if (auto* str = subtype->As<sem::StructType>()) {
|
} else if (auto* str = subtype->As<sem::Struct>()) {
|
||||||
subtype = builder_.Sem().Get(str)->Members()[i]->Type()->UnwrapAll();
|
subtype = str->Members()[i]->Type()->UnwrapAll();
|
||||||
}
|
}
|
||||||
if (subtype != TypeOf(sc)->UnwrapAll()) {
|
if (subtype != TypeOf(sc)->UnwrapAll()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1373,8 +1373,7 @@ uint32_t Builder::GenerateTypeConstructorExpression(
|
||||||
// If the result is not a vector then we should have validated that the
|
// If the result is not a vector then we should have validated that the
|
||||||
// value type is a correctly sized vector so we can just use it directly.
|
// value type is a correctly sized vector so we can just use it directly.
|
||||||
if (result_type == value_type || result_type->Is<sem::Matrix>() ||
|
if (result_type == value_type || result_type->Is<sem::Matrix>() ||
|
||||||
result_type->Is<sem::ArrayType>() ||
|
result_type->Is<sem::ArrayType>() || result_type->Is<sem::Struct>()) {
|
||||||
result_type->Is<sem::StructType>()) {
|
|
||||||
out << "_" << id;
|
out << "_" << id;
|
||||||
|
|
||||||
ops.push_back(Operand::Int(id));
|
ops.push_back(Operand::Int(id));
|
||||||
|
@ -2024,14 +2023,14 @@ uint32_t Builder::GenerateIntrinsic(ast::CallExpression* call,
|
||||||
params.push_back(Operand::Int(struct_id));
|
params.push_back(Operand::Int(struct_id));
|
||||||
|
|
||||||
auto* type = TypeOf(accessor->structure())->UnwrapAll();
|
auto* type = TypeOf(accessor->structure())->UnwrapAll();
|
||||||
if (!type->Is<sem::StructType>()) {
|
if (!type->Is<sem::Struct>()) {
|
||||||
error_ =
|
error_ =
|
||||||
"invalid type (" + type->type_name() + ") for runtime array length";
|
"invalid type (" + type->type_name() + ") for runtime array length";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Runtime array must be the last member in the structure
|
// Runtime array must be the last member in the structure
|
||||||
params.push_back(Operand::Int(
|
params.push_back(Operand::Int(uint32_t(
|
||||||
uint32_t(type->As<sem::StructType>()->impl()->members().size() - 1)));
|
type->As<sem::Struct>()->Declaration()->members().size() - 1)));
|
||||||
|
|
||||||
if (!push_function_inst(spv::Op::OpArrayLength, params)) {
|
if (!push_function_inst(spv::Op::OpArrayLength, params)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2978,7 +2977,7 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
|
||||||
return GenerateTypeIfNeeded(alias->type());
|
return GenerateTypeIfNeeded(alias->type());
|
||||||
}
|
}
|
||||||
if (auto* ac = type->As<sem::AccessControl>()) {
|
if (auto* ac = type->As<sem::AccessControl>()) {
|
||||||
if (!ac->type()->UnwrapIfNeeded()->Is<sem::StructType>()) {
|
if (!ac->type()->UnwrapIfNeeded()->Is<sem::Struct>()) {
|
||||||
return GenerateTypeIfNeeded(ac->type());
|
return GenerateTypeIfNeeded(ac->type());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2993,8 +2992,8 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
|
||||||
if (auto* ac = type->As<sem::AccessControl>()) {
|
if (auto* ac = type->As<sem::AccessControl>()) {
|
||||||
// The non-struct case was handled above.
|
// The non-struct case was handled above.
|
||||||
auto* subtype = ac->type()->UnwrapIfNeeded();
|
auto* subtype = ac->type()->UnwrapIfNeeded();
|
||||||
if (!GenerateStructType(subtype->As<sem::StructType>(),
|
if (!GenerateStructType(subtype->As<sem::Struct>(), ac->access_control(),
|
||||||
ac->access_control(), result)) {
|
result)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (auto* arr = type->As<sem::ArrayType>()) {
|
} else if (auto* arr = type->As<sem::ArrayType>()) {
|
||||||
|
@ -3015,7 +3014,7 @@ uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
|
||||||
if (!GeneratePointerType(ptr, result)) {
|
if (!GeneratePointerType(ptr, result)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (auto* str = type->As<sem::StructType>()) {
|
} else if (auto* str = type->As<sem::Struct>()) {
|
||||||
if (!GenerateStructType(str, ast::AccessControl::kReadWrite, result)) {
|
if (!GenerateStructType(str, ast::AccessControl::kReadWrite, result)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3190,16 +3189,16 @@ bool Builder::GeneratePointerType(const sem::Pointer* ptr,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Builder::GenerateStructType(const sem::StructType* struct_type,
|
bool Builder::GenerateStructType(const sem::Struct* struct_type,
|
||||||
ast::AccessControl::Access access_control,
|
ast::AccessControl::Access access_control,
|
||||||
const Operand& result) {
|
const Operand& result) {
|
||||||
auto struct_id = result.to_i();
|
auto struct_id = result.to_i();
|
||||||
auto* impl = struct_type->impl();
|
auto* impl = struct_type->Declaration();
|
||||||
|
|
||||||
if (struct_type->impl()->name().IsValid()) {
|
if (impl->name().IsValid()) {
|
||||||
push_debug(spv::Op::OpName, {Operand::Int(struct_id),
|
push_debug(spv::Op::OpName,
|
||||||
Operand::String(builder_.Symbols().NameFor(
|
{Operand::Int(struct_id),
|
||||||
struct_type->impl()->name()))});
|
Operand::String(builder_.Symbols().NameFor(impl->name()))});
|
||||||
}
|
}
|
||||||
|
|
||||||
OperandList ops;
|
OperandList ops;
|
||||||
|
|
|
@ -449,7 +449,7 @@ class Builder {
|
||||||
/// @param access_control the access controls to assign to the struct
|
/// @param access_control the access controls to assign to the struct
|
||||||
/// @param result the result operand
|
/// @param result the result operand
|
||||||
/// @returns true if the vector was successfully generated
|
/// @returns true if the vector was successfully generated
|
||||||
bool GenerateStructType(const sem::StructType* struct_type,
|
bool GenerateStructType(const sem::Struct* struct_type,
|
||||||
ast::AccessControl::Access access_control,
|
ast::AccessControl::Access access_control,
|
||||||
const Operand& result);
|
const Operand& result);
|
||||||
/// Generates a struct member
|
/// Generates a struct member
|
||||||
|
|
|
@ -219,7 +219,7 @@ TEST_F(BuilderTest, MemberAccessor) {
|
||||||
// var ident : my_struct
|
// var ident : my_struct
|
||||||
// ident.b
|
// ident.b
|
||||||
|
|
||||||
auto s = Structure("my_struct", {
|
auto* s = Structure("my_struct", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
@ -263,12 +263,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested) {
|
||||||
//
|
//
|
||||||
// var ident : my_struct
|
// var ident : my_struct
|
||||||
// ident.inner.a
|
// ident.inner.a
|
||||||
auto inner_struct = Structure("Inner", {
|
auto* inner_struct = Structure("Inner", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
auto s_type = Structure("my_struct", {Member("inner", inner_struct)});
|
auto* s_type = Structure("my_struct", {Member("inner", inner_struct)});
|
||||||
|
|
||||||
auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
|
auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
|
||||||
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
|
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
|
||||||
|
@ -307,7 +307,7 @@ TEST_F(BuilderTest, MemberAccessor_NonPointer) {
|
||||||
// let ident : my_struct = my_struct();
|
// let ident : my_struct = my_struct();
|
||||||
// ident.b
|
// ident.b
|
||||||
|
|
||||||
auto s = Structure("my_struct", {
|
auto* s = Structure("my_struct", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
@ -345,12 +345,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested_NonPointer) {
|
||||||
//
|
//
|
||||||
// let ident : my_struct = my_struct();
|
// let ident : my_struct = my_struct();
|
||||||
// ident.inner.a
|
// ident.inner.a
|
||||||
auto inner_struct = Structure("Inner", {
|
auto* inner_struct = Structure("Inner", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
auto s_type = Structure("my_struct", {Member("inner", inner_struct)});
|
auto* s_type = Structure("my_struct", {Member("inner", inner_struct)});
|
||||||
|
|
||||||
auto* var = GlobalConst("ident", s_type,
|
auto* var = GlobalConst("ident", s_type,
|
||||||
Construct(s_type, Construct(inner_struct, 0.f, 0.f)));
|
Construct(s_type, Construct(inner_struct, 0.f, 0.f)));
|
||||||
|
@ -388,13 +388,13 @@ TEST_F(BuilderTest, MemberAccessor_Nested_WithAlias) {
|
||||||
//
|
//
|
||||||
// var ident : my_struct
|
// var ident : my_struct
|
||||||
// ident.inner.a
|
// ident.inner.a
|
||||||
auto inner_struct = Structure("Inner", {
|
auto* inner_struct = Structure("Inner", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
auto alias = ty.alias("Inner", inner_struct);
|
auto alias = ty.alias("Inner", inner_struct);
|
||||||
auto s_type = Structure("Outer", {Member("inner", alias)});
|
auto* s_type = Structure("Outer", {Member("inner", alias)});
|
||||||
|
|
||||||
auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
|
auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
|
||||||
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "a");
|
auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "a");
|
||||||
|
@ -434,12 +434,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_LHS) {
|
||||||
//
|
//
|
||||||
// var ident : my_struct
|
// var ident : my_struct
|
||||||
// ident.inner.a = 2.0f;
|
// ident.inner.a = 2.0f;
|
||||||
auto inner_struct = Structure("Inner", {
|
auto* inner_struct = Structure("Inner", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
auto s_type = Structure("my_struct", {Member("inner", inner_struct)});
|
auto* s_type = Structure("my_struct", {Member("inner", inner_struct)});
|
||||||
|
|
||||||
auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
|
auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
|
||||||
auto* expr =
|
auto* expr =
|
||||||
|
@ -483,12 +483,12 @@ TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_RHS) {
|
||||||
// var ident : my_struct
|
// var ident : my_struct
|
||||||
// var store : f32 = ident.inner.a
|
// var store : f32 = ident.inner.a
|
||||||
|
|
||||||
auto inner_struct = Structure("Inner", {
|
auto* inner_struct = Structure("Inner", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
|
||||||
auto s_type = Structure("my_struct", {Member("inner", inner_struct)});
|
auto* s_type = Structure("my_struct", {Member("inner", inner_struct)});
|
||||||
|
|
||||||
auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
|
auto* var = Global("ident", s_type, ast::StorageClass::kFunction);
|
||||||
auto* store = Global("store", ty.f32(), ast::StorageClass::kFunction);
|
auto* store = Global("store", ty.f32(), ast::StorageClass::kFunction);
|
||||||
|
@ -693,11 +693,11 @@ TEST_F(BuilderTest, Accessor_Mixed_ArrayAndMember) {
|
||||||
// var index : array<A, 2>
|
// var index : array<A, 2>
|
||||||
// index[0].foo[2].bar.baz.yx
|
// index[0].foo[2].bar.baz.yx
|
||||||
|
|
||||||
auto c_type = Structure("C", {Member("baz", ty.vec3<f32>())});
|
auto* c_type = Structure("C", {Member("baz", ty.vec3<f32>())});
|
||||||
|
|
||||||
auto b_type = Structure("B", {Member("bar", c_type)});
|
auto* b_type = Structure("B", {Member("bar", c_type)});
|
||||||
auto b_ary_type = ty.array(b_type, 3);
|
auto b_ary_type = ty.array(b_type, 3);
|
||||||
auto a_type = Structure("A", {Member("foo", b_ary_type)});
|
auto* a_type = Structure("A", {Member("foo", b_ary_type)});
|
||||||
|
|
||||||
auto a_ary_type = ty.array(a_type, 2);
|
auto a_ary_type = ty.array(a_type, 2);
|
||||||
auto* var = Global("index", a_ary_type, ast::StorageClass::kFunction);
|
auto* var = Global("index", a_ary_type, ast::StorageClass::kFunction);
|
||||||
|
|
|
@ -176,7 +176,7 @@ TEST_F(BuilderTest, Assign_StructMember) {
|
||||||
// var ident : my_struct
|
// var ident : my_struct
|
||||||
// ident.b = 4.0;
|
// ident.b = 4.0;
|
||||||
|
|
||||||
auto s = Structure("my_struct", {
|
auto* s = Structure("my_struct", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
|
|
@ -1052,7 +1052,7 @@ TEST_F(SpvBuilderConstructorTest, CommonInitializer_Array_VecArray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpvBuilderConstructorTest, Type_Struct) {
|
TEST_F(SpvBuilderConstructorTest, Type_Struct) {
|
||||||
auto s = Structure("my_struct", {
|
auto* s = Structure("my_struct", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.vec3<f32>()),
|
Member("b", ty.vec3<f32>()),
|
||||||
});
|
});
|
||||||
|
@ -1202,7 +1202,7 @@ TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Array) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Struct) {
|
TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Struct) {
|
||||||
auto s = Structure("my_struct", {Member("a", ty.f32())});
|
auto* s = Structure("my_struct", {Member("a", ty.f32())});
|
||||||
auto* t = Construct(s);
|
auto* t = Construct(s);
|
||||||
WrapInFunction(t);
|
WrapInFunction(t);
|
||||||
|
|
||||||
|
@ -1622,7 +1622,7 @@ TEST_F(SpvBuilderConstructorTest, IsConstructorConst_BitCastScalars) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct) {
|
TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct) {
|
||||||
auto s = Structure("my_struct", {
|
auto* s = Structure("my_struct", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.vec3<f32>()),
|
Member("b", ty.vec3<f32>()),
|
||||||
});
|
});
|
||||||
|
@ -1638,7 +1638,7 @@ TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct) {
|
||||||
|
|
||||||
TEST_F(SpvBuilderConstructorTest,
|
TEST_F(SpvBuilderConstructorTest,
|
||||||
IsConstructorConst_Struct_WithIdentSubExpression) {
|
IsConstructorConst_Struct_WithIdentSubExpression) {
|
||||||
auto s = Structure("my_struct", {
|
auto* s = Structure("my_struct", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.vec3<f32>()),
|
Member("b", ty.vec3<f32>()),
|
||||||
});
|
});
|
||||||
|
|
|
@ -188,7 +188,7 @@ TEST_F(BuilderTest, EntryPoint_SharedStruct) {
|
||||||
// return inputs.value;
|
// return inputs.value;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
auto interface = Structure(
|
auto* interface = Structure(
|
||||||
"Interface",
|
"Interface",
|
||||||
{
|
{
|
||||||
Member("value", ty.f32(), ast::DecorationList{Location(1u)}),
|
Member("value", ty.f32(), ast::DecorationList{Location(1u)}),
|
||||||
|
|
|
@ -201,7 +201,7 @@ TEST_F(BuilderTest, Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
auto s = Structure("Data", {Member("d", ty.f32())},
|
auto* s = Structure("Data", {Member("d", ty.f32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
|
||||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||||
|
|
|
@ -376,7 +376,7 @@ TEST_F(BuilderTest, GlobalVar_DeclReadOnly) {
|
||||||
// };
|
// };
|
||||||
// var b : [[access(read)]] A
|
// var b : [[access(read)]] A
|
||||||
|
|
||||||
auto A = Structure("A",
|
auto* A = Structure("A",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.i32()),
|
Member("b", ty.i32()),
|
||||||
|
@ -415,7 +415,7 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasDeclReadOnly) {
|
||||||
// type B = A;
|
// type B = A;
|
||||||
// var b : [[access(read)]] B
|
// var b : [[access(read)]] B
|
||||||
|
|
||||||
auto A = Structure("A", {Member("a", ty.i32())},
|
auto* A = Structure("A", {Member("a", ty.i32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto B = ty.alias("B", A);
|
auto B = ty.alias("B", A);
|
||||||
AST().AddConstructedType(B);
|
AST().AddConstructedType(B);
|
||||||
|
@ -448,7 +448,7 @@ TEST_F(BuilderTest, GlobalVar_TypeAliasAssignReadOnly) {
|
||||||
// type B = [[access(read)]] A;
|
// type B = [[access(read)]] A;
|
||||||
// var b : B
|
// var b : B
|
||||||
|
|
||||||
auto A = Structure("A", {Member("a", ty.i32())},
|
auto* A = Structure("A", {Member("a", ty.i32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, A);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, A);
|
||||||
auto B = ty.alias("B", ac);
|
auto B = ty.alias("B", ac);
|
||||||
|
@ -481,7 +481,7 @@ TEST_F(BuilderTest, GlobalVar_TwoVarDeclReadOnly) {
|
||||||
// var b : [[access(read)]] A
|
// var b : [[access(read)]] A
|
||||||
// var c : [[access(read_write)]] A
|
// var c : [[access(read_write)]] A
|
||||||
|
|
||||||
auto A = Structure("A", {Member("a", ty.i32())},
|
auto* A = Structure("A", {Member("a", ty.i32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto read = ty.access(ast::AccessControl::kReadOnly, A);
|
auto read = ty.access(ast::AccessControl::kReadOnly, A);
|
||||||
auto rw = ty.access(ast::AccessControl::kReadWrite, A);
|
auto rw = ty.access(ast::AccessControl::kReadWrite, A);
|
||||||
|
|
|
@ -1379,7 +1379,7 @@ OpFunctionEnd
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
|
TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
|
||||||
auto s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
|
auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
Global("b", ac, ast::StorageClass::kStorage, nullptr,
|
Global("b", ac, ast::StorageClass::kStorage, nullptr,
|
||||||
|
@ -1425,7 +1425,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
|
TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
|
||||||
auto s = Structure("my_struct",
|
auto* s = Structure("my_struct",
|
||||||
{
|
{
|
||||||
Member(0, "z", ty.f32()),
|
Member(0, "z", ty.f32()),
|
||||||
Member(4, "a", ty.array<f32>(4)),
|
Member(4, "a", ty.array<f32>(4)),
|
||||||
|
|
|
@ -59,7 +59,7 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedAlias) {
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
|
TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
|
||||||
auto ary = ty.array(ty.i32(), 0);
|
auto ary = ty.array(ty.i32(), 0);
|
||||||
auto str = Structure("S", {Member("x", ary)},
|
auto* str = Structure("S", {Member("x", ary)},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, str);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, str);
|
||||||
Global("a", ac, ast::StorageClass::kStorage);
|
Global("a", ac, ast::StorageClass::kStorage);
|
||||||
|
@ -77,7 +77,7 @@ TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) {
|
TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) {
|
||||||
auto ary = ty.array(ty.i32(), 0);
|
auto ary = ty.array(ty.i32(), 0);
|
||||||
auto str = Structure("S", {Member("x", ary)},
|
auto* str = Structure("S", {Member("x", ary)},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, str);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, str);
|
||||||
Global("a", ac, ast::StorageClass::kStorage);
|
Global("a", ac, ast::StorageClass::kStorage);
|
||||||
|
@ -285,11 +285,11 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedPtr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type, GenerateStruct_Empty) {
|
TEST_F(BuilderTest_Type, GenerateStruct_Empty) {
|
||||||
auto s = Structure("S", {});
|
auto* s = Structure("S", {});
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
auto id = b.GenerateTypeIfNeeded(s);
|
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||||
ASSERT_FALSE(b.has_error()) << b.error();
|
ASSERT_FALSE(b.has_error()) << b.error();
|
||||||
EXPECT_EQ(id, 1u);
|
EXPECT_EQ(id, 1u);
|
||||||
|
|
||||||
|
@ -301,11 +301,11 @@ TEST_F(BuilderTest_Type, GenerateStruct_Empty) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type, GenerateStruct) {
|
TEST_F(BuilderTest_Type, GenerateStruct) {
|
||||||
auto s = Structure("my_struct", {Member("a", ty.f32())});
|
auto* s = Structure("my_struct", {Member("a", ty.f32())});
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
auto id = b.GenerateTypeIfNeeded(s);
|
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||||
ASSERT_FALSE(b.has_error()) << b.error();
|
ASSERT_FALSE(b.has_error()) << b.error();
|
||||||
EXPECT_EQ(id, 1u);
|
EXPECT_EQ(id, 1u);
|
||||||
|
|
||||||
|
@ -318,12 +318,12 @@ OpMemberName %1 0 "a"
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type, GenerateStruct_Decorated) {
|
TEST_F(BuilderTest_Type, GenerateStruct_Decorated) {
|
||||||
auto s = Structure("my_struct", {Member("a", ty.f32())},
|
auto* s = Structure("my_struct", {Member("a", ty.f32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
auto id = b.GenerateTypeIfNeeded(s);
|
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||||
ASSERT_FALSE(b.has_error()) << b.error();
|
ASSERT_FALSE(b.has_error()) << b.error();
|
||||||
EXPECT_EQ(id, 1u);
|
EXPECT_EQ(id, 1u);
|
||||||
|
|
||||||
|
@ -339,14 +339,14 @@ OpMemberDecorate %1 0 Offset 0
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) {
|
TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.f32(), {MemberAlign(8)}),
|
Member("b", ty.f32(), {MemberAlign(8)}),
|
||||||
});
|
});
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
auto id = b.GenerateTypeIfNeeded(s);
|
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||||
ASSERT_FALSE(b.has_error()) << b.error();
|
ASSERT_FALSE(b.has_error()) << b.error();
|
||||||
EXPECT_EQ(id, 1u);
|
EXPECT_EQ(id, 1u);
|
||||||
|
|
||||||
|
@ -363,7 +363,7 @@ OpMemberDecorate %1 1 Offset 8
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type, GenerateStruct_NonLayout_Matrix) {
|
TEST_F(BuilderTest_Type, GenerateStruct_NonLayout_Matrix) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.mat2x2<f32>()),
|
Member("a", ty.mat2x2<f32>()),
|
||||||
Member("b", ty.mat2x3<f32>()),
|
Member("b", ty.mat2x3<f32>()),
|
||||||
Member("c", ty.mat4x4<f32>()),
|
Member("c", ty.mat4x4<f32>()),
|
||||||
|
@ -371,7 +371,7 @@ TEST_F(BuilderTest_Type, GenerateStruct_NonLayout_Matrix) {
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
auto id = b.GenerateTypeIfNeeded(s);
|
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||||
ASSERT_FALSE(b.has_error()) << b.error();
|
ASSERT_FALSE(b.has_error()) << b.error();
|
||||||
EXPECT_EQ(id, 1u);
|
EXPECT_EQ(id, 1u);
|
||||||
|
|
||||||
|
@ -403,7 +403,7 @@ OpMemberDecorate %1 2 MatrixStride 16
|
||||||
|
|
||||||
TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutMatrix) {
|
TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutMatrix) {
|
||||||
// We have to infer layout for matrix when it also has an offset.
|
// We have to infer layout for matrix when it also has an offset.
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.mat2x2<f32>()),
|
Member("a", ty.mat2x2<f32>()),
|
||||||
Member("b", ty.mat2x3<f32>()),
|
Member("b", ty.mat2x3<f32>()),
|
||||||
Member("c", ty.mat4x4<f32>()),
|
Member("c", ty.mat4x4<f32>()),
|
||||||
|
@ -411,7 +411,7 @@ TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutMatrix) {
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
auto id = b.GenerateTypeIfNeeded(s);
|
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||||
ASSERT_FALSE(b.has_error()) << b.error();
|
ASSERT_FALSE(b.has_error()) << b.error();
|
||||||
EXPECT_EQ(id, 1u);
|
EXPECT_EQ(id, 1u);
|
||||||
|
|
||||||
|
@ -449,7 +449,8 @@ TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutArraysOfMatrix) {
|
||||||
auto arr_arr_mat2x3 = ty.array(ty.mat2x3<f32>(), 1); // Doubly nested array
|
auto arr_arr_mat2x3 = ty.array(ty.mat2x3<f32>(), 1); // Doubly nested array
|
||||||
auto rtarr_mat4x4 = ty.array(ty.mat4x4<f32>(), 0); // Runtime array
|
auto rtarr_mat4x4 = ty.array(ty.mat4x4<f32>(), 0); // Runtime array
|
||||||
|
|
||||||
auto s = Structure("S",
|
auto* s =
|
||||||
|
Structure("S",
|
||||||
{
|
{
|
||||||
Member("a", arr_mat2x2),
|
Member("a", arr_mat2x2),
|
||||||
Member("b", arr_arr_mat2x3),
|
Member("b", arr_arr_mat2x3),
|
||||||
|
@ -459,7 +460,7 @@ TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutArraysOfMatrix) {
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
auto id = b.GenerateTypeIfNeeded(s);
|
auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
|
||||||
ASSERT_FALSE(b.has_error()) << b.error();
|
ASSERT_FALSE(b.has_error()) << b.error();
|
||||||
EXPECT_EQ(id, 1u);
|
EXPECT_EQ(id, 1u);
|
||||||
|
|
||||||
|
|
|
@ -147,8 +147,8 @@ bool GeneratorImpl::EmitConstructedType(typ::Type type) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out_ << ";" << std::endl;
|
out_ << ";" << std::endl;
|
||||||
} else if (auto* str = ty->As<sem::StructType>()) {
|
} else if (auto* str = ty->As<sem::Struct>()) {
|
||||||
if (!EmitStructType(str->impl())) {
|
if (!EmitStructType(str->Declaration())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -599,10 +599,10 @@ bool GeneratorImpl::EmitType(typ::Type type) {
|
||||||
if (sampler->IsComparison()) {
|
if (sampler->IsComparison()) {
|
||||||
out_ << "_comparison";
|
out_ << "_comparison";
|
||||||
}
|
}
|
||||||
} else if (auto* str = ty->As<sem::StructType>()) {
|
} else if (auto* str = ty->As<sem::Struct>()) {
|
||||||
// The struct, as a type, is just the name. We should have already emitted
|
// The struct, as a type, is just the name. We should have already emitted
|
||||||
// the declaration through a call to |EmitStructType| earlier.
|
// the declaration through a call to |EmitStructType| earlier.
|
||||||
out_ << program_->Symbols().NameFor(str->impl()->name());
|
out_ << program_->Symbols().NameFor(str->Declaration()->name());
|
||||||
} else if (auto* texture = ty->As<sem::Texture>()) {
|
} else if (auto* texture = ty->As<sem::Texture>()) {
|
||||||
out_ << "texture_";
|
out_ << "texture_";
|
||||||
if (texture->Is<sem::DepthTexture>()) {
|
if (texture->Is<sem::DepthTexture>()) {
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#include "src/ast/unary_op_expression.h"
|
#include "src/ast/unary_op_expression.h"
|
||||||
#include "src/program.h"
|
#include "src/program.h"
|
||||||
#include "src/sem/storage_texture_type.h"
|
#include "src/sem/storage_texture_type.h"
|
||||||
#include "src/sem/struct_type.h"
|
#include "src/sem/struct.h"
|
||||||
#include "src/writer/text_generator.h"
|
#include "src/writer/text_generator.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
|
|
@ -31,7 +31,7 @@ TEST_F(WgslGeneratorImplTest, EmitAlias_F32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitConstructedType_Struct) {
|
TEST_F(WgslGeneratorImplTest, EmitConstructedType_Struct) {
|
||||||
auto s = Structure("A", {
|
auto* s = Structure("A", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.i32()),
|
Member("b", ty.i32()),
|
||||||
});
|
});
|
||||||
|
@ -51,7 +51,7 @@ type B = A;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitAlias_ToStruct) {
|
TEST_F(WgslGeneratorImplTest, EmitAlias_ToStruct) {
|
||||||
auto s = Structure("A", {
|
auto* s = Structure("A", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
Member("b", ty.i32()),
|
Member("b", ty.i32()),
|
||||||
});
|
});
|
||||||
|
|
|
@ -202,7 +202,7 @@ TEST_F(WgslGeneratorImplTest,
|
||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
auto s = Structure("Data", {Member("d", ty.f32())},
|
auto* s = Structure("Data", {Member("d", ty.f32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
|
||||||
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
auto ac = ty.access(ast::AccessControl::kReadWrite, s);
|
||||||
|
|
|
@ -48,7 +48,7 @@ TEST_F(WgslGeneratorImplTest, Emit_GlobalDeclAfterFunction) {
|
||||||
TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
|
TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
|
||||||
Global("a0", ty.f32(), ast::StorageClass::kPrivate);
|
Global("a0", ty.f32(), ast::StorageClass::kPrivate);
|
||||||
|
|
||||||
auto s0 = Structure("S0", {Member("a", ty.i32())});
|
auto* s0 = Structure("S0", {Member("a", ty.i32())});
|
||||||
|
|
||||||
Func("func", ast::VariableList{}, ty.f32(),
|
Func("func", ast::VariableList{}, ty.f32(),
|
||||||
ast::StatementList{
|
ast::StatementList{
|
||||||
|
@ -58,7 +58,7 @@ TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
|
||||||
|
|
||||||
Global("a1", ty.f32(), ast::StorageClass::kOutput);
|
Global("a1", ty.f32(), ast::StorageClass::kOutput);
|
||||||
|
|
||||||
auto s1 = Structure("S1", {Member("a", ty.i32())});
|
auto* s1 = Structure("S1", {Member("a", ty.i32())});
|
||||||
|
|
||||||
Func("main", ast::VariableList{}, ty.void_(),
|
Func("main", ast::VariableList{}, ty.void_(),
|
||||||
ast::StatementList{
|
ast::StatementList{
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace {
|
||||||
using WgslGeneratorImplTest = TestHelper;
|
using WgslGeneratorImplTest = TestHelper;
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor) {
|
TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor) {
|
||||||
auto s = Structure("Data", {Member("mem", ty.f32())});
|
auto* s = Structure("Data", {Member("mem", ty.f32())});
|
||||||
Global("str", s, ast::StorageClass::kPrivate);
|
Global("str", s, ast::StorageClass::kPrivate);
|
||||||
|
|
||||||
auto* expr = MemberAccessor("str", "mem");
|
auto* expr = MemberAccessor("str", "mem");
|
||||||
|
|
|
@ -47,7 +47,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_Array) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_Read) {
|
TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_Read) {
|
||||||
auto s = Structure("S", {Member("a", ty.i32())},
|
auto* s = Structure("S", {Member("a", ty.i32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
|
||||||
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
auto a = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
@ -60,7 +60,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_Read) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_ReadWrite) {
|
TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_ReadWrite) {
|
||||||
auto s = Structure("S", {Member("a", ty.i32())},
|
auto* s = Structure("S", {Member("a", ty.i32())},
|
||||||
{create<ast::StructBlockDecoration>()});
|
{create<ast::StructBlockDecoration>()});
|
||||||
|
|
||||||
auto a = ty.access(ast::AccessControl::kReadWrite, s);
|
auto a = ty.access(ast::AccessControl::kReadWrite, s);
|
||||||
|
@ -143,7 +143,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_Pointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitType_Struct) {
|
TEST_F(WgslGeneratorImplTest, EmitType_Struct) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32()),
|
Member("b", ty.f32()),
|
||||||
});
|
});
|
||||||
|
@ -155,7 +155,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_Struct) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl) {
|
TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.i32(), {MemberOffset(8)}),
|
Member("a", ty.i32(), {MemberOffset(8)}),
|
||||||
Member("b", ty.f32(), {MemberOffset(16)}),
|
Member("b", ty.f32(), {MemberOffset(16)}),
|
||||||
});
|
});
|
||||||
|
@ -175,7 +175,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) {
|
TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) {
|
||||||
auto s =
|
auto* s =
|
||||||
Structure("S", {
|
Structure("S", {
|
||||||
Member("tint_0_padding", ty.i32(), {MemberOffset(8)}),
|
Member("tint_0_padding", ty.i32(), {MemberOffset(8)}),
|
||||||
Member("tint_2_padding", ty.f32(), {MemberOffset(16)}),
|
Member("tint_2_padding", ty.f32(), {MemberOffset(16)}),
|
||||||
|
@ -196,7 +196,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) {
|
TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.i32(), {MemberAlign(8)}),
|
Member("a", ty.i32(), {MemberAlign(8)}),
|
||||||
Member("b", ty.f32(), {MemberAlign(16)}),
|
Member("b", ty.f32(), {MemberAlign(16)}),
|
||||||
});
|
});
|
||||||
|
@ -214,7 +214,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) {
|
TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) {
|
||||||
auto s = Structure("S", {
|
auto* s = Structure("S", {
|
||||||
Member("a", ty.i32(), {MemberSize(16)}),
|
Member("a", ty.i32(), {MemberSize(16)}),
|
||||||
Member("b", ty.f32(), {MemberSize(32)}),
|
Member("b", ty.f32(), {MemberSize(32)}),
|
||||||
});
|
});
|
||||||
|
@ -232,7 +232,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithDecoration) {
|
TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithDecoration) {
|
||||||
auto s = Structure("S",
|
auto* s = Structure("S",
|
||||||
{
|
{
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", ty.f32(), {MemberAlign(8)}),
|
Member("b", ty.f32(), {MemberAlign(8)}),
|
||||||
|
@ -255,7 +255,7 @@ TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithEntryPointDecorations) {
|
||||||
ast::DecorationList decos;
|
ast::DecorationList decos;
|
||||||
decos.push_back(create<ast::StructBlockDecoration>());
|
decos.push_back(create<ast::StructBlockDecoration>());
|
||||||
|
|
||||||
auto s = Structure(
|
auto* s = Structure(
|
||||||
"S",
|
"S",
|
||||||
ast::StructMemberList{
|
ast::StructMemberList{
|
||||||
Member("a", ty.u32(), {Builtin(ast::Builtin::kVertexIndex)}),
|
Member("a", ty.u32(), {Builtin(ast::Builtin::kVertexIndex)}),
|
||||||
|
|
|
@ -281,8 +281,8 @@ tint_unittests_source_set("tint_unittests_core_src") {
|
||||||
"../src/sem/pointer_type_test.cc",
|
"../src/sem/pointer_type_test.cc",
|
||||||
"../src/sem/sampled_texture_type_test.cc",
|
"../src/sem/sampled_texture_type_test.cc",
|
||||||
"../src/sem/sampler_type_test.cc",
|
"../src/sem/sampler_type_test.cc",
|
||||||
|
"../src/sem/sem_struct_test.cc",
|
||||||
"../src/sem/storage_texture_type_test.cc",
|
"../src/sem/storage_texture_type_test.cc",
|
||||||
"../src/sem/struct_type_test.cc",
|
|
||||||
"../src/sem/texture_type_test.cc",
|
"../src/sem/texture_type_test.cc",
|
||||||
"../src/sem/type_manager_test.cc",
|
"../src/sem/type_manager_test.cc",
|
||||||
"../src/sem/u32_type_test.cc",
|
"../src/sem/u32_type_test.cc",
|
||||||
|
@ -521,7 +521,6 @@ tint_unittests_source_set("tint_unittests_wgsl_writer_src") {
|
||||||
tint_unittests_source_set("tint_unittests_msl_writer_src") {
|
tint_unittests_source_set("tint_unittests_msl_writer_src") {
|
||||||
sources = [
|
sources = [
|
||||||
"../src/transform/msl_test.cc",
|
"../src/transform/msl_test.cc",
|
||||||
"../src/writer/msl/generator_impl_alias_type_test.cc",
|
|
||||||
"../src/writer/msl/generator_impl_array_accessor_test.cc",
|
"../src/writer/msl/generator_impl_array_accessor_test.cc",
|
||||||
"../src/writer/msl/generator_impl_assign_test.cc",
|
"../src/writer/msl/generator_impl_assign_test.cc",
|
||||||
"../src/writer/msl/generator_impl_binary_test.cc",
|
"../src/writer/msl/generator_impl_binary_test.cc",
|
||||||
|
@ -560,7 +559,6 @@ tint_unittests_source_set("tint_unittests_msl_writer_src") {
|
||||||
tint_unittests_source_set("tint_unittests_hlsl_writer_src") {
|
tint_unittests_source_set("tint_unittests_hlsl_writer_src") {
|
||||||
sources = [
|
sources = [
|
||||||
"../src/transform/hlsl_test.cc",
|
"../src/transform/hlsl_test.cc",
|
||||||
"../src/writer/hlsl/generator_impl_alias_type_test.cc",
|
|
||||||
"../src/writer/hlsl/generator_impl_array_accessor_test.cc",
|
"../src/writer/hlsl/generator_impl_array_accessor_test.cc",
|
||||||
"../src/writer/hlsl/generator_impl_assign_test.cc",
|
"../src/writer/hlsl/generator_impl_assign_test.cc",
|
||||||
"../src/writer/hlsl/generator_impl_binary_test.cc",
|
"../src/writer/hlsl/generator_impl_binary_test.cc",
|
||||||
|
|
Loading…
Reference in New Issue