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