//===- DebugImporter.cpp - LLVM to MLIR Debug conversion ------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "DebugImporter.h" #include "mlir/Dialect/LLVMIR/LLVMAttrs.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/Location.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" using namespace mlir; using namespace mlir::LLVM; using namespace mlir::LLVM::detail; void DebugImporter::translate(llvm::Function *func, LLVMFuncOp funcOp) { if (!func->getSubprogram()) return; // Add a fused location to link the subprogram information. StringAttr name = StringAttr::get(context, func->getSubprogram()->getName()); funcOp->setLoc(FusedLocWith::get( {NameLoc::get(name)}, translate(func->getSubprogram()), context)); } //===----------------------------------------------------------------------===// // Attributes //===----------------------------------------------------------------------===// DIBasicTypeAttr DebugImporter::translateImpl(llvm::DIBasicType *node) { return DIBasicTypeAttr::get(context, node->getTag(), node->getName(), node->getSizeInBits(), node->getEncoding()); } DICompileUnitAttr DebugImporter::translateImpl(llvm::DICompileUnit *node) { std::optional emissionKind = symbolizeDIEmissionKind(node->getEmissionKind()); return DICompileUnitAttr::get(context, node->getSourceLanguage(), translate(node->getFile()), StringAttr::get(context, node->getProducer()), node->isOptimized(), emissionKind.value()); } DICompositeTypeAttr DebugImporter::translateImpl(llvm::DICompositeType *node) { std::optional flags = symbolizeDIFlags(node->getFlags()); SmallVector elements; for (llvm::DINode *element : node->getElements()) { assert(element && "expected a non-null element type"); elements.push_back(translate(element)); } return DICompositeTypeAttr::get( context, node->getTag(), StringAttr::get(context, node->getName()), translate(node->getFile()), node->getLine(), translate(node->getScope()), translate(node->getBaseType()), flags.value_or(DIFlags::Zero), node->getSizeInBits(), node->getAlignInBits(), elements); } DIDerivedTypeAttr DebugImporter::translateImpl(llvm::DIDerivedType *node) { return DIDerivedTypeAttr::get( context, node->getTag(), node->getRawName() ? StringAttr::get(context, node->getName()) : nullptr, translate(node->getBaseType()), node->getSizeInBits(), node->getAlignInBits(), node->getOffsetInBits()); } DIFileAttr DebugImporter::translateImpl(llvm::DIFile *node) { return DIFileAttr::get(context, node->getFilename(), node->getDirectory()); } DILexicalBlockAttr DebugImporter::translateImpl(llvm::DILexicalBlock *node) { return DILexicalBlockAttr::get(context, translate(node->getScope()), translate(node->getFile()), node->getLine(), node->getColumn()); } DILexicalBlockFileAttr DebugImporter::translateImpl(llvm::DILexicalBlockFile *node) { return DILexicalBlockFileAttr::get(context, translate(node->getScope()), translate(node->getFile()), node->getDiscriminator()); } DILocalVariableAttr DebugImporter::translateImpl(llvm::DILocalVariable *node) { return DILocalVariableAttr::get(context, translate(node->getScope()), StringAttr::get(context, node->getName()), translate(node->getFile()), node->getLine(), node->getArg(), node->getAlignInBits(), translate(node->getType())); } DIScopeAttr DebugImporter::translateImpl(llvm::DIScope *node) { return cast(translate(static_cast(node))); } DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) { std::optional subprogramFlags = symbolizeDISubprogramFlags(node->getSubprogram()->getSPFlags()); return DISubprogramAttr::get( context, translate(node->getUnit()), translate(node->getScope()), StringAttr::get(context, node->getName()), node->getRawLinkageName() ? StringAttr::get(context, node->getLinkageName()) : nullptr, translate(node->getFile()), node->getLine(), node->getScopeLine(), subprogramFlags.value(), translate(node->getType())); } DISubrangeAttr DebugImporter::translateImpl(llvm::DISubrange *node) { auto getIntegerAttrOrNull = [&](llvm::DISubrange::BoundType data) { if (auto *constInt = llvm::dyn_cast_or_null(data)) return IntegerAttr::get(IntegerType::get(context, 64), constInt->getSExtValue()); return IntegerAttr(); }; return DISubrangeAttr::get(context, getIntegerAttrOrNull(node->getCount()), getIntegerAttrOrNull(node->getLowerBound()), getIntegerAttrOrNull(node->getUpperBound()), getIntegerAttrOrNull(node->getStride())); } DISubroutineTypeAttr DebugImporter::translateImpl(llvm::DISubroutineType *node) { // Separate the result type since it is null for void functions. DITypeAttr resultType = translate(*node->getTypeArray().begin()); SmallVector argumentTypes; for (llvm::DIType *type : llvm::drop_begin(node->getTypeArray())) { assert(type && "expected a non-null argument type"); argumentTypes.push_back(translate(type)); } return DISubroutineTypeAttr::get(context, node->getCC(), resultType, argumentTypes); } DITypeAttr DebugImporter::translateImpl(llvm::DIType *node) { return cast(translate(static_cast(node))); } DINodeAttr DebugImporter::translate(llvm::DINode *node) { if (!node) return nullptr; // Check for a cached instance. if (DINodeAttr attr = nodeToAttr.lookup(node)) return attr; // Convert the debug metadata if possible. auto translateNode = [this](llvm::DINode *node) -> DINodeAttr { if (auto *casted = dyn_cast(node)) return translateImpl(casted); if (auto *casted = dyn_cast(node)) return translateImpl(casted); if (auto *casted = dyn_cast(node)) return translateImpl(casted); if (auto *casted = dyn_cast(node)) return translateImpl(casted); if (auto *casted = dyn_cast(node)) return translateImpl(casted); if (auto *casted = dyn_cast(node)) return translateImpl(casted); if (auto *casted = dyn_cast(node)) return translateImpl(casted); if (auto *casted = dyn_cast(node)) return translateImpl(casted); if (auto *casted = dyn_cast(node)) return translateImpl(casted); if (auto *casted = dyn_cast(node)) return translateImpl(casted); if (auto *casted = dyn_cast(node)) return translateImpl(casted); return nullptr; }; if (DINodeAttr attr = translateNode(node)) { nodeToAttr.insert({node, attr}); return attr; } return nullptr; } //===----------------------------------------------------------------------===// // Locations //===----------------------------------------------------------------------===// Location DebugImporter::translateLoc(llvm::DILocation *loc) { if (!loc) return UnknownLoc::get(context); // Get the file location of the instruction. Location result = FileLineColLoc::get(context, loc->getFilename(), loc->getLine(), loc->getColumn()); // Add call site information, if available. if (llvm::DILocation *inlinedAt = loc->getInlinedAt()) result = CallSiteLoc::get(result, translateLoc(inlinedAt)); // Add scope information. assert(loc->getScope() && "expected non-null scope"); result = FusedLocWith::get({result}, translate(loc->getScope()), context); return result; }