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