RSForEachExpand.cpp revision acde6013e9c448547e59eed04afd2adbd9681a3a
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
20#include <cstdlib>
21
22#include <llvm/IR/DerivedTypes.h>
23#include <llvm/IR/Function.h>
24#include <llvm/IR/Instructions.h>
25#include <llvm/IR/IRBuilder.h>
26#include <llvm/IR/Module.h>
27#include <llvm/Pass.h>
28#include <llvm/Support/raw_ostream.h>
29#include <llvm/IR/DataLayout.h>
30#include <llvm/IR/Function.h>
31#include <llvm/IR/Type.h>
32#include <llvm/Transforms/Utils/BasicBlockUtils.h>
33
34#include "bcc/Config/Config.h"
35#include "bcc/Renderscript/RSInfo.h"
36#include "bcc/Support/Log.h"
37
38using namespace bcc;
39
40namespace {
41
42/* RSForEachExpandPass - This pass operates on functions that are able to be
43 * called via rsForEach() or "foreach_<NAME>". We create an inner loop for the
44 * ForEach-able function to be invoked over the appropriate data cells of the
45 * input/output allocations (adjusting other relevant parameters as we go). We
46 * support doing this for any ForEach-able compute kernels. The new function
47 * name is the original function name followed by ".expand". Note that we
48 * still generate code for the original function.
49 */
50class RSForEachExpandPass : public llvm::ModulePass {
51private:
52  static char ID;
53
54  llvm::Module *M;
55  llvm::LLVMContext *C;
56
57  const RSInfo::ExportForeachFuncListTy &mFuncs;
58
59  // Turns on optimization of allocation stride values.
60  bool mEnableStepOpt;
61
62  uint32_t getRootSignature(llvm::Function *F) {
63    const llvm::NamedMDNode *ExportForEachMetadata =
64        M->getNamedMetadata("#rs_export_foreach");
65
66    if (!ExportForEachMetadata) {
67      llvm::SmallVector<llvm::Type*, 8> RootArgTys;
68      for (llvm::Function::arg_iterator B = F->arg_begin(),
69                                        E = F->arg_end();
70           B != E;
71           ++B) {
72        RootArgTys.push_back(B->getType());
73      }
74
75      // For pre-ICS bitcode, we may not have signature information. In that
76      // case, we use the size of the RootArgTys to select the number of
77      // arguments.
78      return (1 << RootArgTys.size()) - 1;
79    }
80
81    if (ExportForEachMetadata->getNumOperands() == 0) {
82      return 0;
83    }
84
85    bccAssert(ExportForEachMetadata->getNumOperands() > 0);
86
87    // We only handle the case for legacy root() functions here, so this is
88    // hard-coded to look at only the first such function.
89    llvm::MDNode *SigNode = ExportForEachMetadata->getOperand(0);
90    if (SigNode != NULL && SigNode->getNumOperands() == 1) {
91      llvm::Value *SigVal = SigNode->getOperand(0);
92      if (SigVal->getValueID() == llvm::Value::MDStringVal) {
93        llvm::StringRef SigString =
94            static_cast<llvm::MDString*>(SigVal)->getString();
95        uint32_t Signature = 0;
96        if (SigString.getAsInteger(10, Signature)) {
97          ALOGE("Non-integer signature value '%s'", SigString.str().c_str());
98          return 0;
99        }
100        return Signature;
101      }
102    }
103
104    return 0;
105  }
106
107  // Get the actual value we should use to step through an allocation.
108  //
109  // Normally the value we use to step through an allocation is given to us by
110  // the driver. However, for certain primitive data types, we can derive an
111  // integer constant for the step value. We use this integer constant whenever
112  // possible to allow further compiler optimizations to take place.
113  //
114  // DL - Target Data size/layout information.
115  // T - Type of allocation (should be a pointer).
116  // OrigStep - Original step increment (root.expand() input from driver).
117  llvm::Value *getStepValue(llvm::DataLayout *DL, llvm::Type *T,
118                            llvm::Value *OrigStep) {
119    bccAssert(DL);
120    bccAssert(T);
121    bccAssert(OrigStep);
122    llvm::PointerType *PT = llvm::dyn_cast<llvm::PointerType>(T);
123    llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(*C);
124    if (mEnableStepOpt && T != VoidPtrTy && PT) {
125      llvm::Type *ET = PT->getElementType();
126      uint64_t ETSize = DL->getTypeAllocSize(ET);
127      llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*C);
128      return llvm::ConstantInt::get(Int32Ty, ETSize);
129    } else {
130      return OrigStep;
131    }
132  }
133
134  static bool hasIn(uint32_t Signature) {
135    return Signature & 0x01;
136  }
137
138  static bool hasOut(uint32_t Signature) {
139    return Signature & 0x02;
140  }
141
142  static bool hasUsrData(uint32_t Signature) {
143    return Signature & 0x04;
144  }
145
146  static bool hasX(uint32_t Signature) {
147    return Signature & 0x08;
148  }
149
150  static bool hasY(uint32_t Signature) {
151    return Signature & 0x10;
152  }
153
154  static bool isKernel(uint32_t Signature) {
155    return Signature & 0x20;
156  }
157
158  /// @brief Returns the type of the ForEach stub parameter structure.
159  ///
160  /// Renderscript uses a single structure in which all parameters are passed
161  /// to keep the signature of the expanded function independent of the
162  /// parameters passed to it.
163  llvm::Type *getForeachStubTy() {
164    llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(*C);
165    llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*C);
166    llvm::Type *SizeTy = Int32Ty;
167    /* Defined in frameworks/base/libs/rs/rs_hal.h:
168     *
169     * struct RsForEachStubParamStruct {
170     *   const void *in;
171     *   void *out;
172     *   const void *usr;
173     *   size_t usr_len;
174     *   uint32_t x;
175     *   uint32_t y;
176     *   uint32_t z;
177     *   uint32_t lod;
178     *   enum RsAllocationCubemapFace face;
179     *   uint32_t ar[16];
180     * };
181     */
182    llvm::SmallVector<llvm::Type*, 9> StructTys;
183    StructTys.push_back(VoidPtrTy);  // const void *in
184    StructTys.push_back(VoidPtrTy);  // void *out
185    StructTys.push_back(VoidPtrTy);  // const void *usr
186    StructTys.push_back(SizeTy);     // size_t usr_len
187    StructTys.push_back(Int32Ty);    // uint32_t x
188    StructTys.push_back(Int32Ty);    // uint32_t y
189    StructTys.push_back(Int32Ty);    // uint32_t z
190    StructTys.push_back(Int32Ty);    // uint32_t lod
191    StructTys.push_back(Int32Ty);    // enum RsAllocationCubemapFace
192    StructTys.push_back(llvm::ArrayType::get(Int32Ty, 16));  // uint32_t ar[16]
193
194    return llvm::StructType::create(StructTys, "RsForEachStubParamStruct");
195  }
196
197  /// @brief Create skeleton of the expanded function.
198  ///
199  /// This creates a function with the following signature:
200  ///
201  ///   void (const RsForEachStubParamStruct *p, uint32_t x1, uint32_t x2,
202  ///         uint32_t instep, uint32_t outstep)
203  ///
204  llvm::Function *createEmptyExpandedFunction(llvm::StringRef OldName) {
205    llvm::Type *ForEachStubPtrTy = getForeachStubTy()->getPointerTo();
206    llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*C);
207
208    llvm::SmallVector<llvm::Type*, 8> ParamTys;
209    ParamTys.push_back(ForEachStubPtrTy);  // const RsForEachStubParamStruct *p
210    ParamTys.push_back(Int32Ty);           // uint32_t x1
211    ParamTys.push_back(Int32Ty);           // uint32_t x2
212    ParamTys.push_back(Int32Ty);           // uint32_t instep
213    ParamTys.push_back(Int32Ty);           // uint32_t outstep
214
215    llvm::FunctionType *FT =
216        llvm::FunctionType::get(llvm::Type::getVoidTy(*C), ParamTys, false);
217    llvm::Function *F =
218        llvm::Function::Create(FT, llvm::GlobalValue::ExternalLinkage,
219                               OldName + ".expand", M);
220
221    llvm::Function::arg_iterator AI = F->arg_begin();
222
223    AI->setName("p");
224    AI++;
225    AI->setName("x1");
226    AI++;
227    AI->setName("x2");
228    AI++;
229    AI->setName("arg_instep");
230    AI++;
231    AI->setName("arg_outstep");
232    AI++;
233
234    assert(AI == F->arg_end());
235
236    llvm::BasicBlock *Begin = llvm::BasicBlock::Create(*C, "Begin", F);
237    llvm::IRBuilder<> Builder(Begin);
238    Builder.CreateRetVoid();
239
240    return F;
241  }
242
243  /// @brief Create an empty loop
244  ///
245  /// Create a loop of the form:
246  ///
247  /// for (i = LowerBound; i < UpperBound; i++)
248  ///   ;
249  ///
250  /// After the loop has been created, the builder is set such that
251  /// instructions can be added to the loop body.
252  ///
253  /// @param Builder The builder to use to build this loop. The current
254  ///                position of the builder is the position the loop
255  ///                will be inserted.
256  /// @param LowerBound The first value of the loop iterator
257  /// @param UpperBound The maximal value of the loop iterator
258  /// @param LoopIV A reference that will be set to the loop iterator.
259  /// @return The BasicBlock that will be executed after the loop.
260  llvm::BasicBlock *createLoop(llvm::IRBuilder<> &Builder,
261                               llvm::Value *LowerBound,
262                               llvm::Value *UpperBound,
263                               llvm::PHINode **LoopIV) {
264    assert(LowerBound->getType() == UpperBound->getType());
265
266    llvm::BasicBlock *CondBB, *AfterBB, *HeaderBB;
267    llvm::Value *Cond, *IVNext;
268    llvm::PHINode *IV;
269
270    CondBB = Builder.GetInsertBlock();
271    AfterBB = llvm::SplitBlock(CondBB, Builder.GetInsertPoint(), this);
272    HeaderBB = llvm::BasicBlock::Create(*C, "Loop", CondBB->getParent());
273
274    // if (LowerBound < Upperbound)
275    //   goto LoopHeader
276    // else
277    //   goto AfterBB
278    CondBB->getTerminator()->eraseFromParent();
279    Builder.SetInsertPoint(CondBB);
280    Cond = Builder.CreateICmpULT(LowerBound, UpperBound);
281    Builder.CreateCondBr(Cond, HeaderBB, AfterBB);
282
283    // iv = PHI [CondBB -> LowerBound], [LoopHeader -> NextIV ]
284    // iv.next = iv + 1
285    // if (iv.next < Upperbound)
286    //   goto LoopHeader
287    // else
288    //   goto AfterBB
289    Builder.SetInsertPoint(HeaderBB);
290    IV = Builder.CreatePHI(LowerBound->getType(), 2, "X");
291    IV->addIncoming(LowerBound, CondBB);
292    IVNext = Builder.CreateNUWAdd(IV, Builder.getInt32(1));
293    IV->addIncoming(IVNext, HeaderBB);
294    Cond = Builder.CreateICmpULT(IVNext, UpperBound);
295    Builder.CreateCondBr(Cond, HeaderBB, AfterBB);
296    AfterBB->setName("Exit");
297    Builder.SetInsertPoint(HeaderBB->getFirstNonPHI());
298    *LoopIV = IV;
299    return AfterBB;
300  }
301
302public:
303  RSForEachExpandPass(const RSInfo::ExportForeachFuncListTy &pForeachFuncs,
304                      bool pEnableStepOpt)
305      : ModulePass(ID), M(NULL), C(NULL), mFuncs(pForeachFuncs),
306        mEnableStepOpt(pEnableStepOpt) {
307  }
308
309  /* Performs the actual optimization on a selected function. On success, the
310   * Module will contain a new function of the name "<NAME>.expand" that
311   * invokes <NAME>() in a loop with the appropriate parameters.
312   */
313  bool ExpandFunction(llvm::Function *F, uint32_t Signature) {
314    ALOGV("Expanding ForEach-able Function %s", F->getName().str().c_str());
315
316    if (!Signature) {
317      Signature = getRootSignature(F);
318      if (!Signature) {
319        // We couldn't determine how to expand this function based on its
320        // function signature.
321        return false;
322      }
323    }
324
325    llvm::DataLayout DL(M);
326
327    llvm::Function *ExpandedFunc = createEmptyExpandedFunction(F->getName());
328
329    // Create and name the actual arguments to this expanded function.
330    llvm::SmallVector<llvm::Argument*, 8> ArgVec;
331    for (llvm::Function::arg_iterator B = ExpandedFunc->arg_begin(),
332                                      E = ExpandedFunc->arg_end();
333         B != E;
334         ++B) {
335      ArgVec.push_back(B);
336    }
337
338    if (ArgVec.size() != 5) {
339      ALOGE("Incorrect number of arguments to function: %zu",
340            ArgVec.size());
341      return false;
342    }
343    llvm::Value *Arg_p = ArgVec[0];
344    llvm::Value *Arg_x1 = ArgVec[1];
345    llvm::Value *Arg_x2 = ArgVec[2];
346    llvm::Value *Arg_instep = ArgVec[3];
347    llvm::Value *Arg_outstep = ArgVec[4];
348
349    llvm::Value *InStep = NULL;
350    llvm::Value *OutStep = NULL;
351
352    // Construct the actual function body.
353    llvm::IRBuilder<> Builder(ExpandedFunc->getEntryBlock().begin());
354
355    // Collect and construct the arguments for the kernel().
356    // Note that we load any loop-invariant arguments before entering the Loop.
357    llvm::Function::arg_iterator Args = F->arg_begin();
358
359    llvm::Type *InTy = NULL;
360    llvm::Value *InBasePtr = NULL;
361    if (hasIn(Signature)) {
362      InTy = Args->getType();
363      InStep = getStepValue(&DL, InTy, Arg_instep);
364      InStep->setName("instep");
365      InBasePtr = Builder.CreateLoad(Builder.CreateStructGEP(Arg_p, 0));
366      Args++;
367    }
368
369    llvm::Type *OutTy = NULL;
370    llvm::Value *OutBasePtr = NULL;
371    if (hasOut(Signature)) {
372      OutTy = Args->getType();
373      OutStep = getStepValue(&DL, OutTy, Arg_outstep);
374      OutStep->setName("outstep");
375      OutBasePtr = Builder.CreateLoad(Builder.CreateStructGEP(Arg_p, 1));
376      Args++;
377    }
378
379    llvm::Value *UsrData = NULL;
380    if (hasUsrData(Signature)) {
381      llvm::Type *UsrDataTy = Args->getType();
382      UsrData = Builder.CreatePointerCast(Builder.CreateLoad(
383          Builder.CreateStructGEP(Arg_p, 2)), UsrDataTy);
384      UsrData->setName("UsrData");
385      Args++;
386    }
387
388    if (hasX(Signature)) {
389      Args++;
390    }
391
392    llvm::Value *Y = NULL;
393    if (hasY(Signature)) {
394      Y = Builder.CreateLoad(Builder.CreateStructGEP(Arg_p, 5), "Y");
395      Args++;
396    }
397
398    bccAssert(Args == F->arg_end());
399
400    llvm::PHINode *IV;
401    createLoop(Builder, Arg_x1, Arg_x2, &IV);
402
403    // Populate the actual call to kernel().
404    llvm::SmallVector<llvm::Value*, 8> RootArgs;
405
406    llvm::Value *InPtr = NULL;
407    llvm::Value *OutPtr = NULL;
408
409    // Calculate the current input and output pointers
410    //
411    // We always calculate the input/output pointers with a GEP operating on i8
412    // values and only cast at the very end to OutTy. This is because the step
413    // between two values is given in bytes.
414    //
415    // TODO: We could further optimize the output by using a GEP operation of
416    // type 'OutTy' in cases where the element type of the allocation allows.
417    if (OutBasePtr) {
418      llvm::Value *OutOffset = Builder.CreateSub(IV, Arg_x1);
419      OutOffset = Builder.CreateMul(OutOffset, OutStep);
420      OutPtr = Builder.CreateGEP(OutBasePtr, OutOffset);
421      OutPtr = Builder.CreatePointerCast(OutPtr, OutTy);
422    }
423    if (InBasePtr) {
424      llvm::Value *InOffset = Builder.CreateSub(IV, Arg_x1);
425      InOffset = Builder.CreateMul(InOffset, InStep);
426      InPtr = Builder.CreateGEP(InBasePtr, InOffset);
427      InPtr = Builder.CreatePointerCast(InPtr, InTy);
428    }
429
430    if (InPtr) {
431      RootArgs.push_back(InPtr);
432    }
433
434    if (OutPtr) {
435      RootArgs.push_back(OutPtr);
436    }
437
438    if (UsrData) {
439      RootArgs.push_back(UsrData);
440    }
441
442    llvm::Value *X = IV;
443    if (hasX(Signature)) {
444      RootArgs.push_back(X);
445    }
446
447    if (Y) {
448      RootArgs.push_back(Y);
449    }
450
451    Builder.CreateCall(F, RootArgs);
452
453    return true;
454  }
455
456  /* Expand a pass-by-value kernel.
457   */
458  bool ExpandKernel(llvm::Function *F, uint32_t Signature) {
459    bccAssert(isKernel(Signature));
460    ALOGV("Expanding kernel Function %s", F->getName().str().c_str());
461
462    // TODO: Refactor this to share functionality with ExpandFunction.
463    llvm::DataLayout DL(M);
464
465    llvm::Function *ExpandedFunc = createEmptyExpandedFunction(F->getName());
466
467    // Create and name the actual arguments to this expanded function.
468    llvm::SmallVector<llvm::Argument*, 8> ArgVec;
469    for (llvm::Function::arg_iterator B = ExpandedFunc->arg_begin(),
470                                      E = ExpandedFunc->arg_end();
471         B != E;
472         ++B) {
473      ArgVec.push_back(B);
474    }
475
476    if (ArgVec.size() != 5) {
477      ALOGE("Incorrect number of arguments to function: %zu",
478            ArgVec.size());
479      return false;
480    }
481    llvm::Value *Arg_p = ArgVec[0];
482    llvm::Value *Arg_x1 = ArgVec[1];
483    llvm::Value *Arg_x2 = ArgVec[2];
484    llvm::Value *Arg_instep = ArgVec[3];
485    llvm::Value *Arg_outstep = ArgVec[4];
486
487    llvm::Value *InStep = NULL;
488    llvm::Value *OutStep = NULL;
489
490    // Construct the actual function body.
491    llvm::IRBuilder<> Builder(ExpandedFunc->getEntryBlock().begin());
492
493    // Collect and construct the arguments for the kernel().
494    // Note that we load any loop-invariant arguments before entering the Loop.
495    llvm::Function::arg_iterator Args = F->arg_begin();
496
497    llvm::Type *OutTy = NULL;
498    bool PassOutByReference = false;
499    llvm::Value *OutBasePtr = NULL;
500    if (hasOut(Signature)) {
501      llvm::Type *OutBaseTy = F->getReturnType();
502      if (OutBaseTy->isVoidTy()) {
503        PassOutByReference = true;
504        OutTy = Args->getType();
505        Args++;
506      } else {
507        OutTy = OutBaseTy->getPointerTo();
508        // We don't increment Args, since we are using the actual return type.
509      }
510      OutStep = getStepValue(&DL, OutTy, Arg_outstep);
511      OutStep->setName("outstep");
512      OutBasePtr = Builder.CreateLoad(Builder.CreateStructGEP(Arg_p, 1));
513    }
514
515    llvm::Type *InBaseTy = NULL;
516    llvm::Type *InTy = NULL;
517    llvm::Value *InBasePtr = NULL;
518    if (hasIn(Signature)) {
519      InBaseTy = Args->getType();
520      InTy =InBaseTy->getPointerTo();
521      InStep = getStepValue(&DL, InTy, Arg_instep);
522      InStep->setName("instep");
523      InBasePtr = Builder.CreateLoad(Builder.CreateStructGEP(Arg_p, 0));
524      Args++;
525    }
526
527    // No usrData parameter on kernels.
528    bccAssert(!hasUsrData(Signature));
529
530    if (hasX(Signature)) {
531      Args++;
532    }
533
534    llvm::Value *Y = NULL;
535    if (hasY(Signature)) {
536      Y = Builder.CreateLoad(Builder.CreateStructGEP(Arg_p, 5), "Y");
537      Args++;
538    }
539
540    bccAssert(Args == F->arg_end());
541
542    llvm::PHINode *IV;
543    createLoop(Builder, Arg_x1, Arg_x2, &IV);
544
545    // Populate the actual call to kernel().
546    llvm::SmallVector<llvm::Value*, 8> RootArgs;
547
548    llvm::Value *InPtr = NULL;
549    llvm::Value *OutPtr = NULL;
550
551    // Calculate the current input and output pointers
552    //
553    // We always calculate the input/output pointers with a GEP operating on i8
554    // values and only cast at the very end to OutTy. This is because the step
555    // between two values is given in bytes.
556    //
557    // TODO: We could further optimize the output by using a GEP operation of
558    // type 'OutTy' in cases where the element type of the allocation allows.
559    if (OutBasePtr) {
560      llvm::Value *OutOffset = Builder.CreateSub(IV, Arg_x1);
561      OutOffset = Builder.CreateMul(OutOffset, OutStep);
562      OutPtr = Builder.CreateGEP(OutBasePtr, OutOffset);
563      OutPtr = Builder.CreatePointerCast(OutPtr, OutTy);
564    }
565    if (InBasePtr) {
566      llvm::Value *InOffset = Builder.CreateSub(IV, Arg_x1);
567      InOffset = Builder.CreateMul(InOffset, InStep);
568      InPtr = Builder.CreateGEP(InBasePtr, InOffset);
569      InPtr = Builder.CreatePointerCast(InPtr, InTy);
570    }
571
572    if (PassOutByReference) {
573      RootArgs.push_back(OutPtr);
574    }
575
576    if (InPtr) {
577      llvm::Value *In = Builder.CreateLoad(InPtr, "In");
578      RootArgs.push_back(In);
579    }
580
581    llvm::Value *X = IV;
582    if (hasX(Signature)) {
583      RootArgs.push_back(X);
584    }
585
586    if (Y) {
587      RootArgs.push_back(Y);
588    }
589
590    llvm::Value *RetVal = Builder.CreateCall(F, RootArgs);
591
592    if (OutPtr && !PassOutByReference) {
593      Builder.CreateStore(RetVal, OutPtr);
594    }
595
596    return true;
597  }
598
599  virtual bool runOnModule(llvm::Module &M) {
600    bool Changed = false;
601    this->M = &M;
602    C = &M.getContext();
603
604    for (RSInfo::ExportForeachFuncListTy::const_iterator
605             func_iter = mFuncs.begin(), func_end = mFuncs.end();
606         func_iter != func_end; func_iter++) {
607      const char *name = func_iter->first;
608      uint32_t signature = func_iter->second;
609      llvm::Function *kernel = M.getFunction(name);
610      if (kernel) {
611        if (isKernel(signature)) {
612          Changed |= ExpandKernel(kernel, signature);
613          kernel->setLinkage(llvm::GlobalValue::InternalLinkage);
614        } else if (kernel->getReturnType()->isVoidTy()) {
615          Changed |= ExpandFunction(kernel, signature);
616          kernel->setLinkage(llvm::GlobalValue::InternalLinkage);
617        } else {
618          // There are some graphics root functions that are not
619          // expanded, but that will be called directly. For those
620          // functions, we can not set the linkage to internal.
621        }
622      }
623    }
624
625    return Changed;
626  }
627
628  virtual const char *getPassName() const {
629    return "ForEach-able Function Expansion";
630  }
631
632}; // end RSForEachExpandPass
633
634} // end anonymous namespace
635
636char RSForEachExpandPass::ID = 0;
637
638namespace bcc {
639
640llvm::ModulePass *
641createRSForEachExpandPass(const RSInfo::ExportForeachFuncListTy &pForeachFuncs,
642                          bool pEnableStepOpt){
643  return new RSForEachExpandPass(pForeachFuncs, pEnableStepOpt);
644}
645
646} // end namespace bcc
647