1 // Copyright (c) 2017 The Khronos Group Inc. 2 // Copyright (c) 2017 Valve Corporation 3 // Copyright (c) 2017 LunarG Inc. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 #ifndef SOURCE_OPT_LOCAL_ACCESS_CHAIN_CONVERT_PASS_H_ 18 #define SOURCE_OPT_LOCAL_ACCESS_CHAIN_CONVERT_PASS_H_ 19 20 #include <algorithm> 21 #include <map> 22 #include <memory> 23 #include <queue> 24 #include <string> 25 #include <unordered_map> 26 #include <unordered_set> 27 #include <utility> 28 #include <vector> 29 30 #include "source/opt/basic_block.h" 31 #include "source/opt/def_use_manager.h" 32 #include "source/opt/mem_pass.h" 33 #include "source/opt/module.h" 34 35 namespace spvtools { 36 namespace opt { 37 38 // See optimizer.hpp for documentation. 39 class LocalAccessChainConvertPass : public MemPass { 40 public: 41 LocalAccessChainConvertPass(); 42 name()43 const char* name() const override { return "convert-local-access-chains"; } 44 Status Process() override; 45 GetPreservedAnalyses()46 IRContext::Analysis GetPreservedAnalyses() override { 47 return IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants | 48 IRContext::kAnalysisTypes; 49 } 50 51 using ProcessFunction = std::function<bool(Function*)>; 52 53 private: 54 // Return true if all refs through |ptrId| are only loads or stores and 55 // cache ptrId in supported_ref_ptrs_. TODO(dnovillo): This function is 56 // replicated in other passes and it's slightly different in every pass. Is it 57 // possible to make one common implementation? 58 bool HasOnlySupportedRefs(uint32_t ptrId); 59 60 // Search |func| and cache function scope variables of target type that are 61 // not accessed with non-constant-index access chains. Also cache non-target 62 // variables. 63 void FindTargetVars(Function* func); 64 65 // Build instruction from |opcode|, |typeId|, |resultId|, and |in_opnds|. 66 // Append to |newInsts|. 67 void BuildAndAppendInst(SpvOp opcode, uint32_t typeId, uint32_t resultId, 68 const std::vector<Operand>& in_opnds, 69 std::vector<std::unique_ptr<Instruction>>* newInsts); 70 71 // Build load of variable in |ptrInst| and append to |newInsts|. 72 // Return var in |varId| and its pointee type in |varPteTypeId|. 73 uint32_t BuildAndAppendVarLoad( 74 const Instruction* ptrInst, uint32_t* varId, uint32_t* varPteTypeId, 75 std::vector<std::unique_ptr<Instruction>>* newInsts); 76 77 // Append literal integer operands to |in_opnds| corresponding to constant 78 // integer operands from access chain |ptrInst|. Assumes all indices in 79 // access chains are OpConstant. 80 void AppendConstantOperands(const Instruction* ptrInst, 81 std::vector<Operand>* in_opnds); 82 83 // Create a load/insert/store equivalent to a store of 84 // |valId| through (constant index) access chaing |ptrInst|. 85 // Append to |newInsts|. Returns true if successful. 86 bool GenAccessChainStoreReplacement( 87 const Instruction* ptrInst, uint32_t valId, 88 std::vector<std::unique_ptr<Instruction>>* newInsts); 89 90 // For the (constant index) access chain |address_inst|, create an 91 // equivalent load and extract that replaces |original_load|. The result id 92 // of the extract will be the same as the original result id of 93 // |original_load|. Returns true if successful. 94 bool ReplaceAccessChainLoad(const Instruction* address_inst, 95 Instruction* original_load); 96 97 // Return true if all indices of access chain |acp| are OpConstant integers 98 bool IsConstantIndexAccessChain(const Instruction* acp) const; 99 100 // Identify all function scope variables of target type which are 101 // accessed only with loads, stores and access chains with constant 102 // indices. Convert all loads and stores of such variables into equivalent 103 // loads, stores, extracts and inserts. This unifies access to these 104 // variables to a single mode and simplifies analysis and optimization. 105 // See IsTargetType() for targeted types. 106 // 107 // Nested access chains and pointer access chains are not currently 108 // converted. 109 // 110 // Returns a status to indicate success or failure, and change or no change. 111 Status ConvertLocalAccessChains(Function* func); 112 113 // Initialize extensions allowlist 114 void InitExtensions(); 115 116 // Return true if all extensions in this module are allowed by this pass. 117 bool AllExtensionsSupported() const; 118 119 void Initialize(); 120 Pass::Status ProcessImpl(); 121 122 // Variables with only supported references, ie. loads and stores using 123 // variable directly or through non-ptr access chains. 124 std::unordered_set<uint32_t> supported_ref_ptrs_; 125 126 // Extensions supported by this pass. 127 std::unordered_set<std::string> extensions_allowlist_; 128 }; 129 130 } // namespace opt 131 } // namespace spvtools 132 133 #endif // SOURCE_OPT_LOCAL_ACCESS_CHAIN_CONVERT_PASS_H_ 134