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