C++程序  |  159行  |  5.27 KB

/*
 * Copyright 2012, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "bcc/Assert.h"
#include "bcc/Renderscript/RSTransforms.h"

#include <cstdlib>
#include <vector>

#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Module.h>
#include <llvm/Pass.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/IR/Type.h>

#include "bcc/Config/Config.h"
#include "bcc/Renderscript/RSInfo.h"
#include "bcc/Support/Log.h"

using namespace bcc;

namespace {

/* RSForEachExpandPass - This pass operates on functions that are able to be
 * called via rsForEach() or "foreach_<NAME>". We create an inner loop for the
 * ForEach-able function to be invoked over the appropriate data cells of the
 * input/output allocations (adjusting other relevant parameters as we go). We
 * support doing this for any ForEach-able compute kernels. The new function
 * name is the original function name followed by ".expand". Note that we
 * still generate code for the original function.
 */
class RSEmbedInfoPass : public llvm::ModulePass {
private:
  static char ID;

  llvm::Module *M;
  llvm::LLVMContext *C;

  const RSInfo *mInfo;

public:
  RSEmbedInfoPass(const RSInfo *info)
      : ModulePass(ID),
        mInfo(info) {
  }

  virtual bool runOnModule(llvm::Module &M) {
    this->M = &M;
    C = &M.getContext();

    std::string str;
    llvm::raw_string_ostream s(str);

    // We use a simple text format here that the compatibility library can
    // easily parse. Each section starts out with its name followed by a count.
    // The count denotes the number of lines to parse for that particular
    // category. Variables and Functions merely put the appropriate identifier
    // on the line, while ForEach kernels have the encoded int signature,
    // followed by a hyphen followed by the identifier (function to look up).
    // Object Slots are just listed as one integer per line.
    const RSInfo::ExportVarNameListTy &export_vars = mInfo->getExportVarNames();
    s << "exportVarCount: " << (unsigned int) export_vars.size() << "\n";
    for (RSInfo::ExportVarNameListTy::const_iterator
             export_var_iter = export_vars.begin(),
             export_var_end = export_vars.end();
         export_var_iter != export_var_end; export_var_iter++) {
      s << *export_var_iter << "\n";
    }

    const RSInfo::ExportFuncNameListTy &export_funcs =
        mInfo->getExportFuncNames();
    s << "exportFuncCount: " << (unsigned int) export_funcs.size() << "\n";
    for (RSInfo::ExportFuncNameListTy::const_iterator
             export_func_iter = export_funcs.begin(),
             export_func_end = export_funcs.end();
         export_func_iter != export_func_end; export_func_iter++) {
      s << *export_func_iter << "\n";
    }

    const RSInfo::ExportForeachFuncListTy &export_foreach_funcs =
        mInfo->getExportForeachFuncs();
    s << "exportForEachCount: "
      << (unsigned int) export_foreach_funcs.size() << "\n";
    for (RSInfo::ExportForeachFuncListTy::const_iterator
             foreach_func_iter = export_foreach_funcs.begin(),
             foreach_func_end = export_foreach_funcs.end();
         foreach_func_iter != foreach_func_end; foreach_func_iter++) {
      std::string name(foreach_func_iter->first);
      s << foreach_func_iter->second << " - "
        << foreach_func_iter->first << "\n";
    }

    std::vector<unsigned int> object_slot_numbers;
    unsigned int i = 0;
    const RSInfo::ObjectSlotListTy &object_slots = mInfo->getObjectSlots();
    for (RSInfo::ObjectSlotListTy::const_iterator
             slots_iter = object_slots.begin(),
             slots_end = object_slots.end();
         slots_iter != slots_end; slots_iter++) {
      if (*slots_iter) {
        object_slot_numbers.push_back(i);
      }
      i++;
    }
    s << "objectSlotCount: " << (unsigned int) object_slot_numbers.size()
      << "\n";
    for (i = 0; i < object_slot_numbers.size(); i++) {
      s << object_slot_numbers[i] << "\n";
    }

    s.flush();

    // Embed this as the global variable .rs.info so that it will be
    // accessible from the shared object later.
    llvm::Constant *Init = llvm::ConstantDataArray::getString(*C, str);
    llvm::GlobalVariable *InfoGV =
        new llvm::GlobalVariable(M, Init->getType(), true,
                                 llvm::GlobalValue::ExternalLinkage, Init,
                                 ".rs.info");
    (void) InfoGV;

    return true;
  }

  virtual const char *getPassName() const {
    return "Embed Renderscript Info";
  }

};  // end RSEmbedInfoPass

}  // end anonymous namespace

char RSEmbedInfoPass::ID = 0;

namespace bcc {

llvm::ModulePass *
createRSEmbedInfoPass(const RSInfo *info) {
  return new RSEmbedInfoPass(info);
}

}  // end namespace bcc