ConvertFromLLVMIR.cpp
ConvertToLLVMIR.cpp
DebugTranslation.cpp
+ DebugImporter.cpp
ModuleTranslation.cpp
TypeToLLVM.cpp
TypeFromLLVM.cpp
add_mlir_translation_library(MLIRTargetLLVMIRImport
ConvertFromLLVMIR.cpp
+ DebugImporter.cpp
TypeFromLLVM.cpp
ADDITIONAL_HEADER_DIRS
//
//===----------------------------------------------------------------------===//
+#include "DebugImporter.h"
#include "mlir/Target/LLVMIR/Import.h"
#include "mlir/Dialect/DLTI/DLTI.h"
using namespace mlir;
using namespace mlir::LLVM;
+using mlir::LLVM::detail::DebugImporter;
#include "mlir/Dialect/LLVMIR/LLVMConversionEnumsFromLLVM.inc"
public:
Importer(MLIRContext *context, ModuleOp module)
: builder(context), context(context), module(module),
- typeTranslator(*context) {
+ typeTranslator(*context), debugImporter(context) {
builder.setInsertionPointToStart(module.getBody());
}
/// 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.
DenseMap<llvm::GlobalVariable *, GlobalOp> 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.
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<NamedAttribute, 1> argAttrs;
if (auto *type = func->getParamByValType(it.index())) {
MLIRContext *context) {
context->loadDialect<LLVMDialect>();
context->loadDialect<DLTIDialect>();
- OwningOpRef<ModuleOp> module(ModuleOp::create(
- FileLineColLoc::get(context, "", /*line=*/0, /*column=*/0)));
+ OwningOpRef<ModuleOp> module(ModuleOp::create(FileLineColLoc::get(
+ StringAttr::get(context, llvmModule->getSourceFileName()), /*line=*/0,
+ /*column=*/0)));
DataLayoutSpecInterface dlSpec =
translateDataLayout(llvmModule->getDataLayout(), context);
--- /dev/null
+//===- 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<DISubprogramAttr>::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<DIEmissionKind> 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<DIFlags> flags = symbolizeDIFlags(node->getFlags());
+ SmallVector<DINodeAttr> 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<DIScopeAttr>(translate(static_cast<llvm::DINode *>(node)));
+}
+
+DISubprogramAttr DebugImporter::translateImpl(llvm::DISubprogram *node) {
+ Optional<DISubprogramFlags> 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<llvm::ConstantInt *>(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<DITypeAttr> 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<DITypeAttr>(translate(static_cast<llvm::DINode *>(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<llvm::DIBasicType>(node))
+ return translateImpl(casted);
+ if (auto *casted = dyn_cast<llvm::DICompileUnit>(node))
+ return translateImpl(casted);
+ if (auto *casted = dyn_cast<llvm::DICompositeType>(node))
+ return translateImpl(casted);
+ if (auto *casted = dyn_cast<llvm::DIDerivedType>(node))
+ return translateImpl(casted);
+ if (auto *casted = dyn_cast<llvm::DIFile>(node))
+ return translateImpl(casted);
+ if (auto *casted = dyn_cast<llvm::DILexicalBlock>(node))
+ return translateImpl(casted);
+ if (auto *casted = dyn_cast<llvm::DILexicalBlockFile>(node))
+ return translateImpl(casted);
+ if (auto *casted = dyn_cast<llvm::DILocalVariable>(node))
+ return translateImpl(casted);
+ if (auto *casted = dyn_cast<llvm::DISubprogram>(node))
+ return translateImpl(casted);
+ if (auto *casted = dyn_cast<llvm::DISubrange>(node))
+ return translateImpl(casted);
+ if (auto *casted = dyn_cast<llvm::DISubroutineType>(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<DIScopeAttr>::get({result}, translate(loc->getScope()),
+ context);
+ return result;
+}
--- /dev/null
+//===- 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 <typename DINodeT>
+ auto translate(DINodeT *node) {
+ // Infer the MLIR type from the LLVM metadata type.
+ using MLIRTypeT = decltype(translateImpl(node));
+ return cast_or_null<MLIRTypeT>(
+ translate(static_cast<llvm::DINode *>(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<llvm::DINode *, DINodeAttr> nodeToAttr;
+
+ MLIRContext *context;
+};
+
+} // namespace detail
+} // namespace LLVM
+} // namespace mlir
+
+#endif // MLIR_LIB_TARGET_LLVMIR_DEBUIMPORTN_H_
; // -----
-; 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<compileUnit = #{{.*}}, scope = #{{.*}}, name = "instruction_loc"
+; CHECK: #[[$CALLEE:.+]] = #llvm.di_subprogram<compileUnit = #{{.*}}, scope = #{{.*}}, name = "callee"
+
+; CHECK-LABEL: @instruction_loc
+define i32 @instruction_loc(i32 %arg1) {
+ ; CHECK llvm.add {{.*}} loc(#[[FILE_LOC:.*]])
+ %1 = add i32 %arg1, %arg1, !dbg !5
+
+ ; CHECK llvm.mul {{.*}} loc(#[[CALLSITE_LOC:.*]])
+ %2 = mul i32 %1, %1, !dbg !7
+
+ ret i32 %2
+}
+; CHECK #[[FILE_LOC]] = loc(fused<#[[$SP]]>["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<compileUnit =
+; CHECK: #[[$LB0:.+]] = #llvm.di_lexical_block<scope = #[[SP]], line = 0, column = 0>
+; CHECK: #[[$LB1:.+]] = #llvm.di_lexical_block<scope = #[[SP]], file = #[[FILE]], line = 2, column = 2>
+
+; 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<compileUnit =
+; CHECK: #[[$LB0:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], discriminator = 0>
+; CHECK: #[[$LB1:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], file = #[[FILE]], discriminator = 0>
+
+; 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<tag = DW_TAG_base_type, name = "int1">
+; CHECK: #[[INT2:.+]] = #llvm.di_basic_type<tag = DW_TAG_base_type, name = "int2", sizeInBits = 32, encoding = DW_ATE_signed>
+; CHECK: #llvm.di_subroutine_type<argumentTypes = #[[INT1]], #[[INT2]]>
+
+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<tag = DW_TAG_base_type, name = "int">
+; CHECK: #[[PTR1:.+]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type, baseType = #[[INT]], sizeInBits = 0, alignInBits = 0, offsetInBits = 0>
+; CHECK: #[[PTR2:.+]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type, name = "mypointer", baseType = #[[INT]], sizeInBits = 64, alignInBits = 32, offsetInBits = 4>
+; CHECK: #llvm.di_subroutine_type<argumentTypes = #[[PTR1]], #[[PTR2]]>
+
+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<tag = DW_TAG_base_type, name = "int">
+; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/">
+; CHECK: #[[COMP1:.+]] = #llvm.di_composite_type<tag = DW_TAG_array_type, name = "array1", line = 10, sizeInBits = 128, alignInBits = 32>
+; 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<count = 4 : i64>>
+; CHECK: #[[COMP4:.+]] = #llvm.di_composite_type<{{.*}}, elements = #llvm.di_subrange<lowerBound = 0 : i64, upperBound = 4 : i64, stride = 1 : i64>>
+; CHECK: #llvm.di_subroutine_type<argumentTypes = #[[COMP1]], #[[COMP2]], #[[COMP3]], #[[COMP4]]>
+
+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<tag = DW_TAG_base_type, name = "int">
+; CHECK: #[[FILE:.+]] = #llvm.di_file<"debug-info.ll" in "/">
+; CHECK: #[[CU:.+]] = #llvm.di_compile_unit<sourceLanguage = DW_LANG_C, file = #[[FILE]], producer = "", isOptimized = false, emissionKind = None>
+; CHECK: #[[SP_TYPE:.+]] = #llvm.di_subroutine_type<callingConvention = DW_CC_normal, resultType = #[[INT]], argumentTypes = #[[INT]]>
+; CHECK: #[[SP:.+]] = #llvm.di_subprogram<compileUnit = #[[CU]], scope = #[[FILE]], name = "subprogram", linkageName = "subprogram", file = #[[FILE]], line = 42, scopeLine = 42, subprogramFlags = Definition, type = #[[SP_TYPE]]>
+
+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<compileUnit = #{{.*}}, scope = #{{.*}}, name = "func_loc", file = #{{.*}}, line = 42, scopeLine = 42, subprogramFlags = Definition>
+
+; 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"