Home | History | Annotate | Download | only in Renderscript
      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 
     47   RSAddDebugInfoPass() : ModulePass(ID), kernelTypeMD(nullptr),
     48       sourceFileName(nullptr), emptyExpr(nullptr), abiMetaCU(nullptr),
     49       indexVarType(nullptr) {
     50   }
     51 
     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.
     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.
    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.
    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 
    271 llvm::ModulePass * createRSAddDebugInfoPass() {
    272   return new RSAddDebugInfoPass();
    273 }
    274 
    275 } // end namespace bcc
    276