• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2020 Google LLC
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/debug_info_manager.h"
16 
17 #include <cassert>
18 
19 #include "source/opt/ir_context.h"
20 
21 // Constants for OpenCL.DebugInfo.100 extension instructions.
22 
23 static const uint32_t kOpLineOperandLineIndex = 1;
24 static const uint32_t kLineOperandIndexDebugFunction = 7;
25 static const uint32_t kLineOperandIndexDebugLexicalBlock = 5;
26 static const uint32_t kDebugFunctionOperandFunctionIndex = 13;
27 static const uint32_t kDebugFunctionOperandParentIndex = 9;
28 static const uint32_t kDebugTypeCompositeOperandParentIndex = 9;
29 static const uint32_t kDebugLexicalBlockOperandParentIndex = 7;
30 static const uint32_t kDebugInlinedAtOperandInlinedIndex = 6;
31 static const uint32_t kDebugExpressOperandOperationIndex = 4;
32 static const uint32_t kDebugDeclareOperandLocalVariableIndex = 4;
33 static const uint32_t kDebugDeclareOperandVariableIndex = 5;
34 static const uint32_t kDebugValueOperandExpressionIndex = 6;
35 static const uint32_t kDebugOperationOperandOperationIndex = 4;
36 static const uint32_t kOpVariableOperandStorageClassIndex = 2;
37 static const uint32_t kDebugLocalVariableOperandParentIndex = 9;
38 static const uint32_t kExtInstInstructionInIdx = 1;
39 static const uint32_t kDebugGlobalVariableOperandFlagsIndex = 12;
40 static const uint32_t kDebugLocalVariableOperandFlagsIndex = 10;
41 
42 namespace spvtools {
43 namespace opt {
44 namespace analysis {
45 namespace {
46 
SetInlinedOperand(Instruction * dbg_inlined_at,uint32_t inlined_operand)47 void SetInlinedOperand(Instruction* dbg_inlined_at, uint32_t inlined_operand) {
48   assert(dbg_inlined_at);
49   assert(dbg_inlined_at->GetOpenCL100DebugOpcode() ==
50          OpenCLDebugInfo100DebugInlinedAt);
51   if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex) {
52     dbg_inlined_at->AddOperand(
53         {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inlined_operand}});
54   } else {
55     dbg_inlined_at->SetOperand(kDebugInlinedAtOperandInlinedIndex,
56                                {inlined_operand});
57   }
58 }
59 
GetInlinedOperand(Instruction * dbg_inlined_at)60 uint32_t GetInlinedOperand(Instruction* dbg_inlined_at) {
61   assert(dbg_inlined_at);
62   assert(dbg_inlined_at->GetOpenCL100DebugOpcode() ==
63          OpenCLDebugInfo100DebugInlinedAt);
64   if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex)
65     return kNoInlinedAt;
66   return dbg_inlined_at->GetSingleWordOperand(
67       kDebugInlinedAtOperandInlinedIndex);
68 }
69 
IsEmptyDebugExpression(Instruction * instr)70 bool IsEmptyDebugExpression(Instruction* instr) {
71   return instr->GetOpenCL100DebugOpcode() ==
72              OpenCLDebugInfo100DebugExpression &&
73          instr->NumOperands() == kDebugExpressOperandOperationIndex;
74 }
75 
76 }  // namespace
77 
DebugInfoManager(IRContext * c)78 DebugInfoManager::DebugInfoManager(IRContext* c) : context_(c) {
79   AnalyzeDebugInsts(*c->module());
80 }
81 
GetDbgInst(uint32_t id)82 Instruction* DebugInfoManager::GetDbgInst(uint32_t id) {
83   auto dbg_inst_it = id_to_dbg_inst_.find(id);
84   return dbg_inst_it == id_to_dbg_inst_.end() ? nullptr : dbg_inst_it->second;
85 }
86 
RegisterDbgInst(Instruction * inst)87 void DebugInfoManager::RegisterDbgInst(Instruction* inst) {
88   assert(
89       inst->NumInOperands() != 0 &&
90       context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() ==
91           inst->GetInOperand(0).words[0] &&
92       "Given instruction is not a debug instruction");
93   id_to_dbg_inst_[inst->result_id()] = inst;
94 }
95 
RegisterDbgFunction(Instruction * inst)96 void DebugInfoManager::RegisterDbgFunction(Instruction* inst) {
97   assert(inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction &&
98          "inst is not a DebugFunction");
99   auto fn_id = inst->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex);
100   // Do not register function that has been optimized away
101   auto fn_inst = GetDbgInst(fn_id);
102   if (fn_inst != nullptr) {
103     assert(GetDbgInst(fn_id)->GetOpenCL100DebugOpcode() ==
104            OpenCLDebugInfo100DebugInfoNone);
105     return;
106   }
107   assert(
108       fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() &&
109       "Register DebugFunction for a function that already has DebugFunction");
110   fn_id_to_dbg_fn_[fn_id] = inst;
111 }
112 
RegisterDbgDeclare(uint32_t var_id,Instruction * dbg_declare)113 void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id,
114                                           Instruction* dbg_declare) {
115   assert(dbg_declare->GetOpenCL100DebugOpcode() ==
116              OpenCLDebugInfo100DebugDeclare ||
117          dbg_declare->GetOpenCL100DebugOpcode() ==
118              OpenCLDebugInfo100DebugValue);
119   auto dbg_decl_itr = var_id_to_dbg_decl_.find(var_id);
120   if (dbg_decl_itr == var_id_to_dbg_decl_.end()) {
121     var_id_to_dbg_decl_[var_id] = {dbg_declare};
122   } else {
123     dbg_decl_itr->second.insert(dbg_declare);
124   }
125 }
126 
CreateDebugInlinedAt(const Instruction * line,const DebugScope & scope)127 uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
128                                                 const DebugScope& scope) {
129   if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() ==
130       0)
131     return kNoInlinedAt;
132 
133   uint32_t line_number = 0;
134   if (line == nullptr) {
135     auto* lexical_scope_inst = GetDbgInst(scope.GetLexicalScope());
136     if (lexical_scope_inst == nullptr) return kNoInlinedAt;
137     OpenCLDebugInfo100Instructions debug_opcode =
138         lexical_scope_inst->GetOpenCL100DebugOpcode();
139     switch (debug_opcode) {
140       case OpenCLDebugInfo100DebugFunction:
141         line_number = lexical_scope_inst->GetSingleWordOperand(
142             kLineOperandIndexDebugFunction);
143         break;
144       case OpenCLDebugInfo100DebugLexicalBlock:
145         line_number = lexical_scope_inst->GetSingleWordOperand(
146             kLineOperandIndexDebugLexicalBlock);
147         break;
148       case OpenCLDebugInfo100DebugTypeComposite:
149       case OpenCLDebugInfo100DebugCompilationUnit:
150         assert(false &&
151                "DebugTypeComposite and DebugCompilationUnit are lexical "
152                "scopes, but we inline functions into a function or a block "
153                "of a function, not into a struct/class or a global scope.");
154         break;
155       default:
156         assert(false &&
157                "Unreachable. a debug extension instruction for a "
158                "lexical scope must be DebugFunction, DebugTypeComposite, "
159                "DebugLexicalBlock, or DebugCompilationUnit.");
160         break;
161     }
162   } else {
163     line_number = line->GetSingleWordOperand(kOpLineOperandLineIndex);
164   }
165 
166   uint32_t result_id = context()->TakeNextId();
167   std::unique_ptr<Instruction> inlined_at(new Instruction(
168       context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
169       result_id,
170       {
171           {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
172            {context()
173                 ->get_feature_mgr()
174                 ->GetExtInstImportId_OpenCL100DebugInfo()}},
175           {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
176            {static_cast<uint32_t>(OpenCLDebugInfo100DebugInlinedAt)}},
177           {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {line_number}},
178           {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {scope.GetLexicalScope()}},
179       }));
180   // |scope| already has DebugInlinedAt. We put the existing DebugInlinedAt
181   // into the Inlined operand of this new DebugInlinedAt.
182   if (scope.GetInlinedAt() != kNoInlinedAt) {
183     inlined_at->AddOperand(
184         {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {scope.GetInlinedAt()}});
185   }
186   RegisterDbgInst(inlined_at.get());
187   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
188     context()->get_def_use_mgr()->AnalyzeInstDefUse(inlined_at.get());
189   context()->module()->AddExtInstDebugInfo(std::move(inlined_at));
190   return result_id;
191 }
192 
BuildDebugScope(const DebugScope & callee_instr_scope,DebugInlinedAtContext * inlined_at_ctx)193 DebugScope DebugInfoManager::BuildDebugScope(
194     const DebugScope& callee_instr_scope,
195     DebugInlinedAtContext* inlined_at_ctx) {
196   return DebugScope(callee_instr_scope.GetLexicalScope(),
197                     BuildDebugInlinedAtChain(callee_instr_scope.GetInlinedAt(),
198                                              inlined_at_ctx));
199 }
200 
BuildDebugInlinedAtChain(uint32_t callee_inlined_at,DebugInlinedAtContext * inlined_at_ctx)201 uint32_t DebugInfoManager::BuildDebugInlinedAtChain(
202     uint32_t callee_inlined_at, DebugInlinedAtContext* inlined_at_ctx) {
203   if (inlined_at_ctx->GetScopeOfCallInstruction().GetLexicalScope() ==
204       kNoDebugScope)
205     return kNoInlinedAt;
206 
207   // Reuse the already generated DebugInlinedAt chain if exists.
208   uint32_t already_generated_chain_head_id =
209       inlined_at_ctx->GetDebugInlinedAtChain(callee_inlined_at);
210   if (already_generated_chain_head_id != kNoInlinedAt) {
211     return already_generated_chain_head_id;
212   }
213 
214   const uint32_t new_dbg_inlined_at_id =
215       CreateDebugInlinedAt(inlined_at_ctx->GetLineOfCallInstruction(),
216                            inlined_at_ctx->GetScopeOfCallInstruction());
217   if (new_dbg_inlined_at_id == kNoInlinedAt) return kNoInlinedAt;
218 
219   if (callee_inlined_at == kNoInlinedAt) {
220     inlined_at_ctx->SetDebugInlinedAtChain(kNoInlinedAt, new_dbg_inlined_at_id);
221     return new_dbg_inlined_at_id;
222   }
223 
224   uint32_t chain_head_id = kNoInlinedAt;
225   uint32_t chain_iter_id = callee_inlined_at;
226   Instruction* last_inlined_at_in_chain = nullptr;
227   do {
228     Instruction* new_inlined_at_in_chain = CloneDebugInlinedAt(
229         chain_iter_id, /* insert_before */ last_inlined_at_in_chain);
230     assert(new_inlined_at_in_chain != nullptr);
231 
232     // Set DebugInlinedAt of the new scope as the head of the chain.
233     if (chain_head_id == kNoInlinedAt)
234       chain_head_id = new_inlined_at_in_chain->result_id();
235 
236     // Previous DebugInlinedAt of the chain must point to the new
237     // DebugInlinedAt as its Inlined operand to build a recursive
238     // chain.
239     if (last_inlined_at_in_chain != nullptr) {
240       SetInlinedOperand(last_inlined_at_in_chain,
241                         new_inlined_at_in_chain->result_id());
242     }
243     last_inlined_at_in_chain = new_inlined_at_in_chain;
244 
245     chain_iter_id = GetInlinedOperand(new_inlined_at_in_chain);
246   } while (chain_iter_id != kNoInlinedAt);
247 
248   // Put |new_dbg_inlined_at_id| into the end of the chain.
249   SetInlinedOperand(last_inlined_at_in_chain, new_dbg_inlined_at_id);
250 
251   // Keep the new chain information that will be reused it.
252   inlined_at_ctx->SetDebugInlinedAtChain(callee_inlined_at, chain_head_id);
253   return chain_head_id;
254 }
255 
GetDebugOperationWithDeref()256 Instruction* DebugInfoManager::GetDebugOperationWithDeref() {
257   if (deref_operation_ != nullptr) return deref_operation_;
258 
259   uint32_t result_id = context()->TakeNextId();
260   std::unique_ptr<Instruction> deref_operation(new Instruction(
261       context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
262       result_id,
263       {
264           {SPV_OPERAND_TYPE_ID,
265            {context()
266                 ->get_feature_mgr()
267                 ->GetExtInstImportId_OpenCL100DebugInfo()}},
268           {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
269            {static_cast<uint32_t>(OpenCLDebugInfo100DebugOperation)}},
270           {SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION,
271            {static_cast<uint32_t>(OpenCLDebugInfo100Deref)}},
272       }));
273 
274   // Add to the front of |ext_inst_debuginfo_|.
275   deref_operation_ =
276       context()->module()->ext_inst_debuginfo_begin()->InsertBefore(
277           std::move(deref_operation));
278 
279   RegisterDbgInst(deref_operation_);
280   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
281     context()->get_def_use_mgr()->AnalyzeInstDefUse(deref_operation_);
282   return deref_operation_;
283 }
284 
DerefDebugExpression(Instruction * dbg_expr)285 Instruction* DebugInfoManager::DerefDebugExpression(Instruction* dbg_expr) {
286   assert(dbg_expr->GetOpenCL100DebugOpcode() ==
287          OpenCLDebugInfo100DebugExpression);
288   std::unique_ptr<Instruction> deref_expr(dbg_expr->Clone(context()));
289   deref_expr->SetResultId(context()->TakeNextId());
290   deref_expr->InsertOperand(
291       kDebugExpressOperandOperationIndex,
292       {SPV_OPERAND_TYPE_ID, {GetDebugOperationWithDeref()->result_id()}});
293   auto* deref_expr_instr =
294       context()->ext_inst_debuginfo_end()->InsertBefore(std::move(deref_expr));
295   AnalyzeDebugInst(deref_expr_instr);
296   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
297     context()->get_def_use_mgr()->AnalyzeInstDefUse(deref_expr_instr);
298   return deref_expr_instr;
299 }
300 
GetDebugInfoNone()301 Instruction* DebugInfoManager::GetDebugInfoNone() {
302   if (debug_info_none_inst_ != nullptr) return debug_info_none_inst_;
303 
304   uint32_t result_id = context()->TakeNextId();
305   std::unique_ptr<Instruction> dbg_info_none_inst(new Instruction(
306       context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
307       result_id,
308       {
309           {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
310            {context()
311                 ->get_feature_mgr()
312                 ->GetExtInstImportId_OpenCL100DebugInfo()}},
313           {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
314            {static_cast<uint32_t>(OpenCLDebugInfo100DebugInfoNone)}},
315       }));
316 
317   // Add to the front of |ext_inst_debuginfo_|.
318   debug_info_none_inst_ =
319       context()->module()->ext_inst_debuginfo_begin()->InsertBefore(
320           std::move(dbg_info_none_inst));
321 
322   RegisterDbgInst(debug_info_none_inst_);
323   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
324     context()->get_def_use_mgr()->AnalyzeInstDefUse(debug_info_none_inst_);
325   return debug_info_none_inst_;
326 }
327 
GetEmptyDebugExpression()328 Instruction* DebugInfoManager::GetEmptyDebugExpression() {
329   if (empty_debug_expr_inst_ != nullptr) return empty_debug_expr_inst_;
330 
331   uint32_t result_id = context()->TakeNextId();
332   std::unique_ptr<Instruction> empty_debug_expr(new Instruction(
333       context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
334       result_id,
335       {
336           {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
337            {context()
338                 ->get_feature_mgr()
339                 ->GetExtInstImportId_OpenCL100DebugInfo()}},
340           {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
341            {static_cast<uint32_t>(OpenCLDebugInfo100DebugExpression)}},
342       }));
343 
344   // Add to the front of |ext_inst_debuginfo_|.
345   empty_debug_expr_inst_ =
346       context()->module()->ext_inst_debuginfo_begin()->InsertBefore(
347           std::move(empty_debug_expr));
348 
349   RegisterDbgInst(empty_debug_expr_inst_);
350   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
351     context()->get_def_use_mgr()->AnalyzeInstDefUse(empty_debug_expr_inst_);
352   return empty_debug_expr_inst_;
353 }
354 
GetDebugInlinedAt(uint32_t dbg_inlined_at_id)355 Instruction* DebugInfoManager::GetDebugInlinedAt(uint32_t dbg_inlined_at_id) {
356   auto* inlined_at = GetDbgInst(dbg_inlined_at_id);
357   if (inlined_at == nullptr) return nullptr;
358   if (inlined_at->GetOpenCL100DebugOpcode() !=
359       OpenCLDebugInfo100DebugInlinedAt) {
360     return nullptr;
361   }
362   return inlined_at;
363 }
364 
CloneDebugInlinedAt(uint32_t clone_inlined_at_id,Instruction * insert_before)365 Instruction* DebugInfoManager::CloneDebugInlinedAt(uint32_t clone_inlined_at_id,
366                                                    Instruction* insert_before) {
367   auto* inlined_at = GetDebugInlinedAt(clone_inlined_at_id);
368   if (inlined_at == nullptr) return nullptr;
369   std::unique_ptr<Instruction> new_inlined_at(inlined_at->Clone(context()));
370   new_inlined_at->SetResultId(context()->TakeNextId());
371   RegisterDbgInst(new_inlined_at.get());
372   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
373     context()->get_def_use_mgr()->AnalyzeInstDefUse(new_inlined_at.get());
374   if (insert_before != nullptr)
375     return insert_before->InsertBefore(std::move(new_inlined_at));
376   return context()->module()->ext_inst_debuginfo_end()->InsertBefore(
377       std::move(new_inlined_at));
378 }
379 
IsVariableDebugDeclared(uint32_t variable_id)380 bool DebugInfoManager::IsVariableDebugDeclared(uint32_t variable_id) {
381   auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id);
382   return dbg_decl_itr != var_id_to_dbg_decl_.end();
383 }
384 
KillDebugDeclares(uint32_t variable_id)385 bool DebugInfoManager::KillDebugDeclares(uint32_t variable_id) {
386   bool modified = false;
387   auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id);
388   if (dbg_decl_itr != var_id_to_dbg_decl_.end()) {
389     // We intentionally copy the list of DebugDeclare instructions because
390     // context()->KillInst(dbg_decl) will update |var_id_to_dbg_decl_|. If we
391     // directly use |dbg_decl_itr->second|, it accesses a dangling pointer.
392     auto copy_dbg_decls = dbg_decl_itr->second;
393 
394     for (auto* dbg_decl : copy_dbg_decls) {
395       context()->KillInst(dbg_decl);
396       modified = true;
397     }
398     var_id_to_dbg_decl_.erase(dbg_decl_itr);
399   }
400   return modified;
401 }
402 
GetParentScope(uint32_t child_scope)403 uint32_t DebugInfoManager::GetParentScope(uint32_t child_scope) {
404   auto dbg_scope_itr = id_to_dbg_inst_.find(child_scope);
405   assert(dbg_scope_itr != id_to_dbg_inst_.end());
406   OpenCLDebugInfo100Instructions debug_opcode =
407       dbg_scope_itr->second->GetOpenCL100DebugOpcode();
408   uint32_t parent_scope = kNoDebugScope;
409   switch (debug_opcode) {
410     case OpenCLDebugInfo100DebugFunction:
411       parent_scope = dbg_scope_itr->second->GetSingleWordOperand(
412           kDebugFunctionOperandParentIndex);
413       break;
414     case OpenCLDebugInfo100DebugLexicalBlock:
415       parent_scope = dbg_scope_itr->second->GetSingleWordOperand(
416           kDebugLexicalBlockOperandParentIndex);
417       break;
418     case OpenCLDebugInfo100DebugTypeComposite:
419       parent_scope = dbg_scope_itr->second->GetSingleWordOperand(
420           kDebugTypeCompositeOperandParentIndex);
421       break;
422     case OpenCLDebugInfo100DebugCompilationUnit:
423       // DebugCompilationUnit does not have a parent scope.
424       break;
425     default:
426       assert(false &&
427              "Unreachable. A debug scope instruction must be "
428              "DebugFunction, DebugTypeComposite, DebugLexicalBlock, "
429              "or DebugCompilationUnit.");
430       break;
431   }
432   return parent_scope;
433 }
434 
IsAncestorOfScope(uint32_t scope,uint32_t ancestor)435 bool DebugInfoManager::IsAncestorOfScope(uint32_t scope, uint32_t ancestor) {
436   uint32_t ancestor_scope_itr = scope;
437   while (ancestor_scope_itr != kNoDebugScope) {
438     if (ancestor == ancestor_scope_itr) return true;
439     ancestor_scope_itr = GetParentScope(ancestor_scope_itr);
440   }
441   return false;
442 }
443 
IsDeclareVisibleToInstr(Instruction * dbg_declare,Instruction * scope)444 bool DebugInfoManager::IsDeclareVisibleToInstr(Instruction* dbg_declare,
445                                                Instruction* scope) {
446   assert(dbg_declare != nullptr);
447   assert(scope != nullptr);
448 
449   std::vector<uint32_t> scope_ids;
450   if (scope->opcode() == SpvOpPhi) {
451     scope_ids.push_back(scope->GetDebugScope().GetLexicalScope());
452     for (uint32_t i = 0; i < scope->NumInOperands(); i += 2) {
453       auto* value = context()->get_def_use_mgr()->GetDef(
454           scope->GetSingleWordInOperand(i));
455       if (value != nullptr)
456         scope_ids.push_back(value->GetDebugScope().GetLexicalScope());
457     }
458   } else {
459     scope_ids.push_back(scope->GetDebugScope().GetLexicalScope());
460   }
461 
462   uint32_t dbg_local_var_id =
463       dbg_declare->GetSingleWordOperand(kDebugDeclareOperandLocalVariableIndex);
464   auto dbg_local_var_itr = id_to_dbg_inst_.find(dbg_local_var_id);
465   assert(dbg_local_var_itr != id_to_dbg_inst_.end());
466   uint32_t decl_scope_id = dbg_local_var_itr->second->GetSingleWordOperand(
467       kDebugLocalVariableOperandParentIndex);
468 
469   // If the scope of DebugDeclare is an ancestor scope of the instruction's
470   // scope, the local variable is visible to the instruction.
471   for (uint32_t scope_id : scope_ids) {
472     if (scope_id != kNoDebugScope &&
473         IsAncestorOfScope(scope_id, decl_scope_id)) {
474       return true;
475     }
476   }
477   return false;
478 }
479 
AddDebugValueIfVarDeclIsVisible(Instruction * scope_and_line,uint32_t variable_id,uint32_t value_id,Instruction * insert_pos,std::unordered_set<Instruction * > * invisible_decls)480 bool DebugInfoManager::AddDebugValueIfVarDeclIsVisible(
481     Instruction* scope_and_line, uint32_t variable_id, uint32_t value_id,
482     Instruction* insert_pos,
483     std::unordered_set<Instruction*>* invisible_decls) {
484   assert(scope_and_line != nullptr);
485 
486   auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id);
487   if (dbg_decl_itr == var_id_to_dbg_decl_.end()) return false;
488 
489   bool modified = false;
490   for (auto* dbg_decl_or_val : dbg_decl_itr->second) {
491     if (!IsDeclareVisibleToInstr(dbg_decl_or_val, scope_and_line)) {
492       if (invisible_decls) invisible_decls->insert(dbg_decl_or_val);
493       continue;
494     }
495 
496     // Avoid inserting the new DebugValue between OpPhi or OpVariable
497     // instructions.
498     Instruction* insert_before = insert_pos->NextNode();
499     while (insert_before->opcode() == SpvOpPhi ||
500            insert_before->opcode() == SpvOpVariable) {
501       insert_before = insert_before->NextNode();
502     }
503     modified |= AddDebugValueForDecl(dbg_decl_or_val, value_id, insert_before,
504                                      scope_and_line) != nullptr;
505   }
506   return modified;
507 }
508 
AddDebugValueForDecl(Instruction * dbg_decl,uint32_t value_id,Instruction * insert_before,Instruction * scope_and_line)509 Instruction* DebugInfoManager::AddDebugValueForDecl(
510     Instruction* dbg_decl, uint32_t value_id, Instruction* insert_before,
511     Instruction* scope_and_line) {
512   if (dbg_decl == nullptr || !IsDebugDeclare(dbg_decl)) return nullptr;
513 
514   std::unique_ptr<Instruction> dbg_val(dbg_decl->Clone(context()));
515   dbg_val->SetResultId(context()->TakeNextId());
516   dbg_val->SetInOperand(kExtInstInstructionInIdx,
517                         {OpenCLDebugInfo100DebugValue});
518   dbg_val->SetOperand(kDebugDeclareOperandVariableIndex, {value_id});
519   dbg_val->SetOperand(kDebugValueOperandExpressionIndex,
520                       {GetEmptyDebugExpression()->result_id()});
521   dbg_val->UpdateDebugInfoFrom(scope_and_line);
522 
523   auto* added_dbg_val = insert_before->InsertBefore(std::move(dbg_val));
524   AnalyzeDebugInst(added_dbg_val);
525   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
526     context()->get_def_use_mgr()->AnalyzeInstDefUse(added_dbg_val);
527   if (context()->AreAnalysesValid(
528           IRContext::Analysis::kAnalysisInstrToBlockMapping)) {
529     auto insert_blk = context()->get_instr_block(insert_before);
530     context()->set_instr_block(added_dbg_val, insert_blk);
531   }
532   return added_dbg_val;
533 }
534 
GetVariableIdOfDebugValueUsedForDeclare(Instruction * inst)535 uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare(
536     Instruction* inst) {
537   if (inst->GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugValue) return 0;
538 
539   auto* expr =
540       GetDbgInst(inst->GetSingleWordOperand(kDebugValueOperandExpressionIndex));
541   if (expr == nullptr) return 0;
542   if (expr->NumOperands() != kDebugExpressOperandOperationIndex + 1) return 0;
543 
544   auto* operation = GetDbgInst(
545       expr->GetSingleWordOperand(kDebugExpressOperandOperationIndex));
546   if (operation == nullptr) return 0;
547   if (operation->GetSingleWordOperand(kDebugOperationOperandOperationIndex) !=
548       OpenCLDebugInfo100Deref) {
549     return 0;
550   }
551 
552   uint32_t var_id =
553       inst->GetSingleWordOperand(kDebugDeclareOperandVariableIndex);
554   if (!context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse)) {
555     assert(false &&
556            "Checking a DebugValue can be used for declare needs DefUseManager");
557     return 0;
558   }
559 
560   auto* var = context()->get_def_use_mgr()->GetDef(var_id);
561   if (var->opcode() == SpvOpVariable &&
562       SpvStorageClass(var->GetSingleWordOperand(
563           kOpVariableOperandStorageClassIndex)) == SpvStorageClassFunction) {
564     return var_id;
565   }
566   return 0;
567 }
568 
IsDebugDeclare(Instruction * instr)569 bool DebugInfoManager::IsDebugDeclare(Instruction* instr) {
570   if (!instr->IsOpenCL100DebugInstr()) return false;
571   return instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare ||
572          GetVariableIdOfDebugValueUsedForDeclare(instr) != 0;
573 }
574 
ReplaceAllUsesInDebugScopeWithPredicate(uint32_t before,uint32_t after,const std::function<bool (Instruction *)> & predicate)575 void DebugInfoManager::ReplaceAllUsesInDebugScopeWithPredicate(
576     uint32_t before, uint32_t after,
577     const std::function<bool(Instruction*)>& predicate) {
578   auto scope_id_to_users_itr = scope_id_to_users_.find(before);
579   if (scope_id_to_users_itr != scope_id_to_users_.end()) {
580     for (Instruction* inst : scope_id_to_users_itr->second) {
581       if (predicate(inst)) inst->UpdateLexicalScope(after);
582     }
583     scope_id_to_users_[after] = scope_id_to_users_itr->second;
584     scope_id_to_users_.erase(scope_id_to_users_itr);
585   }
586   auto inlinedat_id_to_users_itr = inlinedat_id_to_users_.find(before);
587   if (inlinedat_id_to_users_itr != inlinedat_id_to_users_.end()) {
588     for (Instruction* inst : inlinedat_id_to_users_itr->second) {
589       if (predicate(inst)) inst->UpdateDebugInlinedAt(after);
590     }
591     inlinedat_id_to_users_[after] = inlinedat_id_to_users_itr->second;
592     inlinedat_id_to_users_.erase(inlinedat_id_to_users_itr);
593   }
594 }
595 
ClearDebugScopeAndInlinedAtUses(Instruction * inst)596 void DebugInfoManager::ClearDebugScopeAndInlinedAtUses(Instruction* inst) {
597   auto scope_id_to_users_itr = scope_id_to_users_.find(inst->result_id());
598   if (scope_id_to_users_itr != scope_id_to_users_.end()) {
599     scope_id_to_users_.erase(scope_id_to_users_itr);
600   }
601   auto inlinedat_id_to_users_itr =
602       inlinedat_id_to_users_.find(inst->result_id());
603   if (inlinedat_id_to_users_itr != inlinedat_id_to_users_.end()) {
604     inlinedat_id_to_users_.erase(inlinedat_id_to_users_itr);
605   }
606 }
607 
AnalyzeDebugInst(Instruction * inst)608 void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) {
609   if (inst->GetDebugScope().GetLexicalScope() != kNoDebugScope) {
610     auto& users = scope_id_to_users_[inst->GetDebugScope().GetLexicalScope()];
611     users.insert(inst);
612   }
613   if (inst->GetDebugInlinedAt() != kNoInlinedAt) {
614     auto& users = inlinedat_id_to_users_[inst->GetDebugInlinedAt()];
615     users.insert(inst);
616   }
617 
618   if (!inst->IsOpenCL100DebugInstr()) return;
619 
620   RegisterDbgInst(inst);
621 
622   if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) {
623     assert(GetDebugFunction(inst->GetSingleWordOperand(
624                kDebugFunctionOperandFunctionIndex)) == nullptr &&
625            "Two DebugFunction instruction exists for a single OpFunction.");
626     RegisterDbgFunction(inst);
627   }
628 
629   if (deref_operation_ == nullptr &&
630       inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugOperation &&
631       inst->GetSingleWordOperand(kDebugOperationOperandOperationIndex) ==
632           OpenCLDebugInfo100Deref) {
633     deref_operation_ = inst;
634   }
635 
636   if (debug_info_none_inst_ == nullptr &&
637       inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) {
638     debug_info_none_inst_ = inst;
639   }
640 
641   if (empty_debug_expr_inst_ == nullptr && IsEmptyDebugExpression(inst)) {
642     empty_debug_expr_inst_ = inst;
643   }
644 
645   if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare) {
646     uint32_t var_id =
647         inst->GetSingleWordOperand(kDebugDeclareOperandVariableIndex);
648     RegisterDbgDeclare(var_id, inst);
649   }
650 
651   if (uint32_t var_id = GetVariableIdOfDebugValueUsedForDeclare(inst)) {
652     RegisterDbgDeclare(var_id, inst);
653   }
654 }
655 
ConvertDebugGlobalToLocalVariable(Instruction * dbg_global_var,Instruction * local_var)656 void DebugInfoManager::ConvertDebugGlobalToLocalVariable(
657     Instruction* dbg_global_var, Instruction* local_var) {
658   if (dbg_global_var->GetOpenCL100DebugOpcode() !=
659       OpenCLDebugInfo100DebugGlobalVariable) {
660     return;
661   }
662   assert(local_var->opcode() == SpvOpVariable ||
663          local_var->opcode() == SpvOpFunctionParameter);
664 
665   // Convert |dbg_global_var| to DebugLocalVariable
666   dbg_global_var->SetInOperand(kExtInstInstructionInIdx,
667                                {OpenCLDebugInfo100DebugLocalVariable});
668   auto flags = dbg_global_var->GetSingleWordOperand(
669       kDebugGlobalVariableOperandFlagsIndex);
670   for (uint32_t i = dbg_global_var->NumInOperands() - 1;
671        i >= kDebugLocalVariableOperandFlagsIndex; --i) {
672     dbg_global_var->RemoveOperand(i);
673   }
674   dbg_global_var->SetOperand(kDebugLocalVariableOperandFlagsIndex, {flags});
675   context()->ForgetUses(dbg_global_var);
676   context()->AnalyzeUses(dbg_global_var);
677 
678   // Create a DebugDeclare
679   std::unique_ptr<Instruction> new_dbg_decl(new Instruction(
680       context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
681       context()->TakeNextId(),
682       {
683           {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
684            {context()
685                 ->get_feature_mgr()
686                 ->GetExtInstImportId_OpenCL100DebugInfo()}},
687           {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
688            {static_cast<uint32_t>(OpenCLDebugInfo100DebugDeclare)}},
689           {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
690            {dbg_global_var->result_id()}},
691           {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {local_var->result_id()}},
692           {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
693            {GetEmptyDebugExpression()->result_id()}},
694       }));
695   auto* added_dbg_decl =
696       local_var->NextNode()->InsertBefore(std::move(new_dbg_decl));
697   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
698     context()->get_def_use_mgr()->AnalyzeInstDefUse(added_dbg_decl);
699   if (context()->AreAnalysesValid(
700           IRContext::Analysis::kAnalysisInstrToBlockMapping)) {
701     auto insert_blk = context()->get_instr_block(local_var);
702     context()->set_instr_block(added_dbg_decl, insert_blk);
703   }
704 }
705 
AnalyzeDebugInsts(Module & module)706 void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
707   deref_operation_ = nullptr;
708   debug_info_none_inst_ = nullptr;
709   empty_debug_expr_inst_ = nullptr;
710   module.ForEachInst([this](Instruction* cpi) { AnalyzeDebugInst(cpi); });
711 
712   // Move |empty_debug_expr_inst_| to the beginning of the debug instruction
713   // list.
714   if (empty_debug_expr_inst_ != nullptr &&
715       empty_debug_expr_inst_->PreviousNode() != nullptr &&
716       empty_debug_expr_inst_->PreviousNode()->IsOpenCL100DebugInstr()) {
717     empty_debug_expr_inst_->InsertBefore(
718         &*context()->module()->ext_inst_debuginfo_begin());
719   }
720 
721   // Move |debug_info_none_inst_| to the beginning of the debug instruction
722   // list.
723   if (debug_info_none_inst_ != nullptr &&
724       debug_info_none_inst_->PreviousNode() != nullptr &&
725       debug_info_none_inst_->PreviousNode()->IsOpenCL100DebugInstr()) {
726     debug_info_none_inst_->InsertBefore(
727         &*context()->module()->ext_inst_debuginfo_begin());
728   }
729 }
730 
ClearDebugInfo(Instruction * instr)731 void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
732   auto scope_id_to_users_itr =
733       scope_id_to_users_.find(instr->GetDebugScope().GetLexicalScope());
734   if (scope_id_to_users_itr != scope_id_to_users_.end()) {
735     scope_id_to_users_itr->second.erase(instr);
736   }
737   auto inlinedat_id_to_users_itr =
738       inlinedat_id_to_users_.find(instr->GetDebugInlinedAt());
739   if (inlinedat_id_to_users_itr != inlinedat_id_to_users_.end()) {
740     inlinedat_id_to_users_itr->second.erase(instr);
741   }
742 
743   if (instr == nullptr || !instr->IsOpenCL100DebugInstr()) {
744     return;
745   }
746 
747   id_to_dbg_inst_.erase(instr->result_id());
748 
749   if (instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) {
750     auto fn_id =
751         instr->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex);
752     fn_id_to_dbg_fn_.erase(fn_id);
753   }
754 
755   if (instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugDeclare ||
756       instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugValue) {
757     auto var_or_value_id =
758         instr->GetSingleWordOperand(kDebugDeclareOperandVariableIndex);
759     auto dbg_decl_itr = var_id_to_dbg_decl_.find(var_or_value_id);
760     if (dbg_decl_itr != var_id_to_dbg_decl_.end()) {
761       dbg_decl_itr->second.erase(instr);
762     }
763   }
764 
765   if (deref_operation_ == instr) {
766     deref_operation_ = nullptr;
767     for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
768          dbg_instr_itr != context()->module()->ext_inst_debuginfo_end();
769          ++dbg_instr_itr) {
770       if (instr != &*dbg_instr_itr &&
771           dbg_instr_itr->GetOpenCL100DebugOpcode() ==
772               OpenCLDebugInfo100DebugOperation &&
773           dbg_instr_itr->GetSingleWordOperand(
774               kDebugOperationOperandOperationIndex) ==
775               OpenCLDebugInfo100Deref) {
776         deref_operation_ = &*dbg_instr_itr;
777         break;
778       }
779     }
780   }
781 
782   if (debug_info_none_inst_ == instr) {
783     debug_info_none_inst_ = nullptr;
784     for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
785          dbg_instr_itr != context()->module()->ext_inst_debuginfo_end();
786          ++dbg_instr_itr) {
787       if (instr != &*dbg_instr_itr &&
788           dbg_instr_itr->GetOpenCL100DebugOpcode() ==
789               OpenCLDebugInfo100DebugInfoNone) {
790         debug_info_none_inst_ = &*dbg_instr_itr;
791         break;
792       }
793     }
794   }
795 
796   if (empty_debug_expr_inst_ == instr) {
797     empty_debug_expr_inst_ = nullptr;
798     for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
799          dbg_instr_itr != context()->module()->ext_inst_debuginfo_end();
800          ++dbg_instr_itr) {
801       if (instr != &*dbg_instr_itr && IsEmptyDebugExpression(&*dbg_instr_itr)) {
802         empty_debug_expr_inst_ = &*dbg_instr_itr;
803         break;
804       }
805     }
806   }
807 }
808 
809 }  // namespace analysis
810 }  // namespace opt
811 }  // namespace spvtools
812