You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
235 lines
8.0 KiB
235 lines
8.0 KiB
/*
|
|
* 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 "Assert.h"
|
|
#include "Log.h"
|
|
#include "RSTransforms.h"
|
|
#include "RSUtils.h"
|
|
#include "rsDefines.h"
|
|
|
|
#include "bcc/Config.h"
|
|
#include "bcinfo/MetadataExtractor.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>
|
|
|
|
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();
|
|
}
|
|
|
|
}
|