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