1 /*
2 * Copyright 2012, 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
21 #include <cstdlib>
22 #include <functional>
23 #include <unordered_set>
24
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/Pass.h>
32 #include <llvm/Support/raw_ostream.h>
33 #include <llvm/IR/DataLayout.h>
34 #include <llvm/IR/Function.h>
35 #include <llvm/IR/Type.h>
36 #include <llvm/Transforms/Utils/BasicBlockUtils.h>
37
38 #include "bcc/Config/Config.h"
39 #include "bcc/Support/Log.h"
40
41 #include "bcinfo/MetadataExtractor.h"
42
43 #ifndef __DISABLE_ASSERTS
44 // Only used in bccAssert()
45 const int kNumExpandedForeachParams = 4;
46 const int kNumExpandedReduceAccumulatorParams = 4;
47 #endif
48
49 const char kRenderScriptTBAARootName[] = "RenderScript Distinct TBAA";
50 const char kRenderScriptTBAANodeName[] = "RenderScript TBAA";
51
52 using namespace bcc;
53
54 namespace {
55
56 static const bool gEnableRsTbaa = true;
57
58 /* RSKernelExpandPass - This pass operates on functions that are able
59 * to be called via rsForEach(), "foreach_<NAME>", or
60 * "reduce_<NAME>". We create an inner loop for the function to be
61 * invoked over the appropriate data cells of the input/output
62 * allocations (adjusting other relevant parameters as we go). We
63 * support doing this for any forEach or reduce style compute
64 * kernels. The new function name is the original function name
65 * followed by ".expand". Note that we still generate code for the
66 * original function.
67 */
68 class RSKernelExpandPass : public llvm::ModulePass {
69 public:
70 static char ID;
71
72 private:
73 static const size_t RS_KERNEL_INPUT_LIMIT = 8; // see frameworks/base/libs/rs/cpu_ref/rsCpuCoreRuntime.h
74
75 typedef std::unordered_set<llvm::Function *> FunctionSet;
76
77 enum RsLaunchDimensionsField {
78 RsLaunchDimensionsFieldX,
79 RsLaunchDimensionsFieldY,
80 RsLaunchDimensionsFieldZ,
81 RsLaunchDimensionsFieldLod,
82 RsLaunchDimensionsFieldFace,
83 RsLaunchDimensionsFieldArray,
84
85 RsLaunchDimensionsFieldCount
86 };
87
88 enum RsExpandKernelDriverInfoPfxField {
89 RsExpandKernelDriverInfoPfxFieldInPtr,
90 RsExpandKernelDriverInfoPfxFieldInStride,
91 RsExpandKernelDriverInfoPfxFieldInLen,
92 RsExpandKernelDriverInfoPfxFieldOutPtr,
93 RsExpandKernelDriverInfoPfxFieldOutStride,
94 RsExpandKernelDriverInfoPfxFieldOutLen,
95 RsExpandKernelDriverInfoPfxFieldDim,
96 RsExpandKernelDriverInfoPfxFieldCurrent,
97 RsExpandKernelDriverInfoPfxFieldUsr,
98 RsExpandKernelDriverInfoPfxFieldUsLenr,
99
100 RsExpandKernelDriverInfoPfxFieldCount
101 };
102
103 llvm::Module *Module;
104 llvm::LLVMContext *Context;
105
106 /*
107 * Pointers to LLVM type information for the the function signatures
108 * for expanded functions. These must be re-calculated for each module
109 * the pass is run on.
110 */
111 llvm::FunctionType *ExpandedForEachType;
112 llvm::Type *RsExpandKernelDriverInfoPfxTy;
113
114 uint32_t mExportForEachCount;
115 const char **mExportForEachNameList;
116 const uint32_t *mExportForEachSignatureList;
117
118 // Turns on optimization of allocation stride values.
119 bool mEnableStepOpt;
120
getRootSignature(llvm::Function * Function)121 uint32_t getRootSignature(llvm::Function *Function) {
122 const llvm::NamedMDNode *ExportForEachMetadata =
123 Module->getNamedMetadata("#rs_export_foreach");
124
125 if (!ExportForEachMetadata) {
126 llvm::SmallVector<llvm::Type*, 8> RootArgTys;
127 for (llvm::Function::arg_iterator B = Function->arg_begin(),
128 E = Function->arg_end();
129 B != E;
130 ++B) {
131 RootArgTys.push_back(B->getType());
132 }
133
134 // For pre-ICS bitcode, we may not have signature information. In that
135 // case, we use the size of the RootArgTys to select the number of
136 // arguments.
137 return (1 << RootArgTys.size()) - 1;
138 }
139
140 if (ExportForEachMetadata->getNumOperands() == 0) {
141 return 0;
142 }
143
144 bccAssert(ExportForEachMetadata->getNumOperands() > 0);
145
146 // We only handle the case for legacy root() functions here, so this is
147 // hard-coded to look at only the first such function.
148 llvm::MDNode *SigNode = ExportForEachMetadata->getOperand(0);
149 if (SigNode != nullptr && SigNode->getNumOperands() == 1) {
150 llvm::Metadata *SigMD = SigNode->getOperand(0);
151 if (llvm::MDString *SigS = llvm::dyn_cast<llvm::MDString>(SigMD)) {
152 llvm::StringRef SigString = SigS->getString();
153 uint32_t Signature = 0;
154 if (SigString.getAsInteger(10, Signature)) {
155 ALOGE("Non-integer signature value '%s'", SigString.str().c_str());
156 return 0;
157 }
158 return Signature;
159 }
160 }
161
162 return 0;
163 }
164
isStepOptSupported(llvm::Type * AllocType)165 bool isStepOptSupported(llvm::Type *AllocType) {
166
167 llvm::PointerType *PT = llvm::dyn_cast<llvm::PointerType>(AllocType);
168 llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(*Context);
169
170 if (mEnableStepOpt) {
171 return false;
172 }
173
174 if (AllocType == VoidPtrTy) {
175 return false;
176 }
177
178 if (!PT) {
179 return false;
180 }
181
182 // remaining conditions are 64-bit only
183 if (VoidPtrTy->getPrimitiveSizeInBits() == 32) {
184 return true;
185 }
186
187 // coerce suggests an upconverted struct type, which we can't support
188 if (AllocType->getStructName().find("coerce") != llvm::StringRef::npos) {
189 return false;
190 }
191
192 // 2xi64 and i128 suggest an upconverted struct type, which are also unsupported
193 llvm::Type *V2xi64Ty = llvm::VectorType::get(llvm::Type::getInt64Ty(*Context), 2);
194 llvm::Type *Int128Ty = llvm::Type::getIntNTy(*Context, 128);
195 if (AllocType == V2xi64Ty || AllocType == Int128Ty) {
196 return false;
197 }
198
199 return true;
200 }
201
202 // Get the actual value we should use to step through an allocation.
203 //
204 // Normally the value we use to step through an allocation is given to us by
205 // the driver. However, for certain primitive data types, we can derive an
206 // integer constant for the step value. We use this integer constant whenever
207 // possible to allow further compiler optimizations to take place.
208 //
209 // DL - Target Data size/layout information.
210 // T - Type of allocation (should be a pointer).
211 // OrigStep - Original step increment (root.expand() input from driver).
getStepValue(llvm::DataLayout * DL,llvm::Type * AllocType,llvm::Value * OrigStep)212 llvm::Value *getStepValue(llvm::DataLayout *DL, llvm::Type *AllocType,
213 llvm::Value *OrigStep) {
214 bccAssert(DL);
215 bccAssert(AllocType);
216 bccAssert(OrigStep);
217 llvm::PointerType *PT = llvm::dyn_cast<llvm::PointerType>(AllocType);
218 if (isStepOptSupported(AllocType)) {
219 llvm::Type *ET = PT->getElementType();
220 uint64_t ETSize = DL->getTypeAllocSize(ET);
221 llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context);
222 return llvm::ConstantInt::get(Int32Ty, ETSize);
223 } else {
224 return OrigStep;
225 }
226 }
227
228 /// Builds the types required by the pass for the given context.
buildTypes(void)229 void buildTypes(void) {
230 // Create the RsLaunchDimensionsTy and RsExpandKernelDriverInfoPfxTy structs.
231
232 llvm::Type *Int8Ty = llvm::Type::getInt8Ty(*Context);
233 llvm::Type *Int8PtrTy = Int8Ty->getPointerTo();
234 llvm::Type *Int8PtrArrayInputLimitTy = llvm::ArrayType::get(Int8PtrTy, RS_KERNEL_INPUT_LIMIT);
235 llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context);
236 llvm::Type *Int32ArrayInputLimitTy = llvm::ArrayType::get(Int32Ty, RS_KERNEL_INPUT_LIMIT);
237 llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(*Context);
238 llvm::Type *Int32Array4Ty = llvm::ArrayType::get(Int32Ty, 4);
239
240 /* Defined in frameworks/base/libs/rs/cpu_ref/rsCpuCore.h:
241 *
242 * struct RsLaunchDimensions {
243 * uint32_t x;
244 * uint32_t y;
245 * uint32_t z;
246 * uint32_t lod;
247 * uint32_t face;
248 * uint32_t array[4];
249 * };
250 */
251 llvm::SmallVector<llvm::Type*, RsLaunchDimensionsFieldCount> RsLaunchDimensionsTypes;
252 RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t x
253 RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t y
254 RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t z
255 RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t lod
256 RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t face
257 RsLaunchDimensionsTypes.push_back(Int32Array4Ty); // uint32_t array[4]
258 llvm::StructType *RsLaunchDimensionsTy =
259 llvm::StructType::create(RsLaunchDimensionsTypes, "RsLaunchDimensions");
260
261 /* Defined as the beginning of RsExpandKernelDriverInfo in frameworks/base/libs/rs/cpu_ref/rsCpuCoreRuntime.h:
262 *
263 * struct RsExpandKernelDriverInfoPfx {
264 * const uint8_t *inPtr[RS_KERNEL_INPUT_LIMIT];
265 * uint32_t inStride[RS_KERNEL_INPUT_LIMIT];
266 * uint32_t inLen;
267 *
268 * uint8_t *outPtr[RS_KERNEL_INPUT_LIMIT];
269 * uint32_t outStride[RS_KERNEL_INPUT_LIMIT];
270 * uint32_t outLen;
271 *
272 * // Dimension of the launch
273 * RsLaunchDimensions dim;
274 *
275 * // The walking iterator of the launch
276 * RsLaunchDimensions current;
277 *
278 * const void *usr;
279 * uint32_t usrLen;
280 *
281 * // Items below this line are not used by the compiler and can be change in the driver.
282 * // So the compiler must assume there are an unknown number of fields of unknown type
283 * // beginning here.
284 * };
285 *
286 * The name "RsExpandKernelDriverInfoPfx" is known to RSInvariantPass (RSInvariant.cpp).
287 */
288 llvm::SmallVector<llvm::Type*, RsExpandKernelDriverInfoPfxFieldCount> RsExpandKernelDriverInfoPfxTypes;
289 RsExpandKernelDriverInfoPfxTypes.push_back(Int8PtrArrayInputLimitTy); // const uint8_t *inPtr[RS_KERNEL_INPUT_LIMIT]
290 RsExpandKernelDriverInfoPfxTypes.push_back(Int32ArrayInputLimitTy); // uint32_t inStride[RS_KERNEL_INPUT_LIMIT]
291 RsExpandKernelDriverInfoPfxTypes.push_back(Int32Ty); // uint32_t inLen
292 RsExpandKernelDriverInfoPfxTypes.push_back(Int8PtrArrayInputLimitTy); // uint8_t *outPtr[RS_KERNEL_INPUT_LIMIT]
293 RsExpandKernelDriverInfoPfxTypes.push_back(Int32ArrayInputLimitTy); // uint32_t outStride[RS_KERNEL_INPUT_LIMIT]
294 RsExpandKernelDriverInfoPfxTypes.push_back(Int32Ty); // uint32_t outLen
295 RsExpandKernelDriverInfoPfxTypes.push_back(RsLaunchDimensionsTy); // RsLaunchDimensions dim
296 RsExpandKernelDriverInfoPfxTypes.push_back(RsLaunchDimensionsTy); // RsLaunchDimensions current
297 RsExpandKernelDriverInfoPfxTypes.push_back(VoidPtrTy); // const void *usr
298 RsExpandKernelDriverInfoPfxTypes.push_back(Int32Ty); // uint32_t usrLen
299 RsExpandKernelDriverInfoPfxTy =
300 llvm::StructType::create(RsExpandKernelDriverInfoPfxTypes, "RsExpandKernelDriverInfoPfx");
301
302 // Create the function type for expanded kernels.
303 llvm::Type *VoidTy = llvm::Type::getVoidTy(*Context);
304
305 llvm::Type *RsExpandKernelDriverInfoPfxPtrTy = RsExpandKernelDriverInfoPfxTy->getPointerTo();
306 // void (const RsExpandKernelDriverInfoPfxTy *p, uint32_t x1, uint32_t x2, uint32_t outstep)
307 ExpandedForEachType = llvm::FunctionType::get(VoidTy,
308 {RsExpandKernelDriverInfoPfxPtrTy, Int32Ty, Int32Ty, Int32Ty}, false);
309 }
310
311 /// @brief Create skeleton of the expanded foreach kernel.
312 ///
313 /// This creates a function with the following signature:
314 ///
315 /// void (const RsForEachStubParamStruct *p, uint32_t x1, uint32_t x2,
316 /// uint32_t outstep)
317 ///
createEmptyExpandedForEachKernel(llvm::StringRef OldName)318 llvm::Function *createEmptyExpandedForEachKernel(llvm::StringRef OldName) {
319 llvm::Function *ExpandedFunction =
320 llvm::Function::Create(ExpandedForEachType,
321 llvm::GlobalValue::ExternalLinkage,
322 OldName + ".expand", Module);
323 bccAssert(ExpandedFunction->arg_size() == kNumExpandedForeachParams);
324 llvm::Function::arg_iterator AI = ExpandedFunction->arg_begin();
325 (AI++)->setName("p");
326 (AI++)->setName("x1");
327 (AI++)->setName("x2");
328 (AI++)->setName("arg_outstep");
329 llvm::BasicBlock *Begin = llvm::BasicBlock::Create(*Context, "Begin",
330 ExpandedFunction);
331 llvm::IRBuilder<> Builder(Begin);
332 Builder.CreateRetVoid();
333 return ExpandedFunction;
334 }
335
336 // Create skeleton of a general reduce kernel's expanded accumulator.
337 //
338 // This creates a function with the following signature:
339 //
340 // void @func.expand(%RsExpandKernelDriverInfoPfx* nocapture %p,
341 // i32 %x1, i32 %x2, accumType* nocapture %accum)
342 //
createEmptyExpandedReduceAccumulator(llvm::StringRef OldName,llvm::Type * AccumArgTy)343 llvm::Function *createEmptyExpandedReduceAccumulator(llvm::StringRef OldName,
344 llvm::Type *AccumArgTy) {
345 llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context);
346 llvm::Type *VoidTy = llvm::Type::getVoidTy(*Context);
347 llvm::FunctionType *ExpandedReduceAccumulatorType =
348 llvm::FunctionType::get(VoidTy,
349 {RsExpandKernelDriverInfoPfxTy->getPointerTo(),
350 Int32Ty, Int32Ty, AccumArgTy}, false);
351 llvm::Function *FnExpandedAccumulator =
352 llvm::Function::Create(ExpandedReduceAccumulatorType,
353 llvm::GlobalValue::ExternalLinkage,
354 OldName + ".expand", Module);
355 bccAssert(FnExpandedAccumulator->arg_size() == kNumExpandedReduceAccumulatorParams);
356
357 llvm::Function::arg_iterator AI = FnExpandedAccumulator->arg_begin();
358
359 using llvm::Attribute;
360
361 llvm::Argument *Arg_p = &(*AI++);
362 Arg_p->setName("p");
363 Arg_p->addAttr(llvm::AttributeSet::get(*Context, Arg_p->getArgNo() + 1,
364 llvm::makeArrayRef(Attribute::NoCapture)));
365
366 llvm::Argument *Arg_x1 = &(*AI++);
367 Arg_x1->setName("x1");
368
369 llvm::Argument *Arg_x2 = &(*AI++);
370 Arg_x2->setName("x2");
371
372 llvm::Argument *Arg_accum = &(*AI++);
373 Arg_accum->setName("accum");
374 Arg_accum->addAttr(llvm::AttributeSet::get(*Context, Arg_accum->getArgNo() + 1,
375 llvm::makeArrayRef(Attribute::NoCapture)));
376
377 llvm::BasicBlock *Begin = llvm::BasicBlock::Create(*Context, "Begin",
378 FnExpandedAccumulator);
379 llvm::IRBuilder<> Builder(Begin);
380 Builder.CreateRetVoid();
381
382 return FnExpandedAccumulator;
383 }
384
385 /// @brief Create an empty loop
386 ///
387 /// Create a loop of the form:
388 ///
389 /// for (i = LowerBound; i < UpperBound; i++)
390 /// ;
391 ///
392 /// After the loop has been created, the builder is set such that
393 /// instructions can be added to the loop body.
394 ///
395 /// @param Builder The builder to use to build this loop. The current
396 /// position of the builder is the position the loop
397 /// will be inserted.
398 /// @param LowerBound The first value of the loop iterator
399 /// @param UpperBound The maximal value of the loop iterator
400 /// @param LoopIV A reference that will be set to the loop iterator.
401 /// @return The BasicBlock that will be executed after the loop.
createLoop(llvm::IRBuilder<> & Builder,llvm::Value * LowerBound,llvm::Value * UpperBound,llvm::Value ** LoopIV)402 llvm::BasicBlock *createLoop(llvm::IRBuilder<> &Builder,
403 llvm::Value *LowerBound,
404 llvm::Value *UpperBound,
405 llvm::Value **LoopIV) {
406 bccAssert(LowerBound->getType() == UpperBound->getType());
407
408 llvm::BasicBlock *CondBB, *AfterBB, *HeaderBB;
409 llvm::Value *Cond, *IVNext, *IV, *IVVar;
410
411 CondBB = Builder.GetInsertBlock();
412 AfterBB = llvm::SplitBlock(CondBB, &*Builder.GetInsertPoint(), nullptr, nullptr);
413 HeaderBB = llvm::BasicBlock::Create(*Context, "Loop", CondBB->getParent());
414
415 CondBB->getTerminator()->eraseFromParent();
416 Builder.SetInsertPoint(CondBB);
417
418 // decltype(LowerBound) *ivvar = alloca(sizeof(int))
419 // *ivvar = LowerBound
420 IVVar = Builder.CreateAlloca(LowerBound->getType(), nullptr, BCC_INDEX_VAR_NAME);
421 Builder.CreateStore(LowerBound, IVVar);
422
423 // if (LowerBound < Upperbound)
424 // goto LoopHeader
425 // else
426 // goto AfterBB
427 Cond = Builder.CreateICmpULT(LowerBound, UpperBound);
428 Builder.CreateCondBr(Cond, HeaderBB, AfterBB);
429
430 // LoopHeader:
431 // iv = *ivvar
432 // <insertion point here>
433 // iv.next = iv + 1
434 // *ivvar = iv.next
435 // if (iv.next < Upperbound)
436 // goto LoopHeader
437 // else
438 // goto AfterBB
439 // AfterBB:
440 Builder.SetInsertPoint(HeaderBB);
441 IV = Builder.CreateLoad(IVVar, "X");
442 IVNext = Builder.CreateNUWAdd(IV, Builder.getInt32(1));
443 Builder.CreateStore(IVNext, IVVar);
444 Cond = Builder.CreateICmpULT(IVNext, UpperBound);
445 Builder.CreateCondBr(Cond, HeaderBB, AfterBB);
446 AfterBB->setName("Exit");
447 Builder.SetInsertPoint(llvm::cast<llvm::Instruction>(IVNext));
448
449 // Record information about this loop.
450 *LoopIV = IV;
451 return AfterBB;
452 }
453
454 // Finish building the outgoing argument list for calling a ForEach-able function.
455 //
456 // ArgVector - on input, the non-special arguments
457 // on output, the non-special arguments combined with the special arguments
458 // from SpecialArgVector
459 // SpecialArgVector - special arguments (from ExpandSpecialArguments())
460 // SpecialArgContextIdx - return value of ExpandSpecialArguments()
461 // (position of context argument in SpecialArgVector)
462 // CalleeFunction - the ForEach-able function being called
463 // Builder - for inserting code into the caller function
464 template<unsigned int ArgVectorLen, unsigned int SpecialArgVectorLen>
finishArgList(llvm::SmallVector<llvm::Value *,ArgVectorLen> & ArgVector,const llvm::SmallVector<llvm::Value *,SpecialArgVectorLen> & SpecialArgVector,const int SpecialArgContextIdx,const llvm::Function & CalleeFunction,llvm::IRBuilder<> & CallerBuilder)465 void finishArgList( llvm::SmallVector<llvm::Value *, ArgVectorLen> &ArgVector,
466 const llvm::SmallVector<llvm::Value *, SpecialArgVectorLen> &SpecialArgVector,
467 const int SpecialArgContextIdx,
468 const llvm::Function &CalleeFunction,
469 llvm::IRBuilder<> &CallerBuilder) {
470 /* The context argument (if any) is a pointer to an opaque user-visible type that differs from
471 * the RsExpandKernelDriverInfoPfx type used in the function we are generating (although the
472 * two types represent the same thing). Therefore, we must introduce a pointer cast when
473 * generating a call to the kernel function.
474 */
475 const int ArgContextIdx =
476 SpecialArgContextIdx >= 0 ? (ArgVector.size() + SpecialArgContextIdx) : SpecialArgContextIdx;
477 ArgVector.append(SpecialArgVector.begin(), SpecialArgVector.end());
478 if (ArgContextIdx >= 0) {
479 llvm::Type *ContextArgType = nullptr;
480 int ArgIdx = ArgContextIdx;
481 for (const auto &Arg : CalleeFunction.getArgumentList()) {
482 if (!ArgIdx--) {
483 ContextArgType = Arg.getType();
484 break;
485 }
486 }
487 bccAssert(ContextArgType);
488 ArgVector[ArgContextIdx] = CallerBuilder.CreatePointerCast(ArgVector[ArgContextIdx], ContextArgType);
489 }
490 }
491
492 // GEPHelper() returns a SmallVector of values suitable for passing
493 // to IRBuilder::CreateGEP(), and SmallGEPIndices is a typedef for
494 // the returned data type. It is sized so that the SmallVector
495 // returned by GEPHelper() never needs to do a heap allocation for
496 // any list of GEP indices it encounters in the code.
497 typedef llvm::SmallVector<llvm::Value *, 3> SmallGEPIndices;
498
499 // Helper for turning a list of constant integer GEP indices into a
500 // SmallVector of llvm::Value*. The return value is suitable for
501 // passing to a GetElementPtrInst constructor or IRBuilder::CreateGEP().
502 //
503 // Inputs:
504 // I32Args should be integers which represent the index arguments
505 // to a GEP instruction.
506 //
507 // Returns:
508 // Returns a SmallVector of ConstantInts.
GEPHelper(const std::initializer_list<int32_t> I32Args)509 SmallGEPIndices GEPHelper(const std::initializer_list<int32_t> I32Args) {
510 SmallGEPIndices Out(I32Args.size());
511 llvm::IntegerType *I32Ty = llvm::Type::getInt32Ty(*Context);
512 std::transform(I32Args.begin(), I32Args.end(), Out.begin(),
513 [I32Ty](int32_t Arg) { return llvm::ConstantInt::get(I32Ty, Arg); });
514 return Out;
515 }
516
517 public:
RSKernelExpandPass(bool pEnableStepOpt=true)518 RSKernelExpandPass(bool pEnableStepOpt = true)
519 : ModulePass(ID), Module(nullptr), Context(nullptr),
520 mEnableStepOpt(pEnableStepOpt) {
521
522 }
523
getAnalysisUsage(llvm::AnalysisUsage & AU) const524 virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
525 // This pass does not use any other analysis passes, but it does
526 // add/wrap the existing functions in the module (thus altering the CFG).
527 }
528
529 // Build contribution to outgoing argument list for calling a
530 // ForEach-able function or a general reduction accumulator
531 // function, based on the special parameters of that function.
532 //
533 // Signature - metadata bits for the signature of the callee
534 // X, Arg_p - values derived directly from expanded function,
535 // suitable for computing arguments for the callee
536 // CalleeArgs - contribution is accumulated here
537 // Bump - invoked once for each contributed outgoing argument
538 // LoopHeaderInsertionPoint - an Instruction in the loop header, before which
539 // this function can insert loop-invariant loads
540 //
541 // Return value is the (zero-based) position of the context (Arg_p)
542 // argument in the CalleeArgs vector, or a negative value if the
543 // context argument is not placed in the CalleeArgs vector.
ExpandSpecialArguments(uint32_t Signature,llvm::Value * X,llvm::Value * Arg_p,llvm::IRBuilder<> & Builder,llvm::SmallVector<llvm::Value *,8> & CalleeArgs,std::function<void ()> Bump,llvm::Instruction * LoopHeaderInsertionPoint)544 int ExpandSpecialArguments(uint32_t Signature,
545 llvm::Value *X,
546 llvm::Value *Arg_p,
547 llvm::IRBuilder<> &Builder,
548 llvm::SmallVector<llvm::Value*, 8> &CalleeArgs,
549 std::function<void ()> Bump,
550 llvm::Instruction *LoopHeaderInsertionPoint) {
551
552 bccAssert(CalleeArgs.empty());
553
554 int Return = -1;
555 if (bcinfo::MetadataExtractor::hasForEachSignatureCtxt(Signature)) {
556 CalleeArgs.push_back(Arg_p);
557 Bump();
558 Return = CalleeArgs.size() - 1;
559 }
560
561 if (bcinfo::MetadataExtractor::hasForEachSignatureX(Signature)) {
562 CalleeArgs.push_back(X);
563 Bump();
564 }
565
566 if (bcinfo::MetadataExtractor::hasForEachSignatureY(Signature) ||
567 bcinfo::MetadataExtractor::hasForEachSignatureZ(Signature)) {
568 bccAssert(LoopHeaderInsertionPoint);
569
570 // Y and Z are loop invariant, so they can be hoisted out of the
571 // loop. Set the IRBuilder insertion point to the loop header.
572 auto OldInsertionPoint = Builder.saveIP();
573 Builder.SetInsertPoint(LoopHeaderInsertionPoint);
574
575 if (bcinfo::MetadataExtractor::hasForEachSignatureY(Signature)) {
576 SmallGEPIndices YValueGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldCurrent,
577 RsLaunchDimensionsFieldY}));
578 llvm::Value *YAddr = Builder.CreateInBoundsGEP(Arg_p, YValueGEP, "Y.gep");
579 CalleeArgs.push_back(Builder.CreateLoad(YAddr, "Y"));
580 Bump();
581 }
582
583 if (bcinfo::MetadataExtractor::hasForEachSignatureZ(Signature)) {
584 SmallGEPIndices ZValueGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldCurrent,
585 RsLaunchDimensionsFieldZ}));
586 llvm::Value *ZAddr = Builder.CreateInBoundsGEP(Arg_p, ZValueGEP, "Z.gep");
587 CalleeArgs.push_back(Builder.CreateLoad(ZAddr, "Z"));
588 Bump();
589 }
590
591 Builder.restoreIP(OldInsertionPoint);
592 }
593
594 return Return;
595 }
596
597 // Generate loop-invariant input processing setup code for an expanded
598 // ForEach-able function or an expanded general reduction accumulator
599 // function.
600 //
601 // LoopHeader - block at the end of which the setup code will be inserted
602 // Arg_p - RSKernelDriverInfo pointer passed to the expanded function
603 // TBAAPointer - metadata for marking loads of pointer values out of RSKernelDriverInfo
604 // ArgIter - iterator pointing to first input of the UNexpanded function
605 // NumInputs - number of inputs (NOT number of ARGUMENTS)
606 //
607 // InTypes[] - this function saves input type, they will be used in ExpandInputsBody().
608 // InBufPtrs[] - this function sets each array element to point to the first cell / byte
609 // (byte for x86, cell for other platforms) of the corresponding input allocation
610 // InStructTempSlots[] - this function sets each array element either to nullptr
611 // or to the result of an alloca (for the case where the
612 // calling convention dictates that a value must be passed
613 // by reference, and so we need a stacked temporary to hold
614 // a copy of that value)
ExpandInputsLoopInvariant(llvm::IRBuilder<> & Builder,llvm::BasicBlock * LoopHeader,llvm::Value * Arg_p,llvm::MDNode * TBAAPointer,llvm::Function::arg_iterator ArgIter,const size_t NumInputs,llvm::SmallVectorImpl<llvm::Type * > & InTypes,llvm::SmallVectorImpl<llvm::Value * > & InBufPtrs,llvm::SmallVectorImpl<llvm::Value * > & InStructTempSlots)615 void ExpandInputsLoopInvariant(llvm::IRBuilder<> &Builder, llvm::BasicBlock *LoopHeader,
616 llvm::Value *Arg_p,
617 llvm::MDNode *TBAAPointer,
618 llvm::Function::arg_iterator ArgIter,
619 const size_t NumInputs,
620 llvm::SmallVectorImpl<llvm::Type *> &InTypes,
621 llvm::SmallVectorImpl<llvm::Value *> &InBufPtrs,
622 llvm::SmallVectorImpl<llvm::Value *> &InStructTempSlots) {
623 bccAssert(NumInputs <= RS_KERNEL_INPUT_LIMIT);
624
625 // Extract information about input slots. The work done
626 // here is loop-invariant, so we can hoist the operations out of the loop.
627 auto OldInsertionPoint = Builder.saveIP();
628 Builder.SetInsertPoint(LoopHeader->getTerminator());
629
630 for (size_t InputIndex = 0; InputIndex < NumInputs; ++InputIndex, ArgIter++) {
631 llvm::Type *InType = ArgIter->getType();
632
633 /*
634 * AArch64 calling conventions dictate that structs of sufficient size
635 * get passed by pointer instead of passed by value. This, combined
636 * with the fact that we don't allow kernels to operate on pointer
637 * data means that if we see a kernel with a pointer parameter we know
638 * that it is a struct input that has been promoted. As such we don't
639 * need to convert its type to a pointer. Later we will need to know
640 * to create a temporary copy on the stack, so we save this information
641 * in InStructTempSlots.
642 */
643 if (auto PtrType = llvm::dyn_cast<llvm::PointerType>(InType)) {
644 llvm::Type *ElementType = PtrType->getElementType();
645 InStructTempSlots.push_back(Builder.CreateAlloca(ElementType, nullptr,
646 "input_struct_slot"));
647 } else {
648 InType = InType->getPointerTo();
649 InStructTempSlots.push_back(nullptr);
650 }
651
652 SmallGEPIndices InBufPtrGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldInPtr,
653 static_cast<int32_t>(InputIndex)}));
654 llvm::Value *InBufPtrAddr = Builder.CreateInBoundsGEP(Arg_p, InBufPtrGEP, "input_buf.gep");
655 llvm::LoadInst *InBufPtr = Builder.CreateLoad(InBufPtrAddr, "input_buf");
656
657 llvm::Value *CastInBufPtr = nullptr;
658 if (Module->getTargetTriple() != DEFAULT_X86_TRIPLE_STRING) {
659 CastInBufPtr = Builder.CreatePointerCast(InBufPtr, InType, "casted_in");
660 } else {
661 // The disagreement between module and x86 target machine datalayout
662 // causes mismatched input/output data offset between slang reflected
663 // code and bcc codegen for GetElementPtr. To solve this issue, skip the
664 // cast to InType and leave CastInBufPtr as an int8_t*. The buffer is
665 // later indexed with an explicit byte offset computed based on
666 // X86_CUSTOM_DL_STRING and then bitcast it to actual input type.
667 CastInBufPtr = InBufPtr;
668 }
669
670 if (gEnableRsTbaa) {
671 InBufPtr->setMetadata("tbaa", TBAAPointer);
672 }
673
674 InTypes.push_back(InType);
675 InBufPtrs.push_back(CastInBufPtr);
676 }
677
678 Builder.restoreIP(OldInsertionPoint);
679 }
680
681 // Generate loop-varying input processing code for an expanded ForEach-able function
682 // or an expanded general reduction accumulator function. Also, for the call to the
683 // UNexpanded function, collect the portion of the argument list corresponding to the
684 // inputs.
685 //
686 // Arg_x1 - first X coordinate to be processed by the expanded function
687 // TBAAAllocation - metadata for marking loads of input values out of allocations
688 // NumInputs -- number of inputs (NOT number of ARGUMENTS)
689 // InTypes[] - this function uses the saved input types in ExpandInputsLoopInvariant()
690 // to convert the pointer of byte InPtr to its real type.
691 // InBufPtrs[] - this function consumes the information produced by ExpandInputsLoopInvariant()
692 // InStructTempSlots[] - this function consumes the information produced by ExpandInputsLoopInvariant()
693 // IndVar - value of loop induction variable (X coordinate) for a given loop iteration
694 //
695 // RootArgs - this function sets this to the list of outgoing argument values corresponding
696 // to the inputs
ExpandInputsBody(llvm::IRBuilder<> & Builder,llvm::Value * Arg_x1,llvm::MDNode * TBAAAllocation,const size_t NumInputs,const llvm::SmallVectorImpl<llvm::Type * > & InTypes,const llvm::SmallVectorImpl<llvm::Value * > & InBufPtrs,const llvm::SmallVectorImpl<llvm::Value * > & InStructTempSlots,llvm::Value * IndVar,llvm::SmallVectorImpl<llvm::Value * > & RootArgs)697 void ExpandInputsBody(llvm::IRBuilder<> &Builder,
698 llvm::Value *Arg_x1,
699 llvm::MDNode *TBAAAllocation,
700 const size_t NumInputs,
701 const llvm::SmallVectorImpl<llvm::Type *> &InTypes,
702 const llvm::SmallVectorImpl<llvm::Value *> &InBufPtrs,
703 const llvm::SmallVectorImpl<llvm::Value *> &InStructTempSlots,
704 llvm::Value *IndVar,
705 llvm::SmallVectorImpl<llvm::Value *> &RootArgs) {
706 llvm::Value *Offset = Builder.CreateSub(IndVar, Arg_x1);
707 llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context);
708
709 for (size_t Index = 0; Index < NumInputs; ++Index) {
710
711 llvm::Value *InPtr = nullptr;
712 if (Module->getTargetTriple() != DEFAULT_X86_TRIPLE_STRING) {
713 InPtr = Builder.CreateInBoundsGEP(InBufPtrs[Index], Offset);
714 } else {
715 // Treat x86 input buffer as byte[], get indexed pointer with explicit
716 // byte offset computed using a datalayout based on
717 // X86_CUSTOM_DL_STRING, then bitcast it to actual input type.
718 llvm::DataLayout DL(X86_CUSTOM_DL_STRING);
719 llvm::Type *InTy = InTypes[Index];
720 uint64_t InStep = DL.getTypeAllocSize(InTy->getPointerElementType());
721 llvm::Value *OffsetInBytes = Builder.CreateMul(Offset, llvm::ConstantInt::get(Int32Ty, InStep));
722 InPtr = Builder.CreateInBoundsGEP(InBufPtrs[Index], OffsetInBytes);
723 InPtr = Builder.CreatePointerCast(InPtr, InTy);
724 }
725
726 llvm::Value *Input;
727 llvm::LoadInst *InputLoad = Builder.CreateLoad(InPtr, "input");
728
729 if (gEnableRsTbaa) {
730 InputLoad->setMetadata("tbaa", TBAAAllocation);
731 }
732
733 if (llvm::Value *TemporarySlot = InStructTempSlots[Index]) {
734 // Pass a pointer to a temporary on the stack, rather than
735 // passing a pointer to the original value. We do not want
736 // the kernel to potentially modify the input data.
737
738 // Note: don't annotate with TBAA, since the kernel might
739 // have its own TBAA annotations for the pointer argument.
740 Builder.CreateStore(InputLoad, TemporarySlot);
741 Input = TemporarySlot;
742 } else {
743 Input = InputLoad;
744 }
745
746 RootArgs.push_back(Input);
747 }
748 }
749
750 /* Performs the actual optimization on a selected function. On success, the
751 * Module will contain a new function of the name "<NAME>.expand" that
752 * invokes <NAME>() in a loop with the appropriate parameters.
753 */
ExpandOldStyleForEach(llvm::Function * Function,uint32_t Signature)754 bool ExpandOldStyleForEach(llvm::Function *Function, uint32_t Signature) {
755 ALOGV("Expanding ForEach-able Function %s",
756 Function->getName().str().c_str());
757
758 if (!Signature) {
759 Signature = getRootSignature(Function);
760 if (!Signature) {
761 // We couldn't determine how to expand this function based on its
762 // function signature.
763 return false;
764 }
765 }
766
767 llvm::DataLayout DL(Module);
768 if (Module->getTargetTriple() == DEFAULT_X86_TRIPLE_STRING) {
769 DL.reset(X86_CUSTOM_DL_STRING);
770 }
771
772 llvm::Function *ExpandedFunction =
773 createEmptyExpandedForEachKernel(Function->getName());
774
775 /*
776 * Extract the expanded function's parameters. It is guaranteed by
777 * createEmptyExpandedForEachKernel that there will be four parameters.
778 */
779
780 bccAssert(ExpandedFunction->arg_size() == kNumExpandedForeachParams);
781
782 llvm::Function::arg_iterator ExpandedFunctionArgIter =
783 ExpandedFunction->arg_begin();
784
785 llvm::Value *Arg_p = &*(ExpandedFunctionArgIter++);
786 llvm::Value *Arg_x1 = &*(ExpandedFunctionArgIter++);
787 llvm::Value *Arg_x2 = &*(ExpandedFunctionArgIter++);
788 llvm::Value *Arg_outstep = &*(ExpandedFunctionArgIter);
789
790 llvm::Value *InStep = nullptr;
791 llvm::Value *OutStep = nullptr;
792
793 // Construct the actual function body.
794 llvm::IRBuilder<> Builder(&*ExpandedFunction->getEntryBlock().begin());
795
796 // Collect and construct the arguments for the kernel().
797 // Note that we load any loop-invariant arguments before entering the Loop.
798 llvm::Function::arg_iterator FunctionArgIter = Function->arg_begin();
799
800 llvm::Type *InTy = nullptr;
801 llvm::Value *InBufPtr = nullptr;
802 if (bcinfo::MetadataExtractor::hasForEachSignatureIn(Signature)) {
803 SmallGEPIndices InStepGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldInStride, 0}));
804 llvm::LoadInst *InStepArg = Builder.CreateLoad(
805 Builder.CreateInBoundsGEP(Arg_p, InStepGEP, "instep_addr.gep"), "instep_addr");
806
807 InTy = (FunctionArgIter++)->getType();
808 InStep = getStepValue(&DL, InTy, InStepArg);
809
810 InStep->setName("instep");
811
812 SmallGEPIndices InputAddrGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldInPtr, 0}));
813 InBufPtr = Builder.CreateLoad(
814 Builder.CreateInBoundsGEP(Arg_p, InputAddrGEP, "input_buf.gep"), "input_buf");
815 }
816
817 llvm::Type *OutTy = nullptr;
818 llvm::Value *OutBasePtr = nullptr;
819 if (bcinfo::MetadataExtractor::hasForEachSignatureOut(Signature)) {
820 OutTy = (FunctionArgIter++)->getType();
821 OutStep = getStepValue(&DL, OutTy, Arg_outstep);
822 OutStep->setName("outstep");
823 SmallGEPIndices OutBaseGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldOutPtr, 0}));
824 OutBasePtr = Builder.CreateLoad(Builder.CreateInBoundsGEP(Arg_p, OutBaseGEP, "out_buf.gep"));
825 }
826
827 llvm::Value *UsrData = nullptr;
828 if (bcinfo::MetadataExtractor::hasForEachSignatureUsrData(Signature)) {
829 llvm::Type *UsrDataTy = (FunctionArgIter++)->getType();
830 llvm::Value *UsrDataPointerAddr = Builder.CreateStructGEP(nullptr, Arg_p, RsExpandKernelDriverInfoPfxFieldUsr);
831 UsrData = Builder.CreatePointerCast(Builder.CreateLoad(UsrDataPointerAddr), UsrDataTy);
832 UsrData->setName("UsrData");
833 }
834
835 llvm::BasicBlock *LoopHeader = Builder.GetInsertBlock();
836 llvm::Value *IV;
837 createLoop(Builder, Arg_x1, Arg_x2, &IV);
838
839 llvm::SmallVector<llvm::Value*, 8> CalleeArgs;
840 const int CalleeArgsContextIdx = ExpandSpecialArguments(Signature, IV, Arg_p, Builder, CalleeArgs,
841 [&FunctionArgIter]() { FunctionArgIter++; },
842 LoopHeader->getTerminator());
843
844 bccAssert(FunctionArgIter == Function->arg_end());
845
846 // Populate the actual call to kernel().
847 llvm::SmallVector<llvm::Value*, 8> RootArgs;
848
849 llvm::Value *InPtr = nullptr;
850 llvm::Value *OutPtr = nullptr;
851
852 // Calculate the current input and output pointers
853 //
854 // We always calculate the input/output pointers with a GEP operating on i8
855 // values and only cast at the very end to OutTy. This is because the step
856 // between two values is given in bytes.
857 //
858 // TODO: We could further optimize the output by using a GEP operation of
859 // type 'OutTy' in cases where the element type of the allocation allows.
860 if (OutBasePtr) {
861 llvm::Value *OutOffset = Builder.CreateSub(IV, Arg_x1);
862 OutOffset = Builder.CreateMul(OutOffset, OutStep);
863 OutPtr = Builder.CreateInBoundsGEP(OutBasePtr, OutOffset);
864 OutPtr = Builder.CreatePointerCast(OutPtr, OutTy);
865 }
866
867 if (InBufPtr) {
868 llvm::Value *InOffset = Builder.CreateSub(IV, Arg_x1);
869 InOffset = Builder.CreateMul(InOffset, InStep);
870 InPtr = Builder.CreateInBoundsGEP(InBufPtr, InOffset);
871 InPtr = Builder.CreatePointerCast(InPtr, InTy);
872 }
873
874 if (InPtr) {
875 RootArgs.push_back(InPtr);
876 }
877
878 if (OutPtr) {
879 RootArgs.push_back(OutPtr);
880 }
881
882 if (UsrData) {
883 RootArgs.push_back(UsrData);
884 }
885
886 finishArgList(RootArgs, CalleeArgs, CalleeArgsContextIdx, *Function, Builder);
887
888 Builder.CreateCall(Function, RootArgs);
889
890 return true;
891 }
892
893 /* Expand a pass-by-value foreach kernel.
894 */
ExpandForEach(llvm::Function * Function,uint32_t Signature)895 bool ExpandForEach(llvm::Function *Function, uint32_t Signature) {
896 bccAssert(bcinfo::MetadataExtractor::hasForEachSignatureKernel(Signature));
897 ALOGV("Expanding kernel Function %s", Function->getName().str().c_str());
898
899 // TODO: Refactor this to share functionality with ExpandOldStyleForEach.
900 llvm::DataLayout DL(Module);
901 if (Module->getTargetTriple() == DEFAULT_X86_TRIPLE_STRING) {
902 DL.reset(X86_CUSTOM_DL_STRING);
903 }
904 llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context);
905
906 llvm::Function *ExpandedFunction =
907 createEmptyExpandedForEachKernel(Function->getName());
908
909 /*
910 * Extract the expanded function's parameters. It is guaranteed by
911 * createEmptyExpandedForEachKernel that there will be four parameters.
912 */
913
914 bccAssert(ExpandedFunction->arg_size() == kNumExpandedForeachParams);
915
916 llvm::Function::arg_iterator ExpandedFunctionArgIter =
917 ExpandedFunction->arg_begin();
918
919 llvm::Value *Arg_p = &*(ExpandedFunctionArgIter++);
920 llvm::Value *Arg_x1 = &*(ExpandedFunctionArgIter++);
921 llvm::Value *Arg_x2 = &*(ExpandedFunctionArgIter++);
922 // Arg_outstep is not used by expanded new-style forEach kernels.
923
924 // Construct the actual function body.
925 llvm::IRBuilder<> Builder(&*ExpandedFunction->getEntryBlock().begin());
926
927 // Create TBAA meta-data.
928 llvm::MDNode *TBAARenderScriptDistinct, *TBAARenderScript,
929 *TBAAAllocation, *TBAAPointer;
930 llvm::MDBuilder MDHelper(*Context);
931
932 TBAARenderScriptDistinct =
933 MDHelper.createTBAARoot(kRenderScriptTBAARootName);
934 TBAARenderScript = MDHelper.createTBAANode(kRenderScriptTBAANodeName,
935 TBAARenderScriptDistinct);
936 TBAAAllocation = MDHelper.createTBAAScalarTypeNode("allocation",
937 TBAARenderScript);
938 TBAAAllocation = MDHelper.createTBAAStructTagNode(TBAAAllocation,
939 TBAAAllocation, 0);
940 TBAAPointer = MDHelper.createTBAAScalarTypeNode("pointer",
941 TBAARenderScript);
942 TBAAPointer = MDHelper.createTBAAStructTagNode(TBAAPointer, TBAAPointer, 0);
943
944 /*
945 * Collect and construct the arguments for the kernel().
946 *
947 * Note that we load any loop-invariant arguments before entering the Loop.
948 */
949 size_t NumRemainingInputs = Function->arg_size();
950
951 // No usrData parameter on kernels.
952 bccAssert(
953 !bcinfo::MetadataExtractor::hasForEachSignatureUsrData(Signature));
954
955 llvm::Function::arg_iterator ArgIter = Function->arg_begin();
956
957 // Check the return type
958 llvm::Type *OutTy = nullptr;
959 llvm::LoadInst *OutBasePtr = nullptr;
960 llvm::Value *CastedOutBasePtr = nullptr;
961
962 bool PassOutByPointer = false;
963
964 if (bcinfo::MetadataExtractor::hasForEachSignatureOut(Signature)) {
965 llvm::Type *OutBaseTy = Function->getReturnType();
966
967 if (OutBaseTy->isVoidTy()) {
968 PassOutByPointer = true;
969 OutTy = ArgIter->getType();
970
971 ArgIter++;
972 --NumRemainingInputs;
973 } else {
974 // We don't increment Args, since we are using the actual return type.
975 OutTy = OutBaseTy->getPointerTo();
976 }
977
978 SmallGEPIndices OutBaseGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldOutPtr, 0}));
979 OutBasePtr = Builder.CreateLoad(Builder.CreateInBoundsGEP(Arg_p, OutBaseGEP, "out_buf.gep"));
980
981 if (gEnableRsTbaa) {
982 OutBasePtr->setMetadata("tbaa", TBAAPointer);
983 }
984
985 if (Module->getTargetTriple() != DEFAULT_X86_TRIPLE_STRING) {
986 CastedOutBasePtr = Builder.CreatePointerCast(OutBasePtr, OutTy, "casted_out");
987 } else {
988 // The disagreement between module and x86 target machine datalayout
989 // causes mismatched input/output data offset between slang reflected
990 // code and bcc codegen for GetElementPtr. To solve this issue, skip the
991 // cast to OutTy and leave CastedOutBasePtr as an int8_t*. The buffer
992 // is later indexed with an explicit byte offset computed based on
993 // X86_CUSTOM_DL_STRING and then bitcast it to actual output type.
994 CastedOutBasePtr = OutBasePtr;
995 }
996 }
997
998 llvm::SmallVector<llvm::Type*, 8> InTypes;
999 llvm::SmallVector<llvm::Value*, 8> InBufPtrs;
1000 llvm::SmallVector<llvm::Value*, 8> InStructTempSlots;
1001
1002 bccAssert(NumRemainingInputs <= RS_KERNEL_INPUT_LIMIT);
1003
1004 // Create the loop structure.
1005 llvm::BasicBlock *LoopHeader = Builder.GetInsertBlock();
1006 llvm::Value *IV;
1007 createLoop(Builder, Arg_x1, Arg_x2, &IV);
1008
1009 llvm::SmallVector<llvm::Value*, 8> CalleeArgs;
1010 const int CalleeArgsContextIdx =
1011 ExpandSpecialArguments(Signature, IV, Arg_p, Builder, CalleeArgs,
1012 [&NumRemainingInputs]() { --NumRemainingInputs; },
1013 LoopHeader->getTerminator());
1014
1015 // After ExpandSpecialArguments() gets called, NumRemainingInputs
1016 // counts the number of arguments to the kernel that correspond to
1017 // an array entry from the InPtr field of the DriverInfo
1018 // structure.
1019 const size_t NumInPtrArguments = NumRemainingInputs;
1020
1021 if (NumInPtrArguments > 0) {
1022 ExpandInputsLoopInvariant(Builder, LoopHeader, Arg_p, TBAAPointer, ArgIter, NumInPtrArguments,
1023 InTypes, InBufPtrs, InStructTempSlots);
1024 }
1025
1026 // Populate the actual call to kernel().
1027 llvm::SmallVector<llvm::Value*, 8> RootArgs;
1028
1029 // Calculate the current input and output pointers.
1030
1031 // Output
1032
1033 llvm::Value *OutPtr = nullptr;
1034 if (CastedOutBasePtr) {
1035 llvm::Value *OutOffset = Builder.CreateSub(IV, Arg_x1);
1036
1037 if (Module->getTargetTriple() != DEFAULT_X86_TRIPLE_STRING) {
1038 OutPtr = Builder.CreateInBoundsGEP(CastedOutBasePtr, OutOffset);
1039 } else {
1040 // Treat x86 output buffer as byte[], get indexed pointer with explicit
1041 // byte offset computed using a datalayout based on
1042 // X86_CUSTOM_DL_STRING, then bitcast it to actual output type.
1043 uint64_t OutStep = DL.getTypeAllocSize(OutTy->getPointerElementType());
1044 llvm::Value *OutOffsetInBytes = Builder.CreateMul(OutOffset, llvm::ConstantInt::get(Int32Ty, OutStep));
1045 OutPtr = Builder.CreateInBoundsGEP(CastedOutBasePtr, OutOffsetInBytes);
1046 OutPtr = Builder.CreatePointerCast(OutPtr, OutTy);
1047 }
1048
1049 if (PassOutByPointer) {
1050 RootArgs.push_back(OutPtr);
1051 }
1052 }
1053
1054 // Inputs
1055
1056 if (NumInPtrArguments > 0) {
1057 ExpandInputsBody(Builder, Arg_x1, TBAAAllocation, NumInPtrArguments,
1058 InTypes, InBufPtrs, InStructTempSlots, IV, RootArgs);
1059 }
1060
1061 finishArgList(RootArgs, CalleeArgs, CalleeArgsContextIdx, *Function, Builder);
1062
1063 llvm::Value *RetVal = Builder.CreateCall(Function, RootArgs);
1064
1065 if (OutPtr && !PassOutByPointer) {
1066 RetVal->setName("call.result");
1067 llvm::StoreInst *Store = Builder.CreateStore(RetVal, OutPtr);
1068 if (gEnableRsTbaa) {
1069 Store->setMetadata("tbaa", TBAAAllocation);
1070 }
1071 }
1072
1073 return true;
1074 }
1075
1076 // Certain categories of functions that make up a general
1077 // reduce-style kernel are called directly from the driver with no
1078 // expansion needed. For a function in such a category, we need to
1079 // promote linkage from static to external, to ensure that the
1080 // function is visible to the driver in the dynamic symbol table.
1081 // This promotion is safe because we don't have any kind of cross
1082 // translation unit linkage model (except for linking against
1083 // RenderScript libraries), so we do not risk name clashes.
PromoteReduceFunction(const char * Name,FunctionSet & PromotedFunctions)1084 bool PromoteReduceFunction(const char *Name, FunctionSet &PromotedFunctions) {
1085 if (!Name) // a presumably-optional function that is not present
1086 return false;
1087
1088 llvm::Function *Fn = Module->getFunction(Name);
1089 bccAssert(Fn != nullptr);
1090 if (PromotedFunctions.insert(Fn).second) {
1091 bccAssert(Fn->getLinkage() == llvm::GlobalValue::InternalLinkage);
1092 Fn->setLinkage(llvm::GlobalValue::ExternalLinkage);
1093 return true;
1094 }
1095
1096 return false;
1097 }
1098
1099 // Expand the accumulator function for a general reduce-style kernel.
1100 //
1101 // The input is a function of the form
1102 //
1103 // define void @func(accumType* %accum, foo1 in1[, ... fooN inN] [, special arguments])
1104 //
1105 // where all arguments except the first are the same as for a foreach kernel.
1106 //
1107 // The input accumulator function gets expanded into a function of the form
1108 //
1109 // define void @func.expand(%RsExpandKernelDriverInfoPfx* %p, i32 %x1, i32 %x2, accumType* %accum)
1110 //
1111 // which performs a serial accumulaion of elements [x1, x2) into *%accum.
1112 //
1113 // In pseudocode, @func.expand does:
1114 //
1115 // for (i = %x1; i < %x2; ++i) {
1116 // func(%accum,
1117 // *((foo1 *)p->inPtr[0] + i)[, ... *((fooN *)p->inPtr[N-1] + i)
1118 // [, p] [, i] [, p->current.y] [, p->current.z]);
1119 // }
1120 //
1121 // This is very similar to foreach kernel expansion with no output.
ExpandReduceAccumulator(llvm::Function * FnAccumulator,uint32_t Signature,size_t NumInputs)1122 bool ExpandReduceAccumulator(llvm::Function *FnAccumulator, uint32_t Signature, size_t NumInputs) {
1123 ALOGV("Expanding accumulator %s for general reduce kernel",
1124 FnAccumulator->getName().str().c_str());
1125
1126 // Create TBAA meta-data.
1127 llvm::MDNode *TBAARenderScriptDistinct, *TBAARenderScript,
1128 *TBAAAllocation, *TBAAPointer;
1129 llvm::MDBuilder MDHelper(*Context);
1130 TBAARenderScriptDistinct =
1131 MDHelper.createTBAARoot(kRenderScriptTBAARootName);
1132 TBAARenderScript = MDHelper.createTBAANode(kRenderScriptTBAANodeName,
1133 TBAARenderScriptDistinct);
1134 TBAAAllocation = MDHelper.createTBAAScalarTypeNode("allocation",
1135 TBAARenderScript);
1136 TBAAAllocation = MDHelper.createTBAAStructTagNode(TBAAAllocation,
1137 TBAAAllocation, 0);
1138 TBAAPointer = MDHelper.createTBAAScalarTypeNode("pointer",
1139 TBAARenderScript);
1140 TBAAPointer = MDHelper.createTBAAStructTagNode(TBAAPointer, TBAAPointer, 0);
1141
1142 auto AccumulatorArgIter = FnAccumulator->arg_begin();
1143
1144 // Create empty accumulator function.
1145 llvm::Function *FnExpandedAccumulator =
1146 createEmptyExpandedReduceAccumulator(FnAccumulator->getName(),
1147 (AccumulatorArgIter++)->getType());
1148
1149 // Extract the expanded accumulator's parameters. It is
1150 // guaranteed by createEmptyExpandedReduceAccumulator that
1151 // there will be 4 parameters.
1152 bccAssert(FnExpandedAccumulator->arg_size() == kNumExpandedReduceAccumulatorParams);
1153 auto ExpandedAccumulatorArgIter = FnExpandedAccumulator->arg_begin();
1154 llvm::Value *Arg_p = &*(ExpandedAccumulatorArgIter++);
1155 llvm::Value *Arg_x1 = &*(ExpandedAccumulatorArgIter++);
1156 llvm::Value *Arg_x2 = &*(ExpandedAccumulatorArgIter++);
1157 llvm::Value *Arg_accum = &*(ExpandedAccumulatorArgIter++);
1158
1159 // Construct the actual function body.
1160 llvm::IRBuilder<> Builder(&*FnExpandedAccumulator->getEntryBlock().begin());
1161
1162 // Create the loop structure.
1163 llvm::BasicBlock *LoopHeader = Builder.GetInsertBlock();
1164 llvm::Value *IndVar;
1165 createLoop(Builder, Arg_x1, Arg_x2, &IndVar);
1166
1167 llvm::SmallVector<llvm::Value*, 8> CalleeArgs;
1168 const int CalleeArgsContextIdx =
1169 ExpandSpecialArguments(Signature, IndVar, Arg_p, Builder, CalleeArgs,
1170 [](){}, LoopHeader->getTerminator());
1171
1172 llvm::SmallVector<llvm::Type*, 8> InTypes;
1173 llvm::SmallVector<llvm::Value*, 8> InBufPtrs;
1174 llvm::SmallVector<llvm::Value*, 8> InStructTempSlots;
1175 ExpandInputsLoopInvariant(Builder, LoopHeader, Arg_p, TBAAPointer, AccumulatorArgIter, NumInputs,
1176 InTypes, InBufPtrs, InStructTempSlots);
1177
1178 // Populate the actual call to the original accumulator.
1179 llvm::SmallVector<llvm::Value*, 8> RootArgs;
1180 RootArgs.push_back(Arg_accum);
1181 ExpandInputsBody(Builder, Arg_x1, TBAAAllocation, NumInputs, InTypes, InBufPtrs, InStructTempSlots,
1182 IndVar, RootArgs);
1183 finishArgList(RootArgs, CalleeArgs, CalleeArgsContextIdx, *FnAccumulator, Builder);
1184 Builder.CreateCall(FnAccumulator, RootArgs);
1185
1186 return true;
1187 }
1188
1189 // Create a combiner function for a general reduce-style kernel that lacks one,
1190 // by calling the accumulator function.
1191 //
1192 // The accumulator function must be of the form
1193 //
1194 // define void @accumFn(accumType* %accum, accumType %in)
1195 //
1196 // A combiner function will be generated of the form
1197 //
1198 // define void @accumFn.combiner(accumType* %accum, accumType* %other) {
1199 // %1 = load accumType, accumType* %other
1200 // call void @accumFn(accumType* %accum, accumType %1);
1201 // }
CreateReduceCombinerFromAccumulator(llvm::Function * FnAccumulator)1202 bool CreateReduceCombinerFromAccumulator(llvm::Function *FnAccumulator) {
1203 ALOGV("Creating combiner from accumulator %s for general reduce kernel",
1204 FnAccumulator->getName().str().c_str());
1205
1206 using llvm::Attribute;
1207
1208 bccAssert(FnAccumulator->arg_size() == 2);
1209 auto AccumulatorArgIter = FnAccumulator->arg_begin();
1210 llvm::Value *AccumulatorArg_accum = &*(AccumulatorArgIter++);
1211 llvm::Value *AccumulatorArg_in = &*(AccumulatorArgIter++);
1212 llvm::Type *AccumulatorArgType = AccumulatorArg_accum->getType();
1213 bccAssert(AccumulatorArgType->isPointerTy());
1214
1215 llvm::Type *VoidTy = llvm::Type::getVoidTy(*Context);
1216 llvm::FunctionType *CombinerType =
1217 llvm::FunctionType::get(VoidTy, { AccumulatorArgType, AccumulatorArgType }, false);
1218 llvm::Function *FnCombiner =
1219 llvm::Function::Create(CombinerType, llvm::GlobalValue::ExternalLinkage,
1220 nameReduceCombinerFromAccumulator(FnAccumulator->getName()),
1221 Module);
1222
1223 auto CombinerArgIter = FnCombiner->arg_begin();
1224
1225 llvm::Argument *CombinerArg_accum = &(*CombinerArgIter++);
1226 CombinerArg_accum->setName("accum");
1227 CombinerArg_accum->addAttr(llvm::AttributeSet::get(*Context, CombinerArg_accum->getArgNo() + 1,
1228 llvm::makeArrayRef(Attribute::NoCapture)));
1229
1230 llvm::Argument *CombinerArg_other = &(*CombinerArgIter++);
1231 CombinerArg_other->setName("other");
1232 CombinerArg_other->addAttr(llvm::AttributeSet::get(*Context, CombinerArg_other->getArgNo() + 1,
1233 llvm::makeArrayRef(Attribute::NoCapture)));
1234
1235 llvm::BasicBlock *BB = llvm::BasicBlock::Create(*Context, "BB", FnCombiner);
1236 llvm::IRBuilder<> Builder(BB);
1237
1238 if (AccumulatorArg_in->getType()->isPointerTy()) {
1239 // Types of sufficient size get passed by pointer-to-copy rather
1240 // than passed by value. An accumulator cannot take a pointer
1241 // at the user level; so if we see a pointer here, we know that
1242 // we have a pass-by-pointer-to-copy case.
1243 llvm::Type *ElementType = AccumulatorArg_in->getType()->getPointerElementType();
1244 llvm::Value *TempMem = Builder.CreateAlloca(ElementType, nullptr, "caller_copy");
1245 Builder.CreateStore(Builder.CreateLoad(CombinerArg_other), TempMem);
1246 Builder.CreateCall(FnAccumulator, { CombinerArg_accum, TempMem });
1247 } else {
1248 llvm::Value *TypeAdjustedOther = CombinerArg_other;
1249 if (AccumulatorArgType->getPointerElementType() != AccumulatorArg_in->getType()) {
1250 // Call lowering by frontend has done some type coercion
1251 TypeAdjustedOther = Builder.CreatePointerCast(CombinerArg_other,
1252 AccumulatorArg_in->getType()->getPointerTo(),
1253 "cast");
1254 }
1255 llvm::Value *DerefOther = Builder.CreateLoad(TypeAdjustedOther);
1256 Builder.CreateCall(FnAccumulator, { CombinerArg_accum, DerefOther });
1257 }
1258 Builder.CreateRetVoid();
1259
1260 return true;
1261 }
1262
1263 /// @brief Checks if pointers to allocation internals are exposed
1264 ///
1265 /// This function verifies if through the parameters passed to the kernel
1266 /// or through calls to the runtime library the script gains access to
1267 /// pointers pointing to data within a RenderScript Allocation.
1268 /// If we know we control all loads from and stores to data within
1269 /// RenderScript allocations and if we know the run-time internal accesses
1270 /// are all annotated with RenderScript TBAA metadata, only then we
1271 /// can safely use TBAA to distinguish between generic and from-allocation
1272 /// pointers.
allocPointersExposed(llvm::Module & Module)1273 bool allocPointersExposed(llvm::Module &Module) {
1274 // Old style kernel function can expose pointers to elements within
1275 // allocations.
1276 // TODO: Extend analysis to allow simple cases of old-style kernels.
1277 for (size_t i = 0; i < mExportForEachCount; ++i) {
1278 const char *Name = mExportForEachNameList[i];
1279 uint32_t Signature = mExportForEachSignatureList[i];
1280 if (Module.getFunction(Name) &&
1281 !bcinfo::MetadataExtractor::hasForEachSignatureKernel(Signature)) {
1282 return true;
1283 }
1284 }
1285
1286 // Check for library functions that expose a pointer to an Allocation or
1287 // that are not yet annotated with RenderScript-specific tbaa information.
1288 static const std::vector<const char *> Funcs{
1289 // rsGetElementAt(...)
1290 "_Z14rsGetElementAt13rs_allocationj",
1291 "_Z14rsGetElementAt13rs_allocationjj",
1292 "_Z14rsGetElementAt13rs_allocationjjj",
1293
1294 // rsSetElementAt()
1295 "_Z14rsSetElementAt13rs_allocationPvj",
1296 "_Z14rsSetElementAt13rs_allocationPvjj",
1297 "_Z14rsSetElementAt13rs_allocationPvjjj",
1298
1299 // rsGetElementAtYuv_uchar_Y()
1300 "_Z25rsGetElementAtYuv_uchar_Y13rs_allocationjj",
1301
1302 // rsGetElementAtYuv_uchar_U()
1303 "_Z25rsGetElementAtYuv_uchar_U13rs_allocationjj",
1304
1305 // rsGetElementAtYuv_uchar_V()
1306 "_Z25rsGetElementAtYuv_uchar_V13rs_allocationjj",
1307 };
1308
1309 for (auto FI : Funcs) {
1310 llvm::Function *Function = Module.getFunction(FI);
1311
1312 if (!Function) {
1313 ALOGE("Missing run-time function '%s'", FI);
1314 return true;
1315 }
1316
1317 if (Function->getNumUses() > 0) {
1318 return true;
1319 }
1320 }
1321
1322 return false;
1323 }
1324
1325 /// @brief Connect RenderScript TBAA metadata to C/C++ metadata
1326 ///
1327 /// The TBAA metadata used to annotate loads/stores from RenderScript
1328 /// Allocations is generated in a separate TBAA tree with a
1329 /// "RenderScript Distinct TBAA" root node. LLVM does assume may-alias for
1330 /// all nodes in unrelated alias analysis trees. This function makes the
1331 /// "RenderScript TBAA" node (which is parented by the Distinct TBAA root),
1332 /// a subtree of the normal C/C++ TBAA tree aside of normal C/C++ types. With
1333 /// the connected trees every access to an Allocation is resolved to
1334 /// must-alias if compared to a normal C/C++ access.
connectRenderScriptTBAAMetadata(llvm::Module & Module)1335 void connectRenderScriptTBAAMetadata(llvm::Module &Module) {
1336 llvm::MDBuilder MDHelper(*Context);
1337 llvm::MDNode *TBAARenderScriptDistinct =
1338 MDHelper.createTBAARoot("RenderScript Distinct TBAA");
1339 llvm::MDNode *TBAARenderScript = MDHelper.createTBAANode(
1340 "RenderScript TBAA", TBAARenderScriptDistinct);
1341 llvm::MDNode *TBAARoot = MDHelper.createTBAARoot("Simple C/C++ TBAA");
1342 TBAARenderScript->replaceOperandWith(1, TBAARoot);
1343 }
1344
runOnModule(llvm::Module & Module)1345 virtual bool runOnModule(llvm::Module &Module) {
1346 bool Changed = false;
1347 this->Module = &Module;
1348 Context = &Module.getContext();
1349
1350 buildTypes();
1351
1352 bcinfo::MetadataExtractor me(&Module);
1353 if (!me.extract()) {
1354 ALOGE("Could not extract metadata from module!");
1355 return false;
1356 }
1357
1358 // Expand forEach_* style kernels.
1359 mExportForEachCount = me.getExportForEachSignatureCount();
1360 mExportForEachNameList = me.getExportForEachNameList();
1361 mExportForEachSignatureList = me.getExportForEachSignatureList();
1362
1363 for (size_t i = 0; i < mExportForEachCount; ++i) {
1364 const char *name = mExportForEachNameList[i];
1365 uint32_t signature = mExportForEachSignatureList[i];
1366 llvm::Function *kernel = Module.getFunction(name);
1367 if (kernel) {
1368 if (bcinfo::MetadataExtractor::hasForEachSignatureKernel(signature)) {
1369 Changed |= ExpandForEach(kernel, signature);
1370 kernel->setLinkage(llvm::GlobalValue::InternalLinkage);
1371 } else if (kernel->getReturnType()->isVoidTy()) {
1372 Changed |= ExpandOldStyleForEach(kernel, signature);
1373 kernel->setLinkage(llvm::GlobalValue::InternalLinkage);
1374 } else {
1375 // There are some graphics root functions that are not
1376 // expanded, but that will be called directly. For those
1377 // functions, we can not set the linkage to internal.
1378 }
1379 }
1380 }
1381
1382 // Process general reduce_* style functions.
1383 const size_t ExportReduceCount = me.getExportReduceCount();
1384 const bcinfo::MetadataExtractor::Reduce *ExportReduceList = me.getExportReduceList();
1385 // Note that functions can be shared between kernels
1386 FunctionSet PromotedFunctions, ExpandedAccumulators, AccumulatorsForCombiners;
1387
1388 for (size_t i = 0; i < ExportReduceCount; ++i) {
1389 Changed |= PromoteReduceFunction(ExportReduceList[i].mInitializerName, PromotedFunctions);
1390 Changed |= PromoteReduceFunction(ExportReduceList[i].mCombinerName, PromotedFunctions);
1391 Changed |= PromoteReduceFunction(ExportReduceList[i].mOutConverterName, PromotedFunctions);
1392
1393 // Accumulator
1394 llvm::Function *accumulator = Module.getFunction(ExportReduceList[i].mAccumulatorName);
1395 bccAssert(accumulator != nullptr);
1396 if (ExpandedAccumulators.insert(accumulator).second)
1397 Changed |= ExpandReduceAccumulator(accumulator,
1398 ExportReduceList[i].mSignature,
1399 ExportReduceList[i].mInputCount);
1400 if (!ExportReduceList[i].mCombinerName) {
1401 if (AccumulatorsForCombiners.insert(accumulator).second)
1402 Changed |= CreateReduceCombinerFromAccumulator(accumulator);
1403 }
1404 }
1405
1406 if (gEnableRsTbaa && !allocPointersExposed(Module)) {
1407 connectRenderScriptTBAAMetadata(Module);
1408 }
1409
1410 return Changed;
1411 }
1412
getPassName() const1413 virtual const char *getPassName() const {
1414 return "forEach_* and reduce_* function expansion";
1415 }
1416
1417 }; // end RSKernelExpandPass
1418
1419 } // end anonymous namespace
1420
1421 char RSKernelExpandPass::ID = 0;
1422 static llvm::RegisterPass<RSKernelExpandPass> X("kernelexp", "Kernel Expand Pass");
1423
1424 namespace bcc {
1425
1426 const char BCC_INDEX_VAR_NAME[] = "rsIndex";
1427
1428 llvm::ModulePass *
createRSKernelExpandPass(bool pEnableStepOpt)1429 createRSKernelExpandPass(bool pEnableStepOpt) {
1430 return new RSKernelExpandPass(pEnableStepOpt);
1431 }
1432
1433 } // end namespace bcc
1434