blob: 99316ce46264fb6e8db3c21fbebacd79d8de7622 [file] [log] [blame]
Tim Murrayb7bce742014-11-03 16:17:30 -08001/*
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
Jean-Luc Brouilleta2dd52f2017-02-16 20:57:26 -080017#include "Assert.h"
18#include "Log.h"
19#include "RSTransforms.h"
20#include "RSUtils.h"
Stephen Hinesfb81ec12015-05-18 20:04:23 -070021#include "rsDefines.h"
Tim Murrayb7bce742014-11-03 16:17:30 -080022
Jean-Luc Brouilleta2dd52f2017-02-16 20:57:26 -080023#include "bcc/Config.h"
24#include "bcinfo/MetadataExtractor.h"
25
Tim Murrayb7bce742014-11-03 16:17:30 -080026#include <cstdlib>
27
28#include <llvm/IR/DataLayout.h>
29#include <llvm/IR/DerivedTypes.h>
30#include <llvm/IR/Function.h>
31#include <llvm/IR/Instructions.h>
32#include <llvm/IR/IRBuilder.h>
33#include <llvm/IR/MDBuilder.h>
34#include <llvm/IR/Module.h>
35#include <llvm/IR/Type.h>
36#include <llvm/Pass.h>
37#include <llvm/Support/raw_ostream.h>
38#include <llvm/Transforms/Utils/BasicBlockUtils.h>
39
Tim Murrayb7bce742014-11-03 16:17:30 -080040using namespace bcc;
41
42namespace {
43
44class RSInvokeHelperPass : public llvm::FunctionPass {
45private:
46 static char ID;
47
48 llvm::StructType* rsAllocationType;
49 llvm::StructType* rsElementType;
50 llvm::StructType* rsSamplerType;
51 llvm::StructType* rsScriptType;
52 llvm::StructType* rsTypeType;
53
54 llvm::Constant* rsAllocationSetObj;
55 llvm::Constant* rsElementSetObj;
56 llvm::Constant* rsSamplerSetObj;
57 llvm::Constant* rsScriptSetObj;
58 llvm::Constant* rsTypeSetObj;
59
60
61public:
62 RSInvokeHelperPass()
63 : FunctionPass(ID) {
64
65 }
66
Stephen Hinesc754d492015-01-08 16:00:50 -080067 virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
68 // This pass does not use any other analysis passes, but it does
69 // modify the existing functions in the module (thus altering the CFG).
70 }
71
Tim Murrayb7bce742014-11-03 16:17:30 -080072 virtual bool doInitialization(llvm::Module &M) override {
73 llvm::FunctionType * SetObjType = nullptr;
74 llvm::SmallVector<llvm::Type*, 4> rsBaseObj;
75 rsBaseObj.append(4, llvm::Type::getInt64PtrTy(M.getContext()));
76
Stephen Hinesfb81ec12015-05-18 20:04:23 -070077 rsAllocationType = llvm::StructType::create(rsBaseObj, kAllocationTypeName);
78 rsElementType = llvm::StructType::create(rsBaseObj, kElementTypeName);
79 rsSamplerType = llvm::StructType::create(rsBaseObj, kSamplerTypeName);
80 rsScriptType = llvm::StructType::create(rsBaseObj, kScriptTypeName);
81 rsTypeType = llvm::StructType::create(rsBaseObj, kTypeTypeName);
Tim Murrayb7bce742014-11-03 16:17:30 -080082
83 llvm::SmallVector<llvm::Value*, 1> SetObjParams;
84 llvm::SmallVector<llvm::Type*, 2> SetObjTypeParams;
85
86 // get rsSetObject(rs_allocation*, rs_allocation*)
87 // according to AArch64 calling convention, these are both pointers because of the size of the struct
88 SetObjTypeParams.push_back(rsAllocationType->getPointerTo());
89 SetObjTypeParams.push_back(rsAllocationType->getPointerTo());
90 SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
91 rsAllocationSetObj = M.getOrInsertFunction("_Z11rsSetObjectP13rs_allocationS_", SetObjType);
92 SetObjTypeParams.clear();
93
94 SetObjTypeParams.push_back(rsElementType->getPointerTo());
95 SetObjTypeParams.push_back(rsElementType->getPointerTo());
96 SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
97 rsElementSetObj = M.getOrInsertFunction("_Z11rsSetObjectP10rs_elementS_", SetObjType);
98 SetObjTypeParams.clear();
99
100 SetObjTypeParams.push_back(rsSamplerType->getPointerTo());
101 SetObjTypeParams.push_back(rsSamplerType->getPointerTo());
102 SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
103 rsSamplerSetObj = M.getOrInsertFunction("_Z11rsSetObjectP10rs_samplerS_", SetObjType);
104 SetObjTypeParams.clear();
105
106 SetObjTypeParams.push_back(rsScriptType->getPointerTo());
107 SetObjTypeParams.push_back(rsScriptType->getPointerTo());
108 SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
109 rsScriptSetObj = M.getOrInsertFunction("_Z11rsSetObjectP9rs_scriptS_", SetObjType);
110 SetObjTypeParams.clear();
111
112 SetObjTypeParams.push_back(rsTypeType->getPointerTo());
113 SetObjTypeParams.push_back(rsTypeType->getPointerTo());
114 SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
115 rsTypeSetObj = M.getOrInsertFunction("_Z11rsSetObjectP7rs_typeS_", SetObjType);
116 SetObjTypeParams.clear();
117
118 return true;
119 }
120
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700121 bool insertSetObjectHelper(llvm::CallInst *Call, llvm::Value *V, enum RsDataType DT) {
Tim Murrayb7bce742014-11-03 16:17:30 -0800122 llvm::Constant *SetObj = nullptr;
Tim Murray4100e8e2015-03-30 12:27:28 -0700123 llvm::StructType *RSStructType = nullptr;
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700124 switch (DT) {
125 case RS_TYPE_ALLOCATION:
Tim Murrayb7bce742014-11-03 16:17:30 -0800126 SetObj = rsAllocationSetObj;
Tim Murray4100e8e2015-03-30 12:27:28 -0700127 RSStructType = rsAllocationType;
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700128 break;
129 case RS_TYPE_ELEMENT:
Tim Murrayb7bce742014-11-03 16:17:30 -0800130 SetObj = rsElementSetObj;
Tim Murray4100e8e2015-03-30 12:27:28 -0700131 RSStructType = rsElementType;
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700132 break;
133 case RS_TYPE_SAMPLER:
Tim Murrayb7bce742014-11-03 16:17:30 -0800134 SetObj = rsSamplerSetObj;
Tim Murray4100e8e2015-03-30 12:27:28 -0700135 RSStructType = rsSamplerType;
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700136 break;
137 case RS_TYPE_SCRIPT:
Tim Murrayb7bce742014-11-03 16:17:30 -0800138 SetObj = rsScriptSetObj;
Tim Murray4100e8e2015-03-30 12:27:28 -0700139 RSStructType = rsScriptType;
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700140 break;
141 case RS_TYPE_TYPE:
Tim Murrayb7bce742014-11-03 16:17:30 -0800142 SetObj = rsTypeSetObj;
Tim Murray4100e8e2015-03-30 12:27:28 -0700143 RSStructType = rsTypeType;
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700144 break;
145 default:
Tim Murrayb7bce742014-11-03 16:17:30 -0800146 return false; // this is for graphics types and matrices; do nothing
147 }
148
Tim Murray4100e8e2015-03-30 12:27:28 -0700149
150 llvm::CastInst* CastedValue = llvm::CastInst::CreatePointerCast(V, RSStructType->getPointerTo(), "", Call);
151
Tim Murrayb7bce742014-11-03 16:17:30 -0800152 llvm::SmallVector<llvm::Value*, 2> SetObjParams;
Tim Murray4100e8e2015-03-30 12:27:28 -0700153 SetObjParams.push_back(CastedValue);
154 SetObjParams.push_back(CastedValue);
Tim Murrayb7bce742014-11-03 16:17:30 -0800155
156 llvm::CallInst::Create(SetObj, SetObjParams, "", Call);
Tim Murray4100e8e2015-03-30 12:27:28 -0700157
158
Tim Murrayb7bce742014-11-03 16:17:30 -0800159 return true;
160 }
161
162
163 // this only modifies .helper functions that take certain RS base object types
164 virtual bool runOnFunction(llvm::Function &F) override {
165 if (!F.getName().startswith(".helper"))
166 return false;
167
168 bool changed = false;
169 const llvm::Function::ArgumentListType &argList(F.getArgumentList());
170 bool containsBaseObj = false;
171
172 // .helper methods should have one arg only, an anonymous struct
173 // that struct may contain BaseObjs
174 for (auto arg = argList.begin(); arg != argList.end(); arg++) {
175 llvm::Type *argType = arg->getType();
176 if (!argType->isPointerTy() || !argType->getPointerElementType()->isStructTy())
177 continue;
178
179 llvm::StructType *argStructType = llvm::dyn_cast<llvm::StructType>(argType->getPointerElementType());
180
181 for (unsigned int i = 0; i < argStructType->getNumElements(); i++) {
182 llvm::Type *currentType = argStructType->getElementType(i);
183 if (currentType->isStructTy() && currentType->getStructName().startswith("struct.rs_")) {
184 containsBaseObj = true;
185 }
186 }
187 break;
188 }
189
190
191 if (containsBaseObj) {
192 // modify the thing that should not be
193 auto &BBList(F.getBasicBlockList());
194 for (auto &BB : BBList) {
195 auto &InstList(BB.getInstList());
196 for (auto &Inst : InstList) {
197 // don't care about anything except call instructions that we didn't already add
198 if (llvm::CallInst *call = llvm::dyn_cast<llvm::CallInst>(&Inst)) {
199 for (unsigned int i = 0; i < call->getNumArgOperands(); i++) {
200 llvm::Value *V = call->getArgOperand(i);
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700201 llvm::Type *T = V->getType();
202 enum RsDataType DT = RS_TYPE_NONE;
203 if (T->isPointerTy() && T->getPointerElementType()->isStructTy()) {
204 DT = getRsDataTypeForType(T->getPointerElementType());
205 }
206 if (DT != RS_TYPE_NONE) {
Tim Murrayb7bce742014-11-03 16:17:30 -0800207 // generate the new call instruction and insert it
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700208 changed |= insertSetObjectHelper(call, V, DT);
Tim Murrayb7bce742014-11-03 16:17:30 -0800209 }
210 }
211 }
212 }
213 }
214 }
215
216 return changed;
217 }
218
Stephen Hines57936132014-11-25 17:54:59 -0800219 virtual const char *getPassName() const override {
Tim Murrayb7bce742014-11-03 16:17:30 -0800220 return ".helper method expansion for large RS objects";
221 }
222}; // end RSInvokeHelperPass class
223} // end anonymous namespace
224
225char RSInvokeHelperPass::ID = 0;
226
227namespace bcc {
228
229llvm::FunctionPass *
230createRSInvokeHelperPass(){
231 return new RSInvokeHelperPass();
232}
233
234}