1 | //===- DebugImporter.h - LLVM to MLIR Debug conversion -------*- C++ -*----===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements the translation between LLVMIR debug information and |
10 | // the corresponding MLIR representation. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef MLIR_LIB_TARGET_LLVMIR_DEBUGIMPORTER_H_ |
15 | #define MLIR_LIB_TARGET_LLVMIR_DEBUGIMPORTER_H_ |
16 | |
17 | #include "mlir/Dialect/LLVMIR/LLVMDialect.h" |
18 | #include "mlir/IR/BuiltinOps.h" |
19 | #include "mlir/IR/MLIRContext.h" |
20 | #include "llvm/IR/DebugInfoMetadata.h" |
21 | |
22 | namespace mlir { |
23 | class Operation; |
24 | |
25 | namespace LLVM { |
26 | class LLVMFuncOp; |
27 | |
28 | namespace detail { |
29 | |
30 | class DebugImporter { |
31 | public: |
32 | DebugImporter(ModuleOp mlirModule, bool dropDICompositeTypeElements); |
33 | |
34 | /// Translates the given LLVM debug location to an MLIR location. |
35 | Location translateLoc(llvm::DILocation *loc); |
36 | |
37 | /// Translates the LLVM DWARF expression metadata to MLIR. |
38 | DIExpressionAttr translateExpression(llvm::DIExpression *node); |
39 | |
40 | /// Translates the LLVM DWARF global variable expression metadata to MLIR. |
41 | DIGlobalVariableExpressionAttr |
42 | translateGlobalVariableExpression(llvm::DIGlobalVariableExpression *node); |
43 | |
44 | /// Translates the debug information for the given function into a Location. |
45 | /// Returns UnknownLoc if `func` has no debug information attached to it. |
46 | Location translateFuncLocation(llvm::Function *func); |
47 | |
48 | /// Translates the given LLVM debug metadata to MLIR. |
49 | DINodeAttr translate(llvm::DINode *node); |
50 | |
51 | /// Infers the metadata type and translates it to MLIR. |
52 | template <typename DINodeT> |
53 | auto translate(DINodeT *node) { |
54 | // Infer the MLIR type from the LLVM metadata type. |
55 | using MLIRTypeT = decltype(translateImpl(node)); |
56 | return cast_or_null<MLIRTypeT>( |
57 | translate(node: static_cast<llvm::DINode *>(node))); |
58 | } |
59 | |
60 | private: |
61 | /// Translates the given LLVM debug metadata to the corresponding attribute. |
62 | DIBasicTypeAttr translateImpl(llvm::DIBasicType *node); |
63 | DICompileUnitAttr translateImpl(llvm::DICompileUnit *node); |
64 | DICompositeTypeAttr translateImpl(llvm::DICompositeType *node); |
65 | DIDerivedTypeAttr translateImpl(llvm::DIDerivedType *node); |
66 | DIFileAttr translateImpl(llvm::DIFile *node); |
67 | DILabelAttr translateImpl(llvm::DILabel *node); |
68 | DILexicalBlockAttr translateImpl(llvm::DILexicalBlock *node); |
69 | DILexicalBlockFileAttr translateImpl(llvm::DILexicalBlockFile *node); |
70 | DIGlobalVariableAttr translateImpl(llvm::DIGlobalVariable *node); |
71 | DILocalVariableAttr translateImpl(llvm::DILocalVariable *node); |
72 | DIModuleAttr translateImpl(llvm::DIModule *node); |
73 | DINamespaceAttr translateImpl(llvm::DINamespace *node); |
74 | DIScopeAttr translateImpl(llvm::DIScope *node); |
75 | DISubprogramAttr translateImpl(llvm::DISubprogram *node); |
76 | DISubrangeAttr translateImpl(llvm::DISubrange *node); |
77 | DISubroutineTypeAttr translateImpl(llvm::DISubroutineType *node); |
78 | DITypeAttr translateImpl(llvm::DIType *node); |
79 | |
80 | /// Constructs a StringAttr from the MDString if it is non-null. Returns a |
81 | /// null attribute otherwise. |
82 | StringAttr getStringAttrOrNull(llvm::MDString *stringNode); |
83 | |
84 | /// Get the DistinctAttr used to represent `node` if one was already created |
85 | /// for it, or create a new one if not. |
86 | DistinctAttr getOrCreateDistinctID(llvm::DINode *node); |
87 | |
88 | /// A mapping between LLVM debug metadata and the corresponding attribute. |
89 | DenseMap<llvm::DINode *, DINodeAttr> nodeToAttr; |
90 | /// A mapping between distinct LLVM debug metadata nodes and the corresponding |
91 | /// distinct id attribute. |
92 | DenseMap<llvm::DINode *, DistinctAttr> nodeToDistinctAttr; |
93 | |
94 | /// Translation helper for recursive DINodes. |
95 | /// Works alongside a stack-based DINode translator (the "main translator") |
96 | /// for gracefully handling DINodes that are recursive. |
97 | /// |
98 | /// Usage: |
99 | /// - Before translating a node, call `pruneOrPushTranslationStack` to see if |
100 | /// the pruner can preempt this translation. If this is a node that the |
101 | /// pruner already knows how to handle, it will return the translated |
102 | /// DINodeAttr. |
103 | /// - After a node is successfully translated by the main translator, call |
104 | /// `finalizeTranslation` to save the translated result with the pruner, and |
105 | /// give it a chance to further modify the result. |
106 | /// - Regardless of success or failure by the main translator, always call |
107 | /// `popTranslationStack` at the end of translating a node. This is |
108 | /// necessary to keep the internal book-keeping in sync. |
109 | /// |
110 | /// This helper maintains an internal cache so that no recursive type will |
111 | /// be translated more than once by the main translator. |
112 | /// This internal cache is different from the cache maintained by the main |
113 | /// translator because it may store nodes that are not self-contained (i.e. |
114 | /// contain unbounded recursive self-references). |
115 | class RecursionPruner { |
116 | public: |
117 | RecursionPruner(MLIRContext *context) : context(context) {} |
118 | |
119 | /// If this node is a recursive instance that was previously seen, returns a |
120 | /// self-reference. If this node was previously cached, returns the cached |
121 | /// result. Otherwise, returns null attr, and a translation stack frame is |
122 | /// created for this node. Expects `finalizeTranslation` & |
123 | /// `popTranslationStack` to be called on this node later. |
124 | DINodeAttr pruneOrPushTranslationStack(llvm::DINode *node); |
125 | |
126 | /// Register the translated result of `node`. Returns the finalized result |
127 | /// (with recId if recursive) and whether the result is self-contained |
128 | /// (i.e. contains no unbound self-refs). |
129 | std::pair<DINodeAttr, bool> finalizeTranslation(llvm::DINode *node, |
130 | DINodeAttr result); |
131 | |
132 | /// Pop off a frame from the translation stack after a node is done being |
133 | /// translated. |
134 | void popTranslationStack(llvm::DINode *node); |
135 | |
136 | private: |
137 | /// Returns the cached result (if exists) or null. |
138 | /// The cache entry will be removed if not all of its dependent self-refs |
139 | /// exists. |
140 | DINodeAttr lookup(llvm::DINode *node); |
141 | |
142 | MLIRContext *context; |
143 | |
144 | /// A cached translation that contains the translated attribute as well |
145 | /// as any unbound self-references that it depends on. |
146 | struct DependentTranslation { |
147 | /// The translated attr. May contain unbound self-references for other |
148 | /// recursive attrs. |
149 | DINodeAttr attr; |
150 | /// The set of unbound self-refs that this cached entry refers to. All |
151 | /// these self-refs must exist for the cached entry to be valid. |
152 | DenseSet<DIRecursiveTypeAttrInterface> unboundSelfRefs; |
153 | }; |
154 | /// A mapping between LLVM debug metadata and the corresponding attribute. |
155 | /// Only contains those with unboundSelfRefs. Fully self-contained attrs |
156 | /// will be cached by the outer main translator. |
157 | DenseMap<llvm::DINode *, DependentTranslation> dependentCache; |
158 | |
159 | /// Each potentially recursive node will have a TranslationState pushed onto |
160 | /// the `translationStack` to keep track of whether this node is actually |
161 | /// recursive (i.e. has self-references inside), and other book-keeping. |
162 | struct TranslationState { |
163 | /// The rec-self if this node is indeed a recursive node (i.e. another |
164 | /// instance of itself is seen while translating it). Null if this node |
165 | /// has not been seen again deeper in the translation stack. |
166 | DIRecursiveTypeAttrInterface recSelf; |
167 | /// All the unbound recursive self references in this layer of the |
168 | /// translation stack. |
169 | DenseSet<DIRecursiveTypeAttrInterface> unboundSelfRefs; |
170 | }; |
171 | /// A stack that stores the metadata nodes that are being traversed. The |
172 | /// stack is used to handle cyclic dependencies during metadata translation. |
173 | /// Each node is pushed with an empty TranslationState. If it is ever seen |
174 | /// later when the stack is deeper, the node is recursive, and its |
175 | /// TranslationState is assigned a recSelf. |
176 | llvm::MapVector<llvm::DINode *, TranslationState> translationStack; |
177 | |
178 | /// A mapping between DINodes that are recursive, and their assigned recId. |
179 | /// This is kept so that repeated occurrences of the same node can reuse the |
180 | /// same ID and be deduplicated. |
181 | DenseMap<llvm::DINode *, DistinctAttr> nodeToRecId; |
182 | }; |
183 | RecursionPruner recursionPruner; |
184 | |
185 | MLIRContext *context; |
186 | ModuleOp mlirModule; |
187 | |
188 | /// An option to control if DICompositeTypes should always be imported without |
189 | /// converting their elements. If set, the option avoids the recursive |
190 | /// traversal of composite type debug information, which can be expensive for |
191 | /// adversarial inputs. |
192 | bool dropDICompositeTypeElements; |
193 | }; |
194 | |
195 | } // namespace detail |
196 | } // namespace LLVM |
197 | } // namespace mlir |
198 | |
199 | #endif // MLIR_LIB_TARGET_LLVMIR_DEBUGIMPORTER_H_ |
200 | |