• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AnalyzeInstDef(Instruction * inst)21 void DefUseManager::AnalyzeInstDef(Instruction* inst) {
22   const uint32_t def_id = inst->result_id();
23   if (def_id != 0) {
24     auto iter = id_to_def_.find(def_id);
25     if (iter != id_to_def_.end()) {
26       // Clear the original instruction that defining the same result id of the
27       // new instruction.
28       ClearInst(iter->second);
29     }
30     id_to_def_[def_id] = inst;
31   } else {
32     ClearInst(inst);
33   }
34 }
35 
AnalyzeInstUse(Instruction * inst)36 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   auto* used_ids = &inst_to_used_ids_[inst];
41   if (used_ids->size()) {
42     EraseUseRecordsOfOperandIds(inst);
43     used_ids = &inst_to_used_ids_[inst];
44   }
45   used_ids->clear();  // It might have existed before.
46 
47   for (uint32_t i = 0; i < inst->NumOperands(); ++i) {
48     switch (inst->GetOperand(i).type) {
49       // For any id type but result id type
50       case SPV_OPERAND_TYPE_ID:
51       case SPV_OPERAND_TYPE_TYPE_ID:
52       case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID:
53       case SPV_OPERAND_TYPE_SCOPE_ID: {
54         uint32_t use_id = inst->GetSingleWordOperand(i);
55         Instruction* def = GetDef(use_id);
56         assert(def && "Definition is not registered.");
57         id_to_users_.insert(UserEntry{def, inst});
58         used_ids->push_back(use_id);
59       } break;
60       default:
61         break;
62     }
63   }
64 }
65 
AnalyzeInstDefUse(Instruction * inst)66 void DefUseManager::AnalyzeInstDefUse(Instruction* inst) {
67   AnalyzeInstDef(inst);
68   AnalyzeInstUse(inst);
69   // Analyze lines last otherwise they will be cleared when inst is
70   // cleared by preceding two calls
71   for (auto& l_inst : inst->dbg_line_insts()) AnalyzeInstDefUse(&l_inst);
72 }
73 
UpdateDefUse(Instruction * inst)74 void DefUseManager::UpdateDefUse(Instruction* inst) {
75   const uint32_t def_id = inst->result_id();
76   if (def_id != 0) {
77     auto iter = id_to_def_.find(def_id);
78     if (iter == id_to_def_.end()) {
79       AnalyzeInstDef(inst);
80     }
81   }
82   AnalyzeInstUse(inst);
83 }
84 
GetDef(uint32_t id)85 Instruction* DefUseManager::GetDef(uint32_t id) {
86   auto iter = id_to_def_.find(id);
87   if (iter == id_to_def_.end()) return nullptr;
88   return iter->second;
89 }
90 
GetDef(uint32_t id) const91 const Instruction* DefUseManager::GetDef(uint32_t id) const {
92   const auto iter = id_to_def_.find(id);
93   if (iter == id_to_def_.end()) return nullptr;
94   return iter->second;
95 }
96 
UsersBegin(const Instruction * def) const97 DefUseManager::IdToUsersMap::const_iterator DefUseManager::UsersBegin(
98     const Instruction* def) const {
99   return id_to_users_.lower_bound(
100       UserEntry{const_cast<Instruction*>(def), nullptr});
101 }
102 
UsersNotEnd(const IdToUsersMap::const_iterator & iter,const IdToUsersMap::const_iterator & cached_end,const Instruction * inst) const103 bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter,
104                                 const IdToUsersMap::const_iterator& cached_end,
105                                 const Instruction* inst) const {
106   return (iter != cached_end && iter->def == inst);
107 }
108 
UsersNotEnd(const IdToUsersMap::const_iterator & iter,const Instruction * inst) const109 bool DefUseManager::UsersNotEnd(const IdToUsersMap::const_iterator& iter,
110                                 const Instruction* inst) const {
111   return UsersNotEnd(iter, id_to_users_.end(), inst);
112 }
113 
WhileEachUser(const Instruction * def,const std::function<bool (Instruction *)> & f) const114 bool DefUseManager::WhileEachUser(
115     const Instruction* def, const std::function<bool(Instruction*)>& f) const {
116   // Ensure that |def| has been registered.
117   assert(def && (!def->HasResultId() || def == GetDef(def->result_id())) &&
118          "Definition is not registered.");
119   if (!def->HasResultId()) return true;
120 
121   auto end = id_to_users_.end();
122   for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) {
123     if (!f(iter->user)) return false;
124   }
125   return true;
126 }
127 
WhileEachUser(uint32_t id,const std::function<bool (Instruction *)> & f) const128 bool DefUseManager::WhileEachUser(
129     uint32_t id, const std::function<bool(Instruction*)>& f) const {
130   return WhileEachUser(GetDef(id), f);
131 }
132 
ForEachUser(const Instruction * def,const std::function<void (Instruction *)> & f) const133 void DefUseManager::ForEachUser(
134     const Instruction* def, const std::function<void(Instruction*)>& f) const {
135   WhileEachUser(def, [&f](Instruction* user) {
136     f(user);
137     return true;
138   });
139 }
140 
ForEachUser(uint32_t id,const std::function<void (Instruction *)> & f) const141 void DefUseManager::ForEachUser(
142     uint32_t id, const std::function<void(Instruction*)>& f) const {
143   ForEachUser(GetDef(id), f);
144 }
145 
WhileEachUse(const Instruction * def,const std::function<bool (Instruction *,uint32_t)> & f) const146 bool DefUseManager::WhileEachUse(
147     const Instruction* def,
148     const std::function<bool(Instruction*, uint32_t)>& f) const {
149   // Ensure that |def| has been registered.
150   assert(def && (!def->HasResultId() || def == GetDef(def->result_id())) &&
151          "Definition is not registered.");
152   if (!def->HasResultId()) return true;
153 
154   auto end = id_to_users_.end();
155   for (auto iter = UsersBegin(def); UsersNotEnd(iter, end, def); ++iter) {
156     Instruction* user = iter->user;
157     for (uint32_t idx = 0; idx != user->NumOperands(); ++idx) {
158       const Operand& op = user->GetOperand(idx);
159       if (op.type != SPV_OPERAND_TYPE_RESULT_ID && spvIsIdType(op.type)) {
160         if (def->result_id() == op.words[0]) {
161           if (!f(user, idx)) return false;
162         }
163       }
164     }
165   }
166   return true;
167 }
168 
WhileEachUse(uint32_t id,const std::function<bool (Instruction *,uint32_t)> & f) const169 bool DefUseManager::WhileEachUse(
170     uint32_t id, const std::function<bool(Instruction*, uint32_t)>& f) const {
171   return WhileEachUse(GetDef(id), f);
172 }
173 
ForEachUse(const Instruction * def,const std::function<void (Instruction *,uint32_t)> & f) const174 void DefUseManager::ForEachUse(
175     const Instruction* def,
176     const std::function<void(Instruction*, uint32_t)>& f) const {
177   WhileEachUse(def, [&f](Instruction* user, uint32_t index) {
178     f(user, index);
179     return true;
180   });
181 }
182 
ForEachUse(uint32_t id,const std::function<void (Instruction *,uint32_t)> & f) const183 void DefUseManager::ForEachUse(
184     uint32_t id, const std::function<void(Instruction*, uint32_t)>& f) const {
185   ForEachUse(GetDef(id), f);
186 }
187 
NumUsers(const Instruction * def) const188 uint32_t DefUseManager::NumUsers(const Instruction* def) const {
189   uint32_t count = 0;
190   ForEachUser(def, [&count](Instruction*) { ++count; });
191   return count;
192 }
193 
NumUsers(uint32_t id) const194 uint32_t DefUseManager::NumUsers(uint32_t id) const {
195   return NumUsers(GetDef(id));
196 }
197 
NumUses(const Instruction * def) const198 uint32_t DefUseManager::NumUses(const Instruction* def) const {
199   uint32_t count = 0;
200   ForEachUse(def, [&count](Instruction*, uint32_t) { ++count; });
201   return count;
202 }
203 
NumUses(uint32_t id) const204 uint32_t DefUseManager::NumUses(uint32_t id) const {
205   return NumUses(GetDef(id));
206 }
207 
GetAnnotations(uint32_t id) const208 std::vector<Instruction*> DefUseManager::GetAnnotations(uint32_t id) const {
209   std::vector<Instruction*> annos;
210   const Instruction* def = GetDef(id);
211   if (!def) return annos;
212 
213   ForEachUser(def, [&annos](Instruction* user) {
214     if (IsAnnotationInst(user->opcode())) {
215       annos.push_back(user);
216     }
217   });
218   return annos;
219 }
220 
AnalyzeDefUse(Module * module)221 void DefUseManager::AnalyzeDefUse(Module* module) {
222   if (!module) return;
223   // Analyze all the defs before any uses to catch forward references.
224   module->ForEachInst(
225       std::bind(&DefUseManager::AnalyzeInstDef, this, std::placeholders::_1),
226       true);
227   module->ForEachInst(
228       std::bind(&DefUseManager::AnalyzeInstUse, this, std::placeholders::_1),
229       true);
230 }
231 
ClearInst(Instruction * inst)232 void DefUseManager::ClearInst(Instruction* inst) {
233   auto iter = inst_to_used_ids_.find(inst);
234   if (iter != inst_to_used_ids_.end()) {
235     EraseUseRecordsOfOperandIds(inst);
236     if (inst->result_id() != 0) {
237       // Remove all uses of this inst.
238       auto users_begin = UsersBegin(inst);
239       auto end = id_to_users_.end();
240       auto new_end = users_begin;
241       for (; UsersNotEnd(new_end, end, inst); ++new_end) {
242       }
243       id_to_users_.erase(users_begin, new_end);
244       id_to_def_.erase(inst->result_id());
245     }
246   }
247 }
248 
EraseUseRecordsOfOperandIds(const Instruction * inst)249 void DefUseManager::EraseUseRecordsOfOperandIds(const Instruction* inst) {
250   // Go through all ids used by this instruction, remove this instruction's
251   // uses of them.
252   auto iter = inst_to_used_ids_.find(inst);
253   if (iter != inst_to_used_ids_.end()) {
254     for (auto use_id : iter->second) {
255       id_to_users_.erase(
256           UserEntry{GetDef(use_id), const_cast<Instruction*>(inst)});
257     }
258     inst_to_used_ids_.erase(iter);
259   }
260 }
261 
CompareAndPrintDifferences(const DefUseManager & lhs,const DefUseManager & rhs)262 bool CompareAndPrintDifferences(const DefUseManager& lhs,
263                                 const DefUseManager& rhs) {
264   bool same = true;
265 
266   if (lhs.id_to_def_ != rhs.id_to_def_) {
267     for (auto p : lhs.id_to_def_) {
268       if (rhs.id_to_def_.find(p.first) == rhs.id_to_def_.end()) {
269         printf("Diff in id_to_def: missing value in rhs\n");
270       }
271     }
272     for (auto p : rhs.id_to_def_) {
273       if (lhs.id_to_def_.find(p.first) == lhs.id_to_def_.end()) {
274         printf("Diff in id_to_def: missing value in lhs\n");
275       }
276     }
277     same = false;
278   }
279 
280   if (lhs.id_to_users_ != rhs.id_to_users_) {
281     for (auto p : lhs.id_to_users_) {
282       if (rhs.id_to_users_.count(p) == 0) {
283         printf("Diff in id_to_users: missing value in rhs\n");
284       }
285     }
286     for (auto p : rhs.id_to_users_) {
287       if (lhs.id_to_users_.count(p) == 0) {
288         printf("Diff in id_to_users: missing value in lhs\n");
289       }
290     }
291     same = false;
292   }
293 
294   if (lhs.inst_to_used_ids_ != rhs.inst_to_used_ids_) {
295     for (auto p : lhs.inst_to_used_ids_) {
296       if (rhs.inst_to_used_ids_.count(p.first) == 0) {
297         printf("Diff in inst_to_used_ids: missing value in rhs\n");
298       }
299     }
300     for (auto p : rhs.inst_to_used_ids_) {
301       if (lhs.inst_to_used_ids_.count(p.first) == 0) {
302         printf("Diff in inst_to_used_ids: missing value in lhs\n");
303       }
304     }
305     same = false;
306   }
307 
308   return same;
309 }
310 
311 }  // namespace analysis
312 }  // namespace opt
313 }  // namespace spvtools
314