1/*
2 * Copyright 2016, 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 "RSSPIRVWriter.h"
18
19#include "Builtin.h"
20#include "Context.h"
21#include "GlobalAllocPass.h"
22#include "GlobalAllocSPIRITPass.h"
23#include "GlobalMergePass.h"
24#include "InlinePreparationPass.h"
25#include "RemoveNonkernelsPass.h"
26#include "SPIRVModule.h"
27#include "Wrapper.h"
28#include "bcinfo/MetadataExtractor.h"
29#include "pass_queue.h"
30
31#include "llvm/ADT/Triple.h"
32#include "llvm/IR/LegacyPassManager.h"
33#include "llvm/IR/Module.h"
34#include "llvm/Support/CommandLine.h"
35#include "llvm/Support/Debug.h"
36#include "llvm/Support/SPIRV.h"
37#include "llvm/Support/raw_ostream.h"
38#include "llvm/Transforms/IPO.h"
39#include "llvm/Transforms/Scalar.h"
40
41#define DEBUG_TYPE "rs2spirv-writer"
42
43using namespace llvm;
44using namespace SPIRV;
45
46namespace rs2spirv {
47
48void addPassesForRS2SPIRV(llvm::legacy::PassManager &PassMgr) {
49  PassMgr.add(createGlobalMergePass());
50
51  PassMgr.add(createInlinePreparationPass());
52  PassMgr.add(createAlwaysInlinerPass());
53  PassMgr.add(createRemoveNonkernelsPass());
54  // Delete unreachable globals.
55  PassMgr.add(createGlobalDCEPass());
56  // Remove dead debug info.
57  PassMgr.add(createStripDeadDebugInfoPass());
58  // Remove dead func decls.
59  PassMgr.add(createStripDeadPrototypesPass());
60  // Transform global allocations and accessors (rs[GS]etElementAt)
61  PassMgr.add(createGlobalAllocPass());
62  // Removed dead MemCpys in 64-bit targets after global alloc pass
63  PassMgr.add(createDeadStoreEliminationPass());
64  PassMgr.add(createAggressiveDCEPass());
65  // Delete unreachable globals (after removing global allocations)
66  PassMgr.add(createRemoveAllGlobalAllocPass());
67  PassMgr.add(createPromoteMemoryToRegisterPass());
68  PassMgr.add(createTransOCLMD());
69  // TODO: investigate removal of OCLTypeToSPIRV pass.
70  PassMgr.add(createOCLTypeToSPIRV());
71  PassMgr.add(createSPIRVRegularizeLLVM());
72  PassMgr.add(createSPIRVLowerConstExpr());
73  PassMgr.add(createSPIRVLowerBool());
74}
75
76bool WriteSPIRV(Context &Ctxt, Module *M,
77                llvm::raw_ostream &OS, std::string &ErrMsg) {
78  llvm::legacy::PassManager PassMgr;
79  addPassesForRS2SPIRV(PassMgr);
80
81  std::unique_ptr<SPIRVModule> BM(SPIRVModule::createSPIRVModule());
82
83  PassMgr.add(createLLVMToSPIRV(BM.get()));
84  PassMgr.run(*M);
85  DEBUG(M->dump());
86
87  if (BM->getError(ErrMsg) != SPIRVEC_Success) {
88    return false;
89  }
90
91  llvm::SmallString<4096> O;
92  llvm::raw_svector_ostream SVOS(O);
93
94  SVOS << *BM;
95
96  llvm::StringRef str = SVOS.str();
97  std::vector<uint32_t> words(str.size() / 4);
98
99  memcpy(words.data(), str.data(), str.size());
100
101  android::spirit::PassQueue spiritPasses;
102  spiritPasses.append(CreateWrapperPass(*M));
103  spiritPasses.append(CreateBuiltinPass());
104  spiritPasses.append(CreateGAPass());
105
106  int error;
107  auto wordsOut = spiritPasses.run(words, &error);
108
109  if (error != 0) {
110    OS << *BM;
111    ErrMsg = "Failed to generate wrappers for kernels";
112    return false;
113  }
114
115  OS.write(reinterpret_cast<const char *>(wordsOut.data()),
116           wordsOut.size() * 4);
117
118  return true;
119}
120
121} // namespace rs2spirv
122