resolver: Resolve atomic types
Bug: tint:892 Change-Id: Ib595378b3b126a8f6bc4712ece943ba70816cb46 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/54647 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: David Neto <dneto@google.com> Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
cf1613ee35
commit
313e6184e6
|
@ -591,6 +591,8 @@ if(${TINT_BUILD_TESTS})
|
|||
intrinsic_table_test.cc
|
||||
program_test.cc
|
||||
resolver/assignment_validation_test.cc
|
||||
resolver/atomics_test.cc
|
||||
resolver/atomics_validation_test.cc
|
||||
resolver/block_test.cc
|
||||
resolver/builtins_validation_test.cc
|
||||
resolver/call_test.cc
|
||||
|
|
|
@ -745,6 +745,12 @@ class ProgramBuilder {
|
|||
return builder->create<ast::Atomic>(source, type);
|
||||
}
|
||||
|
||||
/// @param type the type of the atomic
|
||||
/// @return the atomic to `type`
|
||||
ast::Atomic* atomic(ast::Type* type) const {
|
||||
return builder->create<ast::Atomic>(type);
|
||||
}
|
||||
|
||||
/// @return the atomic to type `T`
|
||||
template <typename T>
|
||||
ast::Atomic* atomic() const {
|
||||
|
@ -1079,6 +1085,19 @@ class ProgramBuilder {
|
|||
type, ExprList(std::forward<ARGS>(args)...));
|
||||
}
|
||||
|
||||
/// @param source the source information
|
||||
/// @param type the type to construct
|
||||
/// @param args the arguments for the constructor
|
||||
/// @return an `ast::TypeConstructorExpression` of `type` constructed with the
|
||||
/// values `args`.
|
||||
template <typename... ARGS>
|
||||
ast::TypeConstructorExpression* Construct(const Source& source,
|
||||
ast::Type* type,
|
||||
ARGS&&... args) {
|
||||
return create<ast::TypeConstructorExpression>(
|
||||
source, type, ExprList(std::forward<ARGS>(args)...));
|
||||
}
|
||||
|
||||
/// @param args the arguments for the vector constructor
|
||||
/// @return an `ast::TypeConstructorExpression` of a 2-element vector of type
|
||||
/// `T`, constructed with the values `args`.
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright 2021 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/ast/struct_block_decoration.h"
|
||||
#include "src/resolver/resolver.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/atomic_type.h"
|
||||
#include "src/sem/reference_type.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
namespace tint {
|
||||
namespace resolver {
|
||||
namespace {
|
||||
|
||||
struct ResolverAtomicTest : public resolver::TestHelper,
|
||||
public testing::Test {};
|
||||
|
||||
TEST_F(ResolverAtomicTest, GlobalWorkgroupI32) {
|
||||
auto* g = Global("a", ty.atomic(Source{{12, 34}}, ty.i32()),
|
||||
ast::StorageClass::kWorkgroup);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
|
||||
auto* atomic = TypeOf(g)->UnwrapRef()->As<sem::Atomic>();
|
||||
ASSERT_NE(atomic, nullptr);
|
||||
EXPECT_TRUE(atomic->Type()->Is<sem::I32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverAtomicTest, GlobalWorkgroupU32) {
|
||||
auto* g = Global("a", ty.atomic(Source{{12, 34}}, ty.u32()),
|
||||
ast::StorageClass::kWorkgroup);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
|
||||
auto* atomic = TypeOf(g)->UnwrapRef()->As<sem::Atomic>();
|
||||
ASSERT_NE(atomic, nullptr);
|
||||
EXPECT_TRUE(atomic->Type()->Is<sem::U32>());
|
||||
}
|
||||
|
||||
TEST_F(ResolverAtomicTest, GlobalStorageStruct) {
|
||||
auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))},
|
||||
{create<ast::StructBlockDecoration>()});
|
||||
auto* g = Global("g", ty.Of(s), ast::StorageClass::kStorage,
|
||||
ast::Access::kReadWrite,
|
||||
ast::DecorationList{
|
||||
create<ast::BindingDecoration>(0),
|
||||
create<ast::GroupDecoration>(0),
|
||||
});
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
|
||||
auto* str = TypeOf(g)->UnwrapRef()->As<sem::Struct>();
|
||||
ASSERT_NE(str, nullptr);
|
||||
ASSERT_EQ(str->Members().size(), 1u);
|
||||
auto* atomic = str->Members()[0]->Type()->As<sem::Atomic>();
|
||||
ASSERT_NE(atomic, nullptr);
|
||||
ASSERT_TRUE(atomic->Type()->Is<sem::I32>());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace resolver
|
||||
} // namespace tint
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright 2021 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/resolver/resolver.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/atomic_type.h"
|
||||
#include "src/sem/reference_type.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
namespace tint {
|
||||
namespace resolver {
|
||||
namespace {
|
||||
|
||||
struct ResolverAtomicValidationTest : public resolver::TestHelper,
|
||||
public testing::Test {};
|
||||
|
||||
TEST_F(ResolverAtomicValidationTest, GlobalOfInvalidType) {
|
||||
Global("a", ty.atomic(ty.f32(Source{{12, 34}})),
|
||||
ast::StorageClass::kWorkgroup);
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: atomic only supports i32 or u32 types");
|
||||
}
|
||||
|
||||
TEST_F(ResolverAtomicValidationTest, GlobalOfInvalidStorageClass) {
|
||||
Global("a", ty.atomic(Source{{12, 34}}, ty.i32()),
|
||||
ast::StorageClass::kPrivate);
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), "12:34 error: atomic var requires workgroup storage");
|
||||
}
|
||||
|
||||
TEST_F(ResolverAtomicValidationTest, GlobalPrivateStruct) {
|
||||
auto* s =
|
||||
Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
|
||||
Global("g", ty.Of(s), ast::StorageClass::kPrivate);
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(),
|
||||
"12:34 error: atomic types can only be used in storage classes "
|
||||
"workgroup or storage, but was used by storage class private");
|
||||
}
|
||||
|
||||
// TODO(crbug.com/tint/901): Validate that storage buffer access mode is
|
||||
// read_write.
|
||||
|
||||
TEST_F(ResolverAtomicValidationTest, Local) {
|
||||
WrapInFunction(Var("a", ty.atomic(Source{{12, 34}}, ty.i32())));
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(),
|
||||
"12:34 error: cannot declare an atomic var in a function scope");
|
||||
}
|
||||
|
||||
TEST_F(ResolverAtomicValidationTest, NoAtomicExpr) {
|
||||
WrapInFunction(Construct(Source{{12, 34}}, ty.atomic<u32>()));
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(),
|
||||
"12:34 error: an expression must not evaluate to an atomic type");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace resolver
|
||||
} // namespace tint
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "gmock/gmock.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/atomic_type.h"
|
||||
|
||||
namespace tint {
|
||||
namespace resolver {
|
||||
|
@ -92,6 +93,11 @@ TEST_F(ResolverIsHostShareable, Pointer) {
|
|||
EXPECT_FALSE(r()->IsHostShareable(ptr));
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsHostShareable, Atomic) {
|
||||
EXPECT_TRUE(r()->IsHostShareable(create<sem::Atomic>(create<sem::I32>())));
|
||||
EXPECT_TRUE(r()->IsHostShareable(create<sem::Atomic>(create<sem::U32>())));
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsHostShareable, ArraySizedOfHostShareable) {
|
||||
auto* arr = create<sem::Array>(create<sem::I32>(), 5, 4, 20, 4, true);
|
||||
EXPECT_TRUE(r()->IsHostShareable(arr));
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "gmock/gmock.h"
|
||||
#include "src/resolver/resolver_test_helper.h"
|
||||
#include "src/sem/atomic_type.h"
|
||||
|
||||
namespace tint {
|
||||
namespace resolver {
|
||||
|
@ -67,6 +68,11 @@ TEST_F(ResolverIsStorableTest, Pointer) {
|
|||
EXPECT_FALSE(r()->IsStorable(ptr));
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsStorableTest, Atomic) {
|
||||
EXPECT_TRUE(r()->IsStorable(create<sem::Atomic>(create<sem::I32>())));
|
||||
EXPECT_TRUE(r()->IsStorable(create<sem::Atomic>(create<sem::U32>())));
|
||||
}
|
||||
|
||||
TEST_F(ResolverIsStorableTest, ArraySizedOfStorable) {
|
||||
auto* arr = create<sem::Array>(create<sem::I32>(), 5, 4, 20, 4, true);
|
||||
EXPECT_TRUE(r()->IsStorable(arr));
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "src/ast/vector.h"
|
||||
#include "src/ast/workgroup_decoration.h"
|
||||
#include "src/sem/array.h"
|
||||
#include "src/sem/atomic_type.h"
|
||||
#include "src/sem/call.h"
|
||||
#include "src/sem/depth_texture_type.h"
|
||||
#include "src/sem/function.h"
|
||||
|
@ -166,19 +167,14 @@ bool Resolver::Resolve() {
|
|||
|
||||
// https://gpuweb.github.io/gpuweb/wgsl/#plain-types-section
|
||||
bool Resolver::IsPlain(const sem::Type* type) {
|
||||
if (type->is_scalar() || type->Is<sem::Vector>() || type->Is<sem::Matrix>() ||
|
||||
type->Is<sem::Array>() || type->Is<sem::Struct>()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return type->is_scalar() || type->Is<sem::Atomic>() ||
|
||||
type->Is<sem::Vector>() || type->Is<sem::Matrix>() ||
|
||||
type->Is<sem::Array>() || type->Is<sem::Struct>();
|
||||
}
|
||||
|
||||
// https://gpuweb.github.io/gpuweb/wgsl.html#storable-types
|
||||
bool Resolver::IsStorable(const sem::Type* type) {
|
||||
if (IsPlain(type) || type->Is<sem::Texture>() || type->Is<sem::Sampler>()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return IsPlain(type) || type->Is<sem::Texture>() || type->Is<sem::Sampler>();
|
||||
}
|
||||
|
||||
// https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable-types
|
||||
|
@ -203,6 +199,9 @@ bool Resolver::IsHostShareable(const sem::Type* type) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
if (auto* atomic = type->As<sem::Atomic>()) {
|
||||
return IsHostShareable(atomic->Type());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -237,6 +236,9 @@ bool Resolver::ResolveInternal() {
|
|||
if (!ValidatePipelineStages()) {
|
||||
return false;
|
||||
}
|
||||
if (!ValidateAtomicUses()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
|
@ -290,6 +292,16 @@ sem::Type* Resolver::Type(const ast::Type* ty) {
|
|||
if (auto* t = ty->As<ast::Array>()) {
|
||||
return Array(t);
|
||||
}
|
||||
if (auto* t = ty->As<ast::Atomic>()) {
|
||||
if (auto* el = Type(t->type())) {
|
||||
auto* a = builder_->create<sem::Atomic>(const_cast<sem::Type*>(el));
|
||||
if (!ValidateAtomic(t, a)) {
|
||||
return nullptr;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
if (auto* t = ty->As<ast::Pointer>()) {
|
||||
if (auto* el = Type(t->type())) {
|
||||
auto access = t->access();
|
||||
|
@ -356,6 +368,45 @@ sem::Type* Resolver::Type(const ast::Type* ty) {
|
|||
return s;
|
||||
}
|
||||
|
||||
bool Resolver::ValidateAtomic(const ast::Atomic* a, const sem::Atomic* s) {
|
||||
// https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
|
||||
// T must be either u32 or i32.
|
||||
if (!s->Type()->IsAnyOf<sem::U32, sem::I32>()) {
|
||||
diagnostics_.add_error("atomic only supports i32 or u32 types",
|
||||
a->type()->source());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resolver::ValidateAtomicUses() {
|
||||
// https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
|
||||
// Atomic types may only be instantiated by variables in the workgroup storage
|
||||
// class or by storage buffer variables with a read_write access mode.
|
||||
for (auto sm : atomic_members_) {
|
||||
auto* structure = sm.structure;
|
||||
for (auto usage : structure->StorageClassUsage()) {
|
||||
if (usage == ast::StorageClass::kWorkgroup) {
|
||||
continue;
|
||||
}
|
||||
if (usage != ast::StorageClass::kStorage) {
|
||||
// TODO(crbug.com/tint/901): Validate that the access mode is
|
||||
// read_write.
|
||||
auto* member = structure->Members()[sm.index];
|
||||
diagnostics_.add_error(
|
||||
"atomic types can only be used in storage classes workgroup or "
|
||||
"storage, but was used by storage class " +
|
||||
std::string(ast::str(usage)),
|
||||
member->Declaration()->type()->source());
|
||||
// TODO(crbug.com/tint/901): Add note pointing at where the usage came
|
||||
// from.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resolver::ValidateStorageTexture(const ast::StorageTexture* t) {
|
||||
switch (t->access()) {
|
||||
case ast::Access::kUndefined:
|
||||
|
@ -816,6 +867,26 @@ bool Resolver::ValidateVariable(const VariableInfo* info) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
|
||||
// Atomic types may only be instantiated by variables in the workgroup storage
|
||||
// class or by storage buffer variables with a read_write access mode.
|
||||
if (info->type->UnwrapRef()->Is<sem::Atomic>()) {
|
||||
if (info->kind != VariableKind::kGlobal) {
|
||||
// Neither storage nor workgroup storage classes can be used in function
|
||||
// scopes.
|
||||
diagnostics_.add_error("cannot declare an atomic var in a function scope",
|
||||
info->declaration->type()->source());
|
||||
return false;
|
||||
}
|
||||
if (info->storage_class != ast::StorageClass::kWorkgroup) {
|
||||
// Storage buffers require a structure, so just check for workgroup
|
||||
// storage here.
|
||||
diagnostics_.add_error("atomic var requires workgroup storage",
|
||||
info->declaration->type()->source());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1620,34 +1691,40 @@ bool Resolver::Expression(ast::Expression* expr) {
|
|||
return true; // Already resolved
|
||||
}
|
||||
|
||||
if (auto* a = expr->As<ast::ArrayAccessorExpression>()) {
|
||||
return ArrayAccessor(a);
|
||||
}
|
||||
if (auto* b = expr->As<ast::BinaryExpression>()) {
|
||||
return Binary(b);
|
||||
}
|
||||
if (auto* b = expr->As<ast::BitcastExpression>()) {
|
||||
return Bitcast(b);
|
||||
}
|
||||
if (auto* c = expr->As<ast::CallExpression>()) {
|
||||
return Call(c);
|
||||
}
|
||||
if (auto* c = expr->As<ast::ConstructorExpression>()) {
|
||||
return Constructor(c);
|
||||
}
|
||||
if (auto* i = expr->As<ast::IdentifierExpression>()) {
|
||||
return Identifier(i);
|
||||
}
|
||||
if (auto* m = expr->As<ast::MemberAccessorExpression>()) {
|
||||
return MemberAccessor(m);
|
||||
}
|
||||
if (auto* u = expr->As<ast::UnaryOpExpression>()) {
|
||||
return UnaryOp(u);
|
||||
bool ok = false;
|
||||
if (auto* array = expr->As<ast::ArrayAccessorExpression>()) {
|
||||
ok = ArrayAccessor(array);
|
||||
} else if (auto* bin_op = expr->As<ast::BinaryExpression>()) {
|
||||
ok = Binary(bin_op);
|
||||
} else if (auto* bitcast = expr->As<ast::BitcastExpression>()) {
|
||||
ok = Bitcast(bitcast);
|
||||
} else if (auto* call = expr->As<ast::CallExpression>()) {
|
||||
ok = Call(call);
|
||||
} else if (auto* ctor = expr->As<ast::ConstructorExpression>()) {
|
||||
ok = Constructor(ctor);
|
||||
} else if (auto* ident = expr->As<ast::IdentifierExpression>()) {
|
||||
ok = Identifier(ident);
|
||||
} else if (auto* member = expr->As<ast::MemberAccessorExpression>()) {
|
||||
ok = MemberAccessor(member);
|
||||
} else if (auto* unary = expr->As<ast::UnaryOpExpression>()) {
|
||||
ok = UnaryOp(unary);
|
||||
} else {
|
||||
diagnostics_.add_error("unknown expression for type determination",
|
||||
expr->source());
|
||||
}
|
||||
|
||||
diagnostics_.add_error("unknown expression for type determination",
|
||||
expr->source());
|
||||
return false;
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* ty = TypeOf(expr);
|
||||
if (ty->Is<sem::Atomic>()) {
|
||||
diagnostics_.add_error("an expression must not evaluate to an atomic type",
|
||||
expr->source());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resolver::ArrayAccessor(ast::ArrayAccessorExpression* expr) {
|
||||
|
@ -2883,7 +2960,8 @@ bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
|
|||
align = 4;
|
||||
size = 4;
|
||||
return true;
|
||||
} else if (auto* vec = ty->As<sem::Vector>()) {
|
||||
}
|
||||
if (auto* vec = ty->As<sem::Vector>()) {
|
||||
if (vec->size() < 2 || vec->size() > 4) {
|
||||
TINT_UNREACHABLE(diagnostics_)
|
||||
<< "Invalid vector size: vec" << vec->size();
|
||||
|
@ -2892,7 +2970,8 @@ bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
|
|||
align = vector_align[vec->size()];
|
||||
size = vector_size[vec->size()];
|
||||
return true;
|
||||
} else if (auto* mat = ty->As<sem::Matrix>()) {
|
||||
}
|
||||
if (auto* mat = ty->As<sem::Matrix>()) {
|
||||
if (mat->columns() < 2 || mat->columns() > 4 || mat->rows() < 2 ||
|
||||
mat->rows() > 4) {
|
||||
TINT_UNREACHABLE(diagnostics_)
|
||||
|
@ -2902,15 +2981,20 @@ bool Resolver::DefaultAlignAndSize(const sem::Type* ty,
|
|||
align = vector_align[mat->rows()];
|
||||
size = vector_align[mat->rows()] * mat->columns();
|
||||
return true;
|
||||
} else if (auto* s = ty->As<sem::Struct>()) {
|
||||
}
|
||||
if (auto* s = ty->As<sem::Struct>()) {
|
||||
align = s->Align();
|
||||
size = s->Size();
|
||||
return true;
|
||||
} else if (auto* a = ty->As<sem::Array>()) {
|
||||
}
|
||||
if (auto* a = ty->As<sem::Array>()) {
|
||||
align = a->Align();
|
||||
size = a->SizeInBytes();
|
||||
return true;
|
||||
}
|
||||
if (auto* a = ty->As<sem::Atomic>()) {
|
||||
return DefaultAlignAndSize(a->Type(), align, size);
|
||||
}
|
||||
TINT_UNREACHABLE(diagnostics_) << "invalid type " << ty->TypeInfo().name;
|
||||
return false;
|
||||
}
|
||||
|
@ -3187,8 +3271,16 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
|
|||
auto size_no_padding = struct_size;
|
||||
struct_size = utils::RoundUp(struct_align, struct_size);
|
||||
|
||||
auto* out = builder_->create<sem::Struct>(
|
||||
str, std::move(sem_members), struct_align, struct_size, size_no_padding);
|
||||
auto* out = builder_->create<sem::Struct>(str, sem_members, struct_align,
|
||||
struct_size, size_no_padding);
|
||||
|
||||
// Keep track of atomic members for validation after all usages have been
|
||||
// determined.
|
||||
for (size_t i = 0; i < sem_members.size(); i++) {
|
||||
if (sem_members[i]->Type()->Is<sem::Atomic>()) {
|
||||
atomic_members_.emplace_back(StructMember{out, i});
|
||||
}
|
||||
}
|
||||
|
||||
if (!ValidateStructure(out)) {
|
||||
return nullptr;
|
||||
|
|
|
@ -52,6 +52,7 @@ class Variable;
|
|||
} // namespace ast
|
||||
namespace sem {
|
||||
class Array;
|
||||
class Atomic;
|
||||
class Intrinsic;
|
||||
class Statement;
|
||||
} // namespace sem
|
||||
|
@ -196,6 +197,13 @@ class Resolver {
|
|||
sem::Type* const sem;
|
||||
};
|
||||
|
||||
// Structure holding a pointer to the sem::Struct and an index to a member of
|
||||
// that structure.
|
||||
struct StructMember {
|
||||
sem::Struct* structure;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
/// Resolves the program, without creating final the semantic nodes.
|
||||
/// @returns true on success, false on error
|
||||
bool ResolveInternal();
|
||||
|
@ -255,6 +263,8 @@ class Resolver {
|
|||
uint32_t el_size,
|
||||
uint32_t el_align,
|
||||
const Source& source);
|
||||
bool ValidateAtomic(const ast::Atomic* a, const sem::Atomic* s);
|
||||
bool ValidateAtomicUses();
|
||||
bool ValidateAssignment(const ast::AssignmentStatement* a);
|
||||
bool ValidateCallStatement(ast::CallStatement* stmt);
|
||||
bool ValidateEntryPoint(const ast::Function* func, const FunctionInfo* info);
|
||||
|
@ -401,6 +411,7 @@ class Resolver {
|
|||
ScopeStack<VariableInfo*> variable_stack_;
|
||||
std::unordered_map<Symbol, FunctionInfo*> symbol_to_function_;
|
||||
std::vector<FunctionInfo*> entry_points_;
|
||||
std::vector<StructMember> atomic_members_;
|
||||
std::unordered_map<const ast::Function*, FunctionInfo*> function_to_info_;
|
||||
std::unordered_map<const ast::Variable*, VariableInfo*> variable_to_info_;
|
||||
std::unordered_map<const ast::CallExpression*, FunctionCallInfo>
|
||||
|
|
|
@ -222,6 +222,8 @@ tint_unittests_source_set("tint_unittests_core_src") {
|
|||
"../src/program_builder_test.cc",
|
||||
"../src/program_test.cc",
|
||||
"../src/resolver/assignment_validation_test.cc",
|
||||
"../src/resolver/atomics_test.cc",
|
||||
"../src/resolver/atomics_validation_test.cc",
|
||||
"../src/resolver/block_test.cc",
|
||||
"../src/resolver/builtins_validation_test.cc",
|
||||
"../src/resolver/call_test.cc",
|
||||
|
|
Loading…
Reference in New Issue