diff --git a/mlir/lib/Target/LLVMIR/CMakeLists.txt b/mlir/lib/Target/LLVMIR/CMakeLists.txt --- a/mlir/lib/Target/LLVMIR/CMakeLists.txt +++ b/mlir/lib/Target/LLVMIR/CMakeLists.txt @@ -4,6 +4,7 @@ ConvertFromLLVMIR.cpp ConvertToLLVMIR.cpp DebugTranslation.cpp + DebugImporter.cpp ModuleTranslation.cpp TypeToLLVM.cpp TypeFromLLVM.cpp @@ -50,6 +51,7 @@ add_mlir_translation_library(MLIRTargetLLVMIRImport ConvertFromLLVMIR.cpp + DebugImporter.cpp TypeFromLLVM.cpp ADDITIONAL_HEADER_DIRS diff --git a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp --- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp +++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "DebugImporter.h" #include "mlir/Target/LLVMIR/Import.h" #include "mlir/Dialect/DLTI/DLTI.h" @@ -42,6 +43,7 @@ using namespace mlir; using namespace mlir::LLVM; +using mlir::LLVM::detail::DebugImporter; #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsFromLLVM.inc" @@ -329,7 +331,7 @@ public: Importer(MLIRContext *context, ModuleOp module) : builder(context), context(context), module(module), - typeTranslator(*context) { + typeTranslator(*context), debugImporter(context) { builder.setInsertionPointToStart(module.getBody()); } @@ -369,12 +371,15 @@ /// Converts `value` to an integer attribute. Asserts if the conversion fails. IntegerAttr matchIntegerAttr(Value value); - /// Translate the debug location to a FileLineColLoc, if `loc` is non-null. - /// Otherwise, return UnknownLoc. - Location translateLoc(llvm::DILocation *loc); + /// Translates the debug location. + Location translateLoc(llvm::DILocation *loc) { + return debugImporter.translateLoc(loc); + } /// Converts the type from LLVM to MLIR LLVM dialect. - Type convertType(llvm::Type *type); + Type convertType(llvm::Type *type) { + return typeTranslator.translateType(type); + } /// Converts an LLVM intrinsic to an MLIR LLVM dialect operation if an MLIR /// counterpart exists. Otherwise, returns failure. @@ -450,21 +455,11 @@ DenseMap globals; /// The stateful type translator (contains named structs). LLVM::TypeFromLLVMIRTranslator typeTranslator; + /// Stateful debug information importer. + DebugImporter debugImporter; }; } // namespace -Location Importer::translateLoc(llvm::DILocation *loc) { - if (!loc) - return UnknownLoc::get(context); - - return FileLineColLoc::get(context, loc->getFilename(), loc->getLine(), - loc->getColumn()); -} - -Type Importer::convertType(llvm::Type *type) { - return typeTranslator.translateType(type); -} - LogicalResult Importer::convertIntrinsic(OpBuilder &odsBuilder, llvm::CallInst *inst) { // Check if the callee is an intrinsic. @@ -1064,6 +1059,9 @@ UnknownLoc::get(context), func->getName(), functionType, convertLinkageFromLLVM(func->getLinkage()), dsoLocal, cconv); + // Set the function debug information if available. + debugImporter.translate(func, funcOp); + for (const auto &it : llvm::enumerate(functionType.getParams())) { llvm::SmallVector argAttrs; if (auto *type = func->getParamByValType(it.index())) { @@ -1150,8 +1148,9 @@ MLIRContext *context) { context->loadDialect(); context->loadDialect(); - OwningOpRef module(ModuleOp::create( - FileLineColLoc::get(context, "", /*line=*/0, /*column=*/0))); + OwningOpRef module(ModuleOp::create(FileLineColLoc::get( + StringAttr::get(context, llvmModule->getSourceFileName()), /*line=*/0, + /*column=*/0))); DataLayoutSpecInterface dlSpec = translateDataLayout(llvmModule->getDataLayout(), context); diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.h b/mlir/lib/Target/LLVMIR/DebugImporter.h new file mode 100644 --- /dev/null +++ b/mlir/lib/Target/LLVMIR/DebugImporter.h @@ -0,0 +1,78 @@ +//===- DebugImporter.h - LLVM to MLIR Debug conversion -------*- C++ -*----===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements the translation between LLVMIR debug information and +// the corresponding MLIR representation. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_LIB_TARGET_LLVMIR_DEBUGIMPORT_H_ +#define MLIR_LIB_TARGET_LLVMIR_DEBUGIMPORT_H_ + +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/IR/BuiltinOps.h" +#include "mlir/IR/MLIRContext.h" +#include "llvm/IR/DebugInfoMetadata.h" + +namespace mlir { +class Operation; + +namespace LLVM { +class LLVMFuncOp; + +namespace detail { + +class DebugImporter { +public: + DebugImporter(MLIRContext *context) : context(context) {} + + /// Translates the given LLVM debug location to an MLIR location. + Location translateLoc(llvm::DILocation *loc); + + /// Translates the debug information for the given function. + void translate(llvm::Function *func, LLVMFuncOp funcOp); + + /// Translates the given LLVM debug metadata to MLIR. + DINodeAttr translate(llvm::DINode *node); + + /// Infers the metadata type and translates it to MLIR. + template + auto translate(DINodeT *node) { + // Infer the MLIR type from the LLVM metadata type. + using MLIRTypeT = decltype(translateImpl(node)); + return cast_or_null( + translate(static_cast(node))); + } + +private: + /// Translates the given LLVM debug metadata to the corresponding attribute. + DIBasicTypeAttr translateImpl(llvm::DIBasicType *node); + DICompileUnitAttr translateImpl(llvm::DICompileUnit *node); + DICompositeTypeAttr translateImpl(llvm::DICompositeType *node); + DIDerivedTypeAttr translateImpl(llvm::DIDerivedType *node); + DIFileAttr translateImpl(llvm::DIFile *node); + DILexicalBlockAttr translateImpl(llvm::DILexicalBlock *node); + DILexicalBlockFileAttr translateImpl(llvm::DILexicalBlockFile *node); + DILocalVariableAttr translateImpl(llvm::DILocalVariable *node); + DIScopeAttr translateImpl(llvm::DIScope *node); + DISubprogramAttr translateImpl(llvm::DISubprogram *node); + DISubrangeAttr translateImpl(llvm::DISubrange *node); + DISubroutineTypeAttr translateImpl(llvm::DISubroutineType *node); + DITypeAttr translateImpl(llvm::DIType *node); + + /// A mapping between LLVM debug metadata and the corresponding attribute. + DenseMap nodeToAttr; + + MLIRContext *context; +}; + +} // namespace detail +} // namespace LLVM +} // namespace mlir + +#endif // MLIR_LIB_TARGET_LLVMIR_DEBUIMPORTN_H_ diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.cpp b/mlir/lib/Target/LLVMIR/DebugImporter.cpp new file mode 100644 --- /dev/null +++ b/mlir/lib/Target/LLVMIR/DebugImporter.cpp @@ -0,0 +1,209 @@ +//===- 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) { + 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) { + 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) { + 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; +} diff --git a/mlir/test/Target/LLVMIR/Import/debug-info.ll b/mlir/test/Target/LLVMIR/Import/debug-info.ll --- a/mlir/test/Target/LLVMIR/Import/debug-info.ll +++ b/mlir/test/Target/LLVMIR/Import/debug-info.ll @@ -17,26 +17,212 @@ ; // ----- -; CHECK-LABEL: @known_loc( -define i32 @known_loc(i32 %0) { -entry: - br label %next -end: - ; CHECK: ^{{.*}}(%{{.+}}: i32 loc("known_loc.cpp":5:2)): - %1 = phi i32 [ %2, %next ], !dbg !4 - ret i32 %1 -next: - ; CHECK: = llvm.mul %{{.+}}, %{{.+}} : i32 loc(#[[LOC:.+]]) - %2 = mul i32 %0, %0, !dbg !5 - br label %end +; CHECK: #[[$SP:.+]] = #llvm.di_subprogram["debug-info.ll":1:2]) +; CHECK #[[CALLSITE_LOC]] = loc(fused<#[[$CALLEE]]>[callsite("debug-info.ll":7:4 at fused<#[[$SP]]>["debug-info.ll":2:2])]) + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!0} +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = distinct !DICompileUnit(language: DW_LANG_C, file: !2) +!2 = !DIFile(filename: "debug-info.ll", directory: "/") +!3 = distinct !DISubprogram(name: "instruction_loc", scope: !2, file: !2, line: 42, scopeLine: 42, spFlags: DISPFlagDefinition, unit: !1) +!4 = distinct !DISubprogram(name: "callee", scope: !2, file: !2, line: 43, scopeLine: 42, spFlags: DISPFlagDefinition, unit: !1) +!5 = !DILocation(line: 1, column: 2, scope: !3) +!6 = !DILocation(line: 2, column: 2, scope: !3) +!7 = !DILocation(line: 7, column: 4, scope: !4, inlinedAt: !6) + +; // ----- + +; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/"> +; CHECK: #[[SP:.+]] = #llvm.di_subprogram +; CHECK: #[[$LB1:.+]] = #llvm.di_lexical_block + +; CHECK-LABEL: @lexical_block +define i32 @lexical_block(i32 %arg1) { + ; CHECK llvm.add {{.*}} loc(#[[LOC0:.*]]) + %1 = add i32 %arg1, %arg1, !dbg !6 + + ; CHECK llvm.mul {{.*}} loc(#[[LOC1:.*]]) + %2 = mul i32 %arg1, %arg1, !dbg !7 + + ret i32 %2 +} +; CHECK #[[LOC0]] = loc(fused<#[[$LB0]]>["debug-info.ll":1:2]) +; CHECK #[[LOC1]] = loc(fused<#[[$LB1]]>["debug-info.ll":1:2]) + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!0} +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = distinct !DICompileUnit(language: DW_LANG_C, file: !2) +!2 = !DIFile(filename: "debug-info.ll", directory: "/") +!3 = distinct !DISubprogram(name: "lexical_block", scope: !2, file: !2, line: 42, scopeLine: 42, spFlags: DISPFlagDefinition, unit: !1) +!4 = !DILexicalBlock(scope: !3) +!5 = !DILexicalBlock(scope: !3, file: !2, line: 2, column: 2) +!6 = !DILocation(line: 1, column: 2, scope: !4) +!7 = !DILocation(line: 2, column: 2, scope: !5) + +; // ----- + +; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/"> +; CHECK: #[[SP:.+]] = #llvm.di_subprogram +; CHECK: #[[$LB1:.+]] = #llvm.di_lexical_block_file + +; CHECK-LABEL: @lexical_block_file +define i32 @lexical_block_file(i32 %arg1) { + ; CHECK llvm.add {{.*}} loc(#[[LOC0:.*]]) + %1 = add i32 %arg1, %arg1, !dbg !6 + + ; CHECK llvm.mul {{.*}} loc(#[[LOC1:.*]]) + %2 = mul i32 %arg1, %arg1, !dbg !7 + + ret i32 %2 +} +; CHECK #[[LOC0]] = loc(fused<#[[$LB0]]>["debug-info.ll":1:2])) +; CHECK #[[LOC1]] = loc(fused<#[[$LB1]]>["debug-info.ll":2:2])) + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!0} +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = distinct !DICompileUnit(language: DW_LANG_C, file: !2) +!2 = !DIFile(filename: "debug-info.ll", directory: "/") +!3 = distinct !DISubprogram(name: "lexical_block_file", scope: !2, file: !2, line: 42, scopeLine: 42, spFlags: DISPFlagDefinition, unit: !1) +!4 = !DILexicalBlockFile(scope: !3, discriminator: 0) +!5 = !DILexicalBlockFile(scope: !3, file: !2, discriminator: 0) +!6 = !DILocation(line: 1, column: 2, scope: !4) +!7 = !DILocation(line: 2, column: 2, scope: !5) + +; // ----- + +; CHECK: #[[INT1:.+]] = #llvm.di_basic_type +; CHECK: #[[INT2:.+]] = #llvm.di_basic_type +; CHECK: #llvm.di_subroutine_type + +define void @basic_type() !dbg !3 { + ret void +} + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!0} +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = distinct !DICompileUnit(language: DW_LANG_C, file: !2) +!2 = !DIFile(filename: "debug-info.ll", directory: "/") +!3 = distinct !DISubprogram(name: "basic_type", scope: !2, file: !2, line: 42, scopeLine: 42, spFlags: DISPFlagDefinition, unit: !1, type: !4) +!4 = !DISubroutineType(types: !5) +!5 = !{null, !6, !7} +!6 = !DIBasicType(name: "int1") +!7 = !DIBasicType(name: "int2", encoding: DW_ATE_signed, size: 32) + +; // ----- + +; CHECK: #[[INT:.+]] = #llvm.di_basic_type +; CHECK: #[[PTR1:.+]] = #llvm.di_derived_type +; CHECK: #[[PTR2:.+]] = #llvm.di_derived_type +; CHECK: #llvm.di_subroutine_type + +define void @derived_type() !dbg !3 { + ret void } -; CHECK: #[[LOC]] = loc("known_loc.cpp":8:3) -!llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!1} -!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !2) -!1 = !{i32 2, !"Debug Info Version", i32 3} -!2 = !DIFile(filename: "known_loc.cpp", directory: "/") -!3 = distinct !DISubprogram(name: "known_loc", scope: !0, file: !2, line: 1, scopeLine: 1, unit: !0) -!4 = !DILocation(line: 5, column: 2, scope: !3) -!5 = !DILocation(line: 8, column: 3, scope: !3) +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!0} +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = distinct !DICompileUnit(language: DW_LANG_C, file: !2) +!2 = !DIFile(filename: "debug-info.ll", directory: "/") +!3 = distinct !DISubprogram(name: "derived_type", scope: !2, file: !2, line: 42, scopeLine: 42, spFlags: DISPFlagDefinition, unit: !1, type: !4) +!4 = !DISubroutineType(types: !5) +!5 = !{null, !7, !8} +!6 = !DIBasicType(name: "int") +!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !6) +!8 = !DIDerivedType(name: "mypointer", tag: DW_TAG_pointer_type, baseType: !6, size: 64, align: 32, offset: 4) + +; // ----- + +; CHECK: #[[INT:.+]] = #llvm.di_basic_type +; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/"> +; CHECK: #[[COMP1:.+]] = #llvm.di_composite_type +; CHECK: #[[COMP2:.+]] = #llvm.di_composite_type<{{.*}}, file = #[[FILE]], line = 0, scope = #[[FILE]], baseType = #[[INT]], sizeInBits = 0, alignInBits = 0> +; CHECK: #[[COMP3:.+]] = #llvm.di_composite_type<{{.*}}, flags = Vector, {{.*}}, elements = #llvm.di_subrange> +; CHECK: #[[COMP4:.+]] = #llvm.di_composite_type<{{.*}}, elements = #llvm.di_subrange> +; CHECK: #llvm.di_subroutine_type + +define void @composite_type() !dbg !3 { + ret void +} + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!0} +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = distinct !DICompileUnit(language: DW_LANG_C, file: !2) +!2 = !DIFile(filename: "debug-info.ll", directory: "/") +!3 = distinct !DISubprogram(name: "composite_type", scope: !2, file: !2, line: 42, scopeLine: 42, spFlags: DISPFlagDefinition, unit: !1, type: !4) +!4 = !DISubroutineType(types: !5) +!5 = !{null, !7, !8, !9, !10} +!6 = !DIBasicType(name: "int") +!7 = !DICompositeType(tag: DW_TAG_array_type, name: "array1", line: 10, size: 128, align: 32) +!8 = !DICompositeType(tag: DW_TAG_array_type, name: "array2", file: !2, scope: !2, baseType: !6) +!9 = !DICompositeType(tag: DW_TAG_array_type, name: "array3", flags: DIFlagVector, elements: !13) +!10 = !DICompositeType(tag: DW_TAG_array_type, name: "array4", flags: DIFlagVector, elements: !14) +!11 = !DISubrange(count: 4) +!12 = !DISubrange(lowerBound: 0, upperBound: 4, stride: 1) +!13 = !{!11} +!14 = !{!12} + +; // ----- + +; CHECK: #[[INT:.+]] = #llvm.di_basic_type +; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/"> +; CHECK: #[[CU:.+]] = #llvm.di_compile_unit +; CHECK: #[[SP_TYPE:.+]] = #llvm.di_subroutine_type +; CHECK: #[[SP:.+]] = #llvm.di_subprogram + +define void @subprogram() !dbg !3 { + ret void +} + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!0} +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = distinct !DICompileUnit(language: DW_LANG_C, file: !2) +!2 = !DIFile(filename: "debug-info.ll", directory: "/") +!3 = distinct !DISubprogram(name: "subprogram", linkageName: "subprogram", scope: !2, file: !2, line: 42, scopeLine: 42, spFlags: DISPFlagDefinition, unit: !1, type: !4) +!4 = !DISubroutineType(cc: DW_CC_normal, types: !5) +!5 = !{!6, !6} +!6 = !DIBasicType(name: "int") + +; // ----- + +; CHECK: #[[$SP:.+]] = #llvm.di_subprogram + +; CHECK-LABEL: @func_loc +define void @func_loc() !dbg !3 { + ret void +} +; CHECK: loc(fused<#[[$SP]]>["func_loc"]) + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!0} +!0 = !{i32 2, !"Debug Info Version", i32 3} +!1 = distinct !DICompileUnit(language: DW_LANG_C, file: !2) +!2 = !DIFile(filename: "debug-info.ll", directory: "/") +!3 = distinct !DISubprogram(name: "func_loc", scope: !2, file: !2, line: 42, scopeLine: 42, spFlags: DISPFlagDefinition, unit: !1) + +; // ----- + +; Verify the module location is set to the source filename. +; CHECK: loc("debug-info.ll":0:0) +source_filename = "debug-info.ll"