Pass to emit DWARF path discriminators.
authorDiego Novillo <dnovillo@google.com>
Mon, 3 Mar 2014 20:06:11 +0000 (20:06 +0000)
committerDiego Novillo <dnovillo@google.com>
Mon, 3 Mar 2014 20:06:11 +0000 (20:06 +0000)
DWARF discriminators are used to distinguish multiple control flow paths
on the same source location. When this happens, instructions across
basic block boundaries will share the same debug location.

This pass detects this situation and creates a new lexical scope to one
of the two instructions. This lexical scope is a child scope of the
original and contains a new discriminator value. This discriminator is
then picked up from MCObjectStreamer::EmitDwarfLocDirective to be
written on the object file.

This fixes http://llvm.org/bugs/show_bug.cgi?id=18270.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202752 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/DebugInfo.h
include/llvm/InitializePasses.h
include/llvm/Transforms/Scalar.h
lib/IR/DebugInfo.cpp
lib/IR/LLVMContextImpl.h
lib/Transforms/Utils/AddDiscriminators.cpp [new file with mode: 0644]
lib/Transforms/Utils/CMakeLists.txt
lib/Transforms/Utils/Utils.cpp
test/Transforms/AddDiscriminators/basic.ll [new file with mode: 0644]
test/Transforms/AddDiscriminators/first-only.ll [new file with mode: 0644]
test/Transforms/AddDiscriminators/multiple.ll [new file with mode: 0644]

index e6ec6592dce69209d70868e3322b00de38499f27..d5d235c0a76c5de54e1e4adb3f4238d5ad32ec42 100644 (file)
@@ -701,6 +701,27 @@ public:
   StringRef getFilename() const { return getScope().getFilename(); }
   StringRef getDirectory() const { return getScope().getDirectory(); }
   bool Verify() const;
+  bool atSameLineAs(const DILocation &Other) const {
+    return (getLineNumber() == Other.getLineNumber() &&
+            getFilename() == Other.getFilename());
+  }
+  /// getDiscriminator - DWARF discriminators are used to distinguish
+  /// identical file locations for instructions that are on different
+  /// basic blocks. If two instructions are inside the same lexical block
+  /// and are in different basic blocks, we create a new lexical block
+  /// with identical location as the original but with a different
+  /// discriminator value (lib/Transforms/Util/AddDiscriminators.cpp
+  /// for details).
+  unsigned getDiscriminator() const {
+    // Since discriminators are associated with lexical blocks, make
+    // sure this location is a lexical block before retrieving its
+    // value.
+    return getScope().isLexicalBlock()
+               ? getFieldAs<DILexicalBlock>(2).getDiscriminator()
+               : 0;
+  }
+  unsigned computeNewDiscriminator(LLVMContext &Ctx);
+  DILocation copyWithNewScope(LLVMContext &Ctx, DILexicalBlock NewScope);
 };
 
 class DIObjCProperty : public DIDescriptor {
index c244257a6e40cdabf84b2696b8c26a336b77941c..9b9f2345ad28fd2d052496d8f7476c580227c315 100644 (file)
@@ -63,6 +63,7 @@ void initializeCodeGen(PassRegistry&);
 void initializeTarget(PassRegistry&);
 
 void initializeAAEvalPass(PassRegistry&);
+void initializeAddDiscriminatorsPass(PassRegistry&);
 void initializeADCEPass(PassRegistry&);
 void initializeAliasAnalysisAnalysisGroup(PassRegistry&);
 void initializeAliasAnalysisCounterPass(PassRegistry&);
index cacd4cb51b6738916b35404a850aa87764e29802..c2c65a5f9b32efbf1ee44e948d052207ae8d19eb 100644 (file)
@@ -376,6 +376,11 @@ FunctionPass *createSampleProfileLoaderPass(StringRef Name);
 //
 FunctionPass *createScalarizerPass();
 
+//===----------------------------------------------------------------------===//
+//
+// AddDiscriminators - Add DWARF path discriminators to the IR.
+FunctionPass *createAddDiscriminatorsPass();
+
 } // End llvm namespace
 
 #endif
index 749e0b5057a76e05414bdfe28d9ad31108813719..f5884a4a90adc21676d999d89eae9dcfac987d53 100644 (file)
@@ -22,6 +22,7 @@
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Intrinsics.h"
+#include "LLVMContextImpl.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Dwarf.h"
@@ -818,6 +819,29 @@ DIArray DICompileUnit::getImportedEntities() const {
   return DIArray(getNodeField(DbgNode, 11));
 }
 
+/// copyWithNewScope - Return a copy of this location, replacing the
+/// current scope with the given one.
+DILocation DILocation::copyWithNewScope(LLVMContext &Ctx,
+                                        DILexicalBlock NewScope) {
+  SmallVector<Value *, 10> Elts;
+  assert(Verify());
+  for (unsigned I = 0; I < DbgNode->getNumOperands(); ++I) {
+    if (I != 2)
+      Elts.push_back(DbgNode->getOperand(I));
+    else
+      Elts.push_back(NewScope);
+  }
+  MDNode *NewDIL = MDNode::get(Ctx, Elts);
+  return DILocation(NewDIL);
+}
+
+/// computeNewDiscriminator - Generate a new discriminator value for this
+/// file and line location.
+unsigned DILocation::computeNewDiscriminator(LLVMContext &Ctx) {
+  std::pair<const char *, unsigned> Key(getFilename().data(), getLineNumber());
+  return ++Ctx.pImpl->DiscriminatorTable[Key];
+}
+
 /// fixupSubprogramName - Replace contains special characters used
 /// in a typical Objective-C names with '.' in a given string.
 static void fixupSubprogramName(DISubprogram Fn, SmallVectorImpl<char> &Out) {
index 0433827246324dc42d1835ad26fd545735df16fc..8b94ab1c779844ca6be6fee1ba7e2657b5109fb6 100644 (file)
@@ -352,7 +352,12 @@ public:
   /// for an index.  The ValueHandle ensures that ScopeINlinedAtIdx stays up
   /// to date.
   std::vector<std::pair<DebugRecVH, DebugRecVH> > ScopeInlinedAtRecords;
-  
+
+  /// DiscriminatorTable - This table maps file:line locations to an
+  /// integer representing the next DWARF path discriminator to assign to
+  /// instructions in different blocks at the same location.
+  DenseMap<std::pair<const char *, unsigned>, unsigned> DiscriminatorTable;
+
   /// IntrinsicIDCache - Cache of intrinsic name (string) to numeric ID mappings
   /// requested in this context
   typedef DenseMap<const Function*, unsigned> IntrinsicIDCacheTy;
diff --git a/lib/Transforms/Utils/AddDiscriminators.cpp b/lib/Transforms/Utils/AddDiscriminators.cpp
new file mode 100644 (file)
index 0000000..50ed5a1
--- /dev/null
@@ -0,0 +1,217 @@
+//===- AddDiscriminators.cpp - Insert DWARF path discriminators -----------===//
+//
+//                      The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file adds DWARF discriminators to the IR. Path discriminators are
+// used to decide what CFG path was taken inside sub-graphs whose instructions
+// share the same line and column number information.
+//
+// The main user of this is the sample profiler. Instruction samples are
+// mapped to line number information. Since a single line may be spread
+// out over several basic blocks, discriminators add more precise location
+// for the samples.
+//
+// For example,
+//
+//   1  #define ASSERT(P)
+//   2      if (!(P))
+//   3        abort()
+//   ...
+//   100   while (true) {
+//   101     ASSERT (sum < 0);
+//   102     ...
+//   130   }
+//
+// when converted to IR, this snippet looks something like:
+//
+// while.body:                                       ; preds = %entry, %if.end
+//   %0 = load i32* %sum, align 4, !dbg !15
+//   %cmp = icmp slt i32 %0, 0, !dbg !15
+//   br i1 %cmp, label %if.end, label %if.then, !dbg !15
+//
+// if.then:                                          ; preds = %while.body
+//   call void @abort(), !dbg !15
+//   br label %if.end, !dbg !15
+//
+// Notice that all the instructions in blocks 'while.body' and 'if.then'
+// have exactly the same debug information. When this program is sampled
+// at runtime, the profiler will assume that all these instructions are
+// equally frequent. This, in turn, will consider the edge while.body->if.then
+// to be frequently taken (which is incorrect).
+//
+// By adding a discriminator value to the instructions in block 'if.then',
+// we can distinguish instructions at line 101 with discriminator 0 from
+// the instructions at line 101 with discriminator 1.
+//
+// For more details about DWARF discriminators, please visit
+// http://wiki.dwarfstd.org/index.php?title=Path_Discriminators
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "add-discriminators"
+
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/DebugInfo.h"
+#include "llvm/DIBuilder.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+namespace {
+  struct AddDiscriminators : public FunctionPass {
+    static char ID; // Pass identification, replacement for typeid
+    AddDiscriminators() : FunctionPass(ID) {
+      initializeAddDiscriminatorsPass(*PassRegistry::getPassRegistry());
+    }
+
+    virtual bool runOnFunction(Function &F);
+  };
+}
+
+char AddDiscriminators::ID = 0;
+INITIALIZE_PASS_BEGIN(AddDiscriminators, "add-discriminators",
+                      "Add DWARF path discriminators", false, false)
+INITIALIZE_PASS_END(AddDiscriminators, "add-discriminators",
+                    "Add DWARF path discriminators", false, false)
+
+// Command line option to disable discriminator generation even in the
+// presence of debug information. This is only needed when debugging
+// debug info generation issues.
+static cl::opt<bool>
+NoDiscriminators("no-discriminators", cl::init(false),
+                 cl::desc("Disable generation of discriminator information."));
+
+FunctionPass *llvm::createAddDiscriminatorsPass() {
+  return new AddDiscriminators();
+}
+
+static bool hasDebugInfo(const Function &F) {
+  NamedMDNode *CUNodes = F.getParent()->getNamedMetadata("llvm.dbg.cu");
+  return CUNodes != 0;
+}
+
+/// \brief Assign DWARF discriminators.
+///
+/// To assign discriminators, we examine the boundaries of every
+/// basic block and its successors. Suppose there is a basic block B1
+/// with successor B2. The last instruction I1 in B1 and the first
+/// instruction I2 in B2 are located at the same file and line number.
+/// This situation is illustrated in the following code snippet:
+///
+///       if (i < 10) x = i;
+///
+///     entry:
+///       br i1 %cmp, label %if.then, label %if.end, !dbg !10
+///     if.then:
+///       %1 = load i32* %i.addr, align 4, !dbg !10
+///       store i32 %1, i32* %x, align 4, !dbg !10
+///       br label %if.end, !dbg !10
+///     if.end:
+///       ret void, !dbg !12
+///
+/// Notice how the branch instruction in block 'entry' and all the
+/// instructions in block 'if.then' have the exact same debug location
+/// information (!dbg !10).
+///
+/// To distinguish instructions in block 'entry' from instructions in
+/// block 'if.then', we generate a new lexical block for all the
+/// instruction in block 'if.then' that share the same file and line
+/// location with the last instruction of block 'entry'.
+///
+/// This new lexical block will have the same location information as
+/// the previous one, but with a new DWARF discriminator value.
+///
+/// One of the main uses of this discriminator value is in runtime
+/// sample profilers. It allows the profiler to distinguish instructions
+/// at location !dbg !10 that execute on different basic blocks. This is
+/// important because while the predicate 'if (x < 10)' may have been
+/// executed millions of times, the assignment 'x = i' may have only
+/// executed a handful of times (meaning that the entry->if.then edge is
+/// seldom taken).
+///
+/// If we did not have discriminator information, the profiler would
+/// assign the same weight to both blocks 'entry' and 'if.then', which
+/// in turn will make it conclude that the entry->if.then edge is very
+/// hot.
+///
+/// To decide where to create new discriminator values, this function
+/// traverses the CFG and examines instruction at basic block boundaries.
+/// If the last instruction I1 of a block B1 is at the same file and line
+/// location as instruction I2 of successor B2, then it creates a new
+/// lexical block for I2 and all the instruction in B2 that share the same
+/// file and line location as I2. This new lexical block will have a
+/// different discriminator number than I1.
+bool AddDiscriminators::runOnFunction(Function &F) {
+  // No need to do anything if there is no debug info for this function.
+  // If the function has debug information, but the user has disabled
+  // discriminators, do nothing.
+  if (!hasDebugInfo(F) || NoDiscriminators) return false;
+
+  bool Changed = false;
+  Module *M = F.getParent();
+  LLVMContext &Ctx = M->getContext();
+  DIBuilder Builder(*M);
+
+  // Traverse all the blocks looking for instructions in different
+  // blocks that are at the same file:line location.
+  for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) {
+    BasicBlock *B = I;
+    TerminatorInst *Last = B->getTerminator();
+    DebugLoc LastLoc = Last->getDebugLoc();
+    if (LastLoc.isUnknown()) continue;
+    DILocation LastDIL(LastLoc.getAsMDNode(Ctx));
+
+    for (unsigned I = 0; I < Last->getNumSuccessors(); ++I) {
+      BasicBlock *Succ = Last->getSuccessor(I);
+      Instruction *First = Succ->getFirstNonPHIOrDbgOrLifetime();
+      DebugLoc FirstLoc = First->getDebugLoc();
+      if (FirstLoc.isUnknown()) continue;
+      DILocation FirstDIL(FirstLoc.getAsMDNode(Ctx));
+
+      // If the first instruction (First) of Succ is at the same file
+      // location as B's last instruction (Last), add a new
+      // discriminator for First's location and all the instructions
+      // in Succ that share the same location with First.
+      if (FirstDIL.atSameLineAs(LastDIL)) {
+        // Create a new lexical scope and compute a new discriminator
+        // number for it.
+        StringRef Filename = FirstDIL.getFilename();
+        unsigned LineNumber = FirstDIL.getLineNumber();
+        unsigned ColumnNumber = FirstDIL.getColumnNumber();
+        DIScope Scope = FirstDIL.getScope();
+        DIFile File = Builder.createFile(Filename, Scope.getDirectory());
+        unsigned Discriminator = FirstDIL.computeNewDiscriminator(Ctx);
+        DILexicalBlock NewScope = Builder.createLexicalBlock(
+            Scope, File, LineNumber, ColumnNumber, Discriminator);
+        DILocation NewDIL = FirstDIL.copyWithNewScope(Ctx, NewScope);
+        DebugLoc newDebugLoc = DebugLoc::getFromDILocation(NewDIL);
+
+        // Attach this new debug location to First and every
+        // instruction following First that shares the same location.
+        for (BasicBlock::iterator I1(*First), E1 = Succ->end(); I1 != E1;
+             ++I1) {
+          if (I1->getDebugLoc() != FirstLoc) break;
+          I1->setDebugLoc(newDebugLoc);
+          DEBUG(dbgs() << NewDIL.getFilename() << ":" << NewDIL.getLineNumber()
+                       << ":" << NewDIL.getColumnNumber() << ":"
+                       << NewDIL.getDiscriminator() << *I1 << "\n");
+        }
+        DEBUG(dbgs() << "\n");
+        Changed = true;
+      }
+    }
+  }
+  return Changed;
+}
index 2858540c8c350dd588bde3d4e447897898b68de7..dac2090dccc03bbd846a3e37a0bd2ff6c4d0772d 100644 (file)
@@ -1,4 +1,5 @@
 add_llvm_library(LLVMTransformUtils
+  AddDiscriminators.cpp
   ASanStackFrameLayout.cpp
   BasicBlockUtils.cpp
   BreakCriticalEdges.cpp
index 3fb5463404228bc3ce6a8e075c55f28cd3925f63..ed4f45c6a615d52c403e1a36ace2f0f7e765936a 100644 (file)
@@ -21,6 +21,7 @@ using namespace llvm;
 /// initializeTransformUtils - Initialize all passes in the TransformUtils
 /// library.
 void llvm::initializeTransformUtils(PassRegistry &Registry) {
+  initializeAddDiscriminatorsPass(Registry);
   initializeBreakCriticalEdgesPass(Registry);
   initializeInstNamerPass(Registry);
   initializeLCSSAPass(Registry);
diff --git a/test/Transforms/AddDiscriminators/basic.ll b/test/Transforms/AddDiscriminators/basic.ll
new file mode 100644 (file)
index 0000000..b12cbee
--- /dev/null
@@ -0,0 +1,59 @@
+; RUN: opt < %s -add-discriminators -S | FileCheck %s
+
+; Basic DWARF discriminator test. All the instructions in block
+; 'if.then' should have a different discriminator value than
+; the conditional branch at the end of block 'entry'.
+;
+; Original code:
+;
+;       void foo(int i) {
+;         int x;
+;         if (i < 10) x = i;
+;       }
+
+define void @foo(i32 %i) #0 {
+entry:
+  %i.addr = alloca i32, align 4
+  %x = alloca i32, align 4
+  store i32 %i, i32* %i.addr, align 4
+  %0 = load i32* %i.addr, align 4, !dbg !10
+  %cmp = icmp slt i32 %0, 10, !dbg !10
+  br i1 %cmp, label %if.then, label %if.end, !dbg !10
+
+if.then:                                          ; preds = %entry
+  %1 = load i32* %i.addr, align 4, !dbg !10
+; CHECK:  %1 = load i32* %i.addr, align 4, !dbg !12
+
+  store i32 %1, i32* %x, align 4, !dbg !10
+; CHECK:  store i32 %1, i32* %x, align 4, !dbg !12
+
+  br label %if.end, !dbg !10
+; CHECK:   br label %if.end, !dbg !12
+
+if.end:                                           ; preds = %if.then, %entry
+  ret void, !dbg !12
+}
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = !{!7, !8}
+!llvm.ident = !{!9}
+
+!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 ] [basic.c] [DW_LANG_C99]
+!1 = metadata !{metadata !"basic.c", metadata !"."}
+!2 = metadata !{}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"foo", metadata !"foo", metadata !"", i32 1, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void (i32)* @foo, null, null, metadata !2, i32 1} ; [ DW_TAG_subprogram ] [line 1] [def] [foo]
+!5 = metadata !{i32 786473, metadata !1}          ; [ DW_TAG_file_type ] [basic.c]
+!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !2, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!7 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!8 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+!9 = metadata !{metadata !"clang version 3.5 "}
+!10 = metadata !{i32 3, i32 0, metadata !11, null}
+!11 = metadata !{i32 786443, metadata !1, metadata !4, i32 3, i32 0, i32 0, i32 0} ; [ DW_TAG_lexical_block ] [basic.c]
+!12 = metadata !{i32 4, i32 0, metadata !4, null}
+
+; CHECK: !12 = metadata !{i32 3, i32 0, metadata !13, null}
+; CHECK: !13 = metadata !{i32 786443, metadata !1, metadata !11, i32 3, i32 0, i32 1, i32 0} ; [ DW_TAG_lexical_block ] [./basic.c]
+; CHECK: !14 = metadata !{i32 4, i32 0, metadata !4, null}
diff --git a/test/Transforms/AddDiscriminators/first-only.ll b/test/Transforms/AddDiscriminators/first-only.ll
new file mode 100644 (file)
index 0000000..f3b0357
--- /dev/null
@@ -0,0 +1,82 @@
+; RUN: opt < %s -add-discriminators -S | FileCheck %s
+
+; Test that the only instructions that receive a new discriminator in
+; the block 'if.then' are those that share the same line number as
+; the branch in 'entry'.
+;
+; Original code:
+;
+;       void foo(int i) {
+;         int x, y;
+;         if (i < 10) { x = i;
+;             y = -i;
+;         }
+;       }
+
+define void @foo(i32 %i) #0 {
+entry:
+  %i.addr = alloca i32, align 4
+  %x = alloca i32, align 4
+  %y = alloca i32, align 4
+  store i32 %i, i32* %i.addr, align 4
+  %0 = load i32* %i.addr, align 4, !dbg !10
+  %cmp = icmp slt i32 %0, 10, !dbg !10
+  br i1 %cmp, label %if.then, label %if.end, !dbg !10
+
+if.then:                                          ; preds = %entry
+  %1 = load i32* %i.addr, align 4, !dbg !12
+  store i32 %1, i32* %x, align 4, !dbg !12
+
+  %2 = load i32* %i.addr, align 4, !dbg !14
+; CHECK:  %2 = load i32* %i.addr, align 4, !dbg !15
+
+  %sub = sub nsw i32 0, %2, !dbg !14
+; CHECK:  %sub = sub nsw i32 0, %2, !dbg !15
+
+  store i32 %sub, i32* %y, align 4, !dbg !14
+; CHECK:  store i32 %sub, i32* %y, align 4, !dbg !15
+
+  br label %if.end, !dbg !15
+; CHECK:  br label %if.end, !dbg !16
+
+if.end:                                           ; preds = %if.then, %entry
+  ret void, !dbg !16
+; CHECK:  ret void, !dbg !17
+}
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = !{!7, !8}
+!llvm.ident = !{!9}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 (trunk 199750) (llvm/trunk 199751)", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [first-only.c] [DW_LANG_C99]
+!1 = metadata !{metadata !"first-only.c", metadata !"."}
+!2 = metadata !{i32 0}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"foo", metadata !"foo", metadata !"", i32 1, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void (i32)* @foo, null, null, metadata !2, i32 1} ; [ DW_TAG_subprogram ] [line 1] [def] [foo]
+!5 = metadata !{i32 786473, metadata !1}          ; [ DW_TAG_file_type ] [first-only.c]
+!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !2, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!7 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!8 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+!9 = metadata !{metadata !"clang version 3.5 (trunk 199750) (llvm/trunk 199751)"}
+!10 = metadata !{i32 3, i32 0, metadata !11, null}
+
+!11 = metadata !{i32 786443, metadata !1, metadata !4, i32 3, i32 0, i32 0} ; [ DW_TAG_lexical_block ] [first-only.c]
+; CHECK: !11 = metadata !{i32 786443, metadata !1, metadata !4, i32 3, i32 0, i32 0}
+
+!12 = metadata !{i32 3, i32 0, metadata !13, null}
+
+!13 = metadata !{i32 786443, metadata !1, metadata !11, i32 3, i32 0, i32 1} ; [ DW_TAG_lexical_block ] [first-only.c]
+; CHECK: !13 = metadata !{i32 786443, metadata !1, metadata !14, i32 3, i32 0, i32 1, i32 0} ; [ DW_TAG_lexical_block ] [./first-only.c]
+
+!14 = metadata !{i32 4, i32 0, metadata !13, null}
+; CHECK: !14 = metadata !{i32 786443, metadata !1, metadata !11, i32 3, i32 0, i32 1}
+
+!15 = metadata !{i32 5, i32 0, metadata !13, null}
+; CHECK: !15 = metadata !{i32 4, i32 0, metadata !14, null}
+
+!16 = metadata !{i32 6, i32 0, metadata !4, null}
+; CHECK: !16 = metadata !{i32 5, i32 0, metadata !14, null}
+; CHECK: !17 = metadata !{i32 6, i32 0, metadata !4, null}
+
diff --git a/test/Transforms/AddDiscriminators/multiple.ll b/test/Transforms/AddDiscriminators/multiple.ll
new file mode 100644 (file)
index 0000000..0241a0c
--- /dev/null
@@ -0,0 +1,71 @@
+; RUN: opt < %s -add-discriminators -S | FileCheck %s
+
+; Discriminator support for multiple CFG paths on the same line.
+;
+;       void foo(int i) {
+;         int x;
+;         if (i < 10) x = i; else x = -i;
+;       }
+;
+; The two stores inside the if-then-else line must have different discriminator
+; values.
+
+define void @foo(i32 %i) #0 {
+entry:
+  %i.addr = alloca i32, align 4
+  %x = alloca i32, align 4
+  store i32 %i, i32* %i.addr, align 4
+  %0 = load i32* %i.addr, align 4, !dbg !10
+  %cmp = icmp slt i32 %0, 10, !dbg !10
+  br i1 %cmp, label %if.then, label %if.else, !dbg !10
+
+if.then:                                          ; preds = %entry
+  %1 = load i32* %i.addr, align 4, !dbg !10
+; CHECK:  %1 = load i32* %i.addr, align 4, !dbg !12
+
+  store i32 %1, i32* %x, align 4, !dbg !10
+; CHECK:  store i32 %1, i32* %x, align 4, !dbg !12
+
+  br label %if.end, !dbg !10
+; CHECK:  br label %if.end, !dbg !12
+
+if.else:                                          ; preds = %entry
+  %2 = load i32* %i.addr, align 4, !dbg !10
+; CHECK:  %2 = load i32* %i.addr, align 4, !dbg !14
+
+  %sub = sub nsw i32 0, %2, !dbg !10
+; CHECK:  %sub = sub nsw i32 0, %2, !dbg !14
+
+  store i32 %sub, i32* %x, align 4, !dbg !10
+; CHECK:  store i32 %sub, i32* %x, align 4, !dbg !14
+
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  ret void, !dbg !12
+}
+
+attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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 = !{!7, !8}
+!llvm.ident = !{!9}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 (trunk 199750) (llvm/trunk 199751)", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [multiple.c] [DW_LANG_C99]
+!1 = metadata !{metadata !"multiple.c", metadata !"."}
+!2 = metadata !{i32 0}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"foo", metadata !"foo", metadata !"", i32 1, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void (i32)* @foo, null, null, metadata !2, i32 1} ; [ DW_TAG_subprogram ] [line 1] [def] [foo]
+!5 = metadata !{i32 786473, metadata !1}          ; [ DW_TAG_file_type ] [multiple.c]
+!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !2, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!7 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!8 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+!9 = metadata !{metadata !"clang version 3.5 (trunk 199750) (llvm/trunk 199751)"}
+!10 = metadata !{i32 3, i32 0, metadata !11, null}
+!11 = metadata !{i32 786443, metadata !1, metadata !4, i32 3, i32 0, i32 0} ; [ DW_TAG_lexical_block ] [multiple.c]
+!12 = metadata !{i32 4, i32 0, metadata !4, null}
+
+; CHECK: !12 = metadata !{i32 3, i32 0, metadata !13, null}
+; CHECK: !13 = metadata !{i32 786443, metadata !1, metadata !11, i32 3, i32 0, i32 1, i32 0} ; [ DW_TAG_lexical_block ] [./multiple.c]
+; CHECK: !14 = metadata !{i32 3, i32 0, metadata !15, null}
+; CHECK: !15 = metadata !{i32 786443, metadata !1, metadata !11, i32 3, i32 0, i32 2, i32 1} ; [ DW_TAG_lexical_block ] [./multiple.c]