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