This is an archive of the discontinued LLVM Phabricator instance.

[prototype] Adding line table debug information to LLVM on Windows
ClosedPublic

Authored by timurrrr on Nov 20 2013, 9:37 AM.
Tokens
"Love" token, awarded by williamledoux.

Details

Summary

Index: include/llvm/Support/DebugLoc.h

  • include/llvm/Support/DebugLoc.h

+++ 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 @@

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.

Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp

  • lib/CodeGen/AsmPrinter/AsmPrinter.cpp

+++ 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 @@

}
 
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;

Index: lib/CodeGen/AsmPrinter/CMakeLists.txt

  • lib/CodeGen/AsmPrinter/CMakeLists.txt

+++ lib/CodeGen/AsmPrinter/CMakeLists.txt
@@ -13,6 +13,7 @@

ErlangGCPrinter.cpp
OcamlGCPrinter.cpp
Win64Exception.cpp

+ WinCodeViewLineTables.cpp

)

add_dependencies(LLVMAsmPrinter intrinsics_gen)

Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp

  • lib/CodeGen/AsmPrinter/DwarfDebug.cpp

+++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -1525,30 +1525,6 @@

}

}

-// 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 @@

// 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()),

Index: lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h

  • /dev/null

+++ 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

Index: lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp

  • /dev/null

+++ 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);
+}
+}

Index: lib/IR/DebugLoc.cpp

  • lib/IR/DebugLoc.cpp

+++ lib/IR/DebugLoc.cpp
@@ -70,6 +70,26 @@

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) {

Index: test/DebugInfo/COFF/asm.ll

  • /dev/null

+++ 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}

Index: test/DebugInfo/COFF/multifile.ll

  • /dev/null

+++ 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 ]

Index: test/DebugInfo/COFF/multifunction.ll

  • /dev/null

+++ 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}

Index: test/DebugInfo/COFF/simple.ll

  • /dev/null

+++ 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}

Index: test/DebugInfo/X86/coff_debug_info_type.ll

  • /dev/null

+++ 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}

Index: test/DebugInfo/X86/coff_relative_names.ll

  • test/DebugInfo/X86/coff_relative_names.ll

+++ 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:

Diff Detail

Event Timeline

timurrrr updated this revision to Unknown Object (????).Dec 3 2013, 8:57 AM

Rebase on top of 196288.

timurrrr updated this revision to Unknown Object (????).Dec 5 2013, 6:18 AM

I've looked how file/dir handling is done in Clang and I think these strings are always stored/obtained separately.
I don't think there's a single place in the Clang codebase where they are merged together into a full filepath string.

I decided to write a dozen of lines in WinCodeViewLineTables.cpp to handle canonicalization of Windows filepaths rather than threading extra info from Clang to IR to LLVM in a cross-platform way...
After all, we only have one "user" of this data as of now.

Do you think this's reasonable?

Eric,

Do you have any comments on this patch?

rnk added a comment.Dec 10 2013, 8:54 AM

I talked to him in person on Friday, and I agree that we need *some* human
readable way to examine the data, not just .long N assembly directives.
I'd be happy if we had some named assembly directives. A dwarf dumper
would also work.

Can we start with factoring the code well?
I can work on a dumper in the meantime.

timurrrr updated this revision to Unknown Object (????).Dec 11 2013, 11:16 AM

Added a prototype CodeView line table dumper to COFFDumper.cpp

Can you please suggest

  • an effective splitting of the whole patch to make it easier to review
  • a good way to structure the new code, e.g. is it fine to leave the CV dumper in COFFDumper or should I have a gorilla holding a banana like dwarf-dump works? (e.g. DI structures etc)
  • is the simple.ll OBJ32 kind of test enough? or maybe you've meant some other kind of testing using a dumper?
  • what tests do we need for the dumper itself?
timurrrr updated this revision to Unknown Object (????).Dec 12 2013, 6:36 AM

Added some more lit test expectations, fixed a couple more bugs

timurrrr updated this revision to Unknown Object (????).Dec 12 2013, 6:43 AM

Make the tests much more readable by putting the input C files into the topmost comments

[Added David to the reviewers list]

timurrrr updated this revision to Unknown Object (????).Dec 16 2013, 8:49 AM

Authored some TODOs (mostly error handling in the COFF dumper).
Need help from someone familiar with the code on the remaining TODOs.

Eric, David,
Do you have anything to tell about this patch?

rnk added a comment.Dec 16 2013, 11:32 AM

Arg, I drafted and lost a whole bunch of comments on this patch. Sending them out, even though they are now out of date...

lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp
31

Is this map here for performance or reducing memory usage? I think the simpler way to reduce memory usage is to do the path canonicalization unconditionally, and then intern the string with a StringSet. Saves a template instantiation. *shrug*

43–45

I suppose if the user is cross-compiling from Linux targeting Windows, they always want backslashes, so llvm::sys::path::native() is wrong.

You can use its shorter implementation though:

std::replace(path.begin(), path.end(), '/', '\\')
52–53

I guess we have to do it textually like this because we can't look at the filesystem. We could be doing distributed cross-compilation, in which case the paths won't actually make sense.

lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h
89

This TODO seems obsolete now.

91

Is this specialized to use string comparison or will it use pointer comparison? If Dir and Filename are uniqued in the IR pointer comparison could be OK.

2013/12/16 Reid Kleckner <rnk@google.com>

Arg, I drafted and lost a whole bunch of comments on this patch.

Sending them out, even though they are now out of date...

:(

Comment at: lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h:90
@@ +89,3 @@
+ // readily available.
+ typedef DenseMap<std::pair<const char*, const char*>, char *>

+ DirAndFilenameToFilepathMapTy;

Is this specialized to use string comparison or will it use pointer
comparison? If Dir and Filename are uniqued in the IR pointer comparison
could be OK.

Good point - will check.

Comment at: lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h:88
@@ +87,3 @@
+
+ // TODO: we can probably get rid of this map if MDNode holds the
fullpath

+ // readily available.

This TODO seems obsolete now.

Yep, it's gone in the newer version of the patch.

Comment at: lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp:42-44
@@ +41,5 @@
+ size_t Cursor = 0;
+ // First, replace all slashes with backslashes.
+ while ((Cursor = Filepath.find('/', Cursor)) != std::string::npos)
+ Filepath[Cursor++] = '\\';

+

I suppose if the user is cross-compiling from Linux targeting Windows,
they always want backslashes, so llvm::sys::path::native() is wrong.

You can use its shorter implementation though:

std::replace(path.begin(), path.end(), '/', '\\')

Good catch - will do.

Comment at: lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp:30
@@ +29,3 @@
+ char *&Result =
+ DirAndFilenameToFilepathMap[std::make_pair(Dir.data(),
Filename.data())];

+ if (Result != 0)

Is this map here for performance or reducing memory usage? I think the
simpler way to reduce memory usage is to do the path canonicalization
unconditionally, and then intern the string with a StringSet. Saves a
template instantiation. *shrug*

I think this improves performance without sacrificing the memory usage too
much.
We call getFullFilename() for each debug location (think asm instruction),
so I think performance is really important here.

Comment at: lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp:51-52
@@ +50,4 @@
+
+ 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;

I guess we have to do it textually like this because we can't look at the
filesystem. We could be doing distributed cross-compilation, in which case
the paths won't actually make sense.

Exactly.
Even running LL lit tests on the same machine after a while makes the
filepaths dangle.

http://llvm-reviews.chandlerc.com/D2232

rnk added a comment.Dec 16 2013, 11:49 AM

Cool, I like how the dumper works. IMO keeping it in readobj is fine.

lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp
163

I'd rather spell out "lookup table"

182

ditto

test/DebugInfo/X86/CodeView/multifile.ll
7 ↗(On Diff #6126)

For future reference, you can clean up the IR a bit by declaring g void:

void g(void);

And then the variadic function type bitcasts in the IR will go away. No need to go back and change the IR for this.

OK, some ideas on how to break this up to make it a bit easier:

a) assembler support - the stuff to basically assemble various different .s files that happen to have the format. Test cases can be simple .s files and use llvm-mc and llvm-readobj to test. At least the label diff doesn't even really need to be a line table I wouldn't think.

b) dumper support - all of the coff dumping support would be good to split out. I don't think you need to worry about a separate directory/debug structure just for the line tables. When we expand past this we can look into it. You can check in some object files to use as test cases here.

c) Middle end support to handle the actual line tables. After a and b we can worry about this.

Sound good?

timurrrr updated this revision to Unknown Object (????).Dec 17 2013, 6:09 AM

Addressed Reid's comments.

+ typedef DenseMap<std::pair<const char*, const char*>, char *>

+ DirAndFilenameToFilepathMapTy;

Is this specialized to use string comparison or will it use pointer comparison?
If Dir and Filename are uniqued in the IR pointer comparison could be OK.

I *think* they are uniqued and null-terminated in the IR.
However, both conditions look very subtle, so I've decided to use pair<StringRef,StringRef> instead.
This requires defining a specialization for DenseMapInfo<StringRef>, which required adding two extra includes to densemapinfo.h.
Alternative suggestions are welcome!

Will try to split the patch now.

timurrrr updated this revision to Unknown Object (????).Dec 17 2013, 8:08 AM

Extracted the dumper part as D2425

2013/12/17 Eric Christopher <echristo@gmail.com>

OK, some ideas on how to break this up to make it a bit easier:

a) assembler support - the stuff to basically assemble various different .s files that happen

to have the format. Test cases can be simple .s files and use llvm-mc and llvm-readobj to test.
At least the label diff doesn't even really need to be a line table I wouldn't think.

Can you please clarify what needs to be tested using .s files?

I think you want me to test that

llc -filetype=asm | llvm-mc -filetype=obj

generates the same file as

llc -filetype=obj

does for the new directives emitted by EmitCOFFSectionReference and
EmitCOFFStaticOffset (namely ".secrel32" and ".offset from L1 to L2").

Just wanted to double-check that I understood you correctly.

b) dumper support - all of the coff dumping support would be good to split out.

I don't think you need to worry about a separate directory/debug structure just for the line tables.
When we expand past this we can look into it.
You can check in some object files to use as test cases here.

Done, http://llvm-reviews.chandlerc.com/D2425

c) Middle end support to handle the actual line tables. After a and b we can worry about this.

Sound good?

2013/12/17 Timur Iskhodzhanov <timurrrr@google.com>:

2013/12/17 Eric Christopher <echristo@gmail.com>

OK, some ideas on how to break this up to make it a bit easier:

a) assembler support - the stuff to basically assemble various different .s files that happen

to have the format. Test cases can be simple .s files and use llvm-mc and llvm-readobj to test.
At least the label diff doesn't even really need to be a line table I wouldn't think.

Can you please clarify what needs to be tested using .s files?

I think you want me to test that

llc -filetype=asm | llvm-mc -filetype=obj

generates the same file as

llc -filetype=obj

does for the new directives emitted by EmitCOFFSectionReference and
EmitCOFFStaticOffset (namely ".secrel32" and ".offset from L1 to L2").

Just wanted to double-check that I understood you correctly.

b) dumper support - all of the coff dumping support would be good to split out.

I don't think you need to worry about a separate directory/debug structure just for the line tables.
When we expand past this we can look into it.
You can check in some object files to use as test cases here.

Done, http://llvm-reviews.chandlerc.com/D2425

Plus r197499

c) Middle end support to handle the actual line tables. After a and b we can worry about this.

Sound good?

2013/12/17 Timur Iskhodzhanov <timurrrr@google.com>

OK, some ideas on how to break this up to make it a bit easier:

a) assembler support - the stuff to basically assemble various

different .s files that happen

to have the format. Test cases can be simple .s files and use llvm-mc

and llvm-readobj to test.

At least the label diff doesn't even really need to be a line table I

wouldn't think.

Can you please clarify what needs to be tested using .s files?

I think you want me to test that

llc -filetype=asm | llvm-mc -filetype=obj

generates the same file as

llc -filetype=obj

does for the new directives emitted by EmitCOFFSectionReference and
EmitCOFFStaticOffset (namely ".secrel32" and ".offset from L1 to L2").

Just wanted to double-check that I understood you correctly.

ping

Sorry, missed the question.

Pretty much. Mostly that you could just hand craft the particular
expressions that you're trying to assemble rather than working up an entire
llc -> .o file path. For example the kind of tests done in
test/MC/COFF/secrel-variant.s.

Make sense?

-eric

2013/12/19 Eric Christopher <echristo@gmail.com>:

Pretty much. Mostly that you could just hand craft the particular
expressions that you're trying to assemble rather than working up an entire
llc -> .o file path. For example the kind of tests done in
test/MC/COFF/secrel-variant.s.

Ah, OK, see D2445.

timurrrr updated this revision to Unknown Object (????).Dec 19 2013, 1:14 PM

I've split the MC stuff into D2445, so the patch looks pretty self-contained now.
Also did some minor refinements and polishing.

Can we start reviewing it in parallel with D2445?

rafael added inline comments.Dec 19 2013, 1:32 PM
test/DebugInfo/COFF/asm.ll
2

Please check the generated assembly instead of using -filetype=obj.

timurrrr added inline comments.Dec 20 2013, 5:08 AM
test/DebugInfo/COFF/asm.ll
2

Do you mean:
a) I shouldn't be using -filetype=obj in these tests at all
or
b) I should use at least -filetype=asm in each test
or
c) I should use -filtype=asm rather than =obj in this very test?

Anyways, adding the =obj RUN lines and checks to this file...

test/DebugInfo/COFF/multifile.ll
4

oops, forgotten the OBJ64 RUN line

210

Typo: should be +0x9.

timurrrr updated this revision to Unknown Object (????).Dec 20 2013, 5:09 AM

Minor fixes; somewhat addressed Rafael's review comment.

Do you mean:
a) I shouldn't be using -filetype=obj in these tests at all

This. Never, ever add a -filetype=obj test unless you have something
that has a good reason to be have a different code path in obj and asm
printing.

timurrrr updated this revision to Unknown Object (????).Dec 20 2013, 8:25 AM

Replace llc -mtriple=TRIPLE -filetype=obj ... with llc -mtriple=TRIPLE ... | llvm-mc -triple=TRIPLE -filetype=obj.

I'm leaving the ... | llvm-readobj ... -codeview-linetables tests here per Eric's initial request to test using a human-readable format.

Eric, Rafael,
Can you please agree on whether I need -filetype=obj | llvm-readobj tests here?

timurrrr updated this revision to Unknown Object (????).Dec 20 2013, 10:08 AM

Update the patch to use a .long To-From rather than .offset from From t To now that D2445 doesn't provide .offset.

timurrrr updated this revision to Unknown Object (????).Dec 20 2013, 11:08 AM

Rebase onto trunk now that D2445 has landed.

timurrrr updated this revision to Unknown Object (????).Dec 20 2013, 11:15 AM

Rebase on top of r197828 as it includes the test I've forgotten to add in r197826.

rafael added inline comments.Dec 20 2013, 11:22 AM
include/llvm/ADT/DenseMapInfo.h
136

This is way too specific to be in this header. "emptykey" and "tombstone!" are valid keys.

timurrrr added inline comments.Dec 20 2013, 11:50 AM
include/llvm/ADT/DenseMapInfo.h
136

Agreed, but not sure how to proceed.

Can you recommend a better way to create a DenseMap<pair<StringRef, StringRef>, X> ?

If you don't need null values, you could have <null, ""> be the empty key
and <"", null> be the tombstone, or something like that.

timurrrr updated this revision to Unknown Object (????).Dec 20 2013, 12:25 PM

Okay, using std::map as it's much simpler yet correct; and is not on the hot path.

In general it's starting to look very nice, thanks. Few comments in there plus the other comments from Rafael and David.

FWIW I do like the test cases for the larger debug info using the dumping facility to make it easier to figure out what's going on.

include/llvm/MC/MCObjectFileInfo.h
132

Is all COFF debug info in one section or just the line tables?

In general adding the sections to the MC layer can just be added as a separate small patch.

lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp
127

Magic!

How about an enum defined somewhere?

136

If you could split this loop into functions it would make it a bit easier.

245

Typo.

246

No particular reason I don't think.

lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h
37

Comment of what this is and what it's used for.

48

Comment of what this is and what it's used for.

59

Comment of what this is and what it's used for.

71

Comments.

If both of those aren't valid strings in the domain you're using this map
for, sure. (pedantry: StringRef("", 1) would suffice, since StringRef's
don't need to be null terminated :))

timurrrr updated this revision to Unknown Object (????).Dec 20 2013, 1:46 PM

Addressed Eric's comments.

Please take another look!

include/llvm/MC/MCObjectFileInfo.h
132

Good catch - it should actually be COFFDebugSymbolsSection.
Not sure adding it in a separate patch is worth it.

lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp
127

Yikes, fixed!

136

Done, also improved the comments a little bit.

245

Addressed the TODO, so no more typo needed :o)

246

ditto

256

Replaced with a FIXME to name the magic constant.

lib/CodeGen/AsmPrinter/WinCodeViewLineTables.h
37

Renamed to FunctionInfo and added a comment.

48

Done

59

Done

71

Done

This is now 99% debug info, so I think Eric should be the one to give
the final LGTM. In any case, the MC bits LGTM.

Looks pretty good, thanks.

I'd prefer you split out the MC bit when you commit, just because it's not necessary as part of this. One other comment below.

lib/CodeGen/AsmPrinter/AsmPrinter.cpp
198–205

I'm not sure this is the right conditional for this - at the very least it should be possible to continue with dwarf information on windows and this isn't going to let it. Possibly a command line option?

As we've discussed on llvm-dev earlier, we'll choose the debug info format
based on the triple for now (to simplify things) but may add a command line
option later when needed.

Are you OK if I just add a FIXME before the condition for now?
09 янв. 2014 г. 18:11 пользователь "Eric Christopher" <echristo@gmail.com>
написал:

Looks pretty good, thanks.

I'd prefer you split out the MC bit when you commit, just because it's

not necessary as part of this. One other comment below.

Comment at: lib/CodeGen/AsmPrinter/AsmPrinter.cpp:198
@@ -195,3 +197,3 @@

if (MAI->doesSupportDebugInformation()) {
  • DD = new DwarfDebug(this, &M);
  • Handlers.push_back(HandlerInfo(DD, DbgTimerName, DWARFGroupName));

+ if (Triple(TM.getTargetTriple()).isOSWindows()) {

+ Handlers.push_back(HandlerInfo(new WinCodeViewLineTables(this),

I'm not sure this is the right conditional for this - at the very least it
should be possible to continue with dwarf information on windows and this
isn't going to let it. Possibly a command line option?

http://llvm-reviews.chandlerc.com/D2232

Paul: Is this going to be an issue for you guys? I imagine so, but I'd like
to verify.

-eric

We're Windows hosted but not Windows targeted, so didn't seem relevant to our stuff.
If "this" was about something else let me know; I haven't been paying attention to this thread.
--paulr

From: Eric Christopher [mailto:echristo@gmail.com]
Sent: Friday, January 10, 2014 12:50 PM
To: timurrrr@google.com; reviews+D2232+public+3e8da1453c292d84@llvm-reviews.chandlerc.com; rnk@google.com; dblaikie@gmail.com; william.ledoux@gmail.com; rafael.espindola@gmail.com; llvm-commits@cs.uiuc.edu; Robinson, Paul
Subject: Re: [PATCH] [prototype] Adding line table debug information to LLVM on Windows

Paul: Is this going to be an issue for you guys? I imagine so, but I'd like to verify.

-eric

Ah right. Fair enough. For some reason I thought you guys did windows
hosted stuff on occasion. I don't know what made me think that.

-eric

echristo accepted this revision.Jan 10 2014, 3:42 PM

Fine for now. We'll want to add a -gcodeview or something to the front end eventually.

We care about *source* compatibility (e.g. pragma syntax) because many licensees dual port to some sort of Microsoft target :) but we really don't care about anything related to COFF.
--paulr

From: Eric Christopher [mailto:echristo@gmail.com]
Sent: Friday, January 10, 2014 3:41 PM
To: Robinson, Paul; timurrrr@google.com; reviews+D2232+public+3e8da1453c292d84@llvm-reviews.chandlerc.com; rnk@google.com; dblaikie@gmail.com; william.ledoux@gmail.com; rafael.espindola@gmail.com; llvm-commits@cs.uiuc.edu
Subject: RE: [PATCH] [prototype] Adding line table debug information to LLVM on Windows

Ah right. Fair enough. For some reason I thought you guys did windows hosted stuff on occasion. I don't know what made me think that.

-eric

Do I read it correctly like "Please add the FIXME, otherwise LGTM"?
10 янв. 2014 г. 17:41 пользователь "Eric Christopher" <echristo@gmail.com>
написал:

Fine for now. We'll want to add a -gcodeview or something to the front

end eventually.

http://llvm-reviews.chandlerc.com/D2232

echristo requested changes to this revision.Jan 11 2014, 8:28 AM

Go ahead and fix the conditional as I've mentioned below so we don't regress cygwin and mingw and it's OK with me.

lib/CodeGen/AsmPrinter/AsmPrinter.cpp
198–205

You need to use Triple(Tm.getTargetTriple()).getOS() == Triple::Win32 here, otherwise you're turning this on for cygwin and mingw and right now those support dwarf just fine and it's fairly expected there.

timurrrr updated this revision to Unknown Object (????).Jan 27 2014, 5:51 PM

[probably no action required]

Address the review comment (the triple condition) and replace TODOs with FIXMEs.

Self-TODO per offline discussion: I should add a couple of simple MinGW+Cygwin tests just to verify they emit DWARF, not CVLT.

timurrrr updated this revision to Unknown Object (????).Jan 28 2014, 11:57 AM

Rebase on top of the fresh trunk, add a simple test that verifies the correct debug sections are there.

Also, remove a conflicting triple assignment in one of the COFF lit tests.

echristo accepted this revision.Jan 28 2014, 12:58 PM
timurrrr closed this revision.Jan 28 2014, 1:41 PM

Landed as r200340.
Thanks for the review!

Reverted in r200375. It broke many llvm and clang tests, at least in msc17 builder.

lib/CodeGen/AsmPrinter/AsmPrinter.cpp
198–205

You should tweak more other tests (also in clang/test/CodeGen/ !) when you suppressed llvm::DwarfDebug.

You can reproduce such a case with LLVM_DEFAULT_TARGET_TRIPLE:=i686-pc-win32

Sorry for the breakage and not reverting it earlier - I don't think I got
an email about the failure.

How do you recommend me to tweak them?
The default triple on windows shouldn't imply dwarf. I think running these
tests with a -cygwin/-mingw32 triple is reasonable, as it is probably (?)
reasonable to run them with the default triple on non-Windows architectures.
28 янв. 2014 г. 22:23 пользователь "NAKAMURA Takumi" <geek4civic@gmail.com>
написал:

Reverted in r200375. It broke many llvm and clang tests, at least in

msc17 builder.

Comment at: lib/CodeGen/AsmPrinter/AsmPrinter.cpp:198
@@ -195,3 +197,3 @@

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),

You should tweak more other tests (also in clang/test/CodeGen/ !) when you
suppressed llvm::DwarfDebug.

You can reproduce such a case with
LLVM_DEFAULT_TARGET_TRIPLE:=i686-pc-win32

http://llvm-reviews.chandlerc.com/D2232

xaxadmin edited edge metadata.
xaxadmin added a subscriber: xaxadmin.
Via Old World