| /* |
| * 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 { |
| |
| namespace { |
| |
| void HandleTargetTriple(llvm::Module &M) { |
| Triple TT(M.getTargetTriple()); |
| auto Arch = TT.getArch(); |
| |
| StringRef NewTriple; |
| switch (Arch) { |
| default: |
| llvm_unreachable("Unrecognized architecture"); |
| break; |
| case Triple::arm: |
| NewTriple = "spir-unknown-unknown"; |
| break; |
| case Triple::aarch64: |
| NewTriple = "spir64-unknown-unknown"; |
| break; |
| case Triple::spir: |
| case Triple::spir64: |
| DEBUG(dbgs() << "!!! Already a spir triple !!!\n"); |
| } |
| |
| DEBUG(dbgs() << "New triple:\t" << NewTriple << "\n"); |
| M.setTargetTriple(NewTriple); |
| } |
| |
| } // namespace |
| |
| void addPassesForRS2SPIRV(llvm::legacy::PassManager &PassMgr) { |
| 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()); |
| PassMgr.add(createGlobalMergePass()); |
| // 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(llvm::Module *M, std::unique_ptr<bcinfo::MetadataExtractor> ME, |
| llvm::raw_ostream &OS, std::string &ErrMsg) { |
| HandleTargetTriple(*M); |
| |
| Context &Ctxt = Context::getInstance(); |
| |
| if (!Ctxt.Initialize(std::move(ME))) { |
| ErrMsg = "Failed to intialize rs2spirv"; |
| return false; |
| } |
| |
| 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 |