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