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