Home | History | Annotate | Download | only in Renderscript
      1 /*
      2  * Copyright 2014, 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/Renderscript/RSUtils.h"
     20 #include "rsDefines.h"
     21 
     22 #include <cstdlib>
     23 
     24 #include <llvm/IR/DataLayout.h>
     25 #include <llvm/IR/DerivedTypes.h>
     26 #include <llvm/IR/Function.h>
     27 #include <llvm/IR/Instructions.h>
     28 #include <llvm/IR/IRBuilder.h>
     29 #include <llvm/IR/MDBuilder.h>
     30 #include <llvm/IR/Module.h>
     31 #include <llvm/IR/Type.h>
     32 #include <llvm/Pass.h>
     33 #include <llvm/Support/raw_ostream.h>
     34 #include <llvm/Transforms/Utils/BasicBlockUtils.h>
     35 
     36 #include "bcc/Config/Config.h"
     37 #include "bcc/Support/Log.h"
     38 
     39 #include "bcinfo/MetadataExtractor.h"
     40 
     41 using namespace bcc;
     42 
     43 namespace {
     44 
     45 class RSInvokeHelperPass : public llvm::FunctionPass {
     46 private:
     47   static char ID;
     48 
     49   llvm::StructType* rsAllocationType;
     50   llvm::StructType* rsElementType;
     51   llvm::StructType* rsSamplerType;
     52   llvm::StructType* rsScriptType;
     53   llvm::StructType* rsTypeType;
     54 
     55   llvm::Constant* rsAllocationSetObj;
     56   llvm::Constant* rsElementSetObj;
     57   llvm::Constant* rsSamplerSetObj;
     58   llvm::Constant* rsScriptSetObj;
     59   llvm::Constant* rsTypeSetObj;
     60 
     61 
     62 public:
     63   RSInvokeHelperPass()
     64     : FunctionPass(ID) {
     65 
     66     }
     67 
     68   virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
     69     // This pass does not use any other analysis passes, but it does
     70     // modify the existing functions in the module (thus altering the CFG).
     71   }
     72 
     73   virtual bool doInitialization(llvm::Module &M) override {
     74     llvm::FunctionType * SetObjType = nullptr;
     75     llvm::SmallVector<llvm::Type*, 4> rsBaseObj;
     76     rsBaseObj.append(4, llvm::Type::getInt64PtrTy(M.getContext()));
     77 
     78     rsAllocationType = llvm::StructType::create(rsBaseObj, kAllocationTypeName);
     79     rsElementType = llvm::StructType::create(rsBaseObj, kElementTypeName);
     80     rsSamplerType = llvm::StructType::create(rsBaseObj, kSamplerTypeName);
     81     rsScriptType = llvm::StructType::create(rsBaseObj, kScriptTypeName);
     82     rsTypeType = llvm::StructType::create(rsBaseObj, kTypeTypeName);
     83 
     84     llvm::SmallVector<llvm::Value*, 1> SetObjParams;
     85     llvm::SmallVector<llvm::Type*, 2> SetObjTypeParams;
     86 
     87     // get rsSetObject(rs_allocation*, rs_allocation*)
     88     // according to AArch64 calling convention, these are both pointers because of the size of the struct
     89     SetObjTypeParams.push_back(rsAllocationType->getPointerTo());
     90     SetObjTypeParams.push_back(rsAllocationType->getPointerTo());
     91     SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
     92     rsAllocationSetObj = M.getOrInsertFunction("_Z11rsSetObjectP13rs_allocationS_", SetObjType);
     93     SetObjTypeParams.clear();
     94 
     95     SetObjTypeParams.push_back(rsElementType->getPointerTo());
     96     SetObjTypeParams.push_back(rsElementType->getPointerTo());
     97     SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
     98     rsElementSetObj = M.getOrInsertFunction("_Z11rsSetObjectP10rs_elementS_", SetObjType);
     99     SetObjTypeParams.clear();
    100 
    101     SetObjTypeParams.push_back(rsSamplerType->getPointerTo());
    102     SetObjTypeParams.push_back(rsSamplerType->getPointerTo());
    103     SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
    104     rsSamplerSetObj = M.getOrInsertFunction("_Z11rsSetObjectP10rs_samplerS_", SetObjType);
    105     SetObjTypeParams.clear();
    106 
    107     SetObjTypeParams.push_back(rsScriptType->getPointerTo());
    108     SetObjTypeParams.push_back(rsScriptType->getPointerTo());
    109     SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
    110     rsScriptSetObj = M.getOrInsertFunction("_Z11rsSetObjectP9rs_scriptS_", SetObjType);
    111     SetObjTypeParams.clear();
    112 
    113     SetObjTypeParams.push_back(rsTypeType->getPointerTo());
    114     SetObjTypeParams.push_back(rsTypeType->getPointerTo());
    115     SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
    116     rsTypeSetObj = M.getOrInsertFunction("_Z11rsSetObjectP7rs_typeS_", SetObjType);
    117     SetObjTypeParams.clear();
    118 
    119     return true;
    120   }
    121 
    122   bool insertSetObjectHelper(llvm::CallInst *Call, llvm::Value *V, enum RsDataType DT) {
    123     llvm::Constant *SetObj = nullptr;
    124     llvm::StructType *RSStructType = nullptr;
    125     switch (DT) {
    126     case RS_TYPE_ALLOCATION:
    127       SetObj = rsAllocationSetObj;
    128       RSStructType = rsAllocationType;
    129       break;
    130     case RS_TYPE_ELEMENT:
    131       SetObj = rsElementSetObj;
    132       RSStructType = rsElementType;
    133       break;
    134     case RS_TYPE_SAMPLER:
    135       SetObj = rsSamplerSetObj;
    136       RSStructType = rsSamplerType;
    137       break;
    138     case RS_TYPE_SCRIPT:
    139       SetObj = rsScriptSetObj;
    140       RSStructType = rsScriptType;
    141       break;
    142     case RS_TYPE_TYPE:
    143       SetObj = rsTypeSetObj;
    144       RSStructType = rsTypeType;
    145       break;
    146     default:
    147       return false; // this is for graphics types and matrices; do nothing
    148     }
    149 
    150 
    151     llvm::CastInst* CastedValue = llvm::CastInst::CreatePointerCast(V, RSStructType->getPointerTo(), "", Call);
    152 
    153     llvm::SmallVector<llvm::Value*, 2> SetObjParams;
    154     SetObjParams.push_back(CastedValue);
    155     SetObjParams.push_back(CastedValue);
    156 
    157     llvm::CallInst::Create(SetObj, SetObjParams, "", Call);
    158 
    159 
    160     return true;
    161   }
    162 
    163 
    164   // this only modifies .helper functions that take certain RS base object types
    165   virtual bool runOnFunction(llvm::Function &F) override {
    166     if (!F.getName().startswith(".helper"))
    167       return false;
    168 
    169     bool changed = false;
    170     const llvm::Function::ArgumentListType &argList(F.getArgumentList());
    171     bool containsBaseObj = false;
    172 
    173     // .helper methods should have one arg only, an anonymous struct
    174     // that struct may contain BaseObjs
    175     for (auto arg = argList.begin(); arg != argList.end(); arg++) {
    176       llvm::Type *argType = arg->getType();
    177       if (!argType->isPointerTy() || !argType->getPointerElementType()->isStructTy())
    178         continue;
    179 
    180       llvm::StructType *argStructType = llvm::dyn_cast<llvm::StructType>(argType->getPointerElementType());
    181 
    182       for (unsigned int i = 0; i < argStructType->getNumElements(); i++) {
    183         llvm::Type *currentType = argStructType->getElementType(i);
    184         if (currentType->isStructTy() && currentType->getStructName().startswith("struct.rs_")) {
    185           containsBaseObj = true;
    186         }
    187       }
    188       break;
    189     }
    190 
    191 
    192     if (containsBaseObj) {
    193       // modify the thing that should not be
    194       auto &BBList(F.getBasicBlockList());
    195       for (auto &BB : BBList) {
    196         auto &InstList(BB.getInstList());
    197         for (auto &Inst : InstList) {
    198           // don't care about anything except call instructions that we didn't already add
    199           if (llvm::CallInst *call = llvm::dyn_cast<llvm::CallInst>(&Inst)) {
    200             for (unsigned int i = 0; i < call->getNumArgOperands(); i++) {
    201               llvm::Value *V = call->getArgOperand(i);
    202               llvm::Type *T = V->getType();
    203               enum RsDataType DT = RS_TYPE_NONE;
    204               if (T->isPointerTy() && T->getPointerElementType()->isStructTy()) {
    205                 DT = getRsDataTypeForType(T->getPointerElementType());
    206               }
    207               if (DT != RS_TYPE_NONE) {
    208                 // generate the new call instruction and insert it
    209                 changed |= insertSetObjectHelper(call, V, DT);
    210               }
    211             }
    212           }
    213         }
    214       }
    215     }
    216 
    217     return changed;
    218   }
    219 
    220   virtual const char *getPassName() const override {
    221     return ".helper method expansion for large RS objects";
    222   }
    223 }; // end RSInvokeHelperPass class
    224 } // end anonymous namespace
    225 
    226 char RSInvokeHelperPass::ID = 0;
    227 
    228 namespace bcc {
    229 
    230 llvm::FunctionPass *
    231 createRSInvokeHelperPass(){
    232   return new RSInvokeHelperPass();
    233 }
    234 
    235 }
    236