While inlining, clone llvm.dbg.func.start intrinsic and adjust 
llvm.dbg.region.end instrinsic. This nested llvm.dbg.func.start/llvm.dbg.region.end pair now enables DW_TAG_inlined_subroutine support in code generator.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@69118 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Transforms/Utils/InlineFunction.cpp b/lib/Transforms/Utils/InlineFunction.cpp
index 1b677fb..a8cba6b 100644
--- a/lib/Transforms/Utils/InlineFunction.cpp
+++ b/lib/Transforms/Utils/InlineFunction.cpp
@@ -17,9 +17,11 @@
 #include "llvm/DerivedTypes.h"
 #include "llvm/Module.h"
 #include "llvm/Instructions.h"
+#include "llvm/IntrinsicInst.h"
 #include "llvm/Intrinsics.h"
 #include "llvm/Attributes.h"
 #include "llvm/Analysis/CallGraph.h"
+#include "llvm/Analysis/DebugInfo.h"
 #include "llvm/Target/TargetData.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
@@ -199,6 +201,31 @@
   CallerNode->removeCallEdgeFor(CS);
 }
 
+/// findFnRegionEndMarker - This is a utility routine that is used by
+/// InlineFunction. Return llvm.dbg.region.end intrinsic that corresponds
+/// to the llvm.dbg.func.start of the function F. Otherwise return NULL.
+static const DbgRegionEndInst *findFnRegionEndMarker(const Function *F) {
+
+  GlobalVariable *FnStart = NULL;
+  const DbgRegionEndInst *FnEnd = NULL;
+  for (Function::const_iterator FI = F->begin(), FE =F->end(); FI != FE; ++FI) 
+    for (BasicBlock::const_iterator BI = FI->begin(), BE = FI->end(); BI != BE;
+         ++BI) {
+      if (FnStart == NULL)  {
+        if (const DbgFuncStartInst *FSI = dyn_cast<DbgFuncStartInst>(BI)) {
+          DISubprogram SP(cast<GlobalVariable>(FSI->getSubprogram()));
+          assert (SP.isNull() == false && "Invalid llvm.dbg.func.start");
+          if (SP.describes(F))
+            FnStart = SP.getGV();
+        }
+      } else {
+        if (const DbgRegionEndInst *REI = dyn_cast<DbgRegionEndInst>(BI))
+          if (REI->getContext() == FnStart)
+            FnEnd = REI;
+      }
+    }
+  return FnEnd;
+}
 
 // InlineFunction - This function inlines the called function into the basic
 // block of the caller.  This returns false if it is not possible to inline this
@@ -320,6 +347,24 @@
       ValueMap[I] = ActualArg;
     }
 
+    // Adjust llvm.dbg.region.end. If the CalledFunc has region end
+    // marker then clone that marker after next stop point at the 
+    // call site. The function body cloner does not clone original
+    // region end marker from the CalledFunc. This will ensure that
+    // inlined function's scope ends at the right place. 
+    const DbgRegionEndInst *DREI = findFnRegionEndMarker(CalledFunc);
+    if (DREI) {
+      for (BasicBlock::iterator BI = TheCall, 
+             BE = TheCall->getParent()->end(); BI != BE; ++BI) {
+        if (DbgStopPointInst *DSPI = dyn_cast<DbgStopPointInst>(BI)) {
+          if (DbgRegionEndInst *NewDREI = 
+              dyn_cast<DbgRegionEndInst>(DREI->clone()))
+            NewDREI->insertAfter(DSPI);
+          break;
+        }
+      }
+    }
+
     // We want the inliner to prune the code as it copies.  We would LOVE to
     // have no dead or constant instructions leftover after inlining occurs
     // (which can happen, e.g., because an argument was constant), but we'll be