18#include "mlir/IR/Operation.h"
20#include "clang/AST/Attrs.inc"
30#include "llvm/Support/Casting.h"
31#include "llvm/Support/MemoryBuffer.h"
32#include "llvm/Support/VirtualFileSystem.h"
46 llvm::StringMap<mlir::Operation *> kernelHandles;
49 llvm::DenseMap<mlir::Operation *, mlir::Operation *> kernelStubs;
54 cir::CUDADeviceVarKind flags;
56 llvm::SmallVector<VarInfo, 16> deviceVars;
59 std::unique_ptr<MangleContext> deviceMC;
62 void emitDeviceStubBodyNew(CIRGenFunction &cgf, cir::FuncOp fn,
63 FunctionArgList &args);
64 void recordDeviceBinary();
65 void transformManagedVars();
66 mlir::Value prepareKernelArgs(CIRGenFunction &cgf, mlir::Location loc,
67 FunctionArgList &args);
68 mlir::Operation *getKernelHandle(cir::FuncOp fn, GlobalDecl gd)
override;
70 mlir::Operation *getKernelStub(mlir::Operation *handle)
override {
71 auto it = kernelStubs.find(handle);
72 assert(it != kernelStubs.end());
75 std::string addPrefixToName(StringRef funcName)
const;
76 std::string addUnderscoredPrefixToName(StringRef funcName)
const;
79 CIRGenNVCUDARuntime(CIRGenModule &cgm);
80 ~CIRGenNVCUDARuntime();
82 void emitDeviceStub(CIRGenFunction &cgf, cir::FuncOp fn,
83 FunctionArgList &args)
override;
85 void handleVarRegistration(
const VarDecl *vd, cir::GlobalOp var)
override;
86 void finalizeModule()
override;
87 void handleGlobalReplace(cir::GlobalOp oldGV, cir::GlobalOp newGV)
override;
89 void internalizeDeviceSideVar(
const VarDecl *d,
90 cir::GlobalLinkageKind &linkage)
override;
92 std::string getDeviceSideName(
const NamedDecl *nd)
override;
94 void registerDeviceVar(
const VarDecl *vd, cir::GlobalOp &var,
bool isExtern,
97 auto &builder = cgm.getBuilder();
98 var->setAttr(cir::CUDAVarRegistrationInfoAttr::getMnemonic(),
99 cir::CUDAVarRegistrationInfoAttr::get(
100 builder.getContext(),
102 cir::CUDADeviceVarKind::Variable, isExtern, isConstant,
103 vd->
hasAttr<HIPManagedAttr>()));
104 deviceVars.push_back({
107 cir::CUDADeviceVarKind::Variable,
111 void registerDeviceSurf(
const VarDecl *vd, cir::GlobalOp &var,
113 auto &builder = cgm.getBuilder();
115 var->setAttr(cir::CUDAVarRegistrationInfoAttr::getMnemonic(),
116 cir::CUDAVarRegistrationInfoAttr::get(
117 builder.getContext(),
119 cir::CUDADeviceVarKind::Surface, isExtern,
123 deviceVars.push_back({
126 cir::CUDADeviceVarKind::Surface,
130 void registerDeviceTex(
const VarDecl *vd, cir::GlobalOp &var,
bool isExtern) {
131 auto &builder = cgm.getBuilder();
133 var->setAttr(cir::CUDAVarRegistrationInfoAttr::getMnemonic(),
134 cir::CUDAVarRegistrationInfoAttr::get(
135 builder.getContext(),
137 cir::CUDADeviceVarKind::Texture, isExtern,
141 deviceVars.push_back({
144 cir::CUDADeviceVarKind::Texture,
151std::string CIRGenNVCUDARuntime::addPrefixToName(StringRef funcName)
const {
152 return (prefix + funcName).str();
156CIRGenNVCUDARuntime::addUnderscoredPrefixToName(StringRef funcName)
const {
157 return (
"__" + prefix + funcName).str();
160CIRGenNVCUDARuntime::CIRGenNVCUDARuntime(CIRGenModule &cgm)
161 : CIRGenCUDARuntime(cgm),
162 deviceMC(cgm.getASTContext().cudaNVInitDeviceMC()) {
164 cgm.
errorNYI(
"CIRGenNVCUDARuntime: Offload via LLVM");
171mlir::Value CIRGenNVCUDARuntime::prepareKernelArgs(
CIRGenFunction &cgf,
177 auto voidPtrArrayTy = cir::ArrayType::get(cgm.
voidPtrTy, args.size());
178 mlir::Value kernelArgs =
179 builder.
createAlloca(loc, cir::PointerType::get(voidPtrArrayTy),
182 mlir::Value kernelArgsDecayed =
183 builder.
createCast(cir::CastKind::array_to_ptrdecay, kernelArgs,
186 for (
const auto &[i, arg] : llvm::enumerate(args)) {
189 mlir::Value storePos =
194 builder.CIRBaseBuilderTy::createStore(loc, argAsVoid, storePos);
197 return kernelArgsDecayed;
202void CIRGenNVCUDARuntime::emitDeviceStubBodyNew(CIRGenFunction &cgf,
204 FunctionArgList &args) {
208 cgm.
errorNYI(
"CIRGenNVCUDARuntime: Offload via LLVM");
211 mlir::Location loc = fn.getLoc();
216 mlir::Value kernelArgs = prepareKernelArgs(cgf, loc, args);
233 std::string kernelLaunchAPI =
"LaunchKernel";
235 LangOptions::GPUDefaultStreamKind::PerThread) {
237 kernelLaunchAPI +=
"_spt";
239 kernelLaunchAPI +=
"_ptsz";
242 std::string launchKernelName = addPrefixToName(kernelLaunchAPI);
243 const IdentifierInfo &launchII =
245 FunctionDecl *cudaLaunchKernelFD =
nullptr;
246 for (NamedDecl *result : dc->
lookup(&launchII)) {
247 if (FunctionDecl *fd = dyn_cast<FunctionDecl>(result))
248 cudaLaunchKernelFD = fd;
251 if (cudaLaunchKernelFD ==
nullptr) {
253 "Can't find declaration for " + launchKernelName);
270 builder.
createAlloca(loc, cir::PointerType::get(dim3Ty),
"grid_dim",
273 builder.
createAlloca(loc, cir::PointerType::get(dim3Ty),
"block_dim",
278 loc, cir::PointerType::get(streamTy),
"stream", cgm.
getPointerAlign());
282 sharedMem.getType(), stream.getType()},
284 addUnderscoredPrefixToName(
"PopCallConfiguration"));
295 mlir::Value kernel = [&]() -> mlir::Value {
296 if (cir::GlobalOp globalOp = llvm::dyn_cast_or_null<cir::GlobalOp>(
297 kernelHandles[fn.getSymName()])) {
298 cir::PointerType kernelTy = cir::PointerType::get(globalOp.getSymType());
299 mlir::Value kernelVal = cir::GetGlobalOp::create(builder, loc, kernelTy,
300 globalOp.getSymName());
304 if (cir::FuncOp funcOp = llvm::dyn_cast_or_null<cir::FuncOp>(
305 kernelHandles[fn.getSymName()])) {
306 cir::PointerType kernelTy =
307 cir::PointerType::get(funcOp.getFunctionType());
308 mlir::Value kernelVal =
309 cir::GetGlobalOp::create(builder, loc, kernelTy, funcOp.getSymName());
313 llvm_unreachable(
"Expected stub handle to be cir::GlobalOp or FuncOp");
316 CallArgList launchArgs;
328 RValue::get(builder.CIRBaseBuilderTy::createLoad(loc, sharedMem)),
330 launchArgs.
add(
RValue::get(builder.CIRBaseBuilderTy::createLoad(loc, stream)),
333 mlir::Type launchTy =
337 const CIRGenFunctionInfo &callInfo =
340 ReturnValueSlot(), launchArgs,
false);
344 cgm.
errorNYI(
"MSVC CUDA stub handling");
347void CIRGenNVCUDARuntime::emitDeviceStub(CIRGenFunction &cgf, cir::FuncOp fn,
348 FunctionArgList &args) {
351 llvm::dyn_cast<cir::GlobalOp>(kernelHandles[fn.getSymName()])) {
353 mlir::Type fnPtrTy = globalOp.getSymType();
354 auto sym = mlir::FlatSymbolRefAttr::get(fn.getSymNameAttr());
355 auto gv = cir::GlobalViewAttr::get(fnPtrTy, sym);
357 globalOp->setAttr(
"initial_value", gv);
358 globalOp->removeAttr(
"sym_visibility");
359 globalOp->setAttr(
"alignment", builder.getI64IntegerAttr(
365 CudaFeature::CUDA_USES_NEW_LAUNCH) ||
368 emitDeviceStubBodyNew(cgf, fn, args);
370 cgm.
errorNYI(
"Emit Stub Body Legacy");
374 return new CIRGenNVCUDARuntime(cgm);
377CIRGenNVCUDARuntime::~CIRGenNVCUDARuntime() {}
379mlir::Operation *CIRGenNVCUDARuntime::getKernelHandle(cir::FuncOp fn,
383 auto it = kernelHandles.find(fn.getSymName());
384 if (it != kernelHandles.end()) {
385 mlir::Operation *oldHandle = it->second;
387 if (kernelStubs[oldHandle] == fn)
395 kernelStubs[oldHandle] = fn;
400 kernelStubs.erase(oldHandle);
405 kernelHandles[fn.getSymName()] = fn;
406 kernelStubs[fn] = fn;
414 cir::PointerType fnPtrTy = builder.
getPointerTo(fn.getFunctionType());
415 cir::GlobalOp globalOp =
418 globalOp->setAttr(
"alignment", builder.getI64IntegerAttr(
422 kernelHandles[fn.getSymName()] = globalOp;
423 kernelStubs[globalOp] = fn;
428void CIRGenNVCUDARuntime::internalizeDeviceSideVar(
429 const VarDecl *d, cir::GlobalLinkageKind &linkage) {
432 "internalizeDeviceSideVar: GPU Relocatable Device Code (RDC)");
439 if (d->
hasAttr<CUDADeviceAttr>() || d->
hasAttr<CUDAConstantAttr>() ||
440 d->
hasAttr<CUDASharedAttr>()) {
441 linkage = cir::GlobalLinkageKind::InternalLinkage;
447 "internalizeDeviceSideVar: CUDA Surface/Texture support");
450std::string CIRGenNVCUDARuntime::getDeviceSideName(
const NamedDecl *nd) {
453 if (
auto *fd = dyn_cast<FunctionDecl>(nd))
454 gd = GlobalDecl(fd, KernelReferenceKind::Kernel);
457 std::string deviceSideName;
464 SmallString<256> buffer;
465 llvm::raw_svector_ostream
out(buffer);
467 deviceSideName = std::string(
out.str());
474 SmallString<256> buffer;
475 llvm::raw_svector_ostream
out(buffer);
476 out << deviceSideName;
478 deviceSideName = std::string(
out.str());
480 return deviceSideName;
483void CIRGenNVCUDARuntime::handleVarRegistration(
const VarDecl *vd,
485 if (vd->
hasAttr<CUDADeviceAttr>() || vd->
hasAttr<CUDAConstantAttr>()) {
501 vd->
hasAttr<HIPManagedAttr>()) {
503 vd->
hasAttr<CUDAConstantAttr>());
519void CIRGenNVCUDARuntime::handleGlobalReplace(cir::GlobalOp oldGV,
520 cir::GlobalOp newGV) {
521 for (
auto &info : deviceVars) {
522 if (
info.var == oldGV)
534 ->walk([](mlir::Operation *op) {
535 if (op->hasAttr(cir::CUDAKernelNameAttr::getMnemonic()) ||
536 op->hasAttr(cir::CUDAVarRegistrationInfoAttr::getMnemonic()))
537 return mlir::WalkResult::interrupt();
538 return mlir::WalkResult::advance();
549void CIRGenNVCUDARuntime::recordDeviceBinary() {
551 if (binaryName.empty())
555 if ((langOpts.HIP || !langOpts.GPURelocatableDeviceCode) &&
563 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> binaryOrErr =
564 fs.getBufferForFile(binaryName, -1,
566 if (std::error_code ec = binaryOrErr.getError()) {
568 << binaryName << ec.message();
576 StringRef
bytes = binaryOrErr.get()->getBuffer();
580 auto fatbinTy = cir::ArrayType::get(charTy,
bytes.size());
581 cgm.
getModule()->setAttr(cir::CIRDialect::getCUDADeviceBinaryAttrName(),
582 mlir::StringAttr::get(
bytes, fatbinTy));
586void CIRGenNVCUDARuntime::transformManagedVars() {
589 for (
auto &&info : deviceVars) {
591 if (
info.flags != cir::CUDADeviceVarKind::Variable ||
592 !
info.d->hasAttr<HIPManagedAttr>())
595 cir::PointerType varPtrTy =
599 cgm.
getLangOpts().CUDAIsDevice ? LangAS::cuda_device : LangAS::Default);
600 std::optional<mlir::SymbolTable::UseRange> uses =
var.getSymbolUses(module);
602 std::string
name =
var.getSymName().str();
604 std::optional<llvm::StringRef> comdat =
var.getComdat();
605 if (comdat && comdat->empty())
606 var.setComdat(llvm::StringRef(name));
608 var.setSymName(name +
".managed");
611 cir::GlobalOp managedVar =
614 managedVar.setLinkage(
var.getLinkage());
615 if (!
var.isDeclaration())
617 managedVar.setDsoLocal(
var.getDsoLocal());
618 managedVar.setGlobalVisibility(
var.getGlobalVisibility());
619 mlir::SymbolTable::setSymbolVisibility(
620 managedVar, mlir::SymbolTable::getSymbolVisibility(var));
622 cir::CUDAExternallyInitializedAttr::getMnemonic(),
626 cir::PointerType managedPtrTy =
627 builder.
getPointerTo(varPtrTy, managedVar.getAddrSpaceAttr());
628 for (mlir::SymbolTable::SymbolUse use : *uses) {
629 auto getGlobalOp = dyn_cast<cir::GetGlobalOp>(use.getUser());
632 "transformManagedVars: non-instruction use");
635 mlir::Value addr = getGlobalOp.getAddr();
636 addr.setType(managedPtrTy);
637 mlir::OpBuilder::InsertionGuard guard(builder);
638 builder.setInsertionPointAfter(getGlobalOp);
640 getGlobalOp.getLoc(), varPtrTy, addr,
642 addr.replaceAllUsesExcept(ld, ld.getDefiningOp());
653void CIRGenNVCUDARuntime::finalizeModule() {
654 transformManagedVars();
656 recordDeviceBinary();
670 for (
auto &&info : deviceVars) {
672 bool isDecl =
info.var.isDeclaration();
674 bool isVarOrSurfaceOrTexture = (
kind == cir::CUDADeviceVarKind::Variable ||
675 kind == cir::CUDADeviceVarKind::Surface ||
676 kind == cir::CUDADeviceVarKind::Texture);
677 bool isUsed =
info.d->isUsed();
678 bool hasUsedAttr =
info.d->hasAttr<UsedAttr>();
679 if (!isDecl && !isLocalLinkage && isVarOrSurfaceOrTexture && isUsed &&
681 if (
auto globalValue = mlir::dyn_cast<cir::CIRGlobalValueInterface>(
682 info.var.getOperation())) {
Defines the clang::ASTContext interface.
static StringRef bytes(const std::vector< T, Allocator > &v)
Provides definitions for the various language-specific address spaces.
static bool hasEntitiesToRegister(mlir::ModuleOp module)
Whether this translation unit has anything for the CUDA runtime to register.
Defines the clang::FileManager interface and associated types.
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
Defines the SourceManager interface.
__CUDA_BUILTIN_VAR __cuda_builtin_blockDim_t blockDim
__CUDA_BUILTIN_VAR __cuda_builtin_gridDim_t gridDim
mlir::TypedAttr getConstNullPtrAttr(mlir::Type t)
mlir::Value createCast(mlir::Location loc, cir::CastKind kind, mlir::Value src, mlir::Type newTy)
cir::PtrStrideOp createPtrStride(mlir::Location loc, mlir::Value base, mlir::Value stride)
cir::PointerType getPointerTo(mlir::Type ty)
mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, llvm::StringRef name, mlir::IntegerAttr alignment, mlir::Value dynAllocSize)
mlir::Value createBitcast(mlir::Value src, mlir::Type newTy)
SourceManager & getSourceManager()
TranslationUnitDecl * getTranslationUnitDecl() const
bool shouldExternalize(const Decl *D) const
Whether a C++ static variable or CUDA/HIP kernel should be externalized.
llvm::SetVector< const VarDecl * > CUDADeviceVarODRUsedByHost
Keep track of CUDA/HIP device-side variables ODR-used by host code.
const TargetInfo & getTargetInfo() const
mlir::Value getPointer() const
cir::LoadOp createAlignedLoad(mlir::Location loc, mlir::Type ty, mlir::Value ptr, llvm::MaybeAlign align)
cir::ConstantOp getConstInt(mlir::Location loc, llvm::APSInt intVal)
clang::MangleContext & getMangleContext()
Gets the mangle context.
static CIRGenCallee forDirect(mlir::Operation *funcPtr, const CIRGenCalleeInfo &abstractInfo=CIRGenCalleeInfo())
CIRGenTypes & getTypes() const
const clang::LangOptions & getLangOpts() const
const clang::Decl * curFuncDecl
Address getAddrOfLocalVar(const clang::VarDecl *vd)
Return the address of a local variable.
mlir::Value emitRuntimeCall(mlir::Location loc, cir::FuncOp callee, llvm::ArrayRef< mlir::Value > args={}, mlir::NamedAttrList attrs={})
RValue emitCall(const CIRGenFunctionInfo &funcInfo, const CIRGenCallee &callee, ReturnValueSlot returnValue, const CallArgList &args, cir::CIRCallOpInterface *callOp, bool isMustTail, SourceRange clangLoc)
This class organizes the cross-function state that is used while generating CIR code.
llvm::StringRef getMangledName(clang::GlobalDecl gd)
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
clang::ASTContext & getASTContext() const
void insertGlobalSymbol(mlir::Operation *op)
CIRGenBuilderTy & getBuilder()
clang::DiagnosticsEngine & getDiags() const
const clang::TargetInfo & getTarget() const
void error(SourceLocation loc, llvm::StringRef error)
Emit a general error that something can't be done.
cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name, mlir::NamedAttrList extraAttrs={}, bool isLocal=false, bool assumeConvergent=false)
void eraseGlobalSymbol(mlir::Operation *op)
const clang::CodeGenOptions & getCodeGenOpts() const
const clang::LangOptions & getLangOpts() const
void printPostfixForExternalizedDecl(llvm::raw_ostream &os, const Decl *d)
Print the postfix for externalized static variable or kernels for single source offloading languages ...
cir::GlobalOp createGlobalOp(mlir::Location loc, llvm::StringRef name, mlir::Type t, bool isConstant=false, mlir::ptr::MemorySpaceAttrInterface addrSpace={}, mlir::Operation *insertPoint=nullptr)
mlir::ModuleOp getModule() const
void addCompilerUsedGlobal(cir::CIRGlobalValueInterface gv)
Add a global value to the llvmCompilerUsed list.
mlir::MLIRContext & getMLIRContext()
CIRGenCXXABI & getCXXABI() const
const CIRGenFunctionInfo & arrangeFunctionDeclaration(const clang::FunctionDecl *fd)
Free functions are functions that are compatible with an ordinary C function pointer type.
mlir::Type convertType(clang::QualType type)
Convert a Clang type into a mlir::Type.
void add(RValue rvalue, clang::QualType type)
Type for representing both the decl and type of parameters to a function.
static RValue get(mlir::Value v)
static RValue getAggregate(Address addr, bool isVolatile=false)
Convert an Address to an RValue.
QuantityType getQuantity() const
Get the raw integer representation of this quantity.
static CharUnits fromQuantity(QuantityType Quantity)
Construct a CharUnits quantity from a raw integer type.
std::string OffloadBinaryToEmbedFile
Name of file passed with -foffload-include-binary option to forward to offloading runtime back-end fo...
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
SourceLocation getLocation() const
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
llvm::vfs::FileSystem & getVirtualFileSystem() const
const ParmVarDecl * getParamDecl(unsigned i) const
GlobalDecl - represents a global declaration.
GlobalDecl getWithKernelReferenceKind(KernelReferenceKind Kind)
StringRef getName() const
Return the actual identifier string.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
GPUDefaultStreamKind GPUDefaultStream
The default stream kind used for HIP kernel launching.
bool shouldMangleDeclName(const NamedDecl *D)
void mangleName(GlobalDecl GD, raw_ostream &)
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
FileManager & getFileManager() const
bool isMicrosoft() const
Is this ABI an MSVC-compatible ABI?
TargetCXXABI getCXXABI() const
Get the C++ ABI currently in use.
unsigned getCharWidth() const
const llvm::VersionTuple & getSDKVersion() const
static DeclContext * castToDeclContext(const TranslationUnitDecl *D)
bool isCUDADeviceBuiltinSurfaceType() const
Check if the type is the CUDA device builtin surface type.
bool isCUDADeviceBuiltinTextureType() const
Check if the type is the CUDA device builtin texture type.
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
bool isInline() const
Whether this variable is (C++1z) inline.
bool hasExternalStorage() const
Returns true if a variable has extern or private_extern storage.
DefinitionKind hasDefinition(ASTContext &) const
Check whether this variable is defined in this translation unit.
static bool isLocalLinkage(GlobalLinkageKind linkage)
mlir::ptr::MemorySpaceAttrInterface toCIRAddressSpaceAttr(mlir::MLIRContext &ctx, clang::LangAS langAS)
Convert an AST LangAS to the appropriate CIR address space attribute interface.
CIRGenCUDARuntime * createNVCUDARuntime(CIRGenModule &cgm)
constexpr Variable var(Literal L)
Returns the variable of L.
@ Address
A pointer to a ValueDecl.
void info(bool Verbose, unsigned Level, const char *Fmt, Ts &&...Args)
Prints an indented note to stderr when Verbose is set.
Top level wrappers for InstallAPI frontend operations.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
bool CudaFeatureEnabled(llvm::VersionTuple, CudaFeature)
U cast(CodeGen::Address addr)
clang::CharUnits getPointerAlign() const
clang::CharUnits getSizeAlign() const
cir::PointerType voidPtrTy
void* in address space 0