1/*
2 * Copyright 2015, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Assert.h"
18#include "Log.h"
19#include "RSTransforms.h"
20
21#include "bcinfo/MetadataExtractor.h"
22
23#include <string>
24
25#include <llvm/Pass.h>
26#include <llvm/IR/DIBuilder.h>
27#include <llvm/IR/Function.h>
28#include <llvm/IR/InstIterator.h>
29#include <llvm/IR/Instructions.h>
30#include <llvm/IR/IRBuilder.h>
31#include <llvm/IR/Module.h>
32#include <llvm/ADT/SetVector.h>
33
34namespace {
35
36const char DEBUG_SOURCE_PATH[] = "/opt/renderscriptdebugger/1";
37const char DEBUG_GENERATED_FILE[] = "generated.rs";
38const char DEBUG_PROTOTYPE_VAR_NAME[] = "rsDebugOuterForeachT";
39const char DEBUG_COMPILE_UNIT_MDNAME[] = "llvm.dbg.cu";
40
41/*
42 * LLVM pass to attach debug information to the bits of code
43 * generated by the compiler.
44 */
45class RSAddDebugInfoPass : public llvm::ModulePass {
46
47public:
48  // Pass ID
49  static char ID;
50
51  RSAddDebugInfoPass() : ModulePass(ID), kernelTypeMD(nullptr),
52      sourceFileName(nullptr), emptyExpr(nullptr), abiMetaCU(nullptr),
53      indexVarType(nullptr) {
54  }
55
56  virtual bool runOnModule(llvm::Module &Module) {
57    // Gather information about this bcc module.
58    bcinfo::MetadataExtractor me(&Module);
59    if (!me.extract()) {
60      ALOGE("Could not extract metadata from module!");
61      return false;
62    }
63
64    const size_t nForEachKernels = me.getExportForEachSignatureCount();
65    const char **forEachKernels = me.getExportForEachNameList();
66    const bcinfo::MetadataExtractor::Reduce *reductions =
67        me.getExportReduceList();
68    const size_t nReductions = me.getExportReduceCount();
69
70    llvm::SmallSetVector<llvm::Function *, 16> expandFuncs{};
71    auto pushExpanded = [&](const char *const name) -> void {
72      bccAssert(name && *name && (::strcmp(name, ".") != 0));
73
74      const std::string expandName = std::string(name) + ".expand";
75      if (llvm::Function *const func = Module.getFunction(expandName))
76        expandFuncs.insert(func);
77    };
78
79    for (size_t i = 0; i < nForEachKernels; ++i)
80      pushExpanded(forEachKernels[i]);
81
82    for (size_t i = 0; i < nReductions; ++i) {
83      const bcinfo::MetadataExtractor::Reduce &reduction = reductions[i];
84      pushExpanded(reduction.mAccumulatorName);
85    }
86
87    // Set up the debug info builder.
88    llvm::DIBuilder DebugInfo(Module);
89    initializeDebugInfo(DebugInfo, Module);
90
91    for (const auto &expandFunc : expandFuncs) {
92      // Attach DI metadata to each generated function.
93      // No inlining has occurred at this point so it's safe to name match
94      // without worrying about inlined function bodies.
95      attachDebugInfo(DebugInfo, *expandFunc);
96    }
97
98    DebugInfo.finalize();
99
100    cleanupDebugInfo(Module);
101
102    return true;
103  }
104
105private:
106
107  // @brief Initialize the debug info generation.
108  //
109  // This method does a couple of things:
110  // * Look up debug metadata for kernel ABI and store it if present.
111  // * Store a couple of useful pieces of debug metadata in member
112  //   variables so they do not have to be created multiple times.
113  void initializeDebugInfo(llvm::DIBuilder &DebugInfo,
114                           const llvm::Module &Module) {
115    llvm::LLVMContext &ctx = Module.getContext();
116
117    // Start generating debug information for bcc-generated code.
118    DebugInfo.createCompileUnit(llvm::dwarf::DW_LANG_GOOGLE_RenderScript,
119                                DEBUG_GENERATED_FILE, DEBUG_SOURCE_PATH,
120                                "RS", false, "", 0);
121
122    // Pre-generate and save useful pieces of debug metadata.
123    sourceFileName = DebugInfo.createFile(DEBUG_GENERATED_FILE, DEBUG_SOURCE_PATH);
124    emptyExpr = DebugInfo.createExpression();
125
126    // Lookup compile unit with kernel ABI debug metadata.
127    llvm::NamedMDNode *mdCompileUnitList =
128        Module.getNamedMetadata(DEBUG_COMPILE_UNIT_MDNAME);
129    bccAssert(mdCompileUnitList != nullptr &&
130        "DebugInfo pass could not find any existing compile units.");
131
132    llvm::DIGlobalVariable *kernelPrototypeVarMD = nullptr;
133    for (llvm::MDNode* CUNode : mdCompileUnitList->operands()) {
134      if (auto *CU = llvm::dyn_cast<llvm::DICompileUnit>(CUNode)) {
135        for (llvm::DIGlobalVariable* GV : CU->getGlobalVariables()) {
136          if (GV->getDisplayName() == DEBUG_PROTOTYPE_VAR_NAME) {
137            kernelPrototypeVarMD = GV;
138            abiMetaCU = CU;
139            break;
140          }
141        }
142        if (kernelPrototypeVarMD != nullptr)
143          break;
144      }
145    }
146
147    // Lookup the expanded function interface type metadata.
148    llvm::MDTuple *kernelPrototypeMD = nullptr;
149    if (kernelPrototypeVarMD != nullptr) {
150      // Dig into the metadata to look for function prototype.
151      llvm::DIDerivedType *DT = nullptr;
152      DT = llvm::cast<llvm::DIDerivedType>(kernelPrototypeVarMD->getType());
153      DT = llvm::cast<llvm::DIDerivedType>(DT->getBaseType());
154      llvm::DISubroutineType *ST = llvm::cast<llvm::DISubroutineType>(DT->getBaseType());
155      kernelPrototypeMD = llvm::cast<llvm::MDTuple>(ST->getRawTypeArray());
156
157      indexVarType = llvm::dyn_cast_or_null<llvm::DIType>(
158          kernelPrototypeMD->getOperand(2));
159    }
160    // Fall back to the function type of void() if there is no proper debug info.
161    if (kernelPrototypeMD == nullptr)
162      kernelPrototypeMD = llvm::MDTuple::get(ctx, {nullptr});
163    // Fall back to unspecified type if we don't have a proper index type.
164    if (indexVarType == nullptr)
165      indexVarType = DebugInfo.createBasicType("uint32_t", 32, 32,
166          llvm::dwarf::DW_ATE_unsigned);
167
168    // Capture the expanded kernel type debug info.
169    kernelTypeMD = DebugInfo.createSubroutineType(kernelPrototypeMD);
170  }
171
172  /// @brief Add debug information to a generated function.
173  ///
174  /// This procedure adds the following pieces of debug information
175  /// to the function specified by Func:
176  /// * Entry for the function to the current compile unit.
177  /// * Adds debug info entries for each function argument.
178  /// * Adds debug info entry for the rsIndex local variable.
179  /// * File/line information to each instruction set to generates.rs:1.
180  void attachDebugInfo(llvm::DIBuilder &DebugInfo, llvm::Function &Func) {
181    // Lookup the current thread coordinate variable.
182    llvm::AllocaInst* indexVar = nullptr;
183    for (llvm::Instruction &inst : llvm::instructions(Func)) {
184      if (auto *allocaInst = llvm::dyn_cast<llvm::AllocaInst>(&inst)) {
185        if (allocaInst->getName() == bcc::BCC_INDEX_VAR_NAME) {
186          indexVar = allocaInst;
187          break;
188        }
189      }
190    }
191
192    // Create function-level debug metadata.
193    llvm::DISubprogram *ExpandedFunc = DebugInfo.createFunction(
194        sourceFileName, // scope
195        Func.getName(), Func.getName(),
196        sourceFileName, 1, kernelTypeMD,
197        false, true, 1, 0, false
198    );
199    Func.setSubprogram(ExpandedFunc);
200
201    // IRBuilder for allocating variables for arguments.
202    llvm::IRBuilder<> ir(&*Func.getEntryBlock().begin());
203
204    // Walk through the argument list and expanded function prototype
205    // debuginfo in lockstep to create debug entries for
206    // the expanded function arguments.
207    unsigned argIdx = 1;
208    llvm::MDTuple *argTypes = kernelTypeMD->getTypeArray().get();
209    for (llvm::Argument &arg : Func.getArgumentList()) {
210      // Stop processing arguments if we run out of debug info.
211      if (argIdx >= argTypes->getNumOperands())
212        break;
213
214      // Create debuginfo entry for the argument and advance.
215      llvm::DILocalVariable *argVarDI = DebugInfo.createParameterVariable(
216          ExpandedFunc, arg.getName(), argIdx, sourceFileName, 1,
217          llvm::cast<llvm::DIType>(argTypes->getOperand(argIdx).get()),
218          true, 0
219      );
220
221      // Annotate the argument variable in the IR.
222      llvm::AllocaInst *argVar =
223          ir.CreateAlloca(arg.getType(), nullptr, arg.getName() + ".var");
224      llvm::StoreInst *argStore = ir.CreateStore(&arg, argVar);
225      llvm::LoadInst *loadedVar = ir.CreateLoad(argVar, arg.getName() + ".l");
226      DebugInfo.insertDeclare(argVar, argVarDI, emptyExpr,
227          llvm::DebugLoc::get(1, 1, ExpandedFunc), loadedVar);
228      for (llvm::Use &u : arg.uses())
229        if (u.getUser() != argStore)
230          u.set(loadedVar);
231      argIdx++;
232    }
233
234    // Annotate the index variable with metadata.
235    if (indexVar) {
236      // Debug information for loop index variable.
237      llvm::DILocalVariable *indexVarDI = DebugInfo.createAutoVariable(
238          ExpandedFunc, bcc::BCC_INDEX_VAR_NAME, sourceFileName, 1,
239          indexVarType, true
240      );
241
242      // Insert declaration annotation in the instruction stream.
243      llvm::Instruction *decl = DebugInfo.insertDeclare(
244          indexVar, indexVarDI, emptyExpr,
245          llvm::DebugLoc::get(1, 1, ExpandedFunc), indexVar);
246      indexVar->moveBefore(decl);
247    }
248
249    // Attach location information to each instruction in the function.
250    for (llvm::Instruction &inst : llvm::instructions(Func)) {
251      inst.setDebugLoc(llvm::DebugLoc::get(1, 1, ExpandedFunc));
252    }
253  }
254
255  // @brief Clean up the debug info.
256  //
257  // At the moment, it only finds the compile unit for the expanded function
258  // metadata generated by clang and removes it.
259  void cleanupDebugInfo(llvm::Module& Module) {
260    if (abiMetaCU == nullptr)
261      return;
262
263    // Remove the compile unit with the runtime interface DI.
264    llvm::SmallVector<llvm::MDNode*, 4> unitsTmp;
265    llvm::NamedMDNode *debugMD =
266        Module.getNamedMetadata(DEBUG_COMPILE_UNIT_MDNAME);
267    for (llvm::MDNode *cu : debugMD->operands())
268      if (cu != abiMetaCU)
269        unitsTmp.push_back(cu);
270    debugMD->eraseFromParent();
271    debugMD = Module.getOrInsertNamedMetadata(DEBUG_COMPILE_UNIT_MDNAME);
272    for (llvm::MDNode *cu : unitsTmp)
273      debugMD->addOperand(cu);
274  }
275
276private:
277  // private attributes
278  llvm::DISubroutineType* kernelTypeMD;
279  llvm::DIFile *sourceFileName;
280  llvm::DIExpression *emptyExpr;
281  llvm::DICompileUnit *abiMetaCU;
282  llvm::DIType *indexVarType;
283
284}; // end class RSAddDebugInfoPass
285
286char RSAddDebugInfoPass::ID = 0;
287static llvm::RegisterPass<RSAddDebugInfoPass> X("addrsdi", "Add RS DebugInfo Pass");
288
289} // end anonymous namespace
290
291namespace bcc {
292
293llvm::ModulePass * createRSAddDebugInfoPass() {
294  return new RSAddDebugInfoPass();
295}
296
297} // end namespace bcc
298