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 #ifndef SOURCE_OPT_DEBUG_INFO_MANAGER_H_ 16 #define SOURCE_OPT_DEBUG_INFO_MANAGER_H_ 17 18 #include <set> 19 #include <unordered_map> 20 #include <unordered_set> 21 22 #include "source/opt/instruction.h" 23 #include "source/opt/module.h" 24 25 namespace spvtools { 26 namespace opt { 27 namespace analysis { 28 29 // When an instruction of a callee function is inlined to its caller function, 30 // we need the line and the scope information of the function call instruction 31 // to generate DebugInlinedAt. This class keeps the data. For multiple inlining 32 // of a single instruction, we have to create multiple DebugInlinedAt 33 // instructions as a chain. This class keeps the information of the generated 34 // DebugInlinedAt chains to reduce the number of chains. 35 class DebugInlinedAtContext { 36 public: DebugInlinedAtContext(Instruction * call_inst)37 explicit DebugInlinedAtContext(Instruction* call_inst) 38 : call_inst_line_(call_inst->dbg_line_inst()), 39 call_inst_scope_(call_inst->GetDebugScope()) {} 40 GetLineOfCallInstruction()41 const Instruction* GetLineOfCallInstruction() { return call_inst_line_; } GetScopeOfCallInstruction()42 const DebugScope& GetScopeOfCallInstruction() { return call_inst_scope_; } 43 // Puts the DebugInlinedAt chain that is generated for the callee instruction 44 // whose DebugInlinedAt of DebugScope is |callee_instr_inlined_at| into 45 // |callee_inlined_at2chain_|. SetDebugInlinedAtChain(uint32_t callee_instr_inlined_at,uint32_t chain_head_id)46 void SetDebugInlinedAtChain(uint32_t callee_instr_inlined_at, 47 uint32_t chain_head_id) { 48 callee_inlined_at2chain_[callee_instr_inlined_at] = chain_head_id; 49 } 50 // Gets the DebugInlinedAt chain from |callee_inlined_at2chain_|. GetDebugInlinedAtChain(uint32_t callee_instr_inlined_at)51 uint32_t GetDebugInlinedAtChain(uint32_t callee_instr_inlined_at) { 52 auto chain_itr = callee_inlined_at2chain_.find(callee_instr_inlined_at); 53 if (chain_itr != callee_inlined_at2chain_.end()) return chain_itr->second; 54 return kNoInlinedAt; 55 } 56 57 private: 58 // The line information of the function call instruction that will be 59 // replaced by the callee function. 60 const Instruction* call_inst_line_; 61 62 // The scope information of the function call instruction that will be 63 // replaced by the callee function. 64 const DebugScope call_inst_scope_; 65 66 // Map from DebugInlinedAt ids of callee to head ids of new generated 67 // DebugInlinedAt chain. 68 std::unordered_map<uint32_t, uint32_t> callee_inlined_at2chain_; 69 }; 70 71 // A class for analyzing, managing, and creating OpenCL.DebugInfo.100 and 72 // NonSemantic.Shader.DebugInfo.100 extension instructions. 73 class DebugInfoManager { 74 public: 75 // Constructs a debug information manager from the given |context|. 76 DebugInfoManager(IRContext* context); 77 78 DebugInfoManager(const DebugInfoManager&) = delete; 79 DebugInfoManager(DebugInfoManager&&) = delete; 80 DebugInfoManager& operator=(const DebugInfoManager&) = delete; 81 DebugInfoManager& operator=(DebugInfoManager&&) = delete; 82 83 friend bool operator==(const DebugInfoManager&, const DebugInfoManager&); 84 friend bool operator!=(const DebugInfoManager& lhs, 85 const DebugInfoManager& rhs) { 86 return !(lhs == rhs); 87 } 88 89 // Analyzes DebugInfo instruction |dbg_inst|. 90 void AnalyzeDebugInst(Instruction* dbg_inst); 91 92 // Creates new DebugInlinedAt and returns its id. Its line operand is the 93 // line number of |line| if |line| is not nullptr. Otherwise, its line operand 94 // is the line number of lexical scope of |scope|. Its Scope and Inlined 95 // operands are Scope and Inlined of |scope|. 96 uint32_t CreateDebugInlinedAt(const Instruction* line, 97 const DebugScope& scope); 98 99 // Clones DebugExpress instruction |dbg_expr| and add Deref Operation 100 // in the front of the Operation list of |dbg_expr|. 101 Instruction* DerefDebugExpression(Instruction* dbg_expr); 102 103 // Returns a DebugInfoNone instruction. 104 Instruction* GetDebugInfoNone(); 105 106 // Returns DebugInlinedAt whose id is |dbg_inlined_at_id|. If it does not 107 // exist or it is not a DebugInlinedAt instruction, return nullptr. 108 Instruction* GetDebugInlinedAt(uint32_t dbg_inlined_at_id); 109 110 // Returns DebugFunction whose Function operand is |fn_id|. If it does not 111 // exist, return nullptr. GetDebugFunction(uint32_t fn_id)112 Instruction* GetDebugFunction(uint32_t fn_id) { 113 auto dbg_fn_it = fn_id_to_dbg_fn_.find(fn_id); 114 return dbg_fn_it == fn_id_to_dbg_fn_.end() ? nullptr : dbg_fn_it->second; 115 } 116 117 // Clones DebugInlinedAt whose id is |clone_inlined_at_id|. If 118 // |clone_inlined_at_id| is not an id of DebugInlinedAt, returns nullptr. 119 // If |insert_before| is given, inserts the new DebugInlinedAt before it. 120 // Otherwise, inserts the new DebugInlinedAt into the debug instruction 121 // section of the module. 122 Instruction* CloneDebugInlinedAt(uint32_t clone_inlined_at_id, 123 Instruction* insert_before = nullptr); 124 125 // Returns the debug scope corresponding to an inlining instruction in the 126 // scope |callee_instr_scope| into |inlined_at_ctx|. Generates all new 127 // debug instructions needed to represent the scope. 128 DebugScope BuildDebugScope(const DebugScope& callee_instr_scope, 129 DebugInlinedAtContext* inlined_at_ctx); 130 131 // Returns DebugInlinedAt corresponding to inlining an instruction, which 132 // was inlined at |callee_inlined_at|, into |inlined_at_ctx|. Generates all 133 // new debug instructions needed to represent the DebugInlinedAt. 134 uint32_t BuildDebugInlinedAtChain(uint32_t callee_inlined_at, 135 DebugInlinedAtContext* inlined_at_ctx); 136 137 // Returns true if there is a debug declaration instruction whose 138 // 'Local Variable' operand is |variable_id|. 139 bool IsVariableDebugDeclared(uint32_t variable_id); 140 141 // Kills all debug declaration instructions with Deref whose 'Local Variable' 142 // operand is |variable_id|. Returns whether it kills an instruction or not. 143 bool KillDebugDeclares(uint32_t variable_id); 144 145 // Generates a DebugValue instruction with value |value_id| for every local 146 // variable that is in the scope of |scope_and_line| and whose memory is 147 // |variable_id| and inserts it after the instruction |insert_pos|. 148 // Returns whether a DebugValue is added or not. 149 bool AddDebugValueForVariable(Instruction* scope_and_line, 150 uint32_t variable_id, uint32_t value_id, 151 Instruction* insert_pos); 152 153 // Creates a DebugValue for DebugDeclare |dbg_decl| and inserts it before 154 // |insert_before|. The new DebugValue has the same line and scope as 155 // |scope_and_line|, or no scope and line information if |scope_and_line| 156 // is nullptr. The new DebugValue has the same operands as DebugDeclare 157 // but it uses |value_id| for the value. Returns the created DebugValue, 158 // or nullptr if fails to create one. 159 Instruction* AddDebugValueForDecl(Instruction* dbg_decl, uint32_t value_id, 160 Instruction* insert_before, 161 Instruction* scope_and_line); 162 163 // Erases |instr| from data structures of this class. 164 void ClearDebugInfo(Instruction* instr); 165 166 // Return the opcode for the Vulkan DebugOperation inst 167 uint32_t GetVulkanDebugOperation(Instruction* inst); 168 169 // Returns the id of Value operand if |inst| is DebugValue who has Deref 170 // operation and its Value operand is a result id of OpVariable with 171 // Function storage class. Otherwise, returns 0. 172 uint32_t GetVariableIdOfDebugValueUsedForDeclare(Instruction* inst); 173 174 // Converts DebugGlobalVariable |dbg_global_var| to a DebugLocalVariable and 175 // creates a DebugDeclare mapping the new DebugLocalVariable to |local_var|. 176 void ConvertDebugGlobalToLocalVariable(Instruction* dbg_global_var, 177 Instruction* local_var); 178 179 // Returns true if |instr| is a debug declaration instruction. 180 bool IsDebugDeclare(Instruction* instr); 181 182 // Replace all uses of |before| id that is an operand of a DebugScope with 183 // |after| id if those uses (instruction) return true for |predicate|. 184 void ReplaceAllUsesInDebugScopeWithPredicate( 185 uint32_t before, uint32_t after, 186 const std::function<bool(Instruction*)>& predicate); 187 188 // Removes uses of DebugScope |inst| from |scope_id_to_users_| or uses of 189 // DebugInlinedAt |inst| from |inlinedat_id_to_users_|. 190 void ClearDebugScopeAndInlinedAtUses(Instruction* inst); 191 192 private: context()193 IRContext* context() { return context_; } 194 195 // Analyzes DebugInfo instructions in the given |module| and 196 // populates data structures in this class. 197 void AnalyzeDebugInsts(Module& module); 198 199 // Get the DebugInfo ExtInstImport Id, or 0 if no DebugInfo is available. 200 uint32_t GetDbgSetImportId(); 201 202 // Returns the debug instruction whose id is |id|. Returns |nullptr| if one 203 // does not exists. 204 Instruction* GetDbgInst(uint32_t id); 205 206 // Returns a DebugOperation instruction with OpCode Deref. 207 Instruction* GetDebugOperationWithDeref(); 208 209 // Registers the debug instruction |inst| into |id_to_dbg_inst_| using id of 210 // |inst| as a key. 211 void RegisterDbgInst(Instruction* inst); 212 213 // Register the DebugFunction instruction |inst|. The function referenced 214 // in |inst| must not already be registered. 215 void RegisterDbgFunction(Instruction* inst); 216 217 // Register the DebugDeclare or DebugValue with Deref operation 218 // |dbg_declare| into |var_id_to_dbg_decl_| using OpVariable id 219 // |var_id| as a key. 220 void RegisterDbgDeclare(uint32_t var_id, Instruction* dbg_declare); 221 222 // Returns a DebugExpression instruction without Operation operands. 223 Instruction* GetEmptyDebugExpression(); 224 225 // Returns true if a scope |ancestor| is |scope| or an ancestor scope 226 // of |scope|. 227 bool IsAncestorOfScope(uint32_t scope, uint32_t ancestor); 228 229 // Returns true if the declaration of a local variable |dbg_declare| 230 // is visible in the scope of an instruction |instr_scope_id|. 231 bool IsDeclareVisibleToInstr(Instruction* dbg_declare, Instruction* scope); 232 233 // Returns the parent scope of the scope |child_scope|. 234 uint32_t GetParentScope(uint32_t child_scope); 235 236 IRContext* context_; 237 238 // Mapping from ids of DebugInfo extension instructions. 239 // to their Instruction instances. 240 std::unordered_map<uint32_t, Instruction*> id_to_dbg_inst_; 241 242 // Mapping from function's ids to DebugFunction instructions whose 243 // operand is the function. 244 std::unordered_map<uint32_t, Instruction*> fn_id_to_dbg_fn_; 245 246 // Orders Instruction* for use in associative containers (i.e. less than 247 // ordering). Unique Id is used. 248 typedef Instruction* InstPtr; 249 struct InstPtrLess { operatorInstPtrLess250 bool operator()(const InstPtr& lhs, const InstPtr& rhs) const { 251 return lhs->unique_id() < rhs->unique_id(); 252 } 253 }; 254 255 // Mapping from variable or value ids to DebugDeclare or DebugValue 256 // instructions whose operand is the variable or value. 257 std::unordered_map<uint32_t, std::set<InstPtr, InstPtrLess>> 258 var_id_to_dbg_decl_; 259 260 // Mapping from DebugScope ids to users. 261 std::unordered_map<uint32_t, std::unordered_set<Instruction*>> 262 scope_id_to_users_; 263 264 // Mapping from DebugInlinedAt ids to users. 265 std::unordered_map<uint32_t, std::unordered_set<Instruction*>> 266 inlinedat_id_to_users_; 267 268 // DebugOperation whose OpCode is OpenCLDebugInfo100Deref. 269 Instruction* deref_operation_; 270 271 // DebugInfoNone instruction. We need only a single DebugInfoNone. 272 // To reuse the existing one, we keep it using this member variable. 273 Instruction* debug_info_none_inst_; 274 275 // DebugExpression instruction without Operation operands. We need only 276 // a single DebugExpression without Operation operands. To reuse the 277 // existing one, we keep it using this member variable. 278 Instruction* empty_debug_expr_inst_; 279 }; 280 281 } // namespace analysis 282 } // namespace opt 283 } // namespace spvtools 284 285 #endif // SOURCE_OPT_DEBUG_INFO_MANAGER_H_ 286