1bca2b6d2SVyacheslav Levytskyy //===-- SPIRVAPI.cpp - SPIR-V Backend API ---------------------*- C++ -*---===// 2bca2b6d2SVyacheslav Levytskyy // 3bca2b6d2SVyacheslav Levytskyy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bca2b6d2SVyacheslav Levytskyy // See https://llvm.org/LICENSE.txt for license information. 5bca2b6d2SVyacheslav Levytskyy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bca2b6d2SVyacheslav Levytskyy // 7bca2b6d2SVyacheslav Levytskyy //===----------------------------------------------------------------------===// 8bca2b6d2SVyacheslav Levytskyy 9bca2b6d2SVyacheslav Levytskyy #include "SPIRVCommandLine.h" 10bca2b6d2SVyacheslav Levytskyy #include "SPIRVSubtarget.h" 11*df122fc7SVyacheslav Levytskyy #include "SPIRVTargetMachine.h" 12bca2b6d2SVyacheslav Levytskyy #include "llvm/Analysis/TargetLibraryInfo.h" 13bca2b6d2SVyacheslav Levytskyy #include "llvm/CodeGen/CommandFlags.h" 14bca2b6d2SVyacheslav Levytskyy #include "llvm/CodeGen/MachineFunctionPass.h" 15bca2b6d2SVyacheslav Levytskyy #include "llvm/CodeGen/MachineModuleInfo.h" 16bca2b6d2SVyacheslav Levytskyy #include "llvm/CodeGen/TargetPassConfig.h" 17bca2b6d2SVyacheslav Levytskyy #include "llvm/CodeGen/TargetSubtargetInfo.h" 18bca2b6d2SVyacheslav Levytskyy #include "llvm/IR/DataLayout.h" 19bca2b6d2SVyacheslav Levytskyy #include "llvm/IR/LLVMContext.h" 20bca2b6d2SVyacheslav Levytskyy #include "llvm/IR/LegacyPassManager.h" 21bca2b6d2SVyacheslav Levytskyy #include "llvm/IR/Module.h" 22bca2b6d2SVyacheslav Levytskyy #include "llvm/IR/Verifier.h" 23bca2b6d2SVyacheslav Levytskyy #include "llvm/InitializePasses.h" 24bca2b6d2SVyacheslav Levytskyy #include "llvm/MC/MCTargetOptionsCommandFlags.h" 25bca2b6d2SVyacheslav Levytskyy #include "llvm/MC/TargetRegistry.h" 26bca2b6d2SVyacheslav Levytskyy #include "llvm/Pass.h" 27bca2b6d2SVyacheslav Levytskyy #include "llvm/Support/CommandLine.h" 28bca2b6d2SVyacheslav Levytskyy #include "llvm/Support/FormattedStream.h" 29bca2b6d2SVyacheslav Levytskyy #include "llvm/Support/InitLLVM.h" 30bca2b6d2SVyacheslav Levytskyy #include "llvm/Support/TargetSelect.h" 31bca2b6d2SVyacheslav Levytskyy #include "llvm/Target/TargetLoweringObjectFile.h" 32bca2b6d2SVyacheslav Levytskyy #include "llvm/Target/TargetMachine.h" 33bca2b6d2SVyacheslav Levytskyy #include "llvm/TargetParser/SubtargetFeature.h" 34bca2b6d2SVyacheslav Levytskyy #include "llvm/TargetParser/Triple.h" 35bca2b6d2SVyacheslav Levytskyy #include <optional> 36bca2b6d2SVyacheslav Levytskyy #include <string> 37bca2b6d2SVyacheslav Levytskyy #include <utility> 38bca2b6d2SVyacheslav Levytskyy #include <vector> 39bca2b6d2SVyacheslav Levytskyy 40bca2b6d2SVyacheslav Levytskyy using namespace llvm; 41bca2b6d2SVyacheslav Levytskyy 42bca2b6d2SVyacheslav Levytskyy namespace { 43bca2b6d2SVyacheslav Levytskyy 44bca2b6d2SVyacheslav Levytskyy std::once_flag InitOnceFlag; 45bca2b6d2SVyacheslav Levytskyy void InitializeSPIRVTarget() { 46bca2b6d2SVyacheslav Levytskyy std::call_once(InitOnceFlag, []() { 47bca2b6d2SVyacheslav Levytskyy LLVMInitializeSPIRVTargetInfo(); 48bca2b6d2SVyacheslav Levytskyy LLVMInitializeSPIRVTarget(); 49bca2b6d2SVyacheslav Levytskyy LLVMInitializeSPIRVTargetMC(); 50bca2b6d2SVyacheslav Levytskyy LLVMInitializeSPIRVAsmPrinter(); 51bca2b6d2SVyacheslav Levytskyy }); 52bca2b6d2SVyacheslav Levytskyy } 53bca2b6d2SVyacheslav Levytskyy } // namespace 54bca2b6d2SVyacheslav Levytskyy 55bca2b6d2SVyacheslav Levytskyy namespace llvm { 56bca2b6d2SVyacheslav Levytskyy 57bca2b6d2SVyacheslav Levytskyy // The goal of this function is to facilitate integration of SPIRV Backend into 58bca2b6d2SVyacheslav Levytskyy // tools and libraries by means of exposing an API call that translate LLVM 59bca2b6d2SVyacheslav Levytskyy // module to SPIR-V and write results into a string as binary SPIR-V output, 60*df122fc7SVyacheslav Levytskyy // providing diagnostics on fail and means of configuring translation. 61bca2b6d2SVyacheslav Levytskyy extern "C" LLVM_EXTERNAL_VISIBILITY bool 62*df122fc7SVyacheslav Levytskyy SPIRVTranslate(Module *M, std::string &SpirvObj, std::string &ErrMsg, 63bca2b6d2SVyacheslav Levytskyy const std::vector<std::string> &AllowExtNames, 64*df122fc7SVyacheslav Levytskyy llvm::CodeGenOptLevel OLevel, Triple TargetTriple) { 65bca2b6d2SVyacheslav Levytskyy // Fallbacks for option values. 66bca2b6d2SVyacheslav Levytskyy static const std::string DefaultTriple = "spirv64-unknown-unknown"; 67bca2b6d2SVyacheslav Levytskyy static const std::string DefaultMArch = ""; 68bca2b6d2SVyacheslav Levytskyy 69bca2b6d2SVyacheslav Levytskyy std::set<SPIRV::Extension::Extension> AllowedExtIds; 70bca2b6d2SVyacheslav Levytskyy StringRef UnknownExt = 71bca2b6d2SVyacheslav Levytskyy SPIRVExtensionsParser::checkExtensions(AllowExtNames, AllowedExtIds); 72bca2b6d2SVyacheslav Levytskyy if (!UnknownExt.empty()) { 73bca2b6d2SVyacheslav Levytskyy ErrMsg = "Unknown SPIR-V extension: " + UnknownExt.str(); 74bca2b6d2SVyacheslav Levytskyy return false; 75bca2b6d2SVyacheslav Levytskyy } 76bca2b6d2SVyacheslav Levytskyy 77bca2b6d2SVyacheslav Levytskyy // SPIR-V-specific target initialization. 78bca2b6d2SVyacheslav Levytskyy InitializeSPIRVTarget(); 79bca2b6d2SVyacheslav Levytskyy 80bca2b6d2SVyacheslav Levytskyy if (TargetTriple.getTriple().empty()) { 81bca2b6d2SVyacheslav Levytskyy TargetTriple.setTriple(DefaultTriple); 82bca2b6d2SVyacheslav Levytskyy M->setTargetTriple(DefaultTriple); 83bca2b6d2SVyacheslav Levytskyy } 84bca2b6d2SVyacheslav Levytskyy const Target *TheTarget = 85bca2b6d2SVyacheslav Levytskyy TargetRegistry::lookupTarget(DefaultMArch, TargetTriple, ErrMsg); 86bca2b6d2SVyacheslav Levytskyy if (!TheTarget) 87bca2b6d2SVyacheslav Levytskyy return false; 88bca2b6d2SVyacheslav Levytskyy 89bca2b6d2SVyacheslav Levytskyy // A call to codegen::InitTargetOptionsFromCodeGenFlags(TargetTriple) 90bca2b6d2SVyacheslav Levytskyy // hits the following assertion: llvm/lib/CodeGen/CommandFlags.cpp:78: 91bca2b6d2SVyacheslav Levytskyy // llvm::FPOpFusion::FPOpFusionMode llvm::codegen::getFuseFPOps(): Assertion 92bca2b6d2SVyacheslav Levytskyy // `FuseFPOpsView && "RegisterCodeGenFlags not created."' failed. 93bca2b6d2SVyacheslav Levytskyy TargetOptions Options; 94bca2b6d2SVyacheslav Levytskyy std::optional<Reloc::Model> RM; 95bca2b6d2SVyacheslav Levytskyy std::optional<CodeModel::Model> CM; 963ff9368eSVyacheslav Levytskyy std::unique_ptr<TargetMachine> Target(TheTarget->createTargetMachine( 97bca2b6d2SVyacheslav Levytskyy TargetTriple.getTriple(), "", "", Options, RM, CM, OLevel)); 98bca2b6d2SVyacheslav Levytskyy if (!Target) { 99bca2b6d2SVyacheslav Levytskyy ErrMsg = "Could not allocate target machine!"; 100bca2b6d2SVyacheslav Levytskyy return false; 101bca2b6d2SVyacheslav Levytskyy } 102bca2b6d2SVyacheslav Levytskyy 103*df122fc7SVyacheslav Levytskyy // Set available extensions. 104*df122fc7SVyacheslav Levytskyy SPIRVTargetMachine *STM = static_cast<SPIRVTargetMachine *>(Target.get()); 105*df122fc7SVyacheslav Levytskyy const_cast<SPIRVSubtarget *>(STM->getSubtargetImpl()) 106*df122fc7SVyacheslav Levytskyy ->initAvailableExtensions(AllowedExtIds); 107*df122fc7SVyacheslav Levytskyy 108bca2b6d2SVyacheslav Levytskyy if (M->getCodeModel()) 109bca2b6d2SVyacheslav Levytskyy Target->setCodeModel(*M->getCodeModel()); 110bca2b6d2SVyacheslav Levytskyy 111bca2b6d2SVyacheslav Levytskyy std::string DLStr = M->getDataLayoutStr(); 112bca2b6d2SVyacheslav Levytskyy Expected<DataLayout> MaybeDL = DataLayout::parse( 113bca2b6d2SVyacheslav Levytskyy DLStr.empty() ? Target->createDataLayout().getStringRepresentation() 114bca2b6d2SVyacheslav Levytskyy : DLStr); 115bca2b6d2SVyacheslav Levytskyy if (!MaybeDL) { 116bca2b6d2SVyacheslav Levytskyy ErrMsg = toString(MaybeDL.takeError()); 117bca2b6d2SVyacheslav Levytskyy return false; 118bca2b6d2SVyacheslav Levytskyy } 119bca2b6d2SVyacheslav Levytskyy M->setDataLayout(MaybeDL.get()); 120bca2b6d2SVyacheslav Levytskyy 121bca2b6d2SVyacheslav Levytskyy TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple())); 122bca2b6d2SVyacheslav Levytskyy legacy::PassManager PM; 123bca2b6d2SVyacheslav Levytskyy PM.add(new TargetLibraryInfoWrapperPass(TLII)); 1243ff9368eSVyacheslav Levytskyy std::unique_ptr<MachineModuleInfoWrapperPass> MMIWP( 1253ff9368eSVyacheslav Levytskyy new MachineModuleInfoWrapperPass(Target.get())); 126bb3f5e1fSMatin Raayai const_cast<TargetLoweringObjectFile *>(Target->getObjFileLowering()) 1273ff9368eSVyacheslav Levytskyy ->Initialize(MMIWP.get()->getMMI().getContext(), *Target); 128bca2b6d2SVyacheslav Levytskyy 129bca2b6d2SVyacheslav Levytskyy SmallString<4096> OutBuffer; 130bca2b6d2SVyacheslav Levytskyy raw_svector_ostream OutStream(OutBuffer); 131bca2b6d2SVyacheslav Levytskyy if (Target->addPassesToEmitFile(PM, OutStream, nullptr, 132bca2b6d2SVyacheslav Levytskyy CodeGenFileType::ObjectFile)) { 133bca2b6d2SVyacheslav Levytskyy ErrMsg = "Target machine cannot emit a file of this type"; 134bca2b6d2SVyacheslav Levytskyy return false; 135bca2b6d2SVyacheslav Levytskyy } 136bca2b6d2SVyacheslav Levytskyy 137bca2b6d2SVyacheslav Levytskyy PM.run(*M); 138bca2b6d2SVyacheslav Levytskyy SpirvObj = OutBuffer.str(); 139bca2b6d2SVyacheslav Levytskyy 140bca2b6d2SVyacheslav Levytskyy return true; 141bca2b6d2SVyacheslav Levytskyy } 142bca2b6d2SVyacheslav Levytskyy 143*df122fc7SVyacheslav Levytskyy // TODO: Remove this wrapper after existing clients switch into a newer 144*df122fc7SVyacheslav Levytskyy // implementation of SPIRVTranslate(). 145*df122fc7SVyacheslav Levytskyy extern "C" LLVM_EXTERNAL_VISIBILITY bool 146*df122fc7SVyacheslav Levytskyy SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg, 147*df122fc7SVyacheslav Levytskyy const std::vector<std::string> &AllowExtNames, 148*df122fc7SVyacheslav Levytskyy const std::vector<std::string> &Opts) { 149*df122fc7SVyacheslav Levytskyy // optional: Opts[0] is a string representation of Triple, 150*df122fc7SVyacheslav Levytskyy // take Module triple otherwise 151*df122fc7SVyacheslav Levytskyy Triple TargetTriple(Opts.empty() || Opts[0].empty() 152*df122fc7SVyacheslav Levytskyy ? M->getTargetTriple() 153*df122fc7SVyacheslav Levytskyy : Triple::normalize(Opts[0])); 154*df122fc7SVyacheslav Levytskyy // optional: Opts[1] is a string representation of CodeGenOptLevel, 155*df122fc7SVyacheslav Levytskyy // no optimization otherwise 156*df122fc7SVyacheslav Levytskyy llvm::CodeGenOptLevel OLevel = CodeGenOptLevel::None; 157*df122fc7SVyacheslav Levytskyy if (Opts.size() > 1 && !Opts[1].empty()) { 158*df122fc7SVyacheslav Levytskyy if (auto Level = CodeGenOpt::parseLevel(Opts[1][0])) { 159*df122fc7SVyacheslav Levytskyy OLevel = *Level; 160*df122fc7SVyacheslav Levytskyy } else { 161*df122fc7SVyacheslav Levytskyy ErrMsg = "Invalid optimization level!"; 162*df122fc7SVyacheslav Levytskyy return false; 163*df122fc7SVyacheslav Levytskyy } 164*df122fc7SVyacheslav Levytskyy } 165*df122fc7SVyacheslav Levytskyy return SPIRVTranslate(M, SpirvObj, ErrMsg, AllowExtNames, OLevel, 166*df122fc7SVyacheslav Levytskyy TargetTriple); 167*df122fc7SVyacheslav Levytskyy } 168*df122fc7SVyacheslav Levytskyy 169bca2b6d2SVyacheslav Levytskyy } // namespace llvm 170