/src/spirv-tools/source/opt/def_use_manager.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 88.6M | void DefUseManager::AnalyzeInstDef(Instruction* inst) { |
22 | 88.6M | const uint32_t def_id = inst->result_id(); |
23 | 88.6M | if (def_id != 0) { |
24 | 60.6M | auto iter = id_to_def_.find(def_id); |
25 | 60.6M | if (iter != id_to_def_.end()) { |
26 | | // Clear the original instruction that defining the same result id of the |
27 | | // new instruction. |
28 | 8.57k | ClearInst(iter->second); |
29 | 8.57k | } |
30 | 60.6M | id_to_def_[def_id] = inst; |
31 | 60.6M | } else { |
32 | 27.9M | ClearInst(inst); |
33 | 27.9M | } |
34 | 88.6M | } |
35 | | |
36 | 97.4M | 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 | 97.4M | auto* used_ids = &inst_to_used_ids_[inst]; |
41 | 97.4M | if (used_ids->size()) { |
42 | 5.25M | EraseUseRecordsOfOperandIds(inst); |
43 | 5.25M | used_ids = &inst_to_used_ids_[inst]; |
44 | 5.25M | } |
45 | 97.4M | used_ids->clear(); // It might have existed before. |
46 | | |
47 | 366M | for (uint32_t i = 0; i < inst->NumOperands(); ++i) { |
48 | 269M | switch (inst->GetOperand(i).type) { |
49 | | // For any id type but result id type |
50 | 131M | case SPV_OPERAND_TYPE_ID: |
51 | 179M | case SPV_OPERAND_TYPE_TYPE_ID: |
52 | 179M | case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: |
53 | 179M | case SPV_OPERAND_TYPE_SCOPE_ID: { |
54 | 179M | uint32_t use_id = inst->GetSingleWordOperand(i); |
55 | 179M | Instruction* def = GetDef(use_id); |
56 | 179M | assert(def && "Definition is not registered."); |
57 | 0 | id_to_users_.insert(UserEntry{def, inst}); |
58 | 179M | used_ids->push_back(use_id); |
59 | 179M | } break; |
60 | 89.3M | default: |
61 | 89.3M | break; |
62 | 269M | } |
63 | 269M | } |
64 | 97.4M | } |
65 | | |
66 | 1.38M | void DefUseManager::AnalyzeInstDefUse(Instruction* inst) { |
67 | 1.38M | AnalyzeInstDef(inst); |
68 | 1.38M | AnalyzeInstUse(inst); |
69 | | // Analyze lines last otherwise they will be cleared when inst is |
70 | | // cleared by preceding two calls |
71 | 1.38M | for (auto& l_inst : inst->dbg_line_insts()) AnalyzeInstDefUse(&l_inst); |
72 | 1.38M | } |
73 | | |
74 | 705k | void DefUseManager::UpdateDefUse(Instruction* inst) { |
75 | 705k | const uint32_t def_id = inst->result_id(); |
76 | 705k | if (def_id != 0) { |
77 | 532k | auto iter = id_to_def_.find(def_id); |
78 | 532k | if (iter == id_to_def_.end()) { |
79 | 0 | AnalyzeInstDef(inst); |
80 | 0 | } |
81 | 532k | } |
82 | 705k | AnalyzeInstUse(inst); |
83 | 705k | } |
84 | | |
85 | 312M | Instruction* DefUseManager::GetDef(uint32_t id) { |
86 | 312M | auto iter = id_to_def_.find(id); |
87 | 312M | if (iter == id_to_def_.end()) return nullptr; |
88 | 305M | return iter->second; |
89 | 312M | } |
90 | | |
91 | 17.4M | const Instruction* DefUseManager::GetDef(uint32_t id) const { |
92 | 17.4M | const auto iter = id_to_def_.find(id); |
93 | 17.4M | if (iter == id_to_def_.end()) return nullptr; |
94 | 17.4M | return iter->second; |
95 | 17.4M | } |
96 | | |
97 | | DefUseManager::IdToUsersMap::const_iterator DefUseManager::UsersBegin( |
98 | 13.5M | const Instruction* def) const { |
99 | 13.5M | return id_to_users_.lower_bound( |
100 | 13.5M | UserEntry{const_cast<Instruction*>(def), nullptr}); |
101 | 13.5M | } |
102 | | |
103 | | bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter, |
104 | | const IdToUsersMap::const_iterator& cached_end, |
105 | 34.9M | const Instruction* inst) const { |
106 | 34.9M | return (iter != cached_end && iter->def == inst); |
107 | 34.9M | } |
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 | 5.45M | const Instruction* def, const std::function<bool(Instruction*)>& f) const { |
116 | | // Ensure that |def| has been registered. |
117 | 5.45M | assert(def && (!def->HasResultId() || def == GetDef(def->result_id())) && |
118 | 5.45M | "Definition is not registered."); |
119 | 5.45M | if (!def->HasResultId()) return true; |
120 | | |
121 | 5.44M | auto end = id_to_users_.end(); |
122 | 20.8M | for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) { |
123 | 15.4M | if (!f(iter->user)) return false; |
124 | 15.4M | } |
125 | 5.31M | return true; |
126 | 5.44M | } |
127 | | |
128 | | bool DefUseManager::WhileEachUser( |
129 | 1.05M | uint32_t id, const std::function<bool(Instruction*)>& f) const { |
130 | 1.05M | return WhileEachUser(GetDef(id), f); |
131 | 1.05M | } |
132 | | |
133 | | void DefUseManager::ForEachUser( |
134 | 4.21M | const Instruction* def, const std::function<void(Instruction*)>& f) const { |
135 | 9.25M | WhileEachUser(def, [&f](Instruction* user) { |
136 | 9.25M | f(user); |
137 | 9.25M | return true; |
138 | 9.25M | }); |
139 | 4.21M | } |
140 | | |
141 | | void DefUseManager::ForEachUser( |
142 | 2.43M | uint32_t id, const std::function<void(Instruction*)>& f) const { |
143 | 2.43M | ForEachUser(GetDef(id), f); |
144 | 2.43M | } |
145 | | |
146 | | bool DefUseManager::WhileEachUse( |
147 | | const Instruction* def, |
148 | 4.45M | const std::function<bool(Instruction*, uint32_t)>& f) const { |
149 | | // Ensure that |def| has been registered. |
150 | 4.45M | assert(def && (!def->HasResultId() || def == GetDef(def->result_id())) && |
151 | 4.45M | "Definition is not registered."); |
152 | 4.45M | if (!def->HasResultId()) return true; |
153 | | |
154 | 4.45M | auto end = id_to_users_.end(); |
155 | 9.03M | for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) { |
156 | 4.62M | Instruction* user = iter->user; |
157 | 21.4M | for (uint32_t idx = 0; idx != user->NumOperands(); ++idx) { |
158 | 16.8M | const Operand& op = user->GetOperand(idx); |
159 | 16.8M | if (op.type != SPV_OPERAND_TYPE_RESULT_ID && spvIsIdType(op.type)) { |
160 | 14.0M | if (def->result_id() == op.words[0]) { |
161 | 4.65M | if (!f(user, idx)) return false; |
162 | 4.65M | } |
163 | 14.0M | } |
164 | 16.8M | } |
165 | 4.62M | } |
166 | 4.41M | return true; |
167 | 4.45M | } |
168 | | |
169 | | bool DefUseManager::WhileEachUse( |
170 | 1.95M | uint32_t id, const std::function<bool(Instruction*, uint32_t)>& f) const { |
171 | 1.95M | return WhileEachUse(GetDef(id), f); |
172 | 1.95M | } |
173 | | |
174 | | void DefUseManager::ForEachUse( |
175 | | const Instruction* def, |
176 | 2.49M | const std::function<void(Instruction*, uint32_t)>& f) const { |
177 | 3.15M | WhileEachUse(def, [&f](Instruction* user, uint32_t index) { |
178 | 3.15M | f(user, index); |
179 | 3.15M | return true; |
180 | 3.15M | }); |
181 | 2.49M | } |
182 | | |
183 | | void DefUseManager::ForEachUse( |
184 | 2.12M | uint32_t id, const std::function<void(Instruction*, uint32_t)>& f) const { |
185 | 2.12M | ForEachUse(GetDef(id), f); |
186 | 2.12M | } |
187 | | |
188 | 56.4k | uint32_t DefUseManager::NumUsers(const Instruction* def) const { |
189 | 56.4k | uint32_t count = 0; |
190 | 161k | ForEachUser(def, [&count](Instruction*) { ++count; }); |
191 | 56.4k | return count; |
192 | 56.4k | } |
193 | | |
194 | 0 | uint32_t DefUseManager::NumUsers(uint32_t id) const { |
195 | 0 | return NumUsers(GetDef(id)); |
196 | 0 | } |
197 | | |
198 | 577 | uint32_t DefUseManager::NumUses(const Instruction* def) const { |
199 | 577 | uint32_t count = 0; |
200 | 904 | ForEachUse(def, [&count](Instruction*, uint32_t) { ++count; }); |
201 | 577 | return count; |
202 | 577 | } |
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 | 318k | void DefUseManager::AnalyzeDefUse(Module* module) { |
222 | 318k | if (!module) return; |
223 | | // Analyze all the defs before any uses to catch forward references. |
224 | 318k | module->ForEachInst( |
225 | 318k | std::bind(&DefUseManager::AnalyzeInstDef, this, std::placeholders::_1), |
226 | 318k | true); |
227 | 318k | module->ForEachInst( |
228 | 318k | std::bind(&DefUseManager::AnalyzeInstUse, this, std::placeholders::_1), |
229 | 318k | true); |
230 | 318k | } |
231 | | |
232 | 32.9M | void DefUseManager::ClearInst(Instruction* inst) { |
233 | 32.9M | auto iter = inst_to_used_ids_.find(inst); |
234 | 32.9M | if (iter != inst_to_used_ids_.end()) { |
235 | 4.88M | EraseUseRecordsOfOperandIds(inst); |
236 | 4.88M | if (inst->result_id() != 0) { |
237 | | // Remove all uses of this inst. |
238 | 3.65M | auto users_begin = UsersBegin(inst); |
239 | 3.65M | auto end = id_to_users_.end(); |
240 | 3.65M | auto new_end = users_begin; |
241 | 5.15M | for (; UsersNotEnd(new_end, end, inst); ++new_end) { |
242 | 1.49M | } |
243 | 3.65M | id_to_users_.erase(users_begin, new_end); |
244 | 3.65M | id_to_def_.erase(inst->result_id()); |
245 | 3.65M | } |
246 | 4.88M | } |
247 | 32.9M | } |
248 | | |
249 | 12.8M | void DefUseManager::EraseUseRecordsOfOperandIds(const Instruction* inst) { |
250 | | // Go through all ids used by this instruction, remove this instruction's |
251 | | // uses of them. |
252 | 12.8M | auto iter = inst_to_used_ids_.find(inst); |
253 | 12.8M | if (iter != inst_to_used_ids_.end()) { |
254 | 34.4M | for (auto use_id : iter->second) { |
255 | 34.4M | id_to_users_.erase( |
256 | 34.4M | UserEntry{GetDef(use_id), const_cast<Instruction*>(inst)}); |
257 | 34.4M | } |
258 | 12.8M | inst_to_used_ids_.erase(iter); |
259 | 12.8M | } |
260 | 12.8M | } |
261 | | |
262 | | bool CompareAndPrintDifferences(const DefUseManager& lhs, |
263 | 298k | const DefUseManager& rhs) { |
264 | 298k | bool same = true; |
265 | | |
266 | 298k | 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 | 298k | 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 | 298k | 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 | 298k | return same; |
309 | 298k | } |
310 | | |
311 | | } // namespace analysis |
312 | | } // namespace opt |
313 | | } // namespace spvtools |