Home | History | Annotate | Download | only in lib
      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 
     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 
    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.
    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 
    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 
    293 llvm::ModulePass * createRSAddDebugInfoPass() {
    294   return new RSAddDebugInfoPass();
    295 }
    296 
    297 } // end namespace bcc
    298