MLIR 23.0.0git
Target.cpp
Go to the documentation of this file.
1//===- Target.cpp - MLIR LLVM XeVM target compilation -----------*- 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// This files defines XeVM target related functions including registration
10// calls for the `#xevm.target` compilation attribute.
11//
12//===----------------------------------------------------------------------===//
13
27#include "llvm/ADT/ScopeExit.h"
28#include "llvm/Bitcode/BitcodeWriter.h"
29#include "llvm/Config/Targets.h"
30#include "llvm/IR/LegacyPassManager.h"
31#include "llvm/Support/FileSystem.h"
32#include "llvm/Support/FileUtilities.h"
33#include "llvm/Support/FormatVariadic.h"
34#include "llvm/Support/MemoryBuffer.h"
35#include "llvm/Support/Path.h"
36#include "llvm/Support/Process.h"
37#include "llvm/Support/Program.h"
38#include "llvm/Support/TargetSelect.h"
39#include "llvm/Support/raw_ostream.h"
40#include "llvm/Target/TargetMachine.h"
41
42#include <cstdint>
43#include <cstdlib>
44
45using namespace mlir;
46using namespace mlir::xevm;
47
48#if MLIR_XEVM_OCLOC_LIB_AVAILABLE
49// Intel compute runtime includes libocloc in the distribution, but
50// <ocloc_api.h> isn't included. Hence forward declarations for the libocloc
51// shared-library APIs is needed. These replace the inclusion of <ocloc_api.h>
52// so that the header is not a build-time requirement; the symbols are resolved
53// at link/load time via the ocloc shared library.
54extern "C" {
55
56// Return code indicating successful ocloc compilation.
57// Matches the OCLOC_SUCCESS enumerator in the real header (value 0).
58enum OclocErrorCode : int { OCLOC_SUCCESS = 0 };
59
60// Drives an in-process ocloc compilation.
61/// Invokes ocloc API using C interface. Supported commands match
62/// the functionality of ocloc executable (check ocloc's "help"
63/// for reference : shared/offline_compiler/source/ocloc_api.cpp).
64///
65/// numArgs and argv params represent the command line.
66/// Remaining params represent I/O.
67/// Output params should be freed using oclocFreeOutput when
68/// no longer needed.
69/// List and names of outputs match outputs of ocloc executable.
70///
71/// \param numArgs is the number of arguments to pass to ocloc
72///
73/// \param argv is an array of arguments to be passed to ocloc
74///
75/// \param numSources is the number of in-memory representations
76/// of source files to be passed to ocloc
77///
78/// \param dataSources is an array of in-memory representations
79/// of source files to be passed to ocloc
80///
81/// \param lenSources is an array of sizes of in-memory representations
82/// of source files passed to ocloc as dataSources
83///
84/// \param nameSources is an array of names of in-memory representations
85/// of source files passed to ocloc as dataSources
86///
87/// \param numInputHeaders is the number of in-memory representations
88/// of header files to be passed to ocloc
89///
90/// \param dataInputHeaders is an array of in-memory representations
91/// of header files to be passed to ocloc
92///
93/// \param lenInputHeaders is an array of sizes of in-memory representations
94/// of header files passed to ocloc as dataInputHeaders
95///
96/// \param nameInputHeaders is an array of names of in-memory representations
97/// of header files passed to ocloc as dataInputHeaders
98///
99/// \param numOutputs returns the number of outputs
100///
101/// \param dataOutputs returns an array of in-memory representations
102/// of output files
103///
104/// \param lenOutputs returns an array of sizes of in-memory representations
105/// of output files
106///
107/// \param nameOutputs returns an array of names of in-memory representations
108/// of output files. Special name stdout.log describes output that contains
109/// messages generated by ocloc (e.g. compiler errors/warnings)
110///
111/// \returns 0 on success. Returns non-0 in case of failure.
112
113int oclocInvoke(unsigned numArgs, const char **argv, unsigned numSources,
114 const uint8_t **dataSources, const uint64_t *lenSources,
115 const char **nameSources, unsigned numHeaders,
116 const uint8_t **dataHeaders, const uint64_t *lenHeaders,
117 const char **nameHeaders, unsigned *numOutputs,
118 uint8_t ***dataOutputs, uint64_t **lenOutputs,
119 char ***nameOutputs);
120
121/// Frees results of oclocInvoke
122///
123/// \param numOutputs is number of outputs as returned by oclocInvoke
124///
125/// \param dataOutputs is array of outputs as returned by oclocInvoke
126///
127/// \param lenOutputs is array of sizes of outputs as returned by oclocInvoke
128///
129/// \param nameOutputs is array of names of outputs as returned by oclocInvoke
130///
131/// \returns 0 on success. Returns non-0 in case of failure.
132int oclocFreeOutput(unsigned *numOutputs, uint8_t ***dataOutputs,
133 uint64_t **lenOutputs, char ***nameOutputs);
134
135} // extern "C"
136#endif // MLIR_XEVM_OCLOC_LIB_AVAILABLE
137
138namespace {
139// XeVM implementation of the gpu:TargetAttrInterface.
140class XeVMTargetAttrImpl
141 : public gpu::TargetAttrInterface::FallbackModel<XeVMTargetAttrImpl> {
142public:
143 std::optional<mlir::gpu::SerializedObject>
144 serializeToObject(Attribute attribute, Operation *module,
145 const gpu::TargetOptions &options) const;
146
147 Attribute createObject(Attribute attribute, Operation *module,
148 const mlir::gpu::SerializedObject &object,
149 const gpu::TargetOptions &options) const;
150};
151} // namespace
152
154 DialectRegistry &registry) {
155 registry.addExtension(+[](MLIRContext *ctx, XeVMDialect *dialect) {
156 XeVMTargetAttr::attachInterface<XeVMTargetAttrImpl>(*ctx);
157 });
158}
159
166
168 Operation &module, XeVMTargetAttr xeTarget,
170 : ModuleToObject(module, xeTarget.getTriple(), "", {}, xeTarget.getO()),
171 xeTarget(xeTarget), librariesToLink(targetOptions.getLibrariesToLink()),
172 targetOptions(targetOptions) {
173 if (xeTarget.getLinkFiles())
174 librariesToLink.append(xeTarget.getLinkFiles().begin(),
175 xeTarget.getLinkFiles().end());
176}
177
178XeVMTargetAttr SerializeGPUModuleBase::getTarget() const { return xeTarget; }
179
180std::optional<SmallVector<std::unique_ptr<llvm::Module>>>
182 if (librariesToLink.empty())
185 if (failed(loadBitcodeFilesFromList(module.getContext(), librariesToLink,
186 bcFiles)))
187 return std::nullopt;
188 return std::move(bcFiles);
189}
190
192 return dyn_cast<gpu::GPUModuleOp>(&SerializeGPUModuleBase::getOperation());
193}
194
195// ----------------------------------------------------------------------------
196// compile via the ocloc shared-library API (in-process, no temp files). Only
197// compiled when the library is available at build time.
198// ----------------------------------------------------------------------------
199#if MLIR_XEVM_OCLOC_LIB_AVAILABLE
200FailureOr<SmallVector<char, 0>>
201SerializeGPUModuleBase::compileToBinaryViaLibocloc(StringRef asmStr,
202 StringRef inputFormat) {
203 Location loc = getGPUModuleOp().getLoc();
204 std::string asmFname = llvm::formatv(
205 "mlir-{0}-{1}-{2}.asm", getGPUModuleOp().getNameAttr().getValue(),
206 getTarget().getTriple(), getTarget().getChip());
207
208 // Build command-line options.
209 std::pair<llvm::BumpPtrAllocator, SmallVector<const char *>> cmdOpts =
211 // Example: --gpu-module-to-binary="opts='opt1 opt2'"
212 const std::string cmdOptsStr = "\"" + llvm::join(cmdOpts.second, " ") + "\"";
213 std::vector<std::string> oclocArgs = {"ocloc",
214 "compile",
215 "-file",
216 asmFname,
217 inputFormat.str(),
218 "-device",
219 getTarget().getChip().str(),
220 "-options",
221 cmdOptsStr};
222
223// Dump tool invocation commands.
224#define DEBUG_TYPE "serialize-to-binary"
225 LLVM_DEBUG({
226 llvm::dbgs() << "libocloc invocation for module: "
227 << getGPUModuleOp().getNameAttr() << "\n";
228 llvm::interleave(oclocArgs, llvm::dbgs(), " ");
229 llvm::dbgs() << "\n";
230 });
231#undef DEBUG_TYPE
232
233 // Build a plain argv array expected by oclocInvoke.
234 std::vector<const char *> argv;
235 for (const auto &str : oclocArgs)
236 argv.push_back(str.c_str());
237
238 // Wire up in-memory source file.
239 const uint8_t *dataSources[1] = {
240 reinterpret_cast<const uint8_t *>(asmStr.data())};
241 const uint64_t lenSources[1] = {asmStr.size()};
242 const char *nameSources[1] = {asmFname.c_str()};
243
244 uint32_t outputsNum = 0;
245 uint8_t **outputs = nullptr;
246 uint64_t *outputLengths = nullptr;
247 char **outputNames = nullptr;
248 // Ensure ocloc output buffers are always freed on exit.
249 auto freeOutputs = llvm::scope_exit([&]() {
250 oclocFreeOutput(&outputsNum, &outputs, &outputLengths, &outputNames);
251 });
252
253 int err = oclocInvoke(static_cast<uint32_t>(argv.size()), argv.data(),
254 /*numSources=*/1, dataSources, lenSources, nameSources,
255 /*numHeaders=*/0, nullptr, nullptr, nullptr,
256 &outputsNum, &outputs, &outputLengths, &outputNames);
257
258 if (err != OCLOC_SUCCESS) {
259 emitError(loc) << "libocloc: `oclocInvoke` failed, error code: " << err;
260 // Emit any compiler log that ocloc produced.
261 for (uint32_t i = 0; i < outputsNum; ++i) {
262 if (llvm::StringRef(outputNames[i]).ends_with(".log"))
263 emitError(loc) << "Compiler log:\n"
264 << llvm::StringRef(reinterpret_cast<char *>(outputs[i]),
265 outputLengths[i]);
266 }
267 return failure();
268 }
269
270 // Find and return the .bin output.
271 for (uint32_t i = 0; i < outputsNum; ++i) {
272 if (llvm::StringRef(outputNames[i]).ends_with(".bin")) {
273 char *begin = reinterpret_cast<char *>(outputs[i]);
274 return SmallVector<char, 0>(begin, begin + outputLengths[i]);
275 }
276 }
277 return emitError(loc) << "`oclocInvoke` did not produce `.bin` output";
278}
279#endif // MLIR_XEVM_OCLOC_LIB_AVAILABLE
280
281// ----------------------------------------------------------------------------
282// Compile by spawning the `ocloc` command-line tool as a process,
283// communicating through temporary files. Acts as a fallback when the shared
284// library is not available.
285// ----------------------------------------------------------------------------
286FailureOr<SmallVector<char, 0>>
288 StringRef inputFormat) {
289 using TmpFile = std::pair<llvm::SmallString<128>, llvm::FileRemover>;
290
291 // Locate the `ocloc` executable on PATH.
292 std::optional<std::string> oclocPath = findTool("ocloc");
293 if (!oclocPath) {
294 emitError(getGPUModuleOp().getLoc()) << "Could not find `ocloc` on PATH";
295 return failure();
296 }
297
298 Location loc = getGPUModuleOp().getLoc();
299 std::string basename = llvm::formatv(
300 "mlir-{0}-{1}-{2}", getGPUModuleOp().getNameAttr().getValue(),
301 getTarget().getTriple(), getTarget().getChip());
302
303 // Helper: create a named temporary file, returning path + auto-remover.
304 auto createTemp = [&](StringRef name,
305 StringRef suffix) -> std::optional<TmpFile> {
307 if (auto ec = llvm::sys::fs::createTemporaryFile(name, suffix, path)) {
308 emitError(loc) << "Couldn't create temp file `" << path
309 << "`: " << ec.message();
310 return std::nullopt;
311 }
312 return TmpFile(path, llvm::FileRemover(path.c_str()));
313 };
314
315 std::optional<TmpFile> asmFile = createTemp(basename, "asm");
316 std::optional<TmpFile> binFile = createTemp(basename, "");
317 std::optional<TmpFile> logFile = createTemp(basename, "log");
318 if (!asmFile || !binFile || !logFile)
319 return failure();
320
321 // Write the assembly source to a temp file.
322 {
323 std::error_code ec;
324 llvm::raw_fd_ostream asmStream(asmFile->first, ec);
325 if (ec) {
326 emitError(loc) << "Couldn't open `" << asmFile->first
327 << "`: " << ec.message();
328 return failure();
329 }
330 asmStream << asmStr;
331 if (asmStream.has_error()) {
332 emitError(loc) << "Error writing assembly to `" << asmFile->first << "`";
333 return failure();
334 }
335 asmStream.flush();
336 }
337
338 // Build command-line options.
339 std::pair<llvm::BumpPtrAllocator, SmallVector<const char *>> cmdOpts =
340 targetOptions.tokenizeCmdOptions();
341 const std::string cmdOptsStr = "\"" + llvm::join(cmdOpts.second, " ") + "\"";
342
344 {"ocloc", "compile", "-file", asmFile->first, inputFormat, "-device",
345 getTarget().getChip(), "-output", binFile->first, "-output_no_suffix",
346 "-options", cmdOptsStr});
347
348 // Dump tool invocation commands.
349#define DEBUG_TYPE "serialize-to-binary"
350 LLVM_DEBUG({
351 llvm::dbgs() << "Tool invocation for module: "
352 << getGPUModuleOp().getNameAttr() << "\n";
353 llvm::interleave(oclocArgs, llvm::dbgs(), " ");
354 llvm::dbgs() << "\n";
355 });
356#undef DEBUG_TYPE
357
358 // Redirect stdout/stderr to the log temp file.
359 std::optional<StringRef> redirects[] = {std::nullopt, logFile->first,
360 logFile->first};
361
362 std::string errorMsg;
363 if (llvm::sys::ExecuteAndWait(*oclocPath, oclocArgs, std::nullopt, redirects,
364 0, 0, &errorMsg)) {
365 // Prefer a structured error message; otherwise dump the log file.
366 if (!errorMsg.empty()) {
367 emitError(loc) << "`ocloc` invocation failed: " << errorMsg;
368 } else if (auto log = llvm::MemoryBuffer::getFile(logFile->first)) {
369 emitError(loc) << "`ocloc` invocation failed. Log:\n"
370 << (*log)->getBuffer();
371 } else {
372 emitError(loc) << "`ocloc` invocation failed (no log available)";
373 }
374 return failure();
375 }
376
377 // Read back the binary output (ocloc appends ".bin" to the base name).
378 binFile->first.append(".bin");
379 auto binaryBuffer = llvm::MemoryBuffer::getFile(binFile->first);
380 if (!binaryBuffer) {
381 emitError(loc) << "Couldn't open binary output `" << binFile->first
382 << "`: " << binaryBuffer.getError().message();
383 return failure();
384 }
385 StringRef bin = (*binaryBuffer)->getBuffer();
386 return SmallVector<char, 0>(bin.begin(), bin.end());
387}
388
389// ----------------------------------------------------------------------------
390// Public entry-point: prefer the in-process library path; fall back to the
391// external tool when the library is not available.
392// ----------------------------------------------------------------------------
393FailureOr<SmallVector<char, 0>>
395 StringRef inputFormat) {
396#if MLIR_XEVM_OCLOC_LIB_AVAILABLE
397 return compileToBinaryViaLibocloc(asmStr, inputFormat);
398#else
399 return compileToBinaryViaOclocTool(asmStr, inputFormat);
400#endif
401}
402
403std::optional<std::string> SerializeGPUModuleBase::findTool(StringRef tool) {
404 // 1. Check the toolkit path given in the command line.
405 StringRef pathRef = targetOptions.getToolkitPath();
407 if (!pathRef.empty()) {
408 path.insert(path.begin(), pathRef.begin(), pathRef.end());
409 llvm::sys::path::append(path, "bin", tool);
410 if (llvm::sys::fs::can_execute(path))
411 return StringRef(path.data(), path.size()).str();
412 }
413 // 2. Check PATH.
414 if (std::optional<std::string> toolPath =
415 llvm::sys::Process::FindInEnvPath("PATH", tool))
416 return *toolPath;
417
418 getGPUModuleOp().emitError()
419 << "Couldn't find the `" << tool
420 << "` binary. Please specify the toolkit "
421 "path via GpuModuleToBinaryPass or add the compiler to $PATH`.";
422 return std::nullopt;
423}
424namespace {
425class SPIRVSerializer : public SerializeGPUModuleBase {
426public:
427 SPIRVSerializer(Operation &module, XeVMTargetAttr xeTarget,
428 const gpu::TargetOptions &targetOptions)
429 : SerializeGPUModuleBase(module, xeTarget, targetOptions) {}
430
431 static void init();
432
433 /// Serializes the LLVM module to an object format, depending on the
434 /// compilation target selected in target options.
435 FailureOr<SmallVector<char, 0>>
436 moduleToObject(llvm::Module &llvmModule) override;
437
438 /// Runs the serialization pipeline, returning `std::nullopt` on error.
439 std::optional<SmallVector<char, 0>> run() override;
440
441private:
442 /// Translates the LLVM module to SPIR-V binary using LLVM's
443 /// SPIR-V target.
444 std::optional<std::string>
445 translateToSPIRVBinary(llvm::Module &llvmModule,
446 llvm::TargetMachine &targetMachine);
447};
448} // namespace
449
450void SPIRVSerializer::init() {
451 static llvm::once_flag initializeBackendOnce;
452 llvm::call_once(initializeBackendOnce, []() {
453#if LLVM_HAS_SPIRV_TARGET
454 LLVMInitializeSPIRVTarget();
455 LLVMInitializeSPIRVTargetInfo();
456 LLVMInitializeSPIRVTargetMC();
457 LLVMInitializeSPIRVAsmPrinter();
458#endif
459 });
460}
461
462#if LLVM_HAS_SPIRV_TARGET
463static const std::vector<std::string> getDefaultSPIRVExtensions() {
464 return {
465 "SPV_EXT_relaxed_printf_string_address_space",
466 "SPV_INTEL_cache_controls",
467 "SPV_INTEL_variable_length_array",
468 };
469}
470
471namespace llvm {
472class Module;
473
474extern "C" bool
475SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
476 const std::vector<std::string> &AllowExtNames,
477 const std::vector<std::string> &Opts);
478} // namespace llvm
479#endif
480
481// There is 1 way to finalize IL to native code: IGC
482// There are 2 ways to access IGC: AOT (ocloc) and JIT (L0 runtime).
483// - L0 runtime consumes IL and is external to MLIR codebase (rt wrappers).
484// - `ocloc` tool can be "queried" from within MLIR.
485FailureOr<SmallVector<char, 0>>
486SPIRVSerializer::moduleToObject(llvm::Module &llvmModule) {
487#define DEBUG_TYPE "serialize-to-llvm"
488 LLVM_DEBUG({
489 llvm::dbgs() << "LLVM IR for module: " << getGPUModuleOp().getNameAttr()
490 << "\n";
491 llvm::dbgs() << llvmModule << "\n";
492 llvm::dbgs().flush();
493 });
494#undef DEBUG_TYPE
495
496 // Return LLVM IR if the compilation target is `offload`.
497 if (targetOptions.getCompilationTarget() == gpu::CompilationTarget::Offload)
499
500#if !LLVM_HAS_SPIRV_TARGET
501 return getGPUModuleOp()->emitError(
502 "The `SPIRV` target was not built. Please enable "
503 "it when building LLVM.");
504#else
505 std::string serializedSPIRVBinary;
506 std::string ErrMsg;
507 std::vector<std::string> Opts;
508 Opts.push_back(triple.str());
509 Opts.push_back(std::to_string(optLevel));
510
511 // Translate the LLVM module to SPIR-V binary using LLVM's SPIR-V Backend API.
512 bool success =
513 SPIRVTranslateModule(&llvmModule, serializedSPIRVBinary, ErrMsg,
514 getDefaultSPIRVExtensions(), Opts);
515
516 if (!success)
517 return getGPUModuleOp().emitError()
518 << "Failed translating the module to Binary."
519 << "Error message: " << ErrMsg;
520
521 if (serializedSPIRVBinary.size() % 4)
522 return getGPUModuleOp().emitError()
523 << "SPIRV code size must be a multiple of 4.";
524
525 StringRef spirvBin(serializedSPIRVBinary.c_str(),
526 serializedSPIRVBinary.size());
527
528 // Return SPIRV binary if the compilation target is `assembly`. Optimization
529 // and SPIR-V extensions are enabled for SPIR-V binary output in both paths
530 // (assembly and binary) as of now. SPIR-V binary
531 // is generated directly using the SPIR-V backends `SPIRVTranslateModule` API.
532 if (targetOptions.getCompilationTarget() ==
533 gpu::CompilationTarget::Assembly) {
534#define DEBUG_TYPE "serialize-to-isa"
535 LLVM_DEBUG({
536 llvm::dbgs() << "SPIR-V for module: " << getGPUModuleOp().getNameAttr()
537 << "\n";
538 llvm::dbgs() << serializedSPIRVBinary << "\n";
539 llvm::dbgs().flush();
540 });
541#undef DEBUG_TYPE
542 return SmallVector<char, 0>(spirvBin.begin(), spirvBin.end());
543 }
544
545 // Return native binary. Compile the SPIR-V binary to native binary for Intel
546 // GPUs using `ocloc` compiler (Intel's OpenCL Offline Compiler).
547
548 return compileToBinary(spirvBin, "-spirv_input");
549#endif // LLVM_HAS_SPIRV_TARGET
550}
551
552std::optional<SmallVector<char, 0>> SPIRVSerializer::run() {
553 // Translate the module to LLVM IR.
554 llvm::LLVMContext llvmContext;
555 std::unique_ptr<llvm::Module> llvmModule = translateToLLVMIR(llvmContext);
556 if (!llvmModule) {
557 getOperation().emitError() << "Failed creating the llvm::Module.";
558 return std::nullopt;
559 }
560 setDataLayoutAndTriple(*llvmModule);
561
562 if (initialLlvmIRCallback)
563 initialLlvmIRCallback(*llvmModule);
564
565 // Link bitcode files.
566 handleModulePreLink(*llvmModule);
567 {
568 auto libs = loadBitcodeFiles(*llvmModule);
569 if (!libs)
570 return std::nullopt;
571 if (!libs->empty())
572 if (failed(linkFiles(*llvmModule, std::move(*libs))))
573 return std::nullopt;
574 handleModulePostLink(*llvmModule);
575 }
576
577 if (linkedLlvmIRCallback)
578 linkedLlvmIRCallback(*llvmModule);
579
580 // Return the serialized object.
581 return moduleToObject(*llvmModule);
582}
583
584std::optional<std::string>
585SPIRVSerializer::translateToSPIRVBinary(llvm::Module &llvmModule,
586 llvm::TargetMachine &targetMachine) {
587 std::string targetISA;
588 llvm::raw_string_ostream stream(targetISA);
589
590 { // Drop pstream after this to prevent the ISA from being stuck buffering
591 llvm::buffer_ostream pstream(stream);
592 llvm::legacy::PassManager codegenPasses;
593 if (targetMachine.addPassesToEmitFile(codegenPasses, pstream, nullptr,
594 llvm::CodeGenFileType::ObjectFile))
595 return std::nullopt;
596
597 codegenPasses.run(llvmModule);
598 }
599 return targetISA;
600}
601
602std::optional<mlir::gpu::SerializedObject>
603XeVMTargetAttrImpl::serializeToObject(Attribute attribute, Operation *module,
604 const gpu::TargetOptions &options) const {
605 if (!module)
606 return std::nullopt;
607 auto gpuMod = dyn_cast<gpu::GPUModuleOp>(module);
608 if (!gpuMod) {
609 module->emitError("expected to be a gpu.module op");
610 return std::nullopt;
611 }
612 auto xeTarget = cast<XeVMTargetAttr>(attribute);
613 if (xeTarget.getTriple().starts_with("spirv")) {
614 gpuMod.walk([&](LLVM::LLVMFuncOp funcOp) {
615 if (funcOp->hasAttr(gpu::GPUDialect::getKernelFuncAttrName())) {
616 funcOp.setIntelReqdSubGroupSize(16);
617 return WalkResult::interrupt();
618 }
619 return WalkResult::advance();
620 });
621
622 SPIRVSerializer serializer(*module, cast<XeVMTargetAttr>(attribute),
623 options);
624 serializer.init();
625
626#if !LLVM_HAS_SPIRV_TARGET
627 module->emitError("Cannot run `TargetRegistry::lookupTarget()` for SPIRV "
628 "without having the target built.");
629#endif
630
631 std::optional<SmallVector<char, 0>> binary = serializer.run();
632 if (!binary)
633 return std::nullopt;
634 return gpu::SerializedObject{std::move(*binary)};
635 }
636 module->emitError("Unsupported XeVM target triple: ") << xeTarget.getTriple();
637 return std::nullopt;
638}
639
640Attribute
641XeVMTargetAttrImpl::createObject(Attribute attribute, Operation *module,
642 const mlir::gpu::SerializedObject &object,
643 const gpu::TargetOptions &options) const {
644 Builder builder(attribute.getContext());
645 gpu::CompilationTarget format = options.getCompilationTarget();
646 auto xeTarget = cast<XeVMTargetAttr>(attribute);
647 SmallVector<NamedAttribute, 2> properties;
648 if (format == gpu::CompilationTarget::Assembly)
649 properties.push_back(
650 builder.getNamedAttr("O", builder.getI32IntegerAttr(xeTarget.getO())));
651
652 DictionaryAttr objectProps;
653 if (!properties.empty())
654 objectProps = builder.getDictionaryAttr(properties);
655
656 return builder.getAttr<gpu::ObjectAttr>(
657 attribute, format,
658 builder.getStringAttr(
659 StringRef(object.getObject().data(), object.getObject().size())),
660 objectProps, /*kernels=*/nullptr);
661}
return success()
static llvm::ManagedStatic< PassManagerOptions > options
MLIRContext * getContext() const
Return the context this attribute belongs to.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
LogicalResult loadBitcodeFilesFromList(llvm::LLVMContext &context, ArrayRef< Attribute > librariesToLink, SmallVector< std::unique_ptr< llvm::Module > > &llvmModules, bool failureOnError=true)
Loads multiple bitcode files.
virtual FailureOr< SmallVector< char, 0 > > moduleToObject(llvm::Module &llvmModule)
Serializes the LLVM IR bitcode to an object file, by default it serializes to LLVM bitcode.
Operation & getOperation()
Returns the operation being serialized.
ModuleToObject(Operation &module, StringRef triple, StringRef chip, StringRef features={}, int optLevel=3, function_ref< void(llvm::Module &)> initialLlvmIRCallback={}, function_ref< void(llvm::Module &)> linkedLlvmIRCallback={}, function_ref< void(llvm::Module &)> optimizedLlvmIRCallback={}, function_ref< void(StringRef)> isaCallback={})
Operation & module
Module to transform to a binary object.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
void appendDialectRegistry(const DialectRegistry &registry)
Append the contents of the given dialect registry to the registry associated with this context.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
static WalkResult advance()
Definition WalkResult.h:47
static WalkResult interrupt()
Definition WalkResult.h:46
This class serves as an opaque interface for passing options to the TargetAttrInterface methods.
std::pair< llvm::BumpPtrAllocator, SmallVector< const char * > > tokenizeCmdOptions() const
Returns a tokenization of the command line options.
Base class for all XeVM serializations from GPU modules into binary strings.
Definition Utils.h:27
gpu::TargetOptions targetOptions
Compiles to native code using the ocloc shared library API, in-process, without temporary files.
Definition Utils.h:70
XeVMTargetAttr getTarget() const
Returns the target attribute.
Definition Target.cpp:178
FailureOr< SmallVector< char, 0 > > compileToBinary(StringRef asmStr, StringRef inputFormat)
Compiles to native code using ocloc (API or tool).
Definition Target.cpp:394
FailureOr< SmallVector< char, 0 > > compileToBinaryViaOclocTool(StringRef asmStr, StringRef inputFormat)
Compiles to native code using the ocloc command-line tool, communicating through temporary files.
Definition Target.cpp:287
std::optional< SmallVector< std::unique_ptr< llvm::Module > > > loadBitcodeFiles(llvm::Module &module) override
Loads the bitcode files in librariesToLink.
Definition Target.cpp:181
SmallVector< Attribute > librariesToLink
List of LLVM bitcode to link into after translation to LLVM IR.
Definition Utils.h:52
SerializeGPUModuleBase(Operation &module, XeVMTargetAttr target, const gpu::TargetOptions &targetOptions={})
Definition Target.cpp:167
XeVMTargetAttr xeTarget
XeVM Target attribute.
Definition Utils.h:48
std::optional< std::string > findTool(StringRef tool)
Returns the path to the tool used for serialization.
Definition Target.cpp:403
gpu::GPUModuleOp getGPUModuleOp()
Returns the gpu module being serialized.
Definition Target.cpp:191
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:717
void registerXeVMTargetInterfaceExternalModels(mlir::DialectRegistry &registry)
Registers the TargetAttrInterface for the #xevm.target attribute in the given registry.
Definition Target.cpp:153
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.