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