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

source code of mlir/lib/Target/LLVMIR/DebugImporter.cpp