Re-implement DebugIR in a way that does not subclass AssemblyWriter:
authorDaniel Malea <daniel.malea@intel.com>
Thu, 23 May 2013 22:34:33 +0000 (22:34 +0000)
committerDaniel Malea <daniel.malea@intel.com>
Thu, 23 May 2013 22:34:33 +0000 (22:34 +0000)
- 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

include/llvm/IR/AsmWriter.h [deleted file]
include/llvm/Transforms/Instrumentation.h
lib/IR/AsmWriter.cpp
lib/IR/AsmWriter.h [new file with mode: 0644]
lib/Transforms/Instrumentation/DebugIR.cpp

diff --git a/include/llvm/IR/AsmWriter.h b/include/llvm/IR/AsmWriter.h
deleted file mode 100644 (file)
index aac7975..0000000
+++ /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<StructType*, unsigned> 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<SlotTracker> 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
index 142b40f1eaa99ba6003ec0d122896b1ed87b0f95..f2027ce82a3a70c2815b7def489f8e9ecb1206f3 100644 (file)
@@ -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
 
index c94620372a23ea51cd2b6555d12677dd7d8a9b70..4a5bf158f30affc0745bd0c9e96da9813d876c08 100644 (file)
@@ -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 <algorithm>
 #include <cctype>
 using namespace llvm;
diff --git a/lib/IR/AsmWriter.h b/lib/IR/AsmWriter.h
new file mode 100644 (file)
index 0000000..8f4a377
--- /dev/null
@@ -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<StructType*, unsigned> 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<SlotTracker> 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
index 62a9b8abd8fb7106b26a4aca629f0b36d199edc8..020804ff5f7871961dd25a2f2316bd2b4a88dadd 100644 (file)
@@ -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
 
 #include <string>
 
-#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<const Value *, unsigned int> Lines;
+  typedef ValueMap<const Value *, unsigned int>::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<const MDNode *, 4> NonDebugNodes;
+/// Removes debug intrisncs like llvm.dbg.declare and llvm.dbg.value.
+class DebugIntrinsicsRemover : public InstVisitor<DebugIntrinsicsRemover> {
+  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<DebugMetadataRemover> {
+public:
+  void visitInstruction(Instruction &I) {
+    if (I.getMetadata(LLVMContext::MD_dbg))
+      I.setMetadata(LLVMContext::MD_dbg, 0);
+  }
 
-    if (hideDebugMetadata)
-      removeDebugMetadata(const_cast<Instruction &>(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<LineNumberReplacer> {
+  /// 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<Instruction &>(I), NewLoc);
   }
 
-  virtual void printInstructionLine(const Instruction &I) {
-    if (hideDebugIntrinsics)
-      if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(&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<std::pair<unsigned, MDNode *>, 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);
 }