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