Index: include/llvm/MC/MCTargetOptions.h =================================================================== --- include/llvm/MC/MCTargetOptions.h +++ include/llvm/MC/MCTargetOptions.h @@ -23,6 +23,12 @@ WinEH, /// Windows Exception Handling }; +enum class AsmSourceOutput { + None, + Alone, + WithDebug +}; + class StringRef; class MCTargetOptions { @@ -47,6 +53,7 @@ bool ShowMCEncoding : 1; bool ShowMCInst : 1; bool AsmVerbose : 1; + int AsmSource : 2; /// Preserve Comments in Assembly. bool PreserveAsmComments : 1; @@ -82,6 +89,7 @@ ARE_EQUAL(ShowMCEncoding) && ARE_EQUAL(ShowMCInst) && ARE_EQUAL(AsmVerbose) && + ARE_EQUAL(AsmSource) && ARE_EQUAL(DwarfVersion) && ARE_EQUAL(ABIName) && ARE_EQUAL(IASSearchPaths)); Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -15,6 +15,7 @@ #include "CodeViewDebug.h" #include "DwarfDebug.h" #include "DwarfException.h" +#include "SourceInterleave.h" #include "WinException.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" @@ -120,6 +121,11 @@ static const char *const CodeViewLineTablesGroupDescription = "CodeView Line Tables"; +static const char *const SourceInterleaveGroupName = "source printer"; +static const char *const SourceInterleaveGroupDescription = "Interleave source code comments with instructions"; +static const char *const SourceInterleaveTimerName = "interleave_source"; +static const char *const SourceInterleaveTimerDescription = "Source interleaver"; + STATISTIC(EmittedInsts, "Number of machine instrs printed"); char AsmPrinter::ID = 0; @@ -294,18 +300,25 @@ if (MAI->doesSupportDebugInformation()) { bool EmitCodeView = MMI->getModule()->getCodeViewFlag(); if (EmitCodeView && (TM.getTargetTriple().isKnownWindowsMSVCEnvironment() || - TM.getTargetTriple().isWindowsItaniumEnvironment())) { - Handlers.push_back(HandlerInfo(new CodeViewDebug(this), - DbgTimerName, DbgTimerDescription, - CodeViewLineTablesGroupName, - CodeViewLineTablesGroupDescription)); + TM.getTargetTriple().isWindowsItaniumEnvironment()) && + TM.Options.MCOptions.AsmSource != (int)llvm::AsmSourceOutput::Alone) { + Handlers.push_back(HandlerInfo( + new CodeViewDebug(this), DbgTimerName, DbgTimerDescription, + CodeViewLineTablesGroupName, CodeViewLineTablesGroupDescription)); } - if (!EmitCodeView || MMI->getModule()->getDwarfVersion()) { + if ((!EmitCodeView || MMI->getModule()->getDwarfVersion()) && + TM.Options.MCOptions.AsmSource != (int)llvm::AsmSourceOutput::Alone) { DD = new DwarfDebug(this, &M); DD->beginModule(); Handlers.push_back(HandlerInfo(DD, DbgTimerName, DbgTimerDescription, DWARFGroupName, DWARFGroupDescription)); } + if (TM.Options.MCOptions.AsmSource) { + Handlers.push_back(HandlerInfo( + new SourceInterleave(this), SourceInterleaveTimerName, + SourceInterleaveTimerDescription, SourceInterleaveGroupName, + SourceInterleaveGroupDescription)); + } } switch (MAI->getExceptionHandlingType()) { @@ -923,8 +936,6 @@ // Emit target-specific gunk before the function body. EmitFunctionBodyStart(); - bool ShouldPrintDebugScopes = MMI->hasDebugInfo(); - // Print out code for the function. bool HasAnyRealCode = false; int NumInstsInFunction = 0; @@ -940,13 +951,10 @@ ++NumInstsInFunction; } - if (ShouldPrintDebugScopes) { - for (const HandlerInfo &HI : Handlers) { - NamedRegionTimer T(HI.TimerName, HI.TimerDescription, - HI.TimerGroupName, HI.TimerGroupDescription, - TimePassesIsEnabled); - HI.Handler->beginInstruction(&MI); - } + for (const HandlerInfo &HI : Handlers) { + NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, + HI.TimerGroupDescription, TimePassesIsEnabled); + HI.Handler->beginInstruction(&MI); } if (isVerbose()) @@ -985,13 +993,10 @@ break; } - if (ShouldPrintDebugScopes) { - for (const HandlerInfo &HI : Handlers) { - NamedRegionTimer T(HI.TimerName, HI.TimerDescription, - HI.TimerGroupName, HI.TimerGroupDescription, - TimePassesIsEnabled); - HI.Handler->endInstruction(); - } + for (const HandlerInfo &HI : Handlers) { + NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, + HI.TimerGroupDescription, TimePassesIsEnabled); + HI.Handler->endInstruction(); } } Index: lib/CodeGen/AsmPrinter/CMakeLists.txt =================================================================== --- lib/CodeGen/AsmPrinter/CMakeLists.txt +++ lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -22,6 +22,7 @@ OcamlGCPrinter.cpp WinException.cpp CodeViewDebug.cpp + SourceInterleave.cpp DEPENDS intrinsics_gen Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1045,7 +1045,8 @@ // Process beginning of an instruction. void DwarfDebug::beginInstruction(const MachineInstr *MI) { DebugHandlerBase::beginInstruction(MI); - assert(CurMI); + if (!CurMI) + return; // Check if source location changes, but ignore DBG_VALUE and CFI locations. if (MI->isDebugValue() || MI->isCFIInstruction()) Index: lib/CodeGen/AsmPrinter/SourceInterleave.h =================================================================== --- /dev/null +++ lib/CodeGen/AsmPrinter/SourceInterleave.h @@ -0,0 +1,52 @@ +//===-- llvm/lib/CodeGen/AsmPrinter/SourceInterleave.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 interleaving source code with assembler. +// +//===----------------------------------------------------------------------===// + +#include "AsmPrinterHandler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/IR/DebugLoc.h" +#include + +namespace llvm { + +class SourceInterleave : public AsmPrinterHandler { + struct SourceCodeInfo { + enum { UnknownFunctionStart = -2 }; + int LastLineSeen = 0; + std::unique_ptr MemBuff; + std::vector LineIndex; + }; + + llvm::StringMap> BufferMap; + + static void indexBuffer(SourceCodeInfo *SI); + SourceCodeInfo *getOrCreateSourceCodeInfo(StringRef FullPath); + + static std::string getFullPathname(StringRef Dir, StringRef Fn); + static std::string getFullPathname(const DebugLoc &DL); + AsmPrinter *AP; + +public: + SourceInterleave(AsmPrinter *ap) : AP(ap) {} + + void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {} + + void endModule() override; + + void beginFunction(const MachineFunction *MF) override; + void endFunction(const MachineFunction *MF) override; + + void beginInstruction(const MachineInstr *MI) override; + void endInstruction() override; +}; +} Index: lib/CodeGen/AsmPrinter/SourceInterleave.cpp =================================================================== --- /dev/null +++ lib/CodeGen/AsmPrinter/SourceInterleave.cpp @@ -0,0 +1,136 @@ +//===-- llvm/lib/CodeGen/AsmPrinter/SourceInterleave.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 interleaving source code with assembler. +// +//===----------------------------------------------------------------------===// + +#include "SourceInterleave.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/LineIterator.h" +#include "llvm/Support/Path.h" + +namespace llvm { + +void SourceInterleave::indexBuffer(SourceCodeInfo *SI) { + SI->LineIndex.reserve(128); + SI->LineIndex.insert(SI->LineIndex.end(), + line_iterator(*SI->MemBuff, /* SkipBlanks */ false), + line_iterator()); +} + +SourceInterleave::SourceCodeInfo * +SourceInterleave::getOrCreateSourceCodeInfo(StringRef FullPathname) { + auto it = BufferMap.find(FullPathname); + if (it == BufferMap.end()) { + std::unique_ptr SI(new SourceCodeInfo); + auto ErrorMemBuffer = MemoryBuffer::getFile(FullPathname); + if (ErrorMemBuffer) { + SI->MemBuff = std::move(*ErrorMemBuffer); + indexBuffer(SI.get()); + } + it = BufferMap.insert({FullPathname, std::move(SI)}).first; + } + return it->second.get(); +} + +std::string SourceInterleave::getFullPathname(StringRef Dir, StringRef Fn) { + SmallString<128> FullPathname; + llvm::sys::path::append(FullPathname, Dir, Fn); + + return FullPathname.str(); +} + +std::string SourceInterleave::getFullPathname(const DebugLoc &DL) { + std::string Dir; + std::string Fn; + if (DIScope *S = DL->getScope()) { + Dir = S->getDirectory(); + Fn = S->getFilename(); + } + + return getFullPathname(Dir, Fn); +} + +void SourceInterleave::endModule() {} + +void SourceInterleave::beginFunction(const MachineFunction *MF) { + const Function *F = MF->getFunction(); + DISubprogram *DS = F->getSubprogram(); + if (!DS) + return; + + if (!DS->getFile()) + return; + + std::string FullPathname = getFullPathname(DS->getFile()->getDirectory(), + DS->getFile()->getFilename()); + SourceCodeInfo *SI = getOrCreateSourceCodeInfo(FullPathname); + assert(SI); + + // If we could not load the file, give up. + if (SI->MemBuff == nullptr) + return; + + // While unlikely, it might happen that we do not really know where this + // function starts. + if (DS->getLine() > 0) + SI->LastLineSeen = DS->getLine() - 1; +} + +void SourceInterleave::endFunction(const MachineFunction *MF) {} + +void SourceInterleave::beginInstruction(const MachineInstr *MI) { + const DebugLoc &DL = MI->getDebugLoc(); + if (!DL) + return; + + std::string FullPathname = getFullPathname(DL); + SourceCodeInfo *SI = getOrCreateSourceCodeInfo(FullPathname); + assert(SI); + + // If we could not load the file, give up. + if (SI->MemBuff == nullptr) + return; + + int CurrentLine = DL->getLine(); + if (CurrentLine == 0) + return; + + // If we have no idea where this function started, use the current line + // as a sensible starting point. + if (SI->LastLineSeen == SourceCodeInfo::UnknownFunctionStart) + SI->LastLineSeen = CurrentLine - 1; + // If we're not moving or going backwards, ignore this. + else if (CurrentLine - SI->LastLineSeen < 0) + return; + + for (int Line = SI->LastLineSeen + 1; Line <= CurrentLine; Line++) { + if (Line <= 0 || (unsigned)Line > SI->LineIndex.size()) + break; + + SmallString<128> Str; + raw_svector_ostream OS(Str); + + OS << ' ' << FullPathname << ':' << Line << ": "; + OS << SI->LineIndex[Line - 1].str(); + + AP->OutStreamer->emitRawComment(OS.str(), false); + } + + SI->LastLineSeen = CurrentLine; +} + +void SourceInterleave::endInstruction() {} +} Index: lib/MC/MCTargetOptions.cpp =================================================================== --- lib/MC/MCTargetOptions.cpp +++ lib/MC/MCTargetOptions.cpp @@ -17,7 +17,7 @@ MCFatalWarnings(false), MCNoWarn(false), MCNoDeprecatedWarn(false), MCSaveTempLabels(false), MCUseDwarfDirectory(false), MCIncrementalLinkerCompatible(false), MCPIECopyRelocations(false), - ShowMCEncoding(false), ShowMCInst(false), AsmVerbose(false), + ShowMCEncoding(false), ShowMCInst(false), AsmVerbose(false), AsmSource(0), PreserveAsmComments(true) {} StringRef MCTargetOptions::getABIName() const {