flatten_decoration_pass.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // Copyright (c) 2017 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "source/opt/flatten_decoration_pass.h"
  15. #include <cassert>
  16. #include <memory>
  17. #include <unordered_map>
  18. #include <unordered_set>
  19. #include <utility>
  20. #include <vector>
  21. #include "source/opt/ir_context.h"
  22. namespace spvtools {
  23. namespace opt {
  24. using Words = std::vector<uint32_t>;
  25. using OrderedUsesMap = std::unordered_map<uint32_t, Words>;
  26. Pass::Status FlattenDecorationPass::Process() {
  27. bool modified = false;
  28. // The target Id of OpDecorationGroup instructions.
  29. // We have to track this separately from its uses, in case it
  30. // has no uses.
  31. std::unordered_set<uint32_t> group_ids;
  32. // Maps a decoration group Id to its GroupDecorate targets, in order
  33. // of appearance.
  34. OrderedUsesMap normal_uses;
  35. // Maps a decoration group Id to its GroupMemberDecorate targets and
  36. // their indices, in of appearance.
  37. OrderedUsesMap member_uses;
  38. auto annotations = context()->annotations();
  39. // On the first pass, record each OpDecorationGroup with its ordered uses.
  40. // Rely on unordered_map::operator[] to create its entries on first access.
  41. for (const auto& inst : annotations) {
  42. switch (inst.opcode()) {
  43. case spv::Op::OpDecorationGroup:
  44. group_ids.insert(inst.result_id());
  45. break;
  46. case spv::Op::OpGroupDecorate: {
  47. Words& words = normal_uses[inst.GetSingleWordInOperand(0)];
  48. for (uint32_t i = 1; i < inst.NumInOperandWords(); i++) {
  49. words.push_back(inst.GetSingleWordInOperand(i));
  50. }
  51. } break;
  52. case spv::Op::OpGroupMemberDecorate: {
  53. Words& words = member_uses[inst.GetSingleWordInOperand(0)];
  54. for (uint32_t i = 1; i < inst.NumInOperandWords(); i++) {
  55. words.push_back(inst.GetSingleWordInOperand(i));
  56. }
  57. } break;
  58. default:
  59. break;
  60. }
  61. }
  62. // On the second pass, replace OpDecorationGroup and its uses with
  63. // equivalent normal and struct member uses.
  64. auto inst_iter = annotations.begin();
  65. // We have to re-evaluate the end pointer
  66. while (inst_iter != context()->annotations().end()) {
  67. // Should we replace this instruction?
  68. bool replace = false;
  69. switch (inst_iter->opcode()) {
  70. case spv::Op::OpDecorationGroup:
  71. case spv::Op::OpGroupDecorate:
  72. case spv::Op::OpGroupMemberDecorate:
  73. replace = true;
  74. break;
  75. case spv::Op::OpDecorate: {
  76. // If this decoration targets a group, then replace it
  77. // by sets of normal and member decorations.
  78. const uint32_t group = inst_iter->GetSingleWordOperand(0);
  79. const auto normal_uses_iter = normal_uses.find(group);
  80. if (normal_uses_iter != normal_uses.end()) {
  81. for (auto target : normal_uses[group]) {
  82. std::unique_ptr<Instruction> new_inst(inst_iter->Clone(context()));
  83. new_inst->SetInOperand(0, Words{target});
  84. inst_iter = inst_iter.InsertBefore(std::move(new_inst));
  85. ++inst_iter;
  86. replace = true;
  87. }
  88. }
  89. const auto member_uses_iter = member_uses.find(group);
  90. if (member_uses_iter != member_uses.end()) {
  91. const Words& member_id_pairs = (*member_uses_iter).second;
  92. // The collection is a sequence of pairs.
  93. assert((member_id_pairs.size() % 2) == 0);
  94. for (size_t i = 0; i < member_id_pairs.size(); i += 2) {
  95. // Make an OpMemberDecorate instruction for each (target, member)
  96. // pair.
  97. const uint32_t target = member_id_pairs[i];
  98. const uint32_t member = member_id_pairs[i + 1];
  99. std::vector<Operand> operands;
  100. operands.push_back(Operand(SPV_OPERAND_TYPE_ID, {target}));
  101. operands.push_back(
  102. Operand(SPV_OPERAND_TYPE_LITERAL_INTEGER, {member}));
  103. auto decoration_operands_iter = inst_iter->begin();
  104. decoration_operands_iter++; // Skip the group target.
  105. operands.insert(operands.end(), decoration_operands_iter,
  106. inst_iter->end());
  107. std::unique_ptr<Instruction> new_inst(new Instruction(
  108. context(), spv::Op::OpMemberDecorate, 0, 0, operands));
  109. inst_iter = inst_iter.InsertBefore(std::move(new_inst));
  110. ++inst_iter;
  111. replace = true;
  112. }
  113. }
  114. // If this is an OpDecorate targeting the OpDecorationGroup itself,
  115. // remove it even if that decoration group itself is not the target of
  116. // any OpGroupDecorate or OpGroupMemberDecorate.
  117. if (!replace && group_ids.count(group)) {
  118. replace = true;
  119. }
  120. } break;
  121. default:
  122. break;
  123. }
  124. if (replace) {
  125. inst_iter = inst_iter.Erase();
  126. modified = true;
  127. } else {
  128. // Handle the case of decorations unrelated to decoration groups.
  129. ++inst_iter;
  130. }
  131. }
  132. // Remove OpName instructions which reference the removed group decorations.
  133. // An OpDecorationGroup instruction might not have been used by an
  134. // OpGroupDecorate or OpGroupMemberDecorate instruction.
  135. if (!group_ids.empty()) {
  136. for (auto debug_inst_iter = context()->debug2_begin();
  137. debug_inst_iter != context()->debug2_end();) {
  138. if (debug_inst_iter->opcode() == spv::Op::OpName) {
  139. const uint32_t target = debug_inst_iter->GetSingleWordOperand(0);
  140. if (group_ids.count(target)) {
  141. debug_inst_iter = debug_inst_iter.Erase();
  142. modified = true;
  143. } else {
  144. ++debug_inst_iter;
  145. }
  146. }
  147. }
  148. }
  149. return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
  150. }
  151. } // namespace opt
  152. } // namespace spvtools