decoration_manager.cpp 23 KB

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