tint/resolver: Temporally ban f16 in buffer, pipeline IO and override
This patch make resolver reject using f16 types in uniform or storage buffer, pipeline IO or overridable variable, since these are not implemented yet. This can help prevent hitting invalid path in writers. Bug: tint:1473, tint:1502 Change-Id: I5ea753e4254276a6d141d7012a6d0987423a61cf Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/95827 Reviewed-by: Ben Clayton <bclayton@google.com> Auto-Submit: Zhaoming Jiang <zhaoming.jiang@intel.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Zhaoming Jiang <zhaoming.jiang@intel.com>
This commit is contained in:
parent
03d9835d14
commit
9c71174f38
|
@ -334,12 +334,26 @@ static constexpr Params cases[] = {
|
||||||
ParamsFor<alias<i32>>(true), //
|
ParamsFor<alias<i32>>(true), //
|
||||||
ParamsFor<alias<u32>>(true), //
|
ParamsFor<alias<u32>>(true), //
|
||||||
ParamsFor<alias<bool>>(false), //
|
ParamsFor<alias<bool>>(false), //
|
||||||
|
// Currently entry point IO of f16 types are not implemented yet.
|
||||||
|
// TODO(tint:1473, tint:1502): Change f16 and vecN<f16> cases to valid after f16 is supported in
|
||||||
|
// entry point IO.
|
||||||
|
ParamsFor<f16>(false), //
|
||||||
|
ParamsFor<vec2<f16>>(false), //
|
||||||
|
ParamsFor<vec3<f16>>(false), //
|
||||||
|
ParamsFor<vec4<f16>>(false), //
|
||||||
|
ParamsFor<mat2x2<f16>>(false), //
|
||||||
|
ParamsFor<mat3x3<f16>>(false), //
|
||||||
|
ParamsFor<mat4x4<f16>>(false), //
|
||||||
|
ParamsFor<alias<f16>>(false), //
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_P(TypeValidationTest, BareInputs) {
|
TEST_P(TypeValidationTest, BareInputs) {
|
||||||
// @fragment
|
// @fragment
|
||||||
// fn main(@location(0) @interpolate(flat) a : *) {}
|
// fn main(@location(0) @interpolate(flat) a : *) {}
|
||||||
auto params = GetParam();
|
auto params = GetParam();
|
||||||
|
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
auto* a = Param("a", params.create_ast_type(*this), {Location(0), Flat()});
|
auto* a = Param("a", params.create_ast_type(*this), {Location(0), Flat()});
|
||||||
Func(Source{{12, 34}}, "main", {a}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
|
Func(Source{{12, 34}}, "main", {a}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
|
||||||
|
|
||||||
|
@ -357,6 +371,9 @@ TEST_P(TypeValidationTest, StructInputs) {
|
||||||
// @fragment
|
// @fragment
|
||||||
// fn main(a : Input) {}
|
// fn main(a : Input) {}
|
||||||
auto params = GetParam();
|
auto params = GetParam();
|
||||||
|
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
auto* input =
|
auto* input =
|
||||||
Structure("Input", {Member("a", params.create_ast_type(*this), {Location(0), Flat()})});
|
Structure("Input", {Member("a", params.create_ast_type(*this), {Location(0), Flat()})});
|
||||||
auto* a = Param("a", ty.Of(input), {});
|
auto* a = Param("a", ty.Of(input), {});
|
||||||
|
@ -375,6 +392,9 @@ TEST_P(TypeValidationTest, BareOutputs) {
|
||||||
// return *();
|
// return *();
|
||||||
// }
|
// }
|
||||||
auto params = GetParam();
|
auto params = GetParam();
|
||||||
|
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
Func(Source{{12, 34}}, "main", {}, params.create_ast_type(*this),
|
Func(Source{{12, 34}}, "main", {}, params.create_ast_type(*this),
|
||||||
{Return(Construct(params.create_ast_type(*this)))}, {Stage(ast::PipelineStage::kFragment)},
|
{Return(Construct(params.create_ast_type(*this)))}, {Stage(ast::PipelineStage::kFragment)},
|
||||||
{Location(0)});
|
{Location(0)});
|
||||||
|
@ -395,6 +415,9 @@ TEST_P(TypeValidationTest, StructOutputs) {
|
||||||
// return Output();
|
// return Output();
|
||||||
// }
|
// }
|
||||||
auto params = GetParam();
|
auto params = GetParam();
|
||||||
|
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
auto* output = Structure("Output", {Member("a", params.create_ast_type(*this), {Location(0)})});
|
auto* output = Structure("Output", {Member("a", params.create_ast_type(*this), {Location(0)})});
|
||||||
Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
|
Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
|
||||||
{Stage(ast::PipelineStage::kFragment)});
|
{Stage(ast::PipelineStage::kFragment)});
|
||||||
|
|
|
@ -107,7 +107,7 @@ TEST_F(ResolverHostShareableValidationTest, NoError) {
|
||||||
Enable(ast::Extension::kF16);
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
auto* i1 = Structure("I1", {
|
auto* i1 = Structure("I1", {
|
||||||
Member(Source{{1, 1}}, "w1", ty.f16()),
|
Member(Source{{1, 1}}, "w1", ty.f32()),
|
||||||
Member(Source{{2, 1}}, "x1", ty.f32()),
|
Member(Source{{2, 1}}, "x1", ty.f32()),
|
||||||
Member(Source{{3, 1}}, "y1", ty.vec3<f32>()),
|
Member(Source{{3, 1}}, "y1", ty.vec3<f32>()),
|
||||||
Member(Source{{4, 1}}, "z1", ty.array<i32, 4>()),
|
Member(Source{{4, 1}}, "z1", ty.array<i32, 4>()),
|
||||||
|
@ -115,7 +115,7 @@ TEST_F(ResolverHostShareableValidationTest, NoError) {
|
||||||
auto* a1 = Alias("a1", ty.Of(i1));
|
auto* a1 = Alias("a1", ty.Of(i1));
|
||||||
auto* i2 = Structure("I2", {
|
auto* i2 = Structure("I2", {
|
||||||
Member(Source{{5, 1}}, "x2", ty.mat2x2<f32>()),
|
Member(Source{{5, 1}}, "x2", ty.mat2x2<f32>()),
|
||||||
Member(Source{{6, 1}}, "w2", ty.mat3x4<f16>()),
|
Member(Source{{6, 1}}, "w2", ty.mat3x4<f32>()),
|
||||||
Member(Source{{7, 1}}, "z2", ty.Of(i1)),
|
Member(Source{{7, 1}}, "z2", ty.Of(i1)),
|
||||||
});
|
});
|
||||||
auto* a2 = Alias("a2", ty.Of(i2));
|
auto* a2 = Alias("a2", ty.Of(i2));
|
||||||
|
|
|
@ -103,5 +103,15 @@ TEST_F(ResolverPipelineOverridableConstantTest, IdTooLarge) {
|
||||||
EXPECT_EQ(r()->error(), "12:34 error: pipeline constant IDs must be between 0 and 65535");
|
EXPECT_EQ(r()->error(), "12:34 error: pipeline constant IDs must be between 0 and 65535");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverPipelineOverridableConstantTest, F16_TemporallyBan) {
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
Override(Source{{12, 34}}, "a", ty.f16(), Expr(1_h), {Id(1u)});
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_EQ(r()->error(), "12:34 error: 'override' of type f16 is not implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace tint::resolver
|
} // namespace tint::resolver
|
||||||
|
|
|
@ -23,6 +23,8 @@ using namespace tint::number_suffixes; // NOLINT
|
||||||
namespace tint::resolver {
|
namespace tint::resolver {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
using ::testing::HasSubstr;
|
||||||
|
|
||||||
using ResolverStorageClassValidationTest = ResolverTest;
|
using ResolverStorageClassValidationTest = ResolverTest;
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, GlobalVariableNoStorageClass_Fail) {
|
TEST_F(ResolverStorageClassValidationTest, GlobalVariableNoStorageClass_Fail) {
|
||||||
|
@ -99,6 +101,139 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferBool) {
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferBoolAlias) {
|
||||||
|
// type a = bool;
|
||||||
|
// var<storage, read> g : a;
|
||||||
|
auto* a = Alias("a", ty.bool_());
|
||||||
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kStorage,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
r()->error(),
|
||||||
|
R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
|
||||||
|
56:78 note: while instantiating 'var' g)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// F16 types in storage and uniform buffer is not implemented yet.
|
||||||
|
// TODO(tint:1473, tint:1502): make these testcases valid after f16 is supported.
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferF16_TemporallyBan) {
|
||||||
|
// var<storage> g : f16;
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
GlobalVar("g", ty.f16(Source{{56, 78}}), ast::StorageClass::kStorage,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
"56:78 error: using f16 types in 'uniform' or 'storage' storage class is not "
|
||||||
|
"implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferF16Alias_TemporallyBan) {
|
||||||
|
// type a = f16;
|
||||||
|
// var<storage, read> g : a;
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
auto* a = Alias("a", ty.f16());
|
||||||
|
GlobalVar("g", ty.type_name(Source{{56, 78}}, a->name), ast::StorageClass::kStorage,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
"56:78 error: using f16 types in 'uniform' or 'storage' storage class is not "
|
||||||
|
"implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferVectorF16_TemporallyBan) {
|
||||||
|
// var<storage> g : vec4<f16>;
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
GlobalVar("g", ty.vec(Source{{56, 78}}, ty.Of<f16>(), 4u), ast::StorageClass::kStorage,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
"56:78 error: using f16 types in 'uniform' or 'storage' storage class is not "
|
||||||
|
"implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferArrayF16_TemporallyBan) {
|
||||||
|
// struct S { a : f16 };
|
||||||
|
// var<storage, read> g : array<S, 3u>;
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
auto* s = Structure("S", {Member("a", ty.f16(Source{{56, 78}}))});
|
||||||
|
auto* a = ty.array(ty.Of(s), 3_u);
|
||||||
|
GlobalVar("g", a, ast::StorageClass::kStorage, ast::Access::kRead,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_THAT(r()->error(),
|
||||||
|
HasSubstr("56:78 error: using f16 types in 'uniform' or 'storage' storage "
|
||||||
|
"class is not implemented yet"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferStructF16_TemporallyBan) {
|
||||||
|
// struct S { x : f16 };
|
||||||
|
// var<storage, read> g : S;
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
auto* s = Structure("S", {Member("x", ty.f16(Source{{12, 34}}))});
|
||||||
|
GlobalVar("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_THAT(r()->error(),
|
||||||
|
HasSubstr("12:34 error: using f16 types in 'uniform' or 'storage' storage "
|
||||||
|
"class is not implemented yet"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoErrorStructF16Aliases_TemporallyBan) {
|
||||||
|
// struct S { x : f16 };
|
||||||
|
// type a1 = S;
|
||||||
|
// var<storage, read> g : a1;
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
auto* s = Structure("S", {Member("x", ty.f16(Source{{12, 34}}))});
|
||||||
|
auto* a1 = Alias("a1", ty.Of(s));
|
||||||
|
auto* a2 = Alias("a2", ty.Of(a1));
|
||||||
|
GlobalVar("g", ty.Of(a2), ast::StorageClass::kStorage, ast::Access::kRead,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_THAT(r()->error(),
|
||||||
|
HasSubstr("12:34 error: using f16 types in 'uniform' or 'storage' storage "
|
||||||
|
"class is not implemented yet"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
|
||||||
// var<storage> g : ptr<private, f32>;
|
// var<storage> g : ptr<private, f32>;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
|
GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
|
||||||
|
@ -127,7 +262,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferIntScalar) {
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferVector) {
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferVectorF32) {
|
||||||
// var<storage> g : vec4<f32>;
|
// var<storage> g : vec4<f32>;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kStorage,
|
GlobalVar(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kStorage,
|
||||||
ast::AttributeList{
|
ast::AttributeList{
|
||||||
|
@ -138,7 +273,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferVector) {
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) {
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferArrayF32) {
|
||||||
// var<storage, read> g : array<S, 3u>;
|
// var<storage, read> g : array<S, 3u>;
|
||||||
auto* s = Structure("S", {Member("a", ty.f32())});
|
auto* s = Structure("S", {Member("a", ty.f32())});
|
||||||
auto* a = ty.array(ty.Of(s), 3_u);
|
auto* a = ty.array(ty.Of(s), 3_u);
|
||||||
|
@ -151,24 +286,6 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) {
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferBoolAlias) {
|
|
||||||
// type a = bool;
|
|
||||||
// var<storage, read> g : a;
|
|
||||||
auto* a = Alias("a", ty.bool_());
|
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kStorage,
|
|
||||||
ast::AttributeList{
|
|
||||||
create<ast::BindingAttribute>(0u),
|
|
||||||
create<ast::GroupAttribute>(0u),
|
|
||||||
});
|
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
|
||||||
|
|
||||||
EXPECT_EQ(
|
|
||||||
r()->error(),
|
|
||||||
R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
|
|
||||||
56:78 note: while instantiating 'var' g)");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, NotStorage_AccessMode) {
|
TEST_F(ResolverStorageClassValidationTest, NotStorage_AccessMode) {
|
||||||
// var<private, read> g : a;
|
// var<private, read> g : a;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kPrivate, ast::Access::kRead);
|
GlobalVar(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kPrivate, ast::Access::kRead);
|
||||||
|
@ -207,7 +324,7 @@ TEST_F(ResolverStorageClassValidationTest, Storage_WriteAccessMode) {
|
||||||
R"(56:78 error: access mode 'write' is not valid for the 'storage' address space)");
|
R"(56:78 error: access mode 'write' is not valid for the 'storage' address space)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Basic) {
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferStructI32) {
|
||||||
// struct S { x : i32 };
|
// struct S { x : i32 };
|
||||||
// var<storage, read> g : S;
|
// var<storage, read> g : S;
|
||||||
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
|
auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
|
||||||
|
@ -220,7 +337,7 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Basic) {
|
||||||
ASSERT_TRUE(r()->Resolve());
|
ASSERT_TRUE(r()->Resolve());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) {
|
TEST_F(ResolverStorageClassValidationTest, StorageBufferNoErrorStructI32Aliases) {
|
||||||
// struct S { x : i32 };
|
// struct S { x : i32 };
|
||||||
// type a1 = S;
|
// type a1 = S;
|
||||||
// var<storage, read> g : a1;
|
// var<storage, read> g : a1;
|
||||||
|
@ -271,6 +388,140 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferBool) {
|
||||||
56:78 note: while instantiating 'var' g)");
|
56:78 note: while instantiating 'var' g)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
|
||||||
|
// type a = bool;
|
||||||
|
// var<uniform> g : a;
|
||||||
|
auto* a = Alias("a", ty.bool_());
|
||||||
|
GlobalVar(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kUniform,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
r()->error(),
|
||||||
|
R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
|
||||||
|
56:78 note: while instantiating 'var' g)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// F16 types in storage and uniform buffer is not implemented yet.
|
||||||
|
// TODO(tint:1473, tint:1502): make these testcases valid after f16 is supported.
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferF16_TemporallyBan) {
|
||||||
|
// var<uniform> g : f16;
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
GlobalVar("g", ty.f16(Source{{56, 78}}), ast::StorageClass::kUniform,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
"56:78 error: using f16 types in 'uniform' or 'storage' storage class is not "
|
||||||
|
"implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferF16Alias_TemporallyBan) {
|
||||||
|
// type a = f16;
|
||||||
|
// var<uniform> g : a;
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
auto* a = Alias("a", ty.f16());
|
||||||
|
GlobalVar("g", ty.type_name(Source{{56, 78}}, a->name), ast::StorageClass::kUniform,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_EQ(r()->error(),
|
||||||
|
"56:78 error: using f16 types in 'uniform' or 'storage' storage class is not "
|
||||||
|
"implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferVectorF16_TemporallyBan) {
|
||||||
|
// var<uniform> g : vec4<f16>;
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
GlobalVar("g", ty.vec(Source{{56, 78}}, ty.Of<f16>(), 4u), ast::StorageClass::kUniform,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_THAT(r()->error(),
|
||||||
|
HasSubstr("56:78 error: using f16 types in 'uniform' or 'storage' storage "
|
||||||
|
"class is not implemented yet"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferArrayF16_TemporallyBan) {
|
||||||
|
// struct S {
|
||||||
|
// @size(16) f : f16;
|
||||||
|
// }
|
||||||
|
// var<uniform> g : array<S, 3u>;
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
auto* s = Structure("S", {Member("a", ty.f16(Source{{56, 78}}), {MemberSize(16)})});
|
||||||
|
auto* a = ty.array(ty.Of(s), 3_u);
|
||||||
|
GlobalVar("g", a, ast::StorageClass::kUniform,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_THAT(r()->error(),
|
||||||
|
HasSubstr("56:78 error: using f16 types in 'uniform' or 'storage' storage "
|
||||||
|
"class is not implemented yet"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferStructF16_TemporallyBan) {
|
||||||
|
// struct S { x : f16 };
|
||||||
|
// var<uniform> g : S;
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
auto* s = Structure("S", {Member("x", ty.f16(Source{{12, 34}}))});
|
||||||
|
GlobalVar("g", ty.Of(s), ast::StorageClass::kUniform,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_THAT(r()->error(),
|
||||||
|
HasSubstr("12:34 error: using f16 types in 'uniform' or 'storage' storage "
|
||||||
|
"class is not implemented yet"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferStructF16Aliases_TemporallyBan) {
|
||||||
|
// struct S { x : f16 };
|
||||||
|
// type a1 = S;
|
||||||
|
// var<uniform> g : a1;
|
||||||
|
Enable(ast::Extension::kF16);
|
||||||
|
|
||||||
|
auto* s = Structure("S", {Member("x", ty.f16(Source{{12, 34}}))});
|
||||||
|
auto* a1 = Alias("a1", ty.Of(s));
|
||||||
|
GlobalVar("g", ty.Of(a1), ast::StorageClass::kUniform,
|
||||||
|
ast::AttributeList{
|
||||||
|
create<ast::BindingAttribute>(0u),
|
||||||
|
create<ast::GroupAttribute>(0u),
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_THAT(r()->error(),
|
||||||
|
HasSubstr("12:34 error: using f16 types in 'uniform' or 'storage' storage "
|
||||||
|
"class is not implemented yet"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
|
||||||
// var<uniform> g : ptr<private, f32>;
|
// var<uniform> g : ptr<private, f32>;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
|
GlobalVar(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
|
||||||
|
@ -299,7 +550,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferIntScalar) {
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferVector) {
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferVectorF32) {
|
||||||
// var<uniform> g : vec4<f32>;
|
// var<uniform> g : vec4<f32>;
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kUniform,
|
GlobalVar(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kUniform,
|
||||||
ast::AttributeList{
|
ast::AttributeList{
|
||||||
|
@ -310,7 +561,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferVector) {
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferArrayF32) {
|
||||||
// struct S {
|
// struct S {
|
||||||
// @size(16) f : f32;
|
// @size(16) f : f32;
|
||||||
// }
|
// }
|
||||||
|
@ -326,25 +577,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferStructI32) {
|
||||||
// type a = bool;
|
|
||||||
// var<uniform> g : a;
|
|
||||||
auto* a = Alias("a", ty.bool_());
|
|
||||||
GlobalVar(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kUniform,
|
|
||||||
ast::AttributeList{
|
|
||||||
create<ast::BindingAttribute>(0u),
|
|
||||||
create<ast::GroupAttribute>(0u),
|
|
||||||
});
|
|
||||||
|
|
||||||
ASSERT_FALSE(r()->Resolve());
|
|
||||||
|
|
||||||
EXPECT_EQ(
|
|
||||||
r()->error(),
|
|
||||||
R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
|
|
||||||
56:78 note: while instantiating 'var' g)");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Basic) {
|
|
||||||
// struct S { x : i32 };
|
// 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())});
|
||||||
|
@ -357,7 +590,7 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Basic) {
|
||||||
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
ASSERT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Aliases) {
|
TEST_F(ResolverStorageClassValidationTest, UniformBufferStructI32Aliases) {
|
||||||
// struct S { x : i32 };
|
// struct S { x : i32 };
|
||||||
// type a1 = S;
|
// type a1 = S;
|
||||||
// var<uniform> g : a1;
|
// var<uniform> g : a1;
|
||||||
|
|
|
@ -392,6 +392,15 @@ bool Validator::StorageClassLayout(const sem::Type* store_ty,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Temporally forbid using f16 types in "uniform" and "storage" storage class.
|
||||||
|
// TODO(tint:1473, tint:1502): Remove this error after f16 is supported in "uniform" and
|
||||||
|
// "storage" storage class.
|
||||||
|
if (Is<sem::F16>(sem::Type::DeepestElementOf(store_ty))) {
|
||||||
|
AddError("using f16 types in 'uniform' or 'storage' storage class is not implemented yet",
|
||||||
|
source);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (auto* str = store_ty->As<sem::Struct>()) {
|
if (auto* str = store_ty->As<sem::Struct>()) {
|
||||||
for (size_t i = 0; i < str->Members().size(); ++i) {
|
for (size_t i = 0; i < str->Members().size(); ++i) {
|
||||||
auto* const m = str->Members()[i];
|
auto* const m = str->Members()[i];
|
||||||
|
@ -801,6 +810,12 @@ bool Validator::Override(const sem::Variable* v) const {
|
||||||
decl->source);
|
decl->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (storage_ty->Is<sem::F16>()) {
|
||||||
|
AddError("'override' of type f16 is not implemented yet", decl->source);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1102,6 +1117,13 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage)
|
||||||
const sem::Type* ty, Source source,
|
const sem::Type* ty, Source source,
|
||||||
ParamOrRetType param_or_ret,
|
ParamOrRetType param_or_ret,
|
||||||
bool is_struct_member) {
|
bool is_struct_member) {
|
||||||
|
// Temporally forbid using f16 types in entry point IO.
|
||||||
|
// TODO(tint:1473, tint:1502): Remove this error after f16 is supported in entry point IO.
|
||||||
|
if (Is<sem::F16>(sem::Type::DeepestElementOf(ty))) {
|
||||||
|
AddError("entry point IO of f16 types is not implemented yet", source);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Scan attributes for pipeline IO attributes.
|
// Scan attributes for pipeline IO attributes.
|
||||||
// Check for overlap with attributes that have been seen previously.
|
// Check for overlap with attributes that have been seen previously.
|
||||||
const ast::Attribute* pipeline_io_attribute = nullptr;
|
const ast::Attribute* pipeline_io_attribute = nullptr;
|
||||||
|
|
Loading…
Reference in New Issue