xref: /llvm-project/llvm/lib/Target/SPIRV/SPIRVAPI.cpp (revision df122fc734ce002632f3bfe8a5fc5010349dba16)
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