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(translate(element)); 81 } 82 } 83 // Drop the elements parameter if any of the elements are invalid. 84 if (llvm::is_contained(elements, nullptr)) 85 elements.clear(); 86 DITypeAttr baseType = translate(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->getBaseType()); 105 if (node->getBaseType() && !baseType) 106 return nullptr; 107 DINodeAttr extraData = 108 translate(dyn_cast_or_null<llvm::DINode>(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->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->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->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->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>(translate(static_cast<llvm::DINode *>(node))); 188 } 189 190 DIScopeAttr DebugImporter::translateImpl(llvm::DIScope *node) { 191 return cast<DIScopeAttr>(translate(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(translate(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->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(translate(retainedNode)); 245 if (llvm::is_contained(retainedNodes, 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>(rawAnns->getOperand(i)); 255 if (tuple->getNumOperands() != 2) 256 continue; 257 const llvm::MDString *name = cast<llvm::MDString>(tuple->getOperand(0)); 258 const llvm::MDString *value = 259 dyn_cast<llvm::MDString>(tuple->getOperand(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 *>(data)) { 286 if (auto *local = dyn_cast<llvm::DILocalVariable>(var)) 287 return translate(local); 288 if (auto *global = dyn_cast<llvm::DIGlobalVariable>(var)) 289 return translate(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 *>(data)) { 321 if (auto *local = dyn_cast<llvm::DILocalVariable>(var)) 322 return translate(local); 323 if (auto *global = dyn_cast<llvm::DIGlobalVariable>(var)) 324 return translate(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(translate(type)); 354 } 355 // Return nullptr if any of the types is invalid. 356 if (llvm::is_contained(types, 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>(translate(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(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>(node)) 377 return translateImpl(casted); 378 if (auto *casted = dyn_cast<llvm::DICommonBlock>(node)) 379 return translateImpl(casted); 380 if (auto *casted = dyn_cast<llvm::DICompileUnit>(node)) 381 return translateImpl(casted); 382 if (auto *casted = dyn_cast<llvm::DICompositeType>(node)) 383 return translateImpl(casted); 384 if (auto *casted = dyn_cast<llvm::DIDerivedType>(node)) 385 return translateImpl(casted); 386 if (auto *casted = dyn_cast<llvm::DIStringType>(node)) 387 return translateImpl(casted); 388 if (auto *casted = dyn_cast<llvm::DIFile>(node)) 389 return translateImpl(casted); 390 if (auto *casted = dyn_cast<llvm::DIGlobalVariable>(node)) 391 return translateImpl(casted); 392 if (auto *casted = dyn_cast<llvm::DIImportedEntity>(node)) 393 return translateImpl(casted); 394 if (auto *casted = dyn_cast<llvm::DILabel>(node)) 395 return translateImpl(casted); 396 if (auto *casted = dyn_cast<llvm::DILexicalBlock>(node)) 397 return translateImpl(casted); 398 if (auto *casted = dyn_cast<llvm::DILexicalBlockFile>(node)) 399 return translateImpl(casted); 400 if (auto *casted = dyn_cast<llvm::DILocalVariable>(node)) 401 return translateImpl(casted); 402 if (auto *casted = dyn_cast<llvm::DIModule>(node)) 403 return translateImpl(casted); 404 if (auto *casted = dyn_cast<llvm::DINamespace>(node)) 405 return translateImpl(casted); 406 if (auto *casted = dyn_cast<llvm::DISubprogram>(node)) 407 return translateImpl(casted); 408 if (auto *casted = dyn_cast<llvm::DISubrange>(node)) 409 return translateImpl(casted); 410 if (auto *casted = dyn_cast<llvm::DIGenericSubrange>(node)) 411 return translateImpl(casted); 412 if (auto *casted = dyn_cast<llvm::DISubroutineType>(node)) 413 return translateImpl(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(node); 421 auto recType = cast<DIRecursiveTypeAttrInterface>(attr); 422 attr = cast<DINodeAttr>(recType.withRecId(recId)); 423 } 424 cacheEntry.resolve(attr); 425 return attr; 426 } 427 cacheEntry.resolve(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(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, loc->getFilename(), 472 loc->getLine(), 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(op.getNumArgs()); 496 for (const auto &i : llvm::seq(op.getNumArgs())) 497 operands.push_back(op.getArg(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