| /* |
| * Copyright 2014, The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "bcc/Assert.h" |
| #include "bcc/Renderscript/RSTransforms.h" |
| #include "bcc/Renderscript/RSUtils.h" |
| #include "rsDefines.h" |
| |
| #include <cstdlib> |
| |
| #include <llvm/IR/DataLayout.h> |
| #include <llvm/IR/DerivedTypes.h> |
| #include <llvm/IR/Function.h> |
| #include <llvm/IR/Instructions.h> |
| #include <llvm/IR/IRBuilder.h> |
| #include <llvm/IR/MDBuilder.h> |
| #include <llvm/IR/Module.h> |
| #include <llvm/IR/Type.h> |
| #include <llvm/Pass.h> |
| #include <llvm/Support/raw_ostream.h> |
| #include <llvm/Transforms/Utils/BasicBlockUtils.h> |
| |
| #include "bcc/Config/Config.h" |
| #include "bcc/Support/Log.h" |
| |
| #include "bcinfo/MetadataExtractor.h" |
| |
| using namespace bcc; |
| |
| namespace { |
| |
| class RSInvokeHelperPass : public llvm::FunctionPass { |
| private: |
| static char ID; |
| |
| llvm::StructType* rsAllocationType; |
| llvm::StructType* rsElementType; |
| llvm::StructType* rsSamplerType; |
| llvm::StructType* rsScriptType; |
| llvm::StructType* rsTypeType; |
| |
| llvm::Constant* rsAllocationSetObj; |
| llvm::Constant* rsElementSetObj; |
| llvm::Constant* rsSamplerSetObj; |
| llvm::Constant* rsScriptSetObj; |
| llvm::Constant* rsTypeSetObj; |
| |
| |
| public: |
| RSInvokeHelperPass() |
| : FunctionPass(ID) { |
| |
| } |
| |
| virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { |
| // This pass does not use any other analysis passes, but it does |
| // modify the existing functions in the module (thus altering the CFG). |
| } |
| |
| virtual bool doInitialization(llvm::Module &M) override { |
| llvm::FunctionType * SetObjType = nullptr; |
| llvm::SmallVector<llvm::Type*, 4> rsBaseObj; |
| rsBaseObj.append(4, llvm::Type::getInt64PtrTy(M.getContext())); |
| |
| rsAllocationType = llvm::StructType::create(rsBaseObj, kAllocationTypeName); |
| rsElementType = llvm::StructType::create(rsBaseObj, kElementTypeName); |
| rsSamplerType = llvm::StructType::create(rsBaseObj, kSamplerTypeName); |
| rsScriptType = llvm::StructType::create(rsBaseObj, kScriptTypeName); |
| rsTypeType = llvm::StructType::create(rsBaseObj, kTypeTypeName); |
| |
| llvm::SmallVector<llvm::Value*, 1> SetObjParams; |
| llvm::SmallVector<llvm::Type*, 2> SetObjTypeParams; |
| |
| // get rsSetObject(rs_allocation*, rs_allocation*) |
| // according to AArch64 calling convention, these are both pointers because of the size of the struct |
| SetObjTypeParams.push_back(rsAllocationType->getPointerTo()); |
| SetObjTypeParams.push_back(rsAllocationType->getPointerTo()); |
| SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false); |
| rsAllocationSetObj = M.getOrInsertFunction("_Z11rsSetObjectP13rs_allocationS_", SetObjType); |
| SetObjTypeParams.clear(); |
| |
| SetObjTypeParams.push_back(rsElementType->getPointerTo()); |
| SetObjTypeParams.push_back(rsElementType->getPointerTo()); |
| SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false); |
| rsElementSetObj = M.getOrInsertFunction("_Z11rsSetObjectP10rs_elementS_", SetObjType); |
| SetObjTypeParams.clear(); |
| |
| SetObjTypeParams.push_back(rsSamplerType->getPointerTo()); |
| SetObjTypeParams.push_back(rsSamplerType->getPointerTo()); |
| SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false); |
| rsSamplerSetObj = M.getOrInsertFunction("_Z11rsSetObjectP10rs_samplerS_", SetObjType); |
| SetObjTypeParams.clear(); |
| |
| SetObjTypeParams.push_back(rsScriptType->getPointerTo()); |
| SetObjTypeParams.push_back(rsScriptType->getPointerTo()); |
| SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false); |
| rsScriptSetObj = M.getOrInsertFunction("_Z11rsSetObjectP9rs_scriptS_", SetObjType); |
| SetObjTypeParams.clear(); |
| |
| SetObjTypeParams.push_back(rsTypeType->getPointerTo()); |
| SetObjTypeParams.push_back(rsTypeType->getPointerTo()); |
| SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false); |
| rsTypeSetObj = M.getOrInsertFunction("_Z11rsSetObjectP7rs_typeS_", SetObjType); |
| SetObjTypeParams.clear(); |
| |
| return true; |
| } |
| |
| bool insertSetObjectHelper(llvm::CallInst *Call, llvm::Value *V, enum RsDataType DT) { |
| llvm::Constant *SetObj = nullptr; |
| llvm::StructType *RSStructType = nullptr; |
| switch (DT) { |
| case RS_TYPE_ALLOCATION: |
| SetObj = rsAllocationSetObj; |
| RSStructType = rsAllocationType; |
| break; |
| case RS_TYPE_ELEMENT: |
| SetObj = rsElementSetObj; |
| RSStructType = rsElementType; |
| break; |
| case RS_TYPE_SAMPLER: |
| SetObj = rsSamplerSetObj; |
| RSStructType = rsSamplerType; |
| break; |
| case RS_TYPE_SCRIPT: |
| SetObj = rsScriptSetObj; |
| RSStructType = rsScriptType; |
| break; |
| case RS_TYPE_TYPE: |
| SetObj = rsTypeSetObj; |
| RSStructType = rsTypeType; |
| break; |
| default: |
| return false; // this is for graphics types and matrices; do nothing |
| } |
| |
| |
| llvm::CastInst* CastedValue = llvm::CastInst::CreatePointerCast(V, RSStructType->getPointerTo(), "", Call); |
| |
| llvm::SmallVector<llvm::Value*, 2> SetObjParams; |
| SetObjParams.push_back(CastedValue); |
| SetObjParams.push_back(CastedValue); |
| |
| llvm::CallInst::Create(SetObj, SetObjParams, "", Call); |
| |
| |
| return true; |
| } |
| |
| |
| // this only modifies .helper functions that take certain RS base object types |
| virtual bool runOnFunction(llvm::Function &F) override { |
| if (!F.getName().startswith(".helper")) |
| return false; |
| |
| bool changed = false; |
| const llvm::Function::ArgumentListType &argList(F.getArgumentList()); |
| bool containsBaseObj = false; |
| |
| // .helper methods should have one arg only, an anonymous struct |
| // that struct may contain BaseObjs |
| for (auto arg = argList.begin(); arg != argList.end(); arg++) { |
| llvm::Type *argType = arg->getType(); |
| if (!argType->isPointerTy() || !argType->getPointerElementType()->isStructTy()) |
| continue; |
| |
| llvm::StructType *argStructType = llvm::dyn_cast<llvm::StructType>(argType->getPointerElementType()); |
| |
| for (unsigned int i = 0; i < argStructType->getNumElements(); i++) { |
| llvm::Type *currentType = argStructType->getElementType(i); |
| if (currentType->isStructTy() && currentType->getStructName().startswith("struct.rs_")) { |
| containsBaseObj = true; |
| } |
| } |
| break; |
| } |
| |
| |
| if (containsBaseObj) { |
| // modify the thing that should not be |
| auto &BBList(F.getBasicBlockList()); |
| for (auto &BB : BBList) { |
| auto &InstList(BB.getInstList()); |
| for (auto &Inst : InstList) { |
| // don't care about anything except call instructions that we didn't already add |
| if (llvm::CallInst *call = llvm::dyn_cast<llvm::CallInst>(&Inst)) { |
| for (unsigned int i = 0; i < call->getNumArgOperands(); i++) { |
| llvm::Value *V = call->getArgOperand(i); |
| llvm::Type *T = V->getType(); |
| enum RsDataType DT = RS_TYPE_NONE; |
| if (T->isPointerTy() && T->getPointerElementType()->isStructTy()) { |
| DT = getRsDataTypeForType(T->getPointerElementType()); |
| } |
| if (DT != RS_TYPE_NONE) { |
| // generate the new call instruction and insert it |
| changed |= insertSetObjectHelper(call, V, DT); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| return changed; |
| } |
| |
| virtual const char *getPassName() const override { |
| return ".helper method expansion for large RS objects"; |
| } |
| }; // end RSInvokeHelperPass class |
| } // end anonymous namespace |
| |
| char RSInvokeHelperPass::ID = 0; |
| |
| namespace bcc { |
| |
| llvm::FunctionPass * |
| createRSInvokeHelperPass(){ |
| return new RSInvokeHelperPass(); |
| } |
| |
| } |