Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion clang/include/clang/CIR/Dialect/IR/CIRCUDAAttrs.td
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,17 @@ def CIR_CUDAKernelNameAttr : CIR_Attr<"CUDAKernelName", "cu.kernel_name"> {
let assemblyFormat = "`<` $kernel_name `>`";
}

def CUDAExternallyInitializedAttr : CIR_Attr<"CUDAExternallyInitialized",
"cu.externally_initialized"> {
let summary = "The marked variable is externally initialized.";
let description =
[{
CUDA __device__ and __constant__ variables, along with surface and
textures, might be initialized by host, hence "externally initialized".
Therefore they must be emitted even if they are not referenced.

The attribute corresponds to the attribute on LLVM with the same name.
}];
}

#endif // CLANG_CIR_DIALECT_IR_CIRCUDAATTRS_TD
#endif // CLANG_CIR_DIALECT_IR_CIRCUDAATTRS_TD
52 changes: 38 additions & 14 deletions clang/lib/CIR/CodeGen/CIRGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
#include "CIRGenFunction.h"
#include "mlir/IR/Location.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Attrs.inc"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclOpenACC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/Cuda.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/MissingFeatures.h"

using namespace clang;
Expand All @@ -38,7 +41,7 @@ CIRGenFunction::emitAutoVarAlloca(const VarDecl &d,
emission.isEscapingByRef = d.isEscapingByref();
if (emission.isEscapingByRef)
cgm.errorNYI(d.getSourceRange(),
"emitAutoVarDecl: decl escaping by reference");
"emitAutoVarAlloca: decl escaping by reference");

CharUnits alignment = getContext().getDeclAlign(&d);

Expand Down Expand Up @@ -363,7 +366,7 @@ void CIRGenFunction::emitVarDecl(const VarDecl &d) {
if (d.getType()->isSamplerT()) {
// Nothing needs to be done here, but let's flag it as an error until we
// have a test. It requires OpenCL support.
cgm.errorNYI(d.getSourceRange(), "emitVarDecl static sampler type");
cgm.errorNYI(d.getSourceRange(), "emitVarDecl: static sampler type");
return;
}

Expand All @@ -378,7 +381,7 @@ void CIRGenFunction::emitVarDecl(const VarDecl &d) {
}

if (d.getType().getAddressSpace() == LangAS::opencl_local)
cgm.errorNYI(d.getSourceRange(), "emitVarDecl openCL address space");
cgm.errorNYI(d.getSourceRange(), "emitVarDecl: openCL address space");

assert(d.hasLocalStorage());

Expand All @@ -399,11 +402,14 @@ static std::string getStaticDeclName(CIRGenModule &cgm, const VarDecl &d) {
if (const auto *fd = dyn_cast<FunctionDecl>(dc))
contextName = std::string(cgm.getMangledName(fd));
else if (isa<BlockDecl>(dc))
cgm.errorNYI(d.getSourceRange(), "block decl context for static var");
cgm.errorNYI(d.getSourceRange(),
"getStaticDeclName: block decl context for static var");
else if (isa<ObjCMethodDecl>(dc))
cgm.errorNYI(d.getSourceRange(), "ObjC decl context for static var");
cgm.errorNYI(d.getSourceRange(),
"getStaticDeclName: ObjC decl context for static var");
else
cgm.errorNYI(d.getSourceRange(), "Unknown context for static var decl");
cgm.errorNYI(d.getSourceRange(),
"getStaticDeclName: Unknown context for static var decl");

contextName += "." + d.getNameAsString();
return contextName;
Expand Down Expand Up @@ -433,12 +439,14 @@ CIRGenModule::getOrCreateStaticVarDecl(const VarDecl &d,
mlir::Type lty = getTypes().convertTypeForMem(ty);
assert(!cir::MissingFeatures::addressSpace());

if (d.hasAttr<LoaderUninitializedAttr>() || d.hasAttr<CUDASharedAttr>())
errorNYI(d.getSourceRange(),
"getOrCreateStaticVarDecl: LoaderUninitializedAttr");
assert(!cir::MissingFeatures::addressSpace());

mlir::Attribute init = builder.getZeroInitAttr(convertType(ty));
// OpenCL variables in local address space and CUDA shared
// variables cannot have an initializer.
mlir::Attribute init = nullptr;
if (ty.getAddressSpace() == LangAS::opencl_local ||
d.hasAttr<CUDASharedAttr>() || d.hasAttr<LoaderUninitializedAttr>())
init = cir::UndefAttr::get(lty);
else
init = builder.getZeroInitAttr(convertType(ty));

cir::GlobalOp gv = builder.createVersionedGlobal(
getModule(), getLoc(d.getLocation()), name, lty, false, linkage);
Expand Down Expand Up @@ -667,8 +675,24 @@ void CIRGenFunction::emitStaticVarDecl(const VarDecl &d,

// There are a lot of attributes that need to be handled here. Until
Comment thread
ZakyHermawan marked this conversation as resolved.
Resolved
// we start to support them, we just report an error if there are any.
if (d.hasAttrs())
cgm.errorNYI(d.getSourceRange(), "static var with attrs");
if (d.hasAttr<AnnotateAttr>())
cgm.errorNYI(d.getSourceRange(), "emitStaticVarDecl: Global annotations");
if (d.getAttr<PragmaClangBSSSectionAttr>())
cgm.errorNYI(d.getSourceRange(),
"emitStaticVarDecl: CIR global BSS section attribute");
if (d.getAttr<PragmaClangDataSectionAttr>())
cgm.errorNYI(d.getSourceRange(),
"emitStaticVarDecl: CIR global Data section attribute");
if (d.getAttr<PragmaClangRodataSectionAttr>())
cgm.errorNYI(d.getSourceRange(),
"emitStaticVarDecl: CIR global Rodata section attribute");
if (d.getAttr<PragmaClangRelroSectionAttr>())
cgm.errorNYI(d.getSourceRange(),
"emitStaticVarDecl: CIR global Relro section attribute");

if (d.getAttr<SectionAttr>())
cgm.errorNYI(d.getSourceRange(),
"emitStaticVarDecl: CIR global object file section attribute");

if (cgm.getCodeGenOpts().KeepPersistentStorageVariables)
cgm.errorNYI(d.getSourceRange(), "static var keep persistent storage");
Expand Down
106 changes: 84 additions & 22 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/Attrs.inc"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclOpenACC.h"
#include "clang/AST/GlobalDecl.h"
Expand Down Expand Up @@ -57,7 +58,7 @@ static CIRGenCXXABI *createCXXABI(CIRGenModule &cgm) {
case TargetCXXABI::WebAssembly:
case TargetCXXABI::XL:
case TargetCXXABI::Microsoft:
cgm.errorNYI("C++ ABI kind not yet implemented");
cgm.errorNYI("createCXXABI: C++ ABI kind");
return nullptr;
}

Expand Down Expand Up @@ -695,7 +696,8 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty,
cir::GlobalOp entry;
if (mlir::Operation *v = getGlobalValue(mangledName)) {
if (!isa<cir::GlobalOp>(v))
errorNYI(d->getSourceRange(), "global with non-GlobalOp type");
errorNYI(d->getSourceRange(),
"getOrCreateCIRGlobal: global with non-GlobalOp type");
entry = cast<cir::GlobalOp>(v);
}

Expand All @@ -716,7 +718,8 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty,
// recognizing the global as a declaration, for now only check if
// initializer is present.
if (isForDefinition && !entry.isDeclaration()) {
errorNYI(d->getSourceRange(), "global with conflicting type");
errorNYI(d->getSourceRange(),
"getOrCreateCIRGlobal: global with conflicting type");
}

// Address space check removed because it is unnecessary because CIR records
Expand Down Expand Up @@ -761,15 +764,16 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty,
// Handle things which are present even on external declarations.
if (d) {
if (langOpts.OpenMP && !langOpts.OpenMPSimd)
errorNYI(d->getSourceRange(), "OpenMP target global variable");
errorNYI(d->getSourceRange(),
"getOrCreateCIRGlobal: OpenMP target global variable");

gv.setAlignmentAttr(getSize(astContext.getDeclAlign(d)));

setLinkageForGV(gv, d);

if (d->getTLSKind()) {
if (d->getTLSKind() == VarDecl::TLS_Dynamic)
errorNYI(d->getSourceRange(), "TLS dynamic");
errorNYI(d->getSourceRange(), "getOrCreateCIRGlobal: TLS dynamic");
setTLSMode(gv, *d);
}

Expand All @@ -778,25 +782,41 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty,
// If required by the ABI, treat declarations of static data members with
// inline initializers as definitions.
if (astContext.isMSStaticDataMemberInlineDefinition(d))
errorNYI(d->getSourceRange(), "MS static data member inline definition");
errorNYI(d->getSourceRange(),
"getOrCreateCIRGlobal: MS static data member inline definition");

assert(!cir::MissingFeatures::opGlobalSection());
gv.setGlobalVisibilityAttr(getGlobalVisibilityAttrFromDecl(d));

// Handle XCore specific ABI requirements.
if (getTriple().getArch() == llvm::Triple::xcore)
errorNYI(d->getSourceRange(), "XCore specific ABI requirements");
errorNYI(d->getSourceRange(),
"getOrCreateCIRGlobal: XCore specific ABI requirements");

// Check if we a have a const declaration with an initializer, we may be
// able to emit it as available_externally to expose it's value to the
// optimizer.
if (getLangOpts().CPlusPlus && gv.isPublic() &&
d->getType().isConstQualified() && gv.isDeclaration() &&
!d->hasDefinition() && d->hasInit() && !d->hasAttr<DLLImportAttr>())
errorNYI(
d->getSourceRange(),
"getOrCreateCIRGlobal: external const declaration with initializer");
}

if (d &&
d->isThisDeclarationADefinition(astContext) == VarDecl::DeclarationOnly) {
getTargetCIRGenInfo().setTargetAttributes(d, gv, *this);
// TODO(cir): set target attributes
// External HIP managed variables needed to be recorded for transformation
// in both device and host compilations.
if (getLangOpts().CUDA && d && d->hasAttr<HIPManagedAttr>() &&
d->hasExternalStorage())
errorNYI(d->getSourceRange(),
"external const declaration with initializer");
"getOrCreateCIRGlobal: HIP managed attribute");
}

assert(!cir::MissingFeatures::addressSpace());
return gv;
}

Expand Down Expand Up @@ -848,7 +868,8 @@ cir::GlobalViewAttr CIRGenModule::getAddrOfGlobalVarAttr(const VarDecl *d) {
void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
bool isTentative) {
if (getLangOpts().OpenCL || getLangOpts().OpenMPIsTargetDevice) {
errorNYI(vd->getSourceRange(), "emit OpenCL/OpenMP global variable");
errorNYI(vd->getSourceRange(),
"emitGlobalVarDefinition: emit OpenCL/OpenMP global variable");
return;
}

Expand Down Expand Up @@ -880,9 +901,19 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,

assert(!cir::MissingFeatures::cudaSupport());

if (vd->hasAttr<LoaderUninitializedAttr>()) {
errorNYI(vd->getSourceRange(), "loader uninitialized attribute");
return;
// CUDA E.2.4.1 "__shared__ variables cannot have an initialization
// as part of their declaration." Sema has already checked for
// error cases, so we just need to set Init to UndefValue.
bool isCUDASharedVar =
getLangOpts().CUDAIsDevice && vd->hasAttr<CUDASharedAttr>();
// TODO(cir): implement isCUDAShadowVar and isCUDADeviceShadowVar, reference:
// OGCG

if (getLangOpts().CUDA && isCUDASharedVar) {
init = cir::UndefAttr::get(&getMLIRContext(), convertType(vd->getType()));
} else if (vd->hasAttr<LoaderUninitializedAttr>()) {
errorNYI(vd->getSourceRange(),
"emitGlobalVarDefinition: loader uninitialized attribute");
} else if (!initExpr) {
// This is a tentative definition; tentative definitions are
// implicitly initialized with { 0 }.
Expand All @@ -905,12 +936,14 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,

if (getLangOpts().CPlusPlus) {
if (initDecl->hasFlexibleArrayInit(astContext))
errorNYI(vd->getSourceRange(), "flexible array initializer");
errorNYI(vd->getSourceRange(),
"emitGlobalVarDefinition: flexible array initializer");
init = builder.getZeroInitAttr(convertType(qt));
if (!isDefinitionAvailableExternally)
needsGlobalCtor = true;
} else {
errorNYI(vd->getSourceRange(), "static initializer");
errorNYI(vd->getSourceRange(),
"emitGlobalVarDefinition: static initializer");
}
} else {
init = initializer;
Expand All @@ -923,7 +956,9 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,

mlir::Type initType;
if (mlir::isa<mlir::SymbolRefAttr>(init)) {
errorNYI(vd->getSourceRange(), "global initializer is a symbol reference");
errorNYI(
vd->getSourceRange(),
"emitGlobalVarDefinition: global initializer is a symbol reference");
return;
} else {
assert(mlir::isa<mlir::TypedAttr>(init) && "This should have a type");
Expand All @@ -937,18 +972,49 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
// TODO(cir): Strip off pointer casts from Entry if we get them?

if (!gv || gv.getSymType() != initType) {
errorNYI(vd->getSourceRange(), "global initializer with type mismatch");
errorNYI(vd->getSourceRange(),
"emitGlobalVarDefinition: global initializer with type mismatch");
return;
}

assert(!cir::MissingFeatures::maybeHandleStaticInExternC());

if (vd->hasAttr<AnnotateAttr>()) {
errorNYI(vd->getSourceRange(), "annotate global variable");
errorNYI(vd->getSourceRange(),
"emitGlobalVarDefinition: annotate global variable");
}

// Set CIR's linkage type as appropriate.
cir::GlobalLinkageKind linkage =
getCIRLinkageVarDefinition(vd, /*IsConstant=*/false);

// CUDA B.2.1 "The __device__ qualifier declares a variable that resides on
// the device. [...]"
// CUDA B.2.2 "The __constant__ qualifier, optionally used together with
// __device__, declares a variable that: [...]
// Is accessible from all the threads within the grid and from the host
// through the runtime library (cudaGetSymbolAddress() / cudaGetSymbolSize()
// / cudaMemcpyToSymbol() / cudaMemcpyFromSymbol())."
if (langOpts.CUDA) {
Comment thread
ZakyHermawan marked this conversation as resolved.
Resolved
errorNYI(vd->getSourceRange(), "CUDA global variable");
if (langOpts.CUDAIsDevice) {
// __shared__ variables is not marked as externally initialized,
// because they must not be initialized.
if (linkage != cir::GlobalLinkageKind::InternalLinkage &&
!vd->isConstexpr() && !vd->getType().isConstQualified() &&
(vd->hasAttr<CUDADeviceAttr>() || vd->hasAttr<CUDAConstantAttr>() ||
vd->getType()->isCUDADeviceBuiltinSurfaceType() ||
vd->getType()->isCUDADeviceBuiltinTextureType())) {
gv->setAttr(cir::CUDAExternallyInitializedAttr::getMnemonic(),
cir::CUDAExternallyInitializedAttr::get(&getMLIRContext()));
}
} else {
// TODO(cir):
// Adjust linkage of shadow variables in host compilation
// getCUDARuntime().internalizeDeviceSideVar(vd, linkage);
}
// TODO(cir):
// Handle variable registration
// getCUDARuntime().handleVarRegistration(vd, gv);
}

// Set initializer and finalize emission
Expand All @@ -965,10 +1031,6 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
/*ExcludeDtor=*/true)));
assert(!cir::MissingFeatures::opGlobalSection());

// Set CIR's linkage type as appropriate.
cir::GlobalLinkageKind linkage =
getCIRLinkageVarDefinition(vd, /*IsConstant=*/false);

// Set CIR linkage and DLL storage class.
gv.setLinkage(linkage);
// FIXME(cir): setLinkage should likely set MLIR's visibility automatically.
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/CIR/CodeGen/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,12 @@ bool TargetCIRGenInfo::isNoProtoCallVariadic(
// For everything else, we just prefer false unless we opt out.
return false;
}

clang::LangAS
TargetCIRGenInfo::getGlobalVarAddressSpace(CIRGenModule &cgm,
const clang::VarDecl *d) const {
assert(!cgm.getLangOpts().OpenCL &&
!(cgm.getLangOpts().CUDA && cgm.getLangOpts().CUDAIsDevice) &&
"Address space agnostic languages only");
return d ? d->getType().getAddressSpace() : LangAS::Default;
}
16 changes: 16 additions & 0 deletions clang/lib/CIR/CodeGen/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ class TargetCIRGenInfo {
/// Returns ABI info helper for the target.
const ABIInfo &getABIInfo() const { return *info; }

/// Get target favored AST address space of a global variable for languages
/// other than OpenCL and CUDA.
/// If \p d is nullptr, returns the default target favored address space
/// for global variable.
virtual clang::LangAS getGlobalVarAddressSpace(CIRGenModule &cgm,
const clang::VarDecl *d) const;

/// Get the address space for alloca.
virtual mlir::ptr::MemorySpaceAttrInterface getCIRAllocaAddressSpace() const {
return cir::LangAddressSpaceAttr::get(&info->cgt.getMLIRContext(),
Expand Down Expand Up @@ -99,6 +106,15 @@ class TargetCIRGenInfo {
/// right thing when calling a function with no know signature.
virtual bool isNoProtoCallVariadic(const FunctionNoProtoType *fnType) const;

/// Provides a convenient hook to handle extra target-specific attributes
/// for the given global.
/// In OG, the function receives an llvm::GlobalValue. However, functions
/// and global variables are separate types in Clang IR, so we use a general
/// mlir::Operation*.
virtual void setTargetAttributes(const clang::Decl *decl,
Comment thread
ZakyHermawan marked this conversation as resolved.
Resolved
mlir::Operation *global,
CIRGenModule &module) const {}

virtual bool isScalarizableAsmOperand(CIRGenFunction &cgf,
mlir::Type ty) const {
return false;
Expand Down
Loading