decoration_manager.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. // Copyright (c) 2017 Pierre Moreau
  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/decoration_manager.h"
  15. #include <algorithm>
  16. #include <memory>
  17. #include <set>
  18. #include <stack>
  19. #include <utility>
  20. #include "source/opt/ir_context.h"
  21. namespace {
  22. using InstructionVector = std::vector<const spvtools::opt::Instruction*>;
  23. using DecorationSet = std::set<std::u32string>;
  24. // Returns true if |a| is a subet of |b|.
  25. bool IsSubset(const DecorationSet& a, const DecorationSet& b) {
  26. auto it1 = a.begin();
  27. auto it2 = b.begin();
  28. while (it1 != a.end()) {
  29. if (it2 == b.end() || *it1 < *it2) {
  30. // |*it1| is in |a|, but not in |b|.
  31. return false;
  32. }
  33. if (*it1 == *it2) {
  34. // Found the element move to the next one.
  35. it1++;
  36. it2++;
  37. } else /* *it1 > *it2 */ {
  38. // Did not find |*it1| yet, check the next element in |b|.
  39. it2++;
  40. }
  41. }
  42. return true;
  43. }
  44. } // namespace
  45. namespace spvtools {
  46. namespace opt {
  47. namespace analysis {
  48. bool DecorationManager::RemoveDecorationsFrom(
  49. uint32_t id, std::function<bool(const Instruction&)> pred) {
  50. bool was_modified = false;
  51. const auto ids_iter = id_to_decoration_insts_.find(id);
  52. if (ids_iter == id_to_decoration_insts_.end()) {
  53. return was_modified;
  54. }
  55. TargetData& decorations_info = ids_iter->second;
  56. auto context = module_->context();
  57. std::vector<Instruction*> insts_to_kill;
  58. const bool is_group = !decorations_info.decorate_insts.empty();
  59. // Schedule all direct decorations for removal if instructed as such by
  60. // |pred|.
  61. for (Instruction* inst : decorations_info.direct_decorations)
  62. if (pred(*inst)) insts_to_kill.push_back(inst);
  63. // For all groups being directly applied to |id|, remove |id| (and the
  64. // literal if |inst| is an OpGroupMemberDecorate) from the instruction
  65. // applying the group.
  66. std::unordered_set<const Instruction*> indirect_decorations_to_remove;
  67. for (Instruction* inst : decorations_info.indirect_decorations) {
  68. assert(inst->opcode() == SpvOpGroupDecorate ||
  69. inst->opcode() == SpvOpGroupMemberDecorate);
  70. std::vector<Instruction*> group_decorations_to_keep;
  71. const uint32_t group_id = inst->GetSingleWordInOperand(0u);
  72. const auto group_iter = id_to_decoration_insts_.find(group_id);
  73. assert(group_iter != id_to_decoration_insts_.end() &&
  74. "Unknown decoration group");
  75. const auto& group_decorations = group_iter->second.direct_decorations;
  76. for (Instruction* decoration : group_decorations) {
  77. if (!pred(*decoration)) group_decorations_to_keep.push_back(decoration);
  78. }
  79. // If all decorations should be kept, then we can keep |id| part of the
  80. // group. However, if the group itself has no decorations, we should remove
  81. // the id from the group. This is needed to make |KillNameAndDecorate| work
  82. // correctly when a decoration group has no decorations.
  83. if (group_decorations_to_keep.size() == group_decorations.size() &&
  84. group_decorations.size() != 0) {
  85. continue;
  86. }
  87. // Otherwise, remove |id| from the targets of |group_id|
  88. const uint32_t stride = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u;
  89. for (uint32_t i = 1u; i < inst->NumInOperands();) {
  90. if (inst->GetSingleWordInOperand(i) != id) {
  91. i += stride;
  92. continue;
  93. }
  94. const uint32_t last_operand_index = inst->NumInOperands() - stride;
  95. if (i < last_operand_index)
  96. inst->GetInOperand(i) = inst->GetInOperand(last_operand_index);
  97. // Remove the associated literal, if it exists.
  98. if (stride == 2u) {
  99. if (i < last_operand_index)
  100. inst->GetInOperand(i + 1u) =
  101. inst->GetInOperand(last_operand_index + 1u);
  102. inst->RemoveInOperand(last_operand_index + 1u);
  103. }
  104. inst->RemoveInOperand(last_operand_index);
  105. was_modified = true;
  106. }
  107. // If the instruction has no targets left, remove the instruction
  108. // altogether.
  109. if (inst->NumInOperands() == 1u) {
  110. indirect_decorations_to_remove.emplace(inst);
  111. insts_to_kill.push_back(inst);
  112. } else if (was_modified) {
  113. context->ForgetUses(inst);
  114. indirect_decorations_to_remove.emplace(inst);
  115. context->AnalyzeUses(inst);
  116. }
  117. // If only some of the decorations should be kept, clone them and apply
  118. // them directly to |id|.
  119. if (!group_decorations_to_keep.empty()) {
  120. for (Instruction* decoration : group_decorations_to_keep) {
  121. // simply clone decoration and change |group_id| to |id|
  122. std::unique_ptr<Instruction> new_inst(
  123. decoration->Clone(module_->context()));
  124. new_inst->SetInOperand(0, {id});
  125. module_->AddAnnotationInst(std::move(new_inst));
  126. auto decoration_iter = --module_->annotation_end();
  127. context->AnalyzeUses(&*decoration_iter);
  128. }
  129. }
  130. }
  131. auto& indirect_decorations = decorations_info.indirect_decorations;
  132. indirect_decorations.erase(
  133. std::remove_if(
  134. indirect_decorations.begin(), indirect_decorations.end(),
  135. [&indirect_decorations_to_remove](const Instruction* inst) {
  136. return indirect_decorations_to_remove.count(inst);
  137. }),
  138. indirect_decorations.end());
  139. was_modified |= !insts_to_kill.empty();
  140. for (Instruction* inst : insts_to_kill) context->KillInst(inst);
  141. insts_to_kill.clear();
  142. // Schedule all instructions applying the group for removal if this group no
  143. // longer applies decorations, either directly or indirectly.
  144. if (is_group && decorations_info.direct_decorations.empty() &&
  145. decorations_info.indirect_decorations.empty()) {
  146. for (Instruction* inst : decorations_info.decorate_insts)
  147. insts_to_kill.push_back(inst);
  148. }
  149. was_modified |= !insts_to_kill.empty();
  150. for (Instruction* inst : insts_to_kill) context->KillInst(inst);
  151. if (decorations_info.direct_decorations.empty() &&
  152. decorations_info.indirect_decorations.empty() &&
  153. decorations_info.decorate_insts.empty()) {
  154. id_to_decoration_insts_.erase(ids_iter);
  155. }
  156. return was_modified;
  157. }
  158. std::vector<Instruction*> DecorationManager::GetDecorationsFor(
  159. uint32_t id, bool include_linkage) {
  160. return InternalGetDecorationsFor<Instruction*>(id, include_linkage);
  161. }
  162. std::vector<const Instruction*> DecorationManager::GetDecorationsFor(
  163. uint32_t id, bool include_linkage) const {
  164. return const_cast<DecorationManager*>(this)
  165. ->InternalGetDecorationsFor<const Instruction*>(id, include_linkage);
  166. }
  167. bool DecorationManager::HaveTheSameDecorations(uint32_t id1,
  168. uint32_t id2) const {
  169. const InstructionVector decorations_for1 = GetDecorationsFor(id1, false);
  170. const InstructionVector decorations_for2 = GetDecorationsFor(id2, false);
  171. // This function splits the decoration instructions into different sets,
  172. // based on their opcode; only OpDecorate, OpDecorateId,
  173. // OpDecorateStringGOOGLE, and OpMemberDecorate are considered, the other
  174. // opcodes are ignored.
  175. const auto fillDecorationSets =
  176. [](const InstructionVector& decoration_list, DecorationSet* decorate_set,
  177. DecorationSet* decorate_id_set, DecorationSet* decorate_string_set,
  178. DecorationSet* member_decorate_set) {
  179. for (const Instruction* inst : decoration_list) {
  180. std::u32string decoration_payload;
  181. // Ignore the opcode and the target as we do not want them to be
  182. // compared.
  183. for (uint32_t i = 1u; i < inst->NumInOperands(); ++i) {
  184. for (uint32_t word : inst->GetInOperand(i).words) {
  185. decoration_payload.push_back(word);
  186. }
  187. }
  188. switch (inst->opcode()) {
  189. case SpvOpDecorate:
  190. decorate_set->emplace(std::move(decoration_payload));
  191. break;
  192. case SpvOpMemberDecorate:
  193. member_decorate_set->emplace(std::move(decoration_payload));
  194. break;
  195. case SpvOpDecorateId:
  196. decorate_id_set->emplace(std::move(decoration_payload));
  197. break;
  198. case SpvOpDecorateStringGOOGLE:
  199. decorate_string_set->emplace(std::move(decoration_payload));
  200. break;
  201. default:
  202. break;
  203. }
  204. }
  205. };
  206. DecorationSet decorate_set_for1;
  207. DecorationSet decorate_id_set_for1;
  208. DecorationSet decorate_string_set_for1;
  209. DecorationSet member_decorate_set_for1;
  210. fillDecorationSets(decorations_for1, &decorate_set_for1,
  211. &decorate_id_set_for1, &decorate_string_set_for1,
  212. &member_decorate_set_for1);
  213. DecorationSet decorate_set_for2;
  214. DecorationSet decorate_id_set_for2;
  215. DecorationSet decorate_string_set_for2;
  216. DecorationSet member_decorate_set_for2;
  217. fillDecorationSets(decorations_for2, &decorate_set_for2,
  218. &decorate_id_set_for2, &decorate_string_set_for2,
  219. &member_decorate_set_for2);
  220. const bool result = decorate_set_for1 == decorate_set_for2 &&
  221. decorate_id_set_for1 == decorate_id_set_for2 &&
  222. member_decorate_set_for1 == member_decorate_set_for2 &&
  223. // Compare string sets last in case the strings are long.
  224. decorate_string_set_for1 == decorate_string_set_for2;
  225. return result;
  226. }
  227. bool DecorationManager::HaveSubsetOfDecorations(uint32_t id1,
  228. uint32_t id2) const {
  229. const InstructionVector decorations_for1 = GetDecorationsFor(id1, false);
  230. const InstructionVector decorations_for2 = GetDecorationsFor(id2, false);
  231. // This function splits the decoration instructions into different sets,
  232. // based on their opcode; only OpDecorate, OpDecorateId,
  233. // OpDecorateStringGOOGLE, and OpMemberDecorate are considered, the other
  234. // opcodes are ignored.
  235. const auto fillDecorationSets =
  236. [](const InstructionVector& decoration_list, DecorationSet* decorate_set,
  237. DecorationSet* decorate_id_set, DecorationSet* decorate_string_set,
  238. DecorationSet* member_decorate_set) {
  239. for (const Instruction* inst : decoration_list) {
  240. std::u32string decoration_payload;
  241. // Ignore the opcode and the target as we do not want them to be
  242. // compared.
  243. for (uint32_t i = 1u; i < inst->NumInOperands(); ++i) {
  244. for (uint32_t word : inst->GetInOperand(i).words) {
  245. decoration_payload.push_back(word);
  246. }
  247. }
  248. switch (inst->opcode()) {
  249. case SpvOpDecorate:
  250. decorate_set->emplace(std::move(decoration_payload));
  251. break;
  252. case SpvOpMemberDecorate:
  253. member_decorate_set->emplace(std::move(decoration_payload));
  254. break;
  255. case SpvOpDecorateId:
  256. decorate_id_set->emplace(std::move(decoration_payload));
  257. break;
  258. case SpvOpDecorateStringGOOGLE:
  259. decorate_string_set->emplace(std::move(decoration_payload));
  260. break;
  261. default:
  262. break;
  263. }
  264. }
  265. };
  266. DecorationSet decorate_set_for1;
  267. DecorationSet decorate_id_set_for1;
  268. DecorationSet decorate_string_set_for1;
  269. DecorationSet member_decorate_set_for1;
  270. fillDecorationSets(decorations_for1, &decorate_set_for1,
  271. &decorate_id_set_for1, &decorate_string_set_for1,
  272. &member_decorate_set_for1);
  273. DecorationSet decorate_set_for2;
  274. DecorationSet decorate_id_set_for2;
  275. DecorationSet decorate_string_set_for2;
  276. DecorationSet member_decorate_set_for2;
  277. fillDecorationSets(decorations_for2, &decorate_set_for2,
  278. &decorate_id_set_for2, &decorate_string_set_for2,
  279. &member_decorate_set_for2);
  280. const bool result =
  281. IsSubset(decorate_set_for1, decorate_set_for2) &&
  282. IsSubset(decorate_id_set_for1, decorate_id_set_for2) &&
  283. IsSubset(member_decorate_set_for1, member_decorate_set_for2) &&
  284. // Compare string sets last in case the strings are long.
  285. IsSubset(decorate_string_set_for1, decorate_string_set_for2);
  286. return result;
  287. }
  288. // TODO(pierremoreau): If OpDecorateId is referencing an OpConstant, one could
  289. // check that the constants are the same rather than just
  290. // looking at the constant ID.
  291. bool DecorationManager::AreDecorationsTheSame(const Instruction* inst1,
  292. const Instruction* inst2,
  293. bool ignore_target) const {
  294. switch (inst1->opcode()) {
  295. case SpvOpDecorate:
  296. case SpvOpMemberDecorate:
  297. case SpvOpDecorateId:
  298. case SpvOpDecorateStringGOOGLE:
  299. break;
  300. default:
  301. return false;
  302. }
  303. if (inst1->opcode() != inst2->opcode() ||
  304. inst1->NumInOperands() != inst2->NumInOperands())
  305. return false;
  306. for (uint32_t i = ignore_target ? 1u : 0u; i < inst1->NumInOperands(); ++i)
  307. if (inst1->GetInOperand(i) != inst2->GetInOperand(i)) return false;
  308. return true;
  309. }
  310. void DecorationManager::AnalyzeDecorations() {
  311. if (!module_) return;
  312. // For each group and instruction, collect all their decoration instructions.
  313. for (Instruction& inst : module_->annotations()) {
  314. AddDecoration(&inst);
  315. }
  316. }
  317. void DecorationManager::AddDecoration(Instruction* inst) {
  318. switch (inst->opcode()) {
  319. case SpvOpDecorate:
  320. case SpvOpDecorateId:
  321. case SpvOpDecorateStringGOOGLE:
  322. case SpvOpMemberDecorate: {
  323. const auto target_id = inst->GetSingleWordInOperand(0u);
  324. id_to_decoration_insts_[target_id].direct_decorations.push_back(inst);
  325. break;
  326. }
  327. case SpvOpGroupDecorate:
  328. case SpvOpGroupMemberDecorate: {
  329. const uint32_t start = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u;
  330. const uint32_t stride = start;
  331. for (uint32_t i = start; i < inst->NumInOperands(); i += stride) {
  332. const auto target_id = inst->GetSingleWordInOperand(i);
  333. TargetData& target_data = id_to_decoration_insts_[target_id];
  334. target_data.indirect_decorations.push_back(inst);
  335. }
  336. const auto target_id = inst->GetSingleWordInOperand(0u);
  337. id_to_decoration_insts_[target_id].decorate_insts.push_back(inst);
  338. break;
  339. }
  340. default:
  341. break;
  342. }
  343. }
  344. void DecorationManager::AddDecoration(SpvOp opcode,
  345. std::vector<Operand> opnds) {
  346. IRContext* ctx = module_->context();
  347. std::unique_ptr<Instruction> newDecoOp(
  348. new Instruction(ctx, opcode, 0, 0, opnds));
  349. ctx->AddAnnotationInst(std::move(newDecoOp));
  350. }
  351. void DecorationManager::AddDecoration(uint32_t inst_id, uint32_t decoration) {
  352. AddDecoration(
  353. SpvOpDecorate,
  354. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inst_id}},
  355. {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {decoration}}});
  356. }
  357. void DecorationManager::AddDecorationVal(uint32_t inst_id, uint32_t decoration,
  358. uint32_t decoration_value) {
  359. AddDecoration(
  360. SpvOpDecorate,
  361. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inst_id}},
  362. {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {decoration}},
  363. {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
  364. {decoration_value}}});
  365. }
  366. void DecorationManager::AddMemberDecoration(uint32_t inst_id, uint32_t member,
  367. uint32_t decoration,
  368. uint32_t decoration_value) {
  369. AddDecoration(
  370. SpvOpMemberDecorate,
  371. {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inst_id}},
  372. {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {member}},
  373. {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {decoration}},
  374. {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
  375. {decoration_value}}});
  376. }
  377. template <typename T>
  378. std::vector<T> DecorationManager::InternalGetDecorationsFor(
  379. uint32_t id, bool include_linkage) {
  380. std::vector<T> decorations;
  381. const auto ids_iter = id_to_decoration_insts_.find(id);
  382. // |id| has no decorations
  383. if (ids_iter == id_to_decoration_insts_.end()) return decorations;
  384. const TargetData& target_data = ids_iter->second;
  385. const auto process_direct_decorations =
  386. [include_linkage,
  387. &decorations](const std::vector<Instruction*>& direct_decorations) {
  388. for (Instruction* inst : direct_decorations) {
  389. const bool is_linkage = inst->opcode() == SpvOpDecorate &&
  390. inst->GetSingleWordInOperand(1u) ==
  391. SpvDecorationLinkageAttributes;
  392. if (include_linkage || !is_linkage) decorations.push_back(inst);
  393. }
  394. };
  395. // Process |id|'s decorations.
  396. process_direct_decorations(ids_iter->second.direct_decorations);
  397. // Process the decorations of all groups applied to |id|.
  398. for (const Instruction* inst : target_data.indirect_decorations) {
  399. const uint32_t group_id = inst->GetSingleWordInOperand(0u);
  400. const auto group_iter = id_to_decoration_insts_.find(group_id);
  401. assert(group_iter != id_to_decoration_insts_.end() && "Unknown group ID");
  402. process_direct_decorations(group_iter->second.direct_decorations);
  403. }
  404. return decorations;
  405. }
  406. bool DecorationManager::WhileEachDecoration(
  407. uint32_t id, uint32_t decoration,
  408. std::function<bool(const Instruction&)> f) {
  409. for (const Instruction* inst : GetDecorationsFor(id, true)) {
  410. switch (inst->opcode()) {
  411. case SpvOpMemberDecorate:
  412. if (inst->GetSingleWordInOperand(2) == decoration) {
  413. if (!f(*inst)) return false;
  414. }
  415. break;
  416. case SpvOpDecorate:
  417. case SpvOpDecorateId:
  418. case SpvOpDecorateStringGOOGLE:
  419. if (inst->GetSingleWordInOperand(1) == decoration) {
  420. if (!f(*inst)) return false;
  421. }
  422. break;
  423. default:
  424. assert(false && "Unexpected decoration instruction");
  425. }
  426. }
  427. return true;
  428. }
  429. void DecorationManager::ForEachDecoration(
  430. uint32_t id, uint32_t decoration,
  431. std::function<void(const Instruction&)> f) {
  432. WhileEachDecoration(id, decoration, [&f](const Instruction& inst) {
  433. f(inst);
  434. return true;
  435. });
  436. }
  437. bool DecorationManager::HasDecoration(uint32_t id, uint32_t decoration) {
  438. bool has_decoration = false;
  439. ForEachDecoration(id, decoration, [&has_decoration](const Instruction&) {
  440. has_decoration = true;
  441. });
  442. return has_decoration;
  443. }
  444. bool DecorationManager::FindDecoration(
  445. uint32_t id, uint32_t decoration,
  446. std::function<bool(const Instruction&)> f) {
  447. return !WhileEachDecoration(
  448. id, decoration, [&f](const Instruction& inst) { return !f(inst); });
  449. }
  450. void DecorationManager::CloneDecorations(uint32_t from, uint32_t to) {
  451. const auto decoration_list = id_to_decoration_insts_.find(from);
  452. if (decoration_list == id_to_decoration_insts_.end()) return;
  453. auto context = module_->context();
  454. for (Instruction* inst : decoration_list->second.direct_decorations) {
  455. // simply clone decoration and change |target-id| to |to|
  456. std::unique_ptr<Instruction> new_inst(inst->Clone(module_->context()));
  457. new_inst->SetInOperand(0, {to});
  458. module_->AddAnnotationInst(std::move(new_inst));
  459. auto decoration_iter = --module_->annotation_end();
  460. context->AnalyzeUses(&*decoration_iter);
  461. }
  462. // We need to copy the list of instructions as ForgetUses and AnalyzeUses are
  463. // going to modify it.
  464. std::vector<Instruction*> indirect_decorations =
  465. decoration_list->second.indirect_decorations;
  466. for (Instruction* inst : indirect_decorations) {
  467. switch (inst->opcode()) {
  468. case SpvOpGroupDecorate:
  469. context->ForgetUses(inst);
  470. // add |to| to list of decorated id's
  471. inst->AddOperand(
  472. Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {to}));
  473. context->AnalyzeUses(inst);
  474. break;
  475. case SpvOpGroupMemberDecorate: {
  476. context->ForgetUses(inst);
  477. // for each (id == from), add (to, literal) as operands
  478. const uint32_t num_operands = inst->NumOperands();
  479. for (uint32_t i = 1; i < num_operands; i += 2) {
  480. Operand op = inst->GetOperand(i);
  481. if (op.words[0] == from) { // add new pair of operands: (to, literal)
  482. inst->AddOperand(
  483. Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {to}));
  484. op = inst->GetOperand(i + 1);
  485. inst->AddOperand(std::move(op));
  486. }
  487. }
  488. context->AnalyzeUses(inst);
  489. break;
  490. }
  491. default:
  492. assert(false && "Unexpected decoration instruction");
  493. }
  494. }
  495. }
  496. void DecorationManager::CloneDecorations(
  497. uint32_t from, uint32_t to,
  498. const std::vector<SpvDecoration>& decorations_to_copy) {
  499. const auto decoration_list = id_to_decoration_insts_.find(from);
  500. if (decoration_list == id_to_decoration_insts_.end()) return;
  501. auto context = module_->context();
  502. for (Instruction* inst : decoration_list->second.direct_decorations) {
  503. if (std::find(decorations_to_copy.begin(), decorations_to_copy.end(),
  504. inst->GetSingleWordInOperand(1)) ==
  505. decorations_to_copy.end()) {
  506. continue;
  507. }
  508. // Clone decoration and change |target-id| to |to|.
  509. std::unique_ptr<Instruction> new_inst(inst->Clone(module_->context()));
  510. new_inst->SetInOperand(0, {to});
  511. module_->AddAnnotationInst(std::move(new_inst));
  512. auto decoration_iter = --module_->annotation_end();
  513. context->AnalyzeUses(&*decoration_iter);
  514. }
  515. // We need to copy the list of instructions as ForgetUses and AnalyzeUses are
  516. // going to modify it.
  517. std::vector<Instruction*> indirect_decorations =
  518. decoration_list->second.indirect_decorations;
  519. for (Instruction* inst : indirect_decorations) {
  520. switch (inst->opcode()) {
  521. case SpvOpGroupDecorate:
  522. CloneDecorations(inst->GetSingleWordInOperand(0), to,
  523. decorations_to_copy);
  524. break;
  525. case SpvOpGroupMemberDecorate: {
  526. assert(false && "The source id is not suppose to be a type.");
  527. break;
  528. }
  529. default:
  530. assert(false && "Unexpected decoration instruction");
  531. }
  532. }
  533. }
  534. void DecorationManager::RemoveDecoration(Instruction* inst) {
  535. const auto remove_from_container = [inst](std::vector<Instruction*>& v) {
  536. v.erase(std::remove(v.begin(), v.end(), inst), v.end());
  537. };
  538. switch (inst->opcode()) {
  539. case SpvOpDecorate:
  540. case SpvOpDecorateId:
  541. case SpvOpDecorateStringGOOGLE:
  542. case SpvOpMemberDecorate: {
  543. const auto target_id = inst->GetSingleWordInOperand(0u);
  544. auto const iter = id_to_decoration_insts_.find(target_id);
  545. if (iter == id_to_decoration_insts_.end()) return;
  546. remove_from_container(iter->second.direct_decorations);
  547. } break;
  548. case SpvOpGroupDecorate:
  549. case SpvOpGroupMemberDecorate: {
  550. const uint32_t stride = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u;
  551. for (uint32_t i = 1u; i < inst->NumInOperands(); i += stride) {
  552. const auto target_id = inst->GetSingleWordInOperand(i);
  553. auto const iter = id_to_decoration_insts_.find(target_id);
  554. if (iter == id_to_decoration_insts_.end()) continue;
  555. remove_from_container(iter->second.indirect_decorations);
  556. }
  557. const auto group_id = inst->GetSingleWordInOperand(0u);
  558. auto const iter = id_to_decoration_insts_.find(group_id);
  559. if (iter == id_to_decoration_insts_.end()) return;
  560. remove_from_container(iter->second.decorate_insts);
  561. } break;
  562. default:
  563. break;
  564. }
  565. }
  566. bool operator==(const DecorationManager& lhs, const DecorationManager& rhs) {
  567. return lhs.id_to_decoration_insts_ == rhs.id_to_decoration_insts_;
  568. }
  569. } // namespace analysis
  570. } // namespace opt
  571. } // namespace spvtools