• 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 "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 
34 namespace {
35 
36 const char DEBUG_SOURCE_PATH[] = "/opt/renderscriptdebugger/1";
37 const char DEBUG_GENERATED_FILE[] = "generated.rs";
38 const char DEBUG_PROTOTYPE_VAR_NAME[] = "rsDebugOuterForeachT";
39 const 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  */
45 class RSAddDebugInfoPass : public llvm::ModulePass {
46 
47 public:
48   // Pass ID
49   static char ID;
50 
RSAddDebugInfoPass()51   RSAddDebugInfoPass() : ModulePass(ID), kernelTypeMD(nullptr),
52       sourceFileName(nullptr), emptyExpr(nullptr), abiMetaCU(nullptr),
53       indexVarType(nullptr) {
54   }
55 
runOnModule(llvm::Module & Module)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 
105 private:
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.
initializeDebugInfo(llvm::DIBuilder & DebugInfo,const llvm::Module & Module)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.
attachDebugInfo(llvm::DIBuilder & DebugInfo,llvm::Function & Func)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.
cleanupDebugInfo(llvm::Module & Module)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 
276 private:
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 
286 char RSAddDebugInfoPass::ID = 0;
287 static llvm::RegisterPass<RSAddDebugInfoPass> X("addrsdi", "Add RS DebugInfo Pass");
288 
289 } // end anonymous namespace
290 
291 namespace bcc {
292 
createRSAddDebugInfoPass()293 llvm::ModulePass * createRSAddDebugInfoPass() {
294   return new RSAddDebugInfoPass();
295 }
296 
297 } // end namespace bcc
298