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
43 using namespace llvm;
44 using namespace SPIRV;
45
46 namespace rs2spirv {
47
addPassesForRS2SPIRV(llvm::legacy::PassManager & PassMgr)48 void 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
WriteSPIRV(Context & Ctxt,Module * M,llvm::raw_ostream & OS,std::string & ErrMsg)76 bool 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