/* * 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 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 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(wordsOut.data()), wordsOut.size() * 4); return true; } } // namespace rs2spirv