MLIR  19.0.0git
Target.cpp
Go to the documentation of this file.
1 //===- Target.cpp - MLIR LLVM NVVM 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 NVVM target related functions including registration
10 // calls for the `#nvvm.target` compilation attribute.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 
16 #include "mlir/Config/mlir-config.h"
24 
25 #include "llvm/Support/FileSystem.h"
26 #include "llvm/Support/FileUtilities.h"
27 #include "llvm/Support/FormatVariadic.h"
28 #include "llvm/Support/MemoryBuffer.h"
29 #include "llvm/Support/Path.h"
30 #include "llvm/Support/Process.h"
31 #include "llvm/Support/Program.h"
32 #include "llvm/Support/TargetSelect.h"
33 
34 #include <cstdlib>
35 
36 using namespace mlir;
37 using namespace mlir::NVVM;
38 
39 #ifndef __DEFAULT_CUDATOOLKIT_PATH__
40 #define __DEFAULT_CUDATOOLKIT_PATH__ ""
41 #endif
42 
43 namespace {
44 // Implementation of the `TargetAttrInterface` model.
45 class NVVMTargetAttrImpl
46  : public gpu::TargetAttrInterface::FallbackModel<NVVMTargetAttrImpl> {
47 public:
48  std::optional<SmallVector<char, 0>>
49  serializeToObject(Attribute attribute, Operation *module,
50  const gpu::TargetOptions &options) const;
51 
52  Attribute createObject(Attribute attribute,
53  const SmallVector<char, 0> &object,
54  const gpu::TargetOptions &options) const;
55 };
56 } // namespace
57 
58 // Register the NVVM dialect, the NVVM translation & the target interface.
60  DialectRegistry &registry) {
61  registry.addExtension(+[](MLIRContext *ctx, NVVM::NVVMDialect *dialect) {
62  NVVMTargetAttr::attachInterface<NVVMTargetAttrImpl>(*ctx);
63  });
64 }
65 
67  MLIRContext &context) {
68  DialectRegistry registry;
70  context.appendDialectRegistry(registry);
71 }
72 
73 // Search for the CUDA toolkit path.
75  if (const char *var = std::getenv("CUDA_ROOT"))
76  return var;
77  if (const char *var = std::getenv("CUDA_HOME"))
78  return var;
79  if (const char *var = std::getenv("CUDA_PATH"))
80  return var;
82 }
83 
85  Operation &module, NVVMTargetAttr target,
86  const gpu::TargetOptions &targetOptions)
87  : ModuleToObject(module, target.getTriple(), target.getChip(),
88  target.getFeatures(), target.getO()),
89  target(target), toolkitPath(targetOptions.getToolkitPath()),
90  fileList(targetOptions.getLinkFiles()) {
91 
92  // If `targetOptions` have an empty toolkitPath use `getCUDAToolkitPath`
93  if (toolkitPath.empty())
95 
96  // Append the files in the target attribute.
97  if (ArrayAttr files = target.getLink())
98  for (Attribute attr : files.getValue())
99  if (auto file = dyn_cast<StringAttr>(attr))
100  fileList.push_back(file.str());
101 
102  // Append libdevice to the files to be loaded.
103  (void)appendStandardLibs();
104 }
105 
107  static llvm::once_flag initializeBackendOnce;
108  llvm::call_once(initializeBackendOnce, []() {
109  // If the `NVPTX` LLVM target was built, initialize it.
110 #if LLVM_HAS_NVPTX_TARGET
111  LLVMInitializeNVPTXTarget();
112  LLVMInitializeNVPTXTargetInfo();
113  LLVMInitializeNVPTXTargetMC();
114  LLVMInitializeNVPTXAsmPrinter();
115 #endif
116  });
117 }
118 
119 NVVMTargetAttr SerializeGPUModuleBase::getTarget() const { return target; }
120 
122 
124  return fileList;
125 }
126 
127 // Try to append `libdevice` from a CUDA toolkit installation.
129  StringRef pathRef = getToolkitPath();
130  if (!pathRef.empty()) {
132  path.insert(path.begin(), pathRef.begin(), pathRef.end());
133  pathRef = StringRef(path.data(), path.size());
134  if (!llvm::sys::fs::is_directory(pathRef)) {
135  getOperation().emitError() << "CUDA path: " << pathRef
136  << " does not exist or is not a directory.\n";
137  return failure();
138  }
139  llvm::sys::path::append(path, "nvvm", "libdevice", "libdevice.10.bc");
140  pathRef = StringRef(path.data(), path.size());
141  if (!llvm::sys::fs::is_regular_file(pathRef)) {
142  getOperation().emitError() << "LibDevice path: " << pathRef
143  << " does not exist or is not a file.\n";
144  return failure();
145  }
146  fileList.push_back(pathRef.str());
147  }
148  return success();
149 }
150 
151 std::optional<SmallVector<std::unique_ptr<llvm::Module>>>
155  true)))
156  return std::nullopt;
157  return std::move(bcFiles);
158 }
159 
160 #if MLIR_ENABLE_CUDA_CONVERSIONS
161 namespace {
162 class NVPTXSerializer : public SerializeGPUModuleBase {
163 public:
164  NVPTXSerializer(Operation &module, NVVMTargetAttr target,
165  const gpu::TargetOptions &targetOptions);
166 
167  gpu::GPUModuleOp getOperation();
168 
169  // Compile PTX to cubin using `ptxas`.
170  std::optional<SmallVector<char, 0>>
171  compileToBinary(const std::string &ptxCode);
172 
173  // Compile PTX to cubin using the `nvptxcompiler` library.
174  std::optional<SmallVector<char, 0>>
175  compileToBinaryNVPTX(const std::string &ptxCode);
176 
177  std::optional<SmallVector<char, 0>>
178  moduleToObject(llvm::Module &llvmModule) override;
179 
180 private:
181  using TmpFile = std::pair<llvm::SmallString<128>, llvm::FileRemover>;
182 
183  // Create a temp file.
184  std::optional<TmpFile> createTemp(StringRef name, StringRef suffix);
185 
186  // Find the `tool` path, where `tool` is the name of the binary to search,
187  // i.e. `ptxas` or `fatbinary`. The search order is:
188  // 1. The toolkit path in `targetOptions`.
189  // 2. In the system PATH.
190  // 3. The path from `getCUDAToolkitPath()`.
191  std::optional<std::string> findTool(StringRef tool);
192 
193  // Target options.
194  gpu::TargetOptions targetOptions;
195 };
196 } // namespace
197 
198 NVPTXSerializer::NVPTXSerializer(Operation &module, NVVMTargetAttr target,
199  const gpu::TargetOptions &targetOptions)
200  : SerializeGPUModuleBase(module, target, targetOptions),
201  targetOptions(targetOptions) {}
202 
203 std::optional<NVPTXSerializer::TmpFile>
204 NVPTXSerializer::createTemp(StringRef name, StringRef suffix) {
205  llvm::SmallString<128> filename;
206  std::error_code ec =
207  llvm::sys::fs::createTemporaryFile(name, suffix, filename);
208  if (ec) {
209  getOperation().emitError() << "Couldn't create the temp file: `" << filename
210  << "`, error message: " << ec.message();
211  return std::nullopt;
212  }
213  return TmpFile(filename, llvm::FileRemover(filename.c_str()));
214 }
215 
216 gpu::GPUModuleOp NVPTXSerializer::getOperation() {
217  return dyn_cast<gpu::GPUModuleOp>(&SerializeGPUModuleBase::getOperation());
218 }
219 
220 std::optional<std::string> NVPTXSerializer::findTool(StringRef tool) {
221  // Find the `tool` path.
222  // 1. Check the toolkit path given in the command line.
223  StringRef pathRef = targetOptions.getToolkitPath();
225  if (!pathRef.empty()) {
226  path.insert(path.begin(), pathRef.begin(), pathRef.end());
227  llvm::sys::path::append(path, "bin", tool);
228  if (llvm::sys::fs::can_execute(path))
229  return StringRef(path.data(), path.size()).str();
230  }
231 
232  // 2. Check PATH.
233  if (std::optional<std::string> toolPath =
234  llvm::sys::Process::FindInEnvPath("PATH", tool))
235  return *toolPath;
236 
237  // 3. Check `getCUDAToolkitPath()`.
238  pathRef = getCUDAToolkitPath();
239  path.clear();
240  if (!pathRef.empty()) {
241  path.insert(path.begin(), pathRef.begin(), pathRef.end());
242  llvm::sys::path::append(path, "bin", tool);
243  if (llvm::sys::fs::can_execute(path))
244  return StringRef(path.data(), path.size()).str();
245  }
246  getOperation().emitError()
247  << "Couldn't find the `" << tool
248  << "` binary. Please specify the toolkit "
249  "path, add the compiler to $PATH, or set one of the environment "
250  "variables in `NVVM::getCUDAToolkitPath()`.";
251  return std::nullopt;
252 }
253 
254 // TODO: clean this method & have a generic tool driver or never emit binaries
255 // with this mechanism and let another stage take care of it.
256 std::optional<SmallVector<char, 0>>
257 NVPTXSerializer::compileToBinary(const std::string &ptxCode) {
258  // Determine if the serializer should create a fatbinary with the PTX embeded
259  // or a simple CUBIN binary.
260  const bool createFatbin =
261  targetOptions.getCompilationTarget() == gpu::CompilationTarget::Fatbin;
262 
263  // Find the `ptxas` & `fatbinary` tools.
264  std::optional<std::string> ptxasCompiler = findTool("ptxas");
265  if (!ptxasCompiler)
266  return std::nullopt;
267  std::optional<std::string> fatbinaryTool = findTool("fatbinary");
268  if (createFatbin && !fatbinaryTool)
269  return std::nullopt;
270  Location loc = getOperation().getLoc();
271 
272  // Base name for all temp files: mlir-<module name>-<target triple>-<chip>.
273  std::string basename =
274  llvm::formatv("mlir-{0}-{1}-{2}", getOperation().getNameAttr().getValue(),
275  getTarget().getTriple(), getTarget().getChip());
276 
277  // Create temp files:
278  std::optional<TmpFile> ptxFile = createTemp(basename, "ptx");
279  if (!ptxFile)
280  return std::nullopt;
281  std::optional<TmpFile> logFile = createTemp(basename, "log");
282  if (!logFile)
283  return std::nullopt;
284  std::optional<TmpFile> binaryFile = createTemp(basename, "bin");
285  if (!binaryFile)
286  return std::nullopt;
287  TmpFile cubinFile;
288  if (createFatbin) {
289  Twine cubinFilename = ptxFile->first + ".cubin";
290  cubinFile = TmpFile(cubinFilename.str(), llvm::FileRemover(cubinFilename));
291  } else {
292  cubinFile.first = binaryFile->first;
293  }
294 
295  std::error_code ec;
296  // Dump the PTX to a temp file.
297  {
298  llvm::raw_fd_ostream ptxStream(ptxFile->first, ec);
299  if (ec) {
300  emitError(loc) << "Couldn't open the file: `" << ptxFile->first
301  << "`, error message: " << ec.message();
302  return std::nullopt;
303  }
304  ptxStream << ptxCode;
305  if (ptxStream.has_error()) {
306  emitError(loc) << "An error occurred while writing the PTX to: `"
307  << ptxFile->first << "`.";
308  return std::nullopt;
309  }
310  ptxStream.flush();
311  }
312 
313  // Command redirects.
314  std::optional<StringRef> redirects[] = {
315  std::nullopt,
316  logFile->first,
317  logFile->first,
318  };
319 
320  // Get any extra args passed in `targetOptions`.
321  std::pair<llvm::BumpPtrAllocator, SmallVector<const char *>> cmdOpts =
322  targetOptions.tokenizeCmdOptions();
323 
324  // Create ptxas args.
325  std::string optLevel = std::to_string(this->optLevel);
326  SmallVector<StringRef, 12> ptxasArgs(
327  {StringRef("ptxas"), StringRef("-arch"), getTarget().getChip(),
328  StringRef(ptxFile->first), StringRef("-o"), StringRef(cubinFile.first),
329  "--opt-level", optLevel});
330 
331  bool useFatbin32 = false;
332  for (const auto *cArg : cmdOpts.second) {
333  // All `cmdOpts` are for `ptxas` except `-32` which passes `-32` to
334  // `fatbinary`, indicating a 32-bit target. By default a 64-bit target is
335  // assumed.
336  if (StringRef arg(cArg); arg != "-32")
337  ptxasArgs.push_back(arg);
338  else
339  useFatbin32 = true;
340  }
341 
342  // Create the `fatbinary` args.
343  StringRef chip = getTarget().getChip();
344  // Remove the arch prefix to obtain the compute capability.
345  chip.consume_front("sm_"), chip.consume_front("compute_");
346  // Embed the cubin object.
347  std::string cubinArg =
348  llvm::formatv("--image3=kind=elf,sm={0},file={1}", chip, cubinFile.first)
349  .str();
350  // Embed the PTX file so the driver can JIT if needed.
351  std::string ptxArg =
352  llvm::formatv("--image3=kind=ptx,sm={0},file={1}", chip, ptxFile->first)
353  .str();
354  SmallVector<StringRef, 6> fatbinArgs({StringRef("fatbinary"),
355  useFatbin32 ? "-32" : "-64", cubinArg,
356  ptxArg, "--create", binaryFile->first});
357 
358  // Dump tool invocation commands.
359 #define DEBUG_TYPE "serialize-to-binary"
360  LLVM_DEBUG({
361  llvm::dbgs() << "Tool invocation for module: "
362  << getOperation().getNameAttr() << "\n";
363  llvm::interleave(ptxasArgs, llvm::dbgs(), " ");
364  llvm::dbgs() << "\n";
365  if (createFatbin) {
366  llvm::interleave(fatbinArgs, llvm::dbgs(), " ");
367  llvm::dbgs() << "\n";
368  }
369  });
370 #undef DEBUG_TYPE
371 
372  // Helper function for printing tool error logs.
373  std::string message;
374  auto emitLogError =
375  [&](StringRef toolName) -> std::optional<SmallVector<char, 0>> {
376  if (message.empty()) {
377  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> toolStderr =
378  llvm::MemoryBuffer::getFile(logFile->first);
379  if (toolStderr)
380  emitError(loc) << toolName << " invocation failed. Log:\n"
381  << toolStderr->get()->getBuffer();
382  else
383  emitError(loc) << toolName << " invocation failed.";
384  return std::nullopt;
385  }
386  emitError(loc) << toolName
387  << " invocation failed, error message: " << message;
388  return std::nullopt;
389  };
390 
391  // Invoke PTXAS.
392  if (llvm::sys::ExecuteAndWait(ptxasCompiler.value(), ptxasArgs,
393  /*Env=*/std::nullopt,
394  /*Redirects=*/redirects,
395  /*SecondsToWait=*/0,
396  /*MemoryLimit=*/0,
397  /*ErrMsg=*/&message))
398  return emitLogError("`ptxas`");
399 
400  // Invoke `fatbin`.
401  message.clear();
402  if (createFatbin && llvm::sys::ExecuteAndWait(*fatbinaryTool, fatbinArgs,
403  /*Env=*/std::nullopt,
404  /*Redirects=*/redirects,
405  /*SecondsToWait=*/0,
406  /*MemoryLimit=*/0,
407  /*ErrMsg=*/&message))
408  return emitLogError("`fatbinary`");
409 
410 // Dump the output of the tools, helpful if the verbose flag was passed.
411 #define DEBUG_TYPE "serialize-to-binary"
412  LLVM_DEBUG({
413  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> logBuffer =
414  llvm::MemoryBuffer::getFile(logFile->first);
415  if (logBuffer && !(*logBuffer)->getBuffer().empty()) {
416  llvm::dbgs() << "Output:\n" << (*logBuffer)->getBuffer() << "\n";
417  llvm::dbgs().flush();
418  }
419  });
420 #undef DEBUG_TYPE
421 
422  // Read the fatbin.
423  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> binaryBuffer =
424  llvm::MemoryBuffer::getFile(binaryFile->first);
425  if (!binaryBuffer) {
426  emitError(loc) << "Couldn't open the file: `" << binaryFile->first
427  << "`, error message: " << binaryBuffer.getError().message();
428  return std::nullopt;
429  }
430  StringRef fatbin = (*binaryBuffer)->getBuffer();
431  return SmallVector<char, 0>(fatbin.begin(), fatbin.end());
432 }
433 
434 #if MLIR_NVPTXCOMPILER_ENABLED == 1
435 #include "nvPTXCompiler.h"
436 
437 #define RETURN_ON_NVPTXCOMPILER_ERROR(expr) \
438  do { \
439  if (auto status = (expr)) { \
440  emitError(loc) << llvm::Twine(#expr).concat(" failed with error code ") \
441  << status; \
442  return std::nullopt; \
443  } \
444  } while (false)
445 
446 std::optional<SmallVector<char, 0>>
447 NVPTXSerializer::compileToBinaryNVPTX(const std::string &ptxCode) {
448  Location loc = getOperation().getLoc();
449  nvPTXCompilerHandle compiler = nullptr;
450  nvPTXCompileResult status;
451  size_t logSize;
452 
453  // Create the options.
454  std::string optLevel = std::to_string(this->optLevel);
455  std::pair<llvm::BumpPtrAllocator, SmallVector<const char *>> cmdOpts =
456  targetOptions.tokenizeCmdOptions();
457  cmdOpts.second.append(
458  {"-arch", getTarget().getChip().data(), "--opt-level", optLevel.c_str()});
459 
460  // Create the compiler handle.
461  RETURN_ON_NVPTXCOMPILER_ERROR(
462  nvPTXCompilerCreate(&compiler, ptxCode.size(), ptxCode.c_str()));
463 
464  // Try to compile the binary.
465  status = nvPTXCompilerCompile(compiler, cmdOpts.second.size(),
466  cmdOpts.second.data());
467 
468  // Check if compilation failed.
469  if (status != NVPTXCOMPILE_SUCCESS) {
470  RETURN_ON_NVPTXCOMPILER_ERROR(
471  nvPTXCompilerGetErrorLogSize(compiler, &logSize));
472  if (logSize != 0) {
473  SmallVector<char> log(logSize + 1, 0);
474  RETURN_ON_NVPTXCOMPILER_ERROR(
475  nvPTXCompilerGetErrorLog(compiler, log.data()));
476  emitError(loc) << "NVPTX compiler invocation failed, error log: "
477  << log.data();
478  } else
479  emitError(loc) << "NVPTX compiler invocation failed with error code: "
480  << status;
481  return std::nullopt;
482  }
483 
484  // Retrieve the binary.
485  size_t elfSize;
486  RETURN_ON_NVPTXCOMPILER_ERROR(
487  nvPTXCompilerGetCompiledProgramSize(compiler, &elfSize));
488  SmallVector<char, 0> binary(elfSize, 0);
489  RETURN_ON_NVPTXCOMPILER_ERROR(
490  nvPTXCompilerGetCompiledProgram(compiler, (void *)binary.data()));
491 
492 // Dump the log of the compiler, helpful if the verbose flag was passed.
493 #define DEBUG_TYPE "serialize-to-binary"
494  LLVM_DEBUG({
495  RETURN_ON_NVPTXCOMPILER_ERROR(
496  nvPTXCompilerGetInfoLogSize(compiler, &logSize));
497  if (logSize != 0) {
498  SmallVector<char> log(logSize + 1, 0);
499  RETURN_ON_NVPTXCOMPILER_ERROR(
500  nvPTXCompilerGetInfoLog(compiler, log.data()));
501  llvm::dbgs() << "NVPTX compiler invocation for module: "
502  << getOperation().getNameAttr() << "\n";
503  llvm::dbgs() << "Arguments: ";
504  llvm::interleave(cmdOpts.second, llvm::dbgs(), " ");
505  llvm::dbgs() << "\nOutput\n" << log.data() << "\n";
506  llvm::dbgs().flush();
507  }
508  });
509 #undef DEBUG_TYPE
510  RETURN_ON_NVPTXCOMPILER_ERROR(nvPTXCompilerDestroy(&compiler));
511  return binary;
512 }
513 #endif // MLIR_NVPTXCOMPILER_ENABLED == 1
514 
515 std::optional<SmallVector<char, 0>>
516 NVPTXSerializer::moduleToObject(llvm::Module &llvmModule) {
517  // Return LLVM IR if the compilation target is offload.
518 #define DEBUG_TYPE "serialize-to-llvm"
519  LLVM_DEBUG({
520  llvm::dbgs() << "LLVM IR for module: " << getOperation().getNameAttr()
521  << "\n";
522  llvm::dbgs() << llvmModule << "\n";
523  llvm::dbgs().flush();
524  });
525 #undef DEBUG_TYPE
526  if (targetOptions.getCompilationTarget() == gpu::CompilationTarget::Offload)
527  return SerializeGPUModuleBase::moduleToObject(llvmModule);
528 
529  // Emit PTX code.
530  std::optional<llvm::TargetMachine *> targetMachine =
531  getOrCreateTargetMachine();
532  if (!targetMachine) {
533  getOperation().emitError() << "Target Machine unavailable for triple "
534  << triple << ", can't optimize with LLVM\n";
535  return std::nullopt;
536  }
537  std::optional<std::string> serializedISA =
538  translateToISA(llvmModule, **targetMachine);
539  if (!serializedISA) {
540  getOperation().emitError() << "Failed translating the module to ISA.";
541  return std::nullopt;
542  }
543 #define DEBUG_TYPE "serialize-to-isa"
544  LLVM_DEBUG({
545  llvm::dbgs() << "PTX for module: " << getOperation().getNameAttr() << "\n";
546  llvm::dbgs() << *serializedISA << "\n";
547  llvm::dbgs().flush();
548  });
549 #undef DEBUG_TYPE
550 
551  // Return PTX if the compilation target is assembly.
552  if (targetOptions.getCompilationTarget() ==
553  gpu::CompilationTarget::Assembly) {
554  // Make sure to include the null terminator.
555  StringRef bin(serializedISA->c_str(), serializedISA->size() + 1);
556  return SmallVector<char, 0>(bin.begin(), bin.end());
557  }
558 
559  // Compile to binary.
560 #if MLIR_NVPTXCOMPILER_ENABLED == 1
561  return compileToBinaryNVPTX(*serializedISA);
562 #else
563  return compileToBinary(*serializedISA);
564 #endif // MLIR_NVPTXCOMPILER_ENABLED == 1
565 }
566 #endif // MLIR_ENABLE_CUDA_CONVERSIONS
567 
568 std::optional<SmallVector<char, 0>>
569 NVVMTargetAttrImpl::serializeToObject(Attribute attribute, Operation *module,
570  const gpu::TargetOptions &options) const {
571  assert(module && "The module must be non null.");
572  if (!module)
573  return std::nullopt;
574  if (!mlir::isa<gpu::GPUModuleOp>(module)) {
575  module->emitError("Module must be a GPU module.");
576  return std::nullopt;
577  }
578 #if MLIR_ENABLE_CUDA_CONVERSIONS
579  NVPTXSerializer serializer(*module, cast<NVVMTargetAttr>(attribute), options);
580  serializer.init();
581  return serializer.run();
582 #else
583  module->emitError(
584  "The `NVPTX` target was not built. Please enable it when building LLVM.");
585  return std::nullopt;
586 #endif // MLIR_ENABLE_CUDA_CONVERSIONS
587 }
588 
589 Attribute
590 NVVMTargetAttrImpl::createObject(Attribute attribute,
591  const SmallVector<char, 0> &object,
592  const gpu::TargetOptions &options) const {
593  auto target = cast<NVVMTargetAttr>(attribute);
594  gpu::CompilationTarget format = options.getCompilationTarget();
595  DictionaryAttr objectProps;
596  Builder builder(attribute.getContext());
597  if (format == gpu::CompilationTarget::Assembly)
598  objectProps = builder.getDictionaryAttr(
599  {builder.getNamedAttr("O", builder.getI32IntegerAttr(target.getO()))});
600  return builder.getAttr<gpu::ObjectAttr>(
601  attribute, format,
602  builder.getStringAttr(StringRef(object.data(), object.size())),
603  objectProps);
604 }
#define __DEFAULT_CUDATOOLKIT_PATH__
Definition: Target.cpp:40
static llvm::ManagedStatic< PassManagerOptions > options
Attributes are known-constant values of operations.
Definition: Attributes.h:25
MLIRContext * getContext() const
Return the context this attribute belongs to.
Definition: Attributes.cpp:37
This class is a general helper class for creating context-global objects like types,...
Definition: Builders.h:50
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
void addExtension(std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
virtual std::optional< 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.
LogicalResult loadBitcodeFilesFromList(llvm::LLVMContext &context, ArrayRef< std::string > fileList, SmallVector< std::unique_ptr< llvm::Module >> &llvmModules, bool failureOnError=true)
Loads multiple bitcode files.
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:63
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
void appendDialectRegistry(const DialectRegistry &registry)
Append the contents of the given dialect registry to the registry associated with this context.
Base class for all NVVM serializations from GPU modules into binary strings.
Definition: Utils.h:32
ArrayRef< std::string > getFileList() const
Returns the bitcode files to be loaded.
Definition: Target.cpp:123
SerializeGPUModuleBase(Operation &module, NVVMTargetAttr target, const gpu::TargetOptions &targetOptions={})
Initializes the toolkitPath with the path in targetOptions or if empty with the path in getCUDAToolki...
Definition: Target.cpp:84
SmallVector< std::string > fileList
List of LLVM bitcode files to link to.
Definition: Utils.h:68
NVVMTargetAttr target
NVVM target attribute.
Definition: Utils.h:62
std::string toolkitPath
CUDA toolkit path.
Definition: Utils.h:65
virtual std::optional< SmallVector< std::unique_ptr< llvm::Module > > > loadBitcodeFiles(llvm::Module &module) override
Loads the bitcode files in fileList.
Definition: Target.cpp:152
LogicalResult appendStandardLibs()
Appends nvvm/libdevice.bc into fileList.
Definition: Target.cpp:128
static void init()
Initializes the LLVM NVPTX target by safely calling LLVMInitializeNVPTX* methods if available.
Definition: Target.cpp:106
StringRef getToolkitPath() const
Returns the CUDA toolkit path.
Definition: Target.cpp:121
NVVMTargetAttr getTarget() const
Returns the target attribute.
Definition: Target.cpp:119
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
MLIRContext * getContext()
Return the context this operation is associated with.
Definition: Operation.h:216
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:268
This class serves as an opaque interface for passing options to the TargetAttrInterface methods.
void registerNVVMTargetInterfaceExternalModels(DialectRegistry &registry)
Registers the TargetAttrInterface for the #nvvm.target attribute in the given registry.
Definition: Target.cpp:59
StringRef getCUDAToolkitPath()
Searches & returns the path CUDA toolkit path, the search order is:
Definition: Target.cpp:74
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26