• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2020-2022 Google LLC
2 // Copyright (c) 2022 LunarG Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "source/opt/debug_info_manager.h"
17 
18 #include <cassert>
19 
20 #include "source/opt/ir_context.h"
21 
22 // Constants for OpenCL.DebugInfo.100 & NonSemantic.Shader.DebugInfo.100
23 // extension instructions.
24 
25 namespace spvtools {
26 namespace opt {
27 namespace analysis {
28 namespace {
29 constexpr uint32_t kOpLineOperandLineIndex = 1;
30 constexpr uint32_t kLineOperandIndexDebugFunction = 7;
31 constexpr uint32_t kLineOperandIndexDebugLexicalBlock = 5;
32 constexpr uint32_t kLineOperandIndexDebugLine = 5;
33 constexpr uint32_t kDebugFunctionOperandFunctionIndex = 13;
34 constexpr uint32_t kDebugFunctionDefinitionOperandDebugFunctionIndex = 4;
35 constexpr uint32_t kDebugFunctionDefinitionOperandOpFunctionIndex = 5;
36 constexpr uint32_t kDebugFunctionOperandParentIndex = 9;
37 constexpr uint32_t kDebugTypeCompositeOperandParentIndex = 9;
38 constexpr uint32_t kDebugLexicalBlockOperandParentIndex = 7;
39 constexpr uint32_t kDebugInlinedAtOperandInlinedIndex = 6;
40 constexpr uint32_t kDebugExpressOperandOperationIndex = 4;
41 constexpr uint32_t kDebugDeclareOperandLocalVariableIndex = 4;
42 constexpr uint32_t kDebugDeclareOperandVariableIndex = 5;
43 constexpr uint32_t kDebugValueOperandExpressionIndex = 6;
44 constexpr uint32_t kDebugOperationOperandOperationIndex = 4;
45 constexpr uint32_t kOpVariableOperandStorageClassIndex = 2;
46 constexpr uint32_t kDebugLocalVariableOperandParentIndex = 9;
47 constexpr uint32_t kExtInstInstructionInIdx = 1;
48 constexpr uint32_t kDebugGlobalVariableOperandFlagsIndex = 12;
49 constexpr uint32_t kDebugLocalVariableOperandFlagsIndex = 10;
50 
SetInlinedOperand(Instruction * dbg_inlined_at,uint32_t inlined_operand)51 void SetInlinedOperand(Instruction* dbg_inlined_at, uint32_t inlined_operand) {
52   assert(dbg_inlined_at);
53   assert(dbg_inlined_at->GetCommonDebugOpcode() ==
54          CommonDebugInfoDebugInlinedAt);
55   if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex) {
56     dbg_inlined_at->AddOperand(
57         {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inlined_operand}});
58   } else {
59     dbg_inlined_at->SetOperand(kDebugInlinedAtOperandInlinedIndex,
60                                {inlined_operand});
61   }
62 }
63 
GetInlinedOperand(Instruction * dbg_inlined_at)64 uint32_t GetInlinedOperand(Instruction* dbg_inlined_at) {
65   assert(dbg_inlined_at);
66   assert(dbg_inlined_at->GetCommonDebugOpcode() ==
67          CommonDebugInfoDebugInlinedAt);
68   if (dbg_inlined_at->NumOperands() <= kDebugInlinedAtOperandInlinedIndex)
69     return kNoInlinedAt;
70   return dbg_inlined_at->GetSingleWordOperand(
71       kDebugInlinedAtOperandInlinedIndex);
72 }
73 
IsEmptyDebugExpression(Instruction * instr)74 bool IsEmptyDebugExpression(Instruction* instr) {
75   return (instr->GetCommonDebugOpcode() == CommonDebugInfoDebugExpression) &&
76          instr->NumOperands() == kDebugExpressOperandOperationIndex;
77 }
78 
79 }  // namespace
80 
DebugInfoManager(IRContext * c)81 DebugInfoManager::DebugInfoManager(IRContext* c) : context_(c) {
82   AnalyzeDebugInsts(*c->module());
83 }
84 
GetDbgSetImportId()85 uint32_t DebugInfoManager::GetDbgSetImportId() {
86   uint32_t setId =
87       context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo();
88   if (setId == 0) {
89     setId =
90         context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo();
91   }
92   return setId;
93 }
94 
GetDbgInst(uint32_t id)95 Instruction* DebugInfoManager::GetDbgInst(uint32_t id) {
96   auto dbg_inst_it = id_to_dbg_inst_.find(id);
97   return dbg_inst_it == id_to_dbg_inst_.end() ? nullptr : dbg_inst_it->second;
98 }
99 
RegisterDbgInst(Instruction * inst)100 void DebugInfoManager::RegisterDbgInst(Instruction* inst) {
101   assert(inst->NumInOperands() != 0 &&
102          (GetDbgSetImportId() == inst->GetInOperand(0).words[0]) &&
103          "Given instruction is not a debug instruction");
104   id_to_dbg_inst_[inst->result_id()] = inst;
105 }
106 
RegisterDbgFunction(Instruction * inst)107 void DebugInfoManager::RegisterDbgFunction(Instruction* inst) {
108   if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) {
109     auto fn_id = inst->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex);
110     // Do not register function that has been optimized away.
111     auto fn_inst = GetDbgInst(fn_id);
112     if (fn_inst != nullptr) {
113       assert(GetDbgInst(fn_id)->GetOpenCL100DebugOpcode() ==
114              OpenCLDebugInfo100DebugInfoNone);
115       return;
116     }
117     assert(
118         fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() &&
119         "Register DebugFunction for a function that already has DebugFunction");
120     fn_id_to_dbg_fn_[fn_id] = inst;
121   } else if (inst->GetShader100DebugOpcode() ==
122              NonSemanticShaderDebugInfo100DebugFunctionDefinition) {
123     auto fn_id = inst->GetSingleWordOperand(
124         kDebugFunctionDefinitionOperandOpFunctionIndex);
125     auto fn_inst = GetDbgInst(inst->GetSingleWordOperand(
126         kDebugFunctionDefinitionOperandDebugFunctionIndex));
127     assert(fn_inst && fn_inst->GetShader100DebugOpcode() ==
128                           NonSemanticShaderDebugInfo100DebugFunction);
129     assert(fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() &&
130            "Register DebugFunctionDefinition for a function that already has "
131            "DebugFunctionDefinition");
132     fn_id_to_dbg_fn_[fn_id] = fn_inst;
133   } else {
134     assert(false && "inst is not a DebugFunction");
135   }
136 }
137 
RegisterDbgDeclare(uint32_t var_id,Instruction * dbg_declare)138 void DebugInfoManager::RegisterDbgDeclare(uint32_t var_id,
139                                           Instruction* dbg_declare) {
140   assert(dbg_declare->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare ||
141          dbg_declare->GetCommonDebugOpcode() == CommonDebugInfoDebugValue);
142   auto dbg_decl_itr = var_id_to_dbg_decl_.find(var_id);
143   if (dbg_decl_itr == var_id_to_dbg_decl_.end()) {
144     var_id_to_dbg_decl_[var_id] = {dbg_declare};
145   } else {
146     dbg_decl_itr->second.insert(dbg_declare);
147   }
148 }
149 
150 // Create new constant directly into global value area, bypassing the
151 // Constant manager. This is used when the DefUse or Constant managers
152 // are invalid and cannot be regenerated due to the module being in an
153 // inconsistent state e.g. in the middle of significant modification
154 // such as inlining. Invalidate Constant and DefUse managers if used.
AddNewConstInGlobals(IRContext * context,uint32_t const_value)155 uint32_t AddNewConstInGlobals(IRContext* context, uint32_t const_value) {
156   uint32_t id = context->TakeNextId();
157   std::unique_ptr<Instruction> new_const(new Instruction(
158       context, spv::Op::OpConstant, context->get_type_mgr()->GetUIntTypeId(),
159       id,
160       {
161           {spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
162            {const_value}},
163       }));
164   context->module()->AddGlobalValue(std::move(new_const));
165   context->InvalidateAnalyses(IRContext::kAnalysisConstants);
166   context->InvalidateAnalyses(IRContext::kAnalysisDefUse);
167   return id;
168 }
169 
CreateDebugInlinedAt(const Instruction * line,const DebugScope & scope)170 uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
171                                                 const DebugScope& scope) {
172   uint32_t setId = GetDbgSetImportId();
173 
174   if (setId == 0) return kNoInlinedAt;
175 
176   spv_operand_type_t line_number_type =
177       spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER;
178 
179   // In NonSemantic.Shader.DebugInfo.100, all constants are IDs of OpConstant,
180   // not literals.
181   if (setId ==
182       context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo())
183     line_number_type = spv_operand_type_t::SPV_OPERAND_TYPE_ID;
184 
185   uint32_t line_number = 0;
186   if (line == nullptr) {
187     auto* lexical_scope_inst = GetDbgInst(scope.GetLexicalScope());
188     if (lexical_scope_inst == nullptr) return kNoInlinedAt;
189     CommonDebugInfoInstructions debug_opcode =
190         lexical_scope_inst->GetCommonDebugOpcode();
191     switch (debug_opcode) {
192       case CommonDebugInfoDebugFunction:
193         line_number = lexical_scope_inst->GetSingleWordOperand(
194             kLineOperandIndexDebugFunction);
195         break;
196       case CommonDebugInfoDebugLexicalBlock:
197         line_number = lexical_scope_inst->GetSingleWordOperand(
198             kLineOperandIndexDebugLexicalBlock);
199         break;
200       case CommonDebugInfoDebugTypeComposite:
201       case CommonDebugInfoDebugCompilationUnit:
202         assert(false &&
203                "DebugTypeComposite and DebugCompilationUnit are lexical "
204                "scopes, but we inline functions into a function or a block "
205                "of a function, not into a struct/class or a global scope.");
206         break;
207       default:
208         assert(false &&
209                "Unreachable. a debug extension instruction for a "
210                "lexical scope must be DebugFunction, DebugTypeComposite, "
211                "DebugLexicalBlock, or DebugCompilationUnit.");
212         break;
213     }
214   } else {
215     if (line->opcode() == spv::Op::OpLine) {
216       line_number = line->GetSingleWordOperand(kOpLineOperandLineIndex);
217     } else if (line->GetShader100DebugOpcode() ==
218                NonSemanticShaderDebugInfo100DebugLine) {
219       line_number = line->GetSingleWordOperand(kLineOperandIndexDebugLine);
220     } else {
221       assert(false &&
222              "Unreachable. A line instruction must be OpLine or DebugLine");
223     }
224 
225     // If we need the line number as an ID, generate that constant now.
226     // If Constant or DefUse managers are invalid, generate constant
227     // directly into the global value section of the module; do not
228     // use Constant manager which may attempt to invoke building of the
229     // DefUse manager which cannot be done during inlining. The extra
230     // constants that may be generated here is likely not significant
231     // and will likely be cleaned up in later passes.
232     if (line_number_type == spv_operand_type_t::SPV_OPERAND_TYPE_ID &&
233         line->opcode() == spv::Op::OpLine) {
234       if (!context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse) ||
235           !context()->AreAnalysesValid(IRContext::Analysis::kAnalysisConstants))
236         line_number = AddNewConstInGlobals(context(), line_number);
237       else
238         line_number =
239             context()->get_constant_mgr()->GetUIntConstId(line_number);
240     }
241   }
242 
243   uint32_t result_id = context()->TakeNextId();
244   std::unique_ptr<Instruction> inlined_at(new Instruction(
245       context(), spv::Op::OpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
246       result_id,
247       {
248           {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {setId}},
249           {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
250            {static_cast<uint32_t>(CommonDebugInfoDebugInlinedAt)}},
251           {line_number_type, {line_number}},
252           {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {scope.GetLexicalScope()}},
253       }));
254   // |scope| already has DebugInlinedAt. We put the existing DebugInlinedAt
255   // into the Inlined operand of this new DebugInlinedAt.
256   if (scope.GetInlinedAt() != kNoInlinedAt) {
257     inlined_at->AddOperand(
258         {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {scope.GetInlinedAt()}});
259   }
260   RegisterDbgInst(inlined_at.get());
261   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
262     context()->get_def_use_mgr()->AnalyzeInstDefUse(inlined_at.get());
263   context()->module()->AddExtInstDebugInfo(std::move(inlined_at));
264   return result_id;
265 }
266 
BuildDebugScope(const DebugScope & callee_instr_scope,DebugInlinedAtContext * inlined_at_ctx)267 DebugScope DebugInfoManager::BuildDebugScope(
268     const DebugScope& callee_instr_scope,
269     DebugInlinedAtContext* inlined_at_ctx) {
270   return DebugScope(callee_instr_scope.GetLexicalScope(),
271                     BuildDebugInlinedAtChain(callee_instr_scope.GetInlinedAt(),
272                                              inlined_at_ctx));
273 }
274 
BuildDebugInlinedAtChain(uint32_t callee_inlined_at,DebugInlinedAtContext * inlined_at_ctx)275 uint32_t DebugInfoManager::BuildDebugInlinedAtChain(
276     uint32_t callee_inlined_at, DebugInlinedAtContext* inlined_at_ctx) {
277   if (inlined_at_ctx->GetScopeOfCallInstruction().GetLexicalScope() ==
278       kNoDebugScope)
279     return kNoInlinedAt;
280 
281   // Reuse the already generated DebugInlinedAt chain if exists.
282   uint32_t already_generated_chain_head_id =
283       inlined_at_ctx->GetDebugInlinedAtChain(callee_inlined_at);
284   if (already_generated_chain_head_id != kNoInlinedAt) {
285     return already_generated_chain_head_id;
286   }
287 
288   const uint32_t new_dbg_inlined_at_id =
289       CreateDebugInlinedAt(inlined_at_ctx->GetLineOfCallInstruction(),
290                            inlined_at_ctx->GetScopeOfCallInstruction());
291   if (new_dbg_inlined_at_id == kNoInlinedAt) return kNoInlinedAt;
292 
293   if (callee_inlined_at == kNoInlinedAt) {
294     inlined_at_ctx->SetDebugInlinedAtChain(kNoInlinedAt, new_dbg_inlined_at_id);
295     return new_dbg_inlined_at_id;
296   }
297 
298   uint32_t chain_head_id = kNoInlinedAt;
299   uint32_t chain_iter_id = callee_inlined_at;
300   Instruction* last_inlined_at_in_chain = nullptr;
301   do {
302     Instruction* new_inlined_at_in_chain = CloneDebugInlinedAt(
303         chain_iter_id, /* insert_before */ last_inlined_at_in_chain);
304     assert(new_inlined_at_in_chain != nullptr);
305 
306     // Set DebugInlinedAt of the new scope as the head of the chain.
307     if (chain_head_id == kNoInlinedAt)
308       chain_head_id = new_inlined_at_in_chain->result_id();
309 
310     // Previous DebugInlinedAt of the chain must point to the new
311     // DebugInlinedAt as its Inlined operand to build a recursive
312     // chain.
313     if (last_inlined_at_in_chain != nullptr) {
314       SetInlinedOperand(last_inlined_at_in_chain,
315                         new_inlined_at_in_chain->result_id());
316     }
317     last_inlined_at_in_chain = new_inlined_at_in_chain;
318 
319     chain_iter_id = GetInlinedOperand(new_inlined_at_in_chain);
320   } while (chain_iter_id != kNoInlinedAt);
321 
322   // Put |new_dbg_inlined_at_id| into the end of the chain.
323   SetInlinedOperand(last_inlined_at_in_chain, new_dbg_inlined_at_id);
324 
325   // Keep the new chain information that will be reused it.
326   inlined_at_ctx->SetDebugInlinedAtChain(callee_inlined_at, chain_head_id);
327   return chain_head_id;
328 }
329 
GetDebugOperationWithDeref()330 Instruction* DebugInfoManager::GetDebugOperationWithDeref() {
331   if (deref_operation_ != nullptr) return deref_operation_;
332 
333   uint32_t result_id = context()->TakeNextId();
334   std::unique_ptr<Instruction> deref_operation;
335 
336   if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
337     deref_operation = std::unique_ptr<Instruction>(new Instruction(
338         context(), spv::Op::OpExtInst,
339         context()->get_type_mgr()->GetVoidTypeId(), result_id,
340         {
341             {SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
342             {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
343              {static_cast<uint32_t>(OpenCLDebugInfo100DebugOperation)}},
344             {SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION,
345              {static_cast<uint32_t>(OpenCLDebugInfo100Deref)}},
346         }));
347   } else {
348     uint32_t deref_id = context()->get_constant_mgr()->GetUIntConstId(
349         NonSemanticShaderDebugInfo100Deref);
350 
351     deref_operation = std::unique_ptr<Instruction>(
352         new Instruction(context(), spv::Op::OpExtInst,
353                         context()->get_type_mgr()->GetVoidTypeId(), result_id,
354                         {
355                             {SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
356                             {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
357                              {static_cast<uint32_t>(
358                                  NonSemanticShaderDebugInfo100DebugOperation)}},
359                             {SPV_OPERAND_TYPE_ID, {deref_id}},
360                         }));
361   }
362 
363   // Add to the front of |ext_inst_debuginfo_|.
364   deref_operation_ =
365       context()->module()->ext_inst_debuginfo_begin()->InsertBefore(
366           std::move(deref_operation));
367 
368   RegisterDbgInst(deref_operation_);
369   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
370     context()->get_def_use_mgr()->AnalyzeInstDefUse(deref_operation_);
371   return deref_operation_;
372 }
373 
DerefDebugExpression(Instruction * dbg_expr)374 Instruction* DebugInfoManager::DerefDebugExpression(Instruction* dbg_expr) {
375   assert(dbg_expr->GetCommonDebugOpcode() == CommonDebugInfoDebugExpression);
376   std::unique_ptr<Instruction> deref_expr(dbg_expr->Clone(context()));
377   deref_expr->SetResultId(context()->TakeNextId());
378   deref_expr->InsertOperand(
379       kDebugExpressOperandOperationIndex,
380       {SPV_OPERAND_TYPE_ID, {GetDebugOperationWithDeref()->result_id()}});
381   auto* deref_expr_instr =
382       context()->ext_inst_debuginfo_end()->InsertBefore(std::move(deref_expr));
383   AnalyzeDebugInst(deref_expr_instr);
384   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
385     context()->get_def_use_mgr()->AnalyzeInstDefUse(deref_expr_instr);
386   return deref_expr_instr;
387 }
388 
GetDebugInfoNone()389 Instruction* DebugInfoManager::GetDebugInfoNone() {
390   if (debug_info_none_inst_ != nullptr) return debug_info_none_inst_;
391 
392   uint32_t result_id = context()->TakeNextId();
393   std::unique_ptr<Instruction> dbg_info_none_inst(new Instruction(
394       context(), spv::Op::OpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
395       result_id,
396       {
397           {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
398           {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
399            {static_cast<uint32_t>(CommonDebugInfoDebugInfoNone)}},
400       }));
401 
402   // Add to the front of |ext_inst_debuginfo_|.
403   debug_info_none_inst_ =
404       context()->module()->ext_inst_debuginfo_begin()->InsertBefore(
405           std::move(dbg_info_none_inst));
406 
407   RegisterDbgInst(debug_info_none_inst_);
408   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
409     context()->get_def_use_mgr()->AnalyzeInstDefUse(debug_info_none_inst_);
410   return debug_info_none_inst_;
411 }
412 
GetEmptyDebugExpression()413 Instruction* DebugInfoManager::GetEmptyDebugExpression() {
414   if (empty_debug_expr_inst_ != nullptr) return empty_debug_expr_inst_;
415 
416   uint32_t result_id = context()->TakeNextId();
417   std::unique_ptr<Instruction> empty_debug_expr(new Instruction(
418       context(), spv::Op::OpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
419       result_id,
420       {
421           {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
422           {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
423            {static_cast<uint32_t>(CommonDebugInfoDebugExpression)}},
424       }));
425 
426   // Add to the front of |ext_inst_debuginfo_|.
427   empty_debug_expr_inst_ =
428       context()->module()->ext_inst_debuginfo_begin()->InsertBefore(
429           std::move(empty_debug_expr));
430 
431   RegisterDbgInst(empty_debug_expr_inst_);
432   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
433     context()->get_def_use_mgr()->AnalyzeInstDefUse(empty_debug_expr_inst_);
434   return empty_debug_expr_inst_;
435 }
436 
GetDebugInlinedAt(uint32_t dbg_inlined_at_id)437 Instruction* DebugInfoManager::GetDebugInlinedAt(uint32_t dbg_inlined_at_id) {
438   auto* inlined_at = GetDbgInst(dbg_inlined_at_id);
439   if (inlined_at == nullptr) return nullptr;
440   if (inlined_at->GetCommonDebugOpcode() != CommonDebugInfoDebugInlinedAt) {
441     return nullptr;
442   }
443   return inlined_at;
444 }
445 
CloneDebugInlinedAt(uint32_t clone_inlined_at_id,Instruction * insert_before)446 Instruction* DebugInfoManager::CloneDebugInlinedAt(uint32_t clone_inlined_at_id,
447                                                    Instruction* insert_before) {
448   auto* inlined_at = GetDebugInlinedAt(clone_inlined_at_id);
449   if (inlined_at == nullptr) return nullptr;
450   std::unique_ptr<Instruction> new_inlined_at(inlined_at->Clone(context()));
451   new_inlined_at->SetResultId(context()->TakeNextId());
452   RegisterDbgInst(new_inlined_at.get());
453   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
454     context()->get_def_use_mgr()->AnalyzeInstDefUse(new_inlined_at.get());
455   if (insert_before != nullptr)
456     return insert_before->InsertBefore(std::move(new_inlined_at));
457   return context()->module()->ext_inst_debuginfo_end()->InsertBefore(
458       std::move(new_inlined_at));
459 }
460 
IsVariableDebugDeclared(uint32_t variable_id)461 bool DebugInfoManager::IsVariableDebugDeclared(uint32_t variable_id) {
462   auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id);
463   return dbg_decl_itr != var_id_to_dbg_decl_.end();
464 }
465 
KillDebugDeclares(uint32_t variable_id)466 bool DebugInfoManager::KillDebugDeclares(uint32_t variable_id) {
467   bool modified = false;
468   auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id);
469   if (dbg_decl_itr != var_id_to_dbg_decl_.end()) {
470     // We intentionally copy the list of DebugDeclare instructions because
471     // context()->KillInst(dbg_decl) will update |var_id_to_dbg_decl_|. If we
472     // directly use |dbg_decl_itr->second|, it accesses a dangling pointer.
473     auto copy_dbg_decls = dbg_decl_itr->second;
474 
475     for (auto* dbg_decl : copy_dbg_decls) {
476       context()->KillInst(dbg_decl);
477       modified = true;
478     }
479     var_id_to_dbg_decl_.erase(dbg_decl_itr);
480   }
481   return modified;
482 }
483 
GetParentScope(uint32_t child_scope)484 uint32_t DebugInfoManager::GetParentScope(uint32_t child_scope) {
485   auto dbg_scope_itr = id_to_dbg_inst_.find(child_scope);
486   assert(dbg_scope_itr != id_to_dbg_inst_.end());
487   CommonDebugInfoInstructions debug_opcode =
488       dbg_scope_itr->second->GetCommonDebugOpcode();
489   uint32_t parent_scope = kNoDebugScope;
490   switch (debug_opcode) {
491     case CommonDebugInfoDebugFunction:
492       parent_scope = dbg_scope_itr->second->GetSingleWordOperand(
493           kDebugFunctionOperandParentIndex);
494       break;
495     case CommonDebugInfoDebugLexicalBlock:
496       parent_scope = dbg_scope_itr->second->GetSingleWordOperand(
497           kDebugLexicalBlockOperandParentIndex);
498       break;
499     case CommonDebugInfoDebugTypeComposite:
500       parent_scope = dbg_scope_itr->second->GetSingleWordOperand(
501           kDebugTypeCompositeOperandParentIndex);
502       break;
503     case CommonDebugInfoDebugCompilationUnit:
504       // DebugCompilationUnit does not have a parent scope.
505       break;
506     default:
507       assert(false &&
508              "Unreachable. A debug scope instruction must be "
509              "DebugFunction, DebugTypeComposite, DebugLexicalBlock, "
510              "or DebugCompilationUnit.");
511       break;
512   }
513   return parent_scope;
514 }
515 
IsAncestorOfScope(uint32_t scope,uint32_t ancestor)516 bool DebugInfoManager::IsAncestorOfScope(uint32_t scope, uint32_t ancestor) {
517   uint32_t ancestor_scope_itr = scope;
518   while (ancestor_scope_itr != kNoDebugScope) {
519     if (ancestor == ancestor_scope_itr) return true;
520     ancestor_scope_itr = GetParentScope(ancestor_scope_itr);
521   }
522   return false;
523 }
524 
IsDeclareVisibleToInstr(Instruction * dbg_declare,Instruction * scope)525 bool DebugInfoManager::IsDeclareVisibleToInstr(Instruction* dbg_declare,
526                                                Instruction* scope) {
527   assert(dbg_declare != nullptr);
528   assert(scope != nullptr);
529 
530   std::vector<uint32_t> scope_ids;
531   if (scope->opcode() == spv::Op::OpPhi) {
532     scope_ids.push_back(scope->GetDebugScope().GetLexicalScope());
533     for (uint32_t i = 0; i < scope->NumInOperands(); i += 2) {
534       auto* value = context()->get_def_use_mgr()->GetDef(
535           scope->GetSingleWordInOperand(i));
536       if (value != nullptr)
537         scope_ids.push_back(value->GetDebugScope().GetLexicalScope());
538     }
539   } else {
540     scope_ids.push_back(scope->GetDebugScope().GetLexicalScope());
541   }
542 
543   uint32_t dbg_local_var_id =
544       dbg_declare->GetSingleWordOperand(kDebugDeclareOperandLocalVariableIndex);
545   auto dbg_local_var_itr = id_to_dbg_inst_.find(dbg_local_var_id);
546   assert(dbg_local_var_itr != id_to_dbg_inst_.end());
547   uint32_t decl_scope_id = dbg_local_var_itr->second->GetSingleWordOperand(
548       kDebugLocalVariableOperandParentIndex);
549 
550   // If the scope of DebugDeclare is an ancestor scope of the instruction's
551   // scope, the local variable is visible to the instruction.
552   for (uint32_t scope_id : scope_ids) {
553     if (scope_id != kNoDebugScope &&
554         IsAncestorOfScope(scope_id, decl_scope_id)) {
555       return true;
556     }
557   }
558   return false;
559 }
560 
AddDebugValueForVariable(Instruction * scope_and_line,uint32_t variable_id,uint32_t value_id,Instruction * insert_pos)561 bool DebugInfoManager::AddDebugValueForVariable(Instruction* scope_and_line,
562                                                 uint32_t variable_id,
563                                                 uint32_t value_id,
564                                                 Instruction* insert_pos) {
565   assert(scope_and_line != nullptr);
566 
567   auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id);
568   if (dbg_decl_itr == var_id_to_dbg_decl_.end()) return false;
569 
570   bool modified = false;
571   for (auto* dbg_decl_or_val : dbg_decl_itr->second) {
572     // Avoid inserting the new DebugValue between OpPhi or OpVariable
573     // instructions.
574     Instruction* insert_before = insert_pos->NextNode();
575     while (insert_before->opcode() == spv::Op::OpPhi ||
576            insert_before->opcode() == spv::Op::OpVariable) {
577       insert_before = insert_before->NextNode();
578     }
579     modified |= AddDebugValueForDecl(dbg_decl_or_val, value_id, insert_before,
580                                      scope_and_line) != nullptr;
581   }
582   return modified;
583 }
584 
AddDebugValueForDecl(Instruction * dbg_decl,uint32_t value_id,Instruction * insert_before,Instruction * scope_and_line)585 Instruction* DebugInfoManager::AddDebugValueForDecl(
586     Instruction* dbg_decl, uint32_t value_id, Instruction* insert_before,
587     Instruction* scope_and_line) {
588   if (dbg_decl == nullptr || !IsDebugDeclare(dbg_decl)) return nullptr;
589 
590   std::unique_ptr<Instruction> dbg_val(dbg_decl->Clone(context()));
591   dbg_val->SetResultId(context()->TakeNextId());
592   dbg_val->SetInOperand(kExtInstInstructionInIdx, {CommonDebugInfoDebugValue});
593   dbg_val->SetOperand(kDebugDeclareOperandVariableIndex, {value_id});
594   dbg_val->SetOperand(kDebugValueOperandExpressionIndex,
595                       {GetEmptyDebugExpression()->result_id()});
596   dbg_val->UpdateDebugInfoFrom(scope_and_line);
597 
598   auto* added_dbg_val = insert_before->InsertBefore(std::move(dbg_val));
599   AnalyzeDebugInst(added_dbg_val);
600   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
601     context()->get_def_use_mgr()->AnalyzeInstDefUse(added_dbg_val);
602   if (context()->AreAnalysesValid(
603           IRContext::Analysis::kAnalysisInstrToBlockMapping)) {
604     auto insert_blk = context()->get_instr_block(insert_before);
605     context()->set_instr_block(added_dbg_val, insert_blk);
606   }
607   return added_dbg_val;
608 }
609 
GetVulkanDebugOperation(Instruction * inst)610 uint32_t DebugInfoManager::GetVulkanDebugOperation(Instruction* inst) {
611   assert(inst->GetShader100DebugOpcode() ==
612              NonSemanticShaderDebugInfo100DebugOperation &&
613          "inst must be Vulkan DebugOperation");
614   return context()
615       ->get_constant_mgr()
616       ->GetConstantFromInst(context()->get_def_use_mgr()->GetDef(
617           inst->GetSingleWordOperand(kDebugOperationOperandOperationIndex)))
618       ->GetU32();
619 }
620 
GetVariableIdOfDebugValueUsedForDeclare(Instruction * inst)621 uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare(
622     Instruction* inst) {
623   if (inst->GetCommonDebugOpcode() != CommonDebugInfoDebugValue) return 0;
624 
625   auto* expr =
626       GetDbgInst(inst->GetSingleWordOperand(kDebugValueOperandExpressionIndex));
627   if (expr == nullptr) return 0;
628   if (expr->NumOperands() != kDebugExpressOperandOperationIndex + 1) return 0;
629 
630   auto* operation = GetDbgInst(
631       expr->GetSingleWordOperand(kDebugExpressOperandOperationIndex));
632   if (operation == nullptr) return 0;
633 
634   // OpenCL.DebugInfo.100 contains a literal for the operation, Vulkan uses an
635   // OpConstant.
636   if (inst->IsOpenCL100DebugInstr()) {
637     if (operation->GetSingleWordOperand(kDebugOperationOperandOperationIndex) !=
638         OpenCLDebugInfo100Deref) {
639       return 0;
640     }
641   } else {
642     uint32_t operation_const = GetVulkanDebugOperation(operation);
643     if (operation_const != NonSemanticShaderDebugInfo100Deref) {
644       return 0;
645     }
646   }
647 
648   uint32_t var_id =
649       inst->GetSingleWordOperand(kDebugDeclareOperandVariableIndex);
650   if (!context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse)) {
651     assert(false &&
652            "Checking a DebugValue can be used for declare needs DefUseManager");
653     return 0;
654   }
655 
656   auto* var = context()->get_def_use_mgr()->GetDef(var_id);
657   if (var->opcode() == spv::Op::OpVariable &&
658       spv::StorageClass(
659           var->GetSingleWordOperand(kOpVariableOperandStorageClassIndex)) ==
660           spv::StorageClass::Function) {
661     return var_id;
662   }
663   return 0;
664 }
665 
IsDebugDeclare(Instruction * instr)666 bool DebugInfoManager::IsDebugDeclare(Instruction* instr) {
667   if (!instr->IsCommonDebugInstr()) return false;
668   return instr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare ||
669          GetVariableIdOfDebugValueUsedForDeclare(instr) != 0;
670 }
671 
ReplaceAllUsesInDebugScopeWithPredicate(uint32_t before,uint32_t after,const std::function<bool (Instruction *)> & predicate)672 void DebugInfoManager::ReplaceAllUsesInDebugScopeWithPredicate(
673     uint32_t before, uint32_t after,
674     const std::function<bool(Instruction*)>& predicate) {
675   auto scope_id_to_users_itr = scope_id_to_users_.find(before);
676   if (scope_id_to_users_itr != scope_id_to_users_.end()) {
677     for (Instruction* inst : scope_id_to_users_itr->second) {
678       if (predicate(inst)) inst->UpdateLexicalScope(after);
679     }
680     scope_id_to_users_[after] = scope_id_to_users_itr->second;
681     scope_id_to_users_.erase(scope_id_to_users_itr);
682   }
683   auto inlinedat_id_to_users_itr = inlinedat_id_to_users_.find(before);
684   if (inlinedat_id_to_users_itr != inlinedat_id_to_users_.end()) {
685     for (Instruction* inst : inlinedat_id_to_users_itr->second) {
686       if (predicate(inst)) inst->UpdateDebugInlinedAt(after);
687     }
688     inlinedat_id_to_users_[after] = inlinedat_id_to_users_itr->second;
689     inlinedat_id_to_users_.erase(inlinedat_id_to_users_itr);
690   }
691 }
692 
ClearDebugScopeAndInlinedAtUses(Instruction * inst)693 void DebugInfoManager::ClearDebugScopeAndInlinedAtUses(Instruction* inst) {
694   auto scope_id_to_users_itr = scope_id_to_users_.find(inst->result_id());
695   if (scope_id_to_users_itr != scope_id_to_users_.end()) {
696     scope_id_to_users_.erase(scope_id_to_users_itr);
697   }
698   auto inlinedat_id_to_users_itr =
699       inlinedat_id_to_users_.find(inst->result_id());
700   if (inlinedat_id_to_users_itr != inlinedat_id_to_users_.end()) {
701     inlinedat_id_to_users_.erase(inlinedat_id_to_users_itr);
702   }
703 }
704 
AnalyzeDebugInst(Instruction * inst)705 void DebugInfoManager::AnalyzeDebugInst(Instruction* inst) {
706   if (inst->GetDebugScope().GetLexicalScope() != kNoDebugScope) {
707     auto& users = scope_id_to_users_[inst->GetDebugScope().GetLexicalScope()];
708     users.insert(inst);
709   }
710   if (inst->GetDebugInlinedAt() != kNoInlinedAt) {
711     auto& users = inlinedat_id_to_users_[inst->GetDebugInlinedAt()];
712     users.insert(inst);
713   }
714 
715   if (!inst->IsCommonDebugInstr()) return;
716 
717   RegisterDbgInst(inst);
718 
719   if (inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction ||
720       inst->GetShader100DebugOpcode() ==
721           NonSemanticShaderDebugInfo100DebugFunctionDefinition) {
722     RegisterDbgFunction(inst);
723   }
724 
725   if (deref_operation_ == nullptr &&
726       inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugOperation &&
727       inst->GetSingleWordOperand(kDebugOperationOperandOperationIndex) ==
728           OpenCLDebugInfo100Deref) {
729     deref_operation_ = inst;
730   }
731 
732   if (deref_operation_ == nullptr &&
733       inst->GetShader100DebugOpcode() ==
734           NonSemanticShaderDebugInfo100DebugOperation) {
735     uint32_t operation_const = GetVulkanDebugOperation(inst);
736     if (operation_const == NonSemanticShaderDebugInfo100Deref) {
737       deref_operation_ = inst;
738     }
739   }
740 
741   if (debug_info_none_inst_ == nullptr &&
742       inst->GetCommonDebugOpcode() == CommonDebugInfoDebugInfoNone) {
743     debug_info_none_inst_ = inst;
744   }
745 
746   if (empty_debug_expr_inst_ == nullptr && IsEmptyDebugExpression(inst)) {
747     empty_debug_expr_inst_ = inst;
748   }
749 
750   if (inst->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare) {
751     uint32_t var_id =
752         inst->GetSingleWordOperand(kDebugDeclareOperandVariableIndex);
753     RegisterDbgDeclare(var_id, inst);
754   }
755 
756   if (uint32_t var_id = GetVariableIdOfDebugValueUsedForDeclare(inst)) {
757     RegisterDbgDeclare(var_id, inst);
758   }
759 }
760 
ConvertDebugGlobalToLocalVariable(Instruction * dbg_global_var,Instruction * local_var)761 void DebugInfoManager::ConvertDebugGlobalToLocalVariable(
762     Instruction* dbg_global_var, Instruction* local_var) {
763   if (dbg_global_var->GetCommonDebugOpcode() !=
764       CommonDebugInfoDebugGlobalVariable) {
765     return;
766   }
767   assert(local_var->opcode() == spv::Op::OpVariable ||
768          local_var->opcode() == spv::Op::OpFunctionParameter);
769 
770   // Convert |dbg_global_var| to DebugLocalVariable
771   dbg_global_var->SetInOperand(kExtInstInstructionInIdx,
772                                {CommonDebugInfoDebugLocalVariable});
773   auto flags = dbg_global_var->GetSingleWordOperand(
774       kDebugGlobalVariableOperandFlagsIndex);
775   for (uint32_t i = dbg_global_var->NumInOperands() - 1;
776        i >= kDebugLocalVariableOperandFlagsIndex; --i) {
777     dbg_global_var->RemoveOperand(i);
778   }
779   dbg_global_var->SetOperand(kDebugLocalVariableOperandFlagsIndex, {flags});
780   context()->ForgetUses(dbg_global_var);
781   context()->AnalyzeUses(dbg_global_var);
782 
783   // Create a DebugDeclare
784   std::unique_ptr<Instruction> new_dbg_decl(new Instruction(
785       context(), spv::Op::OpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
786       context()->TakeNextId(),
787       {
788           {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {GetDbgSetImportId()}},
789           {spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
790            {static_cast<uint32_t>(CommonDebugInfoDebugDeclare)}},
791           {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
792            {dbg_global_var->result_id()}},
793           {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {local_var->result_id()}},
794           {spv_operand_type_t::SPV_OPERAND_TYPE_ID,
795            {GetEmptyDebugExpression()->result_id()}},
796       }));
797   // Must insert after all OpVariables in block
798   Instruction* insert_before = local_var;
799   while (insert_before->opcode() == spv::Op::OpVariable)
800     insert_before = insert_before->NextNode();
801   auto* added_dbg_decl = insert_before->InsertBefore(std::move(new_dbg_decl));
802   if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
803     context()->get_def_use_mgr()->AnalyzeInstDefUse(added_dbg_decl);
804   if (context()->AreAnalysesValid(
805           IRContext::Analysis::kAnalysisInstrToBlockMapping)) {
806     auto insert_blk = context()->get_instr_block(local_var);
807     context()->set_instr_block(added_dbg_decl, insert_blk);
808   }
809 }
810 
AnalyzeDebugInsts(Module & module)811 void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
812   deref_operation_ = nullptr;
813   debug_info_none_inst_ = nullptr;
814   empty_debug_expr_inst_ = nullptr;
815   module.ForEachInst([this](Instruction* cpi) { AnalyzeDebugInst(cpi); });
816 
817   // Move |empty_debug_expr_inst_| to the beginning of the debug instruction
818   // list.
819   if (empty_debug_expr_inst_ != nullptr &&
820       empty_debug_expr_inst_->PreviousNode() != nullptr &&
821       empty_debug_expr_inst_->PreviousNode()->IsCommonDebugInstr()) {
822     empty_debug_expr_inst_->InsertBefore(
823         &*context()->module()->ext_inst_debuginfo_begin());
824   }
825 
826   // Move |debug_info_none_inst_| to the beginning of the debug instruction
827   // list.
828   if (debug_info_none_inst_ != nullptr &&
829       debug_info_none_inst_->PreviousNode() != nullptr &&
830       debug_info_none_inst_->PreviousNode()->IsCommonDebugInstr()) {
831     debug_info_none_inst_->InsertBefore(
832         &*context()->module()->ext_inst_debuginfo_begin());
833   }
834 }
835 
ClearDebugInfo(Instruction * instr)836 void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
837   auto scope_id_to_users_itr =
838       scope_id_to_users_.find(instr->GetDebugScope().GetLexicalScope());
839   if (scope_id_to_users_itr != scope_id_to_users_.end()) {
840     scope_id_to_users_itr->second.erase(instr);
841   }
842   auto inlinedat_id_to_users_itr =
843       inlinedat_id_to_users_.find(instr->GetDebugInlinedAt());
844   if (inlinedat_id_to_users_itr != inlinedat_id_to_users_.end()) {
845     inlinedat_id_to_users_itr->second.erase(instr);
846   }
847 
848   if (instr == nullptr || !instr->IsCommonDebugInstr()) {
849     return;
850   }
851 
852   id_to_dbg_inst_.erase(instr->result_id());
853 
854   if (instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) {
855     auto fn_id =
856         instr->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex);
857     fn_id_to_dbg_fn_.erase(fn_id);
858   }
859   if (instr->GetShader100DebugOpcode() ==
860       NonSemanticShaderDebugInfo100DebugFunctionDefinition) {
861     auto fn_id = instr->GetSingleWordOperand(
862         kDebugFunctionDefinitionOperandOpFunctionIndex);
863     fn_id_to_dbg_fn_.erase(fn_id);
864   }
865 
866   if (instr->GetCommonDebugOpcode() == CommonDebugInfoDebugDeclare ||
867       instr->GetCommonDebugOpcode() == CommonDebugInfoDebugValue) {
868     auto var_or_value_id =
869         instr->GetSingleWordOperand(kDebugDeclareOperandVariableIndex);
870     auto dbg_decl_itr = var_id_to_dbg_decl_.find(var_or_value_id);
871     if (dbg_decl_itr != var_id_to_dbg_decl_.end()) {
872       dbg_decl_itr->second.erase(instr);
873     }
874   }
875 
876   if (deref_operation_ == instr) {
877     deref_operation_ = nullptr;
878     for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
879          dbg_instr_itr != context()->module()->ext_inst_debuginfo_end();
880          ++dbg_instr_itr) {
881       // OpenCL.DebugInfo.100 contains the operation as a literal operand, in
882       // Vulkan it's referenced as an OpConstant.
883       if (instr != &*dbg_instr_itr &&
884           dbg_instr_itr->GetOpenCL100DebugOpcode() ==
885               OpenCLDebugInfo100DebugOperation &&
886           dbg_instr_itr->GetSingleWordOperand(
887               kDebugOperationOperandOperationIndex) ==
888               OpenCLDebugInfo100Deref) {
889         deref_operation_ = &*dbg_instr_itr;
890         break;
891       } else if (instr != &*dbg_instr_itr &&
892                  dbg_instr_itr->GetShader100DebugOpcode() ==
893                      NonSemanticShaderDebugInfo100DebugOperation) {
894         uint32_t operation_const = GetVulkanDebugOperation(&*dbg_instr_itr);
895         if (operation_const == NonSemanticShaderDebugInfo100Deref) {
896           deref_operation_ = &*dbg_instr_itr;
897           break;
898         }
899       }
900     }
901   }
902 
903   if (debug_info_none_inst_ == instr) {
904     debug_info_none_inst_ = nullptr;
905     for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
906          dbg_instr_itr != context()->module()->ext_inst_debuginfo_end();
907          ++dbg_instr_itr) {
908       if (instr != &*dbg_instr_itr && dbg_instr_itr->GetCommonDebugOpcode() ==
909                                           CommonDebugInfoDebugInfoNone) {
910         debug_info_none_inst_ = &*dbg_instr_itr;
911         break;
912       }
913     }
914   }
915 
916   if (empty_debug_expr_inst_ == instr) {
917     empty_debug_expr_inst_ = nullptr;
918     for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
919          dbg_instr_itr != context()->module()->ext_inst_debuginfo_end();
920          ++dbg_instr_itr) {
921       if (instr != &*dbg_instr_itr && IsEmptyDebugExpression(&*dbg_instr_itr)) {
922         empty_debug_expr_inst_ = &*dbg_instr_itr;
923         break;
924       }
925     }
926   }
927 }
928 
929 }  // namespace analysis
930 }  // namespace opt
931 }  // namespace spvtools
932