/src/spirv-tools/source/opt/def_use_manager.cpp
Line | Count | Source |
1 | | // Copyright (c) 2016 Google Inc. |
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 | | |
15 | | #include "source/opt/def_use_manager.h" |
16 | | |
17 | | namespace spvtools { |
18 | | namespace opt { |
19 | | namespace analysis { |
20 | | |
21 | 163M | void DefUseManager::AnalyzeInstDef(Instruction* inst) { |
22 | 163M | const uint32_t def_id = inst->result_id(); |
23 | 163M | if (def_id != 0) { |
24 | 110M | auto iter = id_to_def_.find(def_id); |
25 | 110M | if (iter != id_to_def_.end()) { |
26 | | // Clear the original instruction that defining the same result id of the |
27 | | // new instruction. |
28 | 12.6k | ClearInst(iter->second); |
29 | 12.6k | } |
30 | 110M | id_to_def_[def_id] = inst; |
31 | 110M | } else { |
32 | 53.2M | ClearInst(inst); |
33 | 53.2M | } |
34 | 163M | } |
35 | | |
36 | 181M | void DefUseManager::AnalyzeInstUse(Instruction* inst) { |
37 | | // Create entry for the given instruction. Note that the instruction may |
38 | | // not have any in-operands. In such cases, we still need a entry for those |
39 | | // instructions so this manager knows it has seen the instruction later. |
40 | 181M | auto* used_ids = &inst_to_used_ids_[inst]; |
41 | 181M | if (used_ids->size()) { |
42 | 11.0M | EraseUseRecordsOfOperandIds(inst); |
43 | 11.0M | used_ids = &inst_to_used_ids_[inst]; |
44 | 11.0M | } |
45 | 181M | used_ids->clear(); // It might have existed before. |
46 | | |
47 | 677M | for (uint32_t i = 0; i < inst->NumOperands(); ++i) { |
48 | 496M | switch (inst->GetOperand(i).type) { |
49 | | // For any id type but result id type |
50 | 239M | case SPV_OPERAND_TYPE_ID: |
51 | 328M | case SPV_OPERAND_TYPE_TYPE_ID: |
52 | 328M | case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: |
53 | 328M | case SPV_OPERAND_TYPE_SCOPE_ID: { |
54 | 328M | uint32_t use_id = inst->GetSingleWordOperand(i); |
55 | 328M | Instruction* def = GetDef(use_id); |
56 | 328M | assert(def && "Definition is not registered."); |
57 | 328M | id_to_users_.insert(UserEntry{def, inst}); |
58 | 328M | used_ids->push_back(use_id); |
59 | 328M | } break; |
60 | 167M | default: |
61 | 167M | break; |
62 | 496M | } |
63 | 496M | } |
64 | 181M | } |
65 | | |
66 | 2.54M | void DefUseManager::AnalyzeInstDefUse(Instruction* inst) { |
67 | 2.54M | AnalyzeInstDef(inst); |
68 | 2.54M | AnalyzeInstUse(inst); |
69 | | // Analyze lines last otherwise they will be cleared when inst is |
70 | | // cleared by preceding two calls |
71 | 2.54M | for (auto& l_inst : inst->dbg_line_insts()) AnalyzeInstDefUse(&l_inst); |
72 | 2.54M | } |
73 | | |
74 | 2.21M | void DefUseManager::UpdateDefUse(Instruction* inst) { |
75 | 2.21M | const uint32_t def_id = inst->result_id(); |
76 | 2.21M | if (def_id != 0) { |
77 | 1.90M | auto iter = id_to_def_.find(def_id); |
78 | 1.90M | if (iter == id_to_def_.end()) { |
79 | 0 | AnalyzeInstDef(inst); |
80 | 0 | } |
81 | 1.90M | } |
82 | 2.21M | AnalyzeInstUse(inst); |
83 | 2.21M | } |
84 | | |
85 | 568M | Instruction* DefUseManager::GetDef(uint32_t id) { |
86 | 568M | auto iter = id_to_def_.find(id); |
87 | 568M | if (iter == id_to_def_.end()) return nullptr; |
88 | 556M | return iter->second; |
89 | 568M | } |
90 | | |
91 | 31.0M | const Instruction* DefUseManager::GetDef(uint32_t id) const { |
92 | 31.0M | const auto iter = id_to_def_.find(id); |
93 | 31.0M | if (iter == id_to_def_.end()) return nullptr; |
94 | 31.0M | return iter->second; |
95 | 31.0M | } |
96 | | |
97 | | DefUseManager::IdToUsersMap::const_iterator DefUseManager::UsersBegin( |
98 | 24.9M | const Instruction* def) const { |
99 | 24.9M | return id_to_users_.lower_bound( |
100 | 24.9M | UserEntry{const_cast<Instruction*>(def), nullptr}); |
101 | 24.9M | } |
102 | | |
103 | | bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter, |
104 | | const IdToUsersMap::const_iterator& cached_end, |
105 | 63.6M | const Instruction* inst) const { |
106 | 63.6M | return (iter != cached_end && iter->def == inst); |
107 | 63.6M | } |
108 | | |
109 | | bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter, |
110 | 0 | const Instruction* inst) const { |
111 | 0 | return UsersNotEnd(iter, id_to_users_.end(), inst); |
112 | 0 | } |
113 | | |
114 | | bool DefUseManager::WhileEachUser( |
115 | 9.55M | const Instruction* def, const std::function<bool(Instruction*)>& f) const { |
116 | | // Ensure that |def| has been registered. |
117 | 9.55M | assert(def && (!def->HasResultId() || def == GetDef(def->result_id())) && |
118 | 9.55M | "Definition is not registered."); |
119 | 9.55M | if (!def->HasResultId()) return true; |
120 | | |
121 | 9.53M | auto end = id_to_users_.end(); |
122 | 37.0M | for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) { |
123 | 27.8M | if (!f(iter->user)) return false; |
124 | 27.8M | } |
125 | 9.25M | return true; |
126 | 9.53M | } |
127 | | |
128 | | bool DefUseManager::WhileEachUser( |
129 | 1.63M | uint32_t id, const std::function<bool(Instruction*)>& f) const { |
130 | 1.63M | return WhileEachUser(GetDef(id), f); |
131 | 1.63M | } |
132 | | |
133 | | void DefUseManager::ForEachUser( |
134 | 7.46M | const Instruction* def, const std::function<void(Instruction*)>& f) const { |
135 | 15.2M | WhileEachUser(def, [&f](Instruction* user) { |
136 | 15.2M | f(user); |
137 | 15.2M | return true; |
138 | 15.2M | }); |
139 | 7.46M | } |
140 | | |
141 | | void DefUseManager::ForEachUser( |
142 | 3.95M | uint32_t id, const std::function<void(Instruction*)>& f) const { |
143 | 3.95M | ForEachUser(GetDef(id), f); |
144 | 3.95M | } |
145 | | |
146 | | bool DefUseManager::WhileEachUse( |
147 | | const Instruction* def, |
148 | 8.21M | const std::function<bool(Instruction*, uint32_t)>& f) const { |
149 | | // Ensure that |def| has been registered. |
150 | 8.21M | assert(def && (!def->HasResultId() || def == GetDef(def->result_id())) && |
151 | 8.21M | "Definition is not registered."); |
152 | 8.21M | if (!def->HasResultId()) return true; |
153 | | |
154 | 8.21M | auto end = id_to_users_.end(); |
155 | 16.5M | for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) { |
156 | 8.48M | Instruction* user = iter->user; |
157 | 40.8M | for (uint32_t idx = 0; idx != user->NumOperands(); ++idx) { |
158 | 32.4M | const Operand& op = user->GetOperand(idx); |
159 | 32.4M | if (op.type != SPV_OPERAND_TYPE_RESULT_ID && spvIsIdType(op.type)) { |
160 | 27.1M | if (def->result_id() == op.words[0]) { |
161 | 8.63M | if (!f(user, idx)) return false; |
162 | 8.63M | } |
163 | 27.1M | } |
164 | 32.4M | } |
165 | 8.48M | } |
166 | 8.07M | return true; |
167 | 8.21M | } |
168 | | |
169 | | bool DefUseManager::WhileEachUse( |
170 | 3.68M | uint32_t id, const std::function<bool(Instruction*, uint32_t)>& f) const { |
171 | 3.68M | return WhileEachUse(GetDef(id), f); |
172 | 3.68M | } |
173 | | |
174 | | void DefUseManager::ForEachUse( |
175 | | const Instruction* def, |
176 | 4.52M | const std::function<void(Instruction*, uint32_t)>& f) const { |
177 | 5.68M | WhileEachUse(def, [&f](Instruction* user, uint32_t index) { |
178 | 5.68M | f(user, index); |
179 | 5.68M | return true; |
180 | 5.68M | }); |
181 | 4.52M | } |
182 | | |
183 | | void DefUseManager::ForEachUse( |
184 | 3.99M | uint32_t id, const std::function<void(Instruction*, uint32_t)>& f) const { |
185 | 3.99M | ForEachUse(GetDef(id), f); |
186 | 3.99M | } |
187 | | |
188 | 96.9k | uint32_t DefUseManager::NumUsers(const Instruction* def) const { |
189 | 96.9k | uint32_t count = 0; |
190 | 285k | ForEachUser(def, [&count](Instruction*) { ++count; }); |
191 | 96.9k | return count; |
192 | 96.9k | } |
193 | | |
194 | 0 | uint32_t DefUseManager::NumUsers(uint32_t id) const { |
195 | 0 | return NumUsers(GetDef(id)); |
196 | 0 | } |
197 | | |
198 | 19.0k | uint32_t DefUseManager::NumUses(const Instruction* def) const { |
199 | 19.0k | uint32_t count = 0; |
200 | 116k | ForEachUse(def, [&count](Instruction*, uint32_t) { ++count; }); |
201 | 19.0k | return count; |
202 | 19.0k | } |
203 | | |
204 | 0 | uint32_t DefUseManager::NumUses(uint32_t id) const { |
205 | 0 | return NumUses(GetDef(id)); |
206 | 0 | } |
207 | | |
208 | 0 | std::vector<Instruction*> DefUseManager::GetAnnotations(uint32_t id) const { |
209 | 0 | std::vector<Instruction*> annos; |
210 | 0 | const Instruction* def = GetDef(id); |
211 | 0 | if (!def) return annos; |
212 | | |
213 | 0 | ForEachUser(def, [&annos](Instruction* user) { |
214 | 0 | if (IsAnnotationInst(user->opcode())) { |
215 | 0 | annos.push_back(user); |
216 | 0 | } |
217 | 0 | }); |
218 | 0 | return annos; |
219 | 0 | } |
220 | | |
221 | 591k | void DefUseManager::AnalyzeDefUse(Module* module) { |
222 | 591k | if (!module) return; |
223 | | // Analyze all the defs before any uses to catch forward references. |
224 | 591k | module->ForEachInst( |
225 | 591k | std::bind(&DefUseManager::AnalyzeInstDef, this, std::placeholders::_1), |
226 | 591k | true); |
227 | 591k | module->ForEachInst( |
228 | 591k | std::bind(&DefUseManager::AnalyzeInstUse, this, std::placeholders::_1), |
229 | 591k | true); |
230 | 591k | } |
231 | | |
232 | 63.0M | void DefUseManager::ClearInst(Instruction* inst) { |
233 | 63.0M | auto iter = inst_to_used_ids_.find(inst); |
234 | 63.0M | if (iter != inst_to_used_ids_.end()) { |
235 | 9.61M | EraseUseRecordsOfOperandIds(inst); |
236 | 9.61M | if (inst->result_id() != 0) { |
237 | | // Remove all uses of this inst. |
238 | 7.18M | auto users_begin = UsersBegin(inst); |
239 | 7.18M | auto end = id_to_users_.end(); |
240 | 7.18M | auto new_end = users_begin; |
241 | 9.99M | for (; UsersNotEnd(new_end, end, inst); ++new_end) { |
242 | 2.80M | } |
243 | 7.18M | id_to_users_.erase(users_begin, new_end); |
244 | 7.18M | id_to_def_.erase(inst->result_id()); |
245 | 7.18M | } |
246 | 9.61M | } |
247 | 63.0M | } |
248 | | |
249 | 25.4M | void DefUseManager::EraseUseRecordsOfOperandIds(const Instruction* inst) { |
250 | | // Go through all ids used by this instruction, remove this instruction's |
251 | | // uses of them. |
252 | 25.4M | auto iter = inst_to_used_ids_.find(inst); |
253 | 25.4M | if (iter != inst_to_used_ids_.end()) { |
254 | 68.0M | for (auto use_id : iter->second) { |
255 | 68.0M | id_to_users_.erase( |
256 | 68.0M | UserEntry{GetDef(use_id), const_cast<Instruction*>(inst)}); |
257 | 68.0M | } |
258 | 25.4M | inst_to_used_ids_.erase(iter); |
259 | 25.4M | } |
260 | 25.4M | } |
261 | | |
262 | | bool CompareAndPrintDifferences(const DefUseManager& lhs, |
263 | 554k | const DefUseManager& rhs) { |
264 | 554k | bool same = true; |
265 | | |
266 | 554k | if (lhs.id_to_def_ != rhs.id_to_def_) { |
267 | 0 | for (auto p : lhs.id_to_def_) { |
268 | 0 | if (rhs.id_to_def_.find(p.first) == rhs.id_to_def_.end()) { |
269 | 0 | printf("Diff in id_to_def: missing value in rhs\n"); |
270 | 0 | } |
271 | 0 | } |
272 | 0 | for (auto p : rhs.id_to_def_) { |
273 | 0 | if (lhs.id_to_def_.find(p.first) == lhs.id_to_def_.end()) { |
274 | 0 | printf("Diff in id_to_def: missing value in lhs\n"); |
275 | 0 | } |
276 | 0 | } |
277 | 0 | same = false; |
278 | 0 | } |
279 | | |
280 | 554k | if (lhs.id_to_users_ != rhs.id_to_users_) { |
281 | 0 | for (auto p : lhs.id_to_users_) { |
282 | 0 | if (rhs.id_to_users_.count(p) == 0) { |
283 | 0 | printf("Diff in id_to_users: missing value in rhs\n"); |
284 | 0 | } |
285 | 0 | } |
286 | 0 | for (auto p : rhs.id_to_users_) { |
287 | 0 | if (lhs.id_to_users_.count(p) == 0) { |
288 | 0 | printf("Diff in id_to_users: missing value in lhs\n"); |
289 | 0 | } |
290 | 0 | } |
291 | 0 | same = false; |
292 | 0 | } |
293 | | |
294 | 554k | if (lhs.inst_to_used_ids_ != rhs.inst_to_used_ids_) { |
295 | 0 | for (auto p : lhs.inst_to_used_ids_) { |
296 | 0 | if (rhs.inst_to_used_ids_.count(p.first) == 0) { |
297 | 0 | printf("Diff in inst_to_used_ids: missing value in rhs\n"); |
298 | 0 | } |
299 | 0 | } |
300 | 0 | for (auto p : rhs.inst_to_used_ids_) { |
301 | 0 | if (lhs.inst_to_used_ids_.count(p.first) == 0) { |
302 | 0 | printf("Diff in inst_to_used_ids: missing value in lhs\n"); |
303 | 0 | } |
304 | 0 | } |
305 | 0 | same = false; |
306 | 0 | } |
307 | | |
308 | 554k | return same; |
309 | 554k | } |
310 | | |
311 | | } // namespace analysis |
312 | | } // namespace opt |
313 | | } // namespace spvtools |