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