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