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