Validate that in/out storage classes are not used

Use a DisableValidationDecoration to allow these storage classes only
for variables generated by the SPIR-V sanitizer. This is also used in
the Inspector tests, since the Inspector is currently run *after* the
SPIR-V sanitizer. These tests will be removed when this is no longer
the case.

Also validate that builtin/location decorations are not used on
variables (unless they have input/output storage class).

Fix or delete all of the other tests that were wrongly using these
storage classes and attributes.

Bug: tint:697
Change-Id: I8be7fb16191f5e2bed9f7dfb700e51f3b97fd1fe
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/55862
Auto-Submit: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
James Price 2021-06-24 15:53:26 +00:00 committed by Tint LUCI CQ
parent ffd28e2e1a
commit 14c0b8acbf
25 changed files with 268 additions and 462 deletions

View File

@ -34,8 +34,8 @@ std::string DisableValidationDecoration::InternalName() const {
return "disable_validation__function_has_no_body"; return "disable_validation__function_has_no_body";
case DisabledValidation::kBindingPointCollision: case DisabledValidation::kBindingPointCollision:
return "disable_validation__binding_point_collision"; return "disable_validation__binding_point_collision";
case DisabledValidation::kFunctionVarStorageClass: case DisabledValidation::kIgnoreStorageClass:
return "disable_validation__function_var_storage_class"; return "disable_validation__ignore_storage_class";
case DisabledValidation::kEntryPointParameter: case DisabledValidation::kEntryPointParameter:
return "disable_validation__entry_point_parameter"; return "disable_validation__entry_point_parameter";
} }

View File

@ -31,9 +31,9 @@ enum class DisabledValidation {
/// When applied to a module-scoped variable, the validator will not complain /// When applied to a module-scoped variable, the validator will not complain
/// if two resource variables have the same binding points. /// if two resource variables have the same binding points.
kBindingPointCollision, kBindingPointCollision,
/// When applied to a function-scoped variable, the validator will not /// When applied to a variable, the validator will not complain about the
/// complain if the storage class is not `function`. /// declared storage class.
kFunctionVarStorageClass, kIgnoreStorageClass,
/// When applied to an entry-point function parameter, the validator will not /// When applied to an entry-point function parameter, the validator will not
/// check for entry IO decorations. /// check for entry IO decorations.
kEntryPointParameter, kEntryPointParameter,

View File

@ -14,6 +14,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/ast/call_statement.h" #include "src/ast/call_statement.h"
#include "src/ast/disable_validation_decoration.h"
#include "src/ast/override_decoration.h" #include "src/ast/override_decoration.h"
#include "src/ast/stage_decoration.h" #include "src/ast/stage_decoration.h"
#include "src/ast/struct_block_decoration.h" #include "src/ast/struct_block_decoration.h"
@ -88,9 +89,15 @@ class InspectorHelper : public ProgramBuilder {
std::tie(in, out) = inout; std::tie(in, out) = inout;
Global(in, ty.u32(), ast::StorageClass::kInput, nullptr, Global(in, ty.u32(), ast::StorageClass::kInput, nullptr,
ast::DecorationList{Location(location++)}); ast::DecorationList{
Location(location++),
ASTNodes().Create<ast::DisableValidationDecoration>(
ID(), ast::DisabledValidation::kIgnoreStorageClass)});
Global(out, ty.u32(), ast::StorageClass::kOutput, nullptr, Global(out, ty.u32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{Location(location++)}); ast::DecorationList{
Location(location++),
ASTNodes().Create<ast::DisableValidationDecoration>(
ID(), ast::DisabledValidation::kIgnoreStorageClass)});
} }
} }
@ -1437,9 +1444,15 @@ TEST_F(InspectorGetEntryPointTest,
// TODO(crbug.com/tint/697): Remove this. // TODO(crbug.com/tint/697): Remove this.
TEST_F(InspectorGetEntryPointTest, BuiltInsNotStageVariables_Legacy) { TEST_F(InspectorGetEntryPointTest, BuiltInsNotStageVariables_Legacy) {
Global("in_var", ty.u32(), ast::StorageClass::kInput, nullptr, Global("in_var", ty.u32(), ast::StorageClass::kInput, nullptr,
ast::DecorationList{Builtin(ast::Builtin::kPosition)}); ast::DecorationList{
Builtin(ast::Builtin::kPosition),
ASTNodes().Create<ast::DisableValidationDecoration>(
ID(), ast::DisabledValidation::kIgnoreStorageClass)});
Global("out_var", ty.u32(), ast::StorageClass::kOutput, nullptr, Global("out_var", ty.u32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{Location(0)}); ast::DecorationList{
Location(0),
ASTNodes().Create<ast::DisableValidationDecoration>(
ID(), ast::DisabledValidation::kIgnoreStorageClass)});
MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}}, {}); MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}}, {});

View File

@ -53,7 +53,7 @@ TEST_F(ProgramTest, IDsAreUnique) {
} }
TEST_F(ProgramTest, Assert_GlobalVariable) { TEST_F(ProgramTest, Assert_GlobalVariable) {
Global("var", ty.f32(), ast::StorageClass::kInput); Global("var", ty.f32(), ast::StorageClass::kPrivate);
Program program(std::move(*this)); Program program(std::move(*this));
EXPECT_TRUE(program.IsValid()); EXPECT_TRUE(program.IsValid());

View File

@ -336,7 +336,7 @@ TEST_P(VariableDecorationTest, IsValid) {
ast::StorageClass::kNone, nullptr, ast::StorageClass::kNone, nullptr,
createDecorations(Source{{12, 34}}, *this, params.kind)); createDecorations(Source{{12, 34}}, *this, params.kind));
} else { } else {
Global("a", ty.f32(), ast::StorageClass::kInput, nullptr, Global("a", ty.f32(), ast::StorageClass::kPrivate, nullptr,
createDecorations(Source{{12, 34}}, *this, params.kind)); createDecorations(Source{{12, 34}}, *this, params.kind));
} }
@ -357,9 +357,9 @@ INSTANTIATE_TEST_SUITE_P(
VariableDecorationTest, VariableDecorationTest,
testing::Values(TestParams{DecorationKind::kAlign, false}, testing::Values(TestParams{DecorationKind::kAlign, false},
TestParams{DecorationKind::kBinding, false}, TestParams{DecorationKind::kBinding, false},
TestParams{DecorationKind::kBuiltin, true}, TestParams{DecorationKind::kBuiltin, false},
TestParams{DecorationKind::kGroup, false}, TestParams{DecorationKind::kGroup, false},
TestParams{DecorationKind::kLocation, true}, TestParams{DecorationKind::kLocation, false},
TestParams{DecorationKind::kOverride, false}, TestParams{DecorationKind::kOverride, false},
TestParams{DecorationKind::kOffset, false}, TestParams{DecorationKind::kOffset, false},
TestParams{DecorationKind::kSize, false}, TestParams{DecorationKind::kSize, false},
@ -514,7 +514,7 @@ TEST_P(ArrayStrideTest, All) {
auto* arr = ty.array(Source{{12, 34}}, el_ty, 4, params.stride); auto* arr = ty.array(Source{{12, 34}}, el_ty, 4, params.stride);
Global("myarray", arr, ast::StorageClass::kInput); Global("myarray", arr, ast::StorageClass::kPrivate);
if (params.should_pass) { if (params.should_pass) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
@ -598,7 +598,7 @@ TEST_F(ArrayStrideTest, DuplicateDecoration) {
create<ast::StrideDecoration>(Source{{56, 78}}, 4), create<ast::StrideDecoration>(Source{{56, 78}}, 4),
}); });
Global("myarray", arr, ast::StorageClass::kInput); Global("myarray", arr, ast::StorageClass::kPrivate);
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), EXPECT_EQ(r()->error(),

View File

@ -52,7 +52,7 @@ using ResolverIntrinsicDerivativeTest = ResolverTestWithParam<std::string>;
TEST_P(ResolverIntrinsicDerivativeTest, Scalar) { TEST_P(ResolverIntrinsicDerivativeTest, Scalar) {
auto name = GetParam(); auto name = GetParam();
Global("ident", ty.f32(), ast::StorageClass::kInput); Global("ident", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Call(name, "ident"); auto* expr = Call(name, "ident");
Func("func", {}, ty.void_(), {Ignore(expr)}, Func("func", {}, ty.void_(), {Ignore(expr)},
@ -66,7 +66,7 @@ TEST_P(ResolverIntrinsicDerivativeTest, Scalar) {
TEST_P(ResolverIntrinsicDerivativeTest, Vector) { TEST_P(ResolverIntrinsicDerivativeTest, Vector) {
auto name = GetParam(); auto name = GetParam();
Global("ident", ty.vec4<f32>(), ast::StorageClass::kInput); Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call(name, "ident"); auto* expr = Call(name, "ident");
Func("func", {}, ty.void_(), {Ignore(expr)}, Func("func", {}, ty.void_(), {Ignore(expr)},
@ -111,7 +111,7 @@ using ResolverIntrinsic = ResolverTestWithParam<std::string>;
TEST_P(ResolverIntrinsic, Test) { TEST_P(ResolverIntrinsic, Test) {
auto name = GetParam(); auto name = GetParam();
Global("my_var", ty.vec3<bool>(), ast::StorageClass::kInput); Global("my_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
auto* expr = Call(name, "my_var"); auto* expr = Call(name, "my_var");
WrapInFunction(expr); WrapInFunction(expr);
@ -129,7 +129,7 @@ using ResolverIntrinsicTest_FloatMethod = ResolverTestWithParam<std::string>;
TEST_P(ResolverIntrinsicTest_FloatMethod, Vector) { TEST_P(ResolverIntrinsicTest_FloatMethod, Vector) {
auto name = GetParam(); auto name = GetParam();
Global("my_var", ty.vec3<f32>(), ast::StorageClass::kInput); Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call(name, "my_var"); auto* expr = Call(name, "my_var");
WrapInFunction(expr); WrapInFunction(expr);
@ -145,7 +145,7 @@ TEST_P(ResolverIntrinsicTest_FloatMethod, Vector) {
TEST_P(ResolverIntrinsicTest_FloatMethod, Scalar) { TEST_P(ResolverIntrinsicTest_FloatMethod, Scalar) {
auto name = GetParam(); auto name = GetParam();
Global("my_var", ty.f32(), ast::StorageClass::kInput); Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Call(name, "my_var"); auto* expr = Call(name, "my_var");
WrapInFunction(expr); WrapInFunction(expr);
@ -159,7 +159,7 @@ TEST_P(ResolverIntrinsicTest_FloatMethod, Scalar) {
TEST_P(ResolverIntrinsicTest_FloatMethod, MissingParam) { TEST_P(ResolverIntrinsicTest_FloatMethod, MissingParam) {
auto name = GetParam(); auto name = GetParam();
Global("my_var", ty.f32(), ast::StorageClass::kInput); Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Call(name); auto* expr = Call(name);
WrapInFunction(expr); WrapInFunction(expr);
@ -176,7 +176,7 @@ TEST_P(ResolverIntrinsicTest_FloatMethod, MissingParam) {
TEST_P(ResolverIntrinsicTest_FloatMethod, TooManyParams) { TEST_P(ResolverIntrinsicTest_FloatMethod, TooManyParams) {
auto name = GetParam(); auto name = GetParam();
Global("my_var", ty.f32(), ast::StorageClass::kInput); Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Call(name, "my_var", 1.23f); auto* expr = Call(name, "my_var", 1.23f);
WrapInFunction(expr); WrapInFunction(expr);
@ -378,7 +378,7 @@ INSTANTIATE_TEST_SUITE_P(
TextureTestParams{ast::TextureDimension::k3d})); TextureTestParams{ast::TextureDimension::k3d}));
TEST_F(ResolverIntrinsicTest, Dot_Vec2) { TEST_F(ResolverIntrinsicTest, Dot_Vec2) {
Global("my_var", ty.vec2<f32>(), ast::StorageClass::kInput); Global("my_var", ty.vec2<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call("dot", "my_var", "my_var"); auto* expr = Call("dot", "my_var", "my_var");
WrapInFunction(expr); WrapInFunction(expr);
@ -390,7 +390,7 @@ TEST_F(ResolverIntrinsicTest, Dot_Vec2) {
} }
TEST_F(ResolverIntrinsicTest, Dot_Vec3) { TEST_F(ResolverIntrinsicTest, Dot_Vec3) {
Global("my_var", ty.vec3<f32>(), ast::StorageClass::kInput); Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call("dot", "my_var", "my_var"); auto* expr = Call("dot", "my_var", "my_var");
WrapInFunction(expr); WrapInFunction(expr);
@ -402,7 +402,7 @@ TEST_F(ResolverIntrinsicTest, Dot_Vec3) {
} }
TEST_F(ResolverIntrinsicTest, Dot_Vec4) { TEST_F(ResolverIntrinsicTest, Dot_Vec4) {
Global("my_var", ty.vec4<f32>(), ast::StorageClass::kInput); Global("my_var", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call("dot", "my_var", "my_var"); auto* expr = Call("dot", "my_var", "my_var");
WrapInFunction(expr); WrapInFunction(expr);
@ -428,7 +428,7 @@ TEST_F(ResolverIntrinsicTest, Dot_Error_Scalar) {
} }
TEST_F(ResolverIntrinsicTest, Dot_Error_VectorInt) { TEST_F(ResolverIntrinsicTest, Dot_Error_VectorInt) {
Global("my_var", ty.vec4<i32>(), ast::StorageClass::kInput); Global("my_var", ty.vec4<i32>(), ast::StorageClass::kPrivate);
auto* expr = Call("dot", "my_var", "my_var"); auto* expr = Call("dot", "my_var", "my_var");
WrapInFunction(expr); WrapInFunction(expr);
@ -444,9 +444,9 @@ TEST_F(ResolverIntrinsicTest, Dot_Error_VectorInt) {
} }
TEST_F(ResolverIntrinsicTest, Select) { TEST_F(ResolverIntrinsicTest, Select) {
Global("my_var", ty.vec3<f32>(), ast::StorageClass::kInput); Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
Global("bool_var", ty.vec3<bool>(), ast::StorageClass::kInput); Global("bool_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
auto* expr = Call("select", "my_var", "my_var", "bool_var"); auto* expr = Call("select", "my_var", "my_var", "bool_var");
WrapInFunction(expr); WrapInFunction(expr);
@ -784,7 +784,7 @@ TEST_F(ResolverIntrinsicDataTest, ArrayLength_Vector) {
} }
TEST_F(ResolverIntrinsicDataTest, ArrayLength_Error_ArraySized) { TEST_F(ResolverIntrinsicDataTest, ArrayLength_Error_ArraySized) {
Global("arr", ty.array<int, 4>(), ast::StorageClass::kInput); Global("arr", ty.array<int, 4>(), ast::StorageClass::kPrivate);
auto* call = Call("arrayLength", AddressOf("arr")); auto* call = Call("arrayLength", AddressOf("arr"));
WrapInFunction(call); WrapInFunction(call);
@ -792,7 +792,7 @@ TEST_F(ResolverIntrinsicDataTest, ArrayLength_Error_ArraySized) {
EXPECT_EQ( EXPECT_EQ(
r()->error(), r()->error(),
R"(error: no matching call to arrayLength(ptr<in, array<i32, 4>, read_write>) R"(error: no matching call to arrayLength(ptr<private, array<i32, 4>, read_write>)
1 candidate function: 1 candidate function:
arrayLength(ptr<storage, array<T>, A>) -> u32 arrayLength(ptr<storage, array<T>, A>) -> u32

View File

@ -718,11 +718,14 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
return false; return false;
} }
} else { } else {
if (!(deco->Is<ast::BindingDecoration>() || bool is_shader_io_decoration =
deco->Is<ast::BuiltinDecoration>() || deco->IsAnyOf<ast::BuiltinDecoration, ast::LocationDecoration>();
deco->Is<ast::GroupDecoration>() || bool has_io_storage_class =
deco->Is<ast::LocationDecoration>() || info->storage_class == ast::StorageClass::kInput ||
deco->Is<ast::InternalDecoration>())) { info->storage_class == ast::StorageClass::kOutput;
if (!(deco->IsAnyOf<ast::BindingDecoration, ast::GroupDecoration,
ast::InternalDecoration>()) &&
(!is_shader_io_decoration || !has_io_storage_class)) {
AddError("decoration is not valid for variables", deco->source()); AddError("decoration is not valid for variables", deco->source());
return false; return false;
} }
@ -893,6 +896,14 @@ bool Resolver::ValidateVariable(const VariableInfo* info) {
return false; return false;
} }
if (!IsValidationDisabled(var->decorations(),
ast::DisabledValidation::kIgnoreStorageClass) &&
(var->declared_storage_class() == ast::StorageClass::kInput ||
var->declared_storage_class() == ast::StorageClass::kOutput)) {
AddError("invalid use of input/output storage class", var->source());
return false;
}
// https://gpuweb.github.io/gpuweb/wgsl/#atomic-types // https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
// Atomic types may only be instantiated by variables in the workgroup storage // Atomic types may only be instantiated by variables in the workgroup storage
// class or by storage buffer variables with a read_write access mode. // class or by storage buffer variables with a read_write access mode.
@ -2759,9 +2770,8 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
if (!var->is_const()) { if (!var->is_const()) {
if (info->storage_class != ast::StorageClass::kFunction && if (info->storage_class != ast::StorageClass::kFunction &&
!IsValidationDisabled( !IsValidationDisabled(var->decorations(),
var->decorations(), ast::DisabledValidation::kIgnoreStorageClass)) {
ast::DisabledValidation::kFunctionVarStorageClass)) {
if (info->storage_class != ast::StorageClass::kNone) { if (info->storage_class != ast::StorageClass::kNone) {
AddError("function variable has a non-function storage class", AddError("function variable has a non-function storage class",
stmt->source()); stmt->source());

View File

@ -320,7 +320,7 @@ TEST_F(ResolverTest, Stmt_VariableDecl_AliasRedeclared) {
TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScope) { TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScope) {
auto* init = Expr(2); auto* init = Expr(2);
Global("my_var", ty.i32(), ast::StorageClass::kInput, init); Global("my_var", ty.i32(), ast::StorageClass::kPrivate, init);
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
@ -405,7 +405,7 @@ TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) {
Func("func_i32", params, ty.void_(), {fn_i32_decl}, ast::DecorationList{}); Func("func_i32", params, ty.void_(), {fn_i32_decl}, ast::DecorationList{});
// Declare f32 "foo" at module scope // Declare f32 "foo" at module scope
auto* mod_f32 = Var("foo", ty.f32(), ast::StorageClass::kInput, Expr(2.f)); auto* mod_f32 = Var("foo", ty.f32(), ast::StorageClass::kPrivate, Expr(2.f));
auto* mod_init = mod_f32->constructor(); auto* mod_init = mod_f32->constructor();
AST().AddGlobalVariable(mod_f32); AST().AddGlobalVariable(mod_f32);
@ -477,7 +477,7 @@ TEST_F(ResolverTest, Expr_ArrayAccessor_Array_Constant) {
} }
TEST_F(ResolverTest, ArrayAccessor_Matrix_Dynamic_F32) { TEST_F(ResolverTest, ArrayAccessor_Matrix_Dynamic_F32) {
Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kInput); Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 1.0f)); auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 1.0f));
WrapInFunction(acc); WrapInFunction(acc);
@ -487,7 +487,7 @@ TEST_F(ResolverTest, ArrayAccessor_Matrix_Dynamic_F32) {
} }
TEST_F(ResolverTest, ArrayAccessor_Matrix_Dynamic_Ref) { TEST_F(ResolverTest, ArrayAccessor_Matrix_Dynamic_Ref) {
Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kInput); Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
auto* idx = Var("idx", ty.i32(), Construct(ty.i32())); auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
auto* acc = IndexAccessor("my_var", idx); auto* acc = IndexAccessor("my_var", idx);
WrapInFunction(Decl(idx), acc); WrapInFunction(Decl(idx), acc);
@ -496,7 +496,7 @@ TEST_F(ResolverTest, ArrayAccessor_Matrix_Dynamic_Ref) {
} }
TEST_F(ResolverTest, ArrayAccessor_Matrix_BothDimensions_Dynamic_Ref) { TEST_F(ResolverTest, ArrayAccessor_Matrix_BothDimensions_Dynamic_Ref) {
Global("my_var", ty.mat4x4<f32>(), ast::StorageClass::kOutput); Global("my_var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
auto* idx = Var("idx", ty.u32(), Expr(3u)); auto* idx = Var("idx", ty.u32(), Expr(3u));
auto* idy = Var("idy", ty.u32(), Expr(2u)); auto* idy = Var("idy", ty.u32(), Expr(2u));
auto* acc = IndexAccessor(IndexAccessor("my_var", idx), idy); auto* acc = IndexAccessor(IndexAccessor("my_var", idx), idy);
@ -540,7 +540,7 @@ TEST_F(ResolverTest, ArrayAccessor_Matrix_BothDimension_Dynamic) {
} }
TEST_F(ResolverTest, Expr_ArrayAccessor_Matrix) { TEST_F(ResolverTest, Expr_ArrayAccessor_Matrix) {
Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kInput); Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor("my_var", 2); auto* acc = IndexAccessor("my_var", 2);
WrapInFunction(acc); WrapInFunction(acc);
@ -556,7 +556,7 @@ TEST_F(ResolverTest, Expr_ArrayAccessor_Matrix) {
} }
TEST_F(ResolverTest, Expr_ArrayAccessor_Matrix_BothDimensions) { TEST_F(ResolverTest, Expr_ArrayAccessor_Matrix_BothDimensions) {
Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kInput); Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor(IndexAccessor("my_var", 2), 1); auto* acc = IndexAccessor(IndexAccessor("my_var", 2), 1);
WrapInFunction(acc); WrapInFunction(acc);
@ -571,7 +571,7 @@ TEST_F(ResolverTest, Expr_ArrayAccessor_Matrix_BothDimensions) {
} }
TEST_F(ResolverTest, Expr_ArrayAccessor_Vector_F32) { TEST_F(ResolverTest, Expr_ArrayAccessor_Vector_F32) {
Global("my_var", ty.vec3<f32>(), ast::StorageClass::kInput); Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 2.0f)); auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 2.0f));
WrapInFunction(acc); WrapInFunction(acc);
@ -581,7 +581,7 @@ TEST_F(ResolverTest, Expr_ArrayAccessor_Vector_F32) {
} }
TEST_F(ResolverTest, Expr_ArrayAccessor_Vector_Dynamic_Ref) { TEST_F(ResolverTest, Expr_ArrayAccessor_Vector_Dynamic_Ref) {
Global("my_var", ty.vec3<f32>(), ast::StorageClass::kInput); Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* idx = Var("idx", ty.i32(), Expr(2)); auto* idx = Var("idx", ty.i32(), Expr(2));
auto* acc = IndexAccessor("my_var", idx); auto* acc = IndexAccessor("my_var", idx);
WrapInFunction(Decl(idx), acc); WrapInFunction(Decl(idx), acc);
@ -599,7 +599,7 @@ TEST_F(ResolverTest, Expr_ArrayAccessor_Vector_Dynamic) {
} }
TEST_F(ResolverTest, Expr_ArrayAccessor_Vector) { TEST_F(ResolverTest, Expr_ArrayAccessor_Vector) {
Global("my_var", ty.vec3<f32>(), ast::StorageClass::kInput); Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* acc = IndexAccessor("my_var", 2); auto* acc = IndexAccessor("my_var", 2);
WrapInFunction(acc); WrapInFunction(acc);
@ -737,7 +737,7 @@ TEST_F(ResolverTest, Expr_Constructor_Type_Vec4) {
} }
TEST_F(ResolverTest, Expr_Identifier_GlobalVariable) { TEST_F(ResolverTest, Expr_Identifier_GlobalVariable) {
auto* my_var = Global("my_var", ty.f32(), ast::StorageClass::kInput); auto* my_var = Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
auto* ident = Expr("my_var"); auto* ident = Expr("my_var");
WrapInFunction(ident); WrapInFunction(ident);
@ -972,8 +972,6 @@ TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
auto* s = Structure("S", {Member("m", ty.u32())}, auto* s = Structure("S", {Member("m", ty.u32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto* in_var = Global("in_var", ty.f32(), ast::StorageClass::kInput);
auto* out_var = Global("out_var", ty.f32(), ast::StorageClass::kOutput);
auto* sb_var = Global("sb_var", ty.Of(s), ast::StorageClass::kStorage, auto* sb_var = Global("sb_var", ty.Of(s), ast::StorageClass::kStorage,
ast::Access::kReadWrite, ast::Access::kReadWrite,
ast::DecorationList{ ast::DecorationList{
@ -985,7 +983,6 @@ TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
auto* func = Func("my_func", ast::VariableList{}, ty.void_(), auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
{ {
Assign("out_var", "in_var"),
Assign("wg_var", "wg_var"), Assign("wg_var", "wg_var"),
Assign("sb_var", "sb_var"), Assign("sb_var", "sb_var"),
Assign("priv_var", "priv_var"), Assign("priv_var", "priv_var"),
@ -999,20 +996,16 @@ TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>()); EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
const auto& vars = func_sem->ReferencedModuleVariables(); const auto& vars = func_sem->ReferencedModuleVariables();
ASSERT_EQ(vars.size(), 5u); ASSERT_EQ(vars.size(), 3u);
EXPECT_EQ(vars[0]->Declaration(), out_var); EXPECT_EQ(vars[0]->Declaration(), wg_var);
EXPECT_EQ(vars[1]->Declaration(), in_var); EXPECT_EQ(vars[1]->Declaration(), sb_var);
EXPECT_EQ(vars[2]->Declaration(), wg_var); EXPECT_EQ(vars[2]->Declaration(), priv_var);
EXPECT_EQ(vars[3]->Declaration(), sb_var);
EXPECT_EQ(vars[4]->Declaration(), priv_var);
} }
TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) { TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
auto* s = Structure("S", {Member("m", ty.u32())}, auto* s = Structure("S", {Member("m", ty.u32())},
{create<ast::StructBlockDecoration>()}); {create<ast::StructBlockDecoration>()});
auto* in_var = Global("in_var", ty.f32(), ast::StorageClass::kInput);
auto* out_var = Global("out_var", ty.f32(), ast::StorageClass::kOutput);
auto* sb_var = Global("sb_var", ty.Of(s), ast::StorageClass::kStorage, auto* sb_var = Global("sb_var", ty.Of(s), ast::StorageClass::kStorage,
ast::Access::kReadWrite, ast::Access::kReadWrite,
ast::DecorationList{ ast::DecorationList{
@ -1023,14 +1016,13 @@ TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
auto* priv_var = Global("priv_var", ty.f32(), ast::StorageClass::kPrivate); auto* priv_var = Global("priv_var", ty.f32(), ast::StorageClass::kPrivate);
Func("my_func", ast::VariableList{}, ty.f32(), Func("my_func", ast::VariableList{}, ty.f32(),
{Assign("out_var", "in_var"), Assign("wg_var", "wg_var"), {Assign("wg_var", "wg_var"), Assign("sb_var", "sb_var"),
Assign("sb_var", "sb_var"), Assign("priv_var", "priv_var"), Assign("priv_var", "priv_var"), Return(0.0f)},
Return(0.0f)},
ast::DecorationList{}); ast::DecorationList{});
auto* func2 = Func("func", ast::VariableList{}, ty.void_(), auto* func2 = Func("func", ast::VariableList{}, ty.void_(),
{ {
Assign("out_var", Call("my_func")), WrapInStatement(Call("my_func")),
}, },
ast::DecorationList{}); ast::DecorationList{});
@ -1041,12 +1033,10 @@ TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
EXPECT_EQ(func2_sem->Parameters().size(), 0u); EXPECT_EQ(func2_sem->Parameters().size(), 0u);
const auto& vars = func2_sem->ReferencedModuleVariables(); const auto& vars = func2_sem->ReferencedModuleVariables();
ASSERT_EQ(vars.size(), 5u); ASSERT_EQ(vars.size(), 3u);
EXPECT_EQ(vars[0]->Declaration(), out_var); EXPECT_EQ(vars[0]->Declaration(), wg_var);
EXPECT_EQ(vars[1]->Declaration(), in_var); EXPECT_EQ(vars[1]->Declaration(), sb_var);
EXPECT_EQ(vars[2]->Declaration(), wg_var); EXPECT_EQ(vars[2]->Declaration(), priv_var);
EXPECT_EQ(vars[3]->Declaration(), sb_var);
EXPECT_EQ(vars[4]->Declaration(), priv_var);
} }
TEST_F(ResolverTest, Function_NotRegisterFunctionVariable) { TEST_F(ResolverTest, Function_NotRegisterFunctionVariable) {
@ -1285,7 +1275,7 @@ TEST_F(ResolverTest, Function_WorkgroupSize_Mixed) {
TEST_F(ResolverTest, Expr_MemberAccessor_Struct) { TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
auto* st = Structure("S", {Member("first_member", ty.i32()), auto* st = Structure("S", {Member("first_member", ty.i32()),
Member("second_member", ty.f32())}); Member("second_member", ty.f32())});
Global("my_struct", ty.Of(st), ast::StorageClass::kInput); Global("my_struct", ty.Of(st), ast::StorageClass::kPrivate);
auto* mem = MemberAccessor("my_struct", "second_member"); auto* mem = MemberAccessor("my_struct", "second_member");
WrapInFunction(mem); WrapInFunction(mem);
@ -1309,7 +1299,7 @@ TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
auto* st = Structure("S", {Member("first_member", ty.i32()), auto* st = Structure("S", {Member("first_member", ty.i32()),
Member("second_member", ty.f32())}); Member("second_member", ty.f32())});
auto* alias = Alias("alias", ty.Of(st)); auto* alias = Alias("alias", ty.Of(st));
Global("my_struct", ty.Of(alias), ast::StorageClass::kInput); Global("my_struct", ty.Of(alias), ast::StorageClass::kPrivate);
auto* mem = MemberAccessor("my_struct", "second_member"); auto* mem = MemberAccessor("my_struct", "second_member");
WrapInFunction(mem); WrapInFunction(mem);
@ -1328,7 +1318,7 @@ TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
} }
TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle) { TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle) {
Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kInput); Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* mem = MemberAccessor("my_vec", "xzyw"); auto* mem = MemberAccessor("my_vec", "xzyw");
WrapInFunction(mem); WrapInFunction(mem);
@ -1345,7 +1335,7 @@ TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle) {
} }
TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle_SingleElement) { TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle_SingleElement) {
Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kInput); Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* mem = MemberAccessor("my_vec", "b"); auto* mem = MemberAccessor("my_vec", "b");
WrapInFunction(mem); WrapInFunction(mem);
@ -1389,7 +1379,7 @@ TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
auto* stB = Structure("B", {Member("foo", ty.vec4<f32>())}); auto* stB = Structure("B", {Member("foo", ty.vec4<f32>())});
auto* stA = Structure("A", {Member("mem", ty.vec(ty.Of(stB), 3))}); auto* stA = Structure("A", {Member("mem", ty.vec(ty.Of(stB), 3))});
Global("c", ty.Of(stA), ast::StorageClass::kInput); Global("c", ty.Of(stA), ast::StorageClass::kPrivate);
auto* mem = MemberAccessor( auto* mem = MemberAccessor(
MemberAccessor(IndexAccessor(MemberAccessor("c", "mem"), 0), "foo"), MemberAccessor(IndexAccessor(MemberAccessor("c", "mem"), 0), "foo"),
@ -1408,7 +1398,7 @@ TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
TEST_F(ResolverTest, Expr_MemberAccessor_InBinaryOp) { TEST_F(ResolverTest, Expr_MemberAccessor_InBinaryOp) {
auto* st = Structure("S", {Member("first_member", ty.f32()), auto* st = Structure("S", {Member("first_member", ty.f32()),
Member("second_member", ty.f32())}); Member("second_member", ty.f32())});
Global("my_struct", ty.Of(st), ast::StorageClass::kInput); Global("my_struct", ty.Of(st), ast::StorageClass::kPrivate);
auto* expr = Add(MemberAccessor("my_struct", "first_member"), auto* expr = Add(MemberAccessor("my_struct", "first_member"),
MemberAccessor("my_struct", "second_member")); MemberAccessor("my_struct", "second_member"));
@ -1714,8 +1704,8 @@ TEST_P(Expr_Binary_Test_Valid, All) {
<< FriendlyName(rhs_type); << FriendlyName(rhs_type);
SCOPED_TRACE(ss.str()); SCOPED_TRACE(ss.str());
Global("lhs", lhs_type, ast::StorageClass::kInput); Global("lhs", lhs_type, ast::StorageClass::kPrivate);
Global("rhs", rhs_type, ast::StorageClass::kInput); Global("rhs", rhs_type, ast::StorageClass::kPrivate);
auto* expr = auto* expr =
create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs")); create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
@ -1756,8 +1746,8 @@ TEST_P(Expr_Binary_Test_WithAlias_Valid, All) {
<< " " << FriendlyName(rhs_type); << " " << FriendlyName(rhs_type);
SCOPED_TRACE(ss.str()); SCOPED_TRACE(ss.str());
Global("lhs", lhs_type, ast::StorageClass::kInput); Global("lhs", lhs_type, ast::StorageClass::kPrivate);
Global("rhs", rhs_type, ast::StorageClass::kInput); Global("rhs", rhs_type, ast::StorageClass::kPrivate);
auto* expr = auto* expr =
create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs")); create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
@ -1808,8 +1798,8 @@ TEST_P(Expr_Binary_Test_Invalid, All) {
ss << FriendlyName(lhs_type) << " " << op << " " << FriendlyName(rhs_type); ss << FriendlyName(lhs_type) << " " << op << " " << FriendlyName(rhs_type);
SCOPED_TRACE(ss.str()); SCOPED_TRACE(ss.str());
Global("lhs", lhs_type, ast::StorageClass::kInput); Global("lhs", lhs_type, ast::StorageClass::kPrivate);
Global("rhs", rhs_type, ast::StorageClass::kInput); Global("rhs", rhs_type, ast::StorageClass::kPrivate);
auto* expr = create<ast::BinaryExpression>(Source{{12, 34}}, op, Expr("lhs"), auto* expr = create<ast::BinaryExpression>(Source{{12, 34}}, op, Expr("lhs"),
Expr("rhs")); Expr("rhs"));
@ -1854,8 +1844,8 @@ TEST_P(Expr_Binary_Test_Invalid_VectorMatrixMultiply, All) {
is_valid_expr = vec_size == mat_cols; is_valid_expr = vec_size == mat_cols;
} }
Global("lhs", lhs_type, ast::StorageClass::kInput); Global("lhs", lhs_type, ast::StorageClass::kPrivate);
Global("rhs", rhs_type, ast::StorageClass::kInput); Global("rhs", rhs_type, ast::StorageClass::kPrivate);
auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs")); auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
WrapInFunction(expr); WrapInFunction(expr);
@ -1895,8 +1885,8 @@ TEST_P(Expr_Binary_Test_Invalid_MatrixMatrixMultiply, All) {
auto* col = create<sem::Vector>(f32, lhs_mat_rows); auto* col = create<sem::Vector>(f32, lhs_mat_rows);
auto* result_type = create<sem::Matrix>(col, rhs_mat_cols); auto* result_type = create<sem::Matrix>(col, rhs_mat_cols);
Global("lhs", lhs_type, ast::StorageClass::kInput); Global("lhs", lhs_type, ast::StorageClass::kPrivate);
Global("rhs", rhs_type, ast::StorageClass::kInput); Global("rhs", rhs_type, ast::StorageClass::kPrivate);
auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs")); auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
WrapInFunction(expr); WrapInFunction(expr);
@ -1927,7 +1917,7 @@ using UnaryOpExpressionTest = ResolverTestWithParam<ast::UnaryOp>;
TEST_P(UnaryOpExpressionTest, Expr_UnaryOp) { TEST_P(UnaryOpExpressionTest, Expr_UnaryOp) {
auto op = GetParam(); auto op = GetParam();
Global("ident", ty.vec4<f32>(), ast::StorageClass::kInput); Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* der = create<ast::UnaryOpExpression>(op, Expr("ident")); auto* der = create<ast::UnaryOpExpression>(op, Expr("ident"));
WrapInFunction(der); WrapInFunction(der);

View File

@ -50,9 +50,8 @@ TEST_F(ResolverStorageClassValidationTest, StorageBufferBool) {
} }
TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) { TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
// var<storage> g : ptr<i32, input>; // var<storage> g : vec4<f32>;
Global(Source{{56, 78}}, "g", ty.pointer<i32>(ast::StorageClass::kInput), Global(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kStorage,
ast::StorageClass::kStorage,
ast::DecorationList{ ast::DecorationList{
create<ast::BindingDecoration>(0), create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(0), create<ast::GroupDecoration>(0),
@ -187,9 +186,8 @@ TEST_F(ResolverStorageClassValidationTest, UniformBufferBool) {
} }
TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) { TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
// var<uniform> g : ptr<i32, input>; // var<uniform> g : vec4<f32>;
Global(Source{{56, 78}}, "g", ty.pointer<i32>(ast::StorageClass::kInput), Global(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kUniform,
ast::StorageClass::kUniform,
ast::DecorationList{ ast::DecorationList{
create<ast::BindingDecoration>(0), create<ast::BindingDecoration>(0),
create<ast::GroupDecoration>(0), create<ast::GroupDecoration>(0),

View File

@ -85,17 +85,17 @@ TEST_F(ResolverTypeValidationTest, GlobalConstantNoConstructor_Pass) {
} }
TEST_F(ResolverTypeValidationTest, GlobalVariableWithStorageClass_Pass) { TEST_F(ResolverTypeValidationTest, GlobalVariableWithStorageClass_Pass) {
// var<in> global_var: f32; // var<private> global_var: f32;
Global(Source{{12, 34}}, "global_var", ty.f32(), ast::StorageClass::kInput); Global(Source{{12, 34}}, "global_var", ty.f32(), ast::StorageClass::kPrivate);
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
} }
TEST_F(ResolverTypeValidationTest, GlobalConstantWithStorageClass_Fail) { TEST_F(ResolverTypeValidationTest, GlobalConstantWithStorageClass_Fail) {
// const<in> global_var: f32; // const<private> global_var: f32;
AST().AddGlobalVariable(create<ast::Variable>( AST().AddGlobalVariable(create<ast::Variable>(
Source{{12, 34}}, Symbols().Register("global_var"), Source{{12, 34}}, Symbols().Register("global_var"),
ast::StorageClass::kInput, ast::Access::kUndefined, ty.f32(), true, ast::StorageClass::kPrivate, ast::Access::kUndefined, ty.f32(), true,
Expr(1.23f), ast::DecorationList{})); Expr(1.23f), ast::DecorationList{}));
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());

View File

@ -398,7 +398,7 @@ TEST_F(ResolverValidationTest, StorageClass_TextureExplicitStorageClass) {
} }
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadChar) { TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadChar) {
Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kInput); Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* ident = create<ast::IdentifierExpression>( auto* ident = create<ast::IdentifierExpression>(
Source{{Source::Location{3, 3}, Source::Location{3, 7}}}, Source{{Source::Location{3, 3}, Source::Location{3, 7}}},
@ -412,7 +412,7 @@ TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadChar) {
} }
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_MixedChars) { TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_MixedChars) {
Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kInput); Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
auto* ident = create<ast::IdentifierExpression>( auto* ident = create<ast::IdentifierExpression>(
Source{{Source::Location{3, 3}, Source::Location{3, 7}}}, Source{{Source::Location{3, 3}, Source::Location{3, 7}}},
@ -428,7 +428,7 @@ TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_MixedChars) {
} }
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadLength) { TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadLength) {
Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kInput); Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* ident = create<ast::IdentifierExpression>( auto* ident = create<ast::IdentifierExpression>(
Source{{Source::Location{3, 3}, Source::Location{3, 8}}}, Source{{Source::Location{3, 3}, Source::Location{3, 8}}},
@ -441,7 +441,7 @@ TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadLength) {
} }
TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadIndex) { TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadIndex) {
Global("my_vec", ty.vec2<f32>(), ast::StorageClass::kInput); Global("my_vec", ty.vec2<f32>(), ast::StorageClass::kPrivate);
auto* ident = create<ast::IdentifierExpression>(Source{{3, 3}}, auto* ident = create<ast::IdentifierExpression>(Source{{3, 3}},
Symbols().Register("z")); Symbols().Register("z"));
@ -1897,7 +1897,7 @@ TEST_F(ResolverValidationTest,
TEST_F(ResolverValidationTest, Expr_Constructor_Vector_Alias_Argument_Error) { TEST_F(ResolverValidationTest, Expr_Constructor_Vector_Alias_Argument_Error) {
auto* alias = Alias("UnsignedInt", ty.u32()); auto* alias = Alias("UnsignedInt", ty.u32());
Global("uint_var", ty.Of(alias), ast::StorageClass::kInput); Global("uint_var", ty.Of(alias), ast::StorageClass::kPrivate);
auto* tc = vec2<f32>(Expr(Source{{12, 34}}, "uint_var")); auto* tc = vec2<f32>(Expr(Source{{12, 34}}, "uint_var"));
WrapInFunction(tc); WrapInFunction(tc);
@ -1911,8 +1911,8 @@ TEST_F(ResolverValidationTest, Expr_Constructor_Vector_Alias_Argument_Error) {
TEST_F(ResolverValidationTest, Expr_Constructor_Vector_Alias_Argument_Success) { TEST_F(ResolverValidationTest, Expr_Constructor_Vector_Alias_Argument_Success) {
auto* f32_alias = Alias("Float32", ty.f32()); auto* f32_alias = Alias("Float32", ty.f32());
auto* vec2_alias = Alias("VectorFloat2", ty.vec2<f32>()); auto* vec2_alias = Alias("VectorFloat2", ty.vec2<f32>());
Global("my_f32", ty.Of(f32_alias), ast::StorageClass::kInput); Global("my_f32", ty.Of(f32_alias), ast::StorageClass::kPrivate);
Global("my_vec2", ty.Of(vec2_alias), ast::StorageClass::kInput); Global("my_vec2", ty.Of(vec2_alias), ast::StorageClass::kPrivate);
auto* tc = vec3<f32>("my_vec2", "my_f32"); auto* tc = vec3<f32>("my_vec2", "my_f32");
WrapInFunction(tc); WrapInFunction(tc);

View File

@ -211,8 +211,7 @@ void Msl::HandleModuleScopeVariables(CloneContext& ctx) const {
// scope. Disable storage class validation on this variable. // scope. Disable storage class validation on this variable.
auto* disable_validation = auto* disable_validation =
ctx.dst->ASTNodes().Create<ast::DisableValidationDecoration>( ctx.dst->ASTNodes().Create<ast::DisableValidationDecoration>(
ctx.dst->ID(), ctx.dst->ID(), ast::DisabledValidation::kIgnoreStorageClass);
ast::DisabledValidation::kFunctionVarStorageClass);
auto* constructor = ctx.Clone(var->Declaration()->constructor()); auto* constructor = ctx.Clone(var->Declaration()->constructor());
auto* local_var = ctx.dst->Var( auto* local_var = ctx.dst->Var(
new_var_symbol, store_type, var->StorageClass(), constructor, new_var_symbol, store_type, var->StorageClass(), constructor,

View File

@ -36,8 +36,8 @@ fn main() {
auto* expect = R"( auto* expect = R"(
[[stage(compute)]] [[stage(compute)]]
fn main([[builtin(local_invocation_index)]] local_invocation_index : u32) { fn main([[builtin(local_invocation_index)]] local_invocation_index : u32) {
[[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : f32; [[internal(disable_validation__ignore_storage_class)]] var<workgroup> tint_symbol_1 : f32;
[[internal(disable_validation__function_var_storage_class)]] var<private> tint_symbol_2 : f32; [[internal(disable_validation__ignore_storage_class)]] var<private> tint_symbol_2 : f32;
if ((local_invocation_index == 0u)) { if ((local_invocation_index == 0u)) {
tint_symbol_1 = f32(); tint_symbol_1 = f32();
} }
@ -93,8 +93,8 @@ fn foo(a : f32, tint_symbol_3 : ptr<private, f32>, tint_symbol_4 : ptr<workgroup
[[stage(compute)]] [[stage(compute)]]
fn main([[builtin(local_invocation_index)]] local_invocation_index : u32) { fn main([[builtin(local_invocation_index)]] local_invocation_index : u32) {
[[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_5 : f32; [[internal(disable_validation__ignore_storage_class)]] var<workgroup> tint_symbol_5 : f32;
[[internal(disable_validation__function_var_storage_class)]] var<private> tint_symbol_6 : f32; [[internal(disable_validation__ignore_storage_class)]] var<private> tint_symbol_6 : f32;
if ((local_invocation_index == 0u)) { if ((local_invocation_index == 0u)) {
tint_symbol_5 = f32(); tint_symbol_5 = f32();
} }
@ -122,8 +122,8 @@ fn main() {
auto* expect = R"( auto* expect = R"(
[[stage(compute)]] [[stage(compute)]]
fn main() { fn main() {
[[internal(disable_validation__function_var_storage_class)]] var<private> tint_symbol : f32 = 1.0; [[internal(disable_validation__ignore_storage_class)]] var<private> tint_symbol : f32 = 1.0;
[[internal(disable_validation__function_var_storage_class)]] var<private> tint_symbol_1 : f32 = f32(); [[internal(disable_validation__ignore_storage_class)]] var<private> tint_symbol_1 : f32 = f32();
let x : f32 = (tint_symbol + tint_symbol_1); let x : f32 = (tint_symbol + tint_symbol_1);
} }
)"; )";
@ -150,8 +150,8 @@ fn main() {
auto* expect = R"( auto* expect = R"(
[[stage(compute)]] [[stage(compute)]]
fn main([[builtin(local_invocation_index)]] local_invocation_index : u32) { fn main([[builtin(local_invocation_index)]] local_invocation_index : u32) {
[[internal(disable_validation__function_var_storage_class)]] var<workgroup> tint_symbol_1 : f32; [[internal(disable_validation__ignore_storage_class)]] var<workgroup> tint_symbol_1 : f32;
[[internal(disable_validation__function_var_storage_class)]] var<private> tint_symbol_2 : f32; [[internal(disable_validation__ignore_storage_class)]] var<private> tint_symbol_2 : f32;
if ((local_invocation_index == 0u)) { if ((local_invocation_index == 0u)) {
tint_symbol_1 = f32(); tint_symbol_1 = f32();
} }

View File

@ -18,6 +18,7 @@
#include <utility> #include <utility>
#include "src/ast/call_statement.h" #include "src/ast/call_statement.h"
#include "src/ast/disable_validation_decoration.h"
#include "src/ast/return_statement.h" #include "src/ast/return_statement.h"
#include "src/ast/stage_decoration.h" #include "src/ast/stage_decoration.h"
#include "src/program_builder.h" #include "src/program_builder.h"
@ -272,7 +273,10 @@ void Spirv::EmitVertexPointSize(CloneContext& ctx) const {
Symbol pointsize = ctx.dst->Symbols().New("tint_pointsize"); Symbol pointsize = ctx.dst->Symbols().New("tint_pointsize");
ctx.dst->Global( ctx.dst->Global(
pointsize, ctx.dst->ty.f32(), ast::StorageClass::kOutput, pointsize, ctx.dst->ty.f32(), ast::StorageClass::kOutput,
ast::DecorationList{ctx.dst->Builtin(ast::Builtin::kPointSize)}); ast::DecorationList{
ctx.dst->Builtin(ast::Builtin::kPointSize),
ctx.dst->ASTNodes().Create<ast::DisableValidationDecoration>(
ctx.dst->ID(), ast::DisabledValidation::kIgnoreStorageClass)});
// Assign 1.0 to the global at the start of all vertex shader entry points. // Assign 1.0 to the global at the start of all vertex shader entry points.
ctx.ReplaceAll([&ctx, pointsize](ast::Function* func) -> ast::Function* { ctx.ReplaceAll([&ctx, pointsize](ast::Function* func) -> ast::Function* {
@ -309,6 +313,9 @@ Symbol Spirv::HoistToInputVariables(
return !deco->IsAnyOf<ast::BuiltinDecoration, return !deco->IsAnyOf<ast::BuiltinDecoration,
ast::LocationDecoration>(); ast::LocationDecoration>();
}); });
new_decorations.push_back(
ctx.dst->ASTNodes().Create<ast::DisableValidationDecoration>(
ctx.dst->ID(), ast::DisabledValidation::kIgnoreStorageClass));
auto global_var_symbol = ctx.dst->Sym(); auto global_var_symbol = ctx.dst->Sym();
auto* global_var = auto* global_var =
ctx.dst->Var(global_var_symbol, ctx.Clone(declared_ty), ctx.dst->Var(global_var_symbol, ctx.Clone(declared_ty),
@ -363,6 +370,9 @@ void Spirv::HoistToOutputVariables(CloneContext& ctx,
return !deco->IsAnyOf<ast::BuiltinDecoration, return !deco->IsAnyOf<ast::BuiltinDecoration,
ast::LocationDecoration>(); ast::LocationDecoration>();
}); });
new_decorations.push_back(
ctx.dst->ASTNodes().Create<ast::DisableValidationDecoration>(
ctx.dst->ID(), ast::DisabledValidation::kIgnoreStorageClass));
auto global_var_symbol = ctx.dst->Sym(); auto global_var_symbol = ctx.dst->Sym();
auto* global_var = auto* global_var =
ctx.dst->Var(global_var_symbol, ctx.Clone(declared_ty), ctx.dst->Var(global_var_symbol, ctx.Clone(declared_ty),

View File

@ -38,18 +38,18 @@ fn compute_main([[builtin(local_invocation_id)]] local_id : vec3<u32>,
)"; )";
auto* expect = R"( auto* expect = R"(
[[builtin(position)]] var<in> tint_symbol : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol : vec4<f32>;
[[location(1)]] var<in> tint_symbol_1 : f32; [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_1 : f32;
[[stage(fragment)]] [[stage(fragment)]]
fn frag_main() { fn frag_main() {
var col : f32 = (tint_symbol.x * tint_symbol_1); var col : f32 = (tint_symbol.x * tint_symbol_1);
} }
[[builtin(local_invocation_id)]] var<in> tint_symbol_2 : vec3<u32>; [[builtin(local_invocation_id), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_2 : vec3<u32>;
[[builtin(local_invocation_index)]] var<in> tint_symbol_3 : u32; [[builtin(local_invocation_index), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_3 : u32;
[[stage(compute)]] [[stage(compute)]]
fn compute_main() { fn compute_main() {
@ -74,7 +74,7 @@ fn frag_main([[location(1)]] loc1 : myf32) {
auto* expect = R"( auto* expect = R"(
type myf32 = f32; type myf32 = f32;
[[location(1)]] var<in> tint_symbol : myf32; [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol : myf32;
[[stage(fragment)]] [[stage(fragment)]]
fn frag_main() { fn frag_main() {
@ -95,7 +95,7 @@ fn vert_main() -> [[builtin(position)]] vec4<f32> {
)"; )";
auto* expect = R"( auto* expect = R"(
[[builtin(position)]] var<out> tint_symbol_1 : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_1 : vec4<f32>;
fn tint_symbol_2(tint_symbol : vec4<f32>) { fn tint_symbol_2(tint_symbol : vec4<f32>) {
tint_symbol_1 = tint_symbol; tint_symbol_1 = tint_symbol;
@ -125,9 +125,9 @@ fn frag_main([[location(0)]] loc_in : u32) -> [[location(0)]] f32 {
)"; )";
auto* expect = R"( auto* expect = R"(
[[location(0)]] var<in> tint_symbol : u32; [[location(0), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol : u32;
[[location(0)]] var<out> tint_symbol_2 : f32; [[location(0), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_2 : f32;
fn tint_symbol_3(tint_symbol_1 : f32) { fn tint_symbol_3(tint_symbol_1 : f32) {
tint_symbol_2 = tint_symbol_1; tint_symbol_2 = tint_symbol_1;
@ -165,9 +165,9 @@ fn frag_main([[location(0)]] loc_in : u32) -> [[location(0)]] myf32 {
auto* expect = R"( auto* expect = R"(
type myf32 = f32; type myf32 = f32;
[[location(0)]] var<in> tint_symbol : u32; [[location(0), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol : u32;
[[location(0)]] var<out> tint_symbol_2 : myf32; [[location(0), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_2 : myf32;
fn tint_symbol_3(tint_symbol_1 : myf32) { fn tint_symbol_3(tint_symbol_1 : myf32) {
tint_symbol_2 = tint_symbol_1; tint_symbol_2 = tint_symbol_1;
@ -208,9 +208,9 @@ struct FragmentInput {
value : f32; value : f32;
}; };
[[builtin(position)]] var<in> tint_symbol : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol : vec4<f32>;
[[location(1)]] var<in> tint_symbol_1 : f32; [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_1 : f32;
[[stage(fragment)]] [[stage(fragment)]]
fn frag_main() { fn frag_main() {
@ -240,7 +240,7 @@ struct FragmentInput {
value : f32; value : f32;
}; };
[[location(1)]] var<in> tint_symbol : f32; [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol : f32;
[[stage(fragment)]] [[stage(fragment)]]
fn frag_main() { fn frag_main() {
@ -275,9 +275,9 @@ struct VertexOutput {
value : f32; value : f32;
}; };
[[builtin(position)]] var<out> tint_symbol_1 : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_1 : vec4<f32>;
[[location(1)]] var<out> tint_symbol_2 : f32; [[location(1), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_2 : f32;
fn tint_symbol_3(tint_symbol : VertexOutput) { fn tint_symbol_3(tint_symbol : VertexOutput) {
tint_symbol_1 = tint_symbol.pos; tint_symbol_1 = tint_symbol.pos;
@ -318,9 +318,9 @@ struct Interface {
value : f32; value : f32;
}; };
[[location(1)]] var<in> tint_symbol : f32; [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol : f32;
[[location(1)]] var<out> tint_symbol_3 : f32; [[location(1), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_3 : f32;
fn tint_symbol_4(tint_symbol_2 : Interface) { fn tint_symbol_4(tint_symbol_2 : Interface) {
tint_symbol_3 = tint_symbol_2.value; tint_symbol_3 = tint_symbol_2.value;
@ -363,9 +363,9 @@ struct Interface {
value : f32; value : f32;
}; };
[[builtin(position)]] var<out> tint_symbol_1 : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_1 : vec4<f32>;
[[location(1)]] var<out> tint_symbol_2 : f32; [[location(1), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_2 : f32;
fn tint_symbol_3(tint_symbol : Interface) { fn tint_symbol_3(tint_symbol : Interface) {
tint_symbol_1 = tint_symbol.pos; tint_symbol_1 = tint_symbol.pos;
@ -378,9 +378,9 @@ fn vert_main() {
return; return;
} }
[[builtin(position)]] var<in> tint_symbol_4 : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_4 : vec4<f32>;
[[location(1)]] var<in> tint_symbol_5 : f32; [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_5 : f32;
[[stage(fragment)]] [[stage(fragment)]]
fn frag_main() { fn frag_main() {
@ -426,11 +426,11 @@ struct FragmentOutput {
value : f32; value : f32;
}; };
[[location(1)]] var<in> tint_symbol : f32; [[location(1), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol : f32;
[[builtin(position)]] var<in> tint_symbol_1 : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_1 : vec4<f32>;
[[location(1)]] var<out> tint_symbol_4 : f32; [[location(1), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_4 : f32;
fn tint_symbol_5(tint_symbol_3 : FragmentOutput) { fn tint_symbol_5(tint_symbol_3 : FragmentOutput) {
tint_symbol_4 = tint_symbol_3.value; tint_symbol_4 = tint_symbol_3.value;
@ -472,7 +472,7 @@ struct VertexOutput {
Position : vec4<f32>; Position : vec4<f32>;
}; };
[[builtin(position)]] var<out> tint_symbol_1 : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_1 : vec4<f32>;
fn tint_symbol_2(tint_symbol : VertexOutput) { fn tint_symbol_2(tint_symbol : VertexOutput) {
tint_symbol_1 = tint_symbol.Position; tint_symbol_1 = tint_symbol.Position;
@ -501,11 +501,11 @@ fn main([[builtin(sample_index)]] sample_index : u32,
)"; )";
auto* expect = R"( auto* expect = R"(
[[builtin(sample_index)]] var<in> tint_symbol : u32; [[builtin(sample_index), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol : u32;
[[builtin(sample_mask)]] var<in> tint_symbol_1 : array<u32, 1>; [[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_1 : array<u32, 1>;
[[builtin(sample_mask)]] var<out> tint_symbol_3 : array<u32, 1>; [[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_3 : array<u32, 1>;
fn tint_symbol_4(tint_symbol_2 : u32) { fn tint_symbol_4(tint_symbol_2 : u32) {
tint_symbol_3[0] = tint_symbol_2; tint_symbol_3[0] = tint_symbol_2;
@ -549,9 +549,9 @@ fn set_mask(input : u32) -> u32 {
return input; return input;
} }
[[builtin(sample_mask)]] var<in> tint_symbol : array<u32, 1>; [[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol : array<u32, 1>;
[[builtin(sample_mask)]] var<out> tint_symbol_2 : array<u32, 1>; [[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_2 : array<u32, 1>;
fn tint_symbol_3(tint_symbol_1 : u32) { fn tint_symbol_3(tint_symbol_1 : u32) {
tint_symbol_2[0] = tint_symbol_1; tint_symbol_2[0] = tint_symbol_1;
@ -582,12 +582,12 @@ fn main() -> [[builtin(position)]] vec4<f32> {
)"; )";
auto* expect = R"( auto* expect = R"(
[[builtin(pointsize)]] var<out> tint_pointsize : f32; [[builtin(pointsize), internal(disable_validation__ignore_storage_class)]] var<out> tint_pointsize : f32;
fn non_entry_point() { fn non_entry_point() {
} }
[[builtin(position)]] var<out> tint_symbol_1 : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_1 : vec4<f32>;
fn tint_symbol_2(tint_symbol : vec4<f32>) { fn tint_symbol_2(tint_symbol : vec4<f32>) {
tint_symbol_1 = tint_symbol; tint_symbol_1 = tint_symbol;
@ -628,9 +628,9 @@ fn main3() -> [[builtin(position)]] vec4<f32> {
)"; )";
auto* expect = R"( auto* expect = R"(
[[builtin(pointsize)]] var<out> tint_pointsize : f32; [[builtin(pointsize), internal(disable_validation__ignore_storage_class)]] var<out> tint_pointsize : f32;
[[builtin(position)]] var<out> tint_symbol_1 : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_1 : vec4<f32>;
fn tint_symbol_2(tint_symbol : vec4<f32>) { fn tint_symbol_2(tint_symbol : vec4<f32>) {
tint_symbol_1 = tint_symbol; tint_symbol_1 = tint_symbol;
@ -643,7 +643,7 @@ fn main1() {
return; return;
} }
[[builtin(position)]] var<out> tint_symbol_4 : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_4 : vec4<f32>;
fn tint_symbol_5(tint_symbol_3 : vec4<f32>) { fn tint_symbol_5(tint_symbol_3 : vec4<f32>) {
tint_symbol_4 = tint_symbol_3; tint_symbol_4 = tint_symbol_3;
@ -656,7 +656,7 @@ fn main2() {
return; return;
} }
[[builtin(position)]] var<out> tint_symbol_7 : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_7 : vec4<f32>;
fn tint_symbol_8(tint_symbol_6 : vec4<f32>) { fn tint_symbol_8(tint_symbol_6 : vec4<f32>) {
tint_symbol_7 = tint_symbol_6; tint_symbol_7 = tint_symbol_6;
@ -722,9 +722,9 @@ fn frag_main([[builtin(sample_index)]] sample_index : u32,
)"; )";
auto* expect = R"( auto* expect = R"(
[[builtin(pointsize)]] var<out> tint_pointsize : f32; [[builtin(pointsize), internal(disable_validation__ignore_storage_class)]] var<out> tint_pointsize : f32;
[[builtin(position)]] var<out> tint_symbol_1 : vec4<f32>; [[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_1 : vec4<f32>;
fn tint_symbol_2(tint_symbol : vec4<f32>) { fn tint_symbol_2(tint_symbol : vec4<f32>) {
tint_symbol_1 = tint_symbol; tint_symbol_1 = tint_symbol;
@ -737,11 +737,11 @@ fn vert_main() {
return; return;
} }
[[builtin(sample_index)]] var<in> tint_symbol_3 : u32; [[builtin(sample_index), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_3 : u32;
[[builtin(sample_mask)]] var<in> tint_symbol_4 : array<u32, 1>; [[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_4 : array<u32, 1>;
[[builtin(sample_mask)]] var<out> tint_symbol_6 : array<u32, 1>; [[builtin(sample_mask), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_6 : array<u32, 1>;
fn tint_symbol_7(tint_symbol_5 : u32) { fn tint_symbol_7(tint_symbol_5 : u32) {
tint_symbol_6[0] = tint_symbol_5; tint_symbol_6[0] = tint_symbol_5;

View File

@ -87,7 +87,7 @@ TEST_F(AppendVectorTest, Vec3i32_i32) {
} }
TEST_F(AppendVectorTest, Vec2i32Var_i32) { TEST_F(AppendVectorTest, Vec2i32Var_i32) {
Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kInput); Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
auto* vec_12 = Expr("vec_12"); auto* vec_12 = Expr("vec_12");
auto* scalar_3 = Expr(3); auto* scalar_3 = Expr(3);
WrapInFunction(vec_12, scalar_3); WrapInFunction(vec_12, scalar_3);
@ -104,7 +104,7 @@ TEST_F(AppendVectorTest, Vec2i32Var_i32) {
} }
TEST_F(AppendVectorTest, Vec2i32_i32Var) { TEST_F(AppendVectorTest, Vec2i32_i32Var) {
Global("scalar_3", ty.i32(), ast::StorageClass::kInput); Global("scalar_3", ty.i32(), ast::StorageClass::kPrivate);
auto* scalar_1 = Expr(1); auto* scalar_1 = Expr(1);
auto* scalar_2 = Expr(2); auto* scalar_2 = Expr(2);
auto* scalar_3 = Expr("scalar_3"); auto* scalar_3 = Expr("scalar_3");
@ -124,8 +124,8 @@ TEST_F(AppendVectorTest, Vec2i32_i32Var) {
} }
TEST_F(AppendVectorTest, Vec2i32Var_i32Var) { TEST_F(AppendVectorTest, Vec2i32Var_i32Var) {
Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kInput); Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
Global("scalar_3", ty.i32(), ast::StorageClass::kInput); Global("scalar_3", ty.i32(), ast::StorageClass::kPrivate);
auto* vec_12 = Expr("vec_12"); auto* vec_12 = Expr("vec_12");
auto* scalar_3 = Expr("scalar_3"); auto* scalar_3 = Expr("scalar_3");
WrapInFunction(vec_12, scalar_3); WrapInFunction(vec_12, scalar_3);
@ -142,8 +142,8 @@ TEST_F(AppendVectorTest, Vec2i32Var_i32Var) {
} }
TEST_F(AppendVectorTest, Vec2i32Var_f32Var) { TEST_F(AppendVectorTest, Vec2i32Var_f32Var) {
Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kInput); Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
Global("scalar_3", ty.f32(), ast::StorageClass::kInput); Global("scalar_3", ty.f32(), ast::StorageClass::kPrivate);
auto* vec_12 = Expr("vec_12"); auto* vec_12 = Expr("vec_12");
auto* scalar_3 = Expr("scalar_3"); auto* scalar_3 = Expr("scalar_3");
WrapInFunction(vec_12, scalar_3); WrapInFunction(vec_12, scalar_3);
@ -163,8 +163,8 @@ TEST_F(AppendVectorTest, Vec2i32Var_f32Var) {
} }
TEST_F(AppendVectorTest, Vec2boolVar_boolVar) { TEST_F(AppendVectorTest, Vec2boolVar_boolVar) {
Global("vec_12", ty.vec2<bool>(), ast::StorageClass::kInput); Global("vec_12", ty.vec2<bool>(), ast::StorageClass::kPrivate);
Global("scalar_3", ty.bool_(), ast::StorageClass::kInput); Global("scalar_3", ty.bool_(), ast::StorageClass::kPrivate);
auto* vec_12 = Expr("vec_12"); auto* vec_12 = Expr("vec_12");
auto* scalar_3 = Expr("scalar_3"); auto* scalar_3 = Expr("scalar_3");
WrapInFunction(vec_12, scalar_3); WrapInFunction(vec_12, scalar_3);

View File

@ -20,6 +20,7 @@
#include "spirv/unified1/GLSL.std.450.h" #include "spirv/unified1/GLSL.std.450.h"
#include "src/ast/call_statement.h" #include "src/ast/call_statement.h"
#include "src/ast/fallthrough_statement.h" #include "src/ast/fallthrough_statement.h"
#include "src/ast/internal_decoration.h"
#include "src/ast/override_decoration.h" #include "src/ast/override_decoration.h"
#include "src/sem/array.h" #include "src/sem/array.h"
#include "src/sem/atomic_type.h" #include "src/sem/atomic_type.h"
@ -843,7 +844,7 @@ bool Builder::GenerateGlobalVariable(ast::Variable* var) {
Operand::Int(group->value())}); Operand::Int(group->value())});
} else if (deco->Is<ast::OverrideDecoration>()) { } else if (deco->Is<ast::OverrideDecoration>()) {
// Spec constants are handled elsewhere // Spec constants are handled elsewhere
} else { } else if (!deco->Is<ast::InternalDecoration>()) {
error_ = "unknown decoration"; error_ = "unknown decoration";
return false; return false;
} }

View File

@ -23,7 +23,7 @@ namespace {
using BuilderTest = TestHelper; using BuilderTest = TestHelper;
TEST_F(BuilderTest, Assign_Var) { TEST_F(BuilderTest, Assign_Var) {
auto* v = Global("var", ty.f32(), ast::StorageClass::kOutput); auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
auto* assign = Assign("var", 1.f); auto* assign = Assign("var", 1.f);
@ -39,9 +39,9 @@ TEST_F(BuilderTest, Assign_Var) {
EXPECT_FALSE(b.has_error()); EXPECT_FALSE(b.has_error());
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32 EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
%2 = OpTypePointer Output %3 %2 = OpTypePointer Private %3
%4 = OpConstantNull %3 %4 = OpConstantNull %3
%1 = OpVariable %2 Output %4 %1 = OpVariable %2 Private %4
%5 = OpConstant %3 1 %5 = OpConstant %3 1
)"); )");
@ -51,7 +51,7 @@ TEST_F(BuilderTest, Assign_Var) {
} }
TEST_F(BuilderTest, Assign_Var_OutsideFunction_IsError) { TEST_F(BuilderTest, Assign_Var_OutsideFunction_IsError) {
auto* v = Global("var", ty.f32(), ast::StorageClass::kOutput); auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
auto* assign = Assign("var", Expr(1.f)); auto* assign = Assign("var", Expr(1.f));
@ -70,7 +70,7 @@ TEST_F(BuilderTest, Assign_Var_OutsideFunction_IsError) {
} }
TEST_F(BuilderTest, Assign_Var_ZeroConstructor) { TEST_F(BuilderTest, Assign_Var_ZeroConstructor) {
auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kOutput); auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* val = vec3<f32>(); auto* val = vec3<f32>();
auto* assign = Assign("var", val); auto* assign = Assign("var", val);
@ -88,9 +88,9 @@ TEST_F(BuilderTest, Assign_Var_ZeroConstructor) {
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
%3 = OpTypeVector %4 3 %3 = OpTypeVector %4 3
%2 = OpTypePointer Output %3 %2 = OpTypePointer Private %3
%5 = OpConstantNull %3 %5 = OpConstantNull %3
%1 = OpVariable %2 Output %5 %1 = OpVariable %2 Private %5
)"); )");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
@ -101,7 +101,7 @@ TEST_F(BuilderTest, Assign_Var_ZeroConstructor) {
TEST_F(BuilderTest, Assign_Var_Complex_ConstructorWithExtract) { TEST_F(BuilderTest, Assign_Var_Complex_ConstructorWithExtract) {
auto* init = vec3<f32>(vec2<f32>(1.f, 2.f), 3.f); auto* init = vec3<f32>(vec2<f32>(1.f, 2.f), 3.f);
auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kOutput); auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* assign = Assign("var", init); auto* assign = Assign("var", init);
@ -118,9 +118,9 @@ TEST_F(BuilderTest, Assign_Var_Complex_ConstructorWithExtract) {
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
%3 = OpTypeVector %4 3 %3 = OpTypeVector %4 3
%2 = OpTypePointer Output %3 %2 = OpTypePointer Private %3
%5 = OpConstantNull %3 %5 = OpConstantNull %3
%1 = OpVariable %2 Output %5 %1 = OpVariable %2 Private %5
%6 = OpTypeVector %4 2 %6 = OpTypeVector %4 2
%7 = OpConstant %4 1 %7 = OpConstant %4 1
%8 = OpConstant %4 2 %8 = OpConstant %4 2
@ -138,7 +138,7 @@ OpStore %1 %13
TEST_F(BuilderTest, Assign_Var_Complex_Constructor) { TEST_F(BuilderTest, Assign_Var_Complex_Constructor) {
auto* init = vec3<f32>(1.f, 2.f, 3.f); auto* init = vec3<f32>(1.f, 2.f, 3.f);
auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kOutput); auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* assign = Assign("var", init); auto* assign = Assign("var", init);
@ -155,9 +155,9 @@ TEST_F(BuilderTest, Assign_Var_Complex_Constructor) {
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
%3 = OpTypeVector %4 3 %3 = OpTypeVector %4 3
%2 = OpTypePointer Output %3 %2 = OpTypePointer Private %3
%5 = OpConstantNull %3 %5 = OpConstantNull %3
%1 = OpVariable %2 Output %5 %1 = OpVariable %2 Private %5
%6 = OpConstant %4 1 %6 = OpConstant %4 1
%7 = OpConstant %4 2 %7 = OpConstant %4 2
%8 = OpConstant %4 3 %8 = OpConstant %4 3
@ -213,7 +213,7 @@ OpStore %8 %9
} }
TEST_F(BuilderTest, Assign_Vector) { TEST_F(BuilderTest, Assign_Vector) {
auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kOutput); auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* val = vec3<f32>(1.f, 1.f, 3.f); auto* val = vec3<f32>(1.f, 1.f, 3.f);
auto* assign = Assign("var", val); auto* assign = Assign("var", val);
@ -231,9 +231,9 @@ TEST_F(BuilderTest, Assign_Vector) {
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
%3 = OpTypeVector %4 3 %3 = OpTypeVector %4 3
%2 = OpTypePointer Output %3 %2 = OpTypePointer Private %3
%5 = OpConstantNull %3 %5 = OpConstantNull %3
%1 = OpVariable %2 Output %5 %1 = OpVariable %2 Private %5
%6 = OpConstant %4 1 %6 = OpConstant %4 1
%7 = OpConstant %4 3 %7 = OpConstant %4 3
%8 = OpConstantComposite %3 %6 %6 %7 %8 = OpConstantComposite %3 %6 %6 %7
@ -247,7 +247,7 @@ TEST_F(BuilderTest, Assign_Vector) {
TEST_F(BuilderTest, Assign_Vector_MemberByName) { TEST_F(BuilderTest, Assign_Vector_MemberByName) {
// var.y = 1 // var.y = 1
auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kOutput); auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* assign = Assign(MemberAccessor("var", "y"), Expr(1.f)); auto* assign = Assign(MemberAccessor("var", "y"), Expr(1.f));
@ -264,12 +264,12 @@ TEST_F(BuilderTest, Assign_Vector_MemberByName) {
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
%3 = OpTypeVector %4 3 %3 = OpTypeVector %4 3
%2 = OpTypePointer Output %3 %2 = OpTypePointer Private %3
%5 = OpConstantNull %3 %5 = OpConstantNull %3
%1 = OpVariable %2 Output %5 %1 = OpVariable %2 Private %5
%6 = OpTypeInt 32 0 %6 = OpTypeInt 32 0
%7 = OpConstant %6 1 %7 = OpConstant %6 1
%8 = OpTypePointer Output %4 %8 = OpTypePointer Private %4
%10 = OpConstant %4 1 %10 = OpConstant %4 1
)"); )");
@ -282,7 +282,7 @@ OpStore %9 %10
TEST_F(BuilderTest, Assign_Vector_MemberByIndex) { TEST_F(BuilderTest, Assign_Vector_MemberByIndex) {
// var[1] = 1 // var[1] = 1
auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kOutput); auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* assign = Assign(IndexAccessor("var", 1), Expr(1.f)); auto* assign = Assign(IndexAccessor("var", 1), Expr(1.f));
@ -299,12 +299,12 @@ TEST_F(BuilderTest, Assign_Vector_MemberByIndex) {
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
%3 = OpTypeVector %4 3 %3 = OpTypeVector %4 3
%2 = OpTypePointer Output %3 %2 = OpTypePointer Private %3
%5 = OpConstantNull %3 %5 = OpConstantNull %3
%1 = OpVariable %2 Output %5 %1 = OpVariable %2 Private %5
%6 = OpTypeInt 32 1 %6 = OpTypeInt 32 1
%7 = OpConstant %6 1 %7 = OpConstant %6 1
%8 = OpTypePointer Output %4 %8 = OpTypePointer Private %4
%10 = OpConstant %4 1 %10 = OpConstant %4 1
)"); )");

View File

@ -292,6 +292,22 @@ OpFunctionEnd
Validate(b); Validate(b);
} }
TEST_F(BuilderTest, SampleIndex_SampleRateShadingCapability) {
Func("main",
{Param("sample_index", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})},
ty.void_(), {}, {Stage(ast::PipelineStage::kCompute)});
spirv::Builder& b = SanitizeAndBuild();
ASSERT_TRUE(b.Build()) << b.error();
// Make sure we generate the SampleRateShading capability.
EXPECT_EQ(DumpInstructions(b.capabilities()),
"OpCapability Shader\n"
"OpCapability SampleRateShading\n");
EXPECT_EQ(DumpInstructions(b.annots()), "OpDecorate %1 BuiltIn SampleId\n");
}
} // namespace } // namespace
} // namespace spirv } // namespace spirv
} // namespace writer } // namespace writer

View File

@ -51,17 +51,22 @@ TEST_P(Decoration_StageTest, Emit) {
auto params = GetParam(); auto params = GetParam();
ast::Variable* var = nullptr; ast::Variable* var = nullptr;
ast::Type* ret_type = nullptr;
ast::DecorationList ret_type_decos;
ast::StatementList body; ast::StatementList body;
if (params.stage == ast::PipelineStage::kVertex) { if (params.stage == ast::PipelineStage::kVertex) {
var = Global("pos", ty.vec4<f32>(), ast::StorageClass::kOutput, nullptr, ret_type = ty.vec4<f32>();
ast::DecorationList{Builtin(ast::Builtin::kPosition)}); ret_type_decos.push_back(Builtin(ast::Builtin::kPosition));
body.push_back(Assign("pos", Construct(ty.vec4<f32>()))); body.push_back(Return(Construct(ty.vec4<f32>())));
} else {
ret_type = ty.void_();
} }
auto* func = Func("main", {}, ty.void_(), body, auto* func = Func("main", {}, ret_type, body,
ast::DecorationList{ ast::DecorationList{
Stage(params.stage), Stage(params.stage),
}); },
ret_type_decos);
spirv::Builder& b = Build(); spirv::Builder& b = Build();
@ -88,87 +93,6 @@ INSTANTIATE_TEST_SUITE_P(
FunctionStageData{ast::PipelineStage::kCompute, FunctionStageData{ast::PipelineStage::kCompute,
SpvExecutionModelGLCompute})); SpvExecutionModelGLCompute}));
TEST_F(BuilderTest, Decoration_Stage_WithUnusedInterfaceIds) {
auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
ast::DecorationList{
Stage(ast::PipelineStage::kFragment),
});
auto* v_in = Global("my_in", ty.f32(), ast::StorageClass::kInput);
auto* v_out = Global("my_out", ty.f32(), ast::StorageClass::kOutput);
auto* v_wg = Global("my_wg", ty.f32(), ast::StorageClass::kWorkgroup);
spirv::Builder& b = Build();
EXPECT_TRUE(b.GenerateGlobalVariable(v_in)) << b.error();
EXPECT_TRUE(b.GenerateGlobalVariable(v_out)) << b.error();
EXPECT_TRUE(b.GenerateGlobalVariable(v_wg)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "my_in"
OpName %4 "my_out"
OpName %7 "my_wg"
OpName %11 "main"
)");
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
%2 = OpTypePointer Input %3
%1 = OpVariable %2 Input
%5 = OpTypePointer Output %3
%6 = OpConstantNull %3
%4 = OpVariable %5 Output %6
%8 = OpTypePointer Workgroup %3
%7 = OpVariable %8 Workgroup
%10 = OpTypeVoid
%9 = OpTypeFunction %10
)");
EXPECT_EQ(DumpInstructions(b.entry_points()),
R"(OpEntryPoint Fragment %11 "main"
)");
}
TEST_F(BuilderTest, Decoration_Stage_WithUsedInterfaceIds) {
auto* v_in = Global("my_in", ty.f32(), ast::StorageClass::kInput);
auto* v_out = Global("my_out", ty.f32(), ast::StorageClass::kOutput);
auto* v_wg = Global("my_wg", ty.f32(), ast::StorageClass::kPrivate);
auto* func = Func(
"main", {}, ty.void_(),
ast::StatementList{Assign("my_out", "my_in"), Assign("my_wg", "my_wg"),
// Add duplicate usages so we show they
// don't get output multiple times.
Assign("my_out", "my_in")},
ast::DecorationList{
Stage(ast::PipelineStage::kFragment),
});
spirv::Builder& b = Build();
EXPECT_TRUE(b.GenerateGlobalVariable(v_in)) << b.error();
EXPECT_TRUE(b.GenerateGlobalVariable(v_out)) << b.error();
EXPECT_TRUE(b.GenerateGlobalVariable(v_wg)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "my_in"
OpName %4 "my_out"
OpName %7 "my_wg"
OpName %11 "main"
)");
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
%2 = OpTypePointer Input %3
%1 = OpVariable %2 Input
%5 = OpTypePointer Output %3
%6 = OpConstantNull %3
%4 = OpVariable %5 Output %6
%8 = OpTypePointer Private %3
%7 = OpVariable %8 Private %6
%10 = OpTypeVoid
%9 = OpTypeFunction %10
)");
EXPECT_EQ(DumpInstructions(b.entry_points()),
R"(OpEntryPoint Fragment %11 "main" %4 %1
)");
}
TEST_F(BuilderTest, Decoration_ExecutionMode_Fragment_OriginUpperLeft) { TEST_F(BuilderTest, Decoration_ExecutionMode_Fragment_OriginUpperLeft) {
auto* func = Func("main", {}, ty.void_(), ast::StatementList{}, auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
ast::DecorationList{ ast::DecorationList{
@ -323,22 +247,22 @@ OpFunctionEnd
} }
TEST_F(BuilderTest, Decoration_ExecutionMode_FragDepth) { TEST_F(BuilderTest, Decoration_ExecutionMode_FragDepth) {
Global("fragdepth", ty.f32(), ast::StorageClass::kOutput, nullptr, Func("main", ast::VariableList{}, ty.f32(),
ast::StatementList{
Return(Expr(1.f)),
},
ast::DecorationList{Stage(ast::PipelineStage::kFragment)},
ast::DecorationList{ ast::DecorationList{
Builtin(ast::Builtin::kFragDepth), Builtin(ast::Builtin::kFragDepth),
}); });
auto* func = Func("main", ast::VariableList{}, ty.void_(), spirv::Builder& b = SanitizeAndBuild();
ast::StatementList{
Assign("fragdepth", Expr(1.f)),
},
ast::DecorationList{});
spirv::Builder& b = Build(); ASSERT_TRUE(b.Build());
ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
EXPECT_EQ(DumpInstructions(b.execution_modes()), EXPECT_EQ(DumpInstructions(b.execution_modes()),
R"(OpExecutionMode %3 DepthReplacing R"(OpExecutionMode %11 OriginUpperLeft
OpExecutionMode %11 DepthReplacing
)"); )");
} }

View File

@ -26,7 +26,7 @@ namespace {
using BuilderTest = TestHelper; using BuilderTest = TestHelper;
TEST_F(BuilderTest, GlobalVar_WithStorageClass) { TEST_F(BuilderTest, GlobalVar_WithStorageClass) {
auto* v = Global("var", ty.f32(), ast::StorageClass::kOutput); auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
spirv::Builder& b = Build(); spirv::Builder& b = Build();
@ -34,30 +34,16 @@ TEST_F(BuilderTest, GlobalVar_WithStorageClass) {
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var" EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
)"); )");
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32 EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
%2 = OpTypePointer Output %3 %2 = OpTypePointer Private %3
%4 = OpConstantNull %3 %4 = OpConstantNull %3
%1 = OpVariable %2 Output %4 %1 = OpVariable %2 Private %4
)");
}
TEST_F(BuilderTest, GlobalVar_WithStorageClass_Input) {
auto* v = Global("var", ty.f32(), ast::StorageClass::kInput);
spirv::Builder& b = Build();
EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
)");
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
%2 = OpTypePointer Input %3
%1 = OpVariable %2 Input
)"); )");
} }
TEST_F(BuilderTest, GlobalVar_WithConstructor) { TEST_F(BuilderTest, GlobalVar_WithConstructor) {
auto* init = vec3<f32>(1.f, 1.f, 3.f); auto* init = vec3<f32>(1.f, 1.f, 3.f);
auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kOutput, init); auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate, init);
spirv::Builder& b = Build(); spirv::Builder& b = Build();
@ -71,8 +57,8 @@ TEST_F(BuilderTest, GlobalVar_WithConstructor) {
%3 = OpConstant %2 1 %3 = OpConstant %2 1
%4 = OpConstant %2 3 %4 = OpConstant %2 3
%5 = OpConstantComposite %1 %3 %3 %4 %5 = OpConstantComposite %1 %3 %3 %4
%7 = OpTypePointer Output %1 %7 = OpTypePointer Private %1
%6 = OpVariable %7 Output %5 %6 = OpVariable %7 Private %5
)"); )");
} }
@ -141,26 +127,6 @@ TEST_F(BuilderTest, GlobalVar_Complex_ConstructorWithExtract) {
)"); )");
} }
TEST_F(BuilderTest, GlobalVar_WithLocation) {
auto* v = Global("var", ty.f32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{
Location(5),
});
spirv::Builder& b = Build();
EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
)");
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 Location 5
)");
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
%2 = OpTypePointer Output %3
%4 = OpConstantNull %3
%1 = OpVariable %2 Output %4
)");
}
TEST_F(BuilderTest, GlobalVar_WithBindingAndGroup) { TEST_F(BuilderTest, GlobalVar_WithBindingAndGroup) {
auto* v = Global("var", ty.sampler(ast::SamplerKind::kSampler), auto* v = Global("var", ty.sampler(ast::SamplerKind::kSampler),
ast::StorageClass::kNone, nullptr, ast::StorageClass::kNone, nullptr,
@ -183,26 +149,6 @@ OpDecorate %1 DescriptorSet 3
)"); )");
} }
TEST_F(BuilderTest, GlobalVar_WithBuiltin) {
auto* v = Global("var", ty.f32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{
Builtin(ast::Builtin::kPosition),
});
spirv::Builder& b = Build();
EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
)");
EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 BuiltIn Position
)");
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
%2 = OpTypePointer Output %3
%4 = OpConstantNull %3
%1 = OpVariable %2 Output %4
)");
}
TEST_F(BuilderTest, GlobalVar_Override_Bool) { TEST_F(BuilderTest, GlobalVar_Override_Bool) {
auto* v = GlobalConst("var", ty.bool_(), Expr(true), auto* v = GlobalConst("var", ty.bool_(), Expr(true),
ast::DecorationList{ ast::DecorationList{
@ -661,96 +607,6 @@ OpDecorate %5 DescriptorSet 0
)"); )");
} }
TEST_F(BuilderTest, SampleIndex) {
auto* var =
Global("sample_index", ty.u32(), ast::StorageClass::kInput, nullptr,
ast::DecorationList{
Builtin(ast::Builtin::kSampleIndex),
});
spirv::Builder& b = Build();
EXPECT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
EXPECT_EQ(DumpInstructions(b.capabilities()),
"OpCapability SampleRateShading\n");
EXPECT_EQ(DumpInstructions(b.annots()), "OpDecorate %1 BuiltIn SampleId\n");
EXPECT_EQ(DumpInstructions(b.types()),
"%3 = OpTypeInt 32 0\n"
"%2 = OpTypePointer Input %3\n"
"%1 = OpVariable %2 Input\n");
}
TEST_F(BuilderTest, SampleMask) {
// Input:
// [[builtin(sample_mask)]] var<in> mask_in : u32;
// [[builtin(sample_mask)]] var<out> mask_out : u32;
// [[stage(fragment)]]
// fn main() {
// mask_out = mask_in;
// }
// After sanitization:
// [[builtin(sample_mask)]] var<in> mask_in : array<u32, 1>;
// [[builtin(sample_mask)]] var<out> mask_out : array<u32, 1>;
// [[stage(fragment)]]
// fn main() {
// mask_out[0] = mask_in[0];
// }
Global("mask_in", ty.u32(), ast::StorageClass::kInput, nullptr,
ast::DecorationList{
Builtin(ast::Builtin::kSampleMask),
});
Global("mask_out", ty.u32(), ast::StorageClass::kOutput, nullptr,
ast::DecorationList{
Builtin(ast::Builtin::kSampleMask),
});
Func("main", ast::VariableList{}, ty.void_(),
ast::StatementList{
Assign("mask_out", "mask_in"),
},
ast::DecorationList{
Stage(ast::PipelineStage::kCompute),
});
spirv::Builder& b = SanitizeAndBuild();
ASSERT_TRUE(b.Build());
EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %11 "main" %6 %1
OpExecutionMode %11 LocalSize 1 1 1
OpName %1 "mask_in"
OpName %6 "mask_out"
OpName %11 "main"
OpDecorate %3 ArrayStride 4
OpDecorate %1 BuiltIn SampleMask
OpDecorate %6 BuiltIn SampleMask
%4 = OpTypeInt 32 0
%5 = OpConstant %4 1
%3 = OpTypeArray %4 %5
%2 = OpTypePointer Input %3
%1 = OpVariable %2 Input
%7 = OpTypePointer Output %3
%8 = OpConstantNull %3
%6 = OpVariable %7 Output %8
%10 = OpTypeVoid
%9 = OpTypeFunction %10
%13 = OpTypeInt 32 1
%14 = OpConstant %13 0
%15 = OpTypePointer Output %4
%17 = OpTypePointer Input %4
%11 = OpFunction %10 None %9
%12 = OpLabel
%16 = OpAccessChain %15 %6 %14
%18 = OpAccessChain %17 %1 %14
%19 = OpLoad %4 %18
OpStore %16 %19
OpReturn
OpFunctionEnd
)");
}
} // namespace } // namespace
} // namespace spirv } // namespace spirv
} // namespace writer } // namespace writer

View File

@ -46,7 +46,7 @@ TEST_F(BuilderTest, IdentifierExpression_GlobalConst) {
} }
TEST_F(BuilderTest, IdentifierExpression_GlobalVar) { TEST_F(BuilderTest, IdentifierExpression_GlobalVar) {
auto* v = Global("var", ty.f32(), ast::StorageClass::kOutput); auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Expr("var"); auto* expr = Expr("var");
WrapInFunction(expr); WrapInFunction(expr);
@ -58,9 +58,9 @@ TEST_F(BuilderTest, IdentifierExpression_GlobalVar) {
EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var" EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
)"); )");
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32 EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
%2 = OpTypePointer Output %3 %2 = OpTypePointer Private %3
%4 = OpConstantNull %3 %4 = OpConstantNull %3
%1 = OpVariable %2 Output %4 %1 = OpVariable %2 Private %4
)"); )");
EXPECT_EQ(b.GenerateIdentifierExpression(expr), 1u); EXPECT_EQ(b.GenerateIdentifierExpression(expr), 1u);

View File

@ -70,7 +70,7 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) {
TEST_F(BuilderTest_Type, GenerateArray) { TEST_F(BuilderTest_Type, GenerateArray) {
auto* ary = ty.array(ty.i32(), 4); auto* ary = ty.array(ty.i32(), 4);
Global("a", ary, ast::StorageClass::kInput); Global("a", ary, ast::StorageClass::kPrivate);
spirv::Builder& b = Build(); spirv::Builder& b = Build();
@ -87,7 +87,7 @@ TEST_F(BuilderTest_Type, GenerateArray) {
TEST_F(BuilderTest_Type, GenerateArray_WithStride) { TEST_F(BuilderTest_Type, GenerateArray_WithStride) {
auto* ary = ty.array(ty.i32(), 4, 16u); auto* ary = ty.array(ty.i32(), 4, 16u);
Global("a", ary, ast::StorageClass::kInput); Global("a", ary, ast::StorageClass::kPrivate);
spirv::Builder& b = Build(); spirv::Builder& b = Build();
@ -107,7 +107,7 @@ TEST_F(BuilderTest_Type, GenerateArray_WithStride) {
TEST_F(BuilderTest_Type, ReturnsGeneratedArray) { TEST_F(BuilderTest_Type, ReturnsGeneratedArray) {
auto* ary = ty.array(ty.i32(), 4); auto* ary = ty.array(ty.i32(), 4);
Global("a", ary, ast::StorageClass::kInput); Global("a", ary, ast::StorageClass::kPrivate);
spirv::Builder& b = Build(); spirv::Builder& b = Build();

View File

@ -55,7 +55,7 @@ TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
}, },
ast::DecorationList{}); ast::DecorationList{});
Global("a1", ty.f32(), ast::StorageClass::kOutput); Global("a1", ty.f32(), ast::StorageClass::kPrivate);
auto* s1 = Structure("S1", {Member("a", ty.i32())}); auto* s1 = Structure("S1", {Member("a", ty.i32())});
@ -84,7 +84,7 @@ TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
return a0; return a0;
} }
var<out> a1 : f32; var<private> a1 : f32;
struct S1 { struct S1 {
a : i32; a : i32;

View File

@ -94,31 +94,20 @@ TEST_F(WgslGeneratorImplTest, EmitVariable_Access_ReadWrite) {
R"([[binding(0), group(0)]] var<storage, read_write> a : S; R"([[binding(0), group(0)]] var<storage, read_write> a : S;
)"); )");
} }
TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated) { TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated) {
auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate, nullptr, auto* v = Global("a", ty.sampler(ast::SamplerKind::kSampler),
ast::StorageClass::kNone, nullptr,
ast::DecorationList{ ast::DecorationList{
Location(2), create<ast::GroupDecoration>(1),
}); create<ast::BindingDecoration>(2),
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
EXPECT_EQ(gen.result(), R"([[location(2)]] var<private> a : f32;
)");
}
TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated_Multiple) {
auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate, nullptr,
ast::DecorationList{
Builtin(ast::Builtin::kPosition),
Location(2),
}); });
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error(); ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
EXPECT_EQ(gen.result(), EXPECT_EQ(gen.result(),
R"([[builtin(position), location(2)]] var<private> a : f32; R"([[group(1), binding(2)]] var a : sampler;
)"); )");
} }