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:
parent
fd75bd0965
commit
f19e0e4360
|
@ -479,5 +479,47 @@ TEST_F(ResolverFunctionValidationTest, WorkgroupSize_NonConst) {
|
||||||
"i32 module-scope constant");
|
"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
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -176,19 +176,45 @@ bool Resolver::Resolve() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#plain-types-section
|
// 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>() ||
|
return type->is_scalar() || type->Is<sem::Atomic>() ||
|
||||||
type->Is<sem::Vector>() || type->Is<sem::Matrix>() ||
|
type->Is<sem::Vector>() || type->Is<sem::Matrix>() ||
|
||||||
type->Is<sem::Array>() || type->Is<sem::Struct>();
|
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
|
// 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>();
|
return IsPlain(type) || type->Is<sem::Texture>() || type->Is<sem::Sampler>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable-types
|
// 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>()) {
|
if (type->IsAnyOf<sem::I32, sem::U32, sem::F32>()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1013,6 +1039,13 @@ bool Resolver::ValidateFunction(const ast::Function* func,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!info->return_type->Is<sem::Void>()) {
|
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->body()) {
|
||||||
if (!func->get_last_statement() ||
|
if (!func->get_last_statement() ||
|
||||||
!func->get_last_statement()->Is<ast::ReturnStatement>()) {
|
!func->get_last_statement()->Is<ast::ReturnStatement>()) {
|
||||||
|
|
|
@ -77,15 +77,19 @@ class Resolver {
|
||||||
|
|
||||||
/// @param type the given type
|
/// @param type the given type
|
||||||
/// @returns true if the given type is a plain 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
|
/// @param type the given type
|
||||||
/// @returns true if the given type is storable
|
/// @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
|
/// @param type the given type
|
||||||
/// @returns true if the given type is host-shareable
|
/// @returns true if the given type is host-shareable
|
||||||
bool IsHostShareable(const sem::Type* type);
|
bool IsHostShareable(const sem::Type* type) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Describes the context in which a variable is declared
|
/// Describes the context in which a variable is declared
|
||||||
|
|
Loading…
Reference in New Issue