decoration_manager.cpp 24 KB

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