27#include "llvm/Support/InterleavedRange.h"
29#include "llvm/ADT/ScopeExit.h"
30#include "llvm/Config/Targets.h"
31#include "llvm/Support/DebugLog.h"
32#include "llvm/Support/FileSystem.h"
33#include "llvm/Support/FileUtilities.h"
34#include "llvm/Support/FormatVariadic.h"
35#include "llvm/Support/MemoryBuffer.h"
36#include "llvm/Support/Path.h"
37#include "llvm/Support/Process.h"
38#include "llvm/Support/Program.h"
39#include "llvm/Support/TargetSelect.h"
40#include "llvm/Support/Timer.h"
41#include "llvm/Support/raw_ostream.h"
50#ifndef __DEFAULT_CUDATOOLKIT_PATH__
51#define __DEFAULT_CUDATOOLKIT_PATH__ ""
59class NVVMTargetAttrImpl
60 :
public gpu::TargetAttrInterface::FallbackModel<NVVMTargetAttrImpl> {
62 std::optional<SmallVector<char, 0>>
76 NVVMTargetAttr::attachInterface<NVVMTargetAttrImpl>(*ctx);
89 if (
const char *var = std::getenv(
"CUDA_ROOT"))
91 if (
const char *var = std::getenv(
"CUDA_HOME"))
93 if (
const char *var = std::getenv(
"CUDA_PATH"))
103 targetOptions.getInitialLlvmIRCallback(),
104 targetOptions.getLinkedLlvmIRCallback(),
105 targetOptions.getOptimizedLlvmIRCallback(),
106 targetOptions.getISACallback()),
123 static llvm::once_flag initializeBackendOnce;
124 llvm::call_once(initializeBackendOnce, []() {
126#if LLVM_HAS_NVPTX_TARGET
127 LLVMInitializeNVPTXTarget();
128 LLVMInitializeNVPTXTargetInfo();
129 LLVMInitializeNVPTXTargetMC();
130 LLVMInitializeNVPTXAsmPrinter();
145#if MLIR_NVVM_EMBED_LIBDEVICE
151 IntegerType::get(ctx, 8));
156 resourceManager.getBlobManager().lookup(
"_mlir_embedded_libdevice");
170 type, resourceManager.insert(
"_mlir_embedded_libdevice",
171 std::move(unmanagedBlob))));
174 if (!pathRef.empty()) {
176 path.insert(path.begin(), pathRef.begin(), pathRef.end());
177 pathRef = StringRef(path.data(), path.size());
178 if (!llvm::sys::fs::is_directory(pathRef)) {
180 <<
" does not exist or is not a directory.\n";
183 llvm::sys::path::append(path,
"nvvm",
"libdevice",
"libdevice.10.bc");
184 pathRef = StringRef(path.data(), path.size());
185 if (!llvm::sys::fs::is_regular_file(pathRef)) {
187 <<
" does not exist or is not a file.\n";
196std::optional<SmallVector<std::unique_ptr<llvm::Module>>>
202 return std::move(bcFiles);
212 gpu::GPUModuleOp getOperation();
215 FailureOr<SmallVector<char, 0>> compileToBinary(StringRef ptxCode);
218 FailureOr<SmallVector<char, 0>> compileToBinaryNVPTX(StringRef ptxCode);
222 FailureOr<SmallVector<char, 0>>
223 moduleToObject(llvm::Module &llvmModule)
override;
228 std::optional<int64_t> getLLVMIRToISATimeInMs();
233 std::optional<int64_t> getISAToBinaryTimeInMs();
236 using TmpFile = std::pair<llvm::SmallString<128>, llvm::FileRemover>;
239 std::optional<TmpFile> createTemp(StringRef name, StringRef suffix);
246 std::optional<std::string> findTool(StringRef tool);
252 std::optional<int64_t> llvmToISATimeInMs;
255 std::optional<int64_t> isaToBinaryTimeInMs;
259NVPTXSerializer::NVPTXSerializer(
Operation &module, NVVMTargetAttr
target,
262 targetOptions(targetOptions), llvmToISATimeInMs(std::nullopt),
263 isaToBinaryTimeInMs(std::nullopt) {}
265std::optional<NVPTXSerializer::TmpFile>
266NVPTXSerializer::createTemp(StringRef name, StringRef suffix) {
267 llvm::SmallString<128> filename;
268 if (name.size() > 80)
269 name = name.substr(0, 80);
271 llvm::sys::fs::createTemporaryFile(name, suffix, filename);
273 getOperation().emitError() <<
"Couldn't create the temp file: `" << filename
274 <<
"`, error message: " << ec.message();
277 return TmpFile(filename, llvm::FileRemover(filename.c_str()));
280std::optional<int64_t> NVPTXSerializer::getLLVMIRToISATimeInMs() {
281 return llvmToISATimeInMs;
284std::optional<int64_t> NVPTXSerializer::getISAToBinaryTimeInMs() {
285 return isaToBinaryTimeInMs;
288gpu::GPUModuleOp NVPTXSerializer::getOperation() {
292std::optional<std::string> NVPTXSerializer::findTool(StringRef tool) {
295 StringRef pathRef = targetOptions.getToolkitPath();
296 SmallVector<char, 256> path;
297 if (!pathRef.empty()) {
298 path.insert(path.begin(), pathRef.begin(), pathRef.end());
299 llvm::sys::path::append(path,
"bin", tool);
300 if (llvm::sys::fs::can_execute(path))
301 return StringRef(path.data(), path.size()).str();
305 if (std::optional<std::string> toolPath =
306 llvm::sys::Process::FindInEnvPath(
"PATH", tool))
312 if (!pathRef.empty()) {
313 path.insert(path.begin(), pathRef.begin(), pathRef.end());
314 llvm::sys::path::append(path,
"bin", tool);
315 if (llvm::sys::fs::can_execute(path))
316 return StringRef(path.data(), path.size()).str();
318 getOperation().emitError()
319 <<
"Couldn't find the `" << tool
320 <<
"` binary. Please specify the toolkit "
321 "path, add the compiler to $PATH, or set one of the environment "
322 "variables in `NVVM::getCUDAToolkitPath()`.";
330 if (!
target.hasCmdOptions())
333 std::optional<mlir::NamedAttribute> cmdOptions =
target.getCmdOptions();
334 for (
Attribute attr : cast<ArrayAttr>(cmdOptions->getValue())) {
335 if (
auto strAttr = dyn_cast<StringAttr>(attr)) {
336 if constexpr (std::is_same_v<T, StringRef>) {
337 ptxasArgs.push_back(strAttr.getValue());
338 }
else if constexpr (std::is_same_v<T, const char *>) {
339 ptxasArgs.push_back(strAttr.getValue().data());
347FailureOr<SmallVector<char, 0>>
348NVPTXSerializer::compileToBinary(StringRef ptxCode) {
351 const bool createFatbin =
352 targetOptions.getCompilationTarget() == gpu::CompilationTarget::Fatbin;
355 std::optional<std::string> ptxasCompiler = findTool(
"ptxas");
358 std::optional<std::string> fatbinaryTool;
360 fatbinaryTool = findTool(
"fatbinary");
364 Location loc = getOperation().getLoc();
367 std::string basename =
368 llvm::formatv(
"mlir-{0}-{1}-{2}", getOperation().getNameAttr().getValue(),
369 getTarget().getTriple(), getTarget().getChip());
372 std::optional<TmpFile> ptxFile = createTemp(basename,
"ptx");
375 std::optional<TmpFile> logFile = createTemp(basename,
"log");
378 std::optional<TmpFile> binaryFile = createTemp(basename,
"bin");
383 std::string cubinFilename = (ptxFile->first +
".cubin").str();
384 cubinFile = TmpFile(cubinFilename, llvm::FileRemover(cubinFilename));
386 cubinFile.first = binaryFile->first;
392 llvm::raw_fd_ostream ptxStream(ptxFile->first, ec);
394 return emitError(loc) <<
"Couldn't open the file: `" << ptxFile->first
395 <<
"`, error message: " << ec.message();
397 ptxStream << ptxCode;
398 if (ptxStream.has_error())
399 return emitError(loc) <<
"An error occurred while writing the PTX to: `"
400 << ptxFile->first <<
"`.";
406 std::optional<StringRef> redirects[] = {
413 std::pair<llvm::BumpPtrAllocator, SmallVector<const char *>> cmdOpts =
414 targetOptions.tokenizeCmdOptions();
417 std::string optLevel = std::to_string(this->optLevel);
418 SmallVector<StringRef, 12> ptxasArgs(
419 {StringRef(
"ptxas"), StringRef(
"-arch"), getTarget().getChip(),
420 StringRef(ptxFile->first), StringRef(
"-o"), StringRef(cubinFile.first),
421 "--opt-level", optLevel});
423 bool useFatbin32 =
false;
424 for (
const auto *cArg : cmdOpts.second) {
428 if (StringRef arg(cArg); arg !=
"-32")
429 ptxasArgs.push_back(arg);
438 StringRef chip = getTarget().getChip();
440 chip.consume_front(
"sm_"), chip.consume_front(
"compute_");
442 std::string cubinArg =
443 llvm::formatv(
"--image3=kind=elf,sm={0},file={1}", chip, cubinFile.first)
447 llvm::formatv(
"--image3=kind=ptx,sm={0},file={1}", chip, ptxFile->first)
449 SmallVector<StringRef, 6> fatbinArgs({StringRef(
"fatbinary"),
450 useFatbin32 ?
"-32" :
"-64", cubinArg,
451 ptxArg,
"--create", binaryFile->first});
454#define DEBUG_TYPE "serialize-to-binary"
455 LDBG() <<
"Tool invocation for module: " << getOperation().getNameAttr()
456 <<
"\nptxas executable:" << ptxasCompiler.value()
457 <<
"\nptxas args: " << llvm::interleaved(ptxasArgs,
" ");
459 LDBG() <<
"fatbin args: " << llvm::interleaved(fatbinArgs,
" ");
465 [&](StringRef toolName) -> FailureOr<SmallVector<char, 0>> {
466 if (message.empty()) {
467 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> toolStderr =
468 llvm::MemoryBuffer::getFile(logFile->first);
470 return emitError(loc) << toolName <<
" invocation failed. Log:\n"
471 << toolStderr->get()->getBuffer();
473 return emitError(loc) << toolName <<
" invocation failed.";
476 <<
" invocation failed, error message: " << message;
480 if (llvm::sys::ExecuteAndWait(ptxasCompiler.value(), ptxasArgs,
486 return emitLogError(
"`ptxas`");
487#define DEBUG_TYPE "dump-sass"
489 std::optional<std::string> nvdisasm = findTool(
"nvdisasm");
490 SmallVector<StringRef> nvdisasmArgs(
491 {StringRef(
"nvdisasm"), StringRef(cubinFile.first)});
492 if (llvm::sys::ExecuteAndWait(nvdisasm.value(), nvdisasmArgs,
498 return emitLogError(
"`nvdisasm`");
499 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> logBuffer =
500 llvm::MemoryBuffer::getFile(logFile->first);
501 if (logBuffer && !(*logBuffer)->getBuffer().empty()) {
502 LDBG() <<
"Output:\n" << (*logBuffer)->getBuffer();
503 llvm::dbgs().flush();
510 if (createFatbin && llvm::sys::ExecuteAndWait(*fatbinaryTool, fatbinArgs,
516 return emitLogError(
"`fatbinary`");
519#define DEBUG_TYPE "serialize-to-binary"
521 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> logBuffer =
522 llvm::MemoryBuffer::getFile(logFile->first);
523 if (logBuffer && !(*logBuffer)->getBuffer().empty()) {
524 LDBG() <<
"Output:\n" << (*logBuffer)->getBuffer();
525 llvm::dbgs().flush();
531 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> binaryBuffer =
532 llvm::MemoryBuffer::getFile(binaryFile->first);
534 return emitError(loc) <<
"Couldn't open the file: `" << binaryFile->first
535 <<
"`, error message: "
536 << binaryBuffer.getError().message();
538 StringRef fatbin = (*binaryBuffer)->getBuffer();
539 return SmallVector<char, 0>(fatbin.begin(), fatbin.end());
542#if MLIR_ENABLE_NVPTXCOMPILER
543#include "nvPTXCompiler.h"
545#define RETURN_ON_NVPTXCOMPILER_ERROR(expr) \
547 if (auto status = (expr)) { \
548 emitError(loc) << llvm::Twine(#expr).concat(" failed with error code ") \
550 return std::nullopt; \
556#define RETURN_ON_NVFATBIN_ERROR(expr) \
558 auto result = (expr); \
559 if (result != nvFatbinResult::NVFATBIN_SUCCESS) { \
560 emitError(loc) << llvm::Twine(#expr).concat(" failed with error: ") \
561 << nvFatbinGetErrorString(result); \
562 return std::nullopt; \
566FailureOr<SmallVector<char, 0>>
567NVPTXSerializer::compileToBinaryNVPTX(StringRef ptxCode) {
568 Location loc = getOperation().getLoc();
569 nvPTXCompilerHandle compiler =
nullptr;
570 nvPTXCompileResult status;
574 std::string optLevel = std::to_string(this->optLevel);
575 std::pair<llvm::BumpPtrAllocator, SmallVector<const char *>> cmdOpts =
576 targetOptions.tokenizeCmdOptions();
577 cmdOpts.second.append(
578 {
"-arch", getTarget().getChip().data(),
"--opt-level", optLevel.c_str()});
583 RETURN_ON_NVPTXCOMPILER_ERROR(
584 nvPTXCompilerCreate(&compiler, ptxCode.size(), ptxCode.c_str()));
587 status = nvPTXCompilerCompile(compiler, cmdOpts.second.size(),
588 cmdOpts.second.data());
591 if (status != NVPTXCOMPILE_SUCCESS) {
592 RETURN_ON_NVPTXCOMPILER_ERROR(
593 nvPTXCompilerGetErrorLogSize(compiler, &logSize));
595 SmallVector<char> log(logSize + 1, 0);
596 RETURN_ON_NVPTXCOMPILER_ERROR(
597 nvPTXCompilerGetErrorLog(compiler, log.data()));
599 <<
"NVPTX compiler invocation failed, error log: " << log.data();
602 <<
"NVPTX compiler invocation failed with error code: " << status;
608 RETURN_ON_NVPTXCOMPILER_ERROR(
609 nvPTXCompilerGetCompiledProgramSize(compiler, &elfSize));
610 SmallVector<char, 0> binary(elfSize, 0);
611 RETURN_ON_NVPTXCOMPILER_ERROR(
612 nvPTXCompilerGetCompiledProgram(compiler, (
void *)binary.data()));
615#define DEBUG_TYPE "serialize-to-binary"
617 RETURN_ON_NVPTXCOMPILER_ERROR(
618 nvPTXCompilerGetInfoLogSize(compiler, &logSize));
620 SmallVector<char> log(logSize + 1, 0);
621 RETURN_ON_NVPTXCOMPILER_ERROR(
622 nvPTXCompilerGetInfoLog(compiler, log.data()));
623 LDBG() <<
"NVPTX compiler invocation for module: "
624 << getOperation().getNameAttr()
625 <<
"\nArguments: " << llvm::interleaved(cmdOpts.second,
" ")
631 RETURN_ON_NVPTXCOMPILER_ERROR(nvPTXCompilerDestroy(&compiler));
633 if (targetOptions.getCompilationTarget() == gpu::CompilationTarget::Fatbin) {
634 bool useFatbin32 = llvm::any_of(cmdOpts.second, [](
const char *option) {
635 return llvm::StringRef(option) ==
"-32";
638 const char *cubinOpts[1] = {useFatbin32 ?
"-32" :
"-64"};
639 nvFatbinHandle handle;
641 auto chip = getTarget().getChip();
642 chip.consume_front(
"sm_");
644 RETURN_ON_NVFATBIN_ERROR(nvFatbinCreate(&handle, cubinOpts, 1));
645 RETURN_ON_NVFATBIN_ERROR(nvFatbinAddCubin(
646 handle, binary.data(), binary.size(), chip.data(),
nullptr));
647 RETURN_ON_NVFATBIN_ERROR(nvFatbinAddPTX(
648 handle, ptxCode.data(), ptxCode.size(), chip.data(),
nullptr,
nullptr));
651 RETURN_ON_NVFATBIN_ERROR(nvFatbinSize(handle, &fatbinSize));
652 SmallVector<char, 0> fatbin(fatbinSize, 0);
653 RETURN_ON_NVFATBIN_ERROR(nvFatbinGet(handle, (
void *)fatbin.data()));
654 RETURN_ON_NVFATBIN_ERROR(nvFatbinDestroy(&handle));
662FailureOr<SmallVector<char, 0>>
663NVPTXSerializer::moduleToObject(llvm::Module &llvmModule) {
664 llvm::Timer moduleToObjectTimer(
665 "moduleToObjectTimer",
666 "Timer for perf llvm-ir -> isa and isa -> binary.");
667 auto clear = llvm::make_scope_exit([&]() { moduleToObjectTimer.clear(); });
669#define DEBUG_TYPE "serialize-to-llvm"
671 LDBG() <<
"LLVM IR for module: " << getOperation().getNameAttr();
672 LDBG() << llvmModule;
675 if (targetOptions.getCompilationTarget() == gpu::CompilationTarget::Offload)
678#if !LLVM_HAS_NVPTX_TARGET
679 return getOperation()->emitError(
680 "The `NVPTX` target was not built. Please enable it when building LLVM.");
684 FailureOr<llvm::TargetMachine *> targetMachine = getOrCreateTargetMachine();
685 if (
failed(targetMachine))
686 return getOperation().emitError()
687 <<
"Target Machine unavailable for triple " << triple
688 <<
", can't optimize with LLVM\n";
690 moduleToObjectTimer.startTimer();
691 FailureOr<SmallString<0>> serializedISA =
692 translateModuleToISA(llvmModule, **targetMachine,
693 [&]() {
return getOperation().emitError(); });
694 moduleToObjectTimer.stopTimer();
695 llvmToISATimeInMs = moduleToObjectTimer.getTotalTime().getWallTime() * 1000;
696 moduleToObjectTimer.clear();
697 if (
failed(serializedISA))
698 return getOperation().emitError()
699 <<
"Failed translating the module to ISA.";
702 isaCallback(*serializedISA);
704#define DEBUG_TYPE "serialize-to-isa"
705 LDBG() <<
"PTX for module: " << getOperation().getNameAttr() <<
"\n"
710 if (targetOptions.getCompilationTarget() == gpu::CompilationTarget::Assembly)
711 return SmallVector<char, 0>(serializedISA->begin(), serializedISA->end());
713 FailureOr<SmallVector<char, 0>>
result;
714 moduleToObjectTimer.startTimer();
716#if MLIR_ENABLE_NVPTXCOMPILER
717 result = compileToBinaryNVPTX(*serializedISA);
719 result = compileToBinary(*serializedISA);
722 moduleToObjectTimer.stopTimer();
723 isaToBinaryTimeInMs = moduleToObjectTimer.getTotalTime().getWallTime() * 1000;
724 moduleToObjectTimer.clear();
728std::optional<SmallVector<char, 0>>
729NVVMTargetAttrImpl::serializeToObject(Attribute attribute, Operation *module,
730 const gpu::TargetOptions &
options)
const {
732 assert(module &&
"The module must be non null.");
735 if (!mlir::isa<gpu::GPUModuleOp>(module)) {
736 module->emitError("Module must be a GPU module.");
739 NVPTXSerializer serializer(*module, cast<NVVMTargetAttr>(attribute),
options);
741 std::optional<SmallVector<char, 0>>
result = serializer.run();
742 auto llvmToISATimeInMs = serializer.getLLVMIRToISATimeInMs();
743 if (llvmToISATimeInMs.has_value())
744 module->setAttr("LLVMIRToISATimeInMs",
745 builder.getI64IntegerAttr(*llvmToISATimeInMs));
746 auto isaToBinaryTimeInMs = serializer.getISAToBinaryTimeInMs();
747 if (isaToBinaryTimeInMs.has_value())
748 module->setAttr("ISAToBinaryTimeInMs",
749 builder.getI64IntegerAttr(*isaToBinaryTimeInMs));
754NVVMTargetAttrImpl::createObject(Attribute attribute, Operation *module,
755 const SmallVector<char, 0> &
object,
756 const gpu::TargetOptions &
options)
const {
757 auto target = cast<NVVMTargetAttr>(attribute);
758 gpu::CompilationTarget format =
options.getCompilationTarget();
759 DictionaryAttr objectProps;
761 SmallVector<NamedAttribute, 4> properties;
762 if (format == gpu::CompilationTarget::Assembly)
763 properties.push_back(
764 builder.getNamedAttr(
"O", builder.getI32IntegerAttr(
target.getO())));
766 if (StringRef section =
options.getELFSection(); !section.empty())
768 builder.getStringAttr(section)));
770 for (
const auto *perfName : {
"LLVMIRToISATimeInMs",
"ISAToBinaryTimeInMs"}) {
771 if (module->
hasAttr(perfName)) {
772 IntegerAttr attr = llvm::dyn_cast<IntegerAttr>(module->
getAttr(perfName));
773 properties.push_back(builder.getNamedAttr(
774 perfName, builder.getI64IntegerAttr(attr.getInt())));
778 if (!properties.empty())
779 objectProps = builder.getDictionaryAttr(properties);
781 return builder.getAttr<gpu::ObjectAttr>(
783 builder.getStringAttr(StringRef(
object.data(),
object.size())),
784 objectProps,
nullptr);
static void setOptionalCommandlineArguments(NVVMTargetAttr target, SmallVectorImpl< T > &ptxasArgs)
Adds optional command-line arguments to existing arguments.
const unsigned _mlir_embedded_libdevice_size
#define __DEFAULT_CUDATOOLKIT_PATH__
const unsigned char _mlir_embedded_libdevice[]
static llvm::ManagedStatic< PassManagerOptions > options
Attributes are known-constant values of operations.
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.
The class represents an individual entry of a blob.
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.
MLIRContext is the top-level object for a collection of MLIR operations.
void appendDialectRegistry(const DialectRegistry ®istry)
Append the contents of the given dialect registry to the registry associated with this context.
Dialect * getLoadedDialect(StringRef name)
Get a registered IR dialect with the given namespace.
Base class for all NVVM serializations from GPU modules into binary strings.
ArrayRef< Attribute > getLibrariesToLink() const
Returns the bitcode libraries to be linked into the gpu module after translation to LLVM IR.
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...
NVVMTargetAttr target
NVVM target attribute.
std::string toolkitPath
CUDA toolkit path.
SmallVector< Attribute > librariesToLink
List of LLVM bitcode to link into after translation to LLVM IR.
std::optional< SmallVector< std::unique_ptr< llvm::Module > > > loadBitcodeFiles(llvm::Module &module) override
Loads the bitcode files in librariesToLink.
LogicalResult appendStandardLibs()
Appends nvvm/libdevice.bc into librariesToLink.
static void init()
Initializes the LLVM NVPTX target by safely calling LLVMInitializeNVPTX* methods if available.
StringRef getToolkitPath() const
Returns the CUDA toolkit path.
NVVMTargetAttr getTarget() const
Returns the target attribute.
Operation is the basic unit of execution within MLIR.
Attribute getAttr(StringAttr name)
Return the specified attribute if present, null otherwise.
bool hasAttr(StringAttr name)
Return true if the operation has an attribute with the provided name, false otherwise.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
static AsmResourceBlob allocateInferAlign(ArrayRef< T > data, AsmResourceBlob::DeleterFn deleter={}, bool dataIsMutable=false)
This class serves as an opaque interface for passing options to the TargetAttrInterface methods.
void registerNVVMTargetInterfaceExternalModels(DialectRegistry ®istry)
Registers the TargetAttrInterface for the #nvvm.target attribute in the given registry.
StringRef getCUDAToolkitPath()
Searches & returns the path CUDA toolkit path, the search order is:
constexpr StringLiteral elfSectionName
Include the generated interface declarations.
DialectResourceBlobHandle< BuiltinDialect > DenseResourceElementsHandle
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
static ManagerInterface & getManagerInterface(MLIRContext *ctx)