mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-16 12:21:35 +00:00
Move logic and relevant tests. Remove validator/validator_decoration_test.cc. Bug: tint:642 Change-Id: Ie89118a11233931605f18e762274bb2afcaaa460 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/46941 Commit-Queue: Antonio Maiorano <amaiorano@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: James Price <jrprice@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
311 lines
12 KiB
C++
311 lines
12 KiB
C++
// 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/access_decoration.h"
|
|
#include "src/ast/constant_id_decoration.h"
|
|
#include "src/ast/return_statement.h"
|
|
#include "src/ast/stage_decoration.h"
|
|
#include "src/ast/struct_block_decoration.h"
|
|
#include "src/ast/workgroup_decoration.h"
|
|
#include "src/resolver/resolver.h"
|
|
#include "src/resolver/resolver_test_helper.h"
|
|
|
|
#include "gmock/gmock.h"
|
|
|
|
namespace tint {
|
|
namespace {
|
|
|
|
enum class DecorationKind {
|
|
kAccess,
|
|
kAlign,
|
|
kBinding,
|
|
kBuiltin,
|
|
kConstantId,
|
|
kGroup,
|
|
kLocation,
|
|
kOffset,
|
|
kSize,
|
|
kStage,
|
|
kStride,
|
|
kStructBlock,
|
|
kWorkgroup,
|
|
};
|
|
struct TestParams {
|
|
DecorationKind kind;
|
|
bool should_pass;
|
|
};
|
|
class TestWithParams : public resolver::TestHelper,
|
|
public testing::TestWithParam<TestParams> {};
|
|
|
|
ast::Decoration* createDecoration(const Source& source,
|
|
ProgramBuilder& builder,
|
|
DecorationKind kind) {
|
|
switch (kind) {
|
|
case DecorationKind::kAccess:
|
|
return builder.create<ast::AccessDecoration>(
|
|
source, ast::AccessControl::kReadOnly);
|
|
case DecorationKind::kAlign:
|
|
return builder.create<ast::StructMemberAlignDecoration>(source, 4u);
|
|
case DecorationKind::kBinding:
|
|
return builder.create<ast::BindingDecoration>(source, 1);
|
|
case DecorationKind::kBuiltin:
|
|
return builder.create<ast::BuiltinDecoration>(source,
|
|
ast::Builtin::kPosition);
|
|
case DecorationKind::kConstantId:
|
|
return builder.create<ast::ConstantIdDecoration>(source, 0u);
|
|
case DecorationKind::kGroup:
|
|
return builder.create<ast::GroupDecoration>(source, 1u);
|
|
case DecorationKind::kLocation:
|
|
return builder.create<ast::LocationDecoration>(source, 1);
|
|
case DecorationKind::kOffset:
|
|
return builder.create<ast::StructMemberOffsetDecoration>(source, 4u);
|
|
case DecorationKind::kSize:
|
|
return builder.create<ast::StructMemberSizeDecoration>(source, 4u);
|
|
case DecorationKind::kStage:
|
|
return builder.create<ast::StageDecoration>(source,
|
|
ast::PipelineStage::kCompute);
|
|
case DecorationKind::kStride:
|
|
return builder.create<ast::StrideDecoration>(source, 4u);
|
|
case DecorationKind::kStructBlock:
|
|
return builder.create<ast::StructBlockDecoration>(source);
|
|
case DecorationKind::kWorkgroup:
|
|
return builder.create<ast::WorkgroupDecoration>(source, 1u, 1u, 1u);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
using FunctionReturnTypeDecorationTest = TestWithParams;
|
|
TEST_P(FunctionReturnTypeDecorationTest, IsValid) {
|
|
auto params = GetParam();
|
|
|
|
Func("main", ast::VariableList{}, ty.f32(),
|
|
ast::StatementList{create<ast::ReturnStatement>(Expr(1.f))},
|
|
ast::DecorationList{
|
|
create<ast::StageDecoration>(ast::PipelineStage::kVertex)},
|
|
ast::DecorationList{createDecoration({}, *this, params.kind)});
|
|
|
|
if (params.should_pass) {
|
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
|
} else {
|
|
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
|
EXPECT_EQ(r()->error(),
|
|
"error: decoration is not valid for function return types");
|
|
}
|
|
}
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ResolverDecorationValidationTest,
|
|
FunctionReturnTypeDecorationTest,
|
|
testing::Values(TestParams{DecorationKind::kAccess, false},
|
|
TestParams{DecorationKind::kAlign, false},
|
|
TestParams{DecorationKind::kBinding, false},
|
|
TestParams{DecorationKind::kBuiltin, true},
|
|
TestParams{DecorationKind::kConstantId, false},
|
|
TestParams{DecorationKind::kGroup, false},
|
|
TestParams{DecorationKind::kLocation, true},
|
|
TestParams{DecorationKind::kOffset, false},
|
|
TestParams{DecorationKind::kSize, false},
|
|
TestParams{DecorationKind::kStage, false},
|
|
TestParams{DecorationKind::kStride, false},
|
|
TestParams{DecorationKind::kStructBlock, false},
|
|
TestParams{DecorationKind::kWorkgroup, false}));
|
|
|
|
using ArrayDecorationTest = TestWithParams;
|
|
|
|
TEST_P(ArrayDecorationTest, IsValid) {
|
|
auto params = GetParam();
|
|
|
|
ast::StructMemberList members{Member(
|
|
"a", create<type::Array>(ty.f32(), 0,
|
|
ast::DecorationList{createDecoration(
|
|
Source{{12, 34}}, *this, params.kind)}))};
|
|
auto* s = create<ast::Struct>(
|
|
members, ast::DecorationList{create<ast::StructBlockDecoration>()});
|
|
auto* s_ty = ty.struct_("mystruct", s);
|
|
AST().AddConstructedType(s_ty);
|
|
|
|
WrapInFunction();
|
|
|
|
if (params.should_pass) {
|
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
|
} else {
|
|
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
|
EXPECT_EQ(r()->error(),
|
|
"12:34 error: decoration is not valid for array types");
|
|
}
|
|
}
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ResolverDecorationValidationTest,
|
|
ArrayDecorationTest,
|
|
testing::Values(TestParams{DecorationKind::kAccess, false},
|
|
TestParams{DecorationKind::kAlign, false},
|
|
TestParams{DecorationKind::kBinding, false},
|
|
TestParams{DecorationKind::kBuiltin, false},
|
|
TestParams{DecorationKind::kConstantId, false},
|
|
TestParams{DecorationKind::kGroup, false},
|
|
TestParams{DecorationKind::kLocation, false},
|
|
TestParams{DecorationKind::kOffset, false},
|
|
TestParams{DecorationKind::kSize, false},
|
|
TestParams{DecorationKind::kStage, false},
|
|
TestParams{DecorationKind::kStride, true},
|
|
TestParams{DecorationKind::kStructBlock, false},
|
|
TestParams{DecorationKind::kWorkgroup, false}));
|
|
|
|
using StructDecorationTest = TestWithParams;
|
|
TEST_P(StructDecorationTest, IsValid) {
|
|
auto params = GetParam();
|
|
|
|
auto* s = create<ast::Struct>(ast::StructMemberList{},
|
|
ast::DecorationList{createDecoration(
|
|
Source{{12, 34}}, *this, params.kind)});
|
|
auto* s_ty = ty.struct_("mystruct", s);
|
|
AST().AddConstructedType(s_ty);
|
|
|
|
WrapInFunction();
|
|
|
|
if (params.should_pass) {
|
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
|
} else {
|
|
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
|
EXPECT_EQ(r()->error(),
|
|
"12:34 error: decoration is not valid for struct declarations");
|
|
}
|
|
}
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ResolverDecorationValidationTest,
|
|
StructDecorationTest,
|
|
testing::Values(TestParams{DecorationKind::kAccess, false},
|
|
TestParams{DecorationKind::kAlign, false},
|
|
TestParams{DecorationKind::kBinding, false},
|
|
TestParams{DecorationKind::kBuiltin, false},
|
|
TestParams{DecorationKind::kConstantId, false},
|
|
TestParams{DecorationKind::kGroup, false},
|
|
TestParams{DecorationKind::kLocation, false},
|
|
TestParams{DecorationKind::kOffset, false},
|
|
TestParams{DecorationKind::kSize, false},
|
|
TestParams{DecorationKind::kStage, false},
|
|
TestParams{DecorationKind::kStride, false},
|
|
TestParams{DecorationKind::kStructBlock, true},
|
|
TestParams{DecorationKind::kWorkgroup, false}));
|
|
|
|
using StructMemberDecorationTest = TestWithParams;
|
|
TEST_P(StructMemberDecorationTest, IsValid) {
|
|
auto params = GetParam();
|
|
|
|
ast::StructMemberList members{
|
|
Member("a", ty.i32(),
|
|
ast::DecorationList{
|
|
createDecoration(Source{{12, 34}}, *this, params.kind)})};
|
|
auto* s = create<ast::Struct>(members, ast::DecorationList{});
|
|
auto* s_ty = ty.struct_("mystruct", s);
|
|
AST().AddConstructedType(s_ty);
|
|
|
|
WrapInFunction();
|
|
|
|
if (params.should_pass) {
|
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
|
} else {
|
|
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
|
EXPECT_EQ(r()->error(),
|
|
"12:34 error: decoration is not valid for structure members");
|
|
}
|
|
}
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ResolverDecorationValidationTest,
|
|
StructMemberDecorationTest,
|
|
testing::Values(TestParams{DecorationKind::kAccess, false},
|
|
TestParams{DecorationKind::kAlign, true},
|
|
TestParams{DecorationKind::kBinding, false},
|
|
TestParams{DecorationKind::kBuiltin, true},
|
|
TestParams{DecorationKind::kConstantId, false},
|
|
TestParams{DecorationKind::kGroup, false},
|
|
TestParams{DecorationKind::kLocation, true},
|
|
TestParams{DecorationKind::kOffset, true},
|
|
TestParams{DecorationKind::kSize, true},
|
|
TestParams{DecorationKind::kStage, false},
|
|
TestParams{DecorationKind::kStride, false},
|
|
TestParams{DecorationKind::kStructBlock, false},
|
|
TestParams{DecorationKind::kWorkgroup, false}));
|
|
|
|
using VariableDecorationTest = TestWithParams;
|
|
TEST_P(VariableDecorationTest, IsValid) {
|
|
auto params = GetParam();
|
|
|
|
Global("a", ty.f32(), ast::StorageClass::kInput, nullptr,
|
|
ast::DecorationList{
|
|
createDecoration(Source{{12, 34}}, *this, params.kind)});
|
|
|
|
WrapInFunction();
|
|
|
|
if (params.should_pass) {
|
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
|
} else {
|
|
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
|
EXPECT_EQ(r()->error(),
|
|
"12:34 error: decoration is not valid for variables");
|
|
}
|
|
}
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidatorTest,
|
|
VariableDecorationTest,
|
|
testing::Values(TestParams{DecorationKind::kAccess, false},
|
|
TestParams{DecorationKind::kAlign, false},
|
|
TestParams{DecorationKind::kBinding, true},
|
|
TestParams{DecorationKind::kBuiltin, true},
|
|
TestParams{DecorationKind::kConstantId, true},
|
|
TestParams{DecorationKind::kGroup, true},
|
|
TestParams{DecorationKind::kLocation, true},
|
|
TestParams{DecorationKind::kOffset, false},
|
|
TestParams{DecorationKind::kSize, false},
|
|
TestParams{DecorationKind::kStage, false},
|
|
TestParams{DecorationKind::kStride, false},
|
|
TestParams{DecorationKind::kStructBlock, false},
|
|
TestParams{DecorationKind::kWorkgroup, false}));
|
|
|
|
using FunctionDecorationTest = TestWithParams;
|
|
TEST_P(FunctionDecorationTest, IsValid) {
|
|
auto params = GetParam();
|
|
|
|
Func("foo", ast::VariableList{}, ty.void_(), ast::StatementList{},
|
|
ast::DecorationList{
|
|
create<ast::StageDecoration>(ast::PipelineStage::kCompute),
|
|
createDecoration(Source{{12, 34}}, *this, params.kind)});
|
|
|
|
if (params.should_pass) {
|
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
|
} else {
|
|
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
|
EXPECT_EQ(r()->error(),
|
|
"12:34 error: decoration is not valid for functions");
|
|
}
|
|
}
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
ValidatorTest,
|
|
FunctionDecorationTest,
|
|
testing::Values(TestParams{DecorationKind::kAccess, false},
|
|
TestParams{DecorationKind::kAlign, false},
|
|
TestParams{DecorationKind::kBinding, false},
|
|
TestParams{DecorationKind::kBuiltin, false},
|
|
TestParams{DecorationKind::kConstantId, false},
|
|
TestParams{DecorationKind::kGroup, false},
|
|
TestParams{DecorationKind::kLocation, false},
|
|
TestParams{DecorationKind::kOffset, false},
|
|
TestParams{DecorationKind::kSize, false},
|
|
// Skip kStage as we always apply it in this test
|
|
TestParams{DecorationKind::kStride, false},
|
|
TestParams{DecorationKind::kStructBlock, false},
|
|
TestParams{DecorationKind::kWorkgroup, true}));
|
|
|
|
} // namespace
|
|
} // namespace tint
|