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:
RSInvokeHelperPass()63   RSInvokeHelperPass()
64     : FunctionPass(ID) {
65 
66     }
67 
getAnalysisUsage(llvm::AnalysisUsage & AU) const68   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 
doInitialization(llvm::Module & M)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 
insertSetObjectHelper(llvm::CallInst * Call,llvm::Value * V,enum RsDataType DT)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
runOnFunction(llvm::Function & F)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 
getPassName() const220   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 *
createRSInvokeHelperPass()231 createRSInvokeHelperPass(){
232   return new RSInvokeHelperPass();
233 }
234 
235 }
236