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