xref: /openbsd-src/gnu/llvm/clang/lib/Sema/SemaCUDA.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===--- SemaCUDA.cpp - Semantic Analysis for CUDA constructs -------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick /// \file
9e5dd7070Spatrick /// This file implements semantic analysis for CUDA constructs.
10e5dd7070Spatrick ///
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #include "clang/AST/ASTContext.h"
14e5dd7070Spatrick #include "clang/AST/Decl.h"
15e5dd7070Spatrick #include "clang/AST/ExprCXX.h"
16e5dd7070Spatrick #include "clang/Basic/Cuda.h"
17ec727ea7Spatrick #include "clang/Basic/TargetInfo.h"
18e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
19e5dd7070Spatrick #include "clang/Sema/Lookup.h"
20ec727ea7Spatrick #include "clang/Sema/ScopeInfo.h"
21e5dd7070Spatrick #include "clang/Sema/Sema.h"
22e5dd7070Spatrick #include "clang/Sema/SemaDiagnostic.h"
23e5dd7070Spatrick #include "clang/Sema/SemaInternal.h"
24e5dd7070Spatrick #include "clang/Sema/Template.h"
25e5dd7070Spatrick #include "llvm/ADT/SmallVector.h"
26*12c85518Srobert #include <optional>
27e5dd7070Spatrick using namespace clang;
28e5dd7070Spatrick 
hasExplicitAttr(const VarDecl * D)29a9ac8606Spatrick template <typename AttrT> static bool hasExplicitAttr(const VarDecl *D) {
30a9ac8606Spatrick   if (!D)
31a9ac8606Spatrick     return false;
32a9ac8606Spatrick   if (auto *A = D->getAttr<AttrT>())
33a9ac8606Spatrick     return !A->isImplicit();
34a9ac8606Spatrick   return false;
35a9ac8606Spatrick }
36a9ac8606Spatrick 
PushForceCUDAHostDevice()37e5dd7070Spatrick void Sema::PushForceCUDAHostDevice() {
38e5dd7070Spatrick   assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
39e5dd7070Spatrick   ForceCUDAHostDeviceDepth++;
40e5dd7070Spatrick }
41e5dd7070Spatrick 
PopForceCUDAHostDevice()42e5dd7070Spatrick bool Sema::PopForceCUDAHostDevice() {
43e5dd7070Spatrick   assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
44e5dd7070Spatrick   if (ForceCUDAHostDeviceDepth == 0)
45e5dd7070Spatrick     return false;
46e5dd7070Spatrick   ForceCUDAHostDeviceDepth--;
47e5dd7070Spatrick   return true;
48e5dd7070Spatrick }
49e5dd7070Spatrick 
ActOnCUDAExecConfigExpr(Scope * S,SourceLocation LLLLoc,MultiExprArg ExecConfig,SourceLocation GGGLoc)50e5dd7070Spatrick ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
51e5dd7070Spatrick                                          MultiExprArg ExecConfig,
52e5dd7070Spatrick                                          SourceLocation GGGLoc) {
53e5dd7070Spatrick   FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl();
54e5dd7070Spatrick   if (!ConfigDecl)
55e5dd7070Spatrick     return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use)
56e5dd7070Spatrick                      << getCudaConfigureFuncName());
57e5dd7070Spatrick   QualType ConfigQTy = ConfigDecl->getType();
58e5dd7070Spatrick 
59e5dd7070Spatrick   DeclRefExpr *ConfigDR = new (Context)
60e5dd7070Spatrick       DeclRefExpr(Context, ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc);
61e5dd7070Spatrick   MarkFunctionReferenced(LLLLoc, ConfigDecl);
62e5dd7070Spatrick 
63e5dd7070Spatrick   return BuildCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr,
64e5dd7070Spatrick                        /*IsExecConfig=*/true);
65e5dd7070Spatrick }
66e5dd7070Spatrick 
67e5dd7070Spatrick Sema::CUDAFunctionTarget
IdentifyCUDATarget(const ParsedAttributesView & Attrs)68e5dd7070Spatrick Sema::IdentifyCUDATarget(const ParsedAttributesView &Attrs) {
69e5dd7070Spatrick   bool HasHostAttr = false;
70e5dd7070Spatrick   bool HasDeviceAttr = false;
71e5dd7070Spatrick   bool HasGlobalAttr = false;
72e5dd7070Spatrick   bool HasInvalidTargetAttr = false;
73e5dd7070Spatrick   for (const ParsedAttr &AL : Attrs) {
74e5dd7070Spatrick     switch (AL.getKind()) {
75e5dd7070Spatrick     case ParsedAttr::AT_CUDAGlobal:
76e5dd7070Spatrick       HasGlobalAttr = true;
77e5dd7070Spatrick       break;
78e5dd7070Spatrick     case ParsedAttr::AT_CUDAHost:
79e5dd7070Spatrick       HasHostAttr = true;
80e5dd7070Spatrick       break;
81e5dd7070Spatrick     case ParsedAttr::AT_CUDADevice:
82e5dd7070Spatrick       HasDeviceAttr = true;
83e5dd7070Spatrick       break;
84e5dd7070Spatrick     case ParsedAttr::AT_CUDAInvalidTarget:
85e5dd7070Spatrick       HasInvalidTargetAttr = true;
86e5dd7070Spatrick       break;
87e5dd7070Spatrick     default:
88e5dd7070Spatrick       break;
89e5dd7070Spatrick     }
90e5dd7070Spatrick   }
91e5dd7070Spatrick 
92e5dd7070Spatrick   if (HasInvalidTargetAttr)
93e5dd7070Spatrick     return CFT_InvalidTarget;
94e5dd7070Spatrick 
95e5dd7070Spatrick   if (HasGlobalAttr)
96e5dd7070Spatrick     return CFT_Global;
97e5dd7070Spatrick 
98e5dd7070Spatrick   if (HasHostAttr && HasDeviceAttr)
99e5dd7070Spatrick     return CFT_HostDevice;
100e5dd7070Spatrick 
101e5dd7070Spatrick   if (HasDeviceAttr)
102e5dd7070Spatrick     return CFT_Device;
103e5dd7070Spatrick 
104e5dd7070Spatrick   return CFT_Host;
105e5dd7070Spatrick }
106e5dd7070Spatrick 
107e5dd7070Spatrick template <typename A>
hasAttr(const FunctionDecl * D,bool IgnoreImplicitAttr)108e5dd7070Spatrick static bool hasAttr(const FunctionDecl *D, bool IgnoreImplicitAttr) {
109e5dd7070Spatrick   return D->hasAttrs() && llvm::any_of(D->getAttrs(), [&](Attr *Attribute) {
110e5dd7070Spatrick            return isa<A>(Attribute) &&
111e5dd7070Spatrick                   !(IgnoreImplicitAttr && Attribute->isImplicit());
112e5dd7070Spatrick          });
113e5dd7070Spatrick }
114e5dd7070Spatrick 
115e5dd7070Spatrick /// IdentifyCUDATarget - Determine the CUDA compilation target for this function
IdentifyCUDATarget(const FunctionDecl * D,bool IgnoreImplicitHDAttr)116e5dd7070Spatrick Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D,
117e5dd7070Spatrick                                                   bool IgnoreImplicitHDAttr) {
118e5dd7070Spatrick   // Code that lives outside a function is run on the host.
119e5dd7070Spatrick   if (D == nullptr)
120e5dd7070Spatrick     return CFT_Host;
121e5dd7070Spatrick 
122e5dd7070Spatrick   if (D->hasAttr<CUDAInvalidTargetAttr>())
123e5dd7070Spatrick     return CFT_InvalidTarget;
124e5dd7070Spatrick 
125e5dd7070Spatrick   if (D->hasAttr<CUDAGlobalAttr>())
126e5dd7070Spatrick     return CFT_Global;
127e5dd7070Spatrick 
128e5dd7070Spatrick   if (hasAttr<CUDADeviceAttr>(D, IgnoreImplicitHDAttr)) {
129e5dd7070Spatrick     if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr))
130e5dd7070Spatrick       return CFT_HostDevice;
131e5dd7070Spatrick     return CFT_Device;
132e5dd7070Spatrick   } else if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr)) {
133e5dd7070Spatrick     return CFT_Host;
134a9ac8606Spatrick   } else if ((D->isImplicit() || !D->isUserProvided()) &&
135a9ac8606Spatrick              !IgnoreImplicitHDAttr) {
136e5dd7070Spatrick     // Some implicit declarations (like intrinsic functions) are not marked.
137e5dd7070Spatrick     // Set the most lenient target on them for maximal flexibility.
138e5dd7070Spatrick     return CFT_HostDevice;
139e5dd7070Spatrick   }
140e5dd7070Spatrick 
141e5dd7070Spatrick   return CFT_Host;
142e5dd7070Spatrick }
143e5dd7070Spatrick 
144a9ac8606Spatrick /// IdentifyTarget - Determine the CUDA compilation target for this variable.
IdentifyCUDATarget(const VarDecl * Var)145a9ac8606Spatrick Sema::CUDAVariableTarget Sema::IdentifyCUDATarget(const VarDecl *Var) {
146a9ac8606Spatrick   if (Var->hasAttr<HIPManagedAttr>())
147a9ac8606Spatrick     return CVT_Unified;
148*12c85518Srobert   // Only constexpr and const variabless with implicit constant attribute
149*12c85518Srobert   // are emitted on both sides. Such variables are promoted to device side
150*12c85518Srobert   // only if they have static constant intializers on device side.
151*12c85518Srobert   if ((Var->isConstexpr() || Var->getType().isConstQualified()) &&
152*12c85518Srobert       Var->hasAttr<CUDAConstantAttr>() &&
153a9ac8606Spatrick       !hasExplicitAttr<CUDAConstantAttr>(Var))
154a9ac8606Spatrick     return CVT_Both;
155a9ac8606Spatrick   if (Var->hasAttr<CUDADeviceAttr>() || Var->hasAttr<CUDAConstantAttr>() ||
156a9ac8606Spatrick       Var->hasAttr<CUDASharedAttr>() ||
157a9ac8606Spatrick       Var->getType()->isCUDADeviceBuiltinSurfaceType() ||
158a9ac8606Spatrick       Var->getType()->isCUDADeviceBuiltinTextureType())
159a9ac8606Spatrick     return CVT_Device;
160a9ac8606Spatrick   // Function-scope static variable without explicit device or constant
161a9ac8606Spatrick   // attribute are emitted
162a9ac8606Spatrick   //  - on both sides in host device functions
163a9ac8606Spatrick   //  - on device side in device or global functions
164a9ac8606Spatrick   if (auto *FD = dyn_cast<FunctionDecl>(Var->getDeclContext())) {
165a9ac8606Spatrick     switch (IdentifyCUDATarget(FD)) {
166a9ac8606Spatrick     case CFT_HostDevice:
167a9ac8606Spatrick       return CVT_Both;
168a9ac8606Spatrick     case CFT_Device:
169a9ac8606Spatrick     case CFT_Global:
170a9ac8606Spatrick       return CVT_Device;
171a9ac8606Spatrick     default:
172a9ac8606Spatrick       return CVT_Host;
173a9ac8606Spatrick     }
174a9ac8606Spatrick   }
175a9ac8606Spatrick   return CVT_Host;
176a9ac8606Spatrick }
177a9ac8606Spatrick 
178e5dd7070Spatrick // * CUDA Call preference table
179e5dd7070Spatrick //
180e5dd7070Spatrick // F - from,
181e5dd7070Spatrick // T - to
182e5dd7070Spatrick // Ph - preference in host mode
183e5dd7070Spatrick // Pd - preference in device mode
184e5dd7070Spatrick // H  - handled in (x)
185e5dd7070Spatrick // Preferences: N:native, SS:same side, HD:host-device, WS:wrong side, --:never.
186e5dd7070Spatrick //
187e5dd7070Spatrick // | F  | T  | Ph  | Pd  |  H  |
188e5dd7070Spatrick // |----+----+-----+-----+-----+
189e5dd7070Spatrick // | d  | d  | N   | N   | (c) |
190e5dd7070Spatrick // | d  | g  | --  | --  | (a) |
191e5dd7070Spatrick // | d  | h  | --  | --  | (e) |
192e5dd7070Spatrick // | d  | hd | HD  | HD  | (b) |
193e5dd7070Spatrick // | g  | d  | N   | N   | (c) |
194e5dd7070Spatrick // | g  | g  | --  | --  | (a) |
195e5dd7070Spatrick // | g  | h  | --  | --  | (e) |
196e5dd7070Spatrick // | g  | hd | HD  | HD  | (b) |
197e5dd7070Spatrick // | h  | d  | --  | --  | (e) |
198e5dd7070Spatrick // | h  | g  | N   | N   | (c) |
199e5dd7070Spatrick // | h  | h  | N   | N   | (c) |
200e5dd7070Spatrick // | h  | hd | HD  | HD  | (b) |
201e5dd7070Spatrick // | hd | d  | WS  | SS  | (d) |
202e5dd7070Spatrick // | hd | g  | SS  | --  |(d/a)|
203e5dd7070Spatrick // | hd | h  | SS  | WS  | (d) |
204e5dd7070Spatrick // | hd | hd | HD  | HD  | (b) |
205e5dd7070Spatrick 
206e5dd7070Spatrick Sema::CUDAFunctionPreference
IdentifyCUDAPreference(const FunctionDecl * Caller,const FunctionDecl * Callee)207e5dd7070Spatrick Sema::IdentifyCUDAPreference(const FunctionDecl *Caller,
208e5dd7070Spatrick                              const FunctionDecl *Callee) {
209e5dd7070Spatrick   assert(Callee && "Callee must be valid.");
210e5dd7070Spatrick   CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller);
211e5dd7070Spatrick   CUDAFunctionTarget CalleeTarget = IdentifyCUDATarget(Callee);
212e5dd7070Spatrick 
213e5dd7070Spatrick   // If one of the targets is invalid, the check always fails, no matter what
214e5dd7070Spatrick   // the other target is.
215e5dd7070Spatrick   if (CallerTarget == CFT_InvalidTarget || CalleeTarget == CFT_InvalidTarget)
216e5dd7070Spatrick     return CFP_Never;
217e5dd7070Spatrick 
218e5dd7070Spatrick   // (a) Can't call global from some contexts until we support CUDA's
219e5dd7070Spatrick   // dynamic parallelism.
220e5dd7070Spatrick   if (CalleeTarget == CFT_Global &&
221e5dd7070Spatrick       (CallerTarget == CFT_Global || CallerTarget == CFT_Device))
222e5dd7070Spatrick     return CFP_Never;
223e5dd7070Spatrick 
224e5dd7070Spatrick   // (b) Calling HostDevice is OK for everyone.
225e5dd7070Spatrick   if (CalleeTarget == CFT_HostDevice)
226e5dd7070Spatrick     return CFP_HostDevice;
227e5dd7070Spatrick 
228e5dd7070Spatrick   // (c) Best case scenarios
229e5dd7070Spatrick   if (CalleeTarget == CallerTarget ||
230e5dd7070Spatrick       (CallerTarget == CFT_Host && CalleeTarget == CFT_Global) ||
231e5dd7070Spatrick       (CallerTarget == CFT_Global && CalleeTarget == CFT_Device))
232e5dd7070Spatrick     return CFP_Native;
233e5dd7070Spatrick 
234e5dd7070Spatrick   // (d) HostDevice behavior depends on compilation mode.
235e5dd7070Spatrick   if (CallerTarget == CFT_HostDevice) {
236e5dd7070Spatrick     // It's OK to call a compilation-mode matching function from an HD one.
237e5dd7070Spatrick     if ((getLangOpts().CUDAIsDevice && CalleeTarget == CFT_Device) ||
238e5dd7070Spatrick         (!getLangOpts().CUDAIsDevice &&
239e5dd7070Spatrick          (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global)))
240e5dd7070Spatrick       return CFP_SameSide;
241e5dd7070Spatrick 
242e5dd7070Spatrick     // Calls from HD to non-mode-matching functions (i.e., to host functions
243e5dd7070Spatrick     // when compiling in device mode or to device functions when compiling in
244e5dd7070Spatrick     // host mode) are allowed at the sema level, but eventually rejected if
245e5dd7070Spatrick     // they're ever codegened.  TODO: Reject said calls earlier.
246e5dd7070Spatrick     return CFP_WrongSide;
247e5dd7070Spatrick   }
248e5dd7070Spatrick 
249e5dd7070Spatrick   // (e) Calling across device/host boundary is not something you should do.
250e5dd7070Spatrick   if ((CallerTarget == CFT_Host && CalleeTarget == CFT_Device) ||
251e5dd7070Spatrick       (CallerTarget == CFT_Device && CalleeTarget == CFT_Host) ||
252e5dd7070Spatrick       (CallerTarget == CFT_Global && CalleeTarget == CFT_Host))
253e5dd7070Spatrick     return CFP_Never;
254e5dd7070Spatrick 
255e5dd7070Spatrick   llvm_unreachable("All cases should've been handled by now.");
256e5dd7070Spatrick }
257e5dd7070Spatrick 
hasImplicitAttr(const FunctionDecl * D)258ec727ea7Spatrick template <typename AttrT> static bool hasImplicitAttr(const FunctionDecl *D) {
259ec727ea7Spatrick   if (!D)
260ec727ea7Spatrick     return false;
261ec727ea7Spatrick   if (auto *A = D->getAttr<AttrT>())
262ec727ea7Spatrick     return A->isImplicit();
263ec727ea7Spatrick   return D->isImplicit();
264ec727ea7Spatrick }
265ec727ea7Spatrick 
isCUDAImplicitHostDeviceFunction(const FunctionDecl * D)266ec727ea7Spatrick bool Sema::isCUDAImplicitHostDeviceFunction(const FunctionDecl *D) {
267ec727ea7Spatrick   bool IsImplicitDevAttr = hasImplicitAttr<CUDADeviceAttr>(D);
268ec727ea7Spatrick   bool IsImplicitHostAttr = hasImplicitAttr<CUDAHostAttr>(D);
269ec727ea7Spatrick   return IsImplicitDevAttr && IsImplicitHostAttr;
270ec727ea7Spatrick }
271ec727ea7Spatrick 
EraseUnwantedCUDAMatches(const FunctionDecl * Caller,SmallVectorImpl<std::pair<DeclAccessPair,FunctionDecl * >> & Matches)272e5dd7070Spatrick void Sema::EraseUnwantedCUDAMatches(
273e5dd7070Spatrick     const FunctionDecl *Caller,
274e5dd7070Spatrick     SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>> &Matches) {
275e5dd7070Spatrick   if (Matches.size() <= 1)
276e5dd7070Spatrick     return;
277e5dd7070Spatrick 
278e5dd7070Spatrick   using Pair = std::pair<DeclAccessPair, FunctionDecl*>;
279e5dd7070Spatrick 
280e5dd7070Spatrick   // Gets the CUDA function preference for a call from Caller to Match.
281e5dd7070Spatrick   auto GetCFP = [&](const Pair &Match) {
282e5dd7070Spatrick     return IdentifyCUDAPreference(Caller, Match.second);
283e5dd7070Spatrick   };
284e5dd7070Spatrick 
285e5dd7070Spatrick   // Find the best call preference among the functions in Matches.
286e5dd7070Spatrick   CUDAFunctionPreference BestCFP = GetCFP(*std::max_element(
287e5dd7070Spatrick       Matches.begin(), Matches.end(),
288e5dd7070Spatrick       [&](const Pair &M1, const Pair &M2) { return GetCFP(M1) < GetCFP(M2); }));
289e5dd7070Spatrick 
290e5dd7070Spatrick   // Erase all functions with lower priority.
291e5dd7070Spatrick   llvm::erase_if(Matches,
292e5dd7070Spatrick                  [&](const Pair &Match) { return GetCFP(Match) < BestCFP; });
293e5dd7070Spatrick }
294e5dd7070Spatrick 
295e5dd7070Spatrick /// When an implicitly-declared special member has to invoke more than one
296e5dd7070Spatrick /// base/field special member, conflicts may occur in the targets of these
297e5dd7070Spatrick /// members. For example, if one base's member __host__ and another's is
298e5dd7070Spatrick /// __device__, it's a conflict.
299e5dd7070Spatrick /// This function figures out if the given targets \param Target1 and
300e5dd7070Spatrick /// \param Target2 conflict, and if they do not it fills in
301e5dd7070Spatrick /// \param ResolvedTarget with a target that resolves for both calls.
302e5dd7070Spatrick /// \return true if there's a conflict, false otherwise.
303e5dd7070Spatrick static bool
resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1,Sema::CUDAFunctionTarget Target2,Sema::CUDAFunctionTarget * ResolvedTarget)304e5dd7070Spatrick resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1,
305e5dd7070Spatrick                                 Sema::CUDAFunctionTarget Target2,
306e5dd7070Spatrick                                 Sema::CUDAFunctionTarget *ResolvedTarget) {
307e5dd7070Spatrick   // Only free functions and static member functions may be global.
308e5dd7070Spatrick   assert(Target1 != Sema::CFT_Global);
309e5dd7070Spatrick   assert(Target2 != Sema::CFT_Global);
310e5dd7070Spatrick 
311e5dd7070Spatrick   if (Target1 == Sema::CFT_HostDevice) {
312e5dd7070Spatrick     *ResolvedTarget = Target2;
313e5dd7070Spatrick   } else if (Target2 == Sema::CFT_HostDevice) {
314e5dd7070Spatrick     *ResolvedTarget = Target1;
315e5dd7070Spatrick   } else if (Target1 != Target2) {
316e5dd7070Spatrick     return true;
317e5dd7070Spatrick   } else {
318e5dd7070Spatrick     *ResolvedTarget = Target1;
319e5dd7070Spatrick   }
320e5dd7070Spatrick 
321e5dd7070Spatrick   return false;
322e5dd7070Spatrick }
323e5dd7070Spatrick 
inferCUDATargetForImplicitSpecialMember(CXXRecordDecl * ClassDecl,CXXSpecialMember CSM,CXXMethodDecl * MemberDecl,bool ConstRHS,bool Diagnose)324e5dd7070Spatrick bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
325e5dd7070Spatrick                                                    CXXSpecialMember CSM,
326e5dd7070Spatrick                                                    CXXMethodDecl *MemberDecl,
327e5dd7070Spatrick                                                    bool ConstRHS,
328e5dd7070Spatrick                                                    bool Diagnose) {
329e5dd7070Spatrick   // If the defaulted special member is defined lexically outside of its
330e5dd7070Spatrick   // owning class, or the special member already has explicit device or host
331e5dd7070Spatrick   // attributes, do not infer.
332e5dd7070Spatrick   bool InClass = MemberDecl->getLexicalParent() == MemberDecl->getParent();
333e5dd7070Spatrick   bool HasH = MemberDecl->hasAttr<CUDAHostAttr>();
334e5dd7070Spatrick   bool HasD = MemberDecl->hasAttr<CUDADeviceAttr>();
335e5dd7070Spatrick   bool HasExplicitAttr =
336e5dd7070Spatrick       (HasD && !MemberDecl->getAttr<CUDADeviceAttr>()->isImplicit()) ||
337e5dd7070Spatrick       (HasH && !MemberDecl->getAttr<CUDAHostAttr>()->isImplicit());
338e5dd7070Spatrick   if (!InClass || HasExplicitAttr)
339e5dd7070Spatrick     return false;
340e5dd7070Spatrick 
341*12c85518Srobert   std::optional<CUDAFunctionTarget> InferredTarget;
342e5dd7070Spatrick 
343e5dd7070Spatrick   // We're going to invoke special member lookup; mark that these special
344e5dd7070Spatrick   // members are called from this one, and not from its caller.
345e5dd7070Spatrick   ContextRAII MethodContext(*this, MemberDecl);
346e5dd7070Spatrick 
347e5dd7070Spatrick   // Look for special members in base classes that should be invoked from here.
348e5dd7070Spatrick   // Infer the target of this member base on the ones it should call.
349e5dd7070Spatrick   // Skip direct and indirect virtual bases for abstract classes.
350e5dd7070Spatrick   llvm::SmallVector<const CXXBaseSpecifier *, 16> Bases;
351e5dd7070Spatrick   for (const auto &B : ClassDecl->bases()) {
352e5dd7070Spatrick     if (!B.isVirtual()) {
353e5dd7070Spatrick       Bases.push_back(&B);
354e5dd7070Spatrick     }
355e5dd7070Spatrick   }
356e5dd7070Spatrick 
357e5dd7070Spatrick   if (!ClassDecl->isAbstract()) {
358*12c85518Srobert     llvm::append_range(Bases, llvm::make_pointer_range(ClassDecl->vbases()));
359e5dd7070Spatrick   }
360e5dd7070Spatrick 
361e5dd7070Spatrick   for (const auto *B : Bases) {
362e5dd7070Spatrick     const RecordType *BaseType = B->getType()->getAs<RecordType>();
363e5dd7070Spatrick     if (!BaseType) {
364e5dd7070Spatrick       continue;
365e5dd7070Spatrick     }
366e5dd7070Spatrick 
367e5dd7070Spatrick     CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
368e5dd7070Spatrick     Sema::SpecialMemberOverloadResult SMOR =
369e5dd7070Spatrick         LookupSpecialMember(BaseClassDecl, CSM,
370e5dd7070Spatrick                             /* ConstArg */ ConstRHS,
371e5dd7070Spatrick                             /* VolatileArg */ false,
372e5dd7070Spatrick                             /* RValueThis */ false,
373e5dd7070Spatrick                             /* ConstThis */ false,
374e5dd7070Spatrick                             /* VolatileThis */ false);
375e5dd7070Spatrick 
376e5dd7070Spatrick     if (!SMOR.getMethod())
377e5dd7070Spatrick       continue;
378e5dd7070Spatrick 
379e5dd7070Spatrick     CUDAFunctionTarget BaseMethodTarget = IdentifyCUDATarget(SMOR.getMethod());
380*12c85518Srobert     if (!InferredTarget) {
381e5dd7070Spatrick       InferredTarget = BaseMethodTarget;
382e5dd7070Spatrick     } else {
383e5dd7070Spatrick       bool ResolutionError = resolveCalleeCUDATargetConflict(
384*12c85518Srobert           *InferredTarget, BaseMethodTarget, &*InferredTarget);
385e5dd7070Spatrick       if (ResolutionError) {
386e5dd7070Spatrick         if (Diagnose) {
387e5dd7070Spatrick           Diag(ClassDecl->getLocation(),
388e5dd7070Spatrick                diag::note_implicit_member_target_infer_collision)
389*12c85518Srobert               << (unsigned)CSM << *InferredTarget << BaseMethodTarget;
390e5dd7070Spatrick         }
391e5dd7070Spatrick         MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
392e5dd7070Spatrick         return true;
393e5dd7070Spatrick       }
394e5dd7070Spatrick     }
395e5dd7070Spatrick   }
396e5dd7070Spatrick 
397e5dd7070Spatrick   // Same as for bases, but now for special members of fields.
398e5dd7070Spatrick   for (const auto *F : ClassDecl->fields()) {
399e5dd7070Spatrick     if (F->isInvalidDecl()) {
400e5dd7070Spatrick       continue;
401e5dd7070Spatrick     }
402e5dd7070Spatrick 
403e5dd7070Spatrick     const RecordType *FieldType =
404e5dd7070Spatrick         Context.getBaseElementType(F->getType())->getAs<RecordType>();
405e5dd7070Spatrick     if (!FieldType) {
406e5dd7070Spatrick       continue;
407e5dd7070Spatrick     }
408e5dd7070Spatrick 
409e5dd7070Spatrick     CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(FieldType->getDecl());
410e5dd7070Spatrick     Sema::SpecialMemberOverloadResult SMOR =
411e5dd7070Spatrick         LookupSpecialMember(FieldRecDecl, CSM,
412e5dd7070Spatrick                             /* ConstArg */ ConstRHS && !F->isMutable(),
413e5dd7070Spatrick                             /* VolatileArg */ false,
414e5dd7070Spatrick                             /* RValueThis */ false,
415e5dd7070Spatrick                             /* ConstThis */ false,
416e5dd7070Spatrick                             /* VolatileThis */ false);
417e5dd7070Spatrick 
418e5dd7070Spatrick     if (!SMOR.getMethod())
419e5dd7070Spatrick       continue;
420e5dd7070Spatrick 
421e5dd7070Spatrick     CUDAFunctionTarget FieldMethodTarget =
422e5dd7070Spatrick         IdentifyCUDATarget(SMOR.getMethod());
423*12c85518Srobert     if (!InferredTarget) {
424e5dd7070Spatrick       InferredTarget = FieldMethodTarget;
425e5dd7070Spatrick     } else {
426e5dd7070Spatrick       bool ResolutionError = resolveCalleeCUDATargetConflict(
427*12c85518Srobert           *InferredTarget, FieldMethodTarget, &*InferredTarget);
428e5dd7070Spatrick       if (ResolutionError) {
429e5dd7070Spatrick         if (Diagnose) {
430e5dd7070Spatrick           Diag(ClassDecl->getLocation(),
431e5dd7070Spatrick                diag::note_implicit_member_target_infer_collision)
432*12c85518Srobert               << (unsigned)CSM << *InferredTarget << FieldMethodTarget;
433e5dd7070Spatrick         }
434e5dd7070Spatrick         MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
435e5dd7070Spatrick         return true;
436e5dd7070Spatrick       }
437e5dd7070Spatrick     }
438e5dd7070Spatrick   }
439e5dd7070Spatrick 
440e5dd7070Spatrick 
441e5dd7070Spatrick   // If no target was inferred, mark this member as __host__ __device__;
442e5dd7070Spatrick   // it's the least restrictive option that can be invoked from any target.
443e5dd7070Spatrick   bool NeedsH = true, NeedsD = true;
444*12c85518Srobert   if (InferredTarget) {
445*12c85518Srobert     if (*InferredTarget == CFT_Device)
446e5dd7070Spatrick       NeedsH = false;
447*12c85518Srobert     else if (*InferredTarget == CFT_Host)
448e5dd7070Spatrick       NeedsD = false;
449e5dd7070Spatrick   }
450e5dd7070Spatrick 
451e5dd7070Spatrick   // We either setting attributes first time, or the inferred ones must match
452e5dd7070Spatrick   // previously set ones.
453e5dd7070Spatrick   if (NeedsD && !HasD)
454e5dd7070Spatrick     MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
455e5dd7070Spatrick   if (NeedsH && !HasH)
456e5dd7070Spatrick     MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
457e5dd7070Spatrick 
458e5dd7070Spatrick   return false;
459e5dd7070Spatrick }
460e5dd7070Spatrick 
isEmptyCudaConstructor(SourceLocation Loc,CXXConstructorDecl * CD)461e5dd7070Spatrick bool Sema::isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD) {
462e5dd7070Spatrick   if (!CD->isDefined() && CD->isTemplateInstantiation())
463e5dd7070Spatrick     InstantiateFunctionDefinition(Loc, CD->getFirstDecl());
464e5dd7070Spatrick 
465e5dd7070Spatrick   // (E.2.3.1, CUDA 7.5) A constructor for a class type is considered
466e5dd7070Spatrick   // empty at a point in the translation unit, if it is either a
467e5dd7070Spatrick   // trivial constructor
468e5dd7070Spatrick   if (CD->isTrivial())
469e5dd7070Spatrick     return true;
470e5dd7070Spatrick 
471e5dd7070Spatrick   // ... or it satisfies all of the following conditions:
472e5dd7070Spatrick   // The constructor function has been defined.
473e5dd7070Spatrick   // The constructor function has no parameters,
474e5dd7070Spatrick   // and the function body is an empty compound statement.
475e5dd7070Spatrick   if (!(CD->hasTrivialBody() && CD->getNumParams() == 0))
476e5dd7070Spatrick     return false;
477e5dd7070Spatrick 
478e5dd7070Spatrick   // Its class has no virtual functions and no virtual base classes.
479e5dd7070Spatrick   if (CD->getParent()->isDynamicClass())
480e5dd7070Spatrick     return false;
481e5dd7070Spatrick 
482ec727ea7Spatrick   // Union ctor does not call ctors of its data members.
483ec727ea7Spatrick   if (CD->getParent()->isUnion())
484ec727ea7Spatrick     return true;
485ec727ea7Spatrick 
486e5dd7070Spatrick   // The only form of initializer allowed is an empty constructor.
487e5dd7070Spatrick   // This will recursively check all base classes and member initializers
488e5dd7070Spatrick   if (!llvm::all_of(CD->inits(), [&](const CXXCtorInitializer *CI) {
489e5dd7070Spatrick         if (const CXXConstructExpr *CE =
490e5dd7070Spatrick                 dyn_cast<CXXConstructExpr>(CI->getInit()))
491e5dd7070Spatrick           return isEmptyCudaConstructor(Loc, CE->getConstructor());
492e5dd7070Spatrick         return false;
493e5dd7070Spatrick       }))
494e5dd7070Spatrick     return false;
495e5dd7070Spatrick 
496e5dd7070Spatrick   return true;
497e5dd7070Spatrick }
498e5dd7070Spatrick 
isEmptyCudaDestructor(SourceLocation Loc,CXXDestructorDecl * DD)499e5dd7070Spatrick bool Sema::isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *DD) {
500e5dd7070Spatrick   // No destructor -> no problem.
501e5dd7070Spatrick   if (!DD)
502e5dd7070Spatrick     return true;
503e5dd7070Spatrick 
504e5dd7070Spatrick   if (!DD->isDefined() && DD->isTemplateInstantiation())
505e5dd7070Spatrick     InstantiateFunctionDefinition(Loc, DD->getFirstDecl());
506e5dd7070Spatrick 
507e5dd7070Spatrick   // (E.2.3.1, CUDA 7.5) A destructor for a class type is considered
508e5dd7070Spatrick   // empty at a point in the translation unit, if it is either a
509e5dd7070Spatrick   // trivial constructor
510e5dd7070Spatrick   if (DD->isTrivial())
511e5dd7070Spatrick     return true;
512e5dd7070Spatrick 
513e5dd7070Spatrick   // ... or it satisfies all of the following conditions:
514e5dd7070Spatrick   // The destructor function has been defined.
515e5dd7070Spatrick   // and the function body is an empty compound statement.
516e5dd7070Spatrick   if (!DD->hasTrivialBody())
517e5dd7070Spatrick     return false;
518e5dd7070Spatrick 
519e5dd7070Spatrick   const CXXRecordDecl *ClassDecl = DD->getParent();
520e5dd7070Spatrick 
521e5dd7070Spatrick   // Its class has no virtual functions and no virtual base classes.
522e5dd7070Spatrick   if (ClassDecl->isDynamicClass())
523e5dd7070Spatrick     return false;
524e5dd7070Spatrick 
525ec727ea7Spatrick   // Union does not have base class and union dtor does not call dtors of its
526ec727ea7Spatrick   // data members.
527ec727ea7Spatrick   if (DD->getParent()->isUnion())
528ec727ea7Spatrick     return true;
529ec727ea7Spatrick 
530e5dd7070Spatrick   // Only empty destructors are allowed. This will recursively check
531e5dd7070Spatrick   // destructors for all base classes...
532e5dd7070Spatrick   if (!llvm::all_of(ClassDecl->bases(), [&](const CXXBaseSpecifier &BS) {
533e5dd7070Spatrick         if (CXXRecordDecl *RD = BS.getType()->getAsCXXRecordDecl())
534e5dd7070Spatrick           return isEmptyCudaDestructor(Loc, RD->getDestructor());
535e5dd7070Spatrick         return true;
536e5dd7070Spatrick       }))
537e5dd7070Spatrick     return false;
538e5dd7070Spatrick 
539e5dd7070Spatrick   // ... and member fields.
540e5dd7070Spatrick   if (!llvm::all_of(ClassDecl->fields(), [&](const FieldDecl *Field) {
541e5dd7070Spatrick         if (CXXRecordDecl *RD = Field->getType()
542e5dd7070Spatrick                                     ->getBaseElementTypeUnsafe()
543e5dd7070Spatrick                                     ->getAsCXXRecordDecl())
544e5dd7070Spatrick           return isEmptyCudaDestructor(Loc, RD->getDestructor());
545e5dd7070Spatrick         return true;
546e5dd7070Spatrick       }))
547e5dd7070Spatrick     return false;
548e5dd7070Spatrick 
549e5dd7070Spatrick   return true;
550e5dd7070Spatrick }
551e5dd7070Spatrick 
552a9ac8606Spatrick namespace {
553a9ac8606Spatrick enum CUDAInitializerCheckKind {
554a9ac8606Spatrick   CICK_DeviceOrConstant, // Check initializer for device/constant variable
555a9ac8606Spatrick   CICK_Shared,           // Check initializer for shared variable
556a9ac8606Spatrick };
557a9ac8606Spatrick 
IsDependentVar(VarDecl * VD)558a9ac8606Spatrick bool IsDependentVar(VarDecl *VD) {
559a9ac8606Spatrick   if (VD->getType()->isDependentType())
560a9ac8606Spatrick     return true;
561a9ac8606Spatrick   if (const auto *Init = VD->getInit())
562a9ac8606Spatrick     return Init->isValueDependent();
563a9ac8606Spatrick   return false;
564a9ac8606Spatrick }
565a9ac8606Spatrick 
566a9ac8606Spatrick // Check whether a variable has an allowed initializer for a CUDA device side
567a9ac8606Spatrick // variable with global storage. \p VD may be a host variable to be checked for
568a9ac8606Spatrick // potential promotion to device side variable.
569a9ac8606Spatrick //
570a9ac8606Spatrick // CUDA/HIP allows only empty constructors as initializers for global
571a9ac8606Spatrick // variables (see E.2.3.1, CUDA 7.5). The same restriction also applies to all
572a9ac8606Spatrick // __shared__ variables whether they are local or not (they all are implicitly
573a9ac8606Spatrick // static in CUDA). One exception is that CUDA allows constant initializers
574a9ac8606Spatrick // for __constant__ and __device__ variables.
HasAllowedCUDADeviceStaticInitializer(Sema & S,VarDecl * VD,CUDAInitializerCheckKind CheckKind)575a9ac8606Spatrick bool HasAllowedCUDADeviceStaticInitializer(Sema &S, VarDecl *VD,
576a9ac8606Spatrick                                            CUDAInitializerCheckKind CheckKind) {
577a9ac8606Spatrick   assert(!VD->isInvalidDecl() && VD->hasGlobalStorage());
578a9ac8606Spatrick   assert(!IsDependentVar(VD) && "do not check dependent var");
579a9ac8606Spatrick   const Expr *Init = VD->getInit();
580a9ac8606Spatrick   auto IsEmptyInit = [&](const Expr *Init) {
581a9ac8606Spatrick     if (!Init)
582a9ac8606Spatrick       return true;
583a9ac8606Spatrick     if (const auto *CE = dyn_cast<CXXConstructExpr>(Init)) {
584a9ac8606Spatrick       return S.isEmptyCudaConstructor(VD->getLocation(), CE->getConstructor());
585a9ac8606Spatrick     }
586a9ac8606Spatrick     return false;
587a9ac8606Spatrick   };
588a9ac8606Spatrick   auto IsConstantInit = [&](const Expr *Init) {
589a9ac8606Spatrick     assert(Init);
590*12c85518Srobert     ASTContext::CUDAConstantEvalContextRAII EvalCtx(S.Context,
591*12c85518Srobert                                                     /*NoWronSidedVars=*/true);
592a9ac8606Spatrick     return Init->isConstantInitializer(S.Context,
593a9ac8606Spatrick                                        VD->getType()->isReferenceType());
594a9ac8606Spatrick   };
595a9ac8606Spatrick   auto HasEmptyDtor = [&](VarDecl *VD) {
596a9ac8606Spatrick     if (const auto *RD = VD->getType()->getAsCXXRecordDecl())
597a9ac8606Spatrick       return S.isEmptyCudaDestructor(VD->getLocation(), RD->getDestructor());
598a9ac8606Spatrick     return true;
599a9ac8606Spatrick   };
600a9ac8606Spatrick   if (CheckKind == CICK_Shared)
601a9ac8606Spatrick     return IsEmptyInit(Init) && HasEmptyDtor(VD);
602a9ac8606Spatrick   return S.LangOpts.GPUAllowDeviceInit ||
603a9ac8606Spatrick          ((IsEmptyInit(Init) || IsConstantInit(Init)) && HasEmptyDtor(VD));
604a9ac8606Spatrick }
605a9ac8606Spatrick } // namespace
606a9ac8606Spatrick 
checkAllowedCUDAInitializer(VarDecl * VD)607e5dd7070Spatrick void Sema::checkAllowedCUDAInitializer(VarDecl *VD) {
608a9ac8606Spatrick   // Do not check dependent variables since the ctor/dtor/initializer are not
609a9ac8606Spatrick   // determined. Do it after instantiation.
610a9ac8606Spatrick   if (VD->isInvalidDecl() || !VD->hasInit() || !VD->hasGlobalStorage() ||
611a9ac8606Spatrick       IsDependentVar(VD))
612e5dd7070Spatrick     return;
613e5dd7070Spatrick   const Expr *Init = VD->getInit();
614a9ac8606Spatrick   bool IsSharedVar = VD->hasAttr<CUDASharedAttr>();
615a9ac8606Spatrick   bool IsDeviceOrConstantVar =
616a9ac8606Spatrick       !IsSharedVar &&
617a9ac8606Spatrick       (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>());
618a9ac8606Spatrick   if (IsDeviceOrConstantVar || IsSharedVar) {
619a9ac8606Spatrick     if (HasAllowedCUDADeviceStaticInitializer(
620a9ac8606Spatrick             *this, VD, IsSharedVar ? CICK_Shared : CICK_DeviceOrConstant))
621e5dd7070Spatrick       return;
622a9ac8606Spatrick     Diag(VD->getLocation(),
623a9ac8606Spatrick          IsSharedVar ? diag::err_shared_var_init : diag::err_dynamic_var_init)
624e5dd7070Spatrick         << Init->getSourceRange();
625e5dd7070Spatrick     VD->setInvalidDecl();
626e5dd7070Spatrick   } else {
627e5dd7070Spatrick     // This is a host-side global variable.  Check that the initializer is
628e5dd7070Spatrick     // callable from the host side.
629e5dd7070Spatrick     const FunctionDecl *InitFn = nullptr;
630e5dd7070Spatrick     if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) {
631e5dd7070Spatrick       InitFn = CE->getConstructor();
632e5dd7070Spatrick     } else if (const CallExpr *CE = dyn_cast<CallExpr>(Init)) {
633e5dd7070Spatrick       InitFn = CE->getDirectCallee();
634e5dd7070Spatrick     }
635e5dd7070Spatrick     if (InitFn) {
636e5dd7070Spatrick       CUDAFunctionTarget InitFnTarget = IdentifyCUDATarget(InitFn);
637e5dd7070Spatrick       if (InitFnTarget != CFT_Host && InitFnTarget != CFT_HostDevice) {
638e5dd7070Spatrick         Diag(VD->getLocation(), diag::err_ref_bad_target_global_initializer)
639e5dd7070Spatrick             << InitFnTarget << InitFn;
640e5dd7070Spatrick         Diag(InitFn->getLocation(), diag::note_previous_decl) << InitFn;
641e5dd7070Spatrick         VD->setInvalidDecl();
642e5dd7070Spatrick       }
643e5dd7070Spatrick     }
644e5dd7070Spatrick   }
645e5dd7070Spatrick }
646e5dd7070Spatrick 
647e5dd7070Spatrick // With -fcuda-host-device-constexpr, an unattributed constexpr function is
648e5dd7070Spatrick // treated as implicitly __host__ __device__, unless:
649e5dd7070Spatrick //  * it is a variadic function (device-side variadic functions are not
650e5dd7070Spatrick //    allowed), or
651e5dd7070Spatrick //  * a __device__ function with this signature was already declared, in which
652e5dd7070Spatrick //    case in which case we output an error, unless the __device__ decl is in a
653e5dd7070Spatrick //    system header, in which case we leave the constexpr function unattributed.
654e5dd7070Spatrick //
655e5dd7070Spatrick // In addition, all function decls are treated as __host__ __device__ when
656e5dd7070Spatrick // ForceCUDAHostDeviceDepth > 0 (corresponding to code within a
657e5dd7070Spatrick //   #pragma clang force_cuda_host_device_begin/end
658e5dd7070Spatrick // pair).
maybeAddCUDAHostDeviceAttrs(FunctionDecl * NewD,const LookupResult & Previous)659e5dd7070Spatrick void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD,
660e5dd7070Spatrick                                        const LookupResult &Previous) {
661e5dd7070Spatrick   assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
662e5dd7070Spatrick 
663e5dd7070Spatrick   if (ForceCUDAHostDeviceDepth > 0) {
664e5dd7070Spatrick     if (!NewD->hasAttr<CUDAHostAttr>())
665e5dd7070Spatrick       NewD->addAttr(CUDAHostAttr::CreateImplicit(Context));
666e5dd7070Spatrick     if (!NewD->hasAttr<CUDADeviceAttr>())
667e5dd7070Spatrick       NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
668e5dd7070Spatrick     return;
669e5dd7070Spatrick   }
670e5dd7070Spatrick 
671e5dd7070Spatrick   if (!getLangOpts().CUDAHostDeviceConstexpr || !NewD->isConstexpr() ||
672e5dd7070Spatrick       NewD->isVariadic() || NewD->hasAttr<CUDAHostAttr>() ||
673e5dd7070Spatrick       NewD->hasAttr<CUDADeviceAttr>() || NewD->hasAttr<CUDAGlobalAttr>())
674e5dd7070Spatrick     return;
675e5dd7070Spatrick 
676e5dd7070Spatrick   // Is D a __device__ function with the same signature as NewD, ignoring CUDA
677e5dd7070Spatrick   // attributes?
678e5dd7070Spatrick   auto IsMatchingDeviceFn = [&](NamedDecl *D) {
679e5dd7070Spatrick     if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(D))
680e5dd7070Spatrick       D = Using->getTargetDecl();
681e5dd7070Spatrick     FunctionDecl *OldD = D->getAsFunction();
682e5dd7070Spatrick     return OldD && OldD->hasAttr<CUDADeviceAttr>() &&
683e5dd7070Spatrick            !OldD->hasAttr<CUDAHostAttr>() &&
684e5dd7070Spatrick            !IsOverload(NewD, OldD, /* UseMemberUsingDeclRules = */ false,
685e5dd7070Spatrick                        /* ConsiderCudaAttrs = */ false);
686e5dd7070Spatrick   };
687e5dd7070Spatrick   auto It = llvm::find_if(Previous, IsMatchingDeviceFn);
688e5dd7070Spatrick   if (It != Previous.end()) {
689e5dd7070Spatrick     // We found a __device__ function with the same name and signature as NewD
690e5dd7070Spatrick     // (ignoring CUDA attrs).  This is an error unless that function is defined
691e5dd7070Spatrick     // in a system header, in which case we simply return without making NewD
692e5dd7070Spatrick     // host+device.
693e5dd7070Spatrick     NamedDecl *Match = *It;
694e5dd7070Spatrick     if (!getSourceManager().isInSystemHeader(Match->getLocation())) {
695e5dd7070Spatrick       Diag(NewD->getLocation(),
696e5dd7070Spatrick            diag::err_cuda_unattributed_constexpr_cannot_overload_device)
697e5dd7070Spatrick           << NewD;
698e5dd7070Spatrick       Diag(Match->getLocation(),
699e5dd7070Spatrick            diag::note_cuda_conflicting_device_function_declared_here);
700e5dd7070Spatrick     }
701e5dd7070Spatrick     return;
702e5dd7070Spatrick   }
703e5dd7070Spatrick 
704e5dd7070Spatrick   NewD->addAttr(CUDAHostAttr::CreateImplicit(Context));
705e5dd7070Spatrick   NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
706e5dd7070Spatrick }
707e5dd7070Spatrick 
708a9ac8606Spatrick // TODO: `__constant__` memory may be a limited resource for certain targets.
709a9ac8606Spatrick // A safeguard may be needed at the end of compilation pipeline if
710a9ac8606Spatrick // `__constant__` memory usage goes beyond limit.
MaybeAddCUDAConstantAttr(VarDecl * VD)711ec727ea7Spatrick void Sema::MaybeAddCUDAConstantAttr(VarDecl *VD) {
712a9ac8606Spatrick   // Do not promote dependent variables since the cotr/dtor/initializer are
713a9ac8606Spatrick   // not determined. Do it after instantiation.
714a9ac8606Spatrick   if (getLangOpts().CUDAIsDevice && !VD->hasAttr<CUDAConstantAttr>() &&
715*12c85518Srobert       !VD->hasAttr<CUDASharedAttr>() &&
716a9ac8606Spatrick       (VD->isFileVarDecl() || VD->isStaticDataMember()) &&
717a9ac8606Spatrick       !IsDependentVar(VD) &&
718*12c85518Srobert       ((VD->isConstexpr() || VD->getType().isConstQualified()) &&
719*12c85518Srobert        HasAllowedCUDADeviceStaticInitializer(*this, VD,
720*12c85518Srobert                                              CICK_DeviceOrConstant))) {
721ec727ea7Spatrick     VD->addAttr(CUDAConstantAttr::CreateImplicit(getASTContext()));
722ec727ea7Spatrick   }
723ec727ea7Spatrick }
724ec727ea7Spatrick 
CUDADiagIfDeviceCode(SourceLocation Loc,unsigned DiagID)725a9ac8606Spatrick Sema::SemaDiagnosticBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc,
726e5dd7070Spatrick                                                        unsigned DiagID) {
727e5dd7070Spatrick   assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
728*12c85518Srobert   FunctionDecl *CurFunContext = getCurFunctionDecl(/*AllowLambda=*/true);
729a9ac8606Spatrick   SemaDiagnosticBuilder::Kind DiagKind = [&] {
730*12c85518Srobert     if (!CurFunContext)
731a9ac8606Spatrick       return SemaDiagnosticBuilder::K_Nop;
732e5dd7070Spatrick     switch (CurrentCUDATarget()) {
733e5dd7070Spatrick     case CFT_Global:
734e5dd7070Spatrick     case CFT_Device:
735a9ac8606Spatrick       return SemaDiagnosticBuilder::K_Immediate;
736e5dd7070Spatrick     case CFT_HostDevice:
737e5dd7070Spatrick       // An HD function counts as host code if we're compiling for host, and
738e5dd7070Spatrick       // device code if we're compiling for device.  Defer any errors in device
739e5dd7070Spatrick       // mode until the function is known-emitted.
740a9ac8606Spatrick       if (!getLangOpts().CUDAIsDevice)
741a9ac8606Spatrick         return SemaDiagnosticBuilder::K_Nop;
742a9ac8606Spatrick       if (IsLastErrorImmediate && Diags.getDiagnosticIDs()->isBuiltinNote(DiagID))
743a9ac8606Spatrick         return SemaDiagnosticBuilder::K_Immediate;
744*12c85518Srobert       return (getEmissionStatus(CurFunContext) ==
745e5dd7070Spatrick               FunctionEmissionStatus::Emitted)
746a9ac8606Spatrick                  ? SemaDiagnosticBuilder::K_ImmediateWithCallStack
747a9ac8606Spatrick                  : SemaDiagnosticBuilder::K_Deferred;
748e5dd7070Spatrick     default:
749a9ac8606Spatrick       return SemaDiagnosticBuilder::K_Nop;
750e5dd7070Spatrick     }
751e5dd7070Spatrick   }();
752*12c85518Srobert   return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, CurFunContext, *this);
753e5dd7070Spatrick }
754e5dd7070Spatrick 
CUDADiagIfHostCode(SourceLocation Loc,unsigned DiagID)755a9ac8606Spatrick Sema::SemaDiagnosticBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc,
756e5dd7070Spatrick                                                      unsigned DiagID) {
757e5dd7070Spatrick   assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
758*12c85518Srobert   FunctionDecl *CurFunContext = getCurFunctionDecl(/*AllowLambda=*/true);
759a9ac8606Spatrick   SemaDiagnosticBuilder::Kind DiagKind = [&] {
760*12c85518Srobert     if (!CurFunContext)
761a9ac8606Spatrick       return SemaDiagnosticBuilder::K_Nop;
762e5dd7070Spatrick     switch (CurrentCUDATarget()) {
763e5dd7070Spatrick     case CFT_Host:
764a9ac8606Spatrick       return SemaDiagnosticBuilder::K_Immediate;
765e5dd7070Spatrick     case CFT_HostDevice:
766e5dd7070Spatrick       // An HD function counts as host code if we're compiling for host, and
767e5dd7070Spatrick       // device code if we're compiling for device.  Defer any errors in device
768e5dd7070Spatrick       // mode until the function is known-emitted.
769e5dd7070Spatrick       if (getLangOpts().CUDAIsDevice)
770a9ac8606Spatrick         return SemaDiagnosticBuilder::K_Nop;
771a9ac8606Spatrick       if (IsLastErrorImmediate && Diags.getDiagnosticIDs()->isBuiltinNote(DiagID))
772a9ac8606Spatrick         return SemaDiagnosticBuilder::K_Immediate;
773*12c85518Srobert       return (getEmissionStatus(CurFunContext) ==
774e5dd7070Spatrick               FunctionEmissionStatus::Emitted)
775a9ac8606Spatrick                  ? SemaDiagnosticBuilder::K_ImmediateWithCallStack
776a9ac8606Spatrick                  : SemaDiagnosticBuilder::K_Deferred;
777e5dd7070Spatrick     default:
778a9ac8606Spatrick       return SemaDiagnosticBuilder::K_Nop;
779e5dd7070Spatrick     }
780e5dd7070Spatrick   }();
781*12c85518Srobert   return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, CurFunContext, *this);
782e5dd7070Spatrick }
783e5dd7070Spatrick 
CheckCUDACall(SourceLocation Loc,FunctionDecl * Callee)784e5dd7070Spatrick bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
785e5dd7070Spatrick   assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
786e5dd7070Spatrick   assert(Callee && "Callee may not be null.");
787e5dd7070Spatrick 
788e5dd7070Spatrick   auto &ExprEvalCtx = ExprEvalContexts.back();
789e5dd7070Spatrick   if (ExprEvalCtx.isUnevaluated() || ExprEvalCtx.isConstantEvaluated())
790e5dd7070Spatrick     return true;
791e5dd7070Spatrick 
792e5dd7070Spatrick   // FIXME: Is bailing out early correct here?  Should we instead assume that
793e5dd7070Spatrick   // the caller is a global initializer?
794*12c85518Srobert   FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true);
795e5dd7070Spatrick   if (!Caller)
796e5dd7070Spatrick     return true;
797e5dd7070Spatrick 
798e5dd7070Spatrick   // If the caller is known-emitted, mark the callee as known-emitted.
799e5dd7070Spatrick   // Otherwise, mark the call in our call graph so we can traverse it later.
800e5dd7070Spatrick   bool CallerKnownEmitted =
801e5dd7070Spatrick       getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted;
802a9ac8606Spatrick   SemaDiagnosticBuilder::Kind DiagKind = [this, Caller, Callee,
803e5dd7070Spatrick                                           CallerKnownEmitted] {
804e5dd7070Spatrick     switch (IdentifyCUDAPreference(Caller, Callee)) {
805e5dd7070Spatrick     case CFP_Never:
806e5dd7070Spatrick     case CFP_WrongSide:
807a9ac8606Spatrick       assert(Caller && "Never/wrongSide calls require a non-null caller");
808e5dd7070Spatrick       // If we know the caller will be emitted, we know this wrong-side call
809e5dd7070Spatrick       // will be emitted, so it's an immediate error.  Otherwise, defer the
810e5dd7070Spatrick       // error until we know the caller is emitted.
811a9ac8606Spatrick       return CallerKnownEmitted
812a9ac8606Spatrick                  ? SemaDiagnosticBuilder::K_ImmediateWithCallStack
813a9ac8606Spatrick                  : SemaDiagnosticBuilder::K_Deferred;
814e5dd7070Spatrick     default:
815a9ac8606Spatrick       return SemaDiagnosticBuilder::K_Nop;
816e5dd7070Spatrick     }
817e5dd7070Spatrick   }();
818e5dd7070Spatrick 
819*12c85518Srobert   if (DiagKind == SemaDiagnosticBuilder::K_Nop) {
820*12c85518Srobert     // For -fgpu-rdc, keep track of external kernels used by host functions.
821*12c85518Srobert     if (LangOpts.CUDAIsDevice && LangOpts.GPURelocatableDeviceCode &&
822*12c85518Srobert         Callee->hasAttr<CUDAGlobalAttr>() && !Callee->isDefined())
823*12c85518Srobert       getASTContext().CUDAExternalDeviceDeclODRUsedByHost.insert(Callee);
824e5dd7070Spatrick     return true;
825*12c85518Srobert   }
826e5dd7070Spatrick 
827e5dd7070Spatrick   // Avoid emitting this error twice for the same location.  Using a hashtable
828e5dd7070Spatrick   // like this is unfortunate, but because we must continue parsing as normal
829e5dd7070Spatrick   // after encountering a deferred error, it's otherwise very tricky for us to
830e5dd7070Spatrick   // ensure that we only emit this deferred error once.
831e5dd7070Spatrick   if (!LocsWithCUDACallDiags.insert({Caller, Loc}).second)
832e5dd7070Spatrick     return true;
833e5dd7070Spatrick 
834a9ac8606Spatrick   SemaDiagnosticBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller, *this)
835a9ac8606Spatrick       << IdentifyCUDATarget(Callee) << /*function*/ 0 << Callee
836a9ac8606Spatrick       << IdentifyCUDATarget(Caller);
837a9ac8606Spatrick   if (!Callee->getBuiltinID())
838a9ac8606Spatrick     SemaDiagnosticBuilder(DiagKind, Callee->getLocation(),
839a9ac8606Spatrick                           diag::note_previous_decl, Caller, *this)
840e5dd7070Spatrick         << Callee;
841a9ac8606Spatrick   return DiagKind != SemaDiagnosticBuilder::K_Immediate &&
842a9ac8606Spatrick          DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack;
843e5dd7070Spatrick }
844e5dd7070Spatrick 
845ec727ea7Spatrick // Check the wrong-sided reference capture of lambda for CUDA/HIP.
846ec727ea7Spatrick // A lambda function may capture a stack variable by reference when it is
847ec727ea7Spatrick // defined and uses the capture by reference when the lambda is called. When
848ec727ea7Spatrick // the capture and use happen on different sides, the capture is invalid and
849ec727ea7Spatrick // should be diagnosed.
CUDACheckLambdaCapture(CXXMethodDecl * Callee,const sema::Capture & Capture)850ec727ea7Spatrick void Sema::CUDACheckLambdaCapture(CXXMethodDecl *Callee,
851ec727ea7Spatrick                                   const sema::Capture &Capture) {
852ec727ea7Spatrick   // In host compilation we only need to check lambda functions emitted on host
853ec727ea7Spatrick   // side. In such lambda functions, a reference capture is invalid only
854ec727ea7Spatrick   // if the lambda structure is populated by a device function or kernel then
855ec727ea7Spatrick   // is passed to and called by a host function. However that is impossible,
856ec727ea7Spatrick   // since a device function or kernel can only call a device function, also a
857ec727ea7Spatrick   // kernel cannot pass a lambda back to a host function since we cannot
858ec727ea7Spatrick   // define a kernel argument type which can hold the lambda before the lambda
859ec727ea7Spatrick   // itself is defined.
860ec727ea7Spatrick   if (!LangOpts.CUDAIsDevice)
861ec727ea7Spatrick     return;
862ec727ea7Spatrick 
863ec727ea7Spatrick   // File-scope lambda can only do init captures for global variables, which
864ec727ea7Spatrick   // results in passing by value for these global variables.
865*12c85518Srobert   FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true);
866ec727ea7Spatrick   if (!Caller)
867ec727ea7Spatrick     return;
868ec727ea7Spatrick 
869ec727ea7Spatrick   // In device compilation, we only need to check lambda functions which are
870ec727ea7Spatrick   // emitted on device side. For such lambdas, a reference capture is invalid
871ec727ea7Spatrick   // only if the lambda structure is populated by a host function then passed
872ec727ea7Spatrick   // to and called in a device function or kernel.
873ec727ea7Spatrick   bool CalleeIsDevice = Callee->hasAttr<CUDADeviceAttr>();
874ec727ea7Spatrick   bool CallerIsHost =
875ec727ea7Spatrick       !Caller->hasAttr<CUDAGlobalAttr>() && !Caller->hasAttr<CUDADeviceAttr>();
876ec727ea7Spatrick   bool ShouldCheck = CalleeIsDevice && CallerIsHost;
877ec727ea7Spatrick   if (!ShouldCheck || !Capture.isReferenceCapture())
878ec727ea7Spatrick     return;
879a9ac8606Spatrick   auto DiagKind = SemaDiagnosticBuilder::K_Deferred;
880ec727ea7Spatrick   if (Capture.isVariableCapture()) {
881a9ac8606Spatrick     SemaDiagnosticBuilder(DiagKind, Capture.getLocation(),
882ec727ea7Spatrick                           diag::err_capture_bad_target, Callee, *this)
883ec727ea7Spatrick         << Capture.getVariable();
884ec727ea7Spatrick   } else if (Capture.isThisCapture()) {
885*12c85518Srobert     // Capture of this pointer is allowed since this pointer may be pointing to
886*12c85518Srobert     // managed memory which is accessible on both device and host sides. It only
887*12c85518Srobert     // results in invalid memory access if this pointer points to memory not
888*12c85518Srobert     // accessible on device side.
889a9ac8606Spatrick     SemaDiagnosticBuilder(DiagKind, Capture.getLocation(),
890*12c85518Srobert                           diag::warn_maybe_capture_bad_target_this_ptr, Callee,
891*12c85518Srobert                           *this);
892ec727ea7Spatrick   }
893ec727ea7Spatrick }
894ec727ea7Spatrick 
CUDASetLambdaAttrs(CXXMethodDecl * Method)895e5dd7070Spatrick void Sema::CUDASetLambdaAttrs(CXXMethodDecl *Method) {
896e5dd7070Spatrick   assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
897e5dd7070Spatrick   if (Method->hasAttr<CUDAHostAttr>() || Method->hasAttr<CUDADeviceAttr>())
898e5dd7070Spatrick     return;
899e5dd7070Spatrick   Method->addAttr(CUDADeviceAttr::CreateImplicit(Context));
900e5dd7070Spatrick   Method->addAttr(CUDAHostAttr::CreateImplicit(Context));
901e5dd7070Spatrick }
902e5dd7070Spatrick 
checkCUDATargetOverload(FunctionDecl * NewFD,const LookupResult & Previous)903e5dd7070Spatrick void Sema::checkCUDATargetOverload(FunctionDecl *NewFD,
904e5dd7070Spatrick                                    const LookupResult &Previous) {
905e5dd7070Spatrick   assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
906e5dd7070Spatrick   CUDAFunctionTarget NewTarget = IdentifyCUDATarget(NewFD);
907e5dd7070Spatrick   for (NamedDecl *OldND : Previous) {
908e5dd7070Spatrick     FunctionDecl *OldFD = OldND->getAsFunction();
909e5dd7070Spatrick     if (!OldFD)
910e5dd7070Spatrick       continue;
911e5dd7070Spatrick 
912e5dd7070Spatrick     CUDAFunctionTarget OldTarget = IdentifyCUDATarget(OldFD);
913e5dd7070Spatrick     // Don't allow HD and global functions to overload other functions with the
914e5dd7070Spatrick     // same signature.  We allow overloading based on CUDA attributes so that
915e5dd7070Spatrick     // functions can have different implementations on the host and device, but
916e5dd7070Spatrick     // HD/global functions "exist" in some sense on both the host and device, so
917e5dd7070Spatrick     // should have the same implementation on both sides.
918e5dd7070Spatrick     if (NewTarget != OldTarget &&
919e5dd7070Spatrick         ((NewTarget == CFT_HostDevice) || (OldTarget == CFT_HostDevice) ||
920e5dd7070Spatrick          (NewTarget == CFT_Global) || (OldTarget == CFT_Global)) &&
921e5dd7070Spatrick         !IsOverload(NewFD, OldFD, /* UseMemberUsingDeclRules = */ false,
922e5dd7070Spatrick                     /* ConsiderCudaAttrs = */ false)) {
923e5dd7070Spatrick       Diag(NewFD->getLocation(), diag::err_cuda_ovl_target)
924e5dd7070Spatrick           << NewTarget << NewFD->getDeclName() << OldTarget << OldFD;
925e5dd7070Spatrick       Diag(OldFD->getLocation(), diag::note_previous_declaration);
926e5dd7070Spatrick       NewFD->setInvalidDecl();
927e5dd7070Spatrick       break;
928e5dd7070Spatrick     }
929e5dd7070Spatrick   }
930e5dd7070Spatrick }
931e5dd7070Spatrick 
932e5dd7070Spatrick template <typename AttrTy>
copyAttrIfPresent(Sema & S,FunctionDecl * FD,const FunctionDecl & TemplateFD)933e5dd7070Spatrick static void copyAttrIfPresent(Sema &S, FunctionDecl *FD,
934e5dd7070Spatrick                               const FunctionDecl &TemplateFD) {
935e5dd7070Spatrick   if (AttrTy *Attribute = TemplateFD.getAttr<AttrTy>()) {
936e5dd7070Spatrick     AttrTy *Clone = Attribute->clone(S.Context);
937e5dd7070Spatrick     Clone->setInherited(true);
938e5dd7070Spatrick     FD->addAttr(Clone);
939e5dd7070Spatrick   }
940e5dd7070Spatrick }
941e5dd7070Spatrick 
inheritCUDATargetAttrs(FunctionDecl * FD,const FunctionTemplateDecl & TD)942e5dd7070Spatrick void Sema::inheritCUDATargetAttrs(FunctionDecl *FD,
943e5dd7070Spatrick                                   const FunctionTemplateDecl &TD) {
944e5dd7070Spatrick   const FunctionDecl &TemplateFD = *TD.getTemplatedDecl();
945e5dd7070Spatrick   copyAttrIfPresent<CUDAGlobalAttr>(*this, FD, TemplateFD);
946e5dd7070Spatrick   copyAttrIfPresent<CUDAHostAttr>(*this, FD, TemplateFD);
947e5dd7070Spatrick   copyAttrIfPresent<CUDADeviceAttr>(*this, FD, TemplateFD);
948e5dd7070Spatrick }
949e5dd7070Spatrick 
getCudaConfigureFuncName() const950e5dd7070Spatrick std::string Sema::getCudaConfigureFuncName() const {
951e5dd7070Spatrick   if (getLangOpts().HIP)
952e5dd7070Spatrick     return getLangOpts().HIPUseNewLaunchAPI ? "__hipPushCallConfiguration"
953e5dd7070Spatrick                                             : "hipConfigureCall";
954e5dd7070Spatrick 
955e5dd7070Spatrick   // New CUDA kernel launch sequence.
956e5dd7070Spatrick   if (CudaFeatureEnabled(Context.getTargetInfo().getSDKVersion(),
957e5dd7070Spatrick                          CudaFeature::CUDA_USES_NEW_LAUNCH))
958e5dd7070Spatrick     return "__cudaPushCallConfiguration";
959e5dd7070Spatrick 
960e5dd7070Spatrick   // Legacy CUDA kernel configuration call
961e5dd7070Spatrick   return "cudaConfigureCall";
962e5dd7070Spatrick }
963