• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
30 namespace {
31 
32 const char DEBUG_SOURCE_PATH[] = "/opt/renderscriptdebugger/1";
33 const char DEBUG_GENERATED_FILE[] = "generated.rs";
34 const char DEBUG_PROTOTYPE_VAR_NAME[] = "rsDebugOuterForeachT";
35 const 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  */
41 class RSAddDebugInfoPass : public llvm::ModulePass {
42 
43 public:
44   // Pass ID
45   static char ID;
46 
RSAddDebugInfoPass()47   RSAddDebugInfoPass() : ModulePass(ID), kernelTypeMD(nullptr),
48       sourceFileName(nullptr), emptyExpr(nullptr), abiMetaCU(nullptr),
49       indexVarType(nullptr) {
50   }
51 
runOnModule(llvm::Module & Module)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 
84 private:
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.
initializeDebugInfo(llvm::DIBuilder & DebugInfo,const llvm::Module & Module)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.
attachDebugInfo(llvm::DIBuilder & DebugInfo,llvm::Function & Func)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.
cleanupDebugInfo(llvm::Module & Module)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 
254 private:
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 
264 char RSAddDebugInfoPass::ID = 0;
265 static llvm::RegisterPass<RSAddDebugInfoPass> X("addrsdi", "Add RS DebugInfo Pass");
266 
267 } // end anonymous namespace
268 
269 namespace bcc {
270 
createRSAddDebugInfoPass()271 llvm::ModulePass * createRSAddDebugInfoPass() {
272   return new RSAddDebugInfoPass();
273 }
274 
275 } // end namespace bcc
276