Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -98,7 +98,8 @@ virtual void prettyPrintAsm(MCInstPrinter &InstPrinter, raw_ostream &OS, const MCInst &Inst, const MCSubtargetInfo &STI); - virtual void emitDwarfFileDirective(StringRef Directive); + virtual void emitDwarfFileDirective(unsigned FileNo, StringRef Directory, + StringRef Filename, StringRef Directive); /// Update streamer for a new active section. /// Index: lib/MC/MCAsmStreamer.cpp =================================================================== --- lib/MC/MCAsmStreamer.cpp +++ lib/MC/MCAsmStreamer.cpp @@ -1178,7 +1178,7 @@ UseDwarfDirectory, OS1); if (MCTargetStreamer *TS = getTargetStreamer()) - TS->emitDwarfFileDirective(OS1.str()); + TS->emitDwarfFileDirective(FileNo, Directory, Filename, OS1.str()); else EmitRawText(OS1.str()); @@ -1204,7 +1204,7 @@ UseDwarfDirectory, OS1); if (MCTargetStreamer *TS = getTargetStreamer()) - TS->emitDwarfFileDirective(OS1.str()); + TS->emitDwarfFileDirective(0, Directory, Filename, OS1.str()); else EmitRawText(OS1.str()); } Index: lib/MC/MCStreamer.cpp =================================================================== --- lib/MC/MCStreamer.cpp +++ lib/MC/MCStreamer.cpp @@ -60,7 +60,8 @@ Subsection); } -void MCTargetStreamer::emitDwarfFileDirective(StringRef Directive) { +void MCTargetStreamer::emitDwarfFileDirective(unsigned, StringRef, StringRef, + StringRef Directive) { Streamer.EmitRawText(Directive); } Index: lib/Target/NVPTX/MCTargetDesc/NVPTXTargetStreamer.h =================================================================== --- lib/Target/NVPTX/MCTargetDesc/NVPTXTargetStreamer.h +++ lib/Target/NVPTX/MCTargetDesc/NVPTXTargetStreamer.h @@ -18,7 +18,8 @@ /// Implments NVPTX-specific streamer. class NVPTXTargetStreamer : public MCTargetStreamer { private: - SmallVector DwarfFiles; + SmallVector DwarfDirectives; + StringMap DwarfFilesIds; public: NVPTXTargetStreamer(MCStreamer &S); @@ -36,7 +37,10 @@ /// emitted, i.e. they may be emitted inside functions. We gather all these /// directives and emit them outside of the sections and, thus, outside of the /// functions. - void emitDwarfFileDirective(StringRef Directive) override; + void emitDwarfFileDirective(unsigned FileNo, StringRef Directory, + StringRef Filename, StringRef Directive) override; + /// Gets the file number for the specified diretory/filename. + unsigned getOrCreateFileNo(StringRef Directory, StringRef Filename) const; void changeSection(const MCSection *CurSection, MCSection *Section, const MCExpr *SubSection, raw_ostream &OS) override; }; Index: lib/Target/NVPTX/MCTargetDesc/NVPTXTargetStreamer.cpp =================================================================== --- lib/Target/NVPTX/MCTargetDesc/NVPTXTargetStreamer.cpp +++ lib/Target/NVPTX/MCTargetDesc/NVPTXTargetStreamer.cpp @@ -15,6 +15,7 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/Support/Path.h" using namespace llvm; @@ -25,8 +26,24 @@ NVPTXTargetStreamer::~NVPTXTargetStreamer() = default; -void NVPTXTargetStreamer::emitDwarfFileDirective(StringRef Directive) { - DwarfFiles.emplace_back(Directive); +void NVPTXTargetStreamer::emitDwarfFileDirective(unsigned FileNo, + StringRef Directory, + StringRef Filename, + StringRef Directive) { + DwarfFilesIds.try_emplace( + llvm::join_items(sys::path::get_separator(), Directory, Filename), + FileNo); + DwarfDirectives.emplace_back(Directive); +} + +unsigned NVPTXTargetStreamer::getOrCreateFileNo(StringRef Directory, + StringRef Filename) const { + std::string Path = + llvm::join_items(sys::path::get_separator(), Directory, Filename); + auto It = DwarfFilesIds.find(Path); + if (It != DwarfFilesIds.end()) + return It->second; + return DwarfFilesIds.size() + 1; } static bool isDwarfSection(const MCObjectFileInfo *FI, @@ -82,9 +99,9 @@ OS << "//\t}\n"; if (isDwarfSection(FI, Section)) { // Emit DWARF .file directives in the outermost scope. - for (const std::string &S : DwarfFiles) + for (const std::string &S : DwarfDirectives) getStreamer().EmitRawText(S.data()); - DwarfFiles.clear(); + DwarfDirectives.clear(); OS << "//\t.section"; Section->PrintSwitchToSection(*getStreamer().getContext().getAsmInfo(), FI->getTargetTriple(), OS, SubSection); Index: lib/Target/NVPTX/NVPTXAsmPrinter.cpp =================================================================== --- lib/Target/NVPTX/NVPTXAsmPrinter.cpp +++ lib/Target/NVPTX/NVPTXAsmPrinter.cpp @@ -16,6 +16,7 @@ #include "InstPrinter/NVPTXInstPrinter.h" #include "MCTargetDesc/NVPTXBaseInfo.h" #include "MCTargetDesc/NVPTXMCAsmInfo.h" +#include "MCTargetDesc/NVPTXTargetStreamer.h" #include "NVPTX.h" #include "NVPTXMCExpr.h" #include "NVPTXMachineFunctionInfo.h" @@ -437,6 +438,17 @@ OutStreamer->EmitRawText(StringRef("\t.pragma \"nounroll\";\n")); } +static DebugLoc findPrologueEndLoc(const MachineFunction *MF) { + // First known non-DBG_VALUE and non-frame setup location marks + // the beginning of the function body. + for (const auto &MBB : *MF) + for (const auto &MI : MBB) + if (!MI.isMetaInstruction() && !MI.getFlag(MachineInstr::FrameSetup) && + MI.getDebugLoc()) + return MI.getDebugLoc(); + return DebugLoc(); +} + void NVPTXAsmPrinter::EmitFunctionEntryLabel() { SmallString<128> Str; raw_svector_ostream O(Str); @@ -470,6 +482,28 @@ // Emit open brace for function body. OutStreamer->EmitRawText(StringRef("{\n")); setAndEmitFunctionVirtualRegisters(*MF); + if (MMI && MMI->hasDebugInfo()) { + // Emit initial .loc debug directive for correct relocation symbol data. + // Record beginning of function. + unsigned FileNo = 1; + unsigned Line = 1; + if (DebugLoc PrologEndLoc = findPrologueEndLoc(MF)) { + // We'd like to list the prologue as "not statements" but GDB behaves + // poorly if we do that. Revisit this with caution/GDB (7.5+) testing. + if (const DISubprogram *SP = + PrologEndLoc->getInlinedAtScope()->getSubprogram()) { + const DIFile *DIF = SP->getFile(); + auto *TS = static_cast( + OutStreamer->getTargetStreamer()); + FileNo = TS->getOrCreateFileNo(DIF->getDirectory(), DIF->getFilename()); + Line = SP->getScopeLine(); + } + } + SmallString<128> Str; + raw_svector_ostream O(Str); + O << "\t.loc\t" << FileNo << " " << Line << " 0"; + OutStreamer->EmitRawText(O.str()); + } } bool NVPTXAsmPrinter::runOnMachineFunction(MachineFunction &F) { Index: test/DebugInfo/NVPTX/cu-range-hole.ll =================================================================== --- test/DebugInfo/NVPTX/cu-range-hole.ll +++ test/DebugInfo/NVPTX/cu-range-hole.ll @@ -6,6 +6,7 @@ ; CHECK: .param .b32 b_param_0 ; CHECK: ) ; CHECK: { +; CHECK: .loc 1 1 0 ; CHECK: Lfunc_begin0: ; CHECK: .loc 1 1 0 ; CHECK: .loc 1 1 0 @@ -27,6 +28,7 @@ ; CHECK: .param .b32 d_param_0 ; CHECK: ) ; CHECK: { +; CHECK: .loc 1 3 0 ; CHECK: Lfunc_begin2: ; CHECK: .loc 1 3 0 ; CHECK: ret; Index: test/DebugInfo/NVPTX/debug-loc-offset.ll =================================================================== --- test/DebugInfo/NVPTX/debug-loc-offset.ll +++ test/DebugInfo/NVPTX/debug-loc-offset.ll @@ -11,8 +11,9 @@ ; CHECK: .visible .func (.param .b32 func_retval0) _Z3bari( ; CHECK: { -; CHECK: Lfunc_begin0: ; CHECK: .loc [[CU1:[0-9]+]] 1 0 +; CHECK: Lfunc_begin0: +; CHECK: .loc [[CU1]] 1 0 ; CHECK: //DEBUG_VALUE: bar:b <- {{[0-9]+}} ; CHECK: //DEBUG_VALUE: bar:b <- {{[0-9]+}} @@ -39,8 +40,9 @@ ; CHECK: .visible .func _Z3baz1A( ; CHECK: { -; CHECK: Lfunc_begin1: ; CHECK: .loc [[CU2:[0-9]+]] 6 0 +; CHECK: Lfunc_begin1: +; CHECK: .loc [[CU2]] 6 0 ; CHECK: //DEBUG_VALUE: baz:z <- {{[0-9]+}} ; CHECK: //DEBUG_VALUE: baz:z <- {{[0-9]+}} ; CHECK: .loc [[CU2]] 10 0