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>
This commit is contained in:
David Neto 2021-07-19 17:02:36 +00:00 committed by Tint LUCI CQ
parent a94d1a9c81
commit 93d4501e67
4 changed files with 122 additions and 152 deletions

View File

@ -981,12 +981,10 @@ bool FunctionEmitter::EmitPipelineInput(std::string var_name,
index_prefix.push_back(0); index_prefix.push_back(0);
for (int i = 0; i < static_cast<int>(members.size()); ++i) { for (int i = 0; i < static_cast<int>(members.size()); ++i) {
index_prefix.back() = i; index_prefix.back() = i;
auto* location = parser_impl_.GetMemberLocation(*struct_type, i);
SetLocation(decos, location);
ast::DecorationList member_decos(*decos); ast::DecorationList member_decos(*decos);
if (!parser_impl_.ConvertInterpolationDecorations( if (!parser_impl_.ConvertPipelineDecorations(
struct_type, struct_type,
parser_impl_.GetMemberInterpolationDecorations(*struct_type, i), parser_impl_.GetMemberPipelineDecorations(*struct_type, i),
&member_decos)) { &member_decos)) {
return false; return false;
} }
@ -996,7 +994,7 @@ bool FunctionEmitter::EmitPipelineInput(std::string var_name,
return false; return false;
} }
// Copy the location as updated by nested expansion of the member. // 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(); return success();
} }
@ -1064,26 +1062,6 @@ void FunctionEmitter::IncrementLocation(ast::DecorationList* decos) {
} }
} }
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( ast::Decoration* FunctionEmitter::GetLocation(
const ast::DecorationList& decos) { const ast::DecorationList& decos) {
for (auto* const& deco : decos) { for (auto* const& deco : decos) {
@ -1141,12 +1119,10 @@ bool FunctionEmitter::EmitPipelineOutput(std::string var_name,
index_prefix.push_back(0); index_prefix.push_back(0);
for (int i = 0; i < static_cast<int>(members.size()); ++i) { for (int i = 0; i < static_cast<int>(members.size()); ++i) {
index_prefix.back() = i; index_prefix.back() = i;
auto* location = parser_impl_.GetMemberLocation(*struct_type, i);
SetLocation(decos, location);
ast::DecorationList member_decos(*decos); ast::DecorationList member_decos(*decos);
if (!parser_impl_.ConvertInterpolationDecorations( if (!parser_impl_.ConvertPipelineDecorations(
struct_type, struct_type,
parser_impl_.GetMemberInterpolationDecorations(*struct_type, i), parser_impl_.GetMemberPipelineDecorations(*struct_type, i),
&member_decos)) { &member_decos)) {
return false; return false;
} }
@ -1156,7 +1132,7 @@ bool FunctionEmitter::EmitPipelineOutput(std::string var_name,
return false; return false;
} }
// Copy the location as updated by nested expansion of the member. // 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(); return success();
} }

View File

@ -473,17 +473,6 @@ class FunctionEmitter {
/// @param decos the decoration list to modify /// @param decos the decoration list to modify
void IncrementLocation(ast::DecorationList* decos); 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. /// Returns the Location dcoration, if it exists.
/// @param decos the list of decorations to search /// @param decos the list of decorations to search
/// @returns the Location decoration, or nullptr if it doesn't exist /// @returns the Location decoration, or nullptr if it doesn't exist

View File

@ -234,12 +234,14 @@ bool AssumesResultSignednessMatchesFirstOperand(GLSLstd450 extended_opcode) {
} }
// @param a SPIR-V decoration // @param a SPIR-V decoration
// @return true when the given decoration is an interpolation decoration. // @return true when the given decoration is a pipeline decoration other than a
bool IsInterpolationDecoration(const Decoration& deco) { // bulitin variable.
bool IsPipelineDecoration(const Decoration& deco) {
if (deco.size() < 1) { if (deco.size() < 1) {
return false; return false;
} }
switch (deco[0]) { switch (deco[0]) {
case SpvDecorationLocation:
case SpvDecorationFlat: case SpvDecorationFlat:
case SpvDecorationNoPerspective: case SpvDecorationNoPerspective:
case SpvDecorationCentroid: case SpvDecorationCentroid:
@ -1115,31 +1117,22 @@ const Type* ParserImpl::ConvertType(
bool is_non_writable = false; bool is_non_writable = false;
ast::DecorationList ast_member_decorations; ast::DecorationList ast_member_decorations;
for (auto& decoration : GetDecorationsForMember(type_id, member_index)) { for (auto& decoration : GetDecorationsForMember(type_id, member_index)) {
switch (decoration[0]) { if (IsPipelineDecoration(decoration)) {
case SpvDecorationNonWritable: // IO decorations are handled when emitting the entry point.
continue;
// WGSL doesn't represent individual members as non-writable. Instead, } else if (decoration[0] == SpvDecorationNonWritable) {
// apply the ReadOnly access control to the containing struct if all // WGSL doesn't represent individual members as non-writable. Instead,
// the members are non-writable. // apply the ReadOnly access control to the containing struct if all
is_non_writable = true; // the members are non-writable.
break; is_non_writable = true;
case SpvDecorationLocation: } else {
case SpvDecorationFlat: auto* ast_member_decoration =
case SpvDecorationNoPerspective: ConvertMemberDecoration(type_id, member_index, decoration);
case SpvDecorationCentroid: if (!success_) {
case SpvDecorationSample: return nullptr;
// IO decorations are handled when emitting the entry point. }
break; if (ast_member_decoration) {
default: { ast_member_decorations.push_back(ast_member_decoration);
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;
} }
} }
} }
@ -1622,7 +1615,7 @@ bool ParserImpl::ConvertDecorationsForVariable(uint32_t id,
const Type** store_type, const Type** store_type,
ast::DecorationList* decorations, ast::DecorationList* decorations,
bool transfer_pipeline_io) { bool transfer_pipeline_io) {
DecorationList interpolation_decorations; DecorationList non_builtin_pipeline_decorations;
for (auto& deco : GetDecorationsFor(id)) { for (auto& deco : GetDecorationsFor(id)) {
if (deco.empty()) { if (deco.empty()) {
return Fail() << "malformed decoration on ID " << id << ": it is empty"; return Fail() << "malformed decoration on ID " << id << ": it is empty";
@ -1685,18 +1678,8 @@ bool ParserImpl::ConvertDecorationsForVariable(uint32_t id,
create<ast::BuiltinDecoration>(Source{}, ast_builtin)); create<ast::BuiltinDecoration>(Source{}, ast_builtin));
} }
} }
if (deco[0] == SpvDecorationLocation) { if (transfer_pipeline_io && IsPipelineDecoration(deco)) {
if (deco.size() != 2) { non_builtin_pipeline_decorations.push_back(deco);
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 (deco[0] == SpvDecorationDescriptorSet) { if (deco[0] == SpvDecorationDescriptorSet) {
if (deco.size() == 1) { if (deco.size() == 1) {
@ -1717,8 +1700,8 @@ bool ParserImpl::ConvertDecorationsForVariable(uint32_t id,
} }
if (transfer_pipeline_io) { if (transfer_pipeline_io) {
if (!ConvertInterpolationDecorations(*store_type, interpolation_decorations, if (!ConvertPipelineDecorations(
decorations)) { *store_type, non_builtin_pipeline_decorations, decorations)) {
return false; return false;
} }
} }
@ -1726,62 +1709,95 @@ bool ParserImpl::ConvertDecorationsForVariable(uint32_t id,
return success(); return success();
} }
DecorationList ParserImpl::GetMemberInterpolationDecorations( DecorationList ParserImpl::GetMemberPipelineDecorations(
const Struct& struct_type, const Struct& struct_type,
int member_index) { int member_index) {
// Yes, I could have used std::copy_if or std::copy_if. // Yes, I could have used std::copy_if or std::copy_if.
DecorationList result; DecorationList result;
for (const auto& deco : GetDecorationsForMember( for (const auto& deco : GetDecorationsForMember(
struct_id_for_symbol_[struct_type.name], member_index)) { struct_id_for_symbol_[struct_type.name], member_index)) {
if (IsInterpolationDecoration(deco)) { if (IsPipelineDecoration(deco)) {
result.emplace_back(deco); result.emplace_back(deco);
} }
} }
return result; return result;
} }
bool ParserImpl::ConvertInterpolationDecorations( ast::Decoration* ParserImpl::SetLocation(ast::DecorationList* decos,
const Type* store_type, ast::Decoration* replacement) {
const DecorationList& decorations, if (!replacement) {
ast::DecorationList* ast_decos) { 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_no_perspective = false;
bool has_interpolate_sampling_centroid = false; bool has_interpolate_sampling_centroid = false;
bool has_interpolate_sampling_sample = false; bool has_interpolate_sampling_sample = false;
for (const auto& deco : decorations) { for (const auto& deco : decorations) {
if (deco[0] == SpvDecorationFlat) { TINT_ASSERT(Reader, deco.size() > 0);
// In WGSL, integral types are always flat, and so the decoration switch (deco[0]) {
// is never specified. case SpvDecorationLocation:
if (!store_type->IsIntegerScalarOrVector()) { if (deco.size() != 2) {
ast_decos->emplace_back(create<ast::InterpolateDecoration>( return Fail() << "malformed Location decoration on ID requires one "
Source{}, ast::InterpolationType::kFlat, "literal operand";
ast::InterpolationSampling::kNone)); }
// Only one interpolate attribute is allowed. SetLocation(ast_decos,
return true; create<ast::LocationDecoration>(Source{}, deco[1]));
} break;
} case SpvDecorationFlat:
if (deco[0] == SpvDecorationNoPerspective) { // In WGSL, integral types are always flat, and so the decoration
if (store_type->IsIntegerScalarOrVector()) { // is never specified.
// This doesn't capture the array or struct case. if (!store_type->IsIntegerScalarOrVector()) {
return Fail() << "NoPerspective is invalid on integral IO"; ast_decos->emplace_back(create<ast::InterpolateDecoration>(
} Source{}, ast::InterpolationType::kFlat,
has_interpolate_no_perspective = true; ast::InterpolationSampling::kNone));
} // Only one interpolate attribute is allowed.
if (deco[0] == SpvDecorationCentroid) { return true;
if (store_type->IsIntegerScalarOrVector()) { }
// This doesn't capture the array or struct case. break;
return Fail() case SpvDecorationNoPerspective:
<< "Centroid interpolation sampling is invalid on integral IO"; if (store_type->IsIntegerScalarOrVector()) {
} // This doesn't capture the array or struct case.
has_interpolate_sampling_centroid = true; return Fail() << "NoPerspective is invalid on integral IO";
} }
if (deco[0] == SpvDecorationSample) { has_interpolate_no_perspective = true;
if (store_type->IsIntegerScalarOrVector()) { break;
// This doesn't capture the array or struct case. case SpvDecorationCentroid:
return Fail() if (store_type->IsIntegerScalarOrVector()) {
<< "Sample interpolation sampling is invalid on integral IO"; // This doesn't capture the array or struct case.
} return Fail()
has_interpolate_sampling_sample = true; << "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 @@ std::string ParserImpl::GetMemberName(const Struct& struct_type,
return namer_.GetMemberName(where->second, member_index); 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;
WorkgroupSizeInfo::~WorkgroupSizeInfo() = default; WorkgroupSizeInfo::~WorkgroupSizeInfo() = default;

View File

@ -252,14 +252,25 @@ class ParserImpl : Reader {
ast::DecorationList* ast_decos, ast::DecorationList* ast_decos,
bool transfer_pipeline_io); 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 store_type the store type for the variable or member
/// @param decorations the SPIR-V interpolation decorations /// @param decorations the SPIR-V interpolation decorations
/// @param ast_decos the decoration list to populate. /// @param ast_decos the decoration list to populate.
/// @returns false if conversion fails /// @returns false if conversion fails
bool ConvertInterpolationDecorations(const Type* store_type, bool ConvertPipelineDecorations(const Type* store_type,
const DecorationList& decorations, const DecorationList& decorations,
ast::DecorationList* ast_decos); 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 /// Converts a SPIR-V struct member decoration. If the decoration is
/// recognized but deliberately dropped, then returns nullptr without a /// recognized but deliberately dropped, then returns nullptr without a
@ -393,19 +404,13 @@ class ParserImpl : Reader {
/// @returns the field name /// @returns the field name
std::string GetMemberName(const Struct& struct_type, int member_index); std::string GetMemberName(const Struct& struct_type, int member_index);
/// Returns the location decoration, if any on a struct member. /// Returns the SPIR-V decorations for pipeline IO, if any, on a struct
/// @param struct_type the parser's structure type. /// member.
/// @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.
/// @param struct_type the parser's structure type. /// @param struct_type the parser's structure type.
/// @param member_index the member index /// @param member_index the member index
/// @returns a list of SPIR-V decorations. /// @returns a list of SPIR-V decorations.
DecorationList GetMemberInterpolationDecorations(const Struct& struct_type, DecorationList GetMemberPipelineDecorations(const Struct& struct_type,
int member_index); int member_index);
/// Creates an AST Variable node for a SPIR-V ID, including any attached /// Creates an AST Variable node for a SPIR-V ID, including any attached
/// decorations, unless it's an ignorable builtin variable. /// decorations, unless it's an ignorable builtin variable.