interface_var_sroa.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. // Copyright (c) 2022 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. #ifndef SOURCE_OPT_INTERFACE_VAR_SROA_H_
  15. #define SOURCE_OPT_INTERFACE_VAR_SROA_H_
  16. #include <unordered_set>
  17. #include "source/opt/pass.h"
  18. namespace spvtools {
  19. namespace opt {
  20. // See optimizer.hpp for documentation.
  21. //
  22. // Note that the current implementation of this pass covers only store, load,
  23. // access chain instructions for the interface variables. Supporting other types
  24. // of instructions is a future work.
  25. class InterfaceVariableScalarReplacement : public Pass {
  26. public:
  27. InterfaceVariableScalarReplacement() {}
  28. const char* name() const override {
  29. return "interface-variable-scalar-replacement";
  30. }
  31. Status Process() override;
  32. IRContext::Analysis GetPreservedAnalyses() override {
  33. return IRContext::kAnalysisDecorations | IRContext::kAnalysisDefUse |
  34. IRContext::kAnalysisConstants | IRContext::kAnalysisTypes;
  35. }
  36. private:
  37. // A struct containing components of a composite variable. If the composite
  38. // consists of multiple or recursive components, |component_variable| is
  39. // nullptr and |nested_composite_components| keeps the components. If it has a
  40. // single component, |nested_composite_components| is empty and
  41. // |component_variable| is the component. Note that each element of
  42. // |nested_composite_components| has the NestedCompositeComponents struct as
  43. // its type that can recursively keep the components.
  44. struct NestedCompositeComponents {
  45. NestedCompositeComponents() : component_variable(nullptr) {}
  46. bool HasMultipleComponents() const {
  47. return !nested_composite_components.empty();
  48. }
  49. const std::vector<NestedCompositeComponents>& GetComponents() const {
  50. return nested_composite_components;
  51. }
  52. void AddComponent(const NestedCompositeComponents& component) {
  53. nested_composite_components.push_back(component);
  54. }
  55. Instruction* GetComponentVariable() const { return component_variable; }
  56. void SetSingleComponentVariable(Instruction* var) {
  57. component_variable = var;
  58. }
  59. private:
  60. std::vector<NestedCompositeComponents> nested_composite_components;
  61. Instruction* component_variable;
  62. };
  63. // Collects all interface variables used by the |entry_point|.
  64. std::vector<Instruction*> CollectInterfaceVariables(Instruction& entry_point);
  65. // Returns whether |var| has the extra arrayness for the entry point
  66. // |entry_point| or not.
  67. bool HasExtraArrayness(Instruction& entry_point, Instruction* var);
  68. // Finds a Location BuiltIn decoration of |var| and returns it via
  69. // |location|. Returns true whether the location exists or not.
  70. bool GetVariableLocation(Instruction* var, uint32_t* location);
  71. // Finds a Component BuiltIn decoration of |var| and returns it via
  72. // |component|. Returns true whether the component exists or not.
  73. bool GetVariableComponent(Instruction* var, uint32_t* component);
  74. // Returns the type of |var| as an instruction.
  75. Instruction* GetTypeOfVariable(Instruction* var);
  76. // Replaces an interface variable |interface_var| whose type is
  77. // |interface_var_type| with scalars and returns whether it succeeds or not.
  78. // |location| is the value of Location Decoration for |interface_var|.
  79. // |component| is the value of Component Decoration for |interface_var|.
  80. // If |extra_array_length| is 0, it means |interface_var| has a Patch
  81. // decoration. Otherwise, |extra_array_length| denotes the length of the extra
  82. // array of |interface_var|.
  83. bool ReplaceInterfaceVariableWithScalars(Instruction* interface_var,
  84. Instruction* interface_var_type,
  85. uint32_t location,
  86. uint32_t component,
  87. uint32_t extra_array_length);
  88. // Creates scalar variables with the storage classe |storage_class| to replace
  89. // an interface variable whose type is |interface_var_type|. If
  90. // |extra_array_length| is not zero, adds the extra arrayness to the created
  91. // scalar variables.
  92. NestedCompositeComponents CreateScalarInterfaceVarsForReplacement(
  93. Instruction* interface_var_type, spv::StorageClass storage_class,
  94. uint32_t extra_array_length);
  95. // Creates scalar variables with the storage classe |storage_class| to replace
  96. // the interface variable whose type is OpTypeArray |interface_var_type| with.
  97. // If |extra_array_length| is not zero, adds the extra arrayness to all the
  98. // scalar variables.
  99. NestedCompositeComponents CreateScalarInterfaceVarsForArray(
  100. Instruction* interface_var_type, spv::StorageClass storage_class,
  101. uint32_t extra_array_length);
  102. // Creates scalar variables with the storage classe |storage_class| to replace
  103. // the interface variable whose type is OpTypeMatrix |interface_var_type|
  104. // with. If |extra_array_length| is not zero, adds the extra arrayness to all
  105. // the scalar variables.
  106. NestedCompositeComponents CreateScalarInterfaceVarsForMatrix(
  107. Instruction* interface_var_type, spv::StorageClass storage_class,
  108. uint32_t extra_array_length);
  109. // Recursively adds Location and Component decorations to variables in
  110. // |vars| with |location| and |component|. Increases |location| by one after
  111. // it actually adds Location and Component decorations for a variable.
  112. void AddLocationAndComponentDecorations(const NestedCompositeComponents& vars,
  113. uint32_t* location,
  114. uint32_t component);
  115. // Replaces the interface variable |interface_var| with
  116. // |scalar_interface_vars| and returns whether it succeeds or not.
  117. // |extra_arrayness| is the extra arrayness of the interface variable.
  118. // |scalar_interface_vars| contains the nested variables to replace the
  119. // interface variable with.
  120. bool ReplaceInterfaceVarWith(
  121. Instruction* interface_var, uint32_t extra_arrayness,
  122. const NestedCompositeComponents& scalar_interface_vars);
  123. // Replaces |interface_var| in the operands of instructions
  124. // |interface_var_users| with |scalar_interface_vars|. This is a recursive
  125. // method and |interface_var_component_indices| is used to specify which
  126. // recursive component of |interface_var| is replaced. Returns composite
  127. // construct instructions to be replaced with load instructions of
  128. // |interface_var_users| via |loads_to_composites|. Returns composite
  129. // construct instructions to be replaced with load instructions of access
  130. // chain instructions in |interface_var_users| via
  131. // |loads_for_access_chain_to_composites|.
  132. bool ReplaceComponentsOfInterfaceVarWith(
  133. Instruction* interface_var,
  134. const std::vector<Instruction*>& interface_var_users,
  135. const NestedCompositeComponents& scalar_interface_vars,
  136. std::vector<uint32_t>& interface_var_component_indices,
  137. const uint32_t* extra_array_index,
  138. std::unordered_map<Instruction*, Instruction*>* loads_to_composites,
  139. std::unordered_map<Instruction*, Instruction*>*
  140. loads_for_access_chain_to_composites);
  141. // Replaces |interface_var| in the operands of instructions
  142. // |interface_var_users| with |components| that is a vector of components for
  143. // the interface variable |interface_var|. This is a recursive method and
  144. // |interface_var_component_indices| is used to specify which recursive
  145. // component of |interface_var| is replaced. Returns composite construct
  146. // instructions to be replaced with load instructions of |interface_var_users|
  147. // via |loads_to_composites|. Returns composite construct instructions to be
  148. // replaced with load instructions of access chain instructions in
  149. // |interface_var_users| via |loads_for_access_chain_to_composites|.
  150. bool ReplaceMultipleComponentsOfInterfaceVarWith(
  151. Instruction* interface_var,
  152. const std::vector<Instruction*>& interface_var_users,
  153. const std::vector<NestedCompositeComponents>& components,
  154. std::vector<uint32_t>& interface_var_component_indices,
  155. const uint32_t* extra_array_index,
  156. std::unordered_map<Instruction*, Instruction*>* loads_to_composites,
  157. std::unordered_map<Instruction*, Instruction*>*
  158. loads_for_access_chain_to_composites);
  159. // Replaces a component of |interface_var| that is used as an operand of
  160. // instruction |interface_var_user| with |scalar_var|.
  161. // |interface_var_component_indices| is a vector of recursive indices for
  162. // which recursive component of |interface_var| is replaced. If
  163. // |interface_var_user| is a load, returns the component value via
  164. // |loads_to_component_values|. If |interface_var_user| is an access chain,
  165. // returns the component value for loads of |interface_var_user| via
  166. // |loads_for_access_chain_to_component_values|.
  167. bool ReplaceComponentOfInterfaceVarWith(
  168. Instruction* interface_var, Instruction* interface_var_user,
  169. Instruction* scalar_var,
  170. const std::vector<uint32_t>& interface_var_component_indices,
  171. const uint32_t* extra_array_index,
  172. std::unordered_map<Instruction*, Instruction*>* loads_to_component_values,
  173. std::unordered_map<Instruction*, Instruction*>*
  174. loads_for_access_chain_to_component_values);
  175. // Creates instructions to load |scalar_var| and inserts them before
  176. // |insert_before|. If |extra_array_index| is not null, they load
  177. // |extra_array_index| th component of |scalar_var| instead of |scalar_var|
  178. // itself.
  179. Instruction* LoadScalarVar(Instruction* scalar_var,
  180. const uint32_t* extra_array_index,
  181. Instruction* insert_before);
  182. // Creates instructions to load an access chain to |var| and inserts them
  183. // before |insert_before|. |Indexes| will be Indexes operand of the access
  184. // chain.
  185. Instruction* LoadAccessChainToVar(Instruction* var,
  186. const std::vector<uint32_t>& indexes,
  187. Instruction* insert_before);
  188. // Creates instructions to store a component of an aggregate whose id is
  189. // |value_id| to an access chain to |scalar_var| and inserts the created
  190. // instructions before |insert_before|. To get the component, recursively
  191. // traverses the aggregate with |component_indices| as indexes.
  192. // Numbers in |access_chain_indices| are the Indexes operand of the access
  193. // chain to |scalar_var|
  194. void StoreComponentOfValueToAccessChainToScalarVar(
  195. uint32_t value_id, const std::vector<uint32_t>& component_indices,
  196. Instruction* scalar_var,
  197. const std::vector<uint32_t>& access_chain_indices,
  198. Instruction* insert_before);
  199. // Creates instructions to store a component of an aggregate whose id is
  200. // |value_id| to |scalar_var| and inserts the created instructions before
  201. // |insert_before|. To get the component, recursively traverses the aggregate
  202. // using |extra_array_index| and |component_indices| as indexes.
  203. void StoreComponentOfValueToScalarVar(
  204. uint32_t value_id, const std::vector<uint32_t>& component_indices,
  205. Instruction* scalar_var, const uint32_t* extra_array_index,
  206. Instruction* insert_before);
  207. // Creates instructions to store a component of an aggregate whose id is
  208. // |value_id| to |ptr| and inserts the created instructions before
  209. // |insert_before|. To get the component, recursively traverses the aggregate
  210. // using |extra_array_index| and |component_indices| as indexes.
  211. // |component_type_id| is the id of the type instruction of the component.
  212. void StoreComponentOfValueTo(uint32_t component_type_id, uint32_t value_id,
  213. const std::vector<uint32_t>& component_indices,
  214. Instruction* ptr,
  215. const uint32_t* extra_array_index,
  216. Instruction* insert_before);
  217. // Creates new OpCompositeExtract with |type_id| for Result Type,
  218. // |composite_id| for Composite operand, and |indexes| for Indexes operands.
  219. // If |extra_first_index| is not nullptr, uses it as the first Indexes
  220. // operand.
  221. Instruction* CreateCompositeExtract(uint32_t type_id, uint32_t composite_id,
  222. const std::vector<uint32_t>& indexes,
  223. const uint32_t* extra_first_index);
  224. // Creates a new OpLoad whose Result Type is |type_id| and Pointer operand is
  225. // |ptr|. Inserts the new instruction before |insert_before|.
  226. Instruction* CreateLoad(uint32_t type_id, Instruction* ptr,
  227. Instruction* insert_before);
  228. // Clones an annotation instruction |annotation_inst| and sets the target
  229. // operand of the new annotation instruction as |var_id|.
  230. void CloneAnnotationForVariable(Instruction* annotation_inst,
  231. uint32_t var_id);
  232. // Replaces the interface variable |interface_var| in the operands of the
  233. // entry point |entry_point| with |scalar_var_id|. If it cannot find
  234. // |interface_var| from the operands of the entry point |entry_point|, adds
  235. // |scalar_var_id| as an operand of the entry point |entry_point|.
  236. bool ReplaceInterfaceVarInEntryPoint(Instruction* interface_var,
  237. Instruction* entry_point,
  238. uint32_t scalar_var_id);
  239. // Creates an access chain instruction whose Base operand is |var| and Indexes
  240. // operand is |index|. |component_type_id| is the id of the type instruction
  241. // that is the type of component. Inserts the new access chain before
  242. // |insert_before|.
  243. Instruction* CreateAccessChainWithIndex(uint32_t component_type_id,
  244. Instruction* var, uint32_t index,
  245. Instruction* insert_before);
  246. // Returns the pointee type of the type of variable |var|.
  247. uint32_t GetPointeeTypeIdOfVar(Instruction* var);
  248. // Replaces the access chain |access_chain| and its users with a new access
  249. // chain that points |scalar_var| as the Base operand having
  250. // |interface_var_component_indices| as Indexes operands and users of the new
  251. // access chain. When some of the users are load instructions, returns the
  252. // original load instruction to the new instruction that loads a component of
  253. // the original load value via |loads_to_component_values|.
  254. void ReplaceAccessChainWith(
  255. Instruction* access_chain,
  256. const std::vector<uint32_t>& interface_var_component_indices,
  257. Instruction* scalar_var,
  258. std::unordered_map<Instruction*, Instruction*>*
  259. loads_to_component_values);
  260. // Assuming that |access_chain| is an access chain instruction whose Base
  261. // operand is |base_access_chain|, replaces the operands of |access_chain|
  262. // with operands of |base_access_chain| and Indexes operands of
  263. // |access_chain|.
  264. void UseBaseAccessChainForAccessChain(Instruction* access_chain,
  265. Instruction* base_access_chain);
  266. // Creates composite construct instructions for load instructions that are the
  267. // keys of |loads_to_component_values| if no such composite construct
  268. // instructions exist. Adds a component of the composite as an operand of the
  269. // created composite construct instruction. Each value of
  270. // |loads_to_component_values| is the component. Returns the created composite
  271. // construct instructions using |loads_to_composites|. |depth_to_component| is
  272. // the number of recursive access steps to get the component from the
  273. // composite.
  274. void AddComponentsToCompositesForLoads(
  275. const std::unordered_map<Instruction*, Instruction*>&
  276. loads_to_component_values,
  277. std::unordered_map<Instruction*, Instruction*>* loads_to_composites,
  278. uint32_t depth_to_component);
  279. // Creates a composite construct instruction for a component of the value of
  280. // instruction |load| in |depth_to_component| th recursive depth and inserts
  281. // it after |load|.
  282. Instruction* CreateCompositeConstructForComponentOfLoad(
  283. Instruction* load, uint32_t depth_to_component);
  284. // Creates a new access chain instruction that points to variable |var| whose
  285. // type is the instruction with |var_type_id| and inserts it before
  286. // |insert_before|. The new access chain will have |index_ids| for Indexes
  287. // operands. Returns the type id of the component that is pointed by the new
  288. // access chain via |component_type_id|.
  289. Instruction* CreateAccessChainToVar(uint32_t var_type_id, Instruction* var,
  290. const std::vector<uint32_t>& index_ids,
  291. Instruction* insert_before,
  292. uint32_t* component_type_id);
  293. // Returns the result id of OpTypeArray instrunction whose Element Type
  294. // operand is |elem_type_id| and Length operand is |array_length|.
  295. uint32_t GetArrayType(uint32_t elem_type_id, uint32_t array_length);
  296. // Returns the result id of OpTypePointer instrunction whose Type
  297. // operand is |type_id| and Storage Class operand is |storage_class|.
  298. uint32_t GetPointerType(uint32_t type_id, spv::StorageClass storage_class);
  299. // Kills an instrunction |inst| and its users.
  300. void KillInstructionAndUsers(Instruction* inst);
  301. // Kills a vector of instrunctions |insts| and their users.
  302. void KillInstructionsAndUsers(const std::vector<Instruction*>& insts);
  303. // Kills all OpDecorate instructions for Location and Component of the
  304. // variable whose id is |var_id|.
  305. void KillLocationAndComponentDecorations(uint32_t var_id);
  306. // If |var| has the extra arrayness for an entry point, reports an error and
  307. // returns true. Otherwise, returns false.
  308. bool ReportErrorIfHasExtraArraynessForOtherEntry(Instruction* var);
  309. // If |var| does not have the extra arrayness for an entry point, reports an
  310. // error and returns true. Otherwise, returns false.
  311. bool ReportErrorIfHasNoExtraArraynessForOtherEntry(Instruction* var);
  312. // If |interface_var| has the extra arrayness for an entry point but it does
  313. // not have one for another entry point, reports an error and returns false.
  314. // Otherwise, returns true. |has_extra_arrayness| denotes whether it has an
  315. // extra arrayness for an entry point or not.
  316. bool CheckExtraArraynessConflictBetweenEntries(Instruction* interface_var,
  317. bool has_extra_arrayness);
  318. // Conducts the scalar replacement for the interface variables used by the
  319. // |entry_point|.
  320. Pass::Status ReplaceInterfaceVarsWithScalars(Instruction& entry_point);
  321. // A set of interface variable ids that were already removed from operands of
  322. // the entry point.
  323. std::unordered_set<uint32_t>
  324. interface_vars_removed_from_entry_point_operands_;
  325. // A mapping from ids of new composite construct instructions that load
  326. // instructions are replaced with to the recursive depth of the component of
  327. // load that the new component construct instruction is used for.
  328. std::unordered_map<uint32_t, uint32_t> composite_ids_to_component_depths;
  329. // A set of interface variables with the extra arrayness for any of the entry
  330. // points.
  331. std::unordered_set<Instruction*> vars_with_extra_arrayness;
  332. // A set of interface variables without the extra arrayness for any of the
  333. // entry points.
  334. std::unordered_set<Instruction*> vars_without_extra_arrayness;
  335. };
  336. } // namespace opt
  337. } // namespace spvtools
  338. #endif // SOURCE_OPT_INTERFACE_VAR_SROA_H_