From: Daniel Malea Date: Thu, 23 May 2013 22:34:33 +0000 (+0000) Subject: Re-implement DebugIR in a way that does not subclass AssemblyWriter: X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=f8c243abba01d9d4fe53f7ab962139593f184400;p=oota-llvm.git Re-implement DebugIR in a way that does not subclass AssemblyWriter: - move AsmWriter.h from public headers into lib - marked all AssemblyWriter functions as non-virtual; no need to override them - DebugIR now "plugs into" AssemblyWriter with an AssemblyAnnotationWriter helper - exposed flags to control hiding of a) debug metadata b) debug intrinsic calls C/R: Paul Redmond git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182617 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/IR/AsmWriter.h b/include/llvm/IR/AsmWriter.h deleted file mode 100644 index aac7975ee68..00000000000 --- a/include/llvm/IR/AsmWriter.h +++ /dev/null @@ -1,118 +0,0 @@ -//===-- llvm/IR/AsmWriter.h - Printing LLVM IR as an assembly file - C++ --===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This files defines the interface for the AssemblyWriter class used to print -// LLVM IR and various helper classes that are used in printing. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_IR_ASSEMBLYWRITER_H -#define LLVM_IR_ASSEMBLYWRITER_H - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/IR/Attributes.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/TypeFinder.h" -#include "llvm/Support/FormattedStream.h" - -namespace llvm { - -class BasicBlock; -class Function; -class GlobalValue; -class Module; -class NamedMDNode; -class Value; -class SlotTracker; - -/// Create a new SlotTracker for a Module -SlotTracker *createSlotTracker(const Module *M); - -//===----------------------------------------------------------------------===// -// TypePrinting Class: Type printing machinery -//===----------------------------------------------------------------------===// - -class TypePrinting { - TypePrinting(const TypePrinting &) LLVM_DELETED_FUNCTION; - void operator=(const TypePrinting&) LLVM_DELETED_FUNCTION; -public: - - /// NamedTypes - The named types that are used by the current module. - TypeFinder NamedTypes; - - /// NumberedTypes - The numbered types, along with their value. - DenseMap NumberedTypes; - - - TypePrinting() {} - ~TypePrinting() {} - - void incorporateTypes(const Module &M); - - void print(Type *Ty, raw_ostream &OS); - - void printStructBody(StructType *Ty, raw_ostream &OS); -}; - -class AssemblyWriter { -protected: - formatted_raw_ostream &Out; - const Module *TheModule; - -private: - OwningPtr ModuleSlotTracker; - SlotTracker &Machine; - TypePrinting TypePrinter; - AssemblyAnnotationWriter *AnnotationWriter; - -public: - /// Construct an AssemblyWriter with an external SlotTracker - AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, - const Module *M, AssemblyAnnotationWriter *AAW); - - /// Construct an AssemblyWriter with an internally allocated SlotTracker - AssemblyWriter(formatted_raw_ostream &o, const Module *M, - AssemblyAnnotationWriter *AAW); - - virtual ~AssemblyWriter(); - - virtual void printMDNodeBody(const MDNode *MD); - virtual void printNamedMDNode(const NamedMDNode *NMD); - - virtual void printModule(const Module *M); - - virtual void writeOperand(const Value *Op, bool PrintType); - virtual void writeParamOperand(const Value *Operand, AttributeSet Attrs,unsigned Idx); - virtual void writeAtomic(AtomicOrdering Ordering, SynchronizationScope SynchScope); - - virtual void writeAllMDNodes(); - virtual void writeMDNode(unsigned Slot, const MDNode *Node); - virtual void writeAllAttributeGroups(); - - virtual void printTypeIdentities(); - virtual void printGlobal(const GlobalVariable *GV); - virtual void printAlias(const GlobalAlias *GV); - virtual void printFunction(const Function *F); - virtual void printArgument(const Argument *FA, AttributeSet Attrs, unsigned Idx); - virtual void printBasicBlock(const BasicBlock *BB); - virtual void printInstructionLine(const Instruction &I); - virtual void printInstruction(const Instruction &I); - -private: - void init(); - - // printInfoComment - Print a little comment after the instruction indicating - // which slot it occupies. - void printInfoComment(const Value &V); -}; - -} // namespace llvm - -#endif //LLVM_IR_ASMWRITER_H diff --git a/include/llvm/Transforms/Instrumentation.h b/include/llvm/Transforms/Instrumentation.h index 142b40f1eaa..f2027ce82a3 100644 --- a/include/llvm/Transforms/Instrumentation.h +++ b/include/llvm/Transforms/Instrumentation.h @@ -80,7 +80,9 @@ FunctionPass *createBoundsCheckingPass(); /// createDebugIRPass - Create and return a pass that modifies a module's /// debug metadata to point back to IR instead of the original source file -ModulePass *createDebugIRPass(StringRef FilenamePostfix); +ModulePass *createDebugIRPass(StringRef FilenamePostfix, + bool hideDebugIntrinsics = true, + bool hideDebugMetadata = true); } // End llvm namespace diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp index c94620372a2..4a5bf158f30 100644 --- a/lib/IR/AsmWriter.cpp +++ b/lib/IR/AsmWriter.cpp @@ -14,6 +14,8 @@ // //===----------------------------------------------------------------------===// +#include "AsmWriter.h" + #include "llvm/Assembly/Writer.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" @@ -22,7 +24,6 @@ #include "llvm/Assembly/AssemblyAnnotationWriter.h" #include "llvm/Assembly/PrintModulePass.h" #include "llvm/DebugInfo.h" -#include "llvm/IR/AsmWriter.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" @@ -39,6 +40,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/MathExtras.h" + #include #include using namespace llvm; diff --git a/lib/IR/AsmWriter.h b/lib/IR/AsmWriter.h new file mode 100644 index 00000000000..8f4a37777eb --- /dev/null +++ b/lib/IR/AsmWriter.h @@ -0,0 +1,118 @@ +//===-- llvm/IR/AsmWriter.h - Printing LLVM IR as an assembly file - C++ --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This files defines the interface for the AssemblyWriter class used to print +// LLVM IR and various helper classes that are used in printing. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_IR_ASSEMBLYWRITER_H +#define LLVM_IR_ASSEMBLYWRITER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/TypeFinder.h" +#include "llvm/Support/FormattedStream.h" + +namespace llvm { + +class BasicBlock; +class Function; +class GlobalValue; +class Module; +class NamedMDNode; +class Value; +class SlotTracker; + +/// Create a new SlotTracker for a Module +SlotTracker *createSlotTracker(const Module *M); + +//===----------------------------------------------------------------------===// +// TypePrinting Class: Type printing machinery +//===----------------------------------------------------------------------===// + +class TypePrinting { + TypePrinting(const TypePrinting &) LLVM_DELETED_FUNCTION; + void operator=(const TypePrinting&) LLVM_DELETED_FUNCTION; +public: + + /// NamedTypes - The named types that are used by the current module. + TypeFinder NamedTypes; + + /// NumberedTypes - The numbered types, along with their value. + DenseMap NumberedTypes; + + + TypePrinting() {} + ~TypePrinting() {} + + void incorporateTypes(const Module &M); + + void print(Type *Ty, raw_ostream &OS); + + void printStructBody(StructType *Ty, raw_ostream &OS); +}; + +class AssemblyWriter { +protected: + formatted_raw_ostream &Out; + const Module *TheModule; + +private: + OwningPtr ModuleSlotTracker; + SlotTracker &Machine; + TypePrinting TypePrinter; + AssemblyAnnotationWriter *AnnotationWriter; + +public: + /// Construct an AssemblyWriter with an external SlotTracker + AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, + const Module *M, AssemblyAnnotationWriter *AAW); + + /// Construct an AssemblyWriter with an internally allocated SlotTracker + AssemblyWriter(formatted_raw_ostream &o, const Module *M, + AssemblyAnnotationWriter *AAW); + + virtual ~AssemblyWriter(); + + void printMDNodeBody(const MDNode *MD); + void printNamedMDNode(const NamedMDNode *NMD); + + void printModule(const Module *M); + + void writeOperand(const Value *Op, bool PrintType); + void writeParamOperand(const Value *Operand, AttributeSet Attrs,unsigned Idx); + void writeAtomic(AtomicOrdering Ordering, SynchronizationScope SynchScope); + + void writeAllMDNodes(); + void writeMDNode(unsigned Slot, const MDNode *Node); + void writeAllAttributeGroups(); + + void printTypeIdentities(); + void printGlobal(const GlobalVariable *GV); + void printAlias(const GlobalAlias *GV); + void printFunction(const Function *F); + void printArgument(const Argument *FA, AttributeSet Attrs, unsigned Idx); + void printBasicBlock(const BasicBlock *BB); + void printInstructionLine(const Instruction &I); + void printInstruction(const Instruction &I); + +private: + void init(); + + // printInfoComment - Print a little comment after the instruction indicating + // which slot it occupies. + void printInfoComment(const Value &V); +}; + +} // namespace llvm + +#endif //LLVM_IR_ASMWRITER_H diff --git a/lib/Transforms/Instrumentation/DebugIR.cpp b/lib/Transforms/Instrumentation/DebugIR.cpp index 62a9b8abd8f..020804ff5f7 100644 --- a/lib/Transforms/Instrumentation/DebugIR.cpp +++ b/lib/Transforms/Instrumentation/DebugIR.cpp @@ -13,7 +13,7 @@ // The location where the IR file is emitted is the same as the directory // operand of the !llvm.dbg.cu metadata node present in the input module. The // file name is constructed from the original file name by stripping the -// extension and replacing it with "-debug.ll" or the Postfix string specified +// extension and replacing it with "-debug-ll" or the Postfix string specified // at construction. // // FIXME: instead of replacing debug metadata, additional metadata should be @@ -28,111 +28,134 @@ #include -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/ValueMap.h" +#include "llvm/Assembly/AssemblyAnnotationWriter.h" #include "llvm/DebugInfo.h" #include "llvm/DIBuilder.h" -#include "llvm/IR/AsmWriter.h" +#include "llvm/InstVisitor.h" #include "llvm/IR/Instruction.h" -#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/FormattedStream.h" using namespace llvm; namespace { -/// Returns true if Node's name contains the string "llvm.dbg" -bool isDebugNamedMetadata(const NamedMDNode *Node) { - return Node->getName().str().find("llvm.dbg") != std::string::npos; -} +/// Builds a map of Value* to line numbers on which the Value appears in a +/// textual representation of the IR by plugging into the AssemblyWriter by +/// masquerading as an AssemblyAnnotationWriter. +class ValueToLineMap : public AssemblyAnnotationWriter { + ValueMap Lines; + typedef ValueMap::const_iterator LineIter; -/// Returns true if Inst is a call to llvm.dbg.value or llvm.dbg.declare -bool isDebugIntrinsic(const IntrinsicInst *Inst) { - Intrinsic::ID id = Inst->getIntrinsicID(); - return id == Intrinsic::dbg_value || id == Intrinsic::dbg_declare; -} +public: -/// An AssemblyWriter which generates a succinct representation of the module -/// (without debug intrinsics or metadata) suitable for debugging. As IR -/// instructions are printed, !dbg metadata nodes are added (or updated) -/// to point to the corresponding line in the generated IR file instead -/// of the original source file. The input module must have been constructed -/// with debug metadata (i.e. clang -g). -class IRDebugInfoHelper : public llvm::AssemblyWriter { - /// Directory of debug metadata - const DebugInfoFinder &Finder; + /// Prints Module to a null buffer in order to build the map of Value pointers + /// to line numbers. + ValueToLineMap(Module *M) { + raw_null_ostream ThrowAway; + M->print(ThrowAway, this); + } - /// Flags to control the verbosity of the generated IR file - bool hideDebugIntrinsics; - bool hideDebugMetadata; + // This function is called after an Instruction, GlobalValue, or GlobalAlias + // is printed. + void printInfoComment(const Value &V, formatted_raw_ostream &Out) { + Out.flush(); + Lines.insert(std::make_pair(&V, Out.getLine() + 1)); + } + + /// If V appears on a line in the textual IR representation, sets Line to the + /// line number and returns true, otherwise returns false. + bool getLine(const Value *V, unsigned int &Line) const { + LineIter i = Lines.find(V); + if (i != Lines.end()) { + Line = i->second; + return true; + } + return false; + } +}; - /// Set to track metadata nodes to be printed (used only when - /// printDebugMetadata == false) - SmallSet NonDebugNodes; +/// Removes debug intrisncs like llvm.dbg.declare and llvm.dbg.value. +class DebugIntrinsicsRemover : public InstVisitor { + void remove(Instruction &I) { I.eraseFromParent(); } public: - IRDebugInfoHelper( - formatted_raw_ostream &o, const Module *M, - AssemblyAnnotationWriter *AAW, const DebugInfoFinder &Finder, - bool hideDebugIntrinsics = true, bool hideDebugMetadata = true) - : AssemblyWriter(o, M, AAW), Finder(Finder), - hideDebugIntrinsics(hideDebugIntrinsics), - hideDebugMetadata(hideDebugMetadata) {} + void visitDbgDeclareInst(DbgDeclareInst &I) { remove(I); } + void visitDbgValueInst(DbgValueInst &I) { remove(I); } + void visitDbgInfoIntrinsic(DbgInfoIntrinsic &I) { remove(I); } +}; -private: - virtual void printInstruction(const Instruction &I) { - DebugLoc Loc(I.getDebugLoc()); +/// Removes debug metadata (!dbg) nodes from all instructions as well as +/// metadata named "llvm.dbg.cu" in the Module. +class DebugMetadataRemover : public InstVisitor { +public: + void visitInstruction(Instruction &I) { + if (I.getMetadata(LLVMContext::MD_dbg)) + I.setMetadata(LLVMContext::MD_dbg, 0); + } - if (hideDebugMetadata) - removeDebugMetadata(const_cast(I)); + void run(Module *M) { + // Remove debug metadata attached to instructions + visit(M); - AssemblyWriter::printInstruction(I); - Out.flush(); - // Adjust line number by 1 because we have not yet printed the \n - unsigned Line = Out.getLine() + 1; + // Remove CU named metadata (and all children nodes) + NamedMDNode *Node = M->getNamedMetadata("llvm.dbg.cu"); + M->eraseNamedMetadata(Node); + } +}; + +/// Replaces line number metadata attached to Instruction nodes with new line +/// numbers provided by the ValueToLineMap. +class LineNumberReplacer : public InstVisitor { + /// Table of line numbers + const ValueToLineMap &LineTable; + + /// Table of cloned values + const ValueToValueMapTy &VMap; + + /// Directory of debug metadata + const DebugInfoFinder &Finder; + +public: + LineNumberReplacer(const ValueToLineMap &VLM, const DebugInfoFinder &Finder, + const ValueToValueMapTy &VMap) + : LineTable(VLM), VMap(VMap), Finder(Finder) {} + + void visitInstruction(Instruction &I) { + DebugLoc Loc(I.getDebugLoc()); + + unsigned Col = 0; // FIXME: support columns + unsigned Line; + if (!LineTable.getLine(VMap.lookup(&I), Line)) + // Instruction has no line, it may have been removed (in the module that + // will be passed to the debugger) so there is nothing to do here. + return; DebugLoc NewLoc; if (!Loc.isUnknown()) // I had a previous debug location: re-use the DebugLoc - NewLoc = DebugLoc::get(Line, /* FIXME: support columns */ 0, - Loc.getScope(I.getContext()), + NewLoc = DebugLoc::get(Line, Col, Loc.getScope(I.getContext()), Loc.getInlinedAt(I.getContext())); else if (MDNode *scope = findFunctionMD(I.getParent()->getParent())) // I had no previous debug location, but M has some debug information - NewLoc = DebugLoc::get(Line, 0, scope, /*FIXME: inlined instructions*/ 0); + NewLoc = + DebugLoc::get(Line, Col, scope, /*FIXME: inlined instructions*/ 0); else // Neither I nor M has any debug information -- nothing to do here. // FIXME: support debugging of undecorated IR (generated by clang without // the -g option) return; - if (hideDebugMetadata) - saveNonDebugMetadata(I); - addDebugLocation(const_cast(I), NewLoc); } - virtual void printInstructionLine(const Instruction &I) { - if (hideDebugIntrinsics) - if (const IntrinsicInst *II = dyn_cast(&I)) - if (isDebugIntrinsic(II)) - return; - AssemblyWriter::printInstructionLine(I); - } - - virtual void writeMDNode(unsigned Slot, const MDNode *Node) { - if (hideDebugMetadata == false || isDebugMetadata(Node) == false) - AssemblyWriter::writeMDNode(Slot, Node); - } - - virtual void printNamedMDNode(const NamedMDNode *NMD) { - if (hideDebugMetadata == false || isDebugNamedMetadata(NMD) == false) - AssemblyWriter::printNamedMDNode(NMD); - } +private: /// Returns the MDNode that corresponds with F MDNode *findFunctionMD(const Function *F) { @@ -147,27 +170,6 @@ private: return 0; } - /// Saves all non-debug metadata attached to I - void saveNonDebugMetadata(const Instruction &I) { - typedef SmallVector, 4> MDNodeVector; - MDNodeVector Others; - I.getAllMetadataOtherThanDebugLoc(Others); - for (MDNodeVector::iterator i = Others.begin(), e = Others.end(); i != e; - ++i) - NonDebugNodes.insert(i->second); - } - - /// Returns true if Node was not saved as non-debug metadata with - /// saveNonDebugMetadata(), false otherwise. - bool isDebugMetadata(const MDNode *Node) { - return NonDebugNodes.count(Node) == 0; - } - - void removeDebugMetadata(Instruction &I) { - if (I.getMetadata(LLVMContext::MD_dbg)) - I.setMetadata(LLVMContext::MD_dbg, 0); - } - void addDebugLocation(Instruction &I, DebugLoc Loc) { MDNode *MD = Loc.getAsMDNode(I.getContext()); I.setMetadata(LLVMContext::MD_dbg, MD); @@ -177,20 +179,37 @@ private: class DebugIR : public ModulePass { std::string Postfix; std::string Filename; - DebugInfoFinder Finder; + + /// Flags to control the verbosity of the generated IR file + bool hideDebugIntrinsics; + bool hideDebugMetadata; public: static char ID; - DebugIR() : ModulePass(ID), Postfix("-debug.ll") {} + const char *getPassName() const { return "DebugIR"; } + + // FIXME: figure out if we are compiling something that already exists on disk + // in text IR form, in which case we can omit outputting a new IR file, or if + // we're building something from memory where we actually need to emit a new + // IR file for the debugger. + + /// Output a file with the same base name as the original, but with the + /// postfix "-debug-ll" appended. + DebugIR() + : ModulePass(ID), Postfix("-debug-ll"), hideDebugIntrinsics(true), + hideDebugMetadata(true) {} /// Customize the postfix string used to replace the extension of the /// original filename that appears in the !llvm.dbg.cu metadata node. - DebugIR(StringRef postfix) : ModulePass(ID), Postfix(postfix) {} + DebugIR(StringRef postfix, bool hideDebugIntrinsics, bool hideDebugMetadata) + : ModulePass(ID), Postfix(postfix), + hideDebugIntrinsics(hideDebugIntrinsics), + hideDebugMetadata(hideDebugMetadata) {} private: // Modify the filename embedded in the Compilation-Unit debug information of M - bool replaceFilename(Module &M) { + bool replaceFilename(Module &M, const DebugInfoFinder &Finder) { bool changed = false; // Sanity check -- if llvm.dbg.cu node exists, the DebugInfoFinder @@ -217,22 +236,64 @@ private: return changed; } - void writeAndUpdateDebugIRFile(Module *M) { + /// Replace existing line number metadata with line numbers that correspond + /// with the IR file that is seen by the debugger. + void addLineNumberMetadata(Module *M, const ValueToLineMap &VLM, + const ValueToValueMapTy &VMap, + const DebugInfoFinder &Finder) { + LineNumberReplacer Replacer(VLM, Finder, VMap); + Replacer.visit(M); + } + + void writeDebugBitcode(Module *M) { std::string error; tool_output_file OutFile(Filename.c_str(), error); OutFile.keep(); formatted_raw_ostream OS; - OS.setStream(OutFile.os(), false); + OS.setStream(OutFile.os()); + M->print(OS, 0); + } + + void removeDebugIntrinsics(Module *M) { + DebugIntrinsicsRemover Remover; + Remover.visit(M); + } + + void removeDebugMetadata(Module *M) { + DebugMetadataRemover Remover; + Remover.run(M); + } + + void updateAndWriteDebugIRFile(Module *M, const DebugInfoFinder &Finder) { + // The module we output in text form for a debugger to open is stripped of + // 'extras' like debug intrinsics that end up in DWARF anyways and just + // clutter the debug experience. + + ValueToValueMapTy VMap; + Module *DebuggerM = CloneModule(M, VMap); + + if (hideDebugIntrinsics) + removeDebugIntrinsics(DebuggerM); - IRDebugInfoHelper W(OS, M, 0, Finder); - W.printModule(M); + if (hideDebugMetadata) + removeDebugMetadata(DebuggerM); + + // FIXME: remove all debug metadata from M once we support generating DWARF + // subprogram attributes. + + ValueToLineMap LineTable(DebuggerM); + addLineNumberMetadata(M, LineTable, VMap, Finder); + writeDebugBitcode(DebuggerM); } bool runOnModule(Module &M) { + // Stores existing debug info needed when creating new line number entries. + DebugInfoFinder Finder; Finder.processModule(M); - bool changed = replaceFilename(M); + + bool changed = replaceFilename(M, Finder); if (changed) - writeAndUpdateDebugIRFile(&M); + updateAndWriteDebugIRFile(&M, Finder); return changed; } }; @@ -241,6 +302,9 @@ private: char DebugIR::ID = 0; INITIALIZE_PASS(DebugIR, "debug-ir", "Enable debugging IR", false, false) - ModulePass *llvm::createDebugIRPass(StringRef FilenamePostfix) { - return new DebugIR(FilenamePostfix); + +ModulePass *llvm::createDebugIRPass(StringRef FilenamePostfix, + bool hideDebugIntrinsics, + bool hideDebugMetadata) { + return new DebugIR(FilenamePostfix, hideDebugIntrinsics, hideDebugMetadata); }