25#include "llvm/ADT/SmallVector.h"
32 if (
auto *A = D->
getAttr<AttrT>())
33 return !A->isImplicit();
38 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
39 ForceCUDAHostDeviceDepth++;
43 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
44 if (ForceCUDAHostDeviceDepth == 0)
46 ForceCUDAHostDeviceDepth--;
63 return BuildCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc,
nullptr,
69 bool HasHostAttr =
false;
70 bool HasDeviceAttr =
false;
71 bool HasGlobalAttr =
false;
72 bool HasInvalidTargetAttr =
false;
74 switch (AL.getKind()) {
75 case ParsedAttr::AT_CUDAGlobal:
78 case ParsedAttr::AT_CUDAHost:
81 case ParsedAttr::AT_CUDADevice:
84 case ParsedAttr::AT_CUDAInvalidTarget:
85 HasInvalidTargetAttr =
true;
92 if (HasInvalidTargetAttr)
98 if (HasHostAttr && HasDeviceAttr)
110 return isa<A>(Attribute) &&
111 !(IgnoreImplicitAttr && Attribute->isImplicit());
117 bool IgnoreImplicitHDAttr) {
122 if (D->
hasAttr<CUDAInvalidTargetAttr>())
125 if (D->
hasAttr<CUDAGlobalAttr>())
128 if (hasAttr<CUDADeviceAttr>(D, IgnoreImplicitHDAttr)) {
129 if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr))
132 }
else if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr)) {
135 !IgnoreImplicitHDAttr) {
146 if (Var->
hasAttr<HIPManagedAttr>())
152 Var->
hasAttr<CUDAConstantAttr>() &&
153 !hasExplicitAttr<CUDAConstantAttr>(Var))
155 if (Var->
hasAttr<CUDADeviceAttr>() || Var->
hasAttr<CUDAConstantAttr>() ||
156 Var->
hasAttr<CUDASharedAttr>() ||
209 assert(Callee &&
"Callee must be valid.");
229 if (CalleeTarget == CallerTarget ||
255 llvm_unreachable(
"All cases should've been handled by now.");
261 if (
auto *A = D->
getAttr<AttrT>())
262 return A->isImplicit();
267 bool IsImplicitDevAttr = hasImplicitAttr<CUDADeviceAttr>(D);
268 bool IsImplicitHostAttr = hasImplicitAttr<CUDAHostAttr>(D);
269 return IsImplicitDevAttr && IsImplicitHostAttr;
275 if (Matches.size() <= 1)
278 using Pair = std::pair<DeclAccessPair, FunctionDecl*>;
281 auto GetCFP = [&](
const Pair &Match) {
287 Matches.begin(), Matches.end(),
288 [&](
const Pair &M1,
const Pair &M2) { return GetCFP(M1) < GetCFP(M2); }));
291 llvm::erase_if(Matches,
292 [&](
const Pair &Match) {
return GetCFP(Match) < BestCFP; });
312 *ResolvedTarget = Target2;
314 *ResolvedTarget = Target1;
315 }
else if (Target1 != Target2) {
318 *ResolvedTarget = Target1;
333 bool HasH = MemberDecl->
hasAttr<CUDAHostAttr>();
334 bool HasD = MemberDecl->
hasAttr<CUDADeviceAttr>();
335 bool HasExplicitAttr =
336 (HasD && !MemberDecl->
getAttr<CUDADeviceAttr>()->isImplicit()) ||
337 (HasH && !MemberDecl->
getAttr<CUDAHostAttr>()->isImplicit());
338 if (!InClass || HasExplicitAttr)
341 std::optional<CUDAFunctionTarget> InferredTarget;
351 for (
const auto &B : ClassDecl->
bases()) {
352 if (!B.isVirtual()) {
358 llvm::append_range(Bases, llvm::make_pointer_range(ClassDecl->
vbases()));
361 for (
const auto *B : Bases) {
380 if (!InferredTarget) {
381 InferredTarget = BaseMethodTarget;
384 *InferredTarget, BaseMethodTarget, &*InferredTarget);
385 if (ResolutionError) {
388 diag::note_implicit_member_target_infer_collision)
389 << (
unsigned)CSM << *InferredTarget << BaseMethodTarget;
391 MemberDecl->
addAttr(CUDAInvalidTargetAttr::CreateImplicit(
Context));
398 for (
const auto *F : ClassDecl->
fields()) {
399 if (F->isInvalidDecl()) {
412 ConstRHS && !F->isMutable(),
423 if (!InferredTarget) {
424 InferredTarget = FieldMethodTarget;
427 *InferredTarget, FieldMethodTarget, &*InferredTarget);
428 if (ResolutionError) {
431 diag::note_implicit_member_target_infer_collision)
432 << (
unsigned)CSM << *InferredTarget << FieldMethodTarget;
434 MemberDecl->
addAttr(CUDAInvalidTargetAttr::CreateImplicit(
Context));
443 bool NeedsH =
true, NeedsD =
true;
444 if (InferredTarget) {
447 else if (*InferredTarget ==
CFT_Host)
489 if (const CXXConstructExpr *CE =
490 dyn_cast<CXXConstructExpr>(CI->getInit()))
491 return isEmptyCudaConstructor(Loc, CE->getConstructor());
533 if (CXXRecordDecl *RD = BS.getType()->getAsCXXRecordDecl())
534 return isEmptyCudaDestructor(Loc, RD->getDestructor());
541 if (CXXRecordDecl *RD = Field->getType()
542 ->getBaseElementTypeUnsafe()
543 ->getAsCXXRecordDecl())
544 return isEmptyCudaDestructor(Loc, RD->getDestructor());
553enum CUDAInitializerCheckKind {
554 CICK_DeviceOrConstant,
558bool IsDependentVar(
VarDecl *VD) {
561 if (
const auto *Init = VD->
getInit())
562 return Init->isValueDependent();
575bool HasAllowedCUDADeviceStaticInitializer(
Sema &S,
VarDecl *VD,
576 CUDAInitializerCheckKind CheckKind) {
578 assert(!IsDependentVar(VD) &&
"do not check dependent var");
580 auto IsEmptyInit = [&](
const Expr *Init) {
583 if (
const auto *CE = dyn_cast<CXXConstructExpr>(Init)) {
588 auto IsConstantInit = [&](
const Expr *Init) {
592 return Init->isConstantInitializer(S.
Context,
595 auto HasEmptyDtor = [&](
VarDecl *VD) {
600 if (CheckKind == CICK_Shared)
601 return IsEmptyInit(Init) && HasEmptyDtor(VD);
602 return S.
LangOpts.GPUAllowDeviceInit ||
603 ((IsEmptyInit(Init) || IsConstantInit(Init)) && HasEmptyDtor(VD));
614 bool IsSharedVar = VD->
hasAttr<CUDASharedAttr>();
615 bool IsDeviceOrConstantVar =
617 (VD->
hasAttr<CUDADeviceAttr>() || VD->
hasAttr<CUDAConstantAttr>());
618 if (IsDeviceOrConstantVar || IsSharedVar) {
619 if (HasAllowedCUDADeviceStaticInitializer(
620 *
this, VD, IsSharedVar ? CICK_Shared : CICK_DeviceOrConstant))
623 IsSharedVar ? diag::err_shared_var_init : diag::err_dynamic_var_init)
624 << Init->getSourceRange();
631 InitFn = CE->getConstructor();
632 }
else if (
const CallExpr *CE = dyn_cast<CallExpr>(Init)) {
633 InitFn = CE->getDirectCallee();
639 << InitFnTarget << InitFn;
640 Diag(InitFn->getLocation(), diag::note_previous_decl) << InitFn;
661 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
663 if (ForceCUDAHostDeviceDepth > 0) {
664 if (!NewD->
hasAttr<CUDAHostAttr>())
666 if (!NewD->
hasAttr<CUDADeviceAttr>())
673 NewD->
hasAttr<CUDADeviceAttr>() || NewD->
hasAttr<CUDAGlobalAttr>())
678 auto IsMatchingDeviceFn = [&](
NamedDecl *D) {
680 D = Using->getTargetDecl();
682 return OldD && OldD->
hasAttr<CUDADeviceAttr>() &&
683 !OldD->
hasAttr<CUDAHostAttr>() &&
687 auto It = llvm::find_if(
Previous, IsMatchingDeviceFn);
696 diag::err_cuda_unattributed_constexpr_cannot_overload_device)
699 diag::note_cuda_conflicting_device_function_declared_here);
715 !VD->
hasAttr<CUDASharedAttr>() &&
717 !IsDependentVar(VD) &&
719 HasAllowedCUDADeviceStaticInitializer(*
this, VD,
720 CICK_DeviceOrConstant))) {
727 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
757 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
785 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
786 assert(Callee &&
"Callee may not be null.");
789 if (ExprEvalCtx.isUnevaluated() || ExprEvalCtx.isConstantEvaluated())
800 bool CallerKnownEmitted =
803 CallerKnownEmitted] {
807 assert(Caller &&
"Never/wrongSide calls require a non-null caller");
811 return CallerKnownEmitted
822 Callee->hasAttr<CUDAGlobalAttr>() && !Callee->isDefined())
837 if (!Callee->getBuiltinID())
839 diag::note_previous_decl, Caller, *
this)
873 bool CalleeIsDevice = Callee->hasAttr<CUDADeviceAttr>();
875 !Caller->
hasAttr<CUDAGlobalAttr>() && !Caller->
hasAttr<CUDADeviceAttr>();
876 bool ShouldCheck = CalleeIsDevice && CallerIsHost;
882 diag::err_capture_bad_target, Callee, *
this)
890 diag::warn_maybe_capture_bad_target_this_ptr, Callee,
896 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
897 if (Method->
hasAttr<CUDAHostAttr>() || Method->
hasAttr<CUDADeviceAttr>())
905 assert(
getLangOpts().
CUDA &&
"Should only be called during CUDA compilation");
918 if (NewTarget != OldTarget &&
924 << NewTarget << NewFD->
getDeclName() << OldTarget << OldFD;
925 Diag(OldFD->getLocation(), diag::note_previous_declaration);
932template <
typename AttrTy>
935 if (AttrTy *Attribute = TemplateFD.
getAttr<AttrTy>()) {
936 AttrTy *Clone = Attribute->clone(S.
Context);
937 Clone->setInherited(
true);
945 copyAttrIfPresent<CUDAGlobalAttr>(*
this, FD, TemplateFD);
946 copyAttrIfPresent<CUDAHostAttr>(*
this, FD, TemplateFD);
947 copyAttrIfPresent<CUDADeviceAttr>(*
this, FD, TemplateFD);
952 return getLangOpts().HIPUseNewLaunchAPI ?
"__hipPushCallConfiguration"
953 :
"hipConfigureCall";
958 return "__cudaPushCallConfiguration";
961 return "cudaConfigureCall";
Defines the clang::ASTContext interface.
Defines the clang::Expr interface and subclasses for C++ expressions.
Defines the clang::Preprocessor interface.
static void copyAttrIfPresent(Sema &S, FunctionDecl *FD, const FunctionDecl &TemplateFD)
static bool hasAttr(const FunctionDecl *D, bool IgnoreImplicitAttr)
static bool resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1, Sema::CUDAFunctionTarget Target2, Sema::CUDAFunctionTarget *ResolvedTarget)
When an implicitly-declared special member has to invoke more than one base/field special member,...
static bool hasImplicitAttr(const FunctionDecl *D)
static bool hasExplicitAttr(const VarDecl *D)
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
llvm::DenseSet< const ValueDecl * > CUDAExternalDeviceDeclODRUsedByHost
Keep track of CUDA/HIP external kernels or device variables ODR-used by host code.
FunctionDecl * getcudaConfigureCallDecl()
const TargetInfo & getTargetInfo() const
Attr - This represents one attribute.
Represents a base class of a C++ class.
Represents a call to a C++ constructor.
Represents a C++ constructor within a class.
Represents a C++ base or member initializer.
Represents a C++ destructor within a class.
Represents a static or instance method of a struct/union/class.
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Represents a C++ struct/union/class.
base_class_range vbases()
bool isAbstract() const
Determine whether this class has a pure virtual function.
bool isDynamicClass() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
DeclContext * getLexicalParent()
getLexicalParent - Returns the containing lexical DeclContext.
A reference to a declared variable, function, enum, etc.
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
void setInvalidDecl(bool Invalid=true)
setInvalidDecl - Indicates the Decl had a semantic error.
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
bool isInvalidDecl() const
SourceLocation getLocation() const
DeclContext * getDeclContext()
const IntrusiveRefCntPtr< DiagnosticIDs > & getDiagnosticIDs() const
This represents one expression.
Represents a member of a struct/union/class.
Represents a function declaration or definition.
bool hasTrivialBody() const
Returns whether the function has a trivial body that does not require any specific codegen.
bool isTrivial() const
Whether this function is "trivial" in some specialized C++ senses.
bool isVariadic() const
Whether this function is variadic.
bool isTemplateInstantiation() const
Determines if the given function was instantiated from a function template.
bool isConstexpr() const
Whether this is a (C++11) constexpr function or constexpr constructor.
bool isUserProvided() const
True if this method is user-declared and was not deleted or defaulted on its first declaration.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
bool isDefined(const FunctionDecl *&Definition, bool CheckForPendingFriendDefinition=false) const
Returns true if the function has a definition that does not need to be instantiated.
Declaration of a template function.
FunctionDecl * getTemplatedDecl() const
Get the underlying function declaration of the template.
Represents the results of name lookup.
This represents a decl that may have a name.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
ParsedAttr - Represents a syntactic attribute.
A (possibly-)qualified type.
bool isConstQualified() const
Determine whether this type is const-qualified.
field_range fields() const
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
RecordDecl * getDecl() const
decl_type * getFirstDecl()
Return the first declaration of this declaration or itself if this is the only declaration.
Scope - A scope is a transient data structure that is used while parsing the program.
A generic diagnostic builder for errors which may or may not be deferred.
@ K_Nop
Emit no diagnostics.
@ K_Deferred
Create a deferred diagnostic, which is emitted only if the function it's attached to is codegen'ed.
@ K_ImmediateWithCallStack
Emit the diagnostic immediately, and, if it's a warning or error, also emit a call stack showing how ...
@ K_Immediate
Emit the diagnostic immediately (i.e., behave like Sema::Diag()).
SpecialMemberOverloadResult - The overloading result for a special member function.
CXXMethodDecl * getMethod() const
Sema - This implements semantic analysis and AST building for C.
CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D, bool IgnoreImplicitHDAttr=false)
Determines whether the given function is a CUDA device/host/kernel/etc.
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs=true, bool ConsiderRequiresClauses=true)
bool IsLastErrorImmediate
Is the last error level diagnostic immediate.
void CUDACheckLambdaCapture(CXXMethodDecl *D, const sema::Capture &Capture)
void EraseUnwantedCUDAMatches(const FunctionDecl *Caller, SmallVectorImpl< std::pair< DeclAccessPair, FunctionDecl * > > &Matches)
Finds a function in Matches with highest calling priority from Caller context and erases all function...
ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, MultiExprArg ExecConfig, SourceLocation GGGLoc)
FunctionDecl * getCurFunctionDecl(bool AllowLambda=false) const
Returns a pointer to the innermost enclosing function, or nullptr if the current context is not insid...
ASTContext & getASTContext() const
void checkAllowedCUDAInitializer(VarDecl *VD)
const LangOptions & getLangOpts() const
SpecialMemberOverloadResult LookupSpecialMember(CXXRecordDecl *D, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis)
SemaDiagnosticBuilder CUDADiagIfDeviceCode(SourceLocation Loc, unsigned DiagID)
Creates a SemaDiagnosticBuilder that emits the diagnostic if the current context is "used as device c...
bool CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee)
Check whether we're allowed to call Callee from the current context.
ExprResult BuildCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig=nullptr, bool IsExecConfig=false, bool AllowRecovery=false)
BuildCallExpr - Handle a call to Fn with the specified array of arguments.
const LangOptions & LangOpts
void MaybeAddCUDAConstantAttr(VarDecl *VD)
May add implicit CUDAConstantAttr attribute to VD, depending on VD and current compilation settings.
CUDAFunctionPreference IdentifyCUDAPreference(const FunctionDecl *Caller, const FunctionDecl *Callee)
Identifies relative preference of a given Caller/Callee combination, based on their host/device attri...
void maybeAddCUDAHostDeviceAttrs(FunctionDecl *FD, const LookupResult &Previous)
May add implicit CUDAHostAttr and CUDADeviceAttr attributes to FD, depending on FD and the current co...
void PushForceCUDAHostDevice()
Increments our count of the number of times we've seen a pragma forcing functions to be host device.
SourceManager & getSourceManager() const
llvm::DenseSet< FunctionDeclAndLoc > LocsWithCUDACallDiags
FunctionDecls and SourceLocations for which CheckCUDACall has emitted a (maybe deferred) "bad call" d...
SemaDiagnosticBuilder CUDADiagIfHostCode(SourceLocation Loc, unsigned DiagID)
Creates a SemaDiagnosticBuilder that emits the diagnostic if the current context is "used as host cod...
bool inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, CXXSpecialMember CSM, CXXMethodDecl *MemberDecl, bool ConstRHS, bool Diagnose)
Given a implicit special member, infer its CUDA target from the calls it needs to make to underlying ...
void CUDASetLambdaAttrs(CXXMethodDecl *Method)
Set device or host device attributes on the given lambda operator() method.
FunctionEmissionStatus getEmissionStatus(FunctionDecl *Decl, bool Final=false)
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive=false, bool DefinitionRequired=false, bool AtEndOfTU=false)
Instantiate the definition of the given function from its template.
@ CVT_Both
Emitted on host side only.
@ CVT_Unified
Emitted on both sides with different addresses.
@ CVT_Host
Emitted on device side with a shadow variable on host side.
void inheritCUDATargetAttrs(FunctionDecl *FD, const FunctionTemplateDecl &TD)
Copies target attributes from the template TD to the function FD.
CUDAFunctionTarget CurrentCUDATarget()
Gets the CUDA target for the current context.
bool isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD)
SmallVector< ExpressionEvaluationContextRecord, 8 > ExprEvalContexts
A stack of expression evaluation contexts.
DiagnosticsEngine & Diags
bool isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *CD)
void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, bool MightBeOdrUse=true)
Mark a function referenced, and check whether it is odr-used (C++ [basic.def.odr]p2,...
static bool isCUDAImplicitHostDeviceFunction(const FunctionDecl *D)
bool PopForceCUDAHostDevice()
Decrements our count of the number of times we've seen a pragma forcing functions to be host device.
@ Diagnose
Diagnose issues that are non-constant or that are extensions.
CXXSpecialMember
Kinds of C++ special members.
std::string getCudaConfigureFuncName() const
Returns the name of the launch configuration function.
void checkCUDATargetOverload(FunctionDecl *NewFD, const LookupResult &Previous)
Check whether NewFD is a valid overload for CUDA.
Encodes a location in the source.
const llvm::VersionTuple & getSDKVersion() const
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isReferenceType() const
bool isCUDADeviceBuiltinSurfaceType() const
Check if the type is the CUDA device builtin surface type.
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
bool isCUDADeviceBuiltinTextureType() const
Check if the type is the CUDA device builtin texture type.
const T * getAs() const
Member-template getAs<specific type>'.
Represents a shadow declaration implicitly introduced into a scope by a (resolved) using-declaration ...
Represents a variable declaration or definition.
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
bool isStaticDataMember() const
Determines whether this is a static data member.
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
bool isFileVarDecl() const
Returns true for file scoped variable declaration.
const Expr * getInit() const
ValueDecl * getVariable() const
bool isVariableCapture() const
SourceLocation getLocation() const
Retrieve the location at which this variable was captured.
bool isThisCapture() const
bool isReferenceCapture() const
Defines the clang::TargetInfo interface.
bool CudaFeatureEnabled(llvm::VersionTuple, CudaFeature)
@ VK_LValue
An l-value expression is a reference to an object with independent storage.