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