spirv-reader: refactor handling pipeline IO decorations
This is in preparation for handling the "invariant" decoration.
Bug: tint:972
Change-Id: I17465946932ab37a32dfd3c477525649ab622c6f
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/58580
Auto-Submit: David Neto <dneto@google.com>
Commit-Queue: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index e5ca12f..c618d3a 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -981,12 +981,10 @@
index_prefix.push_back(0);
for (int i = 0; i < static_cast<int>(members.size()); ++i) {
index_prefix.back() = i;
- auto* location = parser_impl_.GetMemberLocation(*struct_type, i);
- SetLocation(decos, location);
ast::DecorationList member_decos(*decos);
- if (!parser_impl_.ConvertInterpolationDecorations(
+ if (!parser_impl_.ConvertPipelineDecorations(
struct_type,
- parser_impl_.GetMemberInterpolationDecorations(*struct_type, i),
+ parser_impl_.GetMemberPipelineDecorations(*struct_type, i),
&member_decos)) {
return false;
}
@@ -996,7 +994,7 @@
return false;
}
// Copy the location as updated by nested expansion of the member.
- SetLocation(decos, GetLocation(member_decos));
+ parser_impl_.SetLocation(decos, GetLocation(member_decos));
}
return success();
}
@@ -1064,26 +1062,6 @@
}
}
-ast::Decoration* FunctionEmitter::SetLocation(ast::DecorationList* decos,
- ast::Decoration* replacement) {
- if (!replacement) {
- return nullptr;
- }
- for (auto*& deco : *decos) {
- if (deco->Is<ast::LocationDecoration>()) {
- // Replace this location decoration with the replacement.
- // The old one doesn't leak because it's kept in the builder's AST node
- // list.
- ast::Decoration* result = deco;
- deco = replacement;
- return result;
- }
- }
- // The list didn't have a location. Add it.
- decos->push_back(replacement);
- return nullptr;
-}
-
ast::Decoration* FunctionEmitter::GetLocation(
const ast::DecorationList& decos) {
for (auto* const& deco : decos) {
@@ -1141,12 +1119,10 @@
index_prefix.push_back(0);
for (int i = 0; i < static_cast<int>(members.size()); ++i) {
index_prefix.back() = i;
- auto* location = parser_impl_.GetMemberLocation(*struct_type, i);
- SetLocation(decos, location);
ast::DecorationList member_decos(*decos);
- if (!parser_impl_.ConvertInterpolationDecorations(
+ if (!parser_impl_.ConvertPipelineDecorations(
struct_type,
- parser_impl_.GetMemberInterpolationDecorations(*struct_type, i),
+ parser_impl_.GetMemberPipelineDecorations(*struct_type, i),
&member_decos)) {
return false;
}
@@ -1156,7 +1132,7 @@
return false;
}
// Copy the location as updated by nested expansion of the member.
- SetLocation(decos, GetLocation(member_decos));
+ parser_impl_.SetLocation(decos, GetLocation(member_decos));
}
return success();
}
diff --git a/src/reader/spirv/function.h b/src/reader/spirv/function.h
index 9d6a82e..1cfed62 100644
--- a/src/reader/spirv/function.h
+++ b/src/reader/spirv/function.h
@@ -473,17 +473,6 @@
/// @param decos the decoration list to modify
void IncrementLocation(ast::DecorationList* decos);
- /// Updates the decoration list, placing a non-null location decoration into
- /// the list, replacing an existing one if it exists. Does nothing if the
- /// replacement is nullptr.
- /// Assumes the list contains at most one Location decoration.
- /// @param decos the decoration list to modify
- /// @param replacement the location decoration to place into the list
- /// @returns the location decoration that was replaced, if one was replaced,
- /// or null otherwise.
- ast::Decoration* SetLocation(ast::DecorationList* decos,
- ast::Decoration* replacement);
-
/// Returns the Location dcoration, if it exists.
/// @param decos the list of decorations to search
/// @returns the Location decoration, or nullptr if it doesn't exist
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index 32d3f9f..81a28057 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -234,12 +234,14 @@
}
// @param a SPIR-V decoration
-// @return true when the given decoration is an interpolation decoration.
-bool IsInterpolationDecoration(const Decoration& deco) {
+// @return true when the given decoration is a pipeline decoration other than a
+// bulitin variable.
+bool IsPipelineDecoration(const Decoration& deco) {
if (deco.size() < 1) {
return false;
}
switch (deco[0]) {
+ case SpvDecorationLocation:
case SpvDecorationFlat:
case SpvDecorationNoPerspective:
case SpvDecorationCentroid:
@@ -1115,31 +1117,22 @@
bool is_non_writable = false;
ast::DecorationList ast_member_decorations;
for (auto& decoration : GetDecorationsForMember(type_id, member_index)) {
- switch (decoration[0]) {
- case SpvDecorationNonWritable:
-
- // WGSL doesn't represent individual members as non-writable. Instead,
- // apply the ReadOnly access control to the containing struct if all
- // the members are non-writable.
- is_non_writable = true;
- break;
- case SpvDecorationLocation:
- case SpvDecorationFlat:
- case SpvDecorationNoPerspective:
- case SpvDecorationCentroid:
- case SpvDecorationSample:
- // IO decorations are handled when emitting the entry point.
- break;
- default: {
- auto* ast_member_decoration =
- ConvertMemberDecoration(type_id, member_index, decoration);
- if (!success_) {
- return nullptr;
- }
- if (ast_member_decoration) {
- ast_member_decorations.push_back(ast_member_decoration);
- }
- break;
+ if (IsPipelineDecoration(decoration)) {
+ // IO decorations are handled when emitting the entry point.
+ continue;
+ } else if (decoration[0] == SpvDecorationNonWritable) {
+ // WGSL doesn't represent individual members as non-writable. Instead,
+ // apply the ReadOnly access control to the containing struct if all
+ // the members are non-writable.
+ is_non_writable = true;
+ } else {
+ auto* ast_member_decoration =
+ ConvertMemberDecoration(type_id, member_index, decoration);
+ if (!success_) {
+ return nullptr;
+ }
+ if (ast_member_decoration) {
+ ast_member_decorations.push_back(ast_member_decoration);
}
}
}
@@ -1622,7 +1615,7 @@
const Type** store_type,
ast::DecorationList* decorations,
bool transfer_pipeline_io) {
- DecorationList interpolation_decorations;
+ DecorationList non_builtin_pipeline_decorations;
for (auto& deco : GetDecorationsFor(id)) {
if (deco.empty()) {
return Fail() << "malformed decoration on ID " << id << ": it is empty";
@@ -1685,18 +1678,8 @@
create<ast::BuiltinDecoration>(Source{}, ast_builtin));
}
}
- if (deco[0] == SpvDecorationLocation) {
- if (deco.size() != 2) {
- return Fail() << "malformed Location decoration on ID " << id
- << ": requires one literal operand";
- }
- if (transfer_pipeline_io) {
- decorations->emplace_back(
- create<ast::LocationDecoration>(Source{}, deco[1]));
- }
- }
- if (transfer_pipeline_io && IsInterpolationDecoration(deco)) {
- interpolation_decorations.push_back(deco);
+ if (transfer_pipeline_io && IsPipelineDecoration(deco)) {
+ non_builtin_pipeline_decorations.push_back(deco);
}
if (deco[0] == SpvDecorationDescriptorSet) {
if (deco.size() == 1) {
@@ -1717,8 +1700,8 @@
}
if (transfer_pipeline_io) {
- if (!ConvertInterpolationDecorations(*store_type, interpolation_decorations,
- decorations)) {
+ if (!ConvertPipelineDecorations(
+ *store_type, non_builtin_pipeline_decorations, decorations)) {
return false;
}
}
@@ -1726,62 +1709,95 @@
return success();
}
-DecorationList ParserImpl::GetMemberInterpolationDecorations(
+DecorationList ParserImpl::GetMemberPipelineDecorations(
const Struct& struct_type,
int member_index) {
// Yes, I could have used std::copy_if or std::copy_if.
DecorationList result;
for (const auto& deco : GetDecorationsForMember(
struct_id_for_symbol_[struct_type.name], member_index)) {
- if (IsInterpolationDecoration(deco)) {
+ if (IsPipelineDecoration(deco)) {
result.emplace_back(deco);
}
}
return result;
}
-bool ParserImpl::ConvertInterpolationDecorations(
- const Type* store_type,
- const DecorationList& decorations,
- ast::DecorationList* ast_decos) {
+ast::Decoration* ParserImpl::SetLocation(ast::DecorationList* decos,
+ ast::Decoration* replacement) {
+ if (!replacement) {
+ return nullptr;
+ }
+ for (auto*& deco : *decos) {
+ if (deco->Is<ast::LocationDecoration>()) {
+ // Replace this location decoration with the replacement.
+ // The old one doesn't leak because it's kept in the builder's AST node
+ // list.
+ ast::Decoration* result = nullptr;
+ result = deco;
+ deco = replacement;
+ return result; // Assume there is only one such decoration.
+ }
+ }
+ // The list didn't have a location. Add it.
+ decos->push_back(replacement);
+ return nullptr;
+}
+
+bool ParserImpl::ConvertPipelineDecorations(const Type* store_type,
+ const DecorationList& decorations,
+ ast::DecorationList* ast_decos) {
bool has_interpolate_no_perspective = false;
bool has_interpolate_sampling_centroid = false;
bool has_interpolate_sampling_sample = false;
for (const auto& deco : decorations) {
- if (deco[0] == SpvDecorationFlat) {
- // In WGSL, integral types are always flat, and so the decoration
- // is never specified.
- if (!store_type->IsIntegerScalarOrVector()) {
- ast_decos->emplace_back(create<ast::InterpolateDecoration>(
- Source{}, ast::InterpolationType::kFlat,
- ast::InterpolationSampling::kNone));
- // Only one interpolate attribute is allowed.
- return true;
- }
- }
- if (deco[0] == SpvDecorationNoPerspective) {
- if (store_type->IsIntegerScalarOrVector()) {
- // This doesn't capture the array or struct case.
- return Fail() << "NoPerspective is invalid on integral IO";
- }
- has_interpolate_no_perspective = true;
- }
- if (deco[0] == SpvDecorationCentroid) {
- if (store_type->IsIntegerScalarOrVector()) {
- // This doesn't capture the array or struct case.
- return Fail()
- << "Centroid interpolation sampling is invalid on integral IO";
- }
- has_interpolate_sampling_centroid = true;
- }
- if (deco[0] == SpvDecorationSample) {
- if (store_type->IsIntegerScalarOrVector()) {
- // This doesn't capture the array or struct case.
- return Fail()
- << "Sample interpolation sampling is invalid on integral IO";
- }
- has_interpolate_sampling_sample = true;
+ TINT_ASSERT(Reader, deco.size() > 0);
+ switch (deco[0]) {
+ case SpvDecorationLocation:
+ if (deco.size() != 2) {
+ return Fail() << "malformed Location decoration on ID requires one "
+ "literal operand";
+ }
+ SetLocation(ast_decos,
+ create<ast::LocationDecoration>(Source{}, deco[1]));
+ break;
+ case SpvDecorationFlat:
+ // In WGSL, integral types are always flat, and so the decoration
+ // is never specified.
+ if (!store_type->IsIntegerScalarOrVector()) {
+ ast_decos->emplace_back(create<ast::InterpolateDecoration>(
+ Source{}, ast::InterpolationType::kFlat,
+ ast::InterpolationSampling::kNone));
+ // Only one interpolate attribute is allowed.
+ return true;
+ }
+ break;
+ case SpvDecorationNoPerspective:
+ if (store_type->IsIntegerScalarOrVector()) {
+ // This doesn't capture the array or struct case.
+ return Fail() << "NoPerspective is invalid on integral IO";
+ }
+ has_interpolate_no_perspective = true;
+ break;
+ case SpvDecorationCentroid:
+ if (store_type->IsIntegerScalarOrVector()) {
+ // This doesn't capture the array or struct case.
+ return Fail()
+ << "Centroid interpolation sampling is invalid on integral IO";
+ }
+ has_interpolate_sampling_centroid = true;
+ break;
+ case SpvDecorationSample:
+ if (store_type->IsIntegerScalarOrVector()) {
+ // This doesn't capture the array or struct case.
+ return Fail()
+ << "Sample interpolation sampling is invalid on integral IO";
+ }
+ has_interpolate_sampling_sample = true;
+ break;
+ default:
+ break;
}
}
@@ -2818,22 +2834,6 @@
return namer_.GetMemberName(where->second, member_index);
}
-ast::Decoration* ParserImpl::GetMemberLocation(const Struct& struct_type,
- int member_index) {
- auto where = struct_id_for_symbol_.find(struct_type.name);
- if (where == struct_id_for_symbol_.end()) {
- Fail() << "no structure type registered for symbol";
- return nullptr;
- }
- const auto type_id = where->second;
- for (auto& deco : GetDecorationsForMember(type_id, member_index)) {
- if ((deco.size() == 2) && (deco[0] == SpvDecorationLocation)) {
- return create<ast::LocationDecoration>(Source{}, deco[1]);
- }
- }
- return nullptr;
-}
-
WorkgroupSizeInfo::WorkgroupSizeInfo() = default;
WorkgroupSizeInfo::~WorkgroupSizeInfo() = default;
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index 99b7cf7..7a69708 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -252,14 +252,25 @@
ast::DecorationList* ast_decos,
bool transfer_pipeline_io);
- /// Converts SPIR-V interpolation decorations into AST decorations.
+ /// Converts SPIR-V decorations for pipeline IO into AST decorations.
/// @param store_type the store type for the variable or member
/// @param decorations the SPIR-V interpolation decorations
/// @param ast_decos the decoration list to populate.
/// @returns false if conversion fails
- bool ConvertInterpolationDecorations(const Type* store_type,
- const DecorationList& decorations,
- ast::DecorationList* ast_decos);
+ bool ConvertPipelineDecorations(const Type* store_type,
+ const DecorationList& decorations,
+ ast::DecorationList* ast_decos);
+
+ /// Updates the decoration list, placing a non-null location decoration into
+ /// the list, replacing an existing one if it exists. Does nothing if the
+ /// replacement is nullptr.
+ /// Assumes the list contains at most one Location decoration.
+ /// @param decos the decoration list to modify
+ /// @param replacement the location decoration to place into the list
+ /// @returns the location decoration that was replaced, if one was replaced,
+ /// or null otherwise.
+ ast::Decoration* SetLocation(ast::DecorationList* decos,
+ ast::Decoration* replacement);
/// Converts a SPIR-V struct member decoration. If the decoration is
/// recognized but deliberately dropped, then returns nullptr without a
@@ -393,19 +404,13 @@
/// @returns the field name
std::string GetMemberName(const Struct& struct_type, int member_index);
- /// Returns the location decoration, if any on a struct member.
- /// @param struct_type the parser's structure type.
- /// @param member_index the member index
- /// @returns a newly created location node, or nullptr
- ast::Decoration* GetMemberLocation(const Struct& struct_type,
- int member_index);
-
- /// Returns the SPIR-V interpolation decorations, if any, on a struct member.
+ /// Returns the SPIR-V decorations for pipeline IO, if any, on a struct
+ /// member.
/// @param struct_type the parser's structure type.
/// @param member_index the member index
/// @returns a list of SPIR-V decorations.
- DecorationList GetMemberInterpolationDecorations(const Struct& struct_type,
- int member_index);
+ DecorationList GetMemberPipelineDecorations(const Struct& struct_type,
+ int member_index);
/// Creates an AST Variable node for a SPIR-V ID, including any attached
/// decorations, unless it's an ignorable builtin variable.