| Yang Ni | 6749f54 | 2016-11-07 20:20:49 -0800 | [diff] [blame] | 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 "SPIRVModule.h" |
| 20 | #include "bcinfo/MetadataExtractor.h" |
| 21 | |
| 22 | #include "llvm/ADT/StringMap.h" |
| 23 | #include "llvm/ADT/Triple.h" |
| 24 | #include "llvm/IR/LegacyPassManager.h" |
| 25 | #include "llvm/IR/Module.h" |
| 26 | #include "llvm/Support/CommandLine.h" |
| 27 | #include "llvm/Support/Debug.h" |
| 28 | #include "llvm/Support/SPIRV.h" |
| 29 | #include "llvm/Support/raw_ostream.h" |
| 30 | #include "llvm/Transforms/IPO.h" |
| 31 | |
| 32 | #include "GlobalMergePass.h" |
| Yang Ni | ec9360e | 2016-11-21 15:50:27 -0800 | [diff] [blame] | 33 | #include "InlinePreparationPass.h" |
| Yang Ni | 6749f54 | 2016-11-07 20:20:49 -0800 | [diff] [blame] | 34 | #include "ReflectionPass.h" |
| I-Jui (Ray) Sung | 3523b2f | 2017-01-19 17:18:23 -0800 | [diff] [blame] | 35 | #include "RemoveNonkernelsPass.h" |
| Yang Ni | 6749f54 | 2016-11-07 20:20:49 -0800 | [diff] [blame] | 36 | |
| 37 | #include <fstream> |
| 38 | #include <sstream> |
| 39 | |
| 40 | #define DEBUG_TYPE "rs2spirv-writer" |
| 41 | |
| 42 | using namespace llvm; |
| 43 | using namespace SPIRV; |
| 44 | |
| 45 | namespace llvm { |
| 46 | FunctionPass *createPromoteMemoryToRegisterPass(); |
| Rahul Chaudhry | 7974fc0 | 2017-02-09 12:33:28 -0800 | [diff] [blame^] | 47 | } // namespace llvm |
| Yang Ni | 6749f54 | 2016-11-07 20:20:49 -0800 | [diff] [blame] | 48 | |
| 49 | namespace rs2spirv { |
| 50 | |
| 51 | static cl::opt<std::string> WrapperOutputFile("wo", |
| 52 | cl::desc("Wrapper output file"), |
| 53 | cl::value_desc("filename.spt")); |
| 54 | |
| Yang Ni | 6749f54 | 2016-11-07 20:20:49 -0800 | [diff] [blame] | 55 | static void HandleTargetTriple(Module &M) { |
| 56 | Triple TT(M.getTargetTriple()); |
| 57 | auto Arch = TT.getArch(); |
| 58 | |
| 59 | StringRef NewTriple; |
| 60 | switch (Arch) { |
| 61 | default: |
| 62 | llvm_unreachable("Unrecognized architecture"); |
| 63 | break; |
| 64 | case Triple::arm: |
| 65 | NewTriple = "spir-unknown-unknown"; |
| 66 | break; |
| 67 | case Triple::aarch64: |
| 68 | NewTriple = "spir64-unknown-unknown"; |
| 69 | break; |
| 70 | case Triple::spir: |
| 71 | case Triple::spir64: |
| 72 | DEBUG(dbgs() << "!!! Already a spir triple !!!\n"); |
| 73 | } |
| 74 | |
| 75 | DEBUG(dbgs() << "New triple:\t" << NewTriple << "\n"); |
| 76 | M.setTargetTriple(NewTriple); |
| 77 | } |
| 78 | |
| I-Jui (Ray) Sung | 3523b2f | 2017-01-19 17:18:23 -0800 | [diff] [blame] | 79 | void addPassesForRS2SPIRV(llvm::legacy::PassManager &PassMgr, |
| 80 | bcinfo::MetadataExtractor &Extractor) { |
| 81 | PassMgr.add(createInlinePreparationPass(Extractor)); |
| 82 | PassMgr.add(createAlwaysInlinerPass()); |
| 83 | PassMgr.add(createRemoveNonkernelsPass(Extractor)); |
| 84 | // Delete unreachable globals. |
| 85 | PassMgr.add(createGlobalDCEPass()); |
| 86 | // Remove dead debug info. |
| 87 | PassMgr.add(createStripDeadDebugInfoPass()); |
| 88 | // Remove dead func decls. |
| 89 | PassMgr.add(createStripDeadPrototypesPass()); |
| Yang Ni | 6749f54 | 2016-11-07 20:20:49 -0800 | [diff] [blame] | 90 | PassMgr.add(createGlobalMergePass()); |
| 91 | PassMgr.add(createPromoteMemoryToRegisterPass()); |
| 92 | PassMgr.add(createTransOCLMD()); |
| 93 | // TODO: investigate removal of OCLTypeToSPIRV pass. |
| 94 | PassMgr.add(createOCLTypeToSPIRV()); |
| 95 | PassMgr.add(createSPIRVRegularizeLLVM()); |
| 96 | PassMgr.add(createSPIRVLowerConstExpr()); |
| 97 | PassMgr.add(createSPIRVLowerBool()); |
| Yang Ni | 6749f54 | 2016-11-07 20:20:49 -0800 | [diff] [blame] | 98 | } |
| 99 | |
| 100 | bool WriteSPIRV(Module *M, llvm::raw_ostream &OS, std::string &ErrMsg) { |
| 101 | std::unique_ptr<SPIRVModule> BM(SPIRVModule::createSPIRVModule()); |
| 102 | |
| 103 | HandleTargetTriple(*M); |
| 104 | |
| 105 | bcinfo::MetadataExtractor ME(M); |
| 106 | if (!ME.extract()) { |
| 107 | errs() << "Could not extract metadata\n"; |
| 108 | return false; |
| 109 | } |
| 110 | DEBUG(dbgs() << "Metadata extracted\n"); |
| 111 | |
| 112 | llvm::legacy::PassManager PassMgr; |
| I-Jui (Ray) Sung | 3523b2f | 2017-01-19 17:18:23 -0800 | [diff] [blame] | 113 | addPassesForRS2SPIRV(PassMgr, ME); |
| Yang Ni | 6749f54 | 2016-11-07 20:20:49 -0800 | [diff] [blame] | 114 | |
| 115 | std::ofstream WrapperF; |
| 116 | if (!WrapperOutputFile.empty()) { |
| 117 | WrapperF.open(WrapperOutputFile, std::ios::trunc); |
| 118 | if (!WrapperF.good()) { |
| 119 | errs() << "Could not create/open file:\t" << WrapperOutputFile << "\n"; |
| 120 | return false; |
| 121 | } |
| 122 | DEBUG(dbgs() << "Wrapper output:\t" << WrapperOutputFile << "\n"); |
| 123 | PassMgr.add(createReflectionPass(WrapperF, ME)); |
| 124 | } |
| 125 | |
| 126 | PassMgr.add(createLLVMToSPIRV(BM.get())); |
| 127 | PassMgr.run(*M); |
| 128 | DEBUG(M->dump()); |
| 129 | |
| 130 | if (BM->getError(ErrMsg) != SPIRVEC_Success) |
| 131 | return false; |
| 132 | |
| 133 | OS << *BM; |
| 134 | |
| 135 | return true; |
| 136 | } |
| 137 | |
| Yang Ni | 6749f54 | 2016-11-07 20:20:49 -0800 | [diff] [blame] | 138 | } // namespace rs2spirv |