copy_prop_arrays.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. // Copyright (c) 2018 Google LLC.
  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/copy_prop_arrays.h"
  15. #include <utility>
  16. #include "source/opt/ir_builder.h"
  17. namespace spvtools {
  18. namespace opt {
  19. namespace {
  20. const uint32_t kLoadPointerInOperand = 0;
  21. const uint32_t kStorePointerInOperand = 0;
  22. const uint32_t kStoreObjectInOperand = 1;
  23. const uint32_t kCompositeExtractObjectInOperand = 0;
  24. const uint32_t kTypePointerStorageClassInIdx = 0;
  25. const uint32_t kTypePointerPointeeInIdx = 1;
  26. bool IsOpenCL100DebugDeclareOrValue(Instruction* di) {
  27. auto dbg_opcode = di->GetOpenCL100DebugOpcode();
  28. return dbg_opcode == OpenCLDebugInfo100DebugDeclare ||
  29. dbg_opcode == OpenCLDebugInfo100DebugValue;
  30. }
  31. } // namespace
  32. Pass::Status CopyPropagateArrays::Process() {
  33. bool modified = false;
  34. for (Function& function : *get_module()) {
  35. BasicBlock* entry_bb = &*function.begin();
  36. for (auto var_inst = entry_bb->begin(); var_inst->opcode() == SpvOpVariable;
  37. ++var_inst) {
  38. if (!IsPointerToArrayType(var_inst->type_id())) {
  39. continue;
  40. }
  41. // Find the only store to the entire memory location, if it exists.
  42. Instruction* store_inst = FindStoreInstruction(&*var_inst);
  43. if (!store_inst) {
  44. continue;
  45. }
  46. std::unique_ptr<MemoryObject> source_object =
  47. FindSourceObjectIfPossible(&*var_inst, store_inst);
  48. if (source_object != nullptr) {
  49. if (CanUpdateUses(&*var_inst, source_object->GetPointerTypeId(this))) {
  50. modified = true;
  51. PropagateObject(&*var_inst, source_object.get(), store_inst);
  52. }
  53. }
  54. }
  55. }
  56. return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
  57. }
  58. std::unique_ptr<CopyPropagateArrays::MemoryObject>
  59. CopyPropagateArrays::FindSourceObjectIfPossible(Instruction* var_inst,
  60. Instruction* store_inst) {
  61. assert(var_inst->opcode() == SpvOpVariable && "Expecting a variable.");
  62. // Check that the variable is a composite object where |store_inst|
  63. // dominates all of its loads.
  64. if (!store_inst) {
  65. return nullptr;
  66. }
  67. // Look at the loads to ensure they are dominated by the store.
  68. if (!HasValidReferencesOnly(var_inst, store_inst)) {
  69. return nullptr;
  70. }
  71. // If so, look at the store to see if it is the copy of an object.
  72. std::unique_ptr<MemoryObject> source = GetSourceObjectIfAny(
  73. store_inst->GetSingleWordInOperand(kStoreObjectInOperand));
  74. if (!source) {
  75. return nullptr;
  76. }
  77. // Ensure that |source| does not change between the point at which it is
  78. // loaded, and the position in which |var_inst| is loaded.
  79. //
  80. // For now we will go with the easy to implement approach, and check that the
  81. // entire variable (not just the specific component) is never written to.
  82. if (!HasNoStores(source->GetVariable())) {
  83. return nullptr;
  84. }
  85. return source;
  86. }
  87. Instruction* CopyPropagateArrays::FindStoreInstruction(
  88. const Instruction* var_inst) const {
  89. Instruction* store_inst = nullptr;
  90. get_def_use_mgr()->WhileEachUser(
  91. var_inst, [&store_inst, var_inst](Instruction* use) {
  92. if (use->opcode() == SpvOpStore &&
  93. use->GetSingleWordInOperand(kStorePointerInOperand) ==
  94. var_inst->result_id()) {
  95. if (store_inst == nullptr) {
  96. store_inst = use;
  97. } else {
  98. store_inst = nullptr;
  99. return false;
  100. }
  101. }
  102. return true;
  103. });
  104. return store_inst;
  105. }
  106. void CopyPropagateArrays::PropagateObject(Instruction* var_inst,
  107. MemoryObject* source,
  108. Instruction* insertion_point) {
  109. assert(var_inst->opcode() == SpvOpVariable &&
  110. "This function propagates variables.");
  111. Instruction* new_access_chain = BuildNewAccessChain(insertion_point, source);
  112. context()->KillNamesAndDecorates(var_inst);
  113. UpdateUses(var_inst, new_access_chain);
  114. }
  115. Instruction* CopyPropagateArrays::BuildNewAccessChain(
  116. Instruction* insertion_point,
  117. CopyPropagateArrays::MemoryObject* source) const {
  118. InstructionBuilder builder(
  119. context(), insertion_point,
  120. IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
  121. if (source->AccessChain().size() == 0) {
  122. return source->GetVariable();
  123. }
  124. return builder.AddAccessChain(source->GetPointerTypeId(this),
  125. source->GetVariable()->result_id(),
  126. source->AccessChain());
  127. }
  128. bool CopyPropagateArrays::HasNoStores(Instruction* ptr_inst) {
  129. return get_def_use_mgr()->WhileEachUser(ptr_inst, [this](Instruction* use) {
  130. if (use->opcode() == SpvOpLoad) {
  131. return true;
  132. } else if (use->opcode() == SpvOpAccessChain) {
  133. return HasNoStores(use);
  134. } else if (use->IsDecoration() || use->opcode() == SpvOpName) {
  135. return true;
  136. } else if (use->opcode() == SpvOpStore) {
  137. return false;
  138. } else if (use->opcode() == SpvOpImageTexelPointer) {
  139. return true;
  140. }
  141. // Some other instruction. Be conservative.
  142. return false;
  143. });
  144. }
  145. bool CopyPropagateArrays::HasValidReferencesOnly(Instruction* ptr_inst,
  146. Instruction* store_inst) {
  147. BasicBlock* store_block = context()->get_instr_block(store_inst);
  148. DominatorAnalysis* dominator_analysis =
  149. context()->GetDominatorAnalysis(store_block->GetParent());
  150. return get_def_use_mgr()->WhileEachUser(
  151. ptr_inst,
  152. [this, store_inst, dominator_analysis, ptr_inst](Instruction* use) {
  153. if (use->opcode() == SpvOpLoad ||
  154. use->opcode() == SpvOpImageTexelPointer) {
  155. // TODO: If there are many load in the same BB as |store_inst| the
  156. // time to do the multiple traverses can add up. Consider collecting
  157. // those loads and doing a single traversal.
  158. return dominator_analysis->Dominates(store_inst, use);
  159. } else if (use->opcode() == SpvOpAccessChain) {
  160. return HasValidReferencesOnly(use, store_inst);
  161. } else if (use->IsDecoration() || use->opcode() == SpvOpName) {
  162. return true;
  163. } else if (use->opcode() == SpvOpStore) {
  164. // If we are storing to part of the object it is not an candidate.
  165. return ptr_inst->opcode() == SpvOpVariable &&
  166. store_inst->GetSingleWordInOperand(kStorePointerInOperand) ==
  167. ptr_inst->result_id();
  168. } else if (IsOpenCL100DebugDeclareOrValue(use)) {
  169. return true;
  170. }
  171. // Some other instruction. Be conservative.
  172. return false;
  173. });
  174. }
  175. std::unique_ptr<CopyPropagateArrays::MemoryObject>
  176. CopyPropagateArrays::GetSourceObjectIfAny(uint32_t result) {
  177. Instruction* result_inst = context()->get_def_use_mgr()->GetDef(result);
  178. switch (result_inst->opcode()) {
  179. case SpvOpLoad:
  180. return BuildMemoryObjectFromLoad(result_inst);
  181. case SpvOpCompositeExtract:
  182. return BuildMemoryObjectFromExtract(result_inst);
  183. case SpvOpCompositeConstruct:
  184. return BuildMemoryObjectFromCompositeConstruct(result_inst);
  185. case SpvOpCopyObject:
  186. return GetSourceObjectIfAny(result_inst->GetSingleWordInOperand(0));
  187. case SpvOpCompositeInsert:
  188. return BuildMemoryObjectFromInsert(result_inst);
  189. default:
  190. return nullptr;
  191. }
  192. }
  193. std::unique_ptr<CopyPropagateArrays::MemoryObject>
  194. CopyPropagateArrays::BuildMemoryObjectFromLoad(Instruction* load_inst) {
  195. std::vector<uint32_t> components_in_reverse;
  196. analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
  197. Instruction* current_inst = def_use_mgr->GetDef(
  198. load_inst->GetSingleWordInOperand(kLoadPointerInOperand));
  199. // Build the access chain for the memory object by collecting the indices used
  200. // in the OpAccessChain instructions. If we find a variable index, then
  201. // return |nullptr| because we cannot know for sure which memory location is
  202. // used.
  203. //
  204. // It is built in reverse order because the different |OpAccessChain|
  205. // instructions are visited in reverse order from which they are applied.
  206. while (current_inst->opcode() == SpvOpAccessChain) {
  207. for (uint32_t i = current_inst->NumInOperands() - 1; i >= 1; --i) {
  208. uint32_t element_index_id = current_inst->GetSingleWordInOperand(i);
  209. components_in_reverse.push_back(element_index_id);
  210. }
  211. current_inst = def_use_mgr->GetDef(current_inst->GetSingleWordInOperand(0));
  212. }
  213. // If the address in the load is not constructed from an |OpVariable|
  214. // instruction followed by a series of |OpAccessChain| instructions, then
  215. // return |nullptr| because we cannot identify the owner or access chain
  216. // exactly.
  217. if (current_inst->opcode() != SpvOpVariable) {
  218. return nullptr;
  219. }
  220. // Build the memory object. Use |rbegin| and |rend| to put the access chain
  221. // back in the correct order.
  222. return std::unique_ptr<CopyPropagateArrays::MemoryObject>(
  223. new MemoryObject(current_inst, components_in_reverse.rbegin(),
  224. components_in_reverse.rend()));
  225. }
  226. std::unique_ptr<CopyPropagateArrays::MemoryObject>
  227. CopyPropagateArrays::BuildMemoryObjectFromExtract(Instruction* extract_inst) {
  228. assert(extract_inst->opcode() == SpvOpCompositeExtract &&
  229. "Expecting an OpCompositeExtract instruction.");
  230. analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
  231. std::unique_ptr<MemoryObject> result = GetSourceObjectIfAny(
  232. extract_inst->GetSingleWordInOperand(kCompositeExtractObjectInOperand));
  233. if (result) {
  234. analysis::Integer int_type(32, false);
  235. const analysis::Type* uint32_type =
  236. context()->get_type_mgr()->GetRegisteredType(&int_type);
  237. std::vector<uint32_t> components;
  238. // Convert the indices in the extract instruction to a series of ids that
  239. // can be used by the |OpAccessChain| instruction.
  240. for (uint32_t i = 1; i < extract_inst->NumInOperands(); ++i) {
  241. uint32_t index = extract_inst->GetSingleWordInOperand(i);
  242. const analysis::Constant* index_const =
  243. const_mgr->GetConstant(uint32_type, {index});
  244. components.push_back(
  245. const_mgr->GetDefiningInstruction(index_const)->result_id());
  246. }
  247. result->GetMember(components);
  248. return result;
  249. }
  250. return nullptr;
  251. }
  252. std::unique_ptr<CopyPropagateArrays::MemoryObject>
  253. CopyPropagateArrays::BuildMemoryObjectFromCompositeConstruct(
  254. Instruction* conststruct_inst) {
  255. assert(conststruct_inst->opcode() == SpvOpCompositeConstruct &&
  256. "Expecting an OpCompositeConstruct instruction.");
  257. // If every operand in the instruction are part of the same memory object, and
  258. // are being combined in the same order, then the result is the same as the
  259. // parent.
  260. std::unique_ptr<MemoryObject> memory_object =
  261. GetSourceObjectIfAny(conststruct_inst->GetSingleWordInOperand(0));
  262. if (!memory_object) {
  263. return nullptr;
  264. }
  265. if (!memory_object->IsMember()) {
  266. return nullptr;
  267. }
  268. analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
  269. const analysis::Constant* last_access =
  270. const_mgr->FindDeclaredConstant(memory_object->AccessChain().back());
  271. if (!last_access || !last_access->type()->AsInteger()) {
  272. return nullptr;
  273. }
  274. if (last_access->GetU32() != 0) {
  275. return nullptr;
  276. }
  277. memory_object->GetParent();
  278. if (memory_object->GetNumberOfMembers() !=
  279. conststruct_inst->NumInOperands()) {
  280. return nullptr;
  281. }
  282. for (uint32_t i = 1; i < conststruct_inst->NumInOperands(); ++i) {
  283. std::unique_ptr<MemoryObject> member_object =
  284. GetSourceObjectIfAny(conststruct_inst->GetSingleWordInOperand(i));
  285. if (!member_object) {
  286. return nullptr;
  287. }
  288. if (!member_object->IsMember()) {
  289. return nullptr;
  290. }
  291. if (!memory_object->Contains(member_object.get())) {
  292. return nullptr;
  293. }
  294. last_access =
  295. const_mgr->FindDeclaredConstant(member_object->AccessChain().back());
  296. if (!last_access || !last_access->type()->AsInteger()) {
  297. return nullptr;
  298. }
  299. if (last_access->GetU32() != i) {
  300. return nullptr;
  301. }
  302. }
  303. return memory_object;
  304. }
  305. std::unique_ptr<CopyPropagateArrays::MemoryObject>
  306. CopyPropagateArrays::BuildMemoryObjectFromInsert(Instruction* insert_inst) {
  307. assert(insert_inst->opcode() == SpvOpCompositeInsert &&
  308. "Expecting an OpCompositeInsert instruction.");
  309. analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
  310. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  311. analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
  312. const analysis::Type* result_type = type_mgr->GetType(insert_inst->type_id());
  313. uint32_t number_of_elements = 0;
  314. if (const analysis::Struct* struct_type = result_type->AsStruct()) {
  315. number_of_elements =
  316. static_cast<uint32_t>(struct_type->element_types().size());
  317. } else if (const analysis::Array* array_type = result_type->AsArray()) {
  318. const analysis::Constant* length_const =
  319. const_mgr->FindDeclaredConstant(array_type->LengthId());
  320. number_of_elements = length_const->GetU32();
  321. } else if (const analysis::Vector* vector_type = result_type->AsVector()) {
  322. number_of_elements = vector_type->element_count();
  323. } else if (const analysis::Matrix* matrix_type = result_type->AsMatrix()) {
  324. number_of_elements = matrix_type->element_count();
  325. }
  326. if (number_of_elements == 0) {
  327. return nullptr;
  328. }
  329. if (insert_inst->NumInOperands() != 3) {
  330. return nullptr;
  331. }
  332. if (insert_inst->GetSingleWordInOperand(2) != number_of_elements - 1) {
  333. return nullptr;
  334. }
  335. std::unique_ptr<MemoryObject> memory_object =
  336. GetSourceObjectIfAny(insert_inst->GetSingleWordInOperand(0));
  337. if (!memory_object) {
  338. return nullptr;
  339. }
  340. if (!memory_object->IsMember()) {
  341. return nullptr;
  342. }
  343. const analysis::Constant* last_access =
  344. const_mgr->FindDeclaredConstant(memory_object->AccessChain().back());
  345. if (!last_access || !last_access->type()->AsInteger()) {
  346. return nullptr;
  347. }
  348. if (last_access->GetU32() != number_of_elements - 1) {
  349. return nullptr;
  350. }
  351. memory_object->GetParent();
  352. Instruction* current_insert =
  353. def_use_mgr->GetDef(insert_inst->GetSingleWordInOperand(1));
  354. for (uint32_t i = number_of_elements - 1; i > 0; --i) {
  355. if (current_insert->opcode() != SpvOpCompositeInsert) {
  356. return nullptr;
  357. }
  358. if (current_insert->NumInOperands() != 3) {
  359. return nullptr;
  360. }
  361. if (current_insert->GetSingleWordInOperand(2) != i - 1) {
  362. return nullptr;
  363. }
  364. std::unique_ptr<MemoryObject> current_memory_object =
  365. GetSourceObjectIfAny(current_insert->GetSingleWordInOperand(0));
  366. if (!current_memory_object) {
  367. return nullptr;
  368. }
  369. if (!current_memory_object->IsMember()) {
  370. return nullptr;
  371. }
  372. if (memory_object->AccessChain().size() + 1 !=
  373. current_memory_object->AccessChain().size()) {
  374. return nullptr;
  375. }
  376. if (!memory_object->Contains(current_memory_object.get())) {
  377. return nullptr;
  378. }
  379. const analysis::Constant* current_last_access =
  380. const_mgr->FindDeclaredConstant(
  381. current_memory_object->AccessChain().back());
  382. if (!current_last_access || !current_last_access->type()->AsInteger()) {
  383. return nullptr;
  384. }
  385. if (current_last_access->GetU32() != i - 1) {
  386. return nullptr;
  387. }
  388. current_insert =
  389. def_use_mgr->GetDef(current_insert->GetSingleWordInOperand(1));
  390. }
  391. return memory_object;
  392. }
  393. bool CopyPropagateArrays::IsPointerToArrayType(uint32_t type_id) {
  394. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  395. analysis::Pointer* pointer_type = type_mgr->GetType(type_id)->AsPointer();
  396. if (pointer_type) {
  397. return pointer_type->pointee_type()->kind() == analysis::Type::kArray ||
  398. pointer_type->pointee_type()->kind() == analysis::Type::kImage;
  399. }
  400. return false;
  401. }
  402. bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst,
  403. uint32_t type_id) {
  404. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  405. analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
  406. analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
  407. analysis::Type* type = type_mgr->GetType(type_id);
  408. if (type->AsRuntimeArray()) {
  409. return false;
  410. }
  411. if (!type->AsStruct() && !type->AsArray() && !type->AsPointer()) {
  412. // If the type is not an aggregate, then the desired type must be the
  413. // same as the current type. No work to do, and we can do that.
  414. return true;
  415. }
  416. return def_use_mgr->WhileEachUse(original_ptr_inst, [this, type_mgr,
  417. const_mgr,
  418. type](Instruction* use,
  419. uint32_t) {
  420. if (IsOpenCL100DebugDeclareOrValue(use)) return true;
  421. switch (use->opcode()) {
  422. case SpvOpLoad: {
  423. analysis::Pointer* pointer_type = type->AsPointer();
  424. uint32_t new_type_id = type_mgr->GetId(pointer_type->pointee_type());
  425. if (new_type_id != use->type_id()) {
  426. return CanUpdateUses(use, new_type_id);
  427. }
  428. return true;
  429. }
  430. case SpvOpAccessChain: {
  431. analysis::Pointer* pointer_type = type->AsPointer();
  432. const analysis::Type* pointee_type = pointer_type->pointee_type();
  433. std::vector<uint32_t> access_chain;
  434. for (uint32_t i = 1; i < use->NumInOperands(); ++i) {
  435. const analysis::Constant* index_const =
  436. const_mgr->FindDeclaredConstant(use->GetSingleWordInOperand(i));
  437. if (index_const) {
  438. access_chain.push_back(index_const->GetU32());
  439. } else {
  440. // Variable index means the type is a type where every element
  441. // is the same type. Use element 0 to get the type.
  442. access_chain.push_back(0);
  443. }
  444. }
  445. const analysis::Type* new_pointee_type =
  446. type_mgr->GetMemberType(pointee_type, access_chain);
  447. analysis::Pointer pointerTy(new_pointee_type,
  448. pointer_type->storage_class());
  449. uint32_t new_pointer_type_id =
  450. context()->get_type_mgr()->GetTypeInstruction(&pointerTy);
  451. if (new_pointer_type_id == 0) {
  452. return false;
  453. }
  454. if (new_pointer_type_id != use->type_id()) {
  455. return CanUpdateUses(use, new_pointer_type_id);
  456. }
  457. return true;
  458. }
  459. case SpvOpCompositeExtract: {
  460. std::vector<uint32_t> access_chain;
  461. for (uint32_t i = 1; i < use->NumInOperands(); ++i) {
  462. access_chain.push_back(use->GetSingleWordInOperand(i));
  463. }
  464. const analysis::Type* new_type =
  465. type_mgr->GetMemberType(type, access_chain);
  466. uint32_t new_type_id = type_mgr->GetTypeInstruction(new_type);
  467. if (new_type_id == 0) {
  468. return false;
  469. }
  470. if (new_type_id != use->type_id()) {
  471. return CanUpdateUses(use, new_type_id);
  472. }
  473. return true;
  474. }
  475. case SpvOpStore:
  476. // If needed, we can create an element-by-element copy to change the
  477. // type of the value being stored. This way we can always handled
  478. // stores.
  479. return true;
  480. case SpvOpImageTexelPointer:
  481. case SpvOpName:
  482. return true;
  483. default:
  484. return use->IsDecoration();
  485. }
  486. });
  487. }
  488. void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
  489. Instruction* new_ptr_inst) {
  490. analysis::TypeManager* type_mgr = context()->get_type_mgr();
  491. analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
  492. analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
  493. std::vector<std::pair<Instruction*, uint32_t> > uses;
  494. def_use_mgr->ForEachUse(original_ptr_inst,
  495. [&uses](Instruction* use, uint32_t index) {
  496. uses.push_back({use, index});
  497. });
  498. for (auto pair : uses) {
  499. Instruction* use = pair.first;
  500. uint32_t index = pair.second;
  501. if (use->IsOpenCL100DebugInstr()) {
  502. switch (use->GetOpenCL100DebugOpcode()) {
  503. case OpenCLDebugInfo100DebugDeclare: {
  504. if (new_ptr_inst->opcode() == SpvOpVariable ||
  505. new_ptr_inst->opcode() == SpvOpFunctionParameter) {
  506. context()->ForgetUses(use);
  507. use->SetOperand(index, {new_ptr_inst->result_id()});
  508. context()->AnalyzeUses(use);
  509. } else {
  510. // Based on the spec, we cannot use a pointer other than OpVariable
  511. // or OpFunctionParameter for DebugDeclare. We have to use
  512. // DebugValue with Deref.
  513. context()->ForgetUses(use);
  514. // Change DebugDeclare to DebugValue.
  515. use->SetOperand(
  516. index - 2,
  517. {static_cast<uint32_t>(OpenCLDebugInfo100DebugValue)});
  518. use->SetOperand(index, {new_ptr_inst->result_id()});
  519. // Add Deref operation.
  520. Instruction* dbg_expr =
  521. def_use_mgr->GetDef(use->GetSingleWordOperand(index + 1));
  522. auto* deref_expr_instr =
  523. context()->get_debug_info_mgr()->DerefDebugExpression(dbg_expr);
  524. use->SetOperand(index + 1, {deref_expr_instr->result_id()});
  525. context()->AnalyzeUses(deref_expr_instr);
  526. context()->AnalyzeUses(use);
  527. }
  528. break;
  529. }
  530. case OpenCLDebugInfo100DebugValue:
  531. context()->ForgetUses(use);
  532. use->SetOperand(index, {new_ptr_inst->result_id()});
  533. context()->AnalyzeUses(use);
  534. break;
  535. default:
  536. assert(false && "Don't know how to rewrite instruction");
  537. break;
  538. }
  539. continue;
  540. }
  541. switch (use->opcode()) {
  542. case SpvOpLoad: {
  543. // Replace the actual use.
  544. context()->ForgetUses(use);
  545. use->SetOperand(index, {new_ptr_inst->result_id()});
  546. // Update the type.
  547. Instruction* pointer_type_inst =
  548. def_use_mgr->GetDef(new_ptr_inst->type_id());
  549. uint32_t new_type_id =
  550. pointer_type_inst->GetSingleWordInOperand(kTypePointerPointeeInIdx);
  551. if (new_type_id != use->type_id()) {
  552. use->SetResultType(new_type_id);
  553. context()->AnalyzeUses(use);
  554. UpdateUses(use, use);
  555. } else {
  556. context()->AnalyzeUses(use);
  557. }
  558. } break;
  559. case SpvOpAccessChain: {
  560. // Update the actual use.
  561. context()->ForgetUses(use);
  562. use->SetOperand(index, {new_ptr_inst->result_id()});
  563. // Convert the ids on the OpAccessChain to indices that can be used to
  564. // get the specific member.
  565. std::vector<uint32_t> access_chain;
  566. for (uint32_t i = 1; i < use->NumInOperands(); ++i) {
  567. const analysis::Constant* index_const =
  568. const_mgr->FindDeclaredConstant(use->GetSingleWordInOperand(i));
  569. if (index_const) {
  570. access_chain.push_back(index_const->GetU32());
  571. } else {
  572. // Variable index means the type is an type where every element
  573. // is the same type. Use element 0 to get the type.
  574. access_chain.push_back(0);
  575. }
  576. }
  577. Instruction* pointer_type_inst =
  578. get_def_use_mgr()->GetDef(new_ptr_inst->type_id());
  579. uint32_t new_pointee_type_id = GetMemberTypeId(
  580. pointer_type_inst->GetSingleWordInOperand(kTypePointerPointeeInIdx),
  581. access_chain);
  582. SpvStorageClass storage_class = static_cast<SpvStorageClass>(
  583. pointer_type_inst->GetSingleWordInOperand(
  584. kTypePointerStorageClassInIdx));
  585. uint32_t new_pointer_type_id =
  586. type_mgr->FindPointerToType(new_pointee_type_id, storage_class);
  587. if (new_pointer_type_id != use->type_id()) {
  588. use->SetResultType(new_pointer_type_id);
  589. context()->AnalyzeUses(use);
  590. UpdateUses(use, use);
  591. } else {
  592. context()->AnalyzeUses(use);
  593. }
  594. } break;
  595. case SpvOpCompositeExtract: {
  596. // Update the actual use.
  597. context()->ForgetUses(use);
  598. use->SetOperand(index, {new_ptr_inst->result_id()});
  599. uint32_t new_type_id = new_ptr_inst->type_id();
  600. std::vector<uint32_t> access_chain;
  601. for (uint32_t i = 1; i < use->NumInOperands(); ++i) {
  602. access_chain.push_back(use->GetSingleWordInOperand(i));
  603. }
  604. new_type_id = GetMemberTypeId(new_type_id, access_chain);
  605. if (new_type_id != use->type_id()) {
  606. use->SetResultType(new_type_id);
  607. context()->AnalyzeUses(use);
  608. UpdateUses(use, use);
  609. } else {
  610. context()->AnalyzeUses(use);
  611. }
  612. } break;
  613. case SpvOpStore:
  614. // If the use is the pointer, then it is the single store to that
  615. // variable. We do not want to replace it. Instead, it will become
  616. // dead after all of the loads are removed, and ADCE will get rid of it.
  617. //
  618. // If the use is the object being stored, we will create a copy of the
  619. // object turning it into the correct type. The copy is done by
  620. // decomposing the object into the base type, which must be the same,
  621. // and then rebuilding them.
  622. if (index == 1) {
  623. Instruction* target_pointer = def_use_mgr->GetDef(
  624. use->GetSingleWordInOperand(kStorePointerInOperand));
  625. Instruction* pointer_type =
  626. def_use_mgr->GetDef(target_pointer->type_id());
  627. uint32_t pointee_type_id =
  628. pointer_type->GetSingleWordInOperand(kTypePointerPointeeInIdx);
  629. uint32_t copy = GenerateCopy(original_ptr_inst, pointee_type_id, use);
  630. context()->ForgetUses(use);
  631. use->SetInOperand(index, {copy});
  632. context()->AnalyzeUses(use);
  633. }
  634. break;
  635. case SpvOpImageTexelPointer:
  636. // We treat an OpImageTexelPointer as a load. The result type should
  637. // always have the Image storage class, and should not need to be
  638. // updated.
  639. // Replace the actual use.
  640. context()->ForgetUses(use);
  641. use->SetOperand(index, {new_ptr_inst->result_id()});
  642. context()->AnalyzeUses(use);
  643. break;
  644. default:
  645. assert(false && "Don't know how to rewrite instruction");
  646. break;
  647. }
  648. }
  649. }
  650. uint32_t CopyPropagateArrays::GetMemberTypeId(
  651. uint32_t id, const std::vector<uint32_t>& access_chain) const {
  652. for (uint32_t element_index : access_chain) {
  653. Instruction* type_inst = get_def_use_mgr()->GetDef(id);
  654. switch (type_inst->opcode()) {
  655. case SpvOpTypeArray:
  656. case SpvOpTypeRuntimeArray:
  657. case SpvOpTypeMatrix:
  658. case SpvOpTypeVector:
  659. id = type_inst->GetSingleWordInOperand(0);
  660. break;
  661. case SpvOpTypeStruct:
  662. id = type_inst->GetSingleWordInOperand(element_index);
  663. break;
  664. default:
  665. break;
  666. }
  667. assert(id != 0 &&
  668. "Tried to extract from an object where it cannot be done.");
  669. }
  670. return id;
  671. }
  672. void CopyPropagateArrays::MemoryObject::GetMember(
  673. const std::vector<uint32_t>& access_chain) {
  674. access_chain_.insert(access_chain_.end(), access_chain.begin(),
  675. access_chain.end());
  676. }
  677. uint32_t CopyPropagateArrays::MemoryObject::GetNumberOfMembers() {
  678. IRContext* context = variable_inst_->context();
  679. analysis::TypeManager* type_mgr = context->get_type_mgr();
  680. const analysis::Type* type = type_mgr->GetType(variable_inst_->type_id());
  681. type = type->AsPointer()->pointee_type();
  682. std::vector<uint32_t> access_indices = GetAccessIds();
  683. type = type_mgr->GetMemberType(type, access_indices);
  684. if (const analysis::Struct* struct_type = type->AsStruct()) {
  685. return static_cast<uint32_t>(struct_type->element_types().size());
  686. } else if (const analysis::Array* array_type = type->AsArray()) {
  687. const analysis::Constant* length_const =
  688. context->get_constant_mgr()->FindDeclaredConstant(
  689. array_type->LengthId());
  690. assert(length_const->type()->AsInteger());
  691. return length_const->GetU32();
  692. } else if (const analysis::Vector* vector_type = type->AsVector()) {
  693. return vector_type->element_count();
  694. } else if (const analysis::Matrix* matrix_type = type->AsMatrix()) {
  695. return matrix_type->element_count();
  696. } else {
  697. return 0;
  698. }
  699. }
  700. template <class iterator>
  701. CopyPropagateArrays::MemoryObject::MemoryObject(Instruction* var_inst,
  702. iterator begin, iterator end)
  703. : variable_inst_(var_inst), access_chain_(begin, end) {}
  704. std::vector<uint32_t> CopyPropagateArrays::MemoryObject::GetAccessIds() const {
  705. analysis::ConstantManager* const_mgr =
  706. variable_inst_->context()->get_constant_mgr();
  707. std::vector<uint32_t> access_indices;
  708. for (uint32_t id : AccessChain()) {
  709. const analysis::Constant* element_index_const =
  710. const_mgr->FindDeclaredConstant(id);
  711. if (!element_index_const) {
  712. access_indices.push_back(0);
  713. } else {
  714. access_indices.push_back(element_index_const->GetU32());
  715. }
  716. }
  717. return access_indices;
  718. }
  719. bool CopyPropagateArrays::MemoryObject::Contains(
  720. CopyPropagateArrays::MemoryObject* other) {
  721. if (this->GetVariable() != other->GetVariable()) {
  722. return false;
  723. }
  724. if (AccessChain().size() > other->AccessChain().size()) {
  725. return false;
  726. }
  727. for (uint32_t i = 0; i < AccessChain().size(); i++) {
  728. if (AccessChain()[i] != other->AccessChain()[i]) {
  729. return false;
  730. }
  731. }
  732. return true;
  733. }
  734. } // namespace opt
  735. } // namespace spvtools