1414#include " gc/Target/LLVM/XeVM/Target.h"
1515
1616#include " gc/Dialect/LLVMIR/XeVMDialect.h"
17+ #include " gc/Target/LLVM/XeVM/Utils.h"
1718#include " mlir/Dialect/GPU/IR/CompilationInterfaces.h"
1819#include " mlir/Dialect/GPU/IR/GPUDialect.h"
1920#include " mlir/Dialect/LLVMIR/LLVMDialect.h"
@@ -36,15 +37,11 @@ class XeVMTargetAttrImpl
3637public:
3738 std::optional<SmallVector<char , 0 >>
3839 serializeToObject (Attribute attribute, Operation *module ,
39- const gpu::TargetOptions &options) const { /* TODO*/
40- return {};
41- }
40+ const gpu::TargetOptions &options) const ;
4241
4342 Attribute createObject (Attribute attribute, Operation *module ,
4443 const SmallVector<char , 0 > &object,
45- const gpu::TargetOptions &options) const { /* TODO*/
46- return {};
47- }
44+ const gpu::TargetOptions &options) const ;
4845};
4946} // namespace
5047
@@ -61,3 +58,144 @@ void mlir::xevm::registerXeVMTargetInterfaceExternalModels(
6158 registerXeVMTargetInterfaceExternalModels (registry);
6259 context.appendDialectRegistry (registry);
6360}
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