10b57cec5SDimitry Andric //===--- SemaCUDA.cpp - Semantic Analysis for CUDA constructs -------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// \file 90b57cec5SDimitry Andric /// This file implements semantic analysis for CUDA constructs. 100b57cec5SDimitry Andric /// 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 13*0fca6ea1SDimitry Andric #include "clang/Sema/SemaCUDA.h" 140b57cec5SDimitry Andric #include "clang/AST/ASTContext.h" 150b57cec5SDimitry Andric #include "clang/AST/Decl.h" 160b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h" 170b57cec5SDimitry Andric #include "clang/Basic/Cuda.h" 185ffd83dbSDimitry Andric #include "clang/Basic/TargetInfo.h" 190b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h" 200b57cec5SDimitry Andric #include "clang/Sema/Lookup.h" 215ffd83dbSDimitry Andric #include "clang/Sema/ScopeInfo.h" 220b57cec5SDimitry Andric #include "clang/Sema/Sema.h" 230b57cec5SDimitry Andric #include "clang/Sema/SemaDiagnostic.h" 240b57cec5SDimitry Andric #include "clang/Sema/SemaInternal.h" 250b57cec5SDimitry Andric #include "clang/Sema/Template.h" 26*0fca6ea1SDimitry Andric #include "llvm/ADT/STLForwardCompat.h" 270b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 28bdd1243dSDimitry Andric #include <optional> 290b57cec5SDimitry Andric using namespace clang; 300b57cec5SDimitry Andric 31*0fca6ea1SDimitry Andric SemaCUDA::SemaCUDA(Sema &S) : SemaBase(S) {} 32*0fca6ea1SDimitry Andric 33fe6060f1SDimitry Andric template <typename AttrT> static bool hasExplicitAttr(const VarDecl *D) { 34fe6060f1SDimitry Andric if (!D) 35fe6060f1SDimitry Andric return false; 36fe6060f1SDimitry Andric if (auto *A = D->getAttr<AttrT>()) 37fe6060f1SDimitry Andric return !A->isImplicit(); 38fe6060f1SDimitry Andric return false; 39fe6060f1SDimitry Andric } 40fe6060f1SDimitry Andric 41*0fca6ea1SDimitry Andric void SemaCUDA::PushForceHostDevice() { 420b57cec5SDimitry Andric assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); 43*0fca6ea1SDimitry Andric ForceHostDeviceDepth++; 440b57cec5SDimitry Andric } 450b57cec5SDimitry Andric 46*0fca6ea1SDimitry Andric bool SemaCUDA::PopForceHostDevice() { 470b57cec5SDimitry Andric assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); 48*0fca6ea1SDimitry Andric if (ForceHostDeviceDepth == 0) 490b57cec5SDimitry Andric return false; 50*0fca6ea1SDimitry Andric ForceHostDeviceDepth--; 510b57cec5SDimitry Andric return true; 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 54*0fca6ea1SDimitry Andric ExprResult SemaCUDA::ActOnExecConfigExpr(Scope *S, SourceLocation LLLLoc, 550b57cec5SDimitry Andric MultiExprArg ExecConfig, 560b57cec5SDimitry Andric SourceLocation GGGLoc) { 57*0fca6ea1SDimitry Andric FunctionDecl *ConfigDecl = getASTContext().getcudaConfigureCallDecl(); 580b57cec5SDimitry Andric if (!ConfigDecl) 590b57cec5SDimitry Andric return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use) 60*0fca6ea1SDimitry Andric << getConfigureFuncName()); 610b57cec5SDimitry Andric QualType ConfigQTy = ConfigDecl->getType(); 620b57cec5SDimitry Andric 63*0fca6ea1SDimitry Andric DeclRefExpr *ConfigDR = new (getASTContext()) DeclRefExpr( 64*0fca6ea1SDimitry Andric getASTContext(), ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc); 65*0fca6ea1SDimitry Andric SemaRef.MarkFunctionReferenced(LLLLoc, ConfigDecl); 660b57cec5SDimitry Andric 67*0fca6ea1SDimitry Andric return SemaRef.BuildCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr, 680b57cec5SDimitry Andric /*IsExecConfig=*/true); 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 71*0fca6ea1SDimitry Andric CUDAFunctionTarget SemaCUDA::IdentifyTarget(const ParsedAttributesView &Attrs) { 720b57cec5SDimitry Andric bool HasHostAttr = false; 730b57cec5SDimitry Andric bool HasDeviceAttr = false; 740b57cec5SDimitry Andric bool HasGlobalAttr = false; 750b57cec5SDimitry Andric bool HasInvalidTargetAttr = false; 760b57cec5SDimitry Andric for (const ParsedAttr &AL : Attrs) { 770b57cec5SDimitry Andric switch (AL.getKind()) { 780b57cec5SDimitry Andric case ParsedAttr::AT_CUDAGlobal: 790b57cec5SDimitry Andric HasGlobalAttr = true; 800b57cec5SDimitry Andric break; 810b57cec5SDimitry Andric case ParsedAttr::AT_CUDAHost: 820b57cec5SDimitry Andric HasHostAttr = true; 830b57cec5SDimitry Andric break; 840b57cec5SDimitry Andric case ParsedAttr::AT_CUDADevice: 850b57cec5SDimitry Andric HasDeviceAttr = true; 860b57cec5SDimitry Andric break; 870b57cec5SDimitry Andric case ParsedAttr::AT_CUDAInvalidTarget: 880b57cec5SDimitry Andric HasInvalidTargetAttr = true; 890b57cec5SDimitry Andric break; 900b57cec5SDimitry Andric default: 910b57cec5SDimitry Andric break; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric if (HasInvalidTargetAttr) 96*0fca6ea1SDimitry Andric return CUDAFunctionTarget::InvalidTarget; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric if (HasGlobalAttr) 99*0fca6ea1SDimitry Andric return CUDAFunctionTarget::Global; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric if (HasHostAttr && HasDeviceAttr) 102*0fca6ea1SDimitry Andric return CUDAFunctionTarget::HostDevice; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric if (HasDeviceAttr) 105*0fca6ea1SDimitry Andric return CUDAFunctionTarget::Device; 1060b57cec5SDimitry Andric 107*0fca6ea1SDimitry Andric return CUDAFunctionTarget::Host; 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric template <typename A> 1115f757f3fSDimitry Andric static bool hasAttr(const Decl *D, bool IgnoreImplicitAttr) { 1120b57cec5SDimitry Andric return D->hasAttrs() && llvm::any_of(D->getAttrs(), [&](Attr *Attribute) { 1130b57cec5SDimitry Andric return isa<A>(Attribute) && 1140b57cec5SDimitry Andric !(IgnoreImplicitAttr && Attribute->isImplicit()); 1150b57cec5SDimitry Andric }); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 118*0fca6ea1SDimitry Andric SemaCUDA::CUDATargetContextRAII::CUDATargetContextRAII( 119*0fca6ea1SDimitry Andric SemaCUDA &S_, SemaCUDA::CUDATargetContextKind K, Decl *D) 1205f757f3fSDimitry Andric : S(S_) { 1215f757f3fSDimitry Andric SavedCtx = S.CurCUDATargetCtx; 122*0fca6ea1SDimitry Andric assert(K == SemaCUDA::CTCK_InitGlobalVar); 1235f757f3fSDimitry Andric auto *VD = dyn_cast_or_null<VarDecl>(D); 1245f757f3fSDimitry Andric if (VD && VD->hasGlobalStorage() && !VD->isStaticLocal()) { 125*0fca6ea1SDimitry Andric auto Target = CUDAFunctionTarget::Host; 1265f757f3fSDimitry Andric if ((hasAttr<CUDADeviceAttr>(VD, /*IgnoreImplicit=*/true) && 1275f757f3fSDimitry Andric !hasAttr<CUDAHostAttr>(VD, /*IgnoreImplicit=*/true)) || 1285f757f3fSDimitry Andric hasAttr<CUDASharedAttr>(VD, /*IgnoreImplicit=*/true) || 1295f757f3fSDimitry Andric hasAttr<CUDAConstantAttr>(VD, /*IgnoreImplicit=*/true)) 130*0fca6ea1SDimitry Andric Target = CUDAFunctionTarget::Device; 1315f757f3fSDimitry Andric S.CurCUDATargetCtx = {Target, K, VD}; 1325f757f3fSDimitry Andric } 1335f757f3fSDimitry Andric } 1345f757f3fSDimitry Andric 135*0fca6ea1SDimitry Andric /// IdentifyTarget - Determine the CUDA compilation target for this function 136*0fca6ea1SDimitry Andric CUDAFunctionTarget SemaCUDA::IdentifyTarget(const FunctionDecl *D, 1370b57cec5SDimitry Andric bool IgnoreImplicitHDAttr) { 1385f757f3fSDimitry Andric // Code that lives outside a function gets the target from CurCUDATargetCtx. 1390b57cec5SDimitry Andric if (D == nullptr) 1405f757f3fSDimitry Andric return CurCUDATargetCtx.Target; 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric if (D->hasAttr<CUDAInvalidTargetAttr>()) 143*0fca6ea1SDimitry Andric return CUDAFunctionTarget::InvalidTarget; 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric if (D->hasAttr<CUDAGlobalAttr>()) 146*0fca6ea1SDimitry Andric return CUDAFunctionTarget::Global; 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric if (hasAttr<CUDADeviceAttr>(D, IgnoreImplicitHDAttr)) { 1490b57cec5SDimitry Andric if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr)) 150*0fca6ea1SDimitry Andric return CUDAFunctionTarget::HostDevice; 151*0fca6ea1SDimitry Andric return CUDAFunctionTarget::Device; 1520b57cec5SDimitry Andric } else if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr)) { 153*0fca6ea1SDimitry Andric return CUDAFunctionTarget::Host; 154e8d8bef9SDimitry Andric } else if ((D->isImplicit() || !D->isUserProvided()) && 155e8d8bef9SDimitry Andric !IgnoreImplicitHDAttr) { 1560b57cec5SDimitry Andric // Some implicit declarations (like intrinsic functions) are not marked. 1570b57cec5SDimitry Andric // Set the most lenient target on them for maximal flexibility. 158*0fca6ea1SDimitry Andric return CUDAFunctionTarget::HostDevice; 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 161*0fca6ea1SDimitry Andric return CUDAFunctionTarget::Host; 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 164fe6060f1SDimitry Andric /// IdentifyTarget - Determine the CUDA compilation target for this variable. 165*0fca6ea1SDimitry Andric SemaCUDA::CUDAVariableTarget SemaCUDA::IdentifyTarget(const VarDecl *Var) { 166fe6060f1SDimitry Andric if (Var->hasAttr<HIPManagedAttr>()) 167fe6060f1SDimitry Andric return CVT_Unified; 16881ad6265SDimitry Andric // Only constexpr and const variabless with implicit constant attribute 16981ad6265SDimitry Andric // are emitted on both sides. Such variables are promoted to device side 17081ad6265SDimitry Andric // only if they have static constant intializers on device side. 17181ad6265SDimitry Andric if ((Var->isConstexpr() || Var->getType().isConstQualified()) && 17281ad6265SDimitry Andric Var->hasAttr<CUDAConstantAttr>() && 173fe6060f1SDimitry Andric !hasExplicitAttr<CUDAConstantAttr>(Var)) 174fe6060f1SDimitry Andric return CVT_Both; 175fe6060f1SDimitry Andric if (Var->hasAttr<CUDADeviceAttr>() || Var->hasAttr<CUDAConstantAttr>() || 176fe6060f1SDimitry Andric Var->hasAttr<CUDASharedAttr>() || 177fe6060f1SDimitry Andric Var->getType()->isCUDADeviceBuiltinSurfaceType() || 178fe6060f1SDimitry Andric Var->getType()->isCUDADeviceBuiltinTextureType()) 179fe6060f1SDimitry Andric return CVT_Device; 180fe6060f1SDimitry Andric // Function-scope static variable without explicit device or constant 181fe6060f1SDimitry Andric // attribute are emitted 182fe6060f1SDimitry Andric // - on both sides in host device functions 183fe6060f1SDimitry Andric // - on device side in device or global functions 184fe6060f1SDimitry Andric if (auto *FD = dyn_cast<FunctionDecl>(Var->getDeclContext())) { 185*0fca6ea1SDimitry Andric switch (IdentifyTarget(FD)) { 186*0fca6ea1SDimitry Andric case CUDAFunctionTarget::HostDevice: 187fe6060f1SDimitry Andric return CVT_Both; 188*0fca6ea1SDimitry Andric case CUDAFunctionTarget::Device: 189*0fca6ea1SDimitry Andric case CUDAFunctionTarget::Global: 190fe6060f1SDimitry Andric return CVT_Device; 191fe6060f1SDimitry Andric default: 192fe6060f1SDimitry Andric return CVT_Host; 193fe6060f1SDimitry Andric } 194fe6060f1SDimitry Andric } 195fe6060f1SDimitry Andric return CVT_Host; 196fe6060f1SDimitry Andric } 197fe6060f1SDimitry Andric 1980b57cec5SDimitry Andric // * CUDA Call preference table 1990b57cec5SDimitry Andric // 2000b57cec5SDimitry Andric // F - from, 2010b57cec5SDimitry Andric // T - to 2020b57cec5SDimitry Andric // Ph - preference in host mode 2030b57cec5SDimitry Andric // Pd - preference in device mode 2040b57cec5SDimitry Andric // H - handled in (x) 2050b57cec5SDimitry Andric // Preferences: N:native, SS:same side, HD:host-device, WS:wrong side, --:never. 2060b57cec5SDimitry Andric // 2070b57cec5SDimitry Andric // | F | T | Ph | Pd | H | 2080b57cec5SDimitry Andric // |----+----+-----+-----+-----+ 2090b57cec5SDimitry Andric // | d | d | N | N | (c) | 2100b57cec5SDimitry Andric // | d | g | -- | -- | (a) | 2110b57cec5SDimitry Andric // | d | h | -- | -- | (e) | 2120b57cec5SDimitry Andric // | d | hd | HD | HD | (b) | 2130b57cec5SDimitry Andric // | g | d | N | N | (c) | 2140b57cec5SDimitry Andric // | g | g | -- | -- | (a) | 2150b57cec5SDimitry Andric // | g | h | -- | -- | (e) | 2160b57cec5SDimitry Andric // | g | hd | HD | HD | (b) | 2170b57cec5SDimitry Andric // | h | d | -- | -- | (e) | 2180b57cec5SDimitry Andric // | h | g | N | N | (c) | 2190b57cec5SDimitry Andric // | h | h | N | N | (c) | 2200b57cec5SDimitry Andric // | h | hd | HD | HD | (b) | 2210b57cec5SDimitry Andric // | hd | d | WS | SS | (d) | 2220b57cec5SDimitry Andric // | hd | g | SS | -- |(d/a)| 2230b57cec5SDimitry Andric // | hd | h | SS | WS | (d) | 2240b57cec5SDimitry Andric // | hd | hd | HD | HD | (b) | 2250b57cec5SDimitry Andric 226*0fca6ea1SDimitry Andric SemaCUDA::CUDAFunctionPreference 227*0fca6ea1SDimitry Andric SemaCUDA::IdentifyPreference(const FunctionDecl *Caller, 2280b57cec5SDimitry Andric const FunctionDecl *Callee) { 2290b57cec5SDimitry Andric assert(Callee && "Callee must be valid."); 2305f757f3fSDimitry Andric 2315f757f3fSDimitry Andric // Treat ctor/dtor as host device function in device var initializer to allow 2325f757f3fSDimitry Andric // trivial ctor/dtor without device attr to be used. Non-trivial ctor/dtor 233*0fca6ea1SDimitry Andric // will be diagnosed by checkAllowedInitializer. 2345f757f3fSDimitry Andric if (Caller == nullptr && CurCUDATargetCtx.Kind == CTCK_InitGlobalVar && 235*0fca6ea1SDimitry Andric CurCUDATargetCtx.Target == CUDAFunctionTarget::Device && 2365f757f3fSDimitry Andric (isa<CXXConstructorDecl>(Callee) || isa<CXXDestructorDecl>(Callee))) 2375f757f3fSDimitry Andric return CFP_HostDevice; 2385f757f3fSDimitry Andric 239*0fca6ea1SDimitry Andric CUDAFunctionTarget CallerTarget = IdentifyTarget(Caller); 240*0fca6ea1SDimitry Andric CUDAFunctionTarget CalleeTarget = IdentifyTarget(Callee); 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric // If one of the targets is invalid, the check always fails, no matter what 2430b57cec5SDimitry Andric // the other target is. 244*0fca6ea1SDimitry Andric if (CallerTarget == CUDAFunctionTarget::InvalidTarget || 245*0fca6ea1SDimitry Andric CalleeTarget == CUDAFunctionTarget::InvalidTarget) 2460b57cec5SDimitry Andric return CFP_Never; 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric // (a) Can't call global from some contexts until we support CUDA's 2490b57cec5SDimitry Andric // dynamic parallelism. 250*0fca6ea1SDimitry Andric if (CalleeTarget == CUDAFunctionTarget::Global && 251*0fca6ea1SDimitry Andric (CallerTarget == CUDAFunctionTarget::Global || 252*0fca6ea1SDimitry Andric CallerTarget == CUDAFunctionTarget::Device)) 2530b57cec5SDimitry Andric return CFP_Never; 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric // (b) Calling HostDevice is OK for everyone. 256*0fca6ea1SDimitry Andric if (CalleeTarget == CUDAFunctionTarget::HostDevice) 2570b57cec5SDimitry Andric return CFP_HostDevice; 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric // (c) Best case scenarios 2600b57cec5SDimitry Andric if (CalleeTarget == CallerTarget || 261*0fca6ea1SDimitry Andric (CallerTarget == CUDAFunctionTarget::Host && 262*0fca6ea1SDimitry Andric CalleeTarget == CUDAFunctionTarget::Global) || 263*0fca6ea1SDimitry Andric (CallerTarget == CUDAFunctionTarget::Global && 264*0fca6ea1SDimitry Andric CalleeTarget == CUDAFunctionTarget::Device)) 2650b57cec5SDimitry Andric return CFP_Native; 2660b57cec5SDimitry Andric 2675f757f3fSDimitry Andric // HipStdPar mode is special, in that assessing whether a device side call to 2685f757f3fSDimitry Andric // a host target is deferred to a subsequent pass, and cannot unambiguously be 2695f757f3fSDimitry Andric // adjudicated in the AST, hence we optimistically allow them to pass here. 2705f757f3fSDimitry Andric if (getLangOpts().HIPStdPar && 271*0fca6ea1SDimitry Andric (CallerTarget == CUDAFunctionTarget::Global || 272*0fca6ea1SDimitry Andric CallerTarget == CUDAFunctionTarget::Device || 273*0fca6ea1SDimitry Andric CallerTarget == CUDAFunctionTarget::HostDevice) && 274*0fca6ea1SDimitry Andric CalleeTarget == CUDAFunctionTarget::Host) 2755f757f3fSDimitry Andric return CFP_HostDevice; 2765f757f3fSDimitry Andric 2770b57cec5SDimitry Andric // (d) HostDevice behavior depends on compilation mode. 278*0fca6ea1SDimitry Andric if (CallerTarget == CUDAFunctionTarget::HostDevice) { 2790b57cec5SDimitry Andric // It's OK to call a compilation-mode matching function from an HD one. 280*0fca6ea1SDimitry Andric if ((getLangOpts().CUDAIsDevice && 281*0fca6ea1SDimitry Andric CalleeTarget == CUDAFunctionTarget::Device) || 2820b57cec5SDimitry Andric (!getLangOpts().CUDAIsDevice && 283*0fca6ea1SDimitry Andric (CalleeTarget == CUDAFunctionTarget::Host || 284*0fca6ea1SDimitry Andric CalleeTarget == CUDAFunctionTarget::Global))) 2850b57cec5SDimitry Andric return CFP_SameSide; 2860b57cec5SDimitry Andric 2870b57cec5SDimitry Andric // Calls from HD to non-mode-matching functions (i.e., to host functions 2880b57cec5SDimitry Andric // when compiling in device mode or to device functions when compiling in 2890b57cec5SDimitry Andric // host mode) are allowed at the sema level, but eventually rejected if 2900b57cec5SDimitry Andric // they're ever codegened. TODO: Reject said calls earlier. 2910b57cec5SDimitry Andric return CFP_WrongSide; 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric // (e) Calling across device/host boundary is not something you should do. 295*0fca6ea1SDimitry Andric if ((CallerTarget == CUDAFunctionTarget::Host && 296*0fca6ea1SDimitry Andric CalleeTarget == CUDAFunctionTarget::Device) || 297*0fca6ea1SDimitry Andric (CallerTarget == CUDAFunctionTarget::Device && 298*0fca6ea1SDimitry Andric CalleeTarget == CUDAFunctionTarget::Host) || 299*0fca6ea1SDimitry Andric (CallerTarget == CUDAFunctionTarget::Global && 300*0fca6ea1SDimitry Andric CalleeTarget == CUDAFunctionTarget::Host)) 3010b57cec5SDimitry Andric return CFP_Never; 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric llvm_unreachable("All cases should've been handled by now."); 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric 3065ffd83dbSDimitry Andric template <typename AttrT> static bool hasImplicitAttr(const FunctionDecl *D) { 3075ffd83dbSDimitry Andric if (!D) 3085ffd83dbSDimitry Andric return false; 3095ffd83dbSDimitry Andric if (auto *A = D->getAttr<AttrT>()) 3105ffd83dbSDimitry Andric return A->isImplicit(); 3115ffd83dbSDimitry Andric return D->isImplicit(); 3125ffd83dbSDimitry Andric } 3135ffd83dbSDimitry Andric 314*0fca6ea1SDimitry Andric bool SemaCUDA::isImplicitHostDeviceFunction(const FunctionDecl *D) { 3155ffd83dbSDimitry Andric bool IsImplicitDevAttr = hasImplicitAttr<CUDADeviceAttr>(D); 3165ffd83dbSDimitry Andric bool IsImplicitHostAttr = hasImplicitAttr<CUDAHostAttr>(D); 3175ffd83dbSDimitry Andric return IsImplicitDevAttr && IsImplicitHostAttr; 3185ffd83dbSDimitry Andric } 3195ffd83dbSDimitry Andric 320*0fca6ea1SDimitry Andric void SemaCUDA::EraseUnwantedMatches( 3210b57cec5SDimitry Andric const FunctionDecl *Caller, 3220b57cec5SDimitry Andric SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>> &Matches) { 3230b57cec5SDimitry Andric if (Matches.size() <= 1) 3240b57cec5SDimitry Andric return; 3250b57cec5SDimitry Andric 3260b57cec5SDimitry Andric using Pair = std::pair<DeclAccessPair, FunctionDecl*>; 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric // Gets the CUDA function preference for a call from Caller to Match. 3290b57cec5SDimitry Andric auto GetCFP = [&](const Pair &Match) { 330*0fca6ea1SDimitry Andric return IdentifyPreference(Caller, Match.second); 3310b57cec5SDimitry Andric }; 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric // Find the best call preference among the functions in Matches. 3340b57cec5SDimitry Andric CUDAFunctionPreference BestCFP = GetCFP(*std::max_element( 3350b57cec5SDimitry Andric Matches.begin(), Matches.end(), 3360b57cec5SDimitry Andric [&](const Pair &M1, const Pair &M2) { return GetCFP(M1) < GetCFP(M2); })); 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric // Erase all functions with lower priority. 3390b57cec5SDimitry Andric llvm::erase_if(Matches, 3400b57cec5SDimitry Andric [&](const Pair &Match) { return GetCFP(Match) < BestCFP; }); 3410b57cec5SDimitry Andric } 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric /// When an implicitly-declared special member has to invoke more than one 3440b57cec5SDimitry Andric /// base/field special member, conflicts may occur in the targets of these 3450b57cec5SDimitry Andric /// members. For example, if one base's member __host__ and another's is 3460b57cec5SDimitry Andric /// __device__, it's a conflict. 3470b57cec5SDimitry Andric /// This function figures out if the given targets \param Target1 and 3480b57cec5SDimitry Andric /// \param Target2 conflict, and if they do not it fills in 3490b57cec5SDimitry Andric /// \param ResolvedTarget with a target that resolves for both calls. 3500b57cec5SDimitry Andric /// \return true if there's a conflict, false otherwise. 3510b57cec5SDimitry Andric static bool 352*0fca6ea1SDimitry Andric resolveCalleeCUDATargetConflict(CUDAFunctionTarget Target1, 353*0fca6ea1SDimitry Andric CUDAFunctionTarget Target2, 354*0fca6ea1SDimitry Andric CUDAFunctionTarget *ResolvedTarget) { 3550b57cec5SDimitry Andric // Only free functions and static member functions may be global. 356*0fca6ea1SDimitry Andric assert(Target1 != CUDAFunctionTarget::Global); 357*0fca6ea1SDimitry Andric assert(Target2 != CUDAFunctionTarget::Global); 3580b57cec5SDimitry Andric 359*0fca6ea1SDimitry Andric if (Target1 == CUDAFunctionTarget::HostDevice) { 3600b57cec5SDimitry Andric *ResolvedTarget = Target2; 361*0fca6ea1SDimitry Andric } else if (Target2 == CUDAFunctionTarget::HostDevice) { 3620b57cec5SDimitry Andric *ResolvedTarget = Target1; 3630b57cec5SDimitry Andric } else if (Target1 != Target2) { 3640b57cec5SDimitry Andric return true; 3650b57cec5SDimitry Andric } else { 3660b57cec5SDimitry Andric *ResolvedTarget = Target1; 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric return false; 3700b57cec5SDimitry Andric } 3710b57cec5SDimitry Andric 372*0fca6ea1SDimitry Andric bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, 373*0fca6ea1SDimitry Andric CXXSpecialMemberKind CSM, 3740b57cec5SDimitry Andric CXXMethodDecl *MemberDecl, 3750b57cec5SDimitry Andric bool ConstRHS, 3760b57cec5SDimitry Andric bool Diagnose) { 377a7dea167SDimitry Andric // If the defaulted special member is defined lexically outside of its 378a7dea167SDimitry Andric // owning class, or the special member already has explicit device or host 379a7dea167SDimitry Andric // attributes, do not infer. 380a7dea167SDimitry Andric bool InClass = MemberDecl->getLexicalParent() == MemberDecl->getParent(); 381a7dea167SDimitry Andric bool HasH = MemberDecl->hasAttr<CUDAHostAttr>(); 382a7dea167SDimitry Andric bool HasD = MemberDecl->hasAttr<CUDADeviceAttr>(); 383a7dea167SDimitry Andric bool HasExplicitAttr = 384a7dea167SDimitry Andric (HasD && !MemberDecl->getAttr<CUDADeviceAttr>()->isImplicit()) || 385a7dea167SDimitry Andric (HasH && !MemberDecl->getAttr<CUDAHostAttr>()->isImplicit()); 386a7dea167SDimitry Andric if (!InClass || HasExplicitAttr) 387a7dea167SDimitry Andric return false; 388a7dea167SDimitry Andric 389bdd1243dSDimitry Andric std::optional<CUDAFunctionTarget> InferredTarget; 3900b57cec5SDimitry Andric 3910b57cec5SDimitry Andric // We're going to invoke special member lookup; mark that these special 3920b57cec5SDimitry Andric // members are called from this one, and not from its caller. 393*0fca6ea1SDimitry Andric Sema::ContextRAII MethodContext(SemaRef, MemberDecl); 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric // Look for special members in base classes that should be invoked from here. 3960b57cec5SDimitry Andric // Infer the target of this member base on the ones it should call. 3970b57cec5SDimitry Andric // Skip direct and indirect virtual bases for abstract classes. 3980b57cec5SDimitry Andric llvm::SmallVector<const CXXBaseSpecifier *, 16> Bases; 3990b57cec5SDimitry Andric for (const auto &B : ClassDecl->bases()) { 4000b57cec5SDimitry Andric if (!B.isVirtual()) { 4010b57cec5SDimitry Andric Bases.push_back(&B); 4020b57cec5SDimitry Andric } 4030b57cec5SDimitry Andric } 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric if (!ClassDecl->isAbstract()) { 40681ad6265SDimitry Andric llvm::append_range(Bases, llvm::make_pointer_range(ClassDecl->vbases())); 4070b57cec5SDimitry Andric } 4080b57cec5SDimitry Andric 4090b57cec5SDimitry Andric for (const auto *B : Bases) { 4100b57cec5SDimitry Andric const RecordType *BaseType = B->getType()->getAs<RecordType>(); 4110b57cec5SDimitry Andric if (!BaseType) { 4120b57cec5SDimitry Andric continue; 4130b57cec5SDimitry Andric } 4140b57cec5SDimitry Andric 4150b57cec5SDimitry Andric CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); 4160b57cec5SDimitry Andric Sema::SpecialMemberOverloadResult SMOR = 417*0fca6ea1SDimitry Andric SemaRef.LookupSpecialMember(BaseClassDecl, CSM, 4180b57cec5SDimitry Andric /* ConstArg */ ConstRHS, 4190b57cec5SDimitry Andric /* VolatileArg */ false, 4200b57cec5SDimitry Andric /* RValueThis */ false, 4210b57cec5SDimitry Andric /* ConstThis */ false, 4220b57cec5SDimitry Andric /* VolatileThis */ false); 4230b57cec5SDimitry Andric 4240b57cec5SDimitry Andric if (!SMOR.getMethod()) 4250b57cec5SDimitry Andric continue; 4260b57cec5SDimitry Andric 427*0fca6ea1SDimitry Andric CUDAFunctionTarget BaseMethodTarget = IdentifyTarget(SMOR.getMethod()); 42881ad6265SDimitry Andric if (!InferredTarget) { 4290b57cec5SDimitry Andric InferredTarget = BaseMethodTarget; 4300b57cec5SDimitry Andric } else { 4310b57cec5SDimitry Andric bool ResolutionError = resolveCalleeCUDATargetConflict( 432bdd1243dSDimitry Andric *InferredTarget, BaseMethodTarget, &*InferredTarget); 4330b57cec5SDimitry Andric if (ResolutionError) { 4340b57cec5SDimitry Andric if (Diagnose) { 4350b57cec5SDimitry Andric Diag(ClassDecl->getLocation(), 4360b57cec5SDimitry Andric diag::note_implicit_member_target_infer_collision) 437*0fca6ea1SDimitry Andric << (unsigned)CSM << llvm::to_underlying(*InferredTarget) 438*0fca6ea1SDimitry Andric << llvm::to_underlying(BaseMethodTarget); 4390b57cec5SDimitry Andric } 440*0fca6ea1SDimitry Andric MemberDecl->addAttr( 441*0fca6ea1SDimitry Andric CUDAInvalidTargetAttr::CreateImplicit(getASTContext())); 4420b57cec5SDimitry Andric return true; 4430b57cec5SDimitry Andric } 4440b57cec5SDimitry Andric } 4450b57cec5SDimitry Andric } 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric // Same as for bases, but now for special members of fields. 4480b57cec5SDimitry Andric for (const auto *F : ClassDecl->fields()) { 4490b57cec5SDimitry Andric if (F->isInvalidDecl()) { 4500b57cec5SDimitry Andric continue; 4510b57cec5SDimitry Andric } 4520b57cec5SDimitry Andric 4530b57cec5SDimitry Andric const RecordType *FieldType = 454*0fca6ea1SDimitry Andric getASTContext().getBaseElementType(F->getType())->getAs<RecordType>(); 4550b57cec5SDimitry Andric if (!FieldType) { 4560b57cec5SDimitry Andric continue; 4570b57cec5SDimitry Andric } 4580b57cec5SDimitry Andric 4590b57cec5SDimitry Andric CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(FieldType->getDecl()); 4600b57cec5SDimitry Andric Sema::SpecialMemberOverloadResult SMOR = 461*0fca6ea1SDimitry Andric SemaRef.LookupSpecialMember(FieldRecDecl, CSM, 4620b57cec5SDimitry Andric /* ConstArg */ ConstRHS && !F->isMutable(), 4630b57cec5SDimitry Andric /* VolatileArg */ false, 4640b57cec5SDimitry Andric /* RValueThis */ false, 4650b57cec5SDimitry Andric /* ConstThis */ false, 4660b57cec5SDimitry Andric /* VolatileThis */ false); 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric if (!SMOR.getMethod()) 4690b57cec5SDimitry Andric continue; 4700b57cec5SDimitry Andric 471*0fca6ea1SDimitry Andric CUDAFunctionTarget FieldMethodTarget = IdentifyTarget(SMOR.getMethod()); 47281ad6265SDimitry Andric if (!InferredTarget) { 4730b57cec5SDimitry Andric InferredTarget = FieldMethodTarget; 4740b57cec5SDimitry Andric } else { 4750b57cec5SDimitry Andric bool ResolutionError = resolveCalleeCUDATargetConflict( 476bdd1243dSDimitry Andric *InferredTarget, FieldMethodTarget, &*InferredTarget); 4770b57cec5SDimitry Andric if (ResolutionError) { 4780b57cec5SDimitry Andric if (Diagnose) { 4790b57cec5SDimitry Andric Diag(ClassDecl->getLocation(), 4800b57cec5SDimitry Andric diag::note_implicit_member_target_infer_collision) 481*0fca6ea1SDimitry Andric << (unsigned)CSM << llvm::to_underlying(*InferredTarget) 482*0fca6ea1SDimitry Andric << llvm::to_underlying(FieldMethodTarget); 4830b57cec5SDimitry Andric } 484*0fca6ea1SDimitry Andric MemberDecl->addAttr( 485*0fca6ea1SDimitry Andric CUDAInvalidTargetAttr::CreateImplicit(getASTContext())); 4860b57cec5SDimitry Andric return true; 4870b57cec5SDimitry Andric } 4880b57cec5SDimitry Andric } 4890b57cec5SDimitry Andric } 4900b57cec5SDimitry Andric 491a7dea167SDimitry Andric 4920b57cec5SDimitry Andric // If no target was inferred, mark this member as __host__ __device__; 4930b57cec5SDimitry Andric // it's the least restrictive option that can be invoked from any target. 494a7dea167SDimitry Andric bool NeedsH = true, NeedsD = true; 49581ad6265SDimitry Andric if (InferredTarget) { 496*0fca6ea1SDimitry Andric if (*InferredTarget == CUDAFunctionTarget::Device) 497a7dea167SDimitry Andric NeedsH = false; 498*0fca6ea1SDimitry Andric else if (*InferredTarget == CUDAFunctionTarget::Host) 499a7dea167SDimitry Andric NeedsD = false; 5000b57cec5SDimitry Andric } 5010b57cec5SDimitry Andric 502a7dea167SDimitry Andric // We either setting attributes first time, or the inferred ones must match 503a7dea167SDimitry Andric // previously set ones. 504a7dea167SDimitry Andric if (NeedsD && !HasD) 505*0fca6ea1SDimitry Andric MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(getASTContext())); 506a7dea167SDimitry Andric if (NeedsH && !HasH) 507*0fca6ea1SDimitry Andric MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(getASTContext())); 508a7dea167SDimitry Andric 5090b57cec5SDimitry Andric return false; 5100b57cec5SDimitry Andric } 5110b57cec5SDimitry Andric 512*0fca6ea1SDimitry Andric bool SemaCUDA::isEmptyConstructor(SourceLocation Loc, CXXConstructorDecl *CD) { 5130b57cec5SDimitry Andric if (!CD->isDefined() && CD->isTemplateInstantiation()) 514*0fca6ea1SDimitry Andric SemaRef.InstantiateFunctionDefinition(Loc, CD->getFirstDecl()); 5150b57cec5SDimitry Andric 5160b57cec5SDimitry Andric // (E.2.3.1, CUDA 7.5) A constructor for a class type is considered 5170b57cec5SDimitry Andric // empty at a point in the translation unit, if it is either a 5180b57cec5SDimitry Andric // trivial constructor 5190b57cec5SDimitry Andric if (CD->isTrivial()) 5200b57cec5SDimitry Andric return true; 5210b57cec5SDimitry Andric 5220b57cec5SDimitry Andric // ... or it satisfies all of the following conditions: 5230b57cec5SDimitry Andric // The constructor function has been defined. 5240b57cec5SDimitry Andric // The constructor function has no parameters, 5250b57cec5SDimitry Andric // and the function body is an empty compound statement. 5260b57cec5SDimitry Andric if (!(CD->hasTrivialBody() && CD->getNumParams() == 0)) 5270b57cec5SDimitry Andric return false; 5280b57cec5SDimitry Andric 5290b57cec5SDimitry Andric // Its class has no virtual functions and no virtual base classes. 5300b57cec5SDimitry Andric if (CD->getParent()->isDynamicClass()) 5310b57cec5SDimitry Andric return false; 5320b57cec5SDimitry Andric 5335ffd83dbSDimitry Andric // Union ctor does not call ctors of its data members. 5345ffd83dbSDimitry Andric if (CD->getParent()->isUnion()) 5355ffd83dbSDimitry Andric return true; 5365ffd83dbSDimitry Andric 5370b57cec5SDimitry Andric // The only form of initializer allowed is an empty constructor. 5380b57cec5SDimitry Andric // This will recursively check all base classes and member initializers 5390b57cec5SDimitry Andric if (!llvm::all_of(CD->inits(), [&](const CXXCtorInitializer *CI) { 5400b57cec5SDimitry Andric if (const CXXConstructExpr *CE = 5410b57cec5SDimitry Andric dyn_cast<CXXConstructExpr>(CI->getInit())) 542*0fca6ea1SDimitry Andric return isEmptyConstructor(Loc, CE->getConstructor()); 5430b57cec5SDimitry Andric return false; 5440b57cec5SDimitry Andric })) 5450b57cec5SDimitry Andric return false; 5460b57cec5SDimitry Andric 5470b57cec5SDimitry Andric return true; 5480b57cec5SDimitry Andric } 5490b57cec5SDimitry Andric 550*0fca6ea1SDimitry Andric bool SemaCUDA::isEmptyDestructor(SourceLocation Loc, CXXDestructorDecl *DD) { 5510b57cec5SDimitry Andric // No destructor -> no problem. 5520b57cec5SDimitry Andric if (!DD) 5530b57cec5SDimitry Andric return true; 5540b57cec5SDimitry Andric 5550b57cec5SDimitry Andric if (!DD->isDefined() && DD->isTemplateInstantiation()) 556*0fca6ea1SDimitry Andric SemaRef.InstantiateFunctionDefinition(Loc, DD->getFirstDecl()); 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric // (E.2.3.1, CUDA 7.5) A destructor for a class type is considered 5590b57cec5SDimitry Andric // empty at a point in the translation unit, if it is either a 5600b57cec5SDimitry Andric // trivial constructor 5610b57cec5SDimitry Andric if (DD->isTrivial()) 5620b57cec5SDimitry Andric return true; 5630b57cec5SDimitry Andric 5640b57cec5SDimitry Andric // ... or it satisfies all of the following conditions: 5650b57cec5SDimitry Andric // The destructor function has been defined. 5660b57cec5SDimitry Andric // and the function body is an empty compound statement. 5670b57cec5SDimitry Andric if (!DD->hasTrivialBody()) 5680b57cec5SDimitry Andric return false; 5690b57cec5SDimitry Andric 5700b57cec5SDimitry Andric const CXXRecordDecl *ClassDecl = DD->getParent(); 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric // Its class has no virtual functions and no virtual base classes. 5730b57cec5SDimitry Andric if (ClassDecl->isDynamicClass()) 5740b57cec5SDimitry Andric return false; 5750b57cec5SDimitry Andric 5765ffd83dbSDimitry Andric // Union does not have base class and union dtor does not call dtors of its 5775ffd83dbSDimitry Andric // data members. 5785ffd83dbSDimitry Andric if (DD->getParent()->isUnion()) 5795ffd83dbSDimitry Andric return true; 5805ffd83dbSDimitry Andric 5810b57cec5SDimitry Andric // Only empty destructors are allowed. This will recursively check 5820b57cec5SDimitry Andric // destructors for all base classes... 5830b57cec5SDimitry Andric if (!llvm::all_of(ClassDecl->bases(), [&](const CXXBaseSpecifier &BS) { 5840b57cec5SDimitry Andric if (CXXRecordDecl *RD = BS.getType()->getAsCXXRecordDecl()) 585*0fca6ea1SDimitry Andric return isEmptyDestructor(Loc, RD->getDestructor()); 5860b57cec5SDimitry Andric return true; 5870b57cec5SDimitry Andric })) 5880b57cec5SDimitry Andric return false; 5890b57cec5SDimitry Andric 5900b57cec5SDimitry Andric // ... and member fields. 5910b57cec5SDimitry Andric if (!llvm::all_of(ClassDecl->fields(), [&](const FieldDecl *Field) { 5920b57cec5SDimitry Andric if (CXXRecordDecl *RD = Field->getType() 5930b57cec5SDimitry Andric ->getBaseElementTypeUnsafe() 5940b57cec5SDimitry Andric ->getAsCXXRecordDecl()) 595*0fca6ea1SDimitry Andric return isEmptyDestructor(Loc, RD->getDestructor()); 5960b57cec5SDimitry Andric return true; 5970b57cec5SDimitry Andric })) 5980b57cec5SDimitry Andric return false; 5990b57cec5SDimitry Andric 6000b57cec5SDimitry Andric return true; 6010b57cec5SDimitry Andric } 6020b57cec5SDimitry Andric 603fe6060f1SDimitry Andric namespace { 604fe6060f1SDimitry Andric enum CUDAInitializerCheckKind { 605fe6060f1SDimitry Andric CICK_DeviceOrConstant, // Check initializer for device/constant variable 606fe6060f1SDimitry Andric CICK_Shared, // Check initializer for shared variable 607fe6060f1SDimitry Andric }; 608fe6060f1SDimitry Andric 609fe6060f1SDimitry Andric bool IsDependentVar(VarDecl *VD) { 610fe6060f1SDimitry Andric if (VD->getType()->isDependentType()) 611fe6060f1SDimitry Andric return true; 612fe6060f1SDimitry Andric if (const auto *Init = VD->getInit()) 613fe6060f1SDimitry Andric return Init->isValueDependent(); 614fe6060f1SDimitry Andric return false; 615fe6060f1SDimitry Andric } 616fe6060f1SDimitry Andric 617fe6060f1SDimitry Andric // Check whether a variable has an allowed initializer for a CUDA device side 618fe6060f1SDimitry Andric // variable with global storage. \p VD may be a host variable to be checked for 619fe6060f1SDimitry Andric // potential promotion to device side variable. 620fe6060f1SDimitry Andric // 621fe6060f1SDimitry Andric // CUDA/HIP allows only empty constructors as initializers for global 622fe6060f1SDimitry Andric // variables (see E.2.3.1, CUDA 7.5). The same restriction also applies to all 623fe6060f1SDimitry Andric // __shared__ variables whether they are local or not (they all are implicitly 624fe6060f1SDimitry Andric // static in CUDA). One exception is that CUDA allows constant initializers 625fe6060f1SDimitry Andric // for __constant__ and __device__ variables. 626*0fca6ea1SDimitry Andric bool HasAllowedCUDADeviceStaticInitializer(SemaCUDA &S, VarDecl *VD, 627fe6060f1SDimitry Andric CUDAInitializerCheckKind CheckKind) { 628fe6060f1SDimitry Andric assert(!VD->isInvalidDecl() && VD->hasGlobalStorage()); 629fe6060f1SDimitry Andric assert(!IsDependentVar(VD) && "do not check dependent var"); 630fe6060f1SDimitry Andric const Expr *Init = VD->getInit(); 631fe6060f1SDimitry Andric auto IsEmptyInit = [&](const Expr *Init) { 632fe6060f1SDimitry Andric if (!Init) 633fe6060f1SDimitry Andric return true; 634fe6060f1SDimitry Andric if (const auto *CE = dyn_cast<CXXConstructExpr>(Init)) { 635*0fca6ea1SDimitry Andric return S.isEmptyConstructor(VD->getLocation(), CE->getConstructor()); 636fe6060f1SDimitry Andric } 637fe6060f1SDimitry Andric return false; 638fe6060f1SDimitry Andric }; 639fe6060f1SDimitry Andric auto IsConstantInit = [&](const Expr *Init) { 640fe6060f1SDimitry Andric assert(Init); 641*0fca6ea1SDimitry Andric ASTContext::CUDAConstantEvalContextRAII EvalCtx(S.getASTContext(), 6421fd87a68SDimitry Andric /*NoWronSidedVars=*/true); 643*0fca6ea1SDimitry Andric return Init->isConstantInitializer(S.getASTContext(), 644fe6060f1SDimitry Andric VD->getType()->isReferenceType()); 645fe6060f1SDimitry Andric }; 646fe6060f1SDimitry Andric auto HasEmptyDtor = [&](VarDecl *VD) { 647fe6060f1SDimitry Andric if (const auto *RD = VD->getType()->getAsCXXRecordDecl()) 648*0fca6ea1SDimitry Andric return S.isEmptyDestructor(VD->getLocation(), RD->getDestructor()); 649fe6060f1SDimitry Andric return true; 650fe6060f1SDimitry Andric }; 651fe6060f1SDimitry Andric if (CheckKind == CICK_Shared) 652fe6060f1SDimitry Andric return IsEmptyInit(Init) && HasEmptyDtor(VD); 653*0fca6ea1SDimitry Andric return S.getLangOpts().GPUAllowDeviceInit || 654fe6060f1SDimitry Andric ((IsEmptyInit(Init) || IsConstantInit(Init)) && HasEmptyDtor(VD)); 655fe6060f1SDimitry Andric } 656fe6060f1SDimitry Andric } // namespace 657fe6060f1SDimitry Andric 658*0fca6ea1SDimitry Andric void SemaCUDA::checkAllowedInitializer(VarDecl *VD) { 6595f757f3fSDimitry Andric // Return early if VD is inside a non-instantiated template function since 6605f757f3fSDimitry Andric // the implicit constructor is not defined yet. 6615f757f3fSDimitry Andric if (const FunctionDecl *FD = 6625f757f3fSDimitry Andric dyn_cast_or_null<FunctionDecl>(VD->getDeclContext())) 6635f757f3fSDimitry Andric if (FD->isDependentContext()) 6645f757f3fSDimitry Andric return; 6655f757f3fSDimitry Andric 666fe6060f1SDimitry Andric // Do not check dependent variables since the ctor/dtor/initializer are not 667fe6060f1SDimitry Andric // determined. Do it after instantiation. 668fe6060f1SDimitry Andric if (VD->isInvalidDecl() || !VD->hasInit() || !VD->hasGlobalStorage() || 669fe6060f1SDimitry Andric IsDependentVar(VD)) 6700b57cec5SDimitry Andric return; 6710b57cec5SDimitry Andric const Expr *Init = VD->getInit(); 672fe6060f1SDimitry Andric bool IsSharedVar = VD->hasAttr<CUDASharedAttr>(); 673fe6060f1SDimitry Andric bool IsDeviceOrConstantVar = 674fe6060f1SDimitry Andric !IsSharedVar && 675fe6060f1SDimitry Andric (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>()); 676fe6060f1SDimitry Andric if (IsDeviceOrConstantVar || IsSharedVar) { 677fe6060f1SDimitry Andric if (HasAllowedCUDADeviceStaticInitializer( 678fe6060f1SDimitry Andric *this, VD, IsSharedVar ? CICK_Shared : CICK_DeviceOrConstant)) 679480093f4SDimitry Andric return; 680fe6060f1SDimitry Andric Diag(VD->getLocation(), 681fe6060f1SDimitry Andric IsSharedVar ? diag::err_shared_var_init : diag::err_dynamic_var_init) 6820b57cec5SDimitry Andric << Init->getSourceRange(); 6830b57cec5SDimitry Andric VD->setInvalidDecl(); 6840b57cec5SDimitry Andric } else { 6850b57cec5SDimitry Andric // This is a host-side global variable. Check that the initializer is 6860b57cec5SDimitry Andric // callable from the host side. 6870b57cec5SDimitry Andric const FunctionDecl *InitFn = nullptr; 6880b57cec5SDimitry Andric if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) { 6890b57cec5SDimitry Andric InitFn = CE->getConstructor(); 6900b57cec5SDimitry Andric } else if (const CallExpr *CE = dyn_cast<CallExpr>(Init)) { 6910b57cec5SDimitry Andric InitFn = CE->getDirectCallee(); 6920b57cec5SDimitry Andric } 6930b57cec5SDimitry Andric if (InitFn) { 694*0fca6ea1SDimitry Andric CUDAFunctionTarget InitFnTarget = IdentifyTarget(InitFn); 695*0fca6ea1SDimitry Andric if (InitFnTarget != CUDAFunctionTarget::Host && 696*0fca6ea1SDimitry Andric InitFnTarget != CUDAFunctionTarget::HostDevice) { 6970b57cec5SDimitry Andric Diag(VD->getLocation(), diag::err_ref_bad_target_global_initializer) 698*0fca6ea1SDimitry Andric << llvm::to_underlying(InitFnTarget) << InitFn; 6990b57cec5SDimitry Andric Diag(InitFn->getLocation(), diag::note_previous_decl) << InitFn; 7000b57cec5SDimitry Andric VD->setInvalidDecl(); 7010b57cec5SDimitry Andric } 7020b57cec5SDimitry Andric } 7030b57cec5SDimitry Andric } 7040b57cec5SDimitry Andric } 7050b57cec5SDimitry Andric 706*0fca6ea1SDimitry Andric void SemaCUDA::RecordImplicitHostDeviceFuncUsedByDevice( 7075f757f3fSDimitry Andric const FunctionDecl *Callee) { 708*0fca6ea1SDimitry Andric FunctionDecl *Caller = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true); 7095f757f3fSDimitry Andric if (!Caller) 7105f757f3fSDimitry Andric return; 7115f757f3fSDimitry Andric 712*0fca6ea1SDimitry Andric if (!isImplicitHostDeviceFunction(Callee)) 7135f757f3fSDimitry Andric return; 7145f757f3fSDimitry Andric 715*0fca6ea1SDimitry Andric CUDAFunctionTarget CallerTarget = IdentifyTarget(Caller); 7165f757f3fSDimitry Andric 7175f757f3fSDimitry Andric // Record whether an implicit host device function is used on device side. 718*0fca6ea1SDimitry Andric if (CallerTarget != CUDAFunctionTarget::Device && 719*0fca6ea1SDimitry Andric CallerTarget != CUDAFunctionTarget::Global && 720*0fca6ea1SDimitry Andric (CallerTarget != CUDAFunctionTarget::HostDevice || 721*0fca6ea1SDimitry Andric (isImplicitHostDeviceFunction(Caller) && 7225f757f3fSDimitry Andric !getASTContext().CUDAImplicitHostDeviceFunUsedByDevice.count(Caller)))) 7235f757f3fSDimitry Andric return; 7245f757f3fSDimitry Andric 7255f757f3fSDimitry Andric getASTContext().CUDAImplicitHostDeviceFunUsedByDevice.insert(Callee); 7265f757f3fSDimitry Andric } 7275f757f3fSDimitry Andric 7280b57cec5SDimitry Andric // With -fcuda-host-device-constexpr, an unattributed constexpr function is 7290b57cec5SDimitry Andric // treated as implicitly __host__ __device__, unless: 7300b57cec5SDimitry Andric // * it is a variadic function (device-side variadic functions are not 7310b57cec5SDimitry Andric // allowed), or 7320b57cec5SDimitry Andric // * a __device__ function with this signature was already declared, in which 7330b57cec5SDimitry Andric // case in which case we output an error, unless the __device__ decl is in a 7340b57cec5SDimitry Andric // system header, in which case we leave the constexpr function unattributed. 7350b57cec5SDimitry Andric // 7360b57cec5SDimitry Andric // In addition, all function decls are treated as __host__ __device__ when 737*0fca6ea1SDimitry Andric // ForceHostDeviceDepth > 0 (corresponding to code within a 7380b57cec5SDimitry Andric // #pragma clang force_cuda_host_device_begin/end 7390b57cec5SDimitry Andric // pair). 740*0fca6ea1SDimitry Andric void SemaCUDA::maybeAddHostDeviceAttrs(FunctionDecl *NewD, 7410b57cec5SDimitry Andric const LookupResult &Previous) { 7420b57cec5SDimitry Andric assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); 7430b57cec5SDimitry Andric 744*0fca6ea1SDimitry Andric if (ForceHostDeviceDepth > 0) { 7450b57cec5SDimitry Andric if (!NewD->hasAttr<CUDAHostAttr>()) 746*0fca6ea1SDimitry Andric NewD->addAttr(CUDAHostAttr::CreateImplicit(getASTContext())); 7470b57cec5SDimitry Andric if (!NewD->hasAttr<CUDADeviceAttr>()) 748*0fca6ea1SDimitry Andric NewD->addAttr(CUDADeviceAttr::CreateImplicit(getASTContext())); 7490b57cec5SDimitry Andric return; 7500b57cec5SDimitry Andric } 7510b57cec5SDimitry Andric 7525f757f3fSDimitry Andric // If a template function has no host/device/global attributes, 7535f757f3fSDimitry Andric // make it implicitly host device function. 7545f757f3fSDimitry Andric if (getLangOpts().OffloadImplicitHostDeviceTemplates && 7555f757f3fSDimitry Andric !NewD->hasAttr<CUDAHostAttr>() && !NewD->hasAttr<CUDADeviceAttr>() && 7565f757f3fSDimitry Andric !NewD->hasAttr<CUDAGlobalAttr>() && 7575f757f3fSDimitry Andric (NewD->getDescribedFunctionTemplate() || 7585f757f3fSDimitry Andric NewD->isFunctionTemplateSpecialization())) { 759*0fca6ea1SDimitry Andric NewD->addAttr(CUDAHostAttr::CreateImplicit(getASTContext())); 760*0fca6ea1SDimitry Andric NewD->addAttr(CUDADeviceAttr::CreateImplicit(getASTContext())); 7615f757f3fSDimitry Andric return; 7625f757f3fSDimitry Andric } 7635f757f3fSDimitry Andric 7640b57cec5SDimitry Andric if (!getLangOpts().CUDAHostDeviceConstexpr || !NewD->isConstexpr() || 7650b57cec5SDimitry Andric NewD->isVariadic() || NewD->hasAttr<CUDAHostAttr>() || 7660b57cec5SDimitry Andric NewD->hasAttr<CUDADeviceAttr>() || NewD->hasAttr<CUDAGlobalAttr>()) 7670b57cec5SDimitry Andric return; 7680b57cec5SDimitry Andric 7690b57cec5SDimitry Andric // Is D a __device__ function with the same signature as NewD, ignoring CUDA 7700b57cec5SDimitry Andric // attributes? 7710b57cec5SDimitry Andric auto IsMatchingDeviceFn = [&](NamedDecl *D) { 7720b57cec5SDimitry Andric if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(D)) 7730b57cec5SDimitry Andric D = Using->getTargetDecl(); 7740b57cec5SDimitry Andric FunctionDecl *OldD = D->getAsFunction(); 7750b57cec5SDimitry Andric return OldD && OldD->hasAttr<CUDADeviceAttr>() && 7760b57cec5SDimitry Andric !OldD->hasAttr<CUDAHostAttr>() && 777*0fca6ea1SDimitry Andric !SemaRef.IsOverload(NewD, OldD, 778*0fca6ea1SDimitry Andric /* UseMemberUsingDeclRules = */ false, 7790b57cec5SDimitry Andric /* ConsiderCudaAttrs = */ false); 7800b57cec5SDimitry Andric }; 7810b57cec5SDimitry Andric auto It = llvm::find_if(Previous, IsMatchingDeviceFn); 7820b57cec5SDimitry Andric if (It != Previous.end()) { 7830b57cec5SDimitry Andric // We found a __device__ function with the same name and signature as NewD 7840b57cec5SDimitry Andric // (ignoring CUDA attrs). This is an error unless that function is defined 7850b57cec5SDimitry Andric // in a system header, in which case we simply return without making NewD 7860b57cec5SDimitry Andric // host+device. 7870b57cec5SDimitry Andric NamedDecl *Match = *It; 788*0fca6ea1SDimitry Andric if (!SemaRef.getSourceManager().isInSystemHeader(Match->getLocation())) { 7890b57cec5SDimitry Andric Diag(NewD->getLocation(), 7900b57cec5SDimitry Andric diag::err_cuda_unattributed_constexpr_cannot_overload_device) 7910b57cec5SDimitry Andric << NewD; 7920b57cec5SDimitry Andric Diag(Match->getLocation(), 7930b57cec5SDimitry Andric diag::note_cuda_conflicting_device_function_declared_here); 7940b57cec5SDimitry Andric } 7950b57cec5SDimitry Andric return; 7960b57cec5SDimitry Andric } 7970b57cec5SDimitry Andric 798*0fca6ea1SDimitry Andric NewD->addAttr(CUDAHostAttr::CreateImplicit(getASTContext())); 799*0fca6ea1SDimitry Andric NewD->addAttr(CUDADeviceAttr::CreateImplicit(getASTContext())); 8000b57cec5SDimitry Andric } 8010b57cec5SDimitry Andric 802fe6060f1SDimitry Andric // TODO: `__constant__` memory may be a limited resource for certain targets. 803fe6060f1SDimitry Andric // A safeguard may be needed at the end of compilation pipeline if 804fe6060f1SDimitry Andric // `__constant__` memory usage goes beyond limit. 805*0fca6ea1SDimitry Andric void SemaCUDA::MaybeAddConstantAttr(VarDecl *VD) { 806fe6060f1SDimitry Andric // Do not promote dependent variables since the cotr/dtor/initializer are 807fe6060f1SDimitry Andric // not determined. Do it after instantiation. 808fe6060f1SDimitry Andric if (getLangOpts().CUDAIsDevice && !VD->hasAttr<CUDAConstantAttr>() && 809fcaf7f86SDimitry Andric !VD->hasAttr<CUDASharedAttr>() && 810fe6060f1SDimitry Andric (VD->isFileVarDecl() || VD->isStaticDataMember()) && 811fe6060f1SDimitry Andric !IsDependentVar(VD) && 81281ad6265SDimitry Andric ((VD->isConstexpr() || VD->getType().isConstQualified()) && 81381ad6265SDimitry Andric HasAllowedCUDADeviceStaticInitializer(*this, VD, 81481ad6265SDimitry Andric CICK_DeviceOrConstant))) { 8155ffd83dbSDimitry Andric VD->addAttr(CUDAConstantAttr::CreateImplicit(getASTContext())); 8165ffd83dbSDimitry Andric } 8175ffd83dbSDimitry Andric } 8185ffd83dbSDimitry Andric 819*0fca6ea1SDimitry Andric SemaBase::SemaDiagnosticBuilder SemaCUDA::DiagIfDeviceCode(SourceLocation Loc, 8200b57cec5SDimitry Andric unsigned DiagID) { 8210b57cec5SDimitry Andric assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); 822*0fca6ea1SDimitry Andric FunctionDecl *CurFunContext = 823*0fca6ea1SDimitry Andric SemaRef.getCurFunctionDecl(/*AllowLambda=*/true); 824e8d8bef9SDimitry Andric SemaDiagnosticBuilder::Kind DiagKind = [&] { 82581ad6265SDimitry Andric if (!CurFunContext) 826e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Nop; 827*0fca6ea1SDimitry Andric switch (CurrentTarget()) { 828*0fca6ea1SDimitry Andric case CUDAFunctionTarget::Global: 829*0fca6ea1SDimitry Andric case CUDAFunctionTarget::Device: 830e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Immediate; 831*0fca6ea1SDimitry Andric case CUDAFunctionTarget::HostDevice: 8320b57cec5SDimitry Andric // An HD function counts as host code if we're compiling for host, and 8330b57cec5SDimitry Andric // device code if we're compiling for device. Defer any errors in device 8340b57cec5SDimitry Andric // mode until the function is known-emitted. 835e8d8bef9SDimitry Andric if (!getLangOpts().CUDAIsDevice) 836e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Nop; 837*0fca6ea1SDimitry Andric if (SemaRef.IsLastErrorImmediate && 838*0fca6ea1SDimitry Andric getDiagnostics().getDiagnosticIDs()->isBuiltinNote(DiagID)) 839e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Immediate; 840*0fca6ea1SDimitry Andric return (SemaRef.getEmissionStatus(CurFunContext) == 841*0fca6ea1SDimitry Andric Sema::FunctionEmissionStatus::Emitted) 842e8d8bef9SDimitry Andric ? SemaDiagnosticBuilder::K_ImmediateWithCallStack 843e8d8bef9SDimitry Andric : SemaDiagnosticBuilder::K_Deferred; 8440b57cec5SDimitry Andric default: 845e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Nop; 8460b57cec5SDimitry Andric } 8470b57cec5SDimitry Andric }(); 848*0fca6ea1SDimitry Andric return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, CurFunContext, SemaRef); 8490b57cec5SDimitry Andric } 8500b57cec5SDimitry Andric 851*0fca6ea1SDimitry Andric Sema::SemaDiagnosticBuilder SemaCUDA::DiagIfHostCode(SourceLocation Loc, 8520b57cec5SDimitry Andric unsigned DiagID) { 8530b57cec5SDimitry Andric assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); 854*0fca6ea1SDimitry Andric FunctionDecl *CurFunContext = 855*0fca6ea1SDimitry Andric SemaRef.getCurFunctionDecl(/*AllowLambda=*/true); 856e8d8bef9SDimitry Andric SemaDiagnosticBuilder::Kind DiagKind = [&] { 85781ad6265SDimitry Andric if (!CurFunContext) 858e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Nop; 859*0fca6ea1SDimitry Andric switch (CurrentTarget()) { 860*0fca6ea1SDimitry Andric case CUDAFunctionTarget::Host: 861e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Immediate; 862*0fca6ea1SDimitry Andric case CUDAFunctionTarget::HostDevice: 8630b57cec5SDimitry Andric // An HD function counts as host code if we're compiling for host, and 8640b57cec5SDimitry Andric // device code if we're compiling for device. Defer any errors in device 8650b57cec5SDimitry Andric // mode until the function is known-emitted. 8660b57cec5SDimitry Andric if (getLangOpts().CUDAIsDevice) 867e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Nop; 868*0fca6ea1SDimitry Andric if (SemaRef.IsLastErrorImmediate && 869*0fca6ea1SDimitry Andric getDiagnostics().getDiagnosticIDs()->isBuiltinNote(DiagID)) 870e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Immediate; 871*0fca6ea1SDimitry Andric return (SemaRef.getEmissionStatus(CurFunContext) == 872*0fca6ea1SDimitry Andric Sema::FunctionEmissionStatus::Emitted) 873e8d8bef9SDimitry Andric ? SemaDiagnosticBuilder::K_ImmediateWithCallStack 874e8d8bef9SDimitry Andric : SemaDiagnosticBuilder::K_Deferred; 8750b57cec5SDimitry Andric default: 876e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Nop; 8770b57cec5SDimitry Andric } 8780b57cec5SDimitry Andric }(); 879*0fca6ea1SDimitry Andric return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, CurFunContext, SemaRef); 8800b57cec5SDimitry Andric } 8810b57cec5SDimitry Andric 882*0fca6ea1SDimitry Andric bool SemaCUDA::CheckCall(SourceLocation Loc, FunctionDecl *Callee) { 8830b57cec5SDimitry Andric assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); 8840b57cec5SDimitry Andric assert(Callee && "Callee may not be null."); 8850b57cec5SDimitry Andric 886*0fca6ea1SDimitry Andric const auto &ExprEvalCtx = SemaRef.currentEvaluationContext(); 8870b57cec5SDimitry Andric if (ExprEvalCtx.isUnevaluated() || ExprEvalCtx.isConstantEvaluated()) 8880b57cec5SDimitry Andric return true; 8890b57cec5SDimitry Andric 8900b57cec5SDimitry Andric // FIXME: Is bailing out early correct here? Should we instead assume that 8910b57cec5SDimitry Andric // the caller is a global initializer? 892*0fca6ea1SDimitry Andric FunctionDecl *Caller = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true); 8930b57cec5SDimitry Andric if (!Caller) 8940b57cec5SDimitry Andric return true; 8950b57cec5SDimitry Andric 8960b57cec5SDimitry Andric // If the caller is known-emitted, mark the callee as known-emitted. 8970b57cec5SDimitry Andric // Otherwise, mark the call in our call graph so we can traverse it later. 898*0fca6ea1SDimitry Andric bool CallerKnownEmitted = SemaRef.getEmissionStatus(Caller) == 899*0fca6ea1SDimitry Andric Sema::FunctionEmissionStatus::Emitted; 900e8d8bef9SDimitry Andric SemaDiagnosticBuilder::Kind DiagKind = [this, Caller, Callee, 9010b57cec5SDimitry Andric CallerKnownEmitted] { 902*0fca6ea1SDimitry Andric switch (IdentifyPreference(Caller, Callee)) { 9030b57cec5SDimitry Andric case CFP_Never: 9040b57cec5SDimitry Andric case CFP_WrongSide: 905e8d8bef9SDimitry Andric assert(Caller && "Never/wrongSide calls require a non-null caller"); 9060b57cec5SDimitry Andric // If we know the caller will be emitted, we know this wrong-side call 9070b57cec5SDimitry Andric // will be emitted, so it's an immediate error. Otherwise, defer the 9080b57cec5SDimitry Andric // error until we know the caller is emitted. 909e8d8bef9SDimitry Andric return CallerKnownEmitted 910e8d8bef9SDimitry Andric ? SemaDiagnosticBuilder::K_ImmediateWithCallStack 911e8d8bef9SDimitry Andric : SemaDiagnosticBuilder::K_Deferred; 9120b57cec5SDimitry Andric default: 913e8d8bef9SDimitry Andric return SemaDiagnosticBuilder::K_Nop; 9140b57cec5SDimitry Andric } 9150b57cec5SDimitry Andric }(); 9160b57cec5SDimitry Andric 91781ad6265SDimitry Andric if (DiagKind == SemaDiagnosticBuilder::K_Nop) { 91881ad6265SDimitry Andric // For -fgpu-rdc, keep track of external kernels used by host functions. 919*0fca6ea1SDimitry Andric if (getLangOpts().CUDAIsDevice && getLangOpts().GPURelocatableDeviceCode && 920*0fca6ea1SDimitry Andric Callee->hasAttr<CUDAGlobalAttr>() && !Callee->isDefined() && 921*0fca6ea1SDimitry Andric (!Caller || (!Caller->getDescribedFunctionTemplate() && 922*0fca6ea1SDimitry Andric getASTContext().GetGVALinkageForFunction(Caller) == 923*0fca6ea1SDimitry Andric GVA_StrongExternal))) 92481ad6265SDimitry Andric getASTContext().CUDAExternalDeviceDeclODRUsedByHost.insert(Callee); 9250b57cec5SDimitry Andric return true; 92681ad6265SDimitry Andric } 9270b57cec5SDimitry Andric 9280b57cec5SDimitry Andric // Avoid emitting this error twice for the same location. Using a hashtable 9290b57cec5SDimitry Andric // like this is unfortunate, but because we must continue parsing as normal 9300b57cec5SDimitry Andric // after encountering a deferred error, it's otherwise very tricky for us to 9310b57cec5SDimitry Andric // ensure that we only emit this deferred error once. 9320b57cec5SDimitry Andric if (!LocsWithCUDACallDiags.insert({Caller, Loc}).second) 9330b57cec5SDimitry Andric return true; 9340b57cec5SDimitry Andric 935*0fca6ea1SDimitry Andric SemaDiagnosticBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller, 936*0fca6ea1SDimitry Andric SemaRef) 937*0fca6ea1SDimitry Andric << llvm::to_underlying(IdentifyTarget(Callee)) << /*function*/ 0 << Callee 938*0fca6ea1SDimitry Andric << llvm::to_underlying(IdentifyTarget(Caller)); 939e8d8bef9SDimitry Andric if (!Callee->getBuiltinID()) 940e8d8bef9SDimitry Andric SemaDiagnosticBuilder(DiagKind, Callee->getLocation(), 941*0fca6ea1SDimitry Andric diag::note_previous_decl, Caller, SemaRef) 9420b57cec5SDimitry Andric << Callee; 943e8d8bef9SDimitry Andric return DiagKind != SemaDiagnosticBuilder::K_Immediate && 944e8d8bef9SDimitry Andric DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack; 9450b57cec5SDimitry Andric } 9460b57cec5SDimitry Andric 9475ffd83dbSDimitry Andric // Check the wrong-sided reference capture of lambda for CUDA/HIP. 9485ffd83dbSDimitry Andric // A lambda function may capture a stack variable by reference when it is 9495ffd83dbSDimitry Andric // defined and uses the capture by reference when the lambda is called. When 9505ffd83dbSDimitry Andric // the capture and use happen on different sides, the capture is invalid and 9515ffd83dbSDimitry Andric // should be diagnosed. 952*0fca6ea1SDimitry Andric void SemaCUDA::CheckLambdaCapture(CXXMethodDecl *Callee, 9535ffd83dbSDimitry Andric const sema::Capture &Capture) { 9545ffd83dbSDimitry Andric // In host compilation we only need to check lambda functions emitted on host 9555ffd83dbSDimitry Andric // side. In such lambda functions, a reference capture is invalid only 9565ffd83dbSDimitry Andric // if the lambda structure is populated by a device function or kernel then 9575ffd83dbSDimitry Andric // is passed to and called by a host function. However that is impossible, 9585ffd83dbSDimitry Andric // since a device function or kernel can only call a device function, also a 9595ffd83dbSDimitry Andric // kernel cannot pass a lambda back to a host function since we cannot 9605ffd83dbSDimitry Andric // define a kernel argument type which can hold the lambda before the lambda 9615ffd83dbSDimitry Andric // itself is defined. 962*0fca6ea1SDimitry Andric if (!getLangOpts().CUDAIsDevice) 9635ffd83dbSDimitry Andric return; 9645ffd83dbSDimitry Andric 9655ffd83dbSDimitry Andric // File-scope lambda can only do init captures for global variables, which 9665ffd83dbSDimitry Andric // results in passing by value for these global variables. 967*0fca6ea1SDimitry Andric FunctionDecl *Caller = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true); 9685ffd83dbSDimitry Andric if (!Caller) 9695ffd83dbSDimitry Andric return; 9705ffd83dbSDimitry Andric 9715ffd83dbSDimitry Andric // In device compilation, we only need to check lambda functions which are 9725ffd83dbSDimitry Andric // emitted on device side. For such lambdas, a reference capture is invalid 9735ffd83dbSDimitry Andric // only if the lambda structure is populated by a host function then passed 9745ffd83dbSDimitry Andric // to and called in a device function or kernel. 9755ffd83dbSDimitry Andric bool CalleeIsDevice = Callee->hasAttr<CUDADeviceAttr>(); 9765ffd83dbSDimitry Andric bool CallerIsHost = 9775ffd83dbSDimitry Andric !Caller->hasAttr<CUDAGlobalAttr>() && !Caller->hasAttr<CUDADeviceAttr>(); 9785ffd83dbSDimitry Andric bool ShouldCheck = CalleeIsDevice && CallerIsHost; 9795ffd83dbSDimitry Andric if (!ShouldCheck || !Capture.isReferenceCapture()) 9805ffd83dbSDimitry Andric return; 981e8d8bef9SDimitry Andric auto DiagKind = SemaDiagnosticBuilder::K_Deferred; 9825f757f3fSDimitry Andric if (Capture.isVariableCapture() && !getLangOpts().HIPStdPar) { 983e8d8bef9SDimitry Andric SemaDiagnosticBuilder(DiagKind, Capture.getLocation(), 984*0fca6ea1SDimitry Andric diag::err_capture_bad_target, Callee, SemaRef) 9855ffd83dbSDimitry Andric << Capture.getVariable(); 9865ffd83dbSDimitry Andric } else if (Capture.isThisCapture()) { 987349cc55cSDimitry Andric // Capture of this pointer is allowed since this pointer may be pointing to 988349cc55cSDimitry Andric // managed memory which is accessible on both device and host sides. It only 989349cc55cSDimitry Andric // results in invalid memory access if this pointer points to memory not 990349cc55cSDimitry Andric // accessible on device side. 991e8d8bef9SDimitry Andric SemaDiagnosticBuilder(DiagKind, Capture.getLocation(), 992349cc55cSDimitry Andric diag::warn_maybe_capture_bad_target_this_ptr, Callee, 993*0fca6ea1SDimitry Andric SemaRef); 9945ffd83dbSDimitry Andric } 9955ffd83dbSDimitry Andric } 9965ffd83dbSDimitry Andric 997*0fca6ea1SDimitry Andric void SemaCUDA::SetLambdaAttrs(CXXMethodDecl *Method) { 9980b57cec5SDimitry Andric assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); 9990b57cec5SDimitry Andric if (Method->hasAttr<CUDAHostAttr>() || Method->hasAttr<CUDADeviceAttr>()) 10000b57cec5SDimitry Andric return; 1001*0fca6ea1SDimitry Andric Method->addAttr(CUDADeviceAttr::CreateImplicit(getASTContext())); 1002*0fca6ea1SDimitry Andric Method->addAttr(CUDAHostAttr::CreateImplicit(getASTContext())); 10030b57cec5SDimitry Andric } 10040b57cec5SDimitry Andric 1005*0fca6ea1SDimitry Andric void SemaCUDA::checkTargetOverload(FunctionDecl *NewFD, 10060b57cec5SDimitry Andric const LookupResult &Previous) { 10070b57cec5SDimitry Andric assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); 1008*0fca6ea1SDimitry Andric CUDAFunctionTarget NewTarget = IdentifyTarget(NewFD); 10090b57cec5SDimitry Andric for (NamedDecl *OldND : Previous) { 10100b57cec5SDimitry Andric FunctionDecl *OldFD = OldND->getAsFunction(); 10110b57cec5SDimitry Andric if (!OldFD) 10120b57cec5SDimitry Andric continue; 10130b57cec5SDimitry Andric 1014*0fca6ea1SDimitry Andric CUDAFunctionTarget OldTarget = IdentifyTarget(OldFD); 10150b57cec5SDimitry Andric // Don't allow HD and global functions to overload other functions with the 10160b57cec5SDimitry Andric // same signature. We allow overloading based on CUDA attributes so that 10170b57cec5SDimitry Andric // functions can have different implementations on the host and device, but 10180b57cec5SDimitry Andric // HD/global functions "exist" in some sense on both the host and device, so 10190b57cec5SDimitry Andric // should have the same implementation on both sides. 10200b57cec5SDimitry Andric if (NewTarget != OldTarget && 1021*0fca6ea1SDimitry Andric !SemaRef.IsOverload(NewFD, OldFD, /* UseMemberUsingDeclRules = */ false, 10220b57cec5SDimitry Andric /* ConsiderCudaAttrs = */ false)) { 1023*0fca6ea1SDimitry Andric if ((NewTarget == CUDAFunctionTarget::HostDevice && 1024*0fca6ea1SDimitry Andric !(getLangOpts().OffloadImplicitHostDeviceTemplates && 1025*0fca6ea1SDimitry Andric isImplicitHostDeviceFunction(NewFD) && 1026*0fca6ea1SDimitry Andric OldTarget == CUDAFunctionTarget::Device)) || 1027*0fca6ea1SDimitry Andric (OldTarget == CUDAFunctionTarget::HostDevice && 1028*0fca6ea1SDimitry Andric !(getLangOpts().OffloadImplicitHostDeviceTemplates && 1029*0fca6ea1SDimitry Andric isImplicitHostDeviceFunction(OldFD) && 1030*0fca6ea1SDimitry Andric NewTarget == CUDAFunctionTarget::Device)) || 1031*0fca6ea1SDimitry Andric (NewTarget == CUDAFunctionTarget::Global) || 1032*0fca6ea1SDimitry Andric (OldTarget == CUDAFunctionTarget::Global)) { 10330b57cec5SDimitry Andric Diag(NewFD->getLocation(), diag::err_cuda_ovl_target) 1034*0fca6ea1SDimitry Andric << llvm::to_underlying(NewTarget) << NewFD->getDeclName() 1035*0fca6ea1SDimitry Andric << llvm::to_underlying(OldTarget) << OldFD; 10360b57cec5SDimitry Andric Diag(OldFD->getLocation(), diag::note_previous_declaration); 10370b57cec5SDimitry Andric NewFD->setInvalidDecl(); 10380b57cec5SDimitry Andric break; 10390b57cec5SDimitry Andric } 1040*0fca6ea1SDimitry Andric if ((NewTarget == CUDAFunctionTarget::Host && 1041*0fca6ea1SDimitry Andric OldTarget == CUDAFunctionTarget::Device) || 1042*0fca6ea1SDimitry Andric (NewTarget == CUDAFunctionTarget::Device && 1043*0fca6ea1SDimitry Andric OldTarget == CUDAFunctionTarget::Host)) { 1044*0fca6ea1SDimitry Andric Diag(NewFD->getLocation(), diag::warn_offload_incompatible_redeclare) 1045*0fca6ea1SDimitry Andric << llvm::to_underlying(NewTarget) << llvm::to_underlying(OldTarget); 1046*0fca6ea1SDimitry Andric Diag(OldFD->getLocation(), diag::note_previous_declaration); 1047*0fca6ea1SDimitry Andric } 1048*0fca6ea1SDimitry Andric } 10490b57cec5SDimitry Andric } 10500b57cec5SDimitry Andric } 10510b57cec5SDimitry Andric 10520b57cec5SDimitry Andric template <typename AttrTy> 10530b57cec5SDimitry Andric static void copyAttrIfPresent(Sema &S, FunctionDecl *FD, 10540b57cec5SDimitry Andric const FunctionDecl &TemplateFD) { 10550b57cec5SDimitry Andric if (AttrTy *Attribute = TemplateFD.getAttr<AttrTy>()) { 10560b57cec5SDimitry Andric AttrTy *Clone = Attribute->clone(S.Context); 10570b57cec5SDimitry Andric Clone->setInherited(true); 10580b57cec5SDimitry Andric FD->addAttr(Clone); 10590b57cec5SDimitry Andric } 10600b57cec5SDimitry Andric } 10610b57cec5SDimitry Andric 1062*0fca6ea1SDimitry Andric void SemaCUDA::inheritTargetAttrs(FunctionDecl *FD, 10630b57cec5SDimitry Andric const FunctionTemplateDecl &TD) { 10640b57cec5SDimitry Andric const FunctionDecl &TemplateFD = *TD.getTemplatedDecl(); 1065*0fca6ea1SDimitry Andric copyAttrIfPresent<CUDAGlobalAttr>(SemaRef, FD, TemplateFD); 1066*0fca6ea1SDimitry Andric copyAttrIfPresent<CUDAHostAttr>(SemaRef, FD, TemplateFD); 1067*0fca6ea1SDimitry Andric copyAttrIfPresent<CUDADeviceAttr>(SemaRef, FD, TemplateFD); 10680b57cec5SDimitry Andric } 10690b57cec5SDimitry Andric 1070*0fca6ea1SDimitry Andric std::string SemaCUDA::getConfigureFuncName() const { 10710b57cec5SDimitry Andric if (getLangOpts().HIP) 1072a7dea167SDimitry Andric return getLangOpts().HIPUseNewLaunchAPI ? "__hipPushCallConfiguration" 1073a7dea167SDimitry Andric : "hipConfigureCall"; 10740b57cec5SDimitry Andric 10750b57cec5SDimitry Andric // New CUDA kernel launch sequence. 1076*0fca6ea1SDimitry Andric if (CudaFeatureEnabled(getASTContext().getTargetInfo().getSDKVersion(), 10770b57cec5SDimitry Andric CudaFeature::CUDA_USES_NEW_LAUNCH)) 10780b57cec5SDimitry Andric return "__cudaPushCallConfiguration"; 10790b57cec5SDimitry Andric 10800b57cec5SDimitry Andric // Legacy CUDA kernel configuration call 10810b57cec5SDimitry Andric return "cudaConfigureCall"; 10820b57cec5SDimitry Andric } 1083