Validate that functions return atomic-free plain types

Bug: tint:876
Change-Id: If00aa2c64fc3039d6271d3c5e35c05635a6bf3d1
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/55480
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
Antonio Maiorano 2021-06-21 20:51:16 +00:00 committed by Tint LUCI CQ
parent fd75bd0965
commit f19e0e4360
3 changed files with 85 additions and 6 deletions

View File

@ -479,5 +479,47 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_NonConst) {
"i32 module-scope constant");
}
TEST_F(ResolverFunctionValidationTest, ReturnIsAtomicFreePlain_NonPlain) {
auto* ret_type =
ty.pointer(Source{{12, 34}}, ty.i32(), ast::StorageClass::kFunction);
Func("f", {}, ret_type, {});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
"12:34 error: function return type must be an atomic-free plain type");
}
TEST_F(ResolverFunctionValidationTest, ReturnIsAtomicFreePlain_AtomicInt) {
auto* ret_type = ty.atomic(Source{{12, 34}}, ty.i32());
Func("f", {}, ret_type, {});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
"12:34 error: function return type must be an atomic-free plain type");
}
TEST_F(ResolverFunctionValidationTest, ReturnIsAtomicFreePlain_ArrayOfAtomic) {
auto* ret_type = ty.array(Source{{12, 34}}, ty.atomic(ty.i32()));
Func("f", {}, ret_type, {});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
"12:34 error: function return type must be an atomic-free plain type");
}
TEST_F(ResolverFunctionValidationTest, ReturnIsAtomicFreePlain_StructOfAtomic) {
Structure("S", {Member("m", ty.atomic(ty.i32()))});
auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
Func("f", {}, ret_type, {});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
"12:34 error: function return type must be an atomic-free plain type");
}
} // namespace
} // namespace tint

View File

@ -176,19 +176,45 @@ bool Resolver::Resolve() {
}
// https://gpuweb.github.io/gpuweb/wgsl/#plain-types-section
bool Resolver::IsPlain(const sem::Type* type) {
bool Resolver::IsPlain(const sem::Type* type) const {
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/#atomic-free
bool Resolver::IsAtomicFreePlain(const sem::Type* type) const {
if (type->Is<sem::Atomic>()) {
return false;
}
if (type->is_scalar() || type->Is<sem::Vector>() || type->Is<sem::Matrix>()) {
return true;
}
if (auto* arr = type->As<sem::Array>()) {
return IsAtomicFreePlain(arr->ElemType());
}
if (auto* str = type->As<sem::Struct>()) {
for (auto* m : str->Members()) {
if (!IsAtomicFreePlain(m->Type())) {
return false;
}
}
return true;
}
return false;
}
// https://gpuweb.github.io/gpuweb/wgsl.html#storable-types
bool Resolver::IsStorable(const sem::Type* type) {
bool Resolver::IsStorable(const sem::Type* type) const {
return IsPlain(type) || type->Is<sem::Texture>() || type->Is<sem::Sampler>();
}
// https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable-types
bool Resolver::IsHostShareable(const sem::Type* type) {
bool Resolver::IsHostShareable(const sem::Type* type) const {
if (type->IsAnyOf<sem::I32, sem::U32, sem::F32>()) {
return true;
}
@ -1013,6 +1039,13 @@ bool Resolver::ValidateFunction(const ast::Function* func,
}
if (!info->return_type->Is<sem::Void>()) {
if (!IsAtomicFreePlain(info->return_type)) {
diagnostics_.add_error(
"function return type must be an atomic-free plain type",
func->return_type()->source());
return false;
}
if (func->body()) {
if (!func->get_last_statement() ||
!func->get_last_statement()->Is<ast::ReturnStatement>()) {

View File

@ -77,15 +77,19 @@ class Resolver {
/// @param type the given type
/// @returns true if the given type is a plain type
bool IsPlain(const sem::Type* type);
bool IsPlain(const sem::Type* type) const;
/// @param type the given type
/// @returns true if the given type is a atomic-free plain type
bool IsAtomicFreePlain(const sem::Type* type) const;
/// @param type the given type
/// @returns true if the given type is storable
bool IsStorable(const sem::Type* type);
bool IsStorable(const sem::Type* type) const;
/// @param type the given type
/// @returns true if the given type is host-shareable
bool IsHostShareable(const sem::Type* type);
bool IsHostShareable(const sem::Type* type) const;
private:
/// Describes the context in which a variable is declared