xref: /freebsd-src/contrib/llvm-project/clang/lib/Sema/SemaCUDA.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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