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