spirv-reader: preserve NonWritable decoration on module-scope vars
Fixed: 348129253
Change-Id: Ic48e6c8e3b39ae82718ee59c2b024625deabc2f0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/194620
Commit-Queue: David Neto <dneto@google.com>
Commit-Queue: James Price <jrprice@google.com>
Auto-Submit: David Neto <dneto@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/spirv/reader/ast_parser/ast_parser.cc b/src/tint/lang/spirv/reader/ast_parser/ast_parser.cc
index efb14a2..8e486f5 100644
--- a/src/tint/lang/spirv/reader/ast_parser/ast_parser.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/ast_parser.cc
@@ -1534,14 +1534,14 @@
// here.)
ast_initializer = MakeConstantExpression(var.GetSingleWordInOperand(1)).expr;
}
- auto ast_access = VarAccess(ast_store_type, ast_address_space);
- auto* ast_var = MakeVar(var.result_id(), ast_address_space, ast_access, ast_store_type,
- ast_initializer, Attributes{});
+ auto* ast_var = MakeVar(var.result_id(), ast_address_space, ast_store_type, ast_initializer,
+ Attributes{});
// TODO(dneto): initializers (a.k.a. initializer expression)
if (ast_var) {
builder_.AST().AddGlobalVariable(ast_var);
module_variable_.GetOrAdd(var.result_id(), [&] {
- return ModuleVariable{ast_var, ast_address_space, ast_access};
+ auto access = VarAccess(var.result_id(), ast_store_type, ast_address_space);
+ return ModuleVariable{ast_var, ast_address_space, access};
});
}
}
@@ -1571,8 +1571,7 @@
}
auto storage_type = ConvertType(builtin_position_.position_member_type_id);
auto ast_address_space = enum_converter_.ToAddressSpace(builtin_position_.storage_class);
- auto ast_access = VarAccess(storage_type, ast_address_space);
- auto* ast_var = MakeVar(builtin_position_.per_vertex_var_id, ast_address_space, ast_access,
+ auto* ast_var = MakeVar(builtin_position_.per_vertex_var_id, ast_address_space,
storage_type, ast_initializer, {});
builder_.AST().AddGlobalVariable(ast_var);
@@ -1606,14 +1605,16 @@
return size->AsIntConstant();
}
-core::Access ASTParser::VarAccess(const Type* storage_type, core::AddressSpace address_space) {
+core::Access ASTParser::VarAccess(uint32_t var_id,
+ const Type* storage_type,
+ core::AddressSpace address_space) {
if (address_space != core::AddressSpace::kStorage) {
return core::Access::kUndefined;
}
- bool read_only = false;
+ bool read_only = read_only_vars_.count(var_id) > 0;
if (auto* tn = storage_type->As<Named>()) {
- read_only = read_only_struct_types_.count(tn->name) > 0;
+ read_only = read_only || read_only_struct_types_.count(tn->name) > 0;
}
// Apply the access(read) or access(read_write) modifier.
@@ -1622,7 +1623,6 @@
const ast::Var* ASTParser::MakeVar(uint32_t id,
core::AddressSpace address_space,
- core::Access access,
const Type* storage_type,
const ast::Expression* initializer,
Attributes attrs) {
@@ -1642,6 +1642,8 @@
return nullptr;
}
+ const auto access = VarAccess(id, storage_type, address_space);
+
// Use type inference if there is an initializer.
auto sym = builder_.Symbols().Register(namer_.Name(id));
return builder_.Var(Source{}, sym, initializer ? ast::Type{} : storage_type->Build(builder_),
@@ -1755,6 +1757,9 @@
}
attrs.Add(builder_.Binding(Source{}, AInt(deco[1])));
}
+ if (deco[0] == uint32_t(spv::Decoration::NonWritable)) {
+ read_only_vars_.insert(id);
+ }
}
if (transfer_pipeline_io) {
diff --git a/src/tint/lang/spirv/reader/ast_parser/ast_parser.h b/src/tint/lang/spirv/reader/ast_parser/ast_parser.h
index 106221a..4174965 100644
--- a/src/tint/lang/spirv/reader/ast_parser/ast_parser.h
+++ b/src/tint/lang/spirv/reader/ast_parser/ast_parser.h
@@ -267,6 +267,7 @@
/// then the `type` parameter is updated. Returns false on failure (with
/// a diagnostic), or when the variable should not be emitted, e.g. for a
/// PointSize builtin.
+ /// This method is idempotent.
/// @param id the ID of the SPIR-V variable
/// @param store_type the WGSL store type for the variable, which should be prepopulated
/// @param attributes the attribute list to populate
@@ -434,17 +435,20 @@
/// @returns a list of SPIR-V decorations.
DecorationList GetMemberPipelineDecorations(const Struct& struct_type, int member_index);
+ /// @param var_id the SPIR-V ID of the OpVariable
/// @param storage_type the 'var' storage type
/// @param address_space the 'var' address space
- /// @returns the access mode for a 'var' declaration with the given storage type and address
- /// space.
- core::Access VarAccess(const Type* storage_type, core::AddressSpace address_space);
+ /// @returns the access mode for a 'var' declaration with the given variable id, storage type
+ /// and address space. Must only be called after decorations for the variable have been
+ /// converted.
+ core::Access VarAccess(uint32_t var_id,
+ const Type* storage_type,
+ core::AddressSpace address_space);
/// Creates an AST 'var' node for a SPIR-V ID, including any attached decorations, unless it's
/// an ignorable builtin variable.
/// @param id the SPIR-V result ID
/// @param address_space the address space, which cannot be core::AddressSpace::kUndefined
- /// @param access the access
/// @param storage_type the storage type of the variable
/// @param initializer the variable initializer
/// @param attributes the variable attributes
@@ -452,7 +456,6 @@
/// in the error case
const ast::Var* MakeVar(uint32_t id,
core::AddressSpace address_space,
- core::Access access,
const Type* storage_type,
const ast::Expression* initializer,
Attributes attributes);
@@ -906,6 +909,9 @@
// The ast::Struct type names with only read-only members.
std::unordered_set<Symbol> read_only_struct_types_;
+ // The IDs of variables marked as NonWritable.
+ std::unordered_set<uint32_t> read_only_vars_;
+
// Maps from OpConstantComposite IDs to identifiers of module-scope const declarations.
std::unordered_map<uint32_t, Symbol> declared_constant_composites_;
diff --git a/src/tint/lang/spirv/reader/ast_parser/function.cc b/src/tint/lang/spirv/reader/ast_parser/function.cc
index b43dc3d..9eaea1e 100644
--- a/src/tint/lang/spirv/reader/ast_parser/function.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/function.cc
@@ -2522,8 +2522,7 @@
}
}
auto* var = parser_impl_.MakeVar(inst.result_id(), core::AddressSpace::kUndefined,
- core::Access::kUndefined, var_store_type, initializer,
- Attributes{});
+ var_store_type, initializer, Attributes{});
auto* var_decl_stmt = create<ast::VariableDeclStatement>(Source{}, var);
AddStatement(var_decl_stmt);
auto* var_type = ty_.Reference(core::AddressSpace::kUndefined, var_store_type);
@@ -3369,9 +3368,8 @@
// no need to remap pointer properties.
auto* store_type = parser_impl_.ConvertType(def_inst->type_id());
AddStatement(create<ast::VariableDeclStatement>(
- Source{},
- parser_impl_.MakeVar(id, core::AddressSpace::kUndefined, core::Access::kUndefined,
- store_type, nullptr, Attributes{})));
+ Source{}, parser_impl_.MakeVar(id, core::AddressSpace::kUndefined, store_type, nullptr,
+ Attributes{})));
auto* type = ty_.Reference(core::AddressSpace::kUndefined, store_type);
identifier_types_.emplace(id, type);
}
diff --git a/src/tint/lang/spirv/reader/ast_parser/module_var_test.cc b/src/tint/lang/spirv/reader/ast_parser/module_var_test.cc
index 3d67797..e3f24e1 100644
--- a/src/tint/lang/spirv/reader/ast_parser/module_var_test.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/module_var_test.cc
@@ -1394,6 +1394,37 @@
<< p->error();
}
+TEST_F(SpvModuleScopeVarParserTest, StorageBuffer_NonWritable_Var) {
+ // Variable should have access(read)
+ auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+ OpDecorate %s Block
+ OpDecorate %1 DescriptorSet 0
+ OpDecorate %1 Binding 0
+ OpDecorate %1 NonWritable
+ OpMemberDecorate %s 0 Offset 0
+ OpMemberDecorate %s 1 Offset 4
+ %void = OpTypeVoid
+ %voidfn = OpTypeFunction %void
+ %float = OpTypeFloat 32
+
+ %s = OpTypeStruct %float %float
+ %ptr_sb_s = OpTypePointer StorageBuffer %s
+ %1 = OpVariable %ptr_sb_s StorageBuffer
+ )" + MainBody()));
+ ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+ EXPECT_TRUE(p->error().empty());
+ const auto module_str = test::ToString(p->program());
+ EXPECT_THAT(module_str, HasSubstr(R"(struct S {
+ /* @offset(0) */
+ field0 : f32,
+ /* @offset(4) */
+ field1 : f32,
+}
+
+@group(0) @binding(0) var<storage, read> x_1 : S;
+)")) << module_str;
+}
+
TEST_F(SpvModuleScopeVarParserTest, StorageBuffer_NonWritable_AllMembers) {
// Variable should have access(read)
auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
diff --git a/test/tint/bug/tint/1776.spvasm.expected.dxc.hlsl b/test/tint/bug/tint/1776.spvasm.expected.dxc.hlsl
index 78faad9..03495e0 100644
--- a/test/tint/bug/tint/1776.spvasm.expected.dxc.hlsl
+++ b/test/tint/bug/tint/1776.spvasm.expected.dxc.hlsl
@@ -3,7 +3,7 @@
int b;
};
-RWByteAddressBuffer sb : register(u0);
+ByteAddressBuffer sb : register(t0);
S sb_load(uint offset) {
S tint_symbol = {asfloat(sb.Load4((offset + 0u))), asint(sb.Load((offset + 16u)))};
diff --git a/test/tint/bug/tint/1776.spvasm.expected.fxc.hlsl b/test/tint/bug/tint/1776.spvasm.expected.fxc.hlsl
index 78faad9..03495e0 100644
--- a/test/tint/bug/tint/1776.spvasm.expected.fxc.hlsl
+++ b/test/tint/bug/tint/1776.spvasm.expected.fxc.hlsl
@@ -3,7 +3,7 @@
int b;
};
-RWByteAddressBuffer sb : register(u0);
+ByteAddressBuffer sb : register(t0);
S sb_load(uint offset) {
S tint_symbol = {asfloat(sb.Load4((offset + 0u))), asint(sb.Load((offset + 16u)))};
diff --git a/test/tint/bug/tint/1776.spvasm.expected.msl b/test/tint/bug/tint/1776.spvasm.expected.msl
index 0933ac0..0548772 100644
--- a/test/tint/bug/tint/1776.spvasm.expected.msl
+++ b/test/tint/bug/tint/1776.spvasm.expected.msl
@@ -24,12 +24,12 @@
/* 0x0000 */ tint_array<S, 1> inner;
};
-void main_1(device sb_block* const tint_symbol_1) {
+void main_1(const device sb_block* const tint_symbol_1) {
S const x_18 = (*(tint_symbol_1)).inner[1];
return;
}
-kernel void tint_symbol(device sb_block* tint_symbol_2 [[buffer(0)]]) {
+kernel void tint_symbol(const device sb_block* tint_symbol_2 [[buffer(0)]]) {
main_1(tint_symbol_2);
return;
}
diff --git a/test/tint/bug/tint/1776.spvasm.expected.spvasm b/test/tint/bug/tint/1776.spvasm.expected.spvasm
index 6e076d1..9e220a4 100644
--- a/test/tint/bug/tint/1776.spvasm.expected.spvasm
+++ b/test/tint/bug/tint/1776.spvasm.expected.spvasm
@@ -20,6 +20,7 @@
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 16
OpDecorate %_runtimearr_S ArrayStride 32
+ OpDecorate %sb NonWritable
OpDecorate %sb DescriptorSet 0
OpDecorate %sb Binding 0
%float = OpTypeFloat 32
diff --git a/test/tint/bug/tint/1776.spvasm.expected.wgsl b/test/tint/bug/tint/1776.spvasm.expected.wgsl
index f9988fa..fa35f5e 100644
--- a/test/tint/bug/tint/1776.spvasm.expected.wgsl
+++ b/test/tint/bug/tint/1776.spvasm.expected.wgsl
@@ -12,7 +12,7 @@
inner : RTArr,
}
-@group(0) @binding(0) var<storage, read_write> sb : sb_block;
+@group(0) @binding(0) var<storage, read> sb : sb_block;
fn main_1() {
let x_18 = sb.inner[1i];