Move storage_class validation from wgsl to resolver
We don't want the WGSL parser to have to maintain type lookups. If the WGSL language is updated to allow module-scope variables to be declared in any order, then the single-pass approach is going to fail horribly. Instead do the check in the Resovler. With this change, the AST nodes actually contain the correctly declared storage class. Fix up the SPIR-V reader to generate StorageClass::kNone for handle types. Fix all tests. Bug: tint:724 Change-Id: I102e30c9bbef32de40e123c2676ea9a281dee74d Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50306 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com> Reviewed-by: James Price <jrprice@google.com>
This commit is contained in:
parent
a34fa0ecb7
commit
fcda15ef67
|
@ -158,24 +158,23 @@ ast::Variable* TextureOverloadCase::buildTextureVariable(
|
||||||
return b->Global("texture",
|
return b->Global("texture",
|
||||||
b->ty.sampled_texture(texture_dimension,
|
b->ty.sampled_texture(texture_dimension,
|
||||||
buildResultVectorComponentType(b)),
|
buildResultVectorComponentType(b)),
|
||||||
ast::StorageClass::kUniformConstant, nullptr, decos);
|
ast::StorageClass::kNone, nullptr, decos);
|
||||||
|
|
||||||
case ast::intrinsic::test::TextureKind::kDepth:
|
case ast::intrinsic::test::TextureKind::kDepth:
|
||||||
return b->Global("texture", b->ty.depth_texture(texture_dimension),
|
return b->Global("texture", b->ty.depth_texture(texture_dimension),
|
||||||
ast::StorageClass::kUniformConstant, nullptr, decos);
|
ast::StorageClass::kNone, nullptr, decos);
|
||||||
|
|
||||||
case ast::intrinsic::test::TextureKind::kMultisampled:
|
case ast::intrinsic::test::TextureKind::kMultisampled:
|
||||||
return b->Global(
|
return b->Global(
|
||||||
"texture",
|
"texture",
|
||||||
b->ty.multisampled_texture(texture_dimension,
|
b->ty.multisampled_texture(texture_dimension,
|
||||||
buildResultVectorComponentType(b)),
|
buildResultVectorComponentType(b)),
|
||||||
ast::StorageClass::kUniformConstant, nullptr, decos);
|
ast::StorageClass::kNone, nullptr, decos);
|
||||||
|
|
||||||
case ast::intrinsic::test::TextureKind::kStorage: {
|
case ast::intrinsic::test::TextureKind::kStorage: {
|
||||||
auto st = b->ty.storage_texture(texture_dimension, image_format);
|
auto st = b->ty.storage_texture(texture_dimension, image_format);
|
||||||
auto ac = b->ty.access(access_control, st);
|
auto ac = b->ty.access(access_control, st);
|
||||||
return b->Global("texture", ac, ast::StorageClass::kUniformConstant,
|
return b->Global("texture", ac, ast::StorageClass::kNone, nullptr, decos);
|
||||||
nullptr, decos);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +189,7 @@ ast::Variable* TextureOverloadCase::buildSamplerVariable(
|
||||||
b->create<ast::BindingDecoration>(1),
|
b->create<ast::BindingDecoration>(1),
|
||||||
};
|
};
|
||||||
return b->Global("sampler", b->ty.sampler(sampler_kind),
|
return b->Global("sampler", b->ty.sampler(sampler_kind),
|
||||||
ast::StorageClass::kUniformConstant, nullptr, decos);
|
ast::StorageClass::kNone, nullptr, decos);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<TextureOverloadCase> TextureOverloadCase::ValidCases() {
|
std::vector<TextureOverloadCase> TextureOverloadCase::ValidCases() {
|
||||||
|
|
|
@ -19,6 +19,10 @@ namespace ast {
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& out, StorageClass sc) {
|
std::ostream& operator<<(std::ostream& out, StorageClass sc) {
|
||||||
switch (sc) {
|
switch (sc) {
|
||||||
|
case StorageClass::kInvalid: {
|
||||||
|
out << "invalid";
|
||||||
|
break;
|
||||||
|
}
|
||||||
case StorageClass::kNone: {
|
case StorageClass::kNone: {
|
||||||
out << "none";
|
out << "none";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -22,7 +22,8 @@ namespace ast {
|
||||||
|
|
||||||
/// Storage class of a given pointer.
|
/// Storage class of a given pointer.
|
||||||
enum class StorageClass {
|
enum class StorageClass {
|
||||||
kNone = -1,
|
kInvalid = -1,
|
||||||
|
kNone,
|
||||||
kInput,
|
kInput,
|
||||||
kOutput,
|
kOutput,
|
||||||
kUniform,
|
kUniform,
|
||||||
|
|
|
@ -316,8 +316,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
/// @param group the binding/group to use for the storage buffer
|
/// @param group the binding/group to use for the storage buffer
|
||||||
/// @param binding the binding number to use for the storage buffer
|
/// @param binding the binding number to use for the storage buffer
|
||||||
void AddSampler(const std::string& name, uint32_t group, uint32_t binding) {
|
void AddSampler(const std::string& name, uint32_t group, uint32_t binding) {
|
||||||
AddBinding(name, sampler_type(), ast::StorageClass::kUniformConstant, group,
|
AddBinding(name, sampler_type(), ast::StorageClass::kNone, group, binding);
|
||||||
binding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a comparison sampler variable to the program
|
/// Adds a comparison sampler variable to the program
|
||||||
|
@ -327,8 +326,8 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
void AddComparisonSampler(const std::string& name,
|
void AddComparisonSampler(const std::string& name,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
AddBinding(name, comparison_sampler_type(),
|
AddBinding(name, comparison_sampler_type(), ast::StorageClass::kNone, group,
|
||||||
ast::StorageClass::kUniformConstant, group, binding);
|
binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a SampledTexture appropriate for the params
|
/// Generates a SampledTexture appropriate for the params
|
||||||
|
@ -366,7 +365,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
ast::Type* type,
|
ast::Type* type,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
|
AddBinding(name, type, ast::StorageClass::kNone, group, binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a multi-sampled texture variable to the program
|
/// Adds a multi-sampled texture variable to the program
|
||||||
|
@ -378,7 +377,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
ast::Type* type,
|
ast::Type* type,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
|
AddBinding(name, type, ast::StorageClass::kNone, group, binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddGlobalVariable(const std::string& name, ast::Type* type) {
|
void AddGlobalVariable(const std::string& name, ast::Type* type) {
|
||||||
|
@ -394,7 +393,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
ast::Type* type,
|
ast::Type* type,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
|
AddBinding(name, type, ast::StorageClass::kNone, group, binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a function that references a specific sampler variable
|
/// Generates a function that references a specific sampler variable
|
||||||
|
@ -566,7 +565,7 @@ class InspectorHelper : public ProgramBuilder {
|
||||||
typ::Type type,
|
typ::Type type,
|
||||||
uint32_t group,
|
uint32_t group,
|
||||||
uint32_t binding) {
|
uint32_t binding) {
|
||||||
AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding);
|
AddBinding(name, type, ast::StorageClass::kNone, group, binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a function that references a storage texture variable.
|
/// Generates a function that references a storage texture variable.
|
||||||
|
|
|
@ -49,7 +49,7 @@ ast::StorageClass EnumConverter::ToStorageClass(const SpvStorageClass sc) {
|
||||||
case SpvStorageClassWorkgroup:
|
case SpvStorageClassWorkgroup:
|
||||||
return ast::StorageClass::kWorkgroup;
|
return ast::StorageClass::kWorkgroup;
|
||||||
case SpvStorageClassUniformConstant:
|
case SpvStorageClassUniformConstant:
|
||||||
return ast::StorageClass::kUniformConstant;
|
return ast::StorageClass::kNone;
|
||||||
case SpvStorageClassStorageBuffer:
|
case SpvStorageClassStorageBuffer:
|
||||||
return ast::StorageClass::kStorage;
|
return ast::StorageClass::kStorage;
|
||||||
case SpvStorageClassImage:
|
case SpvStorageClassImage:
|
||||||
|
@ -63,7 +63,7 @@ ast::StorageClass EnumConverter::ToStorageClass(const SpvStorageClass sc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Fail() << "unknown SPIR-V storage class: " << uint32_t(sc);
|
Fail() << "unknown SPIR-V storage class: " << uint32_t(sc);
|
||||||
return ast::StorageClass::kNone;
|
return ast::StorageClass::kInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::Builtin EnumConverter::ToBuiltin(SpvBuiltIn b) {
|
ast::Builtin EnumConverter::ToBuiltin(SpvBuiltIn b) {
|
||||||
|
|
|
@ -143,7 +143,7 @@ INSTANTIATE_TEST_SUITE_P(
|
||||||
StorageClassCase{SpvStorageClassWorkgroup, true,
|
StorageClassCase{SpvStorageClassWorkgroup, true,
|
||||||
ast::StorageClass::kWorkgroup},
|
ast::StorageClass::kWorkgroup},
|
||||||
StorageClassCase{SpvStorageClassUniformConstant, true,
|
StorageClassCase{SpvStorageClassUniformConstant, true,
|
||||||
ast::StorageClass::kUniformConstant},
|
ast::StorageClass::kNone},
|
||||||
StorageClassCase{SpvStorageClassStorageBuffer, true,
|
StorageClassCase{SpvStorageClassStorageBuffer, true,
|
||||||
ast::StorageClass::kStorage},
|
ast::StorageClass::kStorage},
|
||||||
StorageClassCase{SpvStorageClassImage, true, ast::StorageClass::kImage},
|
StorageClassCase{SpvStorageClassImage, true, ast::StorageClass::kImage},
|
||||||
|
@ -156,7 +156,7 @@ INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
|
||||||
SpvStorageClassTest,
|
SpvStorageClassTest,
|
||||||
testing::Values(StorageClassCase{
|
testing::Values(StorageClassCase{
|
||||||
static_cast<SpvStorageClass>(9999), false,
|
static_cast<SpvStorageClass>(9999), false,
|
||||||
ast::StorageClass::kNone}));
|
ast::StorageClass::kInvalid}));
|
||||||
|
|
||||||
// Builtin
|
// Builtin
|
||||||
|
|
||||||
|
|
|
@ -4005,11 +4005,13 @@ bool FunctionEmitter::RegisterLocallyDefinedValues() {
|
||||||
<< "pointer defined in function from unknown opcode: "
|
<< "pointer defined in function from unknown opcode: "
|
||||||
<< inst.PrettyPrint();
|
<< inst.PrettyPrint();
|
||||||
}
|
}
|
||||||
if (info->storage_class == ast::StorageClass::kUniformConstant) {
|
|
||||||
info->skip = SkipReason::kOpaqueObject;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (type->AsSampler() || type->AsImage() || type->AsSampledImage()) {
|
auto* unwrapped = type;
|
||||||
|
while (auto* ptr = unwrapped->AsPointer()) {
|
||||||
|
unwrapped = ptr->pointee_type();
|
||||||
|
}
|
||||||
|
if (unwrapped->AsSampler() || unwrapped->AsImage() ||
|
||||||
|
unwrapped->AsSampledImage()) {
|
||||||
// Defer code generation until the instruction that actually acts on
|
// Defer code generation until the instruction that actually acts on
|
||||||
// the image.
|
// the image.
|
||||||
info->skip = SkipReason::kOpaqueObject;
|
info->skip = SkipReason::kOpaqueObject;
|
||||||
|
@ -4032,7 +4034,7 @@ ast::StorageClass FunctionEmitter::GetStorageClassForPointerValue(uint32_t id) {
|
||||||
return ptr->storage_class;
|
return ptr->storage_class;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ast::StorageClass::kNone;
|
return ast::StorageClass::kInvalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type* FunctionEmitter::RemapStorageClass(const Type* type,
|
const Type* FunctionEmitter::RemapStorageClass(const Type* type,
|
||||||
|
|
|
@ -1060,7 +1060,7 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ast_storage_class = enum_converter_.ToStorageClass(storage_class);
|
auto ast_storage_class = enum_converter_.ToStorageClass(storage_class);
|
||||||
if (ast_storage_class == ast::StorageClass::kNone) {
|
if (ast_storage_class == ast::StorageClass::kInvalid) {
|
||||||
Fail() << "SPIR-V pointer type with ID " << type_id
|
Fail() << "SPIR-V pointer type with ID " << type_id
|
||||||
<< " has invalid storage class "
|
<< " has invalid storage class "
|
||||||
<< static_cast<uint32_t>(storage_class);
|
<< static_cast<uint32_t>(storage_class);
|
||||||
|
@ -1236,6 +1236,7 @@ bool ParserImpl::EmitModuleScopeVariables() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (enum_converter_.ToStorageClass(spirv_storage_class)) {
|
switch (enum_converter_.ToStorageClass(spirv_storage_class)) {
|
||||||
|
case ast::StorageClass::kNone:
|
||||||
case ast::StorageClass::kInput:
|
case ast::StorageClass::kInput:
|
||||||
case ast::StorageClass::kOutput:
|
case ast::StorageClass::kOutput:
|
||||||
case ast::StorageClass::kUniform:
|
case ast::StorageClass::kUniform:
|
||||||
|
|
|
@ -692,7 +692,7 @@ TEST_F(SpvParserTest, ConvertType_PointerUniformConstant) {
|
||||||
auto* ptr_ty = type->As<Pointer>();
|
auto* ptr_ty = type->As<Pointer>();
|
||||||
EXPECT_NE(ptr_ty, nullptr);
|
EXPECT_NE(ptr_ty, nullptr);
|
||||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kUniformConstant);
|
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kNone);
|
||||||
EXPECT_TRUE(p->error().empty());
|
EXPECT_TRUE(p->error().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -564,17 +564,6 @@ Maybe<ParserImpl::VarDeclInfo> ParserImpl::variable_decl() {
|
||||||
if (decl.errored)
|
if (decl.errored)
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
|
|
||||||
if (decl->type && decl->type->UnwrapAll()->is_handle()) {
|
|
||||||
// handle types implicitly have the `UniformConstant` storage class.
|
|
||||||
if (explicit_sc.matched) {
|
|
||||||
return add_error(
|
|
||||||
explicit_sc.source,
|
|
||||||
decl->type->UnwrapAll()->FriendlyName(builder_.Symbols()) +
|
|
||||||
" variables must not have a storage class");
|
|
||||||
}
|
|
||||||
sc = ast::StorageClass::kUniformConstant;
|
|
||||||
}
|
|
||||||
|
|
||||||
return VarDeclInfo{decl->source, decl->name, sc, decl->type};
|
return VarDeclInfo{decl->source, decl->name, sc, decl->type};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1102,22 +1102,6 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarVectorMissingType) {
|
||||||
" ^\n");
|
" ^\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclSamplerExplicitStorageClass) {
|
|
||||||
EXPECT(
|
|
||||||
"var<uniform> x : sampler;",
|
|
||||||
"test.wgsl:1:5 error: sampler variables must not have a storage class\n"
|
|
||||||
"var<uniform> x : sampler;\n"
|
|
||||||
" ^^^^^^^\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, GlobalDeclTextureExplicitStorageClass) {
|
|
||||||
EXPECT("var<uniform> x : [[access(read)]] texture_1d<f32>;",
|
|
||||||
"test.wgsl:1:5 error: texture_1d<f32> variables must not have a "
|
|
||||||
"storage class\n"
|
|
||||||
"var<uniform> x : [[access(read)]] texture_1d<f32>;\n"
|
|
||||||
" ^^^^^^^\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, IfStmtMissingLParen) {
|
TEST_F(ParserImplErrorTest, IfStmtMissingLParen) {
|
||||||
EXPECT("fn f() { if true) {} }",
|
EXPECT("fn f() { if true) {} }",
|
||||||
"test.wgsl:1:13 error: expected '('\n"
|
"test.wgsl:1:13 error: expected '('\n"
|
||||||
|
|
|
@ -168,38 +168,6 @@ TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) {
|
||||||
EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration");
|
EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalVariableDecl_SamplerImplicitStorageClass) {
|
|
||||||
auto p = parser("var s : sampler;");
|
|
||||||
auto decos = p->decoration_list();
|
|
||||||
EXPECT_FALSE(decos.errored);
|
|
||||||
EXPECT_FALSE(decos.matched);
|
|
||||||
auto e = p->global_variable_decl(decos.value);
|
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
|
||||||
EXPECT_FALSE(e.errored);
|
|
||||||
EXPECT_TRUE(e.matched);
|
|
||||||
ASSERT_NE(e.value, nullptr);
|
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("s"));
|
|
||||||
EXPECT_TRUE(e->type()->Is<ast::Sampler>());
|
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniformConstant);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalVariableDecl_TextureImplicitStorageClass) {
|
|
||||||
auto p = parser("var s : [[access(read)]] texture_1d<f32>;");
|
|
||||||
auto decos = p->decoration_list();
|
|
||||||
EXPECT_FALSE(decos.errored);
|
|
||||||
EXPECT_FALSE(decos.matched);
|
|
||||||
auto e = p->global_variable_decl(decos.value);
|
|
||||||
ASSERT_FALSE(p->has_error()) << p->error();
|
|
||||||
EXPECT_FALSE(e.errored);
|
|
||||||
EXPECT_TRUE(e.matched);
|
|
||||||
ASSERT_NE(e.value, nullptr);
|
|
||||||
|
|
||||||
EXPECT_EQ(e->symbol(), p->builder().Symbols().Get("s"));
|
|
||||||
EXPECT_TRUE(e->type()->UnwrapAll()->Is<ast::Texture>());
|
|
||||||
EXPECT_EQ(e->declared_storage_class(), ast::StorageClass::kUniformConstant);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ParserImplTest, GlobalVariableDecl_StorageClassIn_Deprecated) {
|
TEST_F(ParserImplTest, GlobalVariableDecl_StorageClassIn_Deprecated) {
|
||||||
auto p = parser("[[location(0)]] var<in> a : f32");
|
auto p = parser("[[location(0)]] var<in> a : f32");
|
||||||
auto f = p->function_header();
|
auto f = p->function_header();
|
||||||
|
|
|
@ -244,19 +244,15 @@ TEST_F(ResolverAssignmentValidationTest, AssignFromPointer_Fail) {
|
||||||
return ty.access(ast::AccessControl::kReadOnly, tex_type);
|
return ty.access(ast::AccessControl::kReadOnly, tex_type);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto* var_a = Var("a", make_type(), ast::StorageClass::kFunction);
|
auto* var_a = Global("a", make_type(), ast::StorageClass::kNone);
|
||||||
auto* var_b = Var("b", make_type(), ast::StorageClass::kFunction);
|
auto* var_b = Global("b", make_type(), ast::StorageClass::kNone);
|
||||||
|
|
||||||
auto* lhs = Expr("a");
|
WrapInFunction(Assign(Source{{12, 34}}, var_a, var_b));
|
||||||
auto* rhs = Expr("b");
|
|
||||||
|
|
||||||
auto* assign = Assign(Source{{12, 34}}, lhs, rhs);
|
|
||||||
WrapInFunction(Decl(var_a), Decl(var_b), assign);
|
|
||||||
|
|
||||||
EXPECT_FALSE(r()->Resolve());
|
EXPECT_FALSE(r()->Resolve());
|
||||||
EXPECT_EQ(r()->error(),
|
EXPECT_EQ(r()->error(),
|
||||||
"12:34 error v-000x: invalid assignment: right-hand-side is not "
|
"12:34 error v-000x: invalid assignment: right-hand-side is not "
|
||||||
"storable: ptr<function, [[access(read)]] "
|
"storable: ptr<uniform_constant, [[access(read)]] "
|
||||||
"texture_storage_1d<rgba8unorm>>");
|
"texture_storage_1d<rgba8unorm>>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -243,7 +243,10 @@ class ResolverIntrinsicTest_TextureOperation
|
||||||
void add_call_param(std::string name,
|
void add_call_param(std::string name,
|
||||||
typ::Type type,
|
typ::Type type,
|
||||||
ast::ExpressionList* call_params) {
|
ast::ExpressionList* call_params) {
|
||||||
Global(name, type, ast::StorageClass::kInput);
|
ast::StorageClass storage_class = type->UnwrapAll()->is_handle()
|
||||||
|
? ast::StorageClass::kNone
|
||||||
|
: ast::StorageClass::kPrivate;
|
||||||
|
Global(name, type, storage_class);
|
||||||
call_params->push_back(Expr(name));
|
call_params->push_back(Expr(name));
|
||||||
}
|
}
|
||||||
typ::Type subtype(Texture type) {
|
typ::Type subtype(Texture type) {
|
||||||
|
|
|
@ -500,7 +500,7 @@ bool Resolver::GlobalVariable(ast::Variable* var) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ApplyStorageClassUsageToType(var->declared_storage_class(), info->type,
|
if (!ApplyStorageClassUsageToType(info->storage_class, info->type,
|
||||||
var->source())) {
|
var->source())) {
|
||||||
diagnostics_.add_note("while instantiating variable " +
|
diagnostics_.add_note("while instantiating variable " +
|
||||||
builder_->Symbols().NameFor(var->symbol()),
|
builder_->Symbols().NameFor(var->symbol()),
|
||||||
|
@ -577,11 +577,12 @@ bool Resolver::ValidateGlobalVariable(const VariableInfo* info) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ValidateVariable(info->declaration);
|
return ValidateVariable(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::ValidateVariable(const ast::Variable* var) {
|
bool Resolver::ValidateVariable(const VariableInfo* info) {
|
||||||
auto* type = variable_to_info_[var]->type;
|
auto* var = info->declaration;
|
||||||
|
auto* type = info->type;
|
||||||
if (auto* r = type->As<sem::Array>()) {
|
if (auto* r = type->As<sem::Array>()) {
|
||||||
if (r->IsRuntimeSized()) {
|
if (r->IsRuntimeSized()) {
|
||||||
diagnostics_.add_error(
|
diagnostics_.add_error(
|
||||||
|
@ -643,11 +644,23 @@ bool Resolver::ValidateVariable(const ast::Variable* var) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type->UnwrapAll()->is_handle() &&
|
||||||
|
var->declared_storage_class() != ast::StorageClass::kNone) {
|
||||||
|
// https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
|
||||||
|
// If the store type is a texture type or a sampler type, then the variable
|
||||||
|
// declaration must not have a storage class decoration. The storage class
|
||||||
|
// will always be handle.
|
||||||
|
diagnostics_.add_error("variables of type '" + info->type_name +
|
||||||
|
"' must not have a storage class",
|
||||||
|
var->source());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::ValidateParameter(const ast::Variable* param) {
|
bool Resolver::ValidateParameter(const VariableInfo* info) {
|
||||||
return ValidateVariable(param);
|
return ValidateVariable(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resolver::ValidateFunction(const ast::Function* func,
|
bool Resolver::ValidateFunction(const ast::Function* func,
|
||||||
|
@ -662,7 +675,7 @@ bool Resolver::ValidateFunction(const ast::Function* func,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* param : func->params()) {
|
for (auto* param : func->params()) {
|
||||||
if (!ValidateParameter(param)) {
|
if (!ValidateParameter(variable_to_info_.at(param))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2060,7 +2073,7 @@ bool Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
|
||||||
variable_stack_.set(var->symbol(), info);
|
variable_stack_.set(var->symbol(), info);
|
||||||
current_block_->decls.push_back(var);
|
current_block_->decls.push_back(var);
|
||||||
|
|
||||||
if (!ValidateVariable(var)) {
|
if (!ValidateVariable(info)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2833,7 +2846,16 @@ Resolver::VariableInfo::VariableInfo(const ast::Variable* decl,
|
||||||
: declaration(decl),
|
: declaration(decl),
|
||||||
type(ctype),
|
type(ctype),
|
||||||
type_name(tn),
|
type_name(tn),
|
||||||
storage_class(decl->declared_storage_class()) {}
|
storage_class(decl->declared_storage_class()) {
|
||||||
|
if (storage_class == ast::StorageClass::kNone &&
|
||||||
|
type->UnwrapAll()->is_handle()) {
|
||||||
|
// https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
|
||||||
|
// If the store type is a texture type or a sampler type, then the variable
|
||||||
|
// declaration must not have a storage class decoration. The storage class
|
||||||
|
// will always be handle.
|
||||||
|
storage_class = ast::StorageClass::kUniformConstant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Resolver::VariableInfo::~VariableInfo() = default;
|
Resolver::VariableInfo::~VariableInfo() = default;
|
||||||
|
|
||||||
|
|
|
@ -230,11 +230,11 @@ class Resolver {
|
||||||
bool ValidateGlobalVariable(const VariableInfo* var);
|
bool ValidateGlobalVariable(const VariableInfo* var);
|
||||||
bool ValidateMatrixConstructor(const ast::TypeConstructorExpression* ctor,
|
bool ValidateMatrixConstructor(const ast::TypeConstructorExpression* ctor,
|
||||||
const sem::Matrix* matrix_type);
|
const sem::Matrix* matrix_type);
|
||||||
bool ValidateParameter(const ast::Variable* param);
|
bool ValidateParameter(const VariableInfo* info);
|
||||||
bool ValidateReturn(const ast::ReturnStatement* ret);
|
bool ValidateReturn(const ast::ReturnStatement* ret);
|
||||||
bool ValidateStructure(const sem::Struct* str);
|
bool ValidateStructure(const sem::Struct* str);
|
||||||
bool ValidateSwitch(const ast::SwitchStatement* s);
|
bool ValidateSwitch(const ast::SwitchStatement* s);
|
||||||
bool ValidateVariable(const ast::Variable* param);
|
bool ValidateVariable(const VariableInfo* info);
|
||||||
bool ValidateVectorConstructor(const ast::TypeConstructorExpression* ctor,
|
bool ValidateVectorConstructor(const ast::TypeConstructorExpression* ctor,
|
||||||
const sem::Vector* vec_type);
|
const sem::Vector* vec_type);
|
||||||
|
|
||||||
|
|
|
@ -1458,6 +1458,27 @@ TEST_F(ResolverTest, StorageClass_SetsIfMissing) {
|
||||||
EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kFunction);
|
EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, StorageClass_SetForSampler) {
|
||||||
|
auto t = ty.sampler(ast::SamplerKind::kSampler);
|
||||||
|
auto* var = Global("var", t, ast::StorageClass::kNone);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
EXPECT_EQ(Sem().Get(var)->StorageClass(),
|
||||||
|
ast::StorageClass::kUniformConstant);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, StorageClass_SetForTexture) {
|
||||||
|
auto t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
|
||||||
|
auto ac = ty.access(ast::AccessControl::Access::kReadOnly, t);
|
||||||
|
auto* var = Global("var", ac, ast::StorageClass::kNone);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
EXPECT_EQ(Sem().Get(var)->StorageClass(),
|
||||||
|
ast::StorageClass::kUniformConstant);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ResolverTest, StorageClass_DoesNotSetOnConst) {
|
TEST_F(ResolverTest, StorageClass_DoesNotSetOnConst) {
|
||||||
auto* var = Const("var", ty.i32(), Construct(ty.i32()));
|
auto* var = Const("var", ty.i32(), Construct(ty.i32()));
|
||||||
auto* stmt = Decl(var);
|
auto* stmt = Decl(var);
|
||||||
|
|
|
@ -551,7 +551,7 @@ using MultisampledTextureDimensionTest = ResolverTestWithParam<DimensionParams>;
|
||||||
TEST_P(MultisampledTextureDimensionTest, All) {
|
TEST_P(MultisampledTextureDimensionTest, All) {
|
||||||
auto& params = GetParam();
|
auto& params = GetParam();
|
||||||
Global("a", ty.multisampled_texture(params.dim, ty.i32()),
|
Global("a", ty.multisampled_texture(params.dim, ty.i32()),
|
||||||
ast::StorageClass::kUniformConstant, nullptr,
|
ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(0),
|
create<ast::BindingDecoration>(0),
|
||||||
create<ast::GroupDecoration>(0),
|
create<ast::GroupDecoration>(0),
|
||||||
|
@ -595,7 +595,7 @@ TEST_P(MultisampledTextureTypeTest, All) {
|
||||||
Global(
|
Global(
|
||||||
"a",
|
"a",
|
||||||
ty.multisampled_texture(ast::TextureDimension::k2d, params.type_func(ty)),
|
ty.multisampled_texture(ast::TextureDimension::k2d, params.type_func(ty)),
|
||||||
ast::StorageClass::kUniformConstant, nullptr,
|
ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(0),
|
create<ast::BindingDecoration>(0),
|
||||||
create<ast::GroupDecoration>(0),
|
create<ast::GroupDecoration>(0),
|
||||||
|
@ -636,7 +636,7 @@ TEST_P(StorageTextureDimensionTest, All) {
|
||||||
auto st = ty.storage_texture(params.dim, ast::ImageFormat::kR32Uint);
|
auto st = ty.storage_texture(params.dim, ast::ImageFormat::kR32Uint);
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, st);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, st);
|
||||||
|
|
||||||
Global("a", ac, ast::StorageClass::kUniformConstant, nullptr,
|
Global("a", ac, ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(0),
|
create<ast::BindingDecoration>(0),
|
||||||
create<ast::GroupDecoration>(0),
|
create<ast::GroupDecoration>(0),
|
||||||
|
@ -708,7 +708,7 @@ TEST_P(StorageTextureFormatTest, All) {
|
||||||
|
|
||||||
auto st_a = ty.storage_texture(ast::TextureDimension::k1d, params.format);
|
auto st_a = ty.storage_texture(ast::TextureDimension::k1d, params.format);
|
||||||
auto ac_a = ty.access(ast::AccessControl::kReadOnly, st_a);
|
auto ac_a = ty.access(ast::AccessControl::kReadOnly, st_a);
|
||||||
Global("a", ac_a, ast::StorageClass::kUniformConstant, nullptr,
|
Global("a", ac_a, ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(0),
|
create<ast::BindingDecoration>(0),
|
||||||
create<ast::GroupDecoration>(0),
|
create<ast::GroupDecoration>(0),
|
||||||
|
@ -716,7 +716,7 @@ TEST_P(StorageTextureFormatTest, All) {
|
||||||
|
|
||||||
auto st_b = ty.storage_texture(ast::TextureDimension::k2d, params.format);
|
auto st_b = ty.storage_texture(ast::TextureDimension::k2d, params.format);
|
||||||
auto ac_b = ty.access(ast::AccessControl::kReadOnly, st_b);
|
auto ac_b = ty.access(ast::AccessControl::kReadOnly, st_b);
|
||||||
Global("b", ac_b, ast::StorageClass::kUniformConstant, nullptr,
|
Global("b", ac_b, ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(0),
|
create<ast::BindingDecoration>(0),
|
||||||
create<ast::GroupDecoration>(1),
|
create<ast::GroupDecoration>(1),
|
||||||
|
@ -725,7 +725,7 @@ TEST_P(StorageTextureFormatTest, All) {
|
||||||
auto st_c =
|
auto st_c =
|
||||||
ty.storage_texture(ast::TextureDimension::k2dArray, params.format);
|
ty.storage_texture(ast::TextureDimension::k2dArray, params.format);
|
||||||
auto ac_c = ty.access(ast::AccessControl::kReadOnly, st_c);
|
auto ac_c = ty.access(ast::AccessControl::kReadOnly, st_c);
|
||||||
Global("c", ac_c, ast::StorageClass::kUniformConstant, nullptr,
|
Global("c", ac_c, ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(0),
|
create<ast::BindingDecoration>(0),
|
||||||
create<ast::GroupDecoration>(2),
|
create<ast::GroupDecoration>(2),
|
||||||
|
@ -733,7 +733,7 @@ TEST_P(StorageTextureFormatTest, All) {
|
||||||
|
|
||||||
auto st_d = ty.storage_texture(ast::TextureDimension::k3d, params.format);
|
auto st_d = ty.storage_texture(ast::TextureDimension::k3d, params.format);
|
||||||
auto ac_d = ty.access(ast::AccessControl::kReadOnly, st_d);
|
auto ac_d = ty.access(ast::AccessControl::kReadOnly, st_d);
|
||||||
Global("d", ac_d, ast::StorageClass::kUniformConstant, nullptr,
|
Global("d", ac_d, ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(0),
|
create<ast::BindingDecoration>(0),
|
||||||
create<ast::GroupDecoration>(3),
|
create<ast::GroupDecoration>(3),
|
||||||
|
@ -758,7 +758,7 @@ TEST_F(StorageTextureAccessControlTest, MissingAccessControl_Fail) {
|
||||||
auto st = ty.storage_texture(ast::TextureDimension::k1d,
|
auto st = ty.storage_texture(ast::TextureDimension::k1d,
|
||||||
ast::ImageFormat::kR32Uint);
|
ast::ImageFormat::kR32Uint);
|
||||||
|
|
||||||
Global("a", st, ast::StorageClass::kUniformConstant, nullptr,
|
Global("a", st, ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(0),
|
create<ast::BindingDecoration>(0),
|
||||||
create<ast::GroupDecoration>(0),
|
create<ast::GroupDecoration>(0),
|
||||||
|
@ -775,7 +775,7 @@ TEST_F(StorageTextureAccessControlTest, RWAccessControl_Fail) {
|
||||||
ast::ImageFormat::kR32Uint);
|
ast::ImageFormat::kR32Uint);
|
||||||
auto ac = ty.access(ast::AccessControl::kReadWrite, st);
|
auto ac = ty.access(ast::AccessControl::kReadWrite, st);
|
||||||
|
|
||||||
Global("a", ac, ast::StorageClass::kUniformConstant, nullptr,
|
Global("a", ac, ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(0),
|
create<ast::BindingDecoration>(0),
|
||||||
create<ast::GroupDecoration>(0),
|
create<ast::GroupDecoration>(0),
|
||||||
|
@ -792,7 +792,7 @@ TEST_F(StorageTextureAccessControlTest, ReadOnlyAccessControl_Pass) {
|
||||||
ast::ImageFormat::kR32Uint);
|
ast::ImageFormat::kR32Uint);
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, st);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, st);
|
||||||
|
|
||||||
Global("a", ac, ast::StorageClass::kUniformConstant, nullptr,
|
Global("a", ac, ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(0),
|
create<ast::BindingDecoration>(0),
|
||||||
create<ast::GroupDecoration>(0),
|
create<ast::GroupDecoration>(0),
|
||||||
|
@ -809,7 +809,7 @@ TEST_F(StorageTextureAccessControlTest, WriteOnlyAccessControl_Pass) {
|
||||||
ast::ImageFormat::kR32Uint);
|
ast::ImageFormat::kR32Uint);
|
||||||
auto ac = ty.access(ast::AccessControl::kWriteOnly, st);
|
auto ac = ty.access(ast::AccessControl::kWriteOnly, st);
|
||||||
|
|
||||||
Global("a", ac, ast::StorageClass::kUniformConstant, nullptr,
|
Global("a", ac, ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(0),
|
create<ast::BindingDecoration>(0),
|
||||||
create<ast::GroupDecoration>(0),
|
create<ast::GroupDecoration>(0),
|
||||||
|
|
|
@ -375,6 +375,28 @@ TEST_F(ResolverValidationTest, StorageClass_NonFunctionClassError) {
|
||||||
"error: function variable has a non-function storage class");
|
"error: function variable has a non-function storage class");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverValidationTest, StorageClass_SamplerExplicitStorageClass) {
|
||||||
|
auto t = ty.sampler(ast::SamplerKind::kSampler);
|
||||||
|
Global(Source{{12, 34}}, "var", t, ast::StorageClass::kUniformConstant);
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
r()->error(),
|
||||||
|
R"(12:34 error: variables of type 'sampler' must not have a storage class)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverValidationTest, StorageClass_TextureExplicitStorageClass) {
|
||||||
|
auto t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
|
||||||
|
Global(Source{{12, 34}}, "var", t, ast::StorageClass::kUniformConstant);
|
||||||
|
|
||||||
|
EXPECT_FALSE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
EXPECT_EQ(
|
||||||
|
r()->error(),
|
||||||
|
R"(12:34 error: variables of type 'texture_1d<f32>' must not have a storage class)");
|
||||||
|
}
|
||||||
|
|
||||||
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::kInput);
|
||||||
|
|
||||||
|
|
|
@ -335,7 +335,7 @@ TEST_P(HlslDepthTexturesTest, Emit) {
|
||||||
|
|
||||||
auto t = ty.depth_texture(params.dim);
|
auto t = ty.depth_texture(params.dim);
|
||||||
|
|
||||||
Global("tex", t, ast::StorageClass::kUniformConstant, nullptr,
|
Global("tex", t, ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(1),
|
create<ast::BindingDecoration>(1),
|
||||||
create<ast::GroupDecoration>(2),
|
create<ast::GroupDecoration>(2),
|
||||||
|
@ -394,7 +394,7 @@ TEST_P(HlslSampledTexturesTest, Emit) {
|
||||||
}
|
}
|
||||||
auto t = ty.sampled_texture(params.dim, datatype);
|
auto t = ty.sampled_texture(params.dim, datatype);
|
||||||
|
|
||||||
Global("tex", t, ast::StorageClass::kUniformConstant, nullptr,
|
Global("tex", t, ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(1),
|
create<ast::BindingDecoration>(1),
|
||||||
create<ast::GroupDecoration>(2),
|
create<ast::GroupDecoration>(2),
|
||||||
|
@ -536,7 +536,7 @@ TEST_P(HlslStorageTexturesTest, Emit) {
|
||||||
: ast::AccessControl::kWriteOnly,
|
: ast::AccessControl::kWriteOnly,
|
||||||
t);
|
t);
|
||||||
|
|
||||||
Global("tex", ac, ast::StorageClass::kUniformConstant, nullptr,
|
Global("tex", ac, ast::StorageClass::kNone, nullptr,
|
||||||
ast::DecorationList{
|
ast::DecorationList{
|
||||||
create<ast::BindingDecoration>(1),
|
create<ast::BindingDecoration>(1),
|
||||||
create<ast::GroupDecoration>(2),
|
create<ast::GroupDecoration>(2),
|
||||||
|
|
|
@ -745,7 +745,7 @@ TEST_P(MslStorageTexturesTest, Emit) {
|
||||||
auto ac = ty.access(params.ro ? ast::AccessControl::kReadOnly
|
auto ac = ty.access(params.ro ? ast::AccessControl::kReadOnly
|
||||||
: ast::AccessControl::kWriteOnly,
|
: ast::AccessControl::kWriteOnly,
|
||||||
s);
|
s);
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kNone);
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
|
|
|
@ -769,8 +769,8 @@ bool Builder::GenerateGlobalVariable(ast::Variable* var) {
|
||||||
if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
|
if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
|
||||||
push_annot(spv::Op::OpDecorate,
|
push_annot(spv::Op::OpDecorate,
|
||||||
{Operand::Int(var_id), Operand::Int(SpvDecorationBuiltIn),
|
{Operand::Int(var_id), Operand::Int(SpvDecorationBuiltIn),
|
||||||
Operand::Int(ConvertBuiltin(builtin->value(),
|
Operand::Int(
|
||||||
var->declared_storage_class()))});
|
ConvertBuiltin(builtin->value(), sem->StorageClass()))});
|
||||||
} else if (auto* location = deco->As<ast::LocationDecoration>()) {
|
} else if (auto* location = deco->As<ast::LocationDecoration>()) {
|
||||||
push_annot(spv::Op::OpDecorate,
|
push_annot(spv::Op::OpDecorate,
|
||||||
{Operand::Int(var_id), Operand::Int(SpvDecorationLocation),
|
{Operand::Int(var_id), Operand::Int(SpvDecorationLocation),
|
||||||
|
@ -3243,6 +3243,8 @@ bool Builder::GenerateVectorType(const sem::Vector* vec,
|
||||||
|
|
||||||
SpvStorageClass Builder::ConvertStorageClass(ast::StorageClass klass) const {
|
SpvStorageClass Builder::ConvertStorageClass(ast::StorageClass klass) const {
|
||||||
switch (klass) {
|
switch (klass) {
|
||||||
|
case ast::StorageClass::kInvalid:
|
||||||
|
return SpvStorageClassMax;
|
||||||
case ast::StorageClass::kInput:
|
case ast::StorageClass::kInput:
|
||||||
return SpvStorageClassInput;
|
return SpvStorageClassInput;
|
||||||
case ast::StorageClass::kOutput:
|
case ast::StorageClass::kOutput:
|
||||||
|
|
|
@ -526,7 +526,7 @@ TEST_F(BuilderTest, GlobalVar_TextureStorageReadOnly) {
|
||||||
|
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, type);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, type);
|
||||||
|
|
||||||
auto* var_a = Global("a", ac, ast::StorageClass::kUniformConstant);
|
auto* var_a = Global("a", ac, ast::StorageClass::kNone);
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
@ -549,7 +549,7 @@ TEST_F(BuilderTest, GlobalVar_TextureStorageWriteOnly) {
|
||||||
|
|
||||||
auto ac = ty.access(ast::AccessControl::kWriteOnly, type);
|
auto ac = ty.access(ast::AccessControl::kWriteOnly, type);
|
||||||
|
|
||||||
auto* var_a = Global("a", ac, ast::StorageClass::kUniformConstant);
|
auto* var_a = Global("a", ac, ast::StorageClass::kNone);
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
@ -573,12 +573,12 @@ TEST_F(BuilderTest, GlobalVar_TextureStorageWithDifferentAccess) {
|
||||||
auto type_a = ty.access(ast::AccessControl::kReadOnly,
|
auto type_a = ty.access(ast::AccessControl::kReadOnly,
|
||||||
ty.storage_texture(ast::TextureDimension::k2d,
|
ty.storage_texture(ast::TextureDimension::k2d,
|
||||||
ast::ImageFormat::kR32Uint));
|
ast::ImageFormat::kR32Uint));
|
||||||
auto* var_a = Global("a", type_a, ast::StorageClass::kUniformConstant);
|
auto* var_a = Global("a", type_a, ast::StorageClass::kNone);
|
||||||
|
|
||||||
auto type_b = ty.access(ast::AccessControl::kWriteOnly,
|
auto type_b = ty.access(ast::AccessControl::kWriteOnly,
|
||||||
ty.storage_texture(ast::TextureDimension::k2d,
|
ty.storage_texture(ast::TextureDimension::k2d,
|
||||||
ast::ImageFormat::kR32Uint));
|
ast::ImageFormat::kR32Uint));
|
||||||
auto* var_b = Global("b", type_b, ast::StorageClass::kUniformConstant);
|
auto* var_b = Global("b", type_b, ast::StorageClass::kNone);
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
|
|
@ -373,9 +373,9 @@ TEST_F(IntrinsicBuilderTest, Call_TextureSampleCompare_Twice) {
|
||||||
auto s = ty.sampler(ast::SamplerKind::kComparisonSampler);
|
auto s = ty.sampler(ast::SamplerKind::kComparisonSampler);
|
||||||
auto t = ty.depth_texture(ast::TextureDimension::k2d);
|
auto t = ty.depth_texture(ast::TextureDimension::k2d);
|
||||||
|
|
||||||
auto* tex = Global("texture", t, ast::StorageClass::kInput);
|
auto* tex = Global("texture", t, ast::StorageClass::kNone);
|
||||||
|
|
||||||
auto* sampler = Global("sampler", s, ast::StorageClass::kInput);
|
auto* sampler = Global("sampler", s, ast::StorageClass::kNone);
|
||||||
|
|
||||||
auto* expr1 = Call("textureSampleCompare", "texture", "sampler",
|
auto* expr1 = Call("textureSampleCompare", "texture", "sampler",
|
||||||
vec2<f32>(1.0f, 2.0f), 2.0f);
|
vec2<f32>(1.0f, 2.0f), 2.0f);
|
||||||
|
@ -397,11 +397,11 @@ TEST_F(IntrinsicBuilderTest, Call_TextureSampleCompare_Twice) {
|
||||||
|
|
||||||
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
|
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
|
||||||
%3 = OpTypeImage %4 2D 1 0 0 1 Unknown
|
%3 = OpTypeImage %4 2D 1 0 0 1 Unknown
|
||||||
%2 = OpTypePointer Input %3
|
%2 = OpTypePointer UniformConstant %3
|
||||||
%1 = OpVariable %2 Input
|
%1 = OpVariable %2 UniformConstant
|
||||||
%7 = OpTypeSampler
|
%7 = OpTypeSampler
|
||||||
%6 = OpTypePointer Input %7
|
%6 = OpTypePointer UniformConstant %7
|
||||||
%5 = OpVariable %6 Input
|
%5 = OpVariable %6 UniformConstant
|
||||||
%11 = OpTypeSampledImage %3
|
%11 = OpTypeSampledImage %3
|
||||||
%13 = OpTypeVector %4 2
|
%13 = OpTypeVector %4 2
|
||||||
%14 = OpConstant %4 1
|
%14 = OpConstant %4 1
|
||||||
|
|
|
@ -816,7 +816,7 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_1d) {
|
||||||
ast::ImageFormat::kR32Float);
|
ast::ImageFormat::kR32Float);
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kNone);
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
@ -832,7 +832,7 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_2d) {
|
||||||
ast::ImageFormat::kR32Float);
|
ast::ImageFormat::kR32Float);
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kNone);
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
@ -848,7 +848,7 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_2dArray) {
|
||||||
ast::ImageFormat::kR32Float);
|
ast::ImageFormat::kR32Float);
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kNone);
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
@ -864,7 +864,7 @@ TEST_F(BuilderTest_Type, StorageTexture_Generate_3d) {
|
||||||
ast::ImageFormat::kR32Float);
|
ast::ImageFormat::kR32Float);
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kNone);
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
@ -881,7 +881,7 @@ TEST_F(BuilderTest_Type,
|
||||||
ast::ImageFormat::kR32Float);
|
ast::ImageFormat::kR32Float);
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kNone);
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
@ -898,7 +898,7 @@ TEST_F(BuilderTest_Type,
|
||||||
ast::ImageFormat::kR32Sint);
|
ast::ImageFormat::kR32Sint);
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kNone);
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
@ -915,7 +915,7 @@ TEST_F(BuilderTest_Type,
|
||||||
ast::ImageFormat::kR32Uint);
|
ast::ImageFormat::kR32Uint);
|
||||||
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
auto ac = ty.access(ast::AccessControl::kReadOnly, s);
|
||||||
|
|
||||||
Global("test_var", ac, ast::StorageClass::kInput);
|
Global("test_var", ac, ast::StorageClass::kNone);
|
||||||
|
|
||||||
spirv::Builder& b = Build();
|
spirv::Builder& b = Build();
|
||||||
|
|
||||||
|
|
|
@ -101,8 +101,7 @@ TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WgslGeneratorImplTest, Emit_Global_Sampler) {
|
TEST_F(WgslGeneratorImplTest, Emit_Global_Sampler) {
|
||||||
Global("s", ty.sampler(ast::SamplerKind::kSampler),
|
Global("s", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone);
|
||||||
ast::StorageClass::kUniformConstant);
|
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
|
@ -115,7 +114,7 @@ TEST_F(WgslGeneratorImplTest, Emit_Global_Sampler) {
|
||||||
TEST_F(WgslGeneratorImplTest, Emit_Global_Texture) {
|
TEST_F(WgslGeneratorImplTest, Emit_Global_Texture) {
|
||||||
auto st = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
|
auto st = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
|
||||||
Global("t", ty.access(ast::AccessControl::kReadOnly, st),
|
Global("t", ty.access(ast::AccessControl::kReadOnly, st),
|
||||||
ast::StorageClass::kUniformConstant);
|
ast::StorageClass::kNone);
|
||||||
|
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue