14
14
#include " gc/Target/LLVM/XeVM/Target.h"
15
15
16
16
#include " gc/Dialect/LLVMIR/XeVMDialect.h"
17
+ #include " gc/Target/LLVM/XeVM/Utils.h"
17
18
#include " mlir/Dialect/GPU/IR/CompilationInterfaces.h"
18
19
#include " mlir/Dialect/GPU/IR/GPUDialect.h"
19
20
#include " mlir/Dialect/LLVMIR/LLVMDialect.h"
@@ -36,15 +37,11 @@ class XeVMTargetAttrImpl
36
37
public:
37
38
std::optional<SmallVector<char , 0 >>
38
39
serializeToObject (Attribute attribute, Operation *module ,
39
- const gpu::TargetOptions &options) const { /* TODO*/
40
- return {};
41
- }
40
+ const gpu::TargetOptions &options) const ;
42
41
43
42
Attribute createObject (Attribute attribute, Operation *module ,
44
43
const SmallVector<char , 0 > &object,
45
- const gpu::TargetOptions &options) const { /* TODO*/
46
- return {};
47
- }
44
+ const gpu::TargetOptions &options) const ;
48
45
};
49
46
} // namespace
50
47
@@ -61,3 +58,144 @@ void mlir::xevm::registerXeVMTargetInterfaceExternalModels(
61
58
registerXeVMTargetInterfaceExternalModels (registry);
62
59
context.appendDialectRegistry (registry);
63
60
}
61
+
62
+ SerializeGPUModuleBase::SerializeGPUModuleBase (
63
+ Operation &module , XeVMTargetAttr target,
64
+ const gpu::TargetOptions &targetOptions)
65
+ : ModuleToObject(module , target.getTriple(), target.getChip(), {},
66
+ target.getO()),
67
+ target (target) {}
68
+
69
+ void SerializeGPUModuleBase::init () {
70
+ static llvm::once_flag initializeBackendOnce;
71
+ llvm::call_once (initializeBackendOnce, []() {
72
+ #if LLVM_HAS_SPIRV_TARGET
73
+ LLVMInitializeSPIRVTarget ();
74
+ LLVMInitializeSPIRVTargetInfo ();
75
+ LLVMInitializeSPIRVTargetMC ();
76
+ LLVMInitializeSPIRVAsmPrinter ();
77
+ #endif
78
+ });
79
+ }
80
+
81
+ XeVMTargetAttr SerializeGPUModuleBase::getTarget () const { return target; }
82
+
83
+ namespace {
84
+ class SpirSerializer : public SerializeGPUModuleBase {
85
+ public:
86
+ SpirSerializer (Operation &module , XeVMTargetAttr target,
87
+ const gpu::TargetOptions &targetOptions)
88
+ : SerializeGPUModuleBase(module , target, targetOptions) {}
89
+
90
+ gpu::GPUModuleOp getOperation ();
91
+
92
+ std::optional<SmallVector<char , 0 >>
93
+ moduleToObject (llvm::Module &llvmModule) override ;
94
+
95
+ private:
96
+ std::optional<std::string>
97
+ translateToSPIRVBinary (llvm::Module &llvmModule,
98
+ llvm::TargetMachine &targetMachine);
99
+ gpu::TargetOptions targetOptions;
100
+ };
101
+ } // namespace
102
+
103
+ gpu::GPUModuleOp SpirSerializer::getOperation () {
104
+ return dyn_cast<gpu::GPUModuleOp>(&SerializeGPUModuleBase::getOperation ());
105
+ }
106
+
107
+ std::optional<SmallVector<char , 0 >>
108
+ SpirSerializer::moduleToObject (llvm::Module &llvmModule) {
109
+ // Return LLVM IR if the compilation target is `offload`.
110
+ if (targetOptions.getCompilationTarget () == gpu::CompilationTarget::Offload)
111
+ return SerializeGPUModuleBase::moduleToObject (llvmModule);
112
+
113
+ #if !LLVM_HAS_SPIRV_TARGET
114
+ getOperation ()->emitError (
115
+ " The `SPIRV` target was not built. Please enable it when building LLVM." );
116
+ return std::nullopt;
117
+ #endif // LLVM_HAS_SPIRV_TARGET
118
+
119
+ std::optional<llvm::TargetMachine *> targetMachine =
120
+ getOrCreateTargetMachine ();
121
+ if (!targetMachine) {
122
+ getOperation ().emitError () << " Target Machine unavailable for triple "
123
+ << triple << " , can't compile with LLVM\n " ;
124
+ return std::nullopt;
125
+ }
126
+
127
+ // Return SPIRV if the compilation target is `assembly`.
128
+ if (targetOptions.getCompilationTarget () ==
129
+ gpu::CompilationTarget::Assembly) {
130
+ std::optional<std::string> serializedISA =
131
+ translateToISA (llvmModule, **targetMachine);
132
+ if (!serializedISA) {
133
+ getOperation ().emitError () << " Failed translating the module to ISA." ;
134
+ return std::nullopt;
135
+ }
136
+ // Make sure to include the null terminator.
137
+ StringRef bin (serializedISA->c_str (), serializedISA->size () + 1 );
138
+ return SmallVector<char , 0 >(bin.begin (), bin.end ());
139
+ }
140
+
141
+ std::optional<std::string> serializedSPIRVBinary =
142
+ translateToSPIRVBinary (llvmModule, **targetMachine);
143
+ if (!serializedSPIRVBinary) {
144
+ getOperation ().emitError () << " Failed translating the module to Binary." ;
145
+ return std::nullopt;
146
+ }
147
+
148
+ StringRef bin (serializedSPIRVBinary->c_str (),
149
+ serializedSPIRVBinary->size () + 1 );
150
+ return SmallVector<char , 0 >(bin.begin (), bin.end ());
151
+ }
152
+
153
+ std::optional<std::string>
154
+ SpirSerializer::translateToSPIRVBinary (llvm::Module &llvmModule,
155
+ llvm::TargetMachine &targetMachine) {
156
+ std::string targetISA;
157
+ llvm::raw_string_ostream stream (targetISA);
158
+
159
+ { // Drop pstream after this to prevent the ISA from being stuck buffering
160
+ llvm::buffer_ostream pstream (stream);
161
+ llvm::legacy::PassManager codegenPasses;
162
+
163
+ if (targetMachine.addPassesToEmitFile (codegenPasses, pstream, nullptr ,
164
+ llvm::CodeGenFileType::ObjectFile))
165
+ return std::nullopt;
166
+
167
+ codegenPasses.run (llvmModule);
168
+ }
169
+ return stream.str ();
170
+ }
171
+
172
+ std::optional<SmallVector<char , 0 >>
173
+ XeVMTargetAttrImpl::serializeToObject (Attribute attribute, Operation *module ,
174
+ const gpu::TargetOptions &options) const {
175
+ if (!module )
176
+ return std::nullopt;
177
+ auto gpuMod = dyn_cast<gpu::GPUModuleOp>(module );
178
+ if (!gpuMod) {
179
+ module ->emitError (" expected to be a gpu.module op" );
180
+ return std::nullopt;
181
+ }
182
+
183
+ // TODO: reroute to another serializer for a different target?
184
+ SpirSerializer serializer (*module , cast<XeVMTargetAttr>(attribute), options);
185
+ serializer.init ();
186
+
187
+ return serializer.run ();
188
+ }
189
+
190
+ Attribute
191
+ XeVMTargetAttrImpl::createObject (Attribute attribute, Operation *module ,
192
+ const SmallVector<char , 0 > &object,
193
+ const gpu::TargetOptions &options) const {
194
+ gpu::CompilationTarget format = options.getCompilationTarget ();
195
+ DictionaryAttr objectProps;
196
+ Builder builder (attribute.getContext ());
197
+ return builder.getAttr <gpu::ObjectAttr>(
198
+ attribute, format,
199
+ builder.getStringAttr (StringRef (object.data (), object.size ())),
200
+ objectProps, /* kernels=*/ nullptr );
201
+ }
0 commit comments