1 | //===- DebugImporter.cpp - LLVM to MLIR Debug conversion ------------------===// |
---|---|
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 | #include "DebugImporter.h" |
10 | #include "mlir/Dialect/LLVMIR/LLVMAttrs.h" |
11 | #include "mlir/IR/Attributes.h" |
12 | #include "mlir/IR/BuiltinAttributes.h" |
13 | #include "mlir/IR/Location.h" |
14 | #include "llvm/ADT/STLExtras.h" |
15 | #include "llvm/ADT/ScopeExit.h" |
16 | #include "llvm/ADT/SetOperations.h" |
17 | #include "llvm/ADT/TypeSwitch.h" |
18 | #include "llvm/BinaryFormat/Dwarf.h" |
19 | #include "llvm/IR/Constants.h" |
20 | #include "llvm/IR/DebugInfoMetadata.h" |
21 | #include "llvm/IR/Metadata.h" |
22 | #include "llvm/Support/Casting.h" |
23 | #include "llvm/Support/ErrorHandling.h" |
24 | |
25 | using namespace mlir; |
26 | using namespace mlir::LLVM; |
27 | using namespace mlir::LLVM::detail; |
28 | |
29 | DebugImporter::DebugImporter(ModuleOp mlirModule, |
30 | bool dropDICompositeTypeElements) |
31 | : cache([&](llvm::DINode *node) { return createRecSelf(node); }), |
32 | context(mlirModule.getContext()), mlirModule(mlirModule), |
33 | dropDICompositeTypeElements(dropDICompositeTypeElements) {} |
34 | |
35 | Location DebugImporter::translateFuncLocation(llvm::Function *func) { |
36 | llvm::DISubprogram *subprogram = func->getSubprogram(); |
37 | if (!subprogram) |
38 | return UnknownLoc::get(context); |
39 | |
40 | // Add a fused location to link the subprogram information. |
41 | StringAttr funcName = StringAttr::get(context, subprogram->getName()); |
42 | StringAttr fileName = StringAttr::get(context, subprogram->getFilename()); |
43 | return FusedLocWith<DISubprogramAttr>::get( |
44 | {NameLoc::get(funcName), |
45 | FileLineColLoc::get(fileName, subprogram->getLine(), /*column=*/0)}, |
46 | translate(subprogram), context); |
47 | } |
48 | |
49 | //===----------------------------------------------------------------------===// |
50 | // Attributes |
51 | //===----------------------------------------------------------------------===// |
52 | |
53 | DIBasicTypeAttr DebugImporter::translateImpl(llvm::DIBasicType *node) { |
54 | return DIBasicTypeAttr::get(context, node->getTag(), node->getName(), |
55 | node->getSizeInBits(), node->getEncoding()); |
56 | } |
57 | |
58 | DICompileUnitAttr DebugImporter::translateImpl(llvm::DICompileUnit *node) { |
59 | std::optional<DIEmissionKind> emissionKind = |
60 | symbolizeDIEmissionKind(node->getEmissionKind()); |
61 | std::optional<DINameTableKind> nameTableKind = symbolizeDINameTableKind( |
62 | static_cast< |
63 | std::underlying_type_t<llvm::DICompileUnit::DebugNameTableKind>>( |
64 | node->getNameTableKind())); |
65 | return DICompileUnitAttr::get( |
66 | context, getOrCreateDistinctID(node), node->getSourceLanguage(), |
67 | translate(node->getFile()), getStringAttrOrNull(node->getRawProducer()), |
68 | node->isOptimized(), emissionKind.value(), nameTableKind.value()); |
69 | } |
70 | |
71 | DICompositeTypeAttr DebugImporter::translateImpl(llvm::DICompositeType *node) { |
72 | std::optional<DIFlags> flags = symbolizeDIFlags(node->getFlags()); |
73 | SmallVector<DINodeAttr> elements; |
74 | |
75 | // A vector always requires an element. |
76 | bool isVectorType = flags && bitEnumContainsAll(*flags, DIFlags::Vector); |
77 | if (isVectorType || !dropDICompositeTypeElements) { |
78 | for (llvm::DINode *element : node->getElements()) { |
79 | assert(element && "expected a non-null element type"); |
80 | elements.push_back(Elt: translate(node: element)); |
81 | } |
82 | } |
83 | // Drop the elements parameter if any of the elements are invalid. |
84 | if (llvm::is_contained(Range&: elements, Element: nullptr)) |
85 | elements.clear(); |
86 | DITypeAttr baseType = translate(node: node->getBaseType()); |
87 | // Arrays require a base type, otherwise the debug metadata is considered to |
88 | // be malformed. |
89 | if (node->getTag() == llvm::dwarf::DW_TAG_array_type && !baseType) |
90 | return nullptr; |
91 | return DICompositeTypeAttr::get( |
92 | context, node->getTag(), getStringAttrOrNull(node->getRawName()), |
93 | translate(node->getFile()), node->getLine(), translate(node->getScope()), |
94 | baseType, flags.value_or(DIFlags::Zero), node->getSizeInBits(), |
95 | node->getAlignInBits(), elements, |
96 | translateExpression(node->getDataLocationExp()), |
97 | translateExpression(node->getRankExp()), |
98 | translateExpression(node->getAllocatedExp()), |
99 | translateExpression(node->getAssociatedExp())); |
100 | } |
101 | |
102 | DIDerivedTypeAttr DebugImporter::translateImpl(llvm::DIDerivedType *node) { |
103 | // Return nullptr if the base type is invalid. |
104 | DITypeAttr baseType = translate(node: node->getBaseType()); |
105 | if (node->getBaseType() && !baseType) |
106 | return nullptr; |
107 | DINodeAttr extraData = |
108 | translate(node: dyn_cast_or_null<llvm::DINode>(Val: node->getExtraData())); |
109 | return DIDerivedTypeAttr::get( |
110 | context, node->getTag(), getStringAttrOrNull(node->getRawName()), |
111 | baseType, node->getSizeInBits(), node->getAlignInBits(), |
112 | node->getOffsetInBits(), node->getDWARFAddressSpace(), extraData); |
113 | } |
114 | |
115 | DIStringTypeAttr DebugImporter::translateImpl(llvm::DIStringType *node) { |
116 | return DIStringTypeAttr::get( |
117 | context, node->getTag(), getStringAttrOrNull(node->getRawName()), |
118 | node->getSizeInBits(), node->getAlignInBits(), |
119 | translate(node->getStringLength()), |
120 | translateExpression(node->getStringLengthExp()), |
121 | translateExpression(node->getStringLocationExp()), node->getEncoding()); |
122 | } |
123 | |
124 | DIFileAttr DebugImporter::translateImpl(llvm::DIFile *node) { |
125 | return DIFileAttr::get(context, node->getFilename(), node->getDirectory()); |
126 | } |
127 | |
128 | DILabelAttr DebugImporter::translateImpl(llvm::DILabel *node) { |
129 | // Return nullptr if the scope or type is a cyclic dependency. |
130 | DIScopeAttr scope = translate(node: node->getScope()); |
131 | if (node->getScope() && !scope) |
132 | return nullptr; |
133 | return DILabelAttr::get(context, scope, |
134 | getStringAttrOrNull(node->getRawName()), |
135 | translate(node->getFile()), node->getLine()); |
136 | } |
137 | |
138 | DILexicalBlockAttr DebugImporter::translateImpl(llvm::DILexicalBlock *node) { |
139 | // Return nullptr if the scope or type is a cyclic dependency. |
140 | DIScopeAttr scope = translate(node: node->getScope()); |
141 | if (node->getScope() && !scope) |
142 | return nullptr; |
143 | return DILexicalBlockAttr::get(context, scope, translate(node->getFile()), |
144 | node->getLine(), node->getColumn()); |
145 | } |
146 | |
147 | DILexicalBlockFileAttr |
148 | DebugImporter::translateImpl(llvm::DILexicalBlockFile *node) { |
149 | // Return nullptr if the scope or type is a cyclic dependency. |
150 | DIScopeAttr scope = translate(node: node->getScope()); |
151 | if (node->getScope() && !scope) |
152 | return nullptr; |
153 | return DILexicalBlockFileAttr::get(context, scope, translate(node->getFile()), |
154 | node->getDiscriminator()); |
155 | } |
156 | |
157 | DIGlobalVariableAttr |
158 | DebugImporter::translateImpl(llvm::DIGlobalVariable *node) { |
159 | // Names of DIGlobalVariables can be empty. MLIR models them as null, instead |
160 | // of empty strings, so this special handling is necessary. |
161 | auto convertToStringAttr = [&](StringRef name) -> StringAttr { |
162 | if (name.empty()) |
163 | return {}; |
164 | return StringAttr::get(context, node->getName()); |
165 | }; |
166 | return DIGlobalVariableAttr::get( |
167 | context, translate(node->getScope()), |
168 | convertToStringAttr(node->getName()), |
169 | convertToStringAttr(node->getLinkageName()), translate(node->getFile()), |
170 | node->getLine(), translate(node->getType()), node->isLocalToUnit(), |
171 | node->isDefinition(), node->getAlignInBits()); |
172 | } |
173 | |
174 | DILocalVariableAttr DebugImporter::translateImpl(llvm::DILocalVariable *node) { |
175 | // Return nullptr if the scope or type is a cyclic dependency. |
176 | DIScopeAttr scope = translate(node: node->getScope()); |
177 | if (node->getScope() && !scope) |
178 | return nullptr; |
179 | return DILocalVariableAttr::get( |
180 | context, scope, getStringAttrOrNull(node->getRawName()), |
181 | translate(node->getFile()), node->getLine(), node->getArg(), |
182 | node->getAlignInBits(), translate(node->getType()), |
183 | symbolizeDIFlags(node->getFlags()).value_or(DIFlags::Zero)); |
184 | } |
185 | |
186 | DIVariableAttr DebugImporter::translateImpl(llvm::DIVariable *node) { |
187 | return cast<DIVariableAttr>(Val: translate(node: static_cast<llvm::DINode *>(node))); |
188 | } |
189 | |
190 | DIScopeAttr DebugImporter::translateImpl(llvm::DIScope *node) { |
191 | return cast<DIScopeAttr>(Val: translate(node: static_cast<llvm::DINode *>(node))); |
192 | } |
193 | |
194 | DIModuleAttr DebugImporter::translateImpl(llvm::DIModule *node) { |
195 | return DIModuleAttr::get( |
196 | context, translate(node->getFile()), translate(node->getScope()), |
197 | getStringAttrOrNull(node->getRawName()), |
198 | getStringAttrOrNull(node->getRawConfigurationMacros()), |
199 | getStringAttrOrNull(node->getRawIncludePath()), |
200 | getStringAttrOrNull(node->getRawAPINotesFile()), node->getLineNo(), |
201 | node->getIsDecl()); |
202 | } |
203 | |
204 | DINamespaceAttr DebugImporter::translateImpl(llvm::DINamespace *node) { |
205 | return DINamespaceAttr::get(context, getStringAttrOrNull(node->getRawName()), |
206 | translate(node->getScope()), |
207 | node->getExportSymbols()); |
208 | } |
209 | |
210 | DIImportedEntityAttr |
211 | DebugImporter::translateImpl(llvm::DIImportedEntity *node) { |
212 | SmallVector<DINodeAttr> elements; |
213 | for (llvm::DINode *element : node->getElements()) { |
214 | assert(element && "expected a non-null element type"); |
215 | elements.push_back(Elt: translate(node: element)); |
216 | } |
217 | |
218 | return DIImportedEntityAttr::get( |
219 | context, node->getTag(), translate(node->getScope()), |
220 | translate(node->getEntity()), translate(node->getFile()), node->getLine(), |
221 | getStringAttrOrNull(node->getRawName()), elements); |
222 | } |
223 | |
224 | DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) { |
225 | // Only definitions require a distinct identifier. |
226 | mlir::DistinctAttr id; |
227 | if (node->isDistinct()) |
228 | id = getOrCreateDistinctID(node); |
229 | |
230 | // Return nullptr if the scope or type is invalid. |
231 | DIScopeAttr scope = translate(node: node->getScope()); |
232 | if (node->getScope() && !scope) |
233 | return nullptr; |
234 | std::optional<DISubprogramFlags> subprogramFlags = |
235 | symbolizeDISubprogramFlags(node->getSubprogram()->getSPFlags()); |
236 | assert(subprogramFlags && "expected valid subprogram flags"); |
237 | DISubroutineTypeAttr type = translate(node->getType()); |
238 | if (node->getType() && !type) |
239 | return nullptr; |
240 | |
241 | // Convert the retained nodes but drop all of them if one of them is invalid. |
242 | SmallVector<DINodeAttr> retainedNodes; |
243 | for (llvm::DINode *retainedNode : node->getRetainedNodes()) |
244 | retainedNodes.push_back(Elt: translate(node: retainedNode)); |
245 | if (llvm::is_contained(Range&: retainedNodes, Element: nullptr)) |
246 | retainedNodes.clear(); |
247 | |
248 | SmallVector<DINodeAttr> annotations; |
249 | // We currently only support `string` values for annotations on the MLIR side. |
250 | // Theoretically we could support other primitives, but LLVM is not using |
251 | // other types in practice. |
252 | if (llvm::DINodeArray rawAnns = node->getAnnotations(); rawAnns) { |
253 | for (size_t i = 0, e = rawAnns->getNumOperands(); i < e; ++i) { |
254 | const llvm::MDTuple *tuple = cast<llvm::MDTuple>(Val: rawAnns->getOperand(I: i)); |
255 | if (tuple->getNumOperands() != 2) |
256 | continue; |
257 | const llvm::MDString *name = cast<llvm::MDString>(Val: tuple->getOperand(I: 0)); |
258 | const llvm::MDString *value = |
259 | dyn_cast<llvm::MDString>(Val: tuple->getOperand(I: 1)); |
260 | if (name && value) { |
261 | annotations.push_back(DIAnnotationAttr::get( |
262 | context, StringAttr::get(context, name->getString()), |
263 | StringAttr::get(context, value->getString()))); |
264 | } |
265 | } |
266 | } |
267 | |
268 | return DISubprogramAttr::get(context, id, translate(node->getUnit()), scope, |
269 | getStringAttrOrNull(node->getRawName()), |
270 | getStringAttrOrNull(node->getRawLinkageName()), |
271 | translate(node->getFile()), node->getLine(), |
272 | node->getScopeLine(), *subprogramFlags, type, |
273 | retainedNodes, annotations); |
274 | } |
275 | |
276 | DISubrangeAttr DebugImporter::translateImpl(llvm::DISubrange *node) { |
277 | auto getAttrOrNull = [&](llvm::DISubrange::BoundType data) -> Attribute { |
278 | if (data.isNull()) |
279 | return nullptr; |
280 | if (auto *constInt = dyn_cast<llvm::ConstantInt *>(data)) |
281 | return IntegerAttr::get(IntegerType::get(context, 64), |
282 | constInt->getSExtValue()); |
283 | if (auto *expr = dyn_cast<llvm::DIExpression *>(data)) |
284 | return translateExpression(expr); |
285 | if (auto *var = dyn_cast<llvm::DIVariable *>(Val&: data)) { |
286 | if (auto *local = dyn_cast<llvm::DILocalVariable>(Val: var)) |
287 | return translate(node: local); |
288 | if (auto *global = dyn_cast<llvm::DIGlobalVariable>(Val: var)) |
289 | return translate(node: global); |
290 | return nullptr; |
291 | } |
292 | return nullptr; |
293 | }; |
294 | Attribute count = getAttrOrNull(node->getCount()); |
295 | Attribute upperBound = getAttrOrNull(node->getUpperBound()); |
296 | // Either count or the upper bound needs to be present. Otherwise, the |
297 | // metadata is invalid. The conversion might fail due to unsupported DI nodes. |
298 | if (!count && !upperBound) |
299 | return {}; |
300 | return DISubrangeAttr::get(context, count, |
301 | getAttrOrNull(node->getLowerBound()), upperBound, |
302 | getAttrOrNull(node->getStride())); |
303 | } |
304 | |
305 | DICommonBlockAttr DebugImporter::translateImpl(llvm::DICommonBlock *node) { |
306 | return DICommonBlockAttr::get(context, translate(node->getScope()), |
307 | translate(node->getDecl()), |
308 | getStringAttrOrNull(node->getRawName()), |
309 | translate(node->getFile()), node->getLineNo()); |
310 | } |
311 | |
312 | DIGenericSubrangeAttr |
313 | DebugImporter::translateImpl(llvm::DIGenericSubrange *node) { |
314 | auto getAttrOrNull = |
315 | [&](llvm::DIGenericSubrange::BoundType data) -> Attribute { |
316 | if (data.isNull()) |
317 | return nullptr; |
318 | if (auto *expr = dyn_cast<llvm::DIExpression *>(data)) |
319 | return translateExpression(expr); |
320 | if (auto *var = dyn_cast<llvm::DIVariable *>(Val&: data)) { |
321 | if (auto *local = dyn_cast<llvm::DILocalVariable>(Val: var)) |
322 | return translate(node: local); |
323 | if (auto *global = dyn_cast<llvm::DIGlobalVariable>(Val: var)) |
324 | return translate(node: global); |
325 | return nullptr; |
326 | } |
327 | return nullptr; |
328 | }; |
329 | Attribute count = getAttrOrNull(node->getCount()); |
330 | Attribute upperBound = getAttrOrNull(node->getUpperBound()); |
331 | Attribute lowerBound = getAttrOrNull(node->getLowerBound()); |
332 | Attribute stride = getAttrOrNull(node->getStride()); |
333 | // Either count or the upper bound needs to be present. Otherwise, the |
334 | // metadata is invalid. |
335 | if (!count && !upperBound) |
336 | return {}; |
337 | return DIGenericSubrangeAttr::get(context, count, lowerBound, upperBound, |
338 | stride); |
339 | } |
340 | |
341 | DISubroutineTypeAttr |
342 | DebugImporter::translateImpl(llvm::DISubroutineType *node) { |
343 | SmallVector<DITypeAttr> types; |
344 | for (llvm::DIType *type : node->getTypeArray()) { |
345 | if (!type) { |
346 | // A nullptr entry may appear at the beginning or the end of the |
347 | // subroutine types list modeling either a void result type or the type of |
348 | // a variadic argument. Translate the nullptr to an explicit |
349 | // DINullTypeAttr since the attribute list cannot contain a nullptr entry. |
350 | types.push_back(DINullTypeAttr::get(context)); |
351 | continue; |
352 | } |
353 | types.push_back(Elt: translate(node: type)); |
354 | } |
355 | // Return nullptr if any of the types is invalid. |
356 | if (llvm::is_contained(Range&: types, Element: nullptr)) |
357 | return nullptr; |
358 | return DISubroutineTypeAttr::get(context, node->getCC(), types); |
359 | } |
360 | |
361 | DITypeAttr DebugImporter::translateImpl(llvm::DIType *node) { |
362 | return cast<DITypeAttr>(Val: translate(node: static_cast<llvm::DINode *>(node))); |
363 | } |
364 | |
365 | DINodeAttr DebugImporter::translate(llvm::DINode *node) { |
366 | if (!node) |
367 | return nullptr; |
368 | |
369 | // Check for a cached instance. |
370 | auto cacheEntry = cache.lookupOrInit(element: node); |
371 | if (std::optional<DINodeAttr> result = cacheEntry.get()) |
372 | return *result; |
373 | |
374 | // Convert the debug metadata if possible. |
375 | auto translateNode = [this](llvm::DINode *node) -> DINodeAttr { |
376 | if (auto *casted = dyn_cast<llvm::DIBasicType>(Val: node)) |
377 | return translateImpl(node: casted); |
378 | if (auto *casted = dyn_cast<llvm::DICommonBlock>(Val: node)) |
379 | return translateImpl(node: casted); |
380 | if (auto *casted = dyn_cast<llvm::DICompileUnit>(Val: node)) |
381 | return translateImpl(node: casted); |
382 | if (auto *casted = dyn_cast<llvm::DICompositeType>(Val: node)) |
383 | return translateImpl(node: casted); |
384 | if (auto *casted = dyn_cast<llvm::DIDerivedType>(Val: node)) |
385 | return translateImpl(node: casted); |
386 | if (auto *casted = dyn_cast<llvm::DIStringType>(Val: node)) |
387 | return translateImpl(node: casted); |
388 | if (auto *casted = dyn_cast<llvm::DIFile>(Val: node)) |
389 | return translateImpl(node: casted); |
390 | if (auto *casted = dyn_cast<llvm::DIGlobalVariable>(Val: node)) |
391 | return translateImpl(node: casted); |
392 | if (auto *casted = dyn_cast<llvm::DIImportedEntity>(Val: node)) |
393 | return translateImpl(casted); |
394 | if (auto *casted = dyn_cast<llvm::DILabel>(Val: node)) |
395 | return translateImpl(casted); |
396 | if (auto *casted = dyn_cast<llvm::DILexicalBlock>(Val: node)) |
397 | return translateImpl(node: casted); |
398 | if (auto *casted = dyn_cast<llvm::DILexicalBlockFile>(Val: node)) |
399 | return translateImpl(node: casted); |
400 | if (auto *casted = dyn_cast<llvm::DILocalVariable>(Val: node)) |
401 | return translateImpl(node: casted); |
402 | if (auto *casted = dyn_cast<llvm::DIModule>(Val: node)) |
403 | return translateImpl(node: casted); |
404 | if (auto *casted = dyn_cast<llvm::DINamespace>(Val: node)) |
405 | return translateImpl(node: casted); |
406 | if (auto *casted = dyn_cast<llvm::DISubprogram>(Val: node)) |
407 | return translateImpl(node: casted); |
408 | if (auto *casted = dyn_cast<llvm::DISubrange>(Val: node)) |
409 | return translateImpl(casted); |
410 | if (auto *casted = dyn_cast<llvm::DIGenericSubrange>(Val: node)) |
411 | return translateImpl(casted); |
412 | if (auto *casted = dyn_cast<llvm::DISubroutineType>(Val: node)) |
413 | return translateImpl(node: casted); |
414 | return nullptr; |
415 | }; |
416 | if (DINodeAttr attr = translateNode(node)) { |
417 | // If this node was repeated, lookup its recursive ID and assign it to the |
418 | // base result. |
419 | if (cacheEntry.wasRepeated()) { |
420 | DistinctAttr recId = nodeToRecId.lookup(Val: node); |
421 | auto recType = cast<DIRecursiveTypeAttrInterface>(attr); |
422 | attr = cast<DINodeAttr>(recType.withRecId(recId)); |
423 | } |
424 | cacheEntry.resolve(result: attr); |
425 | return attr; |
426 | } |
427 | cacheEntry.resolve(result: nullptr); |
428 | return nullptr; |
429 | } |
430 | |
431 | /// Get the `getRecSelf` constructor for the translated type of `node` if its |
432 | /// translated DITypeAttr supports recursion. Otherwise, returns nullptr. |
433 | static function_ref<DIRecursiveTypeAttrInterface(DistinctAttr)> |
434 | getRecSelfConstructor(llvm::DINode *node) { |
435 | using CtorType = function_ref<DIRecursiveTypeAttrInterface(DistinctAttr)>; |
436 | return TypeSwitch<llvm::DINode *, CtorType>(node) |
437 | .Case([&](llvm::DICompositeType *) { |
438 | return CtorType(DICompositeTypeAttr::getRecSelf); |
439 | }) |
440 | .Case([&](llvm::DISubprogram *) { |
441 | return CtorType(DISubprogramAttr::getRecSelf); |
442 | }) |
443 | .Default(CtorType()); |
444 | } |
445 | |
446 | std::optional<DINodeAttr> DebugImporter::createRecSelf(llvm::DINode *node) { |
447 | auto recSelfCtor = getRecSelfConstructor(node); |
448 | if (!recSelfCtor) |
449 | return std::nullopt; |
450 | |
451 | // The original node may have already been assigned a recursive ID from |
452 | // a different self-reference. Use that if possible. |
453 | DistinctAttr recId = nodeToRecId.lookup(Val: node); |
454 | if (!recId) { |
455 | recId = DistinctAttr::create(UnitAttr::get(context)); |
456 | nodeToRecId[node] = recId; |
457 | } |
458 | DIRecursiveTypeAttrInterface recSelf = recSelfCtor(recId); |
459 | return cast<DINodeAttr>(recSelf); |
460 | } |
461 | |
462 | //===----------------------------------------------------------------------===// |
463 | // Locations |
464 | //===----------------------------------------------------------------------===// |
465 | |
466 | Location DebugImporter::translateLoc(llvm::DILocation *loc) { |
467 | if (!loc) |
468 | return UnknownLoc::get(context); |
469 | |
470 | // Get the file location of the instruction. |
471 | Location result = FileLineColLoc::get(context, fileName: loc->getFilename(), |
472 | line: loc->getLine(), column: loc->getColumn()); |
473 | |
474 | // Add scope information. |
475 | assert(loc->getScope() && "expected non-null scope"); |
476 | result = FusedLocWith<DIScopeAttr>::get({result}, translate(loc->getScope()), |
477 | context); |
478 | |
479 | // Add call site information, if available. |
480 | if (llvm::DILocation *inlinedAt = loc->getInlinedAt()) |
481 | result = CallSiteLoc::get(result, translateLoc(inlinedAt)); |
482 | |
483 | return result; |
484 | } |
485 | |
486 | DIExpressionAttr DebugImporter::translateExpression(llvm::DIExpression *node) { |
487 | if (!node) |
488 | return nullptr; |
489 | |
490 | SmallVector<DIExpressionElemAttr> ops; |
491 | |
492 | // Begin processing the operations. |
493 | for (const llvm::DIExpression::ExprOperand &op : node->expr_ops()) { |
494 | SmallVector<uint64_t> operands; |
495 | operands.reserve(N: op.getNumArgs()); |
496 | for (const auto &i : llvm::seq(Size: op.getNumArgs())) |
497 | operands.push_back(Elt: op.getArg(I: i)); |
498 | const auto attr = DIExpressionElemAttr::get(context, op.getOp(), operands); |
499 | ops.push_back(attr); |
500 | } |
501 | return DIExpressionAttr::get(context, ops); |
502 | } |
503 | |
504 | DIGlobalVariableExpressionAttr DebugImporter::translateGlobalVariableExpression( |
505 | llvm::DIGlobalVariableExpression *node) { |
506 | return DIGlobalVariableExpressionAttr::get( |
507 | context, translate(node->getVariable()), |
508 | translateExpression(node->getExpression())); |
509 | } |
510 | |
511 | StringAttr DebugImporter::getStringAttrOrNull(llvm::MDString *stringNode) { |
512 | if (!stringNode) |
513 | return StringAttr(); |
514 | return StringAttr::get(context, stringNode->getString()); |
515 | } |
516 | |
517 | DistinctAttr DebugImporter::getOrCreateDistinctID(llvm::DINode *node) { |
518 | DistinctAttr &id = nodeToDistinctAttr[node]; |
519 | if (!id) |
520 | id = DistinctAttr::create(UnitAttr::get(context)); |
521 | return id; |
522 | } |
523 |
Definitions
- DebugImporter
- translateFuncLocation
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translateImpl
- translate
- getRecSelfConstructor
- createRecSelf
- translateLoc
- translateExpression
- translateGlobalVariableExpression
- getStringAttrOrNull
Improve your Profiling and Debugging skills
Find out more