blob: 170c2c6b160c291df5807052291cd647be14b4b5 [file] [log] [blame]
Yang Nia4ded132014-11-17 17:44:08 -08001/*
2 * Copyright 2015, 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 "RSScriptGroupFusion.h"
Yang Nia4ded132014-11-17 17:44:08 -080018
Jean-Luc Brouilleta2dd52f2017-02-16 20:57:26 -080019#include "Assert.h"
20#include "Log.h"
Yang Nia4ded132014-11-17 17:44:08 -080021#include "bcc/BCCContext.h"
Yang Nia4ded132014-11-17 17:44:08 -080022#include "bcc/Source.h"
Yang Nia4ded132014-11-17 17:44:08 -080023#include "bcinfo/MetadataExtractor.h"
Yang Ni0ab50b82015-02-16 12:31:56 -080024#include "llvm/ADT/StringExtras.h"
Yang Nia4ded132014-11-17 17:44:08 -080025#include "llvm/IR/DataLayout.h"
26#include "llvm/IR/IRBuilder.h"
27#include "llvm/IR/Module.h"
Yang Ni531d08c2015-06-29 11:05:51 -070028#include "llvm/Support/raw_ostream.h"
Yang Nia4ded132014-11-17 17:44:08 -080029
30using llvm::Function;
Yang Ni0ab50b82015-02-16 12:31:56 -080031using llvm::Module;
Yang Nia4ded132014-11-17 17:44:08 -080032
Yang Nia4ded132014-11-17 17:44:08 -080033using std::string;
34
35namespace bcc {
36
37namespace {
38
Yang Ni0ab50b82015-02-16 12:31:56 -080039const Function* getInvokeFunction(const Source& source, const int slot,
40 Module* newModule) {
Pirama Arumuga Nainarf229c402016-03-06 23:05:45 -080041
42 bcinfo::MetadataExtractor &metadata = *source.getMetadata();
Yang Ni0ab50b82015-02-16 12:31:56 -080043 const char* functionName = metadata.getExportFuncNameList()[slot];
44 Function* func = newModule->getFunction(functionName);
45 // Materialize the function so that later the caller can inspect its argument
46 // and return types.
47 newModule->materialize(func);
48 return func;
49}
50
51const Function*
52getFunction(Module* mergedModule, const Source* source, const int slot,
53 uint32_t* signature) {
Yang Ni0ab50b82015-02-16 12:31:56 -080054
Pirama Arumuga Nainarf229c402016-03-06 23:05:45 -080055 bcinfo::MetadataExtractor &metadata = *source->getMetadata();
Yang Nia4ded132014-11-17 17:44:08 -080056 const char* functionName = metadata.getExportForEachNameList()[slot];
Stephen Hinesa108bc52015-04-15 13:20:00 -070057 if (functionName == nullptr || !functionName[0]) {
Yang Ni531d08c2015-06-29 11:05:51 -070058 ALOGE("Kernel fusion (module %s slot %d): failed to find kernel function",
59 source->getName().c_str(), slot);
Yang Nia4ded132014-11-17 17:44:08 -080060 return nullptr;
61 }
Yang Nia4ded132014-11-17 17:44:08 -080062
Yang Ni0ab50b82015-02-16 12:31:56 -080063 if (metadata.getExportForEachInputCountList()[slot] > 1) {
Yang Ni531d08c2015-06-29 11:05:51 -070064 ALOGE("Kernel fusion (module %s function %s): cannot handle multiple inputs",
65 source->getName().c_str(), functionName);
Yang Nia4ded132014-11-17 17:44:08 -080066 return nullptr;
67 }
Yang Ni0ab50b82015-02-16 12:31:56 -080068
69 if (signature != nullptr) {
70 *signature = metadata.getExportForEachSignatureList()[slot];
71 }
72
73 const Function* function = mergedModule->getFunction(functionName);
74
75 return function;
Yang Nia4ded132014-11-17 17:44:08 -080076}
77
Yang Ni8c12d612015-06-19 16:02:38 -070078// The whitelist of supported signature bits. Context or user data arguments are
79// not currently supported in kernel fusion. To support them or any new kinds of
80// arguments in the future, it requires not only listing the signature bits here,
81// but also implementing additional necessary fusion logic in the getFusedFuncSig(),
82// getFusedFuncType(), and fuseKernels() functions below.
Yang Ni0ab50b82015-02-16 12:31:56 -080083constexpr uint32_t ExpectedSignatureBits =
84 bcinfo::MD_SIG_In |
85 bcinfo::MD_SIG_Out |
86 bcinfo::MD_SIG_X |
87 bcinfo::MD_SIG_Y |
88 bcinfo::MD_SIG_Z |
89 bcinfo::MD_SIG_Kernel;
Yang Nia4ded132014-11-17 17:44:08 -080090
Yang Ni0ab50b82015-02-16 12:31:56 -080091int getFusedFuncSig(const std::vector<Source*>& sources,
92 const std::vector<int>& slots,
93 uint32_t* retSig) {
94 *retSig = 0;
95 uint32_t firstSignature = 0;
96 uint32_t signature = 0;
97 auto slotIter = slots.begin();
98 for (const Source* source : sources) {
99 const int slot = *slotIter++;
Pirama Arumuga Nainarf229c402016-03-06 23:05:45 -0800100 bcinfo::MetadataExtractor &metadata = *source->getMetadata();
Yang Nia4ded132014-11-17 17:44:08 -0800101
102 if (metadata.getExportForEachInputCountList()[slot] > 1) {
Yang Ni531d08c2015-06-29 11:05:51 -0700103 ALOGE("Kernel fusion (module %s slot %d): cannot handle multiple inputs",
104 source->getName().c_str(), slot);
Yang Ni0ab50b82015-02-16 12:31:56 -0800105 return -1;
Yang Nia4ded132014-11-17 17:44:08 -0800106 }
107
Yang Ni0ab50b82015-02-16 12:31:56 -0800108 signature = metadata.getExportForEachSignatureList()[slot];
109 if (signature & ~ExpectedSignatureBits) {
Yang Ni531d08c2015-06-29 11:05:51 -0700110 ALOGE("Kernel fusion (module %s slot %d): Unexpected signature %x",
111 source->getName().c_str(), slot, signature);
Yang Ni0ab50b82015-02-16 12:31:56 -0800112 return -1;
Yang Nia4ded132014-11-17 17:44:08 -0800113 }
114
Yang Ni0ab50b82015-02-16 12:31:56 -0800115 if (firstSignature == 0) {
116 firstSignature = signature;
117 }
118
119 *retSig |= signature;
Yang Nia4ded132014-11-17 17:44:08 -0800120 }
Yang Ni0ab50b82015-02-16 12:31:56 -0800121
122 if (!bcinfo::MetadataExtractor::hasForEachSignatureIn(firstSignature)) {
123 *retSig &= ~bcinfo::MD_SIG_In;
124 }
125
126 if (!bcinfo::MetadataExtractor::hasForEachSignatureOut(signature)) {
127 *retSig &= ~bcinfo::MD_SIG_Out;
128 }
129
130 return 0;
131}
132
133llvm::FunctionType* getFusedFuncType(bcc::BCCContext& Context,
134 const std::vector<Source*>& sources,
135 const std::vector<int>& slots,
136 Module* M,
137 uint32_t* signature) {
138 int error = getFusedFuncSig(sources, slots, signature);
139
140 if (error < 0) {
141 return nullptr;
142 }
143
144 const Function* firstF = getFunction(M, sources.front(), slots.front(), nullptr);
145
146 bccAssert (firstF != nullptr);
147
148 llvm::SmallVector<llvm::Type*, 8> ArgTys;
149
150 if (bcinfo::MetadataExtractor::hasForEachSignatureIn(*signature)) {
151 ArgTys.push_back(firstF->arg_begin()->getType());
152 }
153
154 llvm::Type* I32Ty = llvm::IntegerType::get(Context.getLLVMContext(), 32);
155 if (bcinfo::MetadataExtractor::hasForEachSignatureX(*signature)) {
156 ArgTys.push_back(I32Ty);
157 }
158 if (bcinfo::MetadataExtractor::hasForEachSignatureY(*signature)) {
159 ArgTys.push_back(I32Ty);
160 }
161 if (bcinfo::MetadataExtractor::hasForEachSignatureZ(*signature)) {
162 ArgTys.push_back(I32Ty);
163 }
164
165 const Function* lastF = getFunction(M, sources.back(), slots.back(), nullptr);
166
167 bccAssert (lastF != nullptr);
168
169 llvm::Type* retTy = lastF->getReturnType();
170
171 return llvm::FunctionType::get(retTy, ArgTys, false);
Yang Nia4ded132014-11-17 17:44:08 -0800172}
173
174} // anonymous namespace
175
Yang Ni0ab50b82015-02-16 12:31:56 -0800176bool fuseKernels(bcc::BCCContext& Context,
177 const std::vector<Source *>& sources,
178 const std::vector<int>& slots,
179 const std::string& fusedName,
180 Module* mergedModule) {
Yang Nia4ded132014-11-17 17:44:08 -0800181 bccAssert(sources.size() == slots.size() && "sources and slots differ in size");
182
Yang Ni8c12d612015-06-19 16:02:38 -0700183 uint32_t fusedFunctionSignature;
Yang Nia4ded132014-11-17 17:44:08 -0800184
Yang Ni0ab50b82015-02-16 12:31:56 -0800185 llvm::FunctionType* fusedType =
Yang Ni8c12d612015-06-19 16:02:38 -0700186 getFusedFuncType(Context, sources, slots, mergedModule, &fusedFunctionSignature);
Yang Ni0ab50b82015-02-16 12:31:56 -0800187
188 if (fusedType == nullptr) {
189 return false;
Yang Nia4ded132014-11-17 17:44:08 -0800190 }
Yang Ni0ab50b82015-02-16 12:31:56 -0800191
Yang Nia4ded132014-11-17 17:44:08 -0800192 Function* fusedKernel =
Yang Ni0ab50b82015-02-16 12:31:56 -0800193 (Function*)(mergedModule->getOrInsertFunction(fusedName, fusedType));
Yang Nia4ded132014-11-17 17:44:08 -0800194
Yang Ni0ab50b82015-02-16 12:31:56 -0800195 llvm::LLVMContext& ctxt = Context.getLLVMContext();
196
197 llvm::BasicBlock* block = llvm::BasicBlock::Create(ctxt, "entry", fusedKernel);
Yang Nia4ded132014-11-17 17:44:08 -0800198 llvm::IRBuilder<> builder(block);
199
200 Function::arg_iterator argIter = fusedKernel->arg_begin();
Yang Ni0ab50b82015-02-16 12:31:56 -0800201
202 llvm::Value* dataElement = nullptr;
Yang Ni8c12d612015-06-19 16:02:38 -0700203 if (bcinfo::MetadataExtractor::hasForEachSignatureIn(fusedFunctionSignature)) {
Pirama Arumuga Nainarf229c402016-03-06 23:05:45 -0800204 dataElement = &*(argIter++);
Yang Ni0ab50b82015-02-16 12:31:56 -0800205 dataElement->setName("DataIn");
206 }
207
208 llvm::Value* X = nullptr;
Yang Ni8c12d612015-06-19 16:02:38 -0700209 if (bcinfo::MetadataExtractor::hasForEachSignatureX(fusedFunctionSignature)) {
Pirama Arumuga Nainarf229c402016-03-06 23:05:45 -0800210 X = &*(argIter++);
Yang Ni8c12d612015-06-19 16:02:38 -0700211 X->setName("x");
Yang Ni0ab50b82015-02-16 12:31:56 -0800212 }
213
214 llvm::Value* Y = nullptr;
Yang Ni8c12d612015-06-19 16:02:38 -0700215 if (bcinfo::MetadataExtractor::hasForEachSignatureY(fusedFunctionSignature)) {
Pirama Arumuga Nainarf229c402016-03-06 23:05:45 -0800216 Y = &*(argIter++);
Yang Ni8c12d612015-06-19 16:02:38 -0700217 Y->setName("y");
Yang Ni0ab50b82015-02-16 12:31:56 -0800218 }
219
220 llvm::Value* Z = nullptr;
Yang Ni8c12d612015-06-19 16:02:38 -0700221 if (bcinfo::MetadataExtractor::hasForEachSignatureZ(fusedFunctionSignature)) {
Pirama Arumuga Nainarf229c402016-03-06 23:05:45 -0800222 Z = &*(argIter++);
Yang Ni8c12d612015-06-19 16:02:38 -0700223 Z->setName("z");
Yang Ni0ab50b82015-02-16 12:31:56 -0800224 }
Yang Nia4ded132014-11-17 17:44:08 -0800225
226 auto slotIter = slots.begin();
227 for (const Source* source : sources) {
Yang Ni531d08c2015-06-29 11:05:51 -0700228 int slot = *slotIter;
Yang Nia4ded132014-11-17 17:44:08 -0800229
Yang Ni8c12d612015-06-19 16:02:38 -0700230 uint32_t inputFunctionSignature;
231 const Function* inputFunction =
232 getFunction(mergedModule, source, slot, &inputFunctionSignature);
233 if (inputFunction == nullptr) {
Yang Ni531d08c2015-06-29 11:05:51 -0700234 // Either failed to find the kernel function, or the function has multiple inputs.
Yang Ni8c12d612015-06-19 16:02:38 -0700235 return false;
236 }
Yang Ni0ab50b82015-02-16 12:31:56 -0800237
Yang Ni8c12d612015-06-19 16:02:38 -0700238 // Don't try to fuse a non-kernel
239 if (!bcinfo::MetadataExtractor::hasForEachSignatureKernel(inputFunctionSignature)) {
Yang Ni531d08c2015-06-29 11:05:51 -0700240 ALOGE("Kernel fusion (module %s function %s): not a kernel",
241 source->getName().c_str(), inputFunction->getName().str().c_str());
Yang Ni0ab50b82015-02-16 12:31:56 -0800242 return false;
Yang Nia4ded132014-11-17 17:44:08 -0800243 }
Yang Nia4ded132014-11-17 17:44:08 -0800244
245 std::vector<llvm::Value*> args;
Yang Ni8c12d612015-06-19 16:02:38 -0700246
247 if (bcinfo::MetadataExtractor::hasForEachSignatureIn(inputFunctionSignature)) {
248 if (dataElement == nullptr) {
Yang Ni531d08c2015-06-29 11:05:51 -0700249 ALOGE("Kernel fusion (module %s function %s): expected input, but got null",
250 source->getName().c_str(), inputFunction->getName().str().c_str());
Yang Ni8c12d612015-06-19 16:02:38 -0700251 return false;
252 }
253
254 const llvm::FunctionType* funcTy = inputFunction->getFunctionType();
255 llvm::Type* firstArgType = funcTy->getParamType(0);
256
Yang Ni531d08c2015-06-29 11:05:51 -0700257 if (dataElement->getType() != firstArgType) {
258 std::string msg;
259 llvm::raw_string_ostream rso(msg);
260 rso << "Mismatching argument type, expected ";
261 firstArgType->print(rso);
262 rso << ", received ";
263 dataElement->getType()->print(rso);
264 ALOGE("Kernel fusion (module %s function %s): %s", source->getName().c_str(),
265 inputFunction->getName().str().c_str(), rso.str().c_str());
Yang Ni8c12d612015-06-19 16:02:38 -0700266 return false;
267 }
268
Yang Ni0ab50b82015-02-16 12:31:56 -0800269 args.push_back(dataElement);
Yang Ni8c12d612015-06-19 16:02:38 -0700270 } else {
271 // Only the first kernel in a batch is allowed to have no input
272 if (slotIter != slots.begin()) {
Yang Ni531d08c2015-06-29 11:05:51 -0700273 ALOGE("Kernel fusion (module %s function %s): function not first in batch takes no input",
274 source->getName().c_str(), inputFunction->getName().str().c_str());
Yang Ni8c12d612015-06-19 16:02:38 -0700275 return false;
276 }
Yang Ni0ab50b82015-02-16 12:31:56 -0800277 }
278
Yang Ni8c12d612015-06-19 16:02:38 -0700279 if (bcinfo::MetadataExtractor::hasForEachSignatureX(inputFunctionSignature)) {
Yang Nia4ded132014-11-17 17:44:08 -0800280 args.push_back(X);
Yang Ni0ab50b82015-02-16 12:31:56 -0800281 }
282
Yang Ni8c12d612015-06-19 16:02:38 -0700283 if (bcinfo::MetadataExtractor::hasForEachSignatureY(inputFunctionSignature)) {
Yang Ni0ab50b82015-02-16 12:31:56 -0800284 args.push_back(Y);
285 }
286
Yang Ni8c12d612015-06-19 16:02:38 -0700287 if (bcinfo::MetadataExtractor::hasForEachSignatureZ(inputFunctionSignature)) {
Yang Ni0ab50b82015-02-16 12:31:56 -0800288 args.push_back(Z);
Yang Nia4ded132014-11-17 17:44:08 -0800289 }
290
Yang Ni8c12d612015-06-19 16:02:38 -0700291 dataElement = builder.CreateCall((llvm::Value*)inputFunction, args);
Yang Ni531d08c2015-06-29 11:05:51 -0700292
293 slotIter++;
Yang Nia4ded132014-11-17 17:44:08 -0800294 }
295
Yang Ni0ab50b82015-02-16 12:31:56 -0800296 if (fusedKernel->getReturnType()->isVoidTy()) {
297 builder.CreateRetVoid();
298 } else {
299 builder.CreateRet(dataElement);
300 }
Yang Nia4ded132014-11-17 17:44:08 -0800301
Yang Ni0ab50b82015-02-16 12:31:56 -0800302 llvm::NamedMDNode* ExportForEachNameMD =
303 mergedModule->getOrInsertNamedMetadata("#rs_export_foreach_name");
Yang Nia4ded132014-11-17 17:44:08 -0800304
Yang Ni0ab50b82015-02-16 12:31:56 -0800305 llvm::MDString* nameMDStr = llvm::MDString::get(ctxt, fusedName);
306 llvm::MDNode* nameMDNode = llvm::MDNode::get(ctxt, nameMDStr);
307 ExportForEachNameMD->addOperand(nameMDNode);
308
309 llvm::NamedMDNode* ExportForEachMD =
310 mergedModule->getOrInsertNamedMetadata("#rs_export_foreach");
311 llvm::MDString* sigMDStr = llvm::MDString::get(ctxt,
Pirama Arumuga Nainarf5b49a02016-09-15 23:04:25 -0700312 llvm::utostr(fusedFunctionSignature));
Yang Ni0ab50b82015-02-16 12:31:56 -0800313 llvm::MDNode* sigMDNode = llvm::MDNode::get(ctxt, sigMDStr);
314 ExportForEachMD->addOperand(sigMDNode);
315
316 return true;
317}
318
319bool renameInvoke(BCCContext& Context, const Source* source, const int slot,
320 const std::string& newName, Module* module) {
321 const llvm::Function* F = getInvokeFunction(*source, slot, module);
322 std::vector<llvm::Type*> params;
323 for (auto I = F->arg_begin(), E = F->arg_end(); I != E; ++I) {
324 params.push_back(I->getType());
325 }
326 llvm::Type* returnTy = F->getReturnType();
327
328 llvm::FunctionType* batchFuncTy =
329 llvm::FunctionType::get(returnTy, params, false);
330
331 llvm::Function* newF =
332 llvm::Function::Create(batchFuncTy,
333 llvm::GlobalValue::ExternalLinkage, newName,
334 module);
335
336 llvm::BasicBlock* block = llvm::BasicBlock::Create(Context.getLLVMContext(),
337 "entry", newF);
338 llvm::IRBuilder<> builder(block);
339
340 llvm::Function::arg_iterator argIter = newF->arg_begin();
Pirama Arumuga Nainarf229c402016-03-06 23:05:45 -0800341 llvm::Value* arg1 = &*(argIter++);
Yang Ni0ab50b82015-02-16 12:31:56 -0800342 builder.CreateCall((llvm::Value*)F, arg1);
343
344 builder.CreateRetVoid();
345
346 llvm::NamedMDNode* ExportFuncNameMD =
347 module->getOrInsertNamedMetadata("#rs_export_func");
348 llvm::MDString* strMD = llvm::MDString::get(module->getContext(), newName);
349 llvm::MDNode* nodeMD = llvm::MDNode::get(module->getContext(), strMD);
350 ExportFuncNameMD->addOperand(nodeMD);
351
352 return true;
Yang Nia4ded132014-11-17 17:44:08 -0800353}
354
355} // namespace bcc