Merge "Initial version of debug info pass for RS."
diff --git a/include/bcc/Compiler.h b/include/bcc/Compiler.h
index 8a30c38..a0925b8 100644
--- a/include/bcc/Compiler.h
+++ b/include/bcc/Compiler.h
@@ -82,6 +82,7 @@
 
   bool addInternalizeSymbolsPass(Script &pScript, llvm::legacy::PassManager &pPM);
   void addExpandKernelPass(llvm::legacy::PassManager &pPM);
+  void addDebugInfoPass(Script &pScript, llvm::legacy::PassManager &pPM);
   void addGlobalInfoPass(Script &pScript, llvm::legacy::PassManager &pPM);
   void addInvariantPass(llvm::legacy::PassManager &pPM);
   void addInvokeHelperPass(llvm::legacy::PassManager &pPM);
diff --git a/include/bcc/Renderscript/RSTransforms.h b/include/bcc/Renderscript/RSTransforms.h
index 6dcfedd..3c81860 100644
--- a/include/bcc/Renderscript/RSTransforms.h
+++ b/include/bcc/Renderscript/RSTransforms.h
@@ -43,6 +43,8 @@
 
 llvm::ModulePass * createRSX86_64CallConvPass();
 
+llvm::ModulePass * createRSAddDebugInfoPass();
+
 } // end namespace bcc
 
 #endif // BCC_RS_TRANSFORMS_H
diff --git a/include/bcc/Source.h b/include/bcc/Source.h
index 54263a2..e6bef2e 100644
--- a/include/bcc/Source.h
+++ b/include/bcc/Source.h
@@ -82,6 +82,10 @@
 
   void addBuildChecksumMetadata(const char *) const;
 
+  // Get whether debugging has been enabled for this module by checking
+  // for presence of debug info in the module.
+  bool getDebugInfoEnabled() const;
+
   ~Source();
 };
 
diff --git a/lib/Core/Compiler.cpp b/lib/Core/Compiler.cpp
index eea0750..35f19d7 100644
--- a/lib/Core/Compiler.cpp
+++ b/lib/Core/Compiler.cpp
@@ -159,6 +159,7 @@
   // Add some initial custom passes.
   addInvokeHelperPass(transformPasses);
   addExpandKernelPass(transformPasses);
+  addDebugInfoPass(pScript, transformPasses);
   addInvariantPass(transformPasses);
   if (!addInternalizeSymbolsPass(pScript, transformPasses))
     return kErrCustomPasses;
@@ -387,6 +388,11 @@
   }
 }
 
+void Compiler::addDebugInfoPass(Script &pScript, llvm::legacy::PassManager &pPM) {
+  if (pScript.getSource().getDebugInfoEnabled())
+    pPM.add(createRSAddDebugInfoPass());
+}
+
 void Compiler::addExpandKernelPass(llvm::legacy::PassManager &pPM) {
   // Expand ForEach and reduce on CPU path to reduce launch overhead.
   bool pEnableStepOpt = true;
diff --git a/lib/Core/Source.cpp b/lib/Core/Source.cpp
index 94da98e..25b263f 100644
--- a/lib/Core/Source.cpp
+++ b/lib/Core/Source.cpp
@@ -181,4 +181,8 @@
     node->addOperand(llvm::MDNode::get(context, val));
 }
 
+bool Source::getDebugInfoEnabled() const {
+  return mModule->getNamedMetadata("llvm.dbg.cu") != nullptr;
+}
+
 } // namespace bcc
diff --git a/lib/Renderscript/Android.mk b/lib/Renderscript/Android.mk
index 7744447..32e65b3 100644
--- a/lib/Renderscript/Android.mk
+++ b/lib/Renderscript/Android.mk
@@ -22,6 +22,7 @@
 #=====================================================================
 
 libbcc_renderscript_SRC_FILES := \
+  RSAddDebugInfoPass.cpp \
   RSCompilerDriver.cpp \
   RSEmbedInfo.cpp \
   RSKernelExpand.cpp \
diff --git a/lib/Renderscript/RSAddDebugInfoPass.cpp b/lib/Renderscript/RSAddDebugInfoPass.cpp
new file mode 100644
index 0000000..03ad24a
--- /dev/null
+++ b/lib/Renderscript/RSAddDebugInfoPass.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Assert.h"
+#include "bcc/Renderscript/RSTransforms.h"
+
+#include <llvm/Pass.h>
+#include <llvm/IR/DataLayout.h>
+#include <llvm/IR/DIBuilder.h>
+#include <llvm/IR/Function.h>
+#include <llvm/IR/Function.h>
+#include <llvm/IR/InstIterator.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/MDBuilder.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Type.h>
+#include <llvm/Transforms/Utils/BasicBlockUtils.h>
+
+namespace {
+
+const char DEBUG_SOURCE_PATH[] = "/opt/renderscriptdebugger/1";
+const char DEBUG_GENERATED_FILE[] = "generated.rs";
+
+/*
+ * LLVM pass to attach debug information to the bits of code
+ * generated by the compiler.
+ */
+class RSAddDebugInfoPass : public llvm::ModulePass {
+
+public:
+  // Pass ID
+  static char ID;
+
+  RSAddDebugInfoPass() : ModulePass(ID) {
+  }
+
+  virtual bool runOnModule(llvm::Module &Module) {
+    // Set up the debug info builder.
+    llvm::DIBuilder DebugInfo(Module);
+    DebugInfo.createCompileUnit(llvm::dwarf::DW_LANG_C99,
+                                DEBUG_GENERATED_FILE, DEBUG_SOURCE_PATH,
+                                "RS", false, "", 0);
+
+    // Attach DI metadata to each generated function.
+    for (llvm::Function &Func : Module)
+      if (Func.getName().endswith(".expand"))
+        attachDebugInfo(DebugInfo, Func);
+
+    DebugInfo.finalize();
+
+    return true;
+  }
+
+private:
+
+  /// @brief Add debug information to a generated function.
+  ///
+  /// This function is used to attach source file and line information
+  /// to the generated function code.
+  void attachDebugInfo(llvm::DIBuilder &DebugInfo, llvm::Function &Func) {
+    llvm::DIFile *sourceFileName =
+      DebugInfo.createFile(DEBUG_GENERATED_FILE, DEBUG_SOURCE_PATH);
+
+    // Fabricated function type
+    llvm::MDTuple *nullMD = llvm::MDTuple::get(Func.getParent()->getContext(),
+                        { DebugInfo.createUnspecifiedType("void") });
+
+    // Create function-level debug metadata.
+    llvm::DIScope *GeneratedScope = DebugInfo.createFunction(
+        sourceFileName, // scope
+        Func.getName(), Func.getName(),
+        sourceFileName, 1,
+        DebugInfo.createSubroutineType(sourceFileName, nullMD),
+        false, true, 1, 0, false, &Func
+    );
+
+    // Attach location inforamtion to each instruction in the function
+    for (llvm::inst_iterator Inst    = llvm::inst_begin(Func),
+                             InstEnd = llvm::inst_end(Func);
+                             Inst != InstEnd;
+                             ++Inst) {
+      Inst->setDebugLoc(llvm::DebugLoc::get(1, 1, GeneratedScope));
+    }
+  }
+
+}; // end class RSAddDebugInfoPass
+
+char RSAddDebugInfoPass::ID = 0;
+static llvm::RegisterPass<RSAddDebugInfoPass> X("addrsdi", "Add RS DebugInfo Pass");
+
+} // end anonymous namespace
+
+namespace bcc {
+
+llvm::ModulePass * createRSAddDebugInfoPass() {
+  return new RSAddDebugInfoPass();
+}
+
+} // end namespace bcc