C++程序  |  122行  |  3.55 KB

/*
 * Copyright 2016, 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 "RSSPIRVWriter.h"

#include "Builtin.h"
#include "Context.h"
#include "GlobalAllocPass.h"
#include "GlobalAllocSPIRITPass.h"
#include "GlobalMergePass.h"
#include "InlinePreparationPass.h"
#include "RemoveNonkernelsPass.h"
#include "SPIRVModule.h"
#include "Wrapper.h"
#include "bcinfo/MetadataExtractor.h"
#include "pass_queue.h"

#include "llvm/ADT/Triple.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/SPIRV.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar.h"

#define DEBUG_TYPE "rs2spirv-writer"

using namespace llvm;
using namespace SPIRV;

namespace rs2spirv {

void addPassesForRS2SPIRV(llvm::legacy::PassManager &PassMgr) {
  PassMgr.add(createGlobalMergePass());

  PassMgr.add(createInlinePreparationPass());
  PassMgr.add(createAlwaysInlinerPass());
  PassMgr.add(createRemoveNonkernelsPass());
  // Delete unreachable globals.
  PassMgr.add(createGlobalDCEPass());
  // Remove dead debug info.
  PassMgr.add(createStripDeadDebugInfoPass());
  // Remove dead func decls.
  PassMgr.add(createStripDeadPrototypesPass());
  // Transform global allocations and accessors (rs[GS]etElementAt)
  PassMgr.add(createGlobalAllocPass());
  // Removed dead MemCpys in 64-bit targets after global alloc pass
  PassMgr.add(createDeadStoreEliminationPass());
  PassMgr.add(createAggressiveDCEPass());
  // Delete unreachable globals (after removing global allocations)
  PassMgr.add(createRemoveAllGlobalAllocPass());
  PassMgr.add(createPromoteMemoryToRegisterPass());
  PassMgr.add(createTransOCLMD());
  // TODO: investigate removal of OCLTypeToSPIRV pass.
  PassMgr.add(createOCLTypeToSPIRV());
  PassMgr.add(createSPIRVRegularizeLLVM());
  PassMgr.add(createSPIRVLowerConstExpr());
  PassMgr.add(createSPIRVLowerBool());
}

bool WriteSPIRV(Context &Ctxt, Module *M,
                llvm::raw_ostream &OS, std::string &ErrMsg) {
  llvm::legacy::PassManager PassMgr;
  addPassesForRS2SPIRV(PassMgr);

  std::unique_ptr<SPIRVModule> BM(SPIRVModule::createSPIRVModule());

  PassMgr.add(createLLVMToSPIRV(BM.get()));
  PassMgr.run(*M);
  DEBUG(M->dump());

  if (BM->getError(ErrMsg) != SPIRVEC_Success) {
    return false;
  }

  llvm::SmallString<4096> O;
  llvm::raw_svector_ostream SVOS(O);

  SVOS << *BM;

  llvm::StringRef str = SVOS.str();
  std::vector<uint32_t> words(str.size() / 4);

  memcpy(words.data(), str.data(), str.size());

  android::spirit::PassQueue spiritPasses;
  spiritPasses.append(CreateWrapperPass(*M));
  spiritPasses.append(CreateBuiltinPass());
  spiritPasses.append(CreateGAPass());

  int error;
  auto wordsOut = spiritPasses.run(words, &error);

  if (error != 0) {
    OS << *BM;
    ErrMsg = "Failed to generate wrappers for kernels";
    return false;
  }

  OS.write(reinterpret_cast<const char *>(wordsOut.data()),
           wordsOut.size() * 4);

  return true;
}

} // namespace rs2spirv