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