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 | |
43 | const char* name() const override { return "convert-local-access-chains" ; } |
44 | Status Process() override; |
45 | |
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 whitelist |
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_whitelist_; |
128 | }; |
129 | |
130 | } // namespace opt |
131 | } // namespace spvtools |
132 | |
133 | #endif // SOURCE_OPT_LOCAL_ACCESS_CHAIN_CONVERT_PASS_H_ |
134 | |