summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimur Iskhodzhanov <timurrrr@google.com>2014-01-28 21:33:27 +0000
committerTimur Iskhodzhanov <timurrrr@google.com>2014-01-28 21:33:27 +0000
commit38afdbea2c6962a3a808400a4d50345d18ccecfd (patch)
treeb03d8ad3387f61b5b2ebe49e5c46a67dd17bc71e
parent6cccb32fb09035854a77b01224d512eefe7de45d (diff)
downloadllvm-38afdbea2c6962a3a808400a4d50345d18ccecfd.tar.gz
llvm-38afdbea2c6962a3a808400a4d50345d18ccecfd.tar.bz2
llvm-38afdbea2c6962a3a808400a4d50345d18ccecfd.tar.xz
Add line table debug info to COFF files when using a win32 triple.
Reviewed at http://llvm-reviews.chandlerc.com/D2232 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@200340 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/Support/DebugLoc.h8
-rw-r--r--lib/CodeGen/AsmPrinter/AsmPrinter.cpp14
-rw-r--r--lib/CodeGen/AsmPrinter/CMakeLists.txt1
-rw-r--r--lib/CodeGen/AsmPrinter/DwarfDebug.cpp26
-rw-r--r--lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp323
-rw-r--r--lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h144
-rw-r--r--lib/IR/DebugLoc.cpp20
-rw-r--r--test/DebugInfo/COFF/asm.ll183
-rw-r--r--test/DebugInfo/COFF/multifile.ll257
-rw-r--r--test/DebugInfo/COFF/multifunction.ll378
-rw-r--r--test/DebugInfo/COFF/simple.ll167
-rw-r--r--test/DebugInfo/X86/coff_debug_info_type.ll39
-rw-r--r--test/DebugInfo/X86/coff_relative_names.ll4
13 files changed, 1531 insertions, 33 deletions
diff --git a/include/llvm/Support/DebugLoc.h b/include/llvm/Support/DebugLoc.h
index 05f31d7a49..f6cd19a61e 100644
--- a/include/llvm/Support/DebugLoc.h
+++ b/include/llvm/Support/DebugLoc.h
@@ -15,7 +15,7 @@
#ifndef LLVM_SUPPORT_DEBUGLOC_H
#define LLVM_SUPPORT_DEBUGLOC_H
-#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/DataTypes.h"
namespace llvm {
template <typename T> struct DenseMapInfo;
@@ -89,6 +89,12 @@ namespace llvm {
void getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA,
const LLVMContext &Ctx) const;
+ /// getScopeNode - Get MDNode for DebugLoc's scope, or null if invalid.
+ MDNode *getScopeNode(const LLVMContext &Ctx) const;
+
+ // getFnDebugLoc - Walk up the scope chain of given debug loc and find line
+ // number info for the function.
+ DebugLoc getFnDebugLoc(const LLVMContext &Ctx);
/// getAsMDNode - This method converts the compressed DebugLoc node into a
/// DILocation compatible MDNode.
diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index cdff074e97..0eee777e12 100644
--- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -49,11 +49,13 @@
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Transforms/Utils/GlobalStatus.h"
+#include "WinCodeViewLineTables.h"
using namespace llvm;
static const char *const DWARFGroupName = "DWARF Emission";
-static const char *const DbgTimerName = "DWARF Debug Writer";
+static const char *const DbgTimerName = "Debug Info Emission";
static const char *const EHTimerName = "DWARF Exception Writer";
+static const char *const CodeViewLineTablesGroupName = "CodeView Line Tables";
STATISTIC(EmittedInsts, "Number of machine instrs printed");
@@ -193,8 +195,14 @@ bool AsmPrinter::doInitialization(Module &M) {
}
if (MAI->doesSupportDebugInformation()) {
- DD = new DwarfDebug(this, &M);
- Handlers.push_back(HandlerInfo(DD, DbgTimerName, DWARFGroupName));
+ if (Triple(TM.getTargetTriple()).getOS() == Triple::Win32) {
+ Handlers.push_back(HandlerInfo(new WinCodeViewLineTables(this),
+ DbgTimerName,
+ CodeViewLineTablesGroupName));
+ } else {
+ DD = new DwarfDebug(this, &M);
+ Handlers.push_back(HandlerInfo(DD, DbgTimerName, DWARFGroupName));
+ }
}
DwarfException *DE = 0;
diff --git a/lib/CodeGen/AsmPrinter/CMakeLists.txt b/lib/CodeGen/AsmPrinter/CMakeLists.txt
index 2ad24e1af9..b3eddac191 100644
--- a/lib/CodeGen/AsmPrinter/CMakeLists.txt
+++ b/lib/CodeGen/AsmPrinter/CMakeLists.txt
@@ -13,6 +13,7 @@ add_llvm_library(LLVMAsmPrinter
ErlangGCPrinter.cpp
OcamlGCPrinter.cpp
Win64Exception.cpp
+ WinCodeViewLineTables.cpp
)
add_dependencies(LLVMAsmPrinter intrinsics_gen)
diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 1d059d9f3c..7c9f7a981a 100644
--- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -1525,30 +1525,6 @@ void DwarfDebug::identifyScopeMarkers() {
}
}
-// Get MDNode for DebugLoc's scope.
-static MDNode *getScopeNode(DebugLoc DL, const LLVMContext &Ctx) {
- if (MDNode *InlinedAt = DL.getInlinedAt(Ctx))
- return getScopeNode(DebugLoc::getFromDILocation(InlinedAt), Ctx);
- return DL.getScope(Ctx);
-}
-
-// Walk up the scope chain of given debug loc and find line number info
-// for the function.
-static DebugLoc getFnDebugLoc(DebugLoc DL, const LLVMContext &Ctx) {
- const MDNode *Scope = getScopeNode(DL, Ctx);
- DISubprogram SP = getDISubprogram(Scope);
- if (SP.isSubprogram()) {
- // Check for number of operands since the compatibility is
- // cheap here.
- if (SP->getNumOperands() > 19)
- return DebugLoc::get(SP.getScopeLineNumber(), 0, SP);
- else
- return DebugLoc::get(SP.getLineNumber(), 0, SP);
- }
-
- return DebugLoc();
-}
-
// Gather pre-function debug information. Assumes being called immediately
// after the function entry point has been emitted.
void DwarfDebug::beginFunction(const MachineFunction *MF) {
@@ -1743,7 +1719,7 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) {
// Record beginning of function.
if (!PrologEndLoc.isUnknown()) {
DebugLoc FnStartDL =
- getFnDebugLoc(PrologEndLoc, MF->getFunction()->getContext());
+ PrologEndLoc.getFnDebugLoc(MF->getFunction()->getContext());
recordSourceLine(
FnStartDL.getLine(), FnStartDL.getCol(),
FnStartDL.getScope(MF->getFunction()->getContext()),
diff --git a/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp b/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp
new file mode 100644
index 0000000000..1cb69e97c0
--- /dev/null
+++ b/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp
@@ -0,0 +1,323 @@
+//===-- llvm/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp --*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for writing line tables info into COFF files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "WinCodeViewLineTables.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/COFF.h"
+
+namespace llvm {
+
+StringRef WinCodeViewLineTables::getFullFilepath(const MDNode *S) {
+ assert(S);
+ DIDescriptor D(S);
+ assert((D.isCompileUnit() || D.isFile() || D.isSubprogram() ||
+ D.isLexicalBlockFile() || D.isLexicalBlock()) &&
+ "Unexpected scope info");
+
+ DIScope Scope(S);
+ StringRef Dir = Scope.getDirectory(),
+ Filename = Scope.getFilename();
+ char *&Result = DirAndFilenameToFilepathMap[std::make_pair(Dir, Filename)];
+ if (Result != 0)
+ return Result;
+
+ // Clang emits directory and relative filename info into the IR, but CodeView
+ // operates on full paths. We could change Clang to emit full paths too, but
+ // that would increase the IR size and probably not needed for other users.
+ // For now, just concatenate and canonicalize the path here.
+ std::string Filepath;
+ if (Filename.find(':') == 1)
+ Filepath = Filename;
+ else
+ Filepath = (Dir + Twine("\\") + Filename).str();
+
+ // Canonicalize the path. We have to do it textually because we may no longer
+ // have access the file in the filesystem.
+ // First, replace all slashes with backslashes.
+ std::replace(Filepath.begin(), Filepath.end(), '/', '\\');
+
+ // Remove all "\.\" with "\".
+ size_t Cursor = 0;
+ while ((Cursor = Filepath.find("\\.\\", Cursor)) != std::string::npos)
+ Filepath.erase(Cursor, 2);
+
+ // Replace all "\XXX\..\" with "\". Don't try too hard though as the original
+ // path should be well-formatted, e.g. start with a drive letter, etc.
+ Cursor = 0;
+ while ((Cursor = Filepath.find("\\..\\", Cursor)) != std::string::npos) {
+ // Something's wrong if the path starts with "\..\", abort.
+ if (Cursor == 0)
+ break;
+
+ size_t PrevSlash = Filepath.rfind('\\', Cursor - 1);
+ if (PrevSlash == std::string::npos)
+ // Something's wrong, abort.
+ break;
+
+ Filepath.erase(PrevSlash, Cursor + 3 - PrevSlash);
+ // The next ".." might be following the one we've just erased.
+ Cursor = PrevSlash;
+ }
+
+ // Remove all duplicate backslashes.
+ Cursor = 0;
+ while ((Cursor = Filepath.find("\\\\", Cursor)) != std::string::npos)
+ Filepath.erase(Cursor, 1);
+
+ Result = strdup(Filepath.c_str());
+ return StringRef(Result);
+}
+
+void WinCodeViewLineTables::maybeRecordLocation(DebugLoc DL,
+ const MachineFunction *MF) {
+ const MDNode *Scope = DL.getScope(MF->getFunction()->getContext());
+ if (!Scope)
+ return;
+ StringRef Filename = getFullFilepath(Scope);
+
+ // Skip this instruction if it has the same file:line as the previous one.
+ assert(CurFn);
+ if (!CurFn->Instrs.empty()) {
+ const InstrInfoTy &LastInstr = InstrInfo[CurFn->Instrs.back()];
+ if (LastInstr.Filename == Filename && LastInstr.LineNumber == DL.getLine())
+ return;
+ }
+ FileNameRegistry.add(Filename);
+
+ MCSymbol *MCL = Asm->MMI->getContext().CreateTempSymbol();
+ Asm->OutStreamer.EmitLabel(MCL);
+ CurFn->Instrs.push_back(MCL);
+ InstrInfo[MCL] = InstrInfoTy(Filename, DL.getLine());
+}
+
+WinCodeViewLineTables::WinCodeViewLineTables(AsmPrinter *Asm)
+ : Asm(Asm), CurFn(0) {
+ // Tell MMI that we have debug info.
+ Asm->MMI->setDebugInfoAvailability(true);
+}
+
+static void EmitLabelDiff(MCStreamer &Streamer,
+ const MCSymbol *From, const MCSymbol *To) {
+ MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
+ MCContext &Context = Streamer.getContext();
+ const MCExpr *FromRef = MCSymbolRefExpr::Create(From, Variant, Context),
+ *ToRef = MCSymbolRefExpr::Create(To, Variant, Context);
+ const MCExpr *AddrDelta =
+ MCBinaryExpr::Create(MCBinaryExpr::Sub, ToRef, FromRef, Context);
+ Streamer.EmitValue(AddrDelta, 4);
+}
+
+void WinCodeViewLineTables::emitDebugInfoForFunction(const Function *GV) {
+ // For each function there is a separate subsection
+ // which holds the PC to file:line table.
+ const MCSymbol *Fn = Asm->getSymbol(GV);
+ const FunctionInfo &FI = FnDebugInfo[GV];
+ assert(Fn);
+ assert(FI.Instrs.size() > 0);
+
+ // PCs/Instructions are grouped into segments sharing the same filename.
+ // Pre-calculate the lengths (in instructions) of these segments and store
+ // them in a map for convenience. Each index in the map is the sequential
+ // number of the respective instruction that starts a new segment.
+ DenseMap<size_t, size_t> FilenameSegmentLengths;
+ size_t LastSegmentEnd = 0;
+ StringRef PrevFilename = InstrInfo[FI.Instrs[0]].Filename;
+ for (size_t J = 1, F = FI.Instrs.size(); J != F; ++J) {
+ if (PrevFilename == InstrInfo[FI.Instrs[J]].Filename)
+ continue;
+ FilenameSegmentLengths[LastSegmentEnd] = J - LastSegmentEnd;
+ LastSegmentEnd = J;
+ PrevFilename = InstrInfo[FI.Instrs[J]].Filename;
+ }
+ FilenameSegmentLengths[LastSegmentEnd] = FI.Instrs.size() - LastSegmentEnd;
+
+ // Emit the control code of the subsection followed by the payload size.
+ Asm->OutStreamer.AddComment(
+ "Linetable subsection for " + Twine(Fn->getName()));
+ Asm->EmitInt32(COFF::DEBUG_LINE_TABLE_SUBSECTION);
+ MCSymbol *SubsectionBegin = Asm->MMI->getContext().CreateTempSymbol(),
+ *SubsectionEnd = Asm->MMI->getContext().CreateTempSymbol();
+ EmitLabelDiff(Asm->OutStreamer, SubsectionBegin, SubsectionEnd);
+ Asm->OutStreamer.EmitLabel(SubsectionBegin);
+
+ // Identify the function this subsection is for.
+ Asm->OutStreamer.EmitCOFFSecRel32(Fn);
+ Asm->OutStreamer.EmitCOFFSectionIndex(Fn);
+
+ // Length of the function's code, in bytes.
+ EmitLabelDiff(Asm->OutStreamer, Fn, FI.End);
+
+ // PC-to-linenumber lookup table:
+ MCSymbol *FileSegmentEnd = 0;
+ for (size_t J = 0, F = FI.Instrs.size(); J != F; ++J) {
+ MCSymbol *Instr = FI.Instrs[J];
+ assert(InstrInfo.count(Instr));
+
+ if (FilenameSegmentLengths.count(J)) {
+ // We came to a beginning of a new filename segment.
+ if (FileSegmentEnd)
+ Asm->OutStreamer.EmitLabel(FileSegmentEnd);
+ StringRef CurFilename = InstrInfo[FI.Instrs[J]].Filename;
+ assert(FileNameRegistry.Infos.count(CurFilename));
+ size_t IndexInStringTable =
+ FileNameRegistry.Infos[CurFilename].FilenameID;
+ // Each segment starts with the offset of the filename
+ // in the string table.
+ Asm->OutStreamer.AddComment(
+ "Segment for file '" + Twine(CurFilename) + "' begins");
+ MCSymbol *FileSegmentBegin = Asm->MMI->getContext().CreateTempSymbol();
+ Asm->OutStreamer.EmitLabel(FileSegmentBegin);
+ Asm->EmitInt32(8 * IndexInStringTable);
+
+ // Number of PC records in the lookup table.
+ size_t SegmentLength = FilenameSegmentLengths[J];
+ Asm->EmitInt32(SegmentLength);
+
+ // Full size of the segment for this filename, including the prev two
+ // records.
+ FileSegmentEnd = Asm->MMI->getContext().CreateTempSymbol();
+ EmitLabelDiff(Asm->OutStreamer, FileSegmentBegin, FileSegmentEnd);
+ }
+
+ // The first PC with the given linenumber and the linenumber itself.
+ EmitLabelDiff(Asm->OutStreamer, Fn, Instr);
+ Asm->EmitInt32(InstrInfo[Instr].LineNumber);
+ }
+
+ if (FileSegmentEnd)
+ Asm->OutStreamer.EmitLabel(FileSegmentEnd);
+ Asm->OutStreamer.EmitLabel(SubsectionEnd);
+}
+
+void WinCodeViewLineTables::endModule() {
+ if (FnDebugInfo.empty())
+ return;
+
+ Asm->OutStreamer.SwitchSection(
+ Asm->getObjFileLowering().getCOFFDebugSymbolsSection());
+ Asm->EmitInt32(COFF::DEBUG_SECTION_MAGIC);
+
+ // The COFF .debug$S section consists of several subsections, each starting
+ // with a 4-byte control code (e.g. 0xF1, 0xF2, etc) and then a 4-byte length
+ // of the payload followed by the payload itself. The subsections are 4-byte
+ // aligned.
+
+ for (size_t I = 0, E = VisitedFunctions.size(); I != E; ++I)
+ emitDebugInfoForFunction(VisitedFunctions[I]);
+
+ // This subsection holds a file index to offset in string table table.
+ Asm->OutStreamer.AddComment("File index to string table offset subsection");
+ Asm->EmitInt32(COFF::DEBUG_INDEX_SUBSECTION);
+ size_t NumFilenames = FileNameRegistry.Infos.size();
+ Asm->EmitInt32(8 * NumFilenames);
+ for (size_t I = 0, E = FileNameRegistry.Filenames.size(); I != E; ++I) {
+ StringRef Filename = FileNameRegistry.Filenames[I];
+ // For each unique filename, just write it's offset in the string table.
+ Asm->EmitInt32(FileNameRegistry.Infos[Filename].StartOffset);
+ // The function name offset is not followed by any additional data.
+ Asm->EmitInt32(0);
+ }
+
+ // This subsection holds the string table.
+ Asm->OutStreamer.AddComment("String table");
+ Asm->EmitInt32(COFF::DEBUG_STRING_TABLE_SUBSECTION);
+ Asm->EmitInt32(FileNameRegistry.LastOffset);
+ // The payload starts with a null character.
+ Asm->EmitInt8(0);
+
+ for (size_t I = 0, E = FileNameRegistry.Filenames.size(); I != E; ++I) {
+ // Just emit unique filenames one by one, separated by a null character.
+ Asm->OutStreamer.EmitBytes(FileNameRegistry.Filenames[I]);
+ Asm->EmitInt8(0);
+ }
+
+ // No more subsections. Fill with zeros to align the end of the section by 4.
+ Asm->OutStreamer.EmitFill((-FileNameRegistry.LastOffset) % 4, 0);
+
+ clear();
+}
+
+void WinCodeViewLineTables::beginFunction(const MachineFunction *MF) {
+ assert(!CurFn && "Can't process two functions at once!");
+
+ if (!Asm->MMI->hasDebugInfo())
+ return;
+
+ // Grab the lexical scopes for the function, if we don't have any of those
+ // then we're not going to be able to do anything.
+ LScopes.initialize(*MF);
+ if (LScopes.empty())
+ return;
+
+ const Function *GV = MF->getFunction();
+ assert(FnDebugInfo.count(GV) == false);
+ VisitedFunctions.push_back(GV);
+ CurFn = &FnDebugInfo[GV];
+
+ // Find the end of the function prolog.
+ // FIXME: is there a simpler a way to do this? Can we just search
+ // for the first instruction of the function, not the last of the prolog?
+ DebugLoc PrologEndLoc;
+ bool EmptyPrologue = true;
+ for (MachineFunction::const_iterator I = MF->begin(), E = MF->end();
+ I != E && PrologEndLoc.isUnknown(); ++I) {
+ for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end();
+ II != IE; ++II) {
+ const MachineInstr *MI = II;
+ if (MI->isDebugValue())
+ continue;
+
+ // First known non-DBG_VALUE and non-frame setup location marks
+ // the beginning of the function body.
+ // FIXME: do we need the first subcondition?
+ if (!MI->getFlag(MachineInstr::FrameSetup) &&
+ (!MI->getDebugLoc().isUnknown())) {
+ PrologEndLoc = MI->getDebugLoc();
+ break;
+ }
+ EmptyPrologue = false;
+ }
+ }
+ // Record beginning of function if we have a non-empty prologue.
+ if (!PrologEndLoc.isUnknown() && !EmptyPrologue) {
+ DebugLoc FnStartDL =
+ PrologEndLoc.getFnDebugLoc(MF->getFunction()->getContext());
+ maybeRecordLocation(FnStartDL, MF);
+ }
+}
+
+void WinCodeViewLineTables::endFunction(const MachineFunction *) {
+ if (!CurFn) // We haven't created any debug info for this function.
+ return;
+
+ if (CurFn->Instrs.empty())
+ llvm_unreachable("Can this ever happen?");
+
+ // Define end label for subprogram.
+ MCSymbol *FunctionEndSym = Asm->OutStreamer.getContext().CreateTempSymbol();
+ Asm->OutStreamer.EmitLabel(FunctionEndSym);
+ CurFn->End = FunctionEndSym;
+ CurFn = 0;
+}
+
+void WinCodeViewLineTables::beginInstruction(const MachineInstr *MI) {
+ // Ignore DBG_VALUE locations and function prologue.
+ if (MI->isDebugValue() || MI->getFlag(MachineInstr::FrameSetup))
+ return;
+ DebugLoc DL = MI->getDebugLoc();
+ if (DL == PrevInstLoc || DL.isUnknown())
+ return;
+ maybeRecordLocation(DL, Asm->MF);
+}
+}
diff --git a/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h b/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h
new file mode 100644
index 0000000000..f61ecc2f64
--- /dev/null
+++ b/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h
@@ -0,0 +1,144 @@
+//===-- llvm/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h ----*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains support for writing line tables info into COFF files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CODEGEN_ASMPRINTER_WINCODEVIEWLINETABLES_H__
+#define CODEGEN_ASMPRINTER_WINCODEVIEWLINETABLES_H__
+
+#include "AsmPrinterHandler.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/LexicalScopes.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/DebugLoc.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
+
+namespace llvm {
+/// \brief Collects and handles line tables information in a CodeView format.
+class WinCodeViewLineTables : public AsmPrinterHandler {
+ AsmPrinter *Asm;
+ DebugLoc PrevInstLoc;
+ LexicalScopes LScopes;
+
+ // For each function, store a vector of labels to its instructions, as well as
+ // to the end of the function.
+ struct FunctionInfo {
+ SmallVector<MCSymbol *, 10> Instrs;
+ MCSymbol *End;
+ } *CurFn;
+
+ typedef DenseMap<const Function *, FunctionInfo> FnDebugInfoTy;
+ FnDebugInfoTy FnDebugInfo;
+ // Store the functions we've visited in a vector so we can maintain a stable
+ // order while emitting subsections.
+ SmallVector<const Function *, 10> VisitedFunctions;
+
+ // InstrInfoTy - Holds the Filename:LineNumber information for every
+ // instruction with a unique debug location.
+ struct InstrInfoTy {
+ StringRef Filename;
+ unsigned LineNumber;
+
+ InstrInfoTy() : LineNumber(0) {}
+
+ InstrInfoTy(StringRef Filename, unsigned LineNumber)
+ : Filename(Filename), LineNumber(LineNumber) {}
+ };
+ DenseMap<MCSymbol *, InstrInfoTy> InstrInfo;
+
+ // FileNameRegistry - Manages filenames observed while generating debug info
+ // by filtering out duplicates and bookkeeping the offsets in the string
+ // table to be generated.
+ struct FileNameRegistryTy {
+ SmallVector<StringRef, 10> Filenames;
+ struct PerFileInfo {
+ size_t FilenameID, StartOffset;
+ };
+ StringMap<PerFileInfo> Infos;
+
+ // The offset in the string table where we'll write the next unique
+ // filename.
+ size_t LastOffset;
+
+ FileNameRegistryTy() {
+ clear();
+ }
+
+ // Add Filename to the registry, if it was not observed before.
+ void add(StringRef Filename) {
+ if (Infos.count(Filename))
+ return;
+ size_t OldSize = Infos.size();
+ Infos[Filename].FilenameID = OldSize;
+ Infos[Filename].StartOffset = LastOffset;
+ LastOffset += Filename.size() + 1;
+ Filenames.push_back(Filename);
+ }
+
+ void clear() {
+ LastOffset = 1;
+ Infos.clear();
+ Filenames.clear();
+ }
+ } FileNameRegistry;
+
+ typedef std::map<std::pair<StringRef, StringRef>, char *>
+ DirAndFilenameToFilepathMapTy;
+ DirAndFilenameToFilepathMapTy DirAndFilenameToFilepathMap;
+ StringRef getFullFilepath(const MDNode *S);
+
+ void maybeRecordLocation(DebugLoc DL, const MachineFunction *MF);
+
+ void clear() {
+ assert(CurFn == 0);
+ FileNameRegistry.clear();
+ InstrInfo.clear();
+ }
+
+ void emitDebugInfoForFunction(const Function *GV);
+
+public:
+ WinCodeViewLineTables(AsmPrinter *Asm);
+
+ ~WinCodeViewLineTables() {
+ for (DirAndFilenameToFilepathMapTy::iterator
+ I = DirAndFilenameToFilepathMap.begin(),
+ E = DirAndFilenameToFilepathMap.end();
+ I != E; ++I)
+ free(I->second);
+ }
+
+ virtual void setSymbolSize(const llvm::MCSymbol *, uint64_t) {}
+
+ /// \brief Emit the COFF section that holds the line table information.
+ virtual void endModule();
+
+ /// \brief Gather pre-function debug information.
+ virtual void beginFunction(const MachineFunction *MF);
+
+ /// \brief Gather post-function debug information.
+ virtual void endFunction(const MachineFunction *);
+
+ /// \brief Process beginning of an instruction.
+ virtual void beginInstruction(const MachineInstr *MI);
+
+ /// \brief Process end of an instruction.
+ virtual void endInstruction() {}
+};
+} // End of namespace llvm
+
+#endif
diff --git a/lib/IR/DebugLoc.cpp b/lib/IR/DebugLoc.cpp
index c57b5a3053..fcb6f4194e 100644
--- a/lib/IR/DebugLoc.cpp
+++ b/lib/IR/DebugLoc.cpp
@@ -70,6 +70,26 @@ void DebugLoc::getScopeAndInlinedAt(MDNode *&Scope, MDNode *&IA,
IA = Ctx.pImpl->ScopeInlinedAtRecords[-ScopeIdx-1].second.get();
}
+MDNode *DebugLoc::getScopeNode(const LLVMContext &Ctx) const {
+ if (MDNode *InlinedAt = getInlinedAt(Ctx))
+ return DebugLoc::getFromDILocation(InlinedAt).getScopeNode(Ctx);
+ return getScope(Ctx);
+}
+
+DebugLoc DebugLoc::getFnDebugLoc(const LLVMContext &Ctx) {
+ const MDNode *Scope = getScopeNode(Ctx);
+ DISubprogram SP = getDISubprogram(Scope);
+ if (SP.isSubprogram()) {
+ // Check for number of operands since the compatibility is
+ // cheap here. FIXME: Name the magic constant.
+ if (SP->getNumOperands() > 19)
+ return DebugLoc::get(SP.getScopeLineNumber(), 0, SP);
+ else
+ return DebugLoc::get(SP.getLineNumber(), 0, SP);
+ }
+
+ return DebugLoc();
+}
DebugLoc DebugLoc::get(unsigned Line, unsigned Col,
MDNode *Scope, MDNode *InlinedAt) {
diff --git a/test/DebugInfo/COFF/asm.ll b/test/DebugInfo/COFF/asm.ll
new file mode 100644
index 0000000000..1c6fbbf416
--- /dev/null
+++ b/test/DebugInfo/COFF/asm.ll
@@ -0,0 +1,183 @@
+; RUN: llc -mtriple=i686-pc-win32 -O0 < %s | FileCheck --check-prefix=X86 %s
+; RUN: llc -mtriple=i686-pc-win32 -o - -O0 < %s | llvm-mc -triple=i686-pc-win32 -filetype=obj | llvm-readobj -s -sr -codeview-linetables | FileCheck --check-prefix=OBJ32 %s
+; RUN: llc -mtriple=x86_64-pc-win32 -O0 < %s | FileCheck --check-prefix=X64 %s
+; RUN: llc -mtriple=x86_64-pc-win32 -o - -O0 < %s | llvm-mc -triple=x86_64-pc-win32 -filetype=obj | llvm-readobj -s -sr -codeview-linetables | FileCheck --check-prefix=OBJ64 %s
+
+; This LL file was generated by running clang on the following code:
+; D:\asm.c:
+; 1 void g(void);
+; 2
+; 3 void f(void) {
+; 4 __asm align 4;
+; 5 g();
+; 6 }
+
+; X86: _f:
+; X86-NEXT: # BB
+; X86-NEXT: [[ASM_LINE:^L.*]]:{{$}}
+; X86: [[CALL_LINE:^L.*]]:{{$}}
+; X86-NEXT: calll _g
+; X86-NEXT: [[RETURN_STMT:.*]]:
+; X86-NEXT: ret
+; X86-NEXT: [[END_OF_F:.*]]:
+;
+; X86: .section .debug$S,"rn"
+; X86-NEXT: .long 4
+; X86-NEXT: .long 242
+; X86-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
+; X86-NEXT: [[F2_START]]:
+; X86-NEXT: .secrel32 _f
+; X86-NEXT: .secidx _f
+; X86-NEXT: .long [[END_OF_F]]-_f
+; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X86-NEXT: .long 0
+; X86-NEXT: .long 3
+; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X86-NEXT: .long [[ASM_LINE]]-_f
+; X86-NEXT: .long 4
+; X86-NEXT: .long [[CALL_LINE]]-_f
+; X86-NEXT: .long 5
+; X86-NEXT: .long [[RETURN_STMT]]-_f
+; X86-NEXT: .long 6
+; X86-NEXT: [[FILE_SEGMENT_END]]:
+; X86-NEXT: [[F2_END]]:
+; File index to string table offset subsection
+; X86-NEXT: .long 244
+; X86-NEXT: .long 8
+; X86-NEXT: .long 1
+; X86-NEXT: .long 0
+; String table
+; X86-NEXT: .long 243
+; X86-NEXT: .long 10
+; X86-NEXT: .byte 0
+; X86-NEXT: .ascii "D:\\asm.c"
+; X86-NEXT: .byte 0
+; Padding
+; X86-NEXT: .zero 2
+
+; OBJ32: Section {
+; OBJ32: Name: .debug$S (2E 64 65 62 75 67 24 53)
+; OBJ32: Characteristics [ (0x42100040)
+; OBJ32: ]
+; OBJ32: Relocations [
+; OBJ32-NEXT: 0xC IMAGE_REL_I386_SECREL _f
+; OBJ32-NEXT: 0x10 IMAGE_REL_I386_SECTION _f
+; OBJ32-NEXT: ]
+; OBJ32: FunctionLineTable [
+; OBJ32-NEXT: Name: _f
+; OBJ32-NEXT: CodeSize: 0x6
+; OBJ32-NEXT: FilenameSegment [
+; OBJ32-NEXT: Filename: D:\asm.c
+; FIXME: An empty __asm stmt creates an extra entry.
+; We seem to know that these offsets are the same statically during the
+; execution of endModule().
+; OBJ32-NEXT: +0x0: 4
+; OBJ32-NEXT: +0x0: 5
+; OBJ32-NEXT: +0x5: 6
+; OBJ32-NEXT: ]
+; OBJ32-NEXT: ]
+; OBJ32: }
+
+; X64: f:
+; X64-NEXT: [[START:.*]]:{{$}}
+; X64-NEXT: # BB
+; X64-NEXT: subq $40, %rsp
+; X64-NEXT: [[ASM_LINE:.*]]:{{$}}
+; X64: [[CALL_LINE:.*]]:{{$}}
+; X64-NEXT: callq g
+; X64-NEXT: [[EPILOG_AND_RET:.*]]:
+; X64-NEXT: addq $40, %rsp
+; X64-NEXT: ret
+; X64-NEXT: [[END_OF_F:.*]]:
+;
+; X64: .section .debug$S,"rn"
+; X64-NEXT: .long 4
+; X64-NEXT: .long 242
+; X64-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
+; X64-NEXT: [[F2_START]]:
+; X64-NEXT: .secrel32 f
+; X64-NEXT: .secidx f
+; X64-NEXT: .long [[END_OF_F]]-f
+; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X64-NEXT: .long 0
+; X64-NEXT: .long 4
+; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X64-NEXT: .long [[START]]-f
+; X64-NEXT: .long 3
+; X64-NEXT: .long [[ASM_LINE]]-f
+; X64-NEXT: .long 4
+; X64-NEXT: .long [[CALL_LINE]]-f
+; X64-NEXT: .long 5
+; X64-NEXT: .long [[EPILOG_AND_RET]]-f
+; X64-NEXT: .long 6
+; X64-NEXT: [[FILE_SEGMENT_END]]:
+; X64-NEXT: [[F2_END]]:
+; File index to string table offset subsection
+; X64-NEXT: .long 244
+; X64-NEXT: .long 8
+; X64-NEXT: .long 1
+; X64-NEXT: .long 0
+; String table
+; X64-NEXT: .long 243
+; X64-NEXT: .long 10
+; X64-NEXT: .byte 0
+; X64-NEXT: .ascii "D:\\asm.c"
+; X64-NEXT: .byte 0
+; Padding
+; X64-NEXT: .zero 2
+
+; OBJ64: Section {
+; OBJ64: Name: .debug$S (2E 64 65 62 75 67 24 53)
+; OBJ64: Characteristics [ (0x42100040)
+; OBJ64: ]
+; OBJ64: Relocations [
+; OBJ64-NEXT: 0xC IMAGE_REL_AMD64_SECREL f
+; OBJ64-NEXT: 0x10 IMAGE_REL_AMD64_SECTION f
+; OBJ64-NEXT: ]
+; OBJ64: FunctionLineTable [
+; OBJ64-NEXT: Name: f
+; OBJ64-NEXT: CodeSize: 0xE
+; OBJ64-NEXT: FilenameSegment [
+; OBJ64-NEXT: Filename: D:\asm.c
+; OBJ64-NEXT: +0x0: 3
+; FIXME: An empty __asm stmt creates an extra entry.
+; OBJ64-NEXT: +0x4: 4
+; OBJ64-NEXT: +0x4: 5
+; OBJ64-NEXT: +0x9: 6
+; OBJ64-NEXT: ]
+; OBJ64-NEXT: ]
+; OBJ64: }
+
+; Function Attrs: nounwind
+define void @f() #0 {
+entry:
+ call void asm sideeffect inteldialect ".align 4", "~{dirflag},~{fpsr},~{flags}"() #2, !dbg !12
+ call void @g(), !dbg !13
+ ret void, !dbg !14
+}
+
+declare void @g() #1
+
+attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!9, !10}
+!llvm.ident = !{!11}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [D:\/<unknown>] [DW_LANG_C99]
+!1 = metadata !{metadata !"<unknown>", metadata !"D:\5C"}
+!2 = metadata !{i32 0}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786478, metadata !5, metadata !6, metadata !"f", metadata !"f", metadata !"", i32 3, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @f, null, null, metadata !2, i32 3} ; [ DW_TAG_subprogram ] [line 3] [def] [f]
+!5 = metadata !{metadata !"asm.c", metadata !"D:\5C"}
+!6 = metadata !{i32 786473, metadata !5} ; [ DW_TAG_file_type ] [D:\/asm.c]
+!7 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !8, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!8 = metadata !{null}
+!9 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!10 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+!11 = metadata !{metadata !"clang version 3.5 "}
+!12 = metadata !{i32 4, i32 0, metadata !4, null}
+!13 = metadata !{i32 5, i32 0, metadata !4, null}
+!14 = metadata !{i32 6, i32 0, metadata !4, null}
diff --git a/test/DebugInfo/COFF/multifile.ll b/test/DebugInfo/COFF/multifile.ll
new file mode 100644
index 0000000000..f218522868
--- /dev/null
+++ b/test/DebugInfo/COFF/multifile.ll
@@ -0,0 +1,257 @@
+; RUN: llc -mtriple=i686-pc-win32 -O0 < %s | FileCheck --check-prefix=X86 %s
+; RUN: llc -mtriple=i686-pc-win32 -o - -O0 < %s | llvm-mc -triple=i686-pc-win32 -filetype=obj | llvm-readobj -s -sr -codeview-linetables | FileCheck --check-prefix=OBJ32 %s
+; RUN: llc -mtriple=x86_64-pc-win32 -O0 < %s | FileCheck --check-prefix=X64 %s
+; RUN: llc -mtriple=x86_64-pc-win32 -o - -O0 < %s | llvm-mc -triple=x86_64-pc-win32 -filetype=obj | llvm-readobj -s -sr -codeview-linetables | FileCheck --check-prefix=OBJ64 %s
+
+; This LL file was generated by running clang on the following code:
+; D:\input.c:
+; 1 void g(void);
+; 2
+; 3 void f() {
+; 4 #line 1 "one.c"
+; 5 g(void);
+; 6 #line 2 "two.c"
+; 7 g(void);
+; 8 #line 7 "one.c"
+; 9 g(void);
+; 10 }
+
+; X86: _f:
+; X86-NEXT: # BB
+; X86-NEXT: [[CALL_LINE_1:.*]]:{{$}}
+; X86-NEXT: calll _g
+; X86-NEXT: [[CALL_LINE_2:.*]]:{{$}}
+; X86-NEXT: calll _g
+; X86-NEXT: [[CALL_LINE_3:.*]]:{{$}}
+; X86-NEXT: calll _g
+; X86-NEXT: [[RETURN_STMT:.*]]:
+; X86-NEXT: ret
+; X86-NEXT: [[END_OF_F:.*]]:
+;
+; X86: .section .debug$S,"rn"
+; X86-NEXT: .long 4
+; X86-NEXT: .long 242
+; X86-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
+; X86-NEXT: [[F2_START]]:
+; X86-NEXT: .secrel32 _f
+; X86-NEXT: .secidx _f
+; X86-NEXT: .long [[END_OF_F]]-_f
+; Segment for file 'D:\\one.c' begins
+; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X86-NEXT: .long 0
+; X86-NEXT: .long 1
+; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X86-NEXT: .long [[CALL_LINE_1]]-_f
+; X86-NEXT: .long 1
+; X86-NEXT: [[FILE_SEGMENT_END]]:
+; Segment for file 'D:\\two.c' begins
+; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X86-NEXT: .long 8
+; X86-NEXT: .long 1
+; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X86-NEXT: .long [[CALL_LINE_2]]-_f
+; X86-NEXT: .long 2
+; X86-NEXT: [[FILE_SEGMENT_END]]:
+; A new segment for file 'D:\\one.c' begins
+; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X86-NEXT: .long 0
+; X86-NEXT: .long 2
+; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X86-NEXT: .long [[CALL_LINE_3]]-_f
+; X86-NEXT: .long 7
+; X86-NEXT: .long [[RETURN_STMT]]-_f
+; X86-NEXT: .long 8
+; X86-NEXT: [[FILE_SEGMENT_END]]:
+; X86-NEXT: [[F2_END]]:
+; File index to string table offset subsection
+; X86-NEXT: .long 244
+; X86-NEXT: .long 16
+; X86-NEXT: .long 1
+; X86-NEXT: .long 0
+; X86-NEXT: .long 10
+; X86-NEXT: .long 0
+; String table
+; X86-NEXT: .long 243
+; X86-NEXT: .long 19
+; X86-NEXT: .byte 0
+; X86-NEXT: .ascii "D:\\one.c"
+; X86-NEXT: .byte 0
+; X86-NEXT: .ascii "D:\\two.c"
+; X86-NEXT: .byte 0
+; X86-NEXT: .zero 1
+
+; OBJ32: Section {
+; OBJ32: Name: .debug$S (2E 64 65 62 75 67 24 53)
+; OBJ32: Characteristics [ (0x42100040)
+; OBJ32: ]
+; OBJ32: Relocations [
+; OBJ32-NEXT: 0xC IMAGE_REL_I386_SECREL _f
+; OBJ32-NEXT: 0x10 IMAGE_REL_I386_SECTION _f
+; OBJ32-NEXT: ]
+; OBJ32: FunctionLineTable [
+; OBJ32-NEXT: Name: _f
+; OBJ32-NEXT: CodeSize: 0x10
+; OBJ32-NEXT: FilenameSegment [
+; OBJ32-NEXT: Filename: D:\one.c
+; OBJ32-NEXT: +0x0: 1
+; OBJ32-NEXT: ]
+; OBJ32-NEXT: FilenameSegment [
+; OBJ32-NEXT: Filename: D:\two.c
+; OBJ32-NEXT: +0x5: 2
+; OBJ32-NEXT: ]
+; OBJ32-NEXT: FilenameSegment [
+; OBJ32-NEXT: Filename: D:\one.c
+; OBJ32-NEXT: +0xA: 7
+; OBJ32-NEXT: +0xF: 8
+; OBJ32-NEXT: ]
+; OBJ32-NEXT: ]
+; OBJ32: }
+
+; X64: f:
+; X64-NEXT: [[START:.*]]:{{$}}
+; X64-NEXT: # BB
+; X64-NEXT: subq $40, %rsp
+; X64-NEXT: [[CALL_LINE_1:.*]]:{{$}}
+; X64-NEXT: callq g
+; X64-NEXT: [[CALL_LINE_2:.*]]:{{$}}
+; X64-NEXT: callq g
+; X64-NEXT: [[CALL_LINE_3:.*]]:{{$}}
+; X64-NEXT: callq g
+; X64-NEXT: [[EPILOG_AND_RET:.*]]:
+; X64-NEXT: addq $40, %rsp
+; X64-NEXT: ret
+; X64-NEXT: [[END_OF_F:.*]]:
+;
+; X64: .section .debug$S,"rn"
+; X64-NEXT: .long 4
+; X64-NEXT: .long 242
+; X64-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
+; X64-NEXT: [[F2_START]]:
+; X64-NEXT: .secrel32 f
+; X64-NEXT: .secidx f
+; X64-NEXT: .long [[END_OF_F]]-f
+; Segment for file 'D:\\input.c' begins
+; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X64-NEXT: .long 0
+; X64-NEXT: .long 1
+; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X64-NEXT: .long [[START]]-f
+; X64-NEXT: .long 3
+; X64-NEXT: [[FILE_SEGMENT_END]]:
+; Segment for file 'D:\\one.c' begins
+; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X64-NEXT: .long 8
+; X64-NEXT: .long 1
+; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X64-NEXT: .long [[CALL_LINE_1]]-f
+; X64-NEXT: .long 1
+; X64-NEXT: [[FILE_SEGMENT_END]]:
+; Segment for file 'D:\\two.c' begins
+; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X64-NEXT: .long 16
+; X64-NEXT: .long 1
+; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X64-NEXT: .long [[CALL_LINE_2]]-f
+; X64-NEXT: .long 2
+; X64-NEXT: [[FILE_SEGMENT_END]]:
+; A new segment for file 'D:\\one.c' begins
+; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X64-NEXT: .long 8
+; X64-NEXT: .long 2
+; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X64-NEXT: .long [[CALL_LINE_3]]-f
+; X64-NEXT: .long 7
+; X64-NEXT: .long [[EPILOG_AND_RET]]-f
+; X64-NEXT: .long 8
+; X64-NEXT: [[FILE_SEGMENT_END]]:
+; X64-NEXT: [[F2_END]]:
+; File index to string table offset subsection
+; X64-NEXT: .long 244
+; X64-NEXT: .long 24
+; X64-NEXT: .long 1
+; X64-NEXT: .long 0
+; X64-NEXT: .long 12
+; X64-NEXT: .long 0
+; X64-NEXT: .long 21
+; X64-NEXT: .long 0
+; String table
+; X64-NEXT: .long 243
+; X64-NEXT: .long 30
+; X64-NEXT: .byte 0
+; X64-NEXT: .ascii "D:\\input.c"
+; X64-NEXT: .byte 0
+; X64-NEXT: .ascii "D:\\one.c"
+; X64-NEXT: .byte 0
+; X64-NEXT: .ascii "D:\\two.c"
+; X64-NEXT: .byte 0
+; X64-NEXT: .zero 2
+
+; OBJ64: Section {
+; OBJ64: Name: .debug$S (2E 64 65 62 75 67 24 53)
+; OBJ64: Characteristics [ (0x42100040)
+; OBJ64: ]
+; OBJ64: Relocations [
+; OBJ64-NEXT: 0xC IMAGE_REL_AMD64_SECREL f
+; OBJ64-NEXT: 0x10 IMAGE_REL_AMD64_SECTION f
+; OBJ64-NEXT: ]
+; OBJ64: FunctionLineTable [
+; OBJ64-NEXT: Name: f
+; OBJ64-NEXT: CodeSize: 0x18
+; OBJ64-NEXT: FilenameSegment [
+; OBJ64-NEXT: Filename: D:\input.c
+; OBJ64-NEXT: +0x0: 3
+; OBJ64-NEXT: ]
+; OBJ64-NEXT: FilenameSegment [
+; OBJ64-NEXT: Filename: D:\one.c
+; OBJ64-NEXT: +0x4: 1
+; OBJ64-NEXT: ]
+; OBJ64-NEXT: FilenameSegment [
+; OBJ64-NEXT: Filename: D:\two.c
+; OBJ64-NEXT: +0x9: 2
+; OBJ64-NEXT: ]
+; OBJ64-NEXT: FilenameSegment [
+; OBJ64-NEXT: Filename: D:\one.c
+; OBJ64-NEXT: +0xE: 7
+; OBJ64-NEXT: +0x13: 8
+; OBJ64-NEXT: ]
+; OBJ64-NEXT: ]
+; OBJ64: }
+
+; Function Attrs: nounwind
+define void @f() #0 {
+entry:
+ call void @g(), !dbg !12
+ call void @g(), !dbg !15
+ call void @g(), !dbg !18
+ ret void, !dbg !19
+}
+
+declare void @g() #1
+
+attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!9, !10}
+!llvm.ident = !{!11}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [D:\/<unknown>] [DW_LANG_C99]
+!1 = metadata !{metadata !"<unknown>", metadata !"D:\5C"}
+!2 = metadata !{i32 0}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786478, metadata !5, metadata !6, metadata !"f", metadata !"f", metadata !"", i32 3, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @f, null, null, metadata !2, i32 3} ; [ DW_TAG_subprogram ] [line 3] [def] [f]
+!5 = metadata !{metadata !"input.c", metadata !"D:\5C"}
+!6 = metadata !{i32 786473, metadata !5} ; [ DW_TAG_file_type ] [D:\/input.c]
+!7 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !8, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!8 = metadata !{null}
+!9 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!10 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+!11 = metadata !{metadata !"clang version 3.5 "}
+!12 = metadata !{i32 1, i32 0, metadata !13, null}
+!13 = metadata !{i32 786443, metadata !14, metadata !4} ; [ DW_TAG_lexical_block ] [D:\/one.c]
+!14 = metadata !{metadata !"one.c", metadata !"D:\5C"}
+!15 = metadata !{i32 2, i32 0, metadata !16, null}
+!16 = metadata !{i32 786443, metadata !17, metadata !4} ; [ DW_TAG_lexical_block ] [D:\/two.c]
+!17 = metadata !{metadata !"two.c", metadata !"D:\5C"}
+!18 = metadata !{i32 7, i32 0, metadata !13, null}
+!19 = metadata !{i32 8, i32 0, metadata !13, null} ; [ DW_TAG_imported_declaration ]
diff --git a/test/DebugInfo/COFF/multifunction.ll b/test/DebugInfo/COFF/multifunction.ll
new file mode 100644
index 0000000000..f051db9d74
--- /dev/null
+++ b/test/DebugInfo/COFF/multifunction.ll
@@ -0,0 +1,378 @@
+; RUN: llc -mtriple=i686-pc-win32 -O0 < %s | FileCheck --check-prefix=X86 %s
+; RUN: llc -mtriple=i686-pc-win32 -o - -O0 < %s | llvm-mc -triple=i686-pc-win32 -filetype=obj | llvm-readobj -s -sr -codeview-linetables | FileCheck --check-prefix=OBJ32 %s
+; RUN: llc -mtriple=x86_64-pc-win32 -O0 < %s | FileCheck --check-prefix=X64 %s
+; RUN: llc -mtriple=x86_64-pc-win32 -o - -O0 < %s | llvm-mc -triple=x86_64-pc-win32 -filetype=obj | llvm-readobj -s -sr -codeview-linetables | FileCheck --check-prefix=OBJ64 %s
+
+; This LL file was generated by running clang on the following code:
+; D:\source.c:
+; 1 void z(void);
+; 2
+; 3 void x(void) {
+; 4 z();
+; 5 }
+; 6
+; 7 void y(void) {
+; 8 z();
+; 9 }
+; 10
+; 11 void f(void) {
+; 12 x();
+; 13 y();
+; 14 z();
+; 15 }
+
+
+; X86: _x:
+; X86-NEXT: # BB
+; X86-NEXT: [[X_CALL:.*]]:{{$}}
+; X86-NEXT: calll _z
+; X86-NEXT: [[X_RETURN:.*]]:
+; X86-NEXT: ret
+; X86-NEXT: [[END_OF_X:.*]]:
+;
+; X86: _y:
+; X86-NEXT: # BB
+; X86-NEXT: [[Y_CALL:.*]]:{{$}}
+; X86-NEXT: calll _z
+; X86-NEXT: [[Y_RETURN:.*]]:
+; X86-NEXT: ret
+; X86-NEXT: [[END_OF_Y:.*]]:
+;
+; X86: _f:
+; X86-NEXT: # BB
+; X86-NEXT: [[F_CALLS_X:.*]]:{{$}}
+; X86-NEXT: calll _x
+; X86-NEXT: [[F_CALLS_Y:.*]]:
+; X86-NEXT: calll _y
+; X86-NEXT: [[F_CALLS_Z:.*]]:
+; X86-NEXT: calll _z
+; X86-NEXT: [[F_RETURN:.*]]:
+; X86-NEXT: ret
+; X86-NEXT: [[END_OF_F:.*]]:
+;
+; X86: .section .debug$S,"rn"
+; X86-NEXT: .long 4
+; Line table subsection for x
+; X86-NEXT: .long 242
+; X86-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
+; X86-NEXT: [[F2_START]]:
+; X86-NEXT: .secrel32 _x
+; X86-NEXT: .secidx _x
+; X86-NEXT: .long [[END_OF_X]]-_x
+; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X86-NEXT: .long 0
+; X86-NEXT: .long 2
+; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X86-NEXT: .long [[X_CALL]]-_x
+; X86-NEXT: .long 4
+; X86-NEXT: .long [[X_RETURN]]-_x
+; X86-NEXT: .long 5
+; X86-NEXT: [[FILE_SEGMENT_END]]:
+; X86-NEXT: [[F2_END]]:
+; Line table subsection for y
+; X86-NEXT: .long 242
+; X86-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
+; X86-NEXT: [[F2_START]]:
+; X86-NEXT: .secrel32 _y
+; X86-NEXT: .secidx _y
+; X86-NEXT: .long [[END_OF_Y]]-_y
+; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X86-NEXT: .long 0
+; X86-NEXT: .long 2
+; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X86-NEXT: .long [[Y_CALL]]-_y
+; X86-NEXT: .long 8
+; X86-NEXT: .long [[Y_RETURN]]-_y
+; X86-NEXT: .long 9
+; X86-NEXT: [[FILE_SEGMENT_END]]:
+; X86-NEXT: [[F2_END]]:
+; Line table subsection for f
+; X86-NEXT: .long 242
+; X86-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
+; X86-NEXT: [[F2_START]]:
+; X86-NEXT: .secrel32 _f
+; X86-NEXT: .secidx _f
+; X86-NEXT: .long [[END_OF_F]]-_f
+; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X86-NEXT: .long 0
+; X86-NEXT: .long 4
+; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X86-NEXT: .long [[F_CALLS_X]]-_f
+; X86-NEXT: .long 12
+; X86-NEXT: .long [[F_CALLS_Y]]-_f
+; X86-NEXT: .long 13
+; X86-NEXT: .long [[F_CALLS_Z]]-_f
+; X86-NEXT: .long 14
+; X86-NEXT: .long [[F_RETURN]]-_f
+; X86-NEXT: .long 15
+; X86-NEXT: [[FILE_SEGMENT_END]]:
+; X86-NEXT: [[F2_END]]:
+; File index to string table offset subsection
+; X86-NEXT: .long 244
+; X86-NEXT: .long 8
+; X86-NEXT: .long 1
+; X86-NEXT: .long 0
+; String table
+; X86-NEXT: .long 243
+; X86-NEXT: .long 13
+; X86-NEXT: .byte 0
+; X86-NEXT: .ascii "D:\\source.c"
+; X86-NEXT: .byte 0
+; X86-NEXT: .zero 3
+
+; OBJ32: Section {
+; OBJ32: Name: .debug$S (2E 64 65 62 75 67 24 53)
+; OBJ32: Characteristics [ (0x42100040)
+; OBJ32: ]
+; OBJ32: Relocations [
+; OBJ32-NEXT: 0xC IMAGE_REL_I386_SECREL _x
+; OBJ32-NEXT: 0x10 IMAGE_REL_I386_SECTION _x
+; OBJ32-NEXT: 0x3C IMAGE_REL_I386_SECREL _y
+; OBJ32-NEXT: 0x40 IMAGE_REL_I386_SECTION _y
+; OBJ32-NEXT: 0x6C IMAGE_REL_I386_SECREL _f
+; OBJ32-NEXT: 0x70 IMAGE_REL_I386_SECTION _f
+; OBJ32-NEXT: ]
+; OBJ32: FunctionLineTable [
+; OBJ32-NEXT: Name: _x
+; OBJ32-NEXT: CodeSize: 0x6
+; OBJ32-NEXT: FilenameSegment [
+; OBJ32-NEXT: Filename: D:\source.c
+; OBJ32-NEXT: +0x0: 4
+; OBJ32-NEXT: +0x5: 5
+; OBJ32-NEXT: ]
+; OBJ32-NEXT: ]
+; OBJ32-NEXT: FunctionLineTable [
+; OBJ32-NEXT: Name: _y
+; OBJ32-NEXT: CodeSize: 0x6
+; OBJ32-NEXT: FilenameSegment [
+; OBJ32-NEXT: Filename: D:\source.c
+; OBJ32-NEXT: +0x0: 8
+; OBJ32-NEXT: +0x5: 9
+; OBJ32-NEXT: ]
+; OBJ32-NEXT: ]
+; OBJ32-NEXT: FunctionLineTable [
+; OBJ32-NEXT: Name: _f
+; OBJ32-NEXT: CodeSize: 0x10
+; OBJ32-NEXT: FilenameSegment [
+; OBJ32-NEXT: Filename: D:\source.c
+; OBJ32-NEXT: +0x0: 12
+; OBJ32-NEXT: +0x5: 13
+; OBJ32-NEXT: +0xA: 14
+; OBJ32-NEXT: +0xF: 15
+; OBJ32-NEXT: ]
+; OBJ32-NEXT: ]
+; OBJ32: }
+
+; X64: x:
+; X64-NEXT: [[X_START:.*]]:{{$}}
+; X64-NEXT: # BB
+; X64-NEXT: subq $40, %rsp
+; X64-NEXT: [[X_CALL_LINE:.*]]:{{$}}
+; X64-NEXT: callq z
+; X64-NEXT: [[X_EPILOG_AND_RET:.*]]:
+; X64-NEXT: addq $40, %rsp
+; X64-NEXT: ret
+; X64-NEXT: [[END_OF_X:.*]]:
+;
+; X64: y:
+; X64-NEXT: [[Y_START:.*]]:{{$}}
+; X64-NEXT: # BB
+; X64-NEXT: subq $40, %rsp
+; X64-NEXT: [[Y_CALL_LINE:.*]]:{{$}}
+; X64-NEXT: callq z
+; X64-NEXT: [[Y_EPILOG_AND_RET:.*]]:
+; X64-NEXT: addq $40, %rsp
+; X64-NEXT: ret
+; X64-NEXT: [[END_OF_Y:.*]]:
+;
+; X64: f:
+; X64-NEXT: [[F_START:.*]]:{{$}}
+; X64-NEXT: # BB
+; X64-NEXT: subq $40, %rsp
+; X64-NEXT: [[F_CALLS_X:.*]]:{{$}}
+; X64-NEXT: callq x
+; X64-NEXT: [[F_CALLS_Y:.*]]:
+; X64-NEXT: callq y
+; X64-NEXT: [[F_CALLS_Z:.*]]:
+; X64-NEXT: callq z
+; X64-NEXT: [[F_EPILOG_AND_RET:.*]]:
+; X64-NEXT: addq $40, %rsp
+; X64-NEXT: ret
+; X64-NEXT: [[END_OF_F:.*]]:
+;
+; X64: .section .debug$S,"rn"
+; X64-NEXT: .long 4
+; Line table subsection for x
+; X64-NEXT: .long 242
+; X64-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
+; X64-NEXT: [[F2_START]]:
+; X64-NEXT: .secrel32 x
+; X64-NEXT: .secidx x
+; X64-NEXT: .long [[END_OF_X]]-x
+; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X64-NEXT: .long 0
+; X64-NEXT: .long 3
+; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X64-NEXT: .long [[X_START]]-x
+; X64-NEXT: .long 3
+; X64-NEXT: .long [[X_CALL_LINE]]-x
+; X64-NEXT: .long 4
+; X64-NEXT: .long [[X_EPILOG_AND_RET]]-x
+; X64-NEXT: .long 5
+; X64-NEXT: [[FILE_SEGMENT_END]]:
+; X64-NEXT: [[F2_END]]:
+; Line table subsection for y
+; X64-NEXT: .long 242
+; X64-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
+; X64-NEXT: [[F2_START]]:
+; X64-NEXT: .secrel32 y
+; X64-NEXT: .secidx y
+; X64-NEXT: .long [[END_OF_Y]]-y
+; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X64-NEXT: .long 0
+; X64-NEXT: .long 3
+; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X64-NEXT: .long [[Y_START]]-y
+; X64-NEXT: .long 7
+; X64-NEXT: .long [[Y_CALL_LINE]]-y
+; X64-NEXT: .long 8
+; X64-NEXT: .long [[Y_EPILOG_AND_RET]]-y
+; X64-NEXT: .long 9
+; X64-NEXT: [[FILE_SEGMENT_END]]:
+; X64-NEXT: [[F2_END]]:
+; Line table subsection for f
+; X64-NEXT: .long 242
+; X64-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
+; X64-NEXT: [[F2_START]]:
+; X64-NEXT: .secrel32 f
+; X64-NEXT: .secidx f
+; X64-NEXT: .long [[END_OF_F]]-f
+; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X64-NEXT: .long 0
+; X64-NEXT: .long 5
+; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X64-NEXT: .long [[F_START]]-f
+; X64-NEXT: .long 11
+; X64-NEXT: .long [[F_CALLS_X]]-f
+; X64-NEXT: .long 12
+; X64-NEXT: .long [[F_CALLS_Y]]-f
+; X64-NEXT: .long 13
+; X64-NEXT: .long [[F_CALLS_Z]]-f
+; X64-NEXT: .long 14
+; X64-NEXT: .long [[F_EPILOG_AND_RET]]-f
+; X64-NEXT: .long 15
+; X64-NEXT: [[FILE_SEGMENT_END]]:
+; X64-NEXT: [[F2_END]]:
+; File index to string table offset subsection
+; X64-NEXT: .long 244
+; X64-NEXT: .long 8
+; X64-NEXT: .long 1
+; X64-NEXT: .long 0
+; String table
+; X64-NEXT: .long 243
+; X64-NEXT: .long 13
+; X64-NEXT: .byte 0
+; X64-NEXT: .ascii "D:\\source.c"
+; X64-NEXT: .byte 0
+; X64-NEXT: .zero 3
+
+; OBJ64: Section {
+; OBJ64: Name: .debug$S (2E 64 65 62 75 67 24 53)
+; OBJ64: Characteristics [ (0x42100040)
+; OBJ64: ]
+; OBJ64: Relocations [
+; OBJ64-NEXT: 0xC IMAGE_REL_AMD64_SECREL x
+; OBJ64-NEXT: 0x10 IMAGE_REL_AMD64_SECTION x
+; OBJ64-NEXT: 0x44 IMAGE_REL_AMD64_SECREL y
+; OBJ64-NEXT: 0x48 IMAGE_REL_AMD64_SECTION y
+; OBJ64-NEXT: 0x7C IMAGE_REL_AMD64_SECREL f
+; OBJ64-NEXT: 0x80 IMAGE_REL_AMD64_SECTION f
+; OBJ64-NEXT: ]
+; OBJ64: FunctionLineTable [
+; OBJ64-NEXT: Name: x
+; OBJ64-NEXT: CodeSize: 0xE
+; OBJ64-NEXT: FilenameSegment [
+; OBJ64-NEXT: Filename: D:\source.c
+; OBJ64-NEXT: +0x0: 3
+; OBJ64-NEXT: +0x4: 4
+; OBJ64-NEXT: +0x9: 5
+; OBJ64-NEXT: ]
+; OBJ64-NEXT: ]
+; OBJ64-NEXT: FunctionLineTable [
+; OBJ64-NEXT: Name: y
+; OBJ64-NEXT: CodeSize: 0xE
+; OBJ64-NEXT: FilenameSegment [
+; OBJ64-NEXT: Filename: D:\source.c
+; OBJ64-NEXT: +0x0: 7
+; OBJ64-NEXT: +0x4: 8
+; OBJ64-NEXT: +0x9: 9
+; OBJ64-NEXT: ]
+; OBJ64-NEXT: ]
+; OBJ64-NEXT: FunctionLineTable [
+; OBJ64-NEXT: Name: f
+; OBJ64-NEXT: CodeSize: 0x18
+; OBJ64-NEXT: FilenameSegment [
+; OBJ64-NEXT: Filename: D:\source.c
+; OBJ64-NEXT: +0x0: 11
+; OBJ64-NEXT: +0x4: 12
+; OBJ64-NEXT: +0x9: 13
+; OBJ64-NEXT: +0xE: 14
+; OBJ64-NEXT: +0x13: 15
+; OBJ64-NEXT: ]
+; OBJ64-NEXT: ]
+; OBJ64: }
+
+; Function Attrs: nounwind
+define void @x() #0 {
+entry:
+ call void @z(), !dbg !14
+ ret void, !dbg !15
+}
+
+declare void @z() #1
+
+; Function Attrs: nounwind
+define void @y() #0 {
+entry:
+ call void @z(), !dbg !16
+ ret void, !dbg !17
+}
+
+; Function Attrs: nounwind
+define void @f() #0 {
+entry:
+ call void @x(), !dbg !18
+ call void @y(), !dbg !19
+ call void @z(), !dbg !20
+ ret void, !dbg !21
+}
+
+attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!11, !12}
+!llvm.ident = !{!13}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [D:\/<unknown>] [DW_LANG_C99]
+!1 = metadata !{metadata !"<unknown>", metadata !"D:\5C"}
+!2 = metadata !{i32 0}
+!3 = metadata !{metadata !4, metadata !9, metadata !10}
+!4 = metadata !{i32 786478, metadata !5, metadata !6, metadata !"x", metadata !"x", metadata !"", i32 3, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @x, null, null, metadata !2, i32 3} ; [ DW_TAG_subprogram ] [line 3] [def] [x]
+!5 = metadata !{metadata !"source.c", metadata !"D:\5C"}
+!6 = metadata !{i32 786473, metadata !5} ; [ DW_TAG_file_type ] [D:\/source.c]
+!7 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !8, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!8 = metadata !{null}
+!9 = metadata !{i32 786478, metadata !5, metadata !6, metadata !"y", metadata !"y", metadata !"", i32 7, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @y, null, null, metadata !2, i32 7} ; [ DW_TAG_subprogram ] [line 7] [def] [y]
+!10 = metadata !{i32 786478, metadata !5, metadata !6, metadata !"f", metadata !"f", metadata !"", i32 11, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @f, null, null, metadata !2, i32 11} ; [ DW_TAG_subprogram ] [line 11] [def] [f]
+!11 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!12 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+!13 = metadata !{metadata !"clang version 3.5 "}
+!14 = metadata !{i32 4, i32 0, metadata !4, null}
+!15 = metadata !{i32 5, i32 0, metadata !4, null}
+!16 = metadata !{i32 8, i32 0, metadata !9, null} ; [ DW_TAG_imported_declaration ]
+!17 = metadata !{i32 9, i32 0, metadata !9, null}
+!18 = metadata !{i32 12, i32 0, metadata !10, null}
+!19 = metadata !{i32 13, i32 0, metadata !10, null}
+!20 = metadata !{i32 14, i32 0, metadata !10, null}
+!21 = metadata !{i32 15, i32 0, metadata !10, null}
diff --git a/test/DebugInfo/COFF/simple.ll b/test/DebugInfo/COFF/simple.ll
new file mode 100644
index 0000000000..2b3ab87351
--- /dev/null
+++ b/test/DebugInfo/COFF/simple.ll
@@ -0,0 +1,167 @@
+; RUN: llc -mtriple=i686-pc-win32 -O0 < %s | FileCheck --check-prefix=X86 %s
+; RUN: llc -mtriple=i686-pc-win32 -o - -O0 < %s | llvm-mc -triple=i686-pc-win32 -filetype=obj | llvm-readobj -s -sr -codeview-linetables | FileCheck --check-prefix=OBJ32 %s
+; RUN: llc -mtriple=x86_64-pc-win32 -O0 < %s | FileCheck --check-prefix=X64 %s
+; RUN: llc -mtriple=x86_64-pc-win32 -o - -O0 < %s | llvm-mc -triple=x86_64-pc-win32 -filetype=obj | llvm-readobj -s -sr -codeview-linetables | FileCheck --check-prefix=OBJ64 %s
+
+; This LL file was generated by running clang on the following code:
+; D:\test.c:
+; 1 void g(void);
+; 2
+; 3 void f(void) {
+; 4 g();
+; 5 }
+
+; X86: _f:
+; X86-NEXT: # BB
+; X86-NEXT: [[CALL_LINE:^L.*]]:{{$}}
+; X86-NEXT: calll _g
+; X86-NEXT: [[RETURN_STMT:.*]]:
+; X86-NEXT: ret
+; X86-NEXT: [[END_OF_F:.*]]:
+;
+; X86: .section .debug$S,"rn"
+; X86-NEXT: .long 4
+; X86-NEXT: .long 242
+; X86-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
+; X86-NEXT: [[F2_START]]:
+; X86-NEXT: .secrel32 _f
+; X86-NEXT: .secidx _f
+; X86-NEXT: .long [[END_OF_F]]-_f
+; X86-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X86-NEXT: .long 0
+; X86-NEXT: .long 2
+; X86-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X86-NEXT: .long [[CALL_LINE]]-_f
+; X86-NEXT: .long 4
+; X86-NEXT: .long [[RETURN_STMT]]-_f
+; X86-NEXT: .long 5
+; X86-NEXT: [[FILE_SEGMENT_END]]:
+; X86-NEXT: [[F2_END]]:
+; File index to string table offset subsection
+; X86-NEXT: .long 244
+; X86-NEXT: .long 8
+; X86-NEXT: .long 1
+; X86-NEXT: .long 0
+; String table
+; X86-NEXT: .long 243
+; X86-NEXT: .long 11
+; X86-NEXT: .byte 0
+; X86-NEXT: .ascii "D:\\test.c"
+; X86-NEXT: .byte 0
+; Padding
+; X86-NEXT: .zero 1
+
+; OBJ32: Section {
+; OBJ32: Name: .debug$S (2E 64 65 62 75 67 24 53)
+; OBJ32: Characteristics [ (0x42100040)
+; OBJ32: ]
+; OBJ32: Relocations [
+; OBJ32-NEXT: 0xC IMAGE_REL_I386_SECREL _f
+; OBJ32-NEXT: 0x10 IMAGE_REL_I386_SECTION _f
+; OBJ32-NEXT: ]
+; OBJ32: FunctionLineTable [
+; OBJ32-NEXT: Name: _f
+; OBJ32-NEXT: CodeSize: 0x6
+; OBJ32-NEXT: FilenameSegment [
+; OBJ32-NEXT: Filename: D:\test.c
+; OBJ32-NEXT: +0x0: 4
+; OBJ32-NEXT: +0x5: 5
+; OBJ32-NEXT: ]
+; OBJ32-NEXT: ]
+; OBJ32: }
+
+; X64: f:
+; X64-NEXT: [[START:.*]]:{{$}}
+; X64-NEXT: # BB
+; X64-NEXT: subq $40, %rsp
+; X64-NEXT: [[CALL_LINE:.*]]:{{$}}
+; X64-NEXT: callq g
+; X64-NEXT: [[EPILOG_AND_RET:.*]]:
+; X64-NEXT: addq $40, %rsp
+; X64-NEXT: ret
+; X64-NEXT: [[END_OF_F:.*]]:
+;
+; X64: .section .debug$S,"rn"
+; X64-NEXT: .long 4
+; X64-NEXT: .long 242
+; X64-NEXT: .long [[F2_END:.*]]-[[F2_START:.*]]
+; X64-NEXT: [[F2_START]]:
+; X64-NEXT: .secrel32 f
+; X64-NEXT: .secidx f
+; X64-NEXT: .long [[END_OF_F]]-f
+; X64-NEXT: [[FILE_SEGMENT_START:[^:]*]]:
+; X64-NEXT: .long 0
+; X64-NEXT: .long 3
+; X64-NEXT: .long [[FILE_SEGMENT_END:.*]]-[[FILE_SEGMENT_START]]
+; X64-NEXT: .long [[START]]-f
+; X64-NEXT: .long 3
+; X64-NEXT: .long [[CALL_LINE]]-f
+; X64-NEXT: .long 4
+; X64-NEXT: .long [[EPILOG_AND_RET]]-f
+; X64-NEXT: .long 5
+; X64-NEXT: [[FILE_SEGMENT_END]]:
+; X64-NEXT: [[F2_END]]:
+; File index to string table offset subsection
+; X64-NEXT: .long 244
+; X64-NEXT: .long 8
+; X64-NEXT: .long 1
+; X64-NEXT: .long 0
+; String table
+; X64-NEXT: .long 243
+; X64-NEXT: .long 11
+; X64-NEXT: .byte 0
+; X64-NEXT: .ascii "D:\\test.c"
+; X64-NEXT: .byte 0
+; Padding
+; X64-NEXT: .zero 1
+
+; OBJ64: Section {
+; OBJ64: Name: .debug$S (2E 64 65 62 75 67 24 53)
+; OBJ64: Characteristics [ (0x42100040)
+; OBJ64: ]
+; OBJ64: Relocations [
+; OBJ64-NEXT: 0xC IMAGE_REL_AMD64_SECREL f
+; OBJ64-NEXT: 0x10 IMAGE_REL_AMD64_SECTION f
+; OBJ64-NEXT: ]
+; OBJ64: FunctionLineTable [
+; OBJ64-NEXT: Name: f
+; OBJ64-NEXT: CodeSize: 0xE
+; OBJ64-NEXT: FilenameSegment [
+; OBJ64-NEXT: Filename: D:\test.c
+; OBJ64-NEXT: +0x0: 3
+; OBJ64-NEXT: +0x4: 4
+; OBJ64-NEXT: +0x9: 5
+; OBJ64-NEXT: ]
+; OBJ64-NEXT: ]
+; OBJ64: }
+
+; Function Attrs: nounwind
+define void @f() #0 {
+entry:
+ call void @g(), !dbg !12
+ ret void, !dbg !13
+}
+
+declare void @g() #1
+
+attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!9, !10}
+!llvm.ident = !{!11}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [D:\/<unknown>] [DW_LANG_C99]
+!1 = metadata !{metadata !"<unknown>", metadata !"D:\5C"}
+!2 = metadata !{i32 0}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786478, metadata !5, metadata !6, metadata !"f", metadata !"f", metadata !"", i32 3, metadata !7, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void ()* @f, null, null, metadata !2, i32 3} ; [ DW_TAG_subprogram ] [line 3] [def] [f]
+!5 = metadata !{metadata !"test.c", metadata !"D:\5C"}
+!6 = metadata !{i32 786473, metadata !5} ; [ DW_TAG_file_type ] [D:\/test.c]
+!7 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !8, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!8 = metadata !{null}
+!9 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!10 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+!11 = metadata !{metadata !"clang version 3.5 "}
+!12 = metadata !{i32 4, i32 0, metadata !4, null}
+!13 = metadata !{i32 5, i32 0, metadata !4, null}
diff --git a/test/DebugInfo/X86/coff_debug_info_type.ll b/test/DebugInfo/X86/coff_debug_info_type.ll
new file mode 100644
index 0000000000..2d63f58e4e
--- /dev/null
+++ b/test/DebugInfo/X86/coff_debug_info_type.ll
@@ -0,0 +1,39 @@
+; RUN: llc -mtriple=i686-pc-mingw32 -filetype=asm -O0 < %s | FileCheck %s
+; RUN: llc -mtriple=i686-pc-cygwin -filetype=asm -O0 < %s | FileCheck %s
+; RUN: llc -mtriple=i686-w64-mingw32 -filetype=asm -O0 < %s | FileCheck %s
+; CHECK: .section .debug_info
+
+; RUN: llc -mtriple=i686-pc-win32 -filetype=asm -O0 < %s | FileCheck -check-prefix=WIN32 %s
+; WIN32: .section .debug$S,"rn"
+
+; generated from:
+; clang -g -S -emit-llvm test.c -o test.ll
+; int main()
+; {
+; return 0;
+; }
+
+define i32 @main() #0 {
+entry:
+ %retval = alloca i32, align 4
+ store i32 0, i32* %retval
+ ret i32 0, !dbg !10
+}
+
+attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"="true" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!9, !11}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.4 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [C:\Projects/test.c] [DW_LANG_C99]
+!1 = metadata !{metadata !"test.c", metadata !"C:\5CProjects"}
+!2 = metadata !{i32 0}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"main", metadata !"main", metadata !"", i32 1, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 0, i1 false, i32 ()* @main, null, null, metadata !2, i32 2} ; [ DW_TAG_subprogram ] [line 1] [def] [scope 2] [main]
+!5 = metadata !{i32 786473, metadata !1} ; [ DW_TAG_file_type ] [C:\Projects/test.c]
+!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!7 = metadata !{metadata !8}
+!8 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
+!9 = metadata !{i32 2, metadata !"Dwarf Version", i32 3}
+!10 = metadata !{i32 3, i32 0, metadata !4, null}
+!11 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
diff --git a/test/DebugInfo/X86/coff_relative_names.ll b/test/DebugInfo/X86/coff_relative_names.ll
index 4cc38a63be..e5a5446063 100644
--- a/test/DebugInfo/X86/coff_relative_names.ll
+++ b/test/DebugInfo/X86/coff_relative_names.ll
@@ -10,10 +10,6 @@
; return 0;
; }
-; ModuleID = 'test.c'
-target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S32"
-target triple = "i686-pc-win32"
-
; Function Attrs: nounwind
define i32 @main() #0 {
entry: