xref: /aosp_15_r20/external/clang/lib/Sema/SemaCUDA.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li //===--- SemaCUDA.cpp - Semantic Analysis for CUDA constructs -------------===//
2*67e74705SXin Li //
3*67e74705SXin Li //                     The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li /// \file
10*67e74705SXin Li /// \brief This file implements semantic analysis for CUDA constructs.
11*67e74705SXin Li ///
12*67e74705SXin Li //===----------------------------------------------------------------------===//
13*67e74705SXin Li 
14*67e74705SXin Li #include "clang/AST/ASTContext.h"
15*67e74705SXin Li #include "clang/AST/Decl.h"
16*67e74705SXin Li #include "clang/AST/ExprCXX.h"
17*67e74705SXin Li #include "clang/Lex/Preprocessor.h"
18*67e74705SXin Li #include "clang/Sema/Lookup.h"
19*67e74705SXin Li #include "clang/Sema/Sema.h"
20*67e74705SXin Li #include "clang/Sema/SemaDiagnostic.h"
21*67e74705SXin Li #include "clang/Sema/Template.h"
22*67e74705SXin Li #include "llvm/ADT/Optional.h"
23*67e74705SXin Li #include "llvm/ADT/SmallVector.h"
24*67e74705SXin Li using namespace clang;
25*67e74705SXin Li 
ActOnCUDAExecConfigExpr(Scope * S,SourceLocation LLLLoc,MultiExprArg ExecConfig,SourceLocation GGGLoc)26*67e74705SXin Li ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
27*67e74705SXin Li                                          MultiExprArg ExecConfig,
28*67e74705SXin Li                                          SourceLocation GGGLoc) {
29*67e74705SXin Li   FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl();
30*67e74705SXin Li   if (!ConfigDecl)
31*67e74705SXin Li     return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use)
32*67e74705SXin Li                      << "cudaConfigureCall");
33*67e74705SXin Li   QualType ConfigQTy = ConfigDecl->getType();
34*67e74705SXin Li 
35*67e74705SXin Li   DeclRefExpr *ConfigDR = new (Context)
36*67e74705SXin Li       DeclRefExpr(ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc);
37*67e74705SXin Li   MarkFunctionReferenced(LLLLoc, ConfigDecl);
38*67e74705SXin Li 
39*67e74705SXin Li   return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr,
40*67e74705SXin Li                        /*IsExecConfig=*/true);
41*67e74705SXin Li }
42*67e74705SXin Li 
43*67e74705SXin Li /// IdentifyCUDATarget - Determine the CUDA compilation target for this function
IdentifyCUDATarget(const FunctionDecl * D)44*67e74705SXin Li Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) {
45*67e74705SXin Li   if (D->hasAttr<CUDAInvalidTargetAttr>())
46*67e74705SXin Li     return CFT_InvalidTarget;
47*67e74705SXin Li 
48*67e74705SXin Li   if (D->hasAttr<CUDAGlobalAttr>())
49*67e74705SXin Li     return CFT_Global;
50*67e74705SXin Li 
51*67e74705SXin Li   if (D->hasAttr<CUDADeviceAttr>()) {
52*67e74705SXin Li     if (D->hasAttr<CUDAHostAttr>())
53*67e74705SXin Li       return CFT_HostDevice;
54*67e74705SXin Li     return CFT_Device;
55*67e74705SXin Li   } else if (D->hasAttr<CUDAHostAttr>()) {
56*67e74705SXin Li     return CFT_Host;
57*67e74705SXin Li   } else if (D->isImplicit()) {
58*67e74705SXin Li     // Some implicit declarations (like intrinsic functions) are not marked.
59*67e74705SXin Li     // Set the most lenient target on them for maximal flexibility.
60*67e74705SXin Li     return CFT_HostDevice;
61*67e74705SXin Li   }
62*67e74705SXin Li 
63*67e74705SXin Li   return CFT_Host;
64*67e74705SXin Li }
65*67e74705SXin Li 
66*67e74705SXin Li // * CUDA Call preference table
67*67e74705SXin Li //
68*67e74705SXin Li // F - from,
69*67e74705SXin Li // T - to
70*67e74705SXin Li // Ph - preference in host mode
71*67e74705SXin Li // Pd - preference in device mode
72*67e74705SXin Li // H  - handled in (x)
73*67e74705SXin Li // Preferences: N:native, SS:same side, HD:host-device, WS:wrong side, --:never.
74*67e74705SXin Li //
75*67e74705SXin Li // | F  | T  | Ph  | Pd  |  H  |
76*67e74705SXin Li // |----+----+-----+-----+-----+
77*67e74705SXin Li // | d  | d  | N   | N   | (c) |
78*67e74705SXin Li // | d  | g  | --  | --  | (a) |
79*67e74705SXin Li // | d  | h  | --  | --  | (e) |
80*67e74705SXin Li // | d  | hd | HD  | HD  | (b) |
81*67e74705SXin Li // | g  | d  | N   | N   | (c) |
82*67e74705SXin Li // | g  | g  | --  | --  | (a) |
83*67e74705SXin Li // | g  | h  | --  | --  | (e) |
84*67e74705SXin Li // | g  | hd | HD  | HD  | (b) |
85*67e74705SXin Li // | h  | d  | --  | --  | (e) |
86*67e74705SXin Li // | h  | g  | N   | N   | (c) |
87*67e74705SXin Li // | h  | h  | N   | N   | (c) |
88*67e74705SXin Li // | h  | hd | HD  | HD  | (b) |
89*67e74705SXin Li // | hd | d  | WS  | SS  | (d) |
90*67e74705SXin Li // | hd | g  | SS  | --  |(d/a)|
91*67e74705SXin Li // | hd | h  | SS  | WS  | (d) |
92*67e74705SXin Li // | hd | hd | HD  | HD  | (b) |
93*67e74705SXin Li 
94*67e74705SXin Li Sema::CUDAFunctionPreference
IdentifyCUDAPreference(const FunctionDecl * Caller,const FunctionDecl * Callee)95*67e74705SXin Li Sema::IdentifyCUDAPreference(const FunctionDecl *Caller,
96*67e74705SXin Li                              const FunctionDecl *Callee) {
97*67e74705SXin Li   assert(Callee && "Callee must be valid.");
98*67e74705SXin Li   CUDAFunctionTarget CalleeTarget = IdentifyCUDATarget(Callee);
99*67e74705SXin Li   CUDAFunctionTarget CallerTarget =
100*67e74705SXin Li       (Caller != nullptr) ? IdentifyCUDATarget(Caller) : Sema::CFT_Host;
101*67e74705SXin Li 
102*67e74705SXin Li   // If one of the targets is invalid, the check always fails, no matter what
103*67e74705SXin Li   // the other target is.
104*67e74705SXin Li   if (CallerTarget == CFT_InvalidTarget || CalleeTarget == CFT_InvalidTarget)
105*67e74705SXin Li     return CFP_Never;
106*67e74705SXin Li 
107*67e74705SXin Li   // (a) Can't call global from some contexts until we support CUDA's
108*67e74705SXin Li   // dynamic parallelism.
109*67e74705SXin Li   if (CalleeTarget == CFT_Global &&
110*67e74705SXin Li       (CallerTarget == CFT_Global || CallerTarget == CFT_Device ||
111*67e74705SXin Li        (CallerTarget == CFT_HostDevice && getLangOpts().CUDAIsDevice)))
112*67e74705SXin Li     return CFP_Never;
113*67e74705SXin Li 
114*67e74705SXin Li   // (b) Calling HostDevice is OK for everyone.
115*67e74705SXin Li   if (CalleeTarget == CFT_HostDevice)
116*67e74705SXin Li     return CFP_HostDevice;
117*67e74705SXin Li 
118*67e74705SXin Li   // (c) Best case scenarios
119*67e74705SXin Li   if (CalleeTarget == CallerTarget ||
120*67e74705SXin Li       (CallerTarget == CFT_Host && CalleeTarget == CFT_Global) ||
121*67e74705SXin Li       (CallerTarget == CFT_Global && CalleeTarget == CFT_Device))
122*67e74705SXin Li     return CFP_Native;
123*67e74705SXin Li 
124*67e74705SXin Li   // (d) HostDevice behavior depends on compilation mode.
125*67e74705SXin Li   if (CallerTarget == CFT_HostDevice) {
126*67e74705SXin Li     // It's OK to call a compilation-mode matching function from an HD one.
127*67e74705SXin Li     if ((getLangOpts().CUDAIsDevice && CalleeTarget == CFT_Device) ||
128*67e74705SXin Li         (!getLangOpts().CUDAIsDevice &&
129*67e74705SXin Li          (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global)))
130*67e74705SXin Li       return CFP_SameSide;
131*67e74705SXin Li 
132*67e74705SXin Li     // Calls from HD to non-mode-matching functions (i.e., to host functions
133*67e74705SXin Li     // when compiling in device mode or to device functions when compiling in
134*67e74705SXin Li     // host mode) are allowed at the sema level, but eventually rejected if
135*67e74705SXin Li     // they're ever codegened.  TODO: Reject said calls earlier.
136*67e74705SXin Li     return CFP_WrongSide;
137*67e74705SXin Li   }
138*67e74705SXin Li 
139*67e74705SXin Li   // (e) Calling across device/host boundary is not something you should do.
140*67e74705SXin Li   if ((CallerTarget == CFT_Host && CalleeTarget == CFT_Device) ||
141*67e74705SXin Li       (CallerTarget == CFT_Device && CalleeTarget == CFT_Host) ||
142*67e74705SXin Li       (CallerTarget == CFT_Global && CalleeTarget == CFT_Host))
143*67e74705SXin Li     return CFP_Never;
144*67e74705SXin Li 
145*67e74705SXin Li   llvm_unreachable("All cases should've been handled by now.");
146*67e74705SXin Li }
147*67e74705SXin Li 
148*67e74705SXin Li template <typename T>
EraseUnwantedCUDAMatchesImpl(Sema & S,const FunctionDecl * Caller,llvm::SmallVectorImpl<T> & Matches,std::function<const FunctionDecl * (const T &)> FetchDecl)149*67e74705SXin Li static void EraseUnwantedCUDAMatchesImpl(
150*67e74705SXin Li     Sema &S, const FunctionDecl *Caller, llvm::SmallVectorImpl<T> &Matches,
151*67e74705SXin Li     std::function<const FunctionDecl *(const T &)> FetchDecl) {
152*67e74705SXin Li   if (Matches.size() <= 1)
153*67e74705SXin Li     return;
154*67e74705SXin Li 
155*67e74705SXin Li   // Gets the CUDA function preference for a call from Caller to Match.
156*67e74705SXin Li   auto GetCFP = [&](const T &Match) {
157*67e74705SXin Li     return S.IdentifyCUDAPreference(Caller, FetchDecl(Match));
158*67e74705SXin Li   };
159*67e74705SXin Li 
160*67e74705SXin Li   // Find the best call preference among the functions in Matches.
161*67e74705SXin Li   Sema::CUDAFunctionPreference BestCFP = GetCFP(*std::max_element(
162*67e74705SXin Li       Matches.begin(), Matches.end(),
163*67e74705SXin Li       [&](const T &M1, const T &M2) { return GetCFP(M1) < GetCFP(M2); }));
164*67e74705SXin Li 
165*67e74705SXin Li   // Erase all functions with lower priority.
166*67e74705SXin Li   Matches.erase(
167*67e74705SXin Li       llvm::remove_if(Matches,
168*67e74705SXin Li                       [&](const T &Match) { return GetCFP(Match) < BestCFP; }),
169*67e74705SXin Li       Matches.end());
170*67e74705SXin Li }
171*67e74705SXin Li 
EraseUnwantedCUDAMatches(const FunctionDecl * Caller,SmallVectorImpl<FunctionDecl * > & Matches)172*67e74705SXin Li void Sema::EraseUnwantedCUDAMatches(const FunctionDecl *Caller,
173*67e74705SXin Li                                     SmallVectorImpl<FunctionDecl *> &Matches){
174*67e74705SXin Li   EraseUnwantedCUDAMatchesImpl<FunctionDecl *>(
175*67e74705SXin Li       *this, Caller, Matches, [](const FunctionDecl *item) { return item; });
176*67e74705SXin Li }
177*67e74705SXin Li 
EraseUnwantedCUDAMatches(const FunctionDecl * Caller,SmallVectorImpl<DeclAccessPair> & Matches)178*67e74705SXin Li void Sema::EraseUnwantedCUDAMatches(const FunctionDecl *Caller,
179*67e74705SXin Li                                     SmallVectorImpl<DeclAccessPair> &Matches) {
180*67e74705SXin Li   EraseUnwantedCUDAMatchesImpl<DeclAccessPair>(
181*67e74705SXin Li       *this, Caller, Matches, [](const DeclAccessPair &item) {
182*67e74705SXin Li         return dyn_cast<FunctionDecl>(item.getDecl());
183*67e74705SXin Li       });
184*67e74705SXin Li }
185*67e74705SXin Li 
EraseUnwantedCUDAMatches(const FunctionDecl * Caller,SmallVectorImpl<std::pair<DeclAccessPair,FunctionDecl * >> & Matches)186*67e74705SXin Li void Sema::EraseUnwantedCUDAMatches(
187*67e74705SXin Li     const FunctionDecl *Caller,
188*67e74705SXin Li     SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>> &Matches){
189*67e74705SXin Li   EraseUnwantedCUDAMatchesImpl<std::pair<DeclAccessPair, FunctionDecl *>>(
190*67e74705SXin Li       *this, Caller, Matches,
191*67e74705SXin Li       [](const std::pair<DeclAccessPair, FunctionDecl *> &item) {
192*67e74705SXin Li         return dyn_cast<FunctionDecl>(item.second);
193*67e74705SXin Li       });
194*67e74705SXin Li }
195*67e74705SXin Li 
196*67e74705SXin Li /// When an implicitly-declared special member has to invoke more than one
197*67e74705SXin Li /// base/field special member, conflicts may occur in the targets of these
198*67e74705SXin Li /// members. For example, if one base's member __host__ and another's is
199*67e74705SXin Li /// __device__, it's a conflict.
200*67e74705SXin Li /// This function figures out if the given targets \param Target1 and
201*67e74705SXin Li /// \param Target2 conflict, and if they do not it fills in
202*67e74705SXin Li /// \param ResolvedTarget with a target that resolves for both calls.
203*67e74705SXin Li /// \return true if there's a conflict, false otherwise.
204*67e74705SXin Li static bool
resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1,Sema::CUDAFunctionTarget Target2,Sema::CUDAFunctionTarget * ResolvedTarget)205*67e74705SXin Li resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1,
206*67e74705SXin Li                                 Sema::CUDAFunctionTarget Target2,
207*67e74705SXin Li                                 Sema::CUDAFunctionTarget *ResolvedTarget) {
208*67e74705SXin Li   // Only free functions and static member functions may be global.
209*67e74705SXin Li   assert(Target1 != Sema::CFT_Global);
210*67e74705SXin Li   assert(Target2 != Sema::CFT_Global);
211*67e74705SXin Li 
212*67e74705SXin Li   if (Target1 == Sema::CFT_HostDevice) {
213*67e74705SXin Li     *ResolvedTarget = Target2;
214*67e74705SXin Li   } else if (Target2 == Sema::CFT_HostDevice) {
215*67e74705SXin Li     *ResolvedTarget = Target1;
216*67e74705SXin Li   } else if (Target1 != Target2) {
217*67e74705SXin Li     return true;
218*67e74705SXin Li   } else {
219*67e74705SXin Li     *ResolvedTarget = Target1;
220*67e74705SXin Li   }
221*67e74705SXin Li 
222*67e74705SXin Li   return false;
223*67e74705SXin Li }
224*67e74705SXin Li 
inferCUDATargetForImplicitSpecialMember(CXXRecordDecl * ClassDecl,CXXSpecialMember CSM,CXXMethodDecl * MemberDecl,bool ConstRHS,bool Diagnose)225*67e74705SXin Li bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
226*67e74705SXin Li                                                    CXXSpecialMember CSM,
227*67e74705SXin Li                                                    CXXMethodDecl *MemberDecl,
228*67e74705SXin Li                                                    bool ConstRHS,
229*67e74705SXin Li                                                    bool Diagnose) {
230*67e74705SXin Li   llvm::Optional<CUDAFunctionTarget> InferredTarget;
231*67e74705SXin Li 
232*67e74705SXin Li   // We're going to invoke special member lookup; mark that these special
233*67e74705SXin Li   // members are called from this one, and not from its caller.
234*67e74705SXin Li   ContextRAII MethodContext(*this, MemberDecl);
235*67e74705SXin Li 
236*67e74705SXin Li   // Look for special members in base classes that should be invoked from here.
237*67e74705SXin Li   // Infer the target of this member base on the ones it should call.
238*67e74705SXin Li   // Skip direct and indirect virtual bases for abstract classes.
239*67e74705SXin Li   llvm::SmallVector<const CXXBaseSpecifier *, 16> Bases;
240*67e74705SXin Li   for (const auto &B : ClassDecl->bases()) {
241*67e74705SXin Li     if (!B.isVirtual()) {
242*67e74705SXin Li       Bases.push_back(&B);
243*67e74705SXin Li     }
244*67e74705SXin Li   }
245*67e74705SXin Li 
246*67e74705SXin Li   if (!ClassDecl->isAbstract()) {
247*67e74705SXin Li     for (const auto &VB : ClassDecl->vbases()) {
248*67e74705SXin Li       Bases.push_back(&VB);
249*67e74705SXin Li     }
250*67e74705SXin Li   }
251*67e74705SXin Li 
252*67e74705SXin Li   for (const auto *B : Bases) {
253*67e74705SXin Li     const RecordType *BaseType = B->getType()->getAs<RecordType>();
254*67e74705SXin Li     if (!BaseType) {
255*67e74705SXin Li       continue;
256*67e74705SXin Li     }
257*67e74705SXin Li 
258*67e74705SXin Li     CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
259*67e74705SXin Li     Sema::SpecialMemberOverloadResult *SMOR =
260*67e74705SXin Li         LookupSpecialMember(BaseClassDecl, CSM,
261*67e74705SXin Li                             /* ConstArg */ ConstRHS,
262*67e74705SXin Li                             /* VolatileArg */ false,
263*67e74705SXin Li                             /* RValueThis */ false,
264*67e74705SXin Li                             /* ConstThis */ false,
265*67e74705SXin Li                             /* VolatileThis */ false);
266*67e74705SXin Li 
267*67e74705SXin Li     if (!SMOR || !SMOR->getMethod()) {
268*67e74705SXin Li       continue;
269*67e74705SXin Li     }
270*67e74705SXin Li 
271*67e74705SXin Li     CUDAFunctionTarget BaseMethodTarget = IdentifyCUDATarget(SMOR->getMethod());
272*67e74705SXin Li     if (!InferredTarget.hasValue()) {
273*67e74705SXin Li       InferredTarget = BaseMethodTarget;
274*67e74705SXin Li     } else {
275*67e74705SXin Li       bool ResolutionError = resolveCalleeCUDATargetConflict(
276*67e74705SXin Li           InferredTarget.getValue(), BaseMethodTarget,
277*67e74705SXin Li           InferredTarget.getPointer());
278*67e74705SXin Li       if (ResolutionError) {
279*67e74705SXin Li         if (Diagnose) {
280*67e74705SXin Li           Diag(ClassDecl->getLocation(),
281*67e74705SXin Li                diag::note_implicit_member_target_infer_collision)
282*67e74705SXin Li               << (unsigned)CSM << InferredTarget.getValue() << BaseMethodTarget;
283*67e74705SXin Li         }
284*67e74705SXin Li         MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
285*67e74705SXin Li         return true;
286*67e74705SXin Li       }
287*67e74705SXin Li     }
288*67e74705SXin Li   }
289*67e74705SXin Li 
290*67e74705SXin Li   // Same as for bases, but now for special members of fields.
291*67e74705SXin Li   for (const auto *F : ClassDecl->fields()) {
292*67e74705SXin Li     if (F->isInvalidDecl()) {
293*67e74705SXin Li       continue;
294*67e74705SXin Li     }
295*67e74705SXin Li 
296*67e74705SXin Li     const RecordType *FieldType =
297*67e74705SXin Li         Context.getBaseElementType(F->getType())->getAs<RecordType>();
298*67e74705SXin Li     if (!FieldType) {
299*67e74705SXin Li       continue;
300*67e74705SXin Li     }
301*67e74705SXin Li 
302*67e74705SXin Li     CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(FieldType->getDecl());
303*67e74705SXin Li     Sema::SpecialMemberOverloadResult *SMOR =
304*67e74705SXin Li         LookupSpecialMember(FieldRecDecl, CSM,
305*67e74705SXin Li                             /* ConstArg */ ConstRHS && !F->isMutable(),
306*67e74705SXin Li                             /* VolatileArg */ false,
307*67e74705SXin Li                             /* RValueThis */ false,
308*67e74705SXin Li                             /* ConstThis */ false,
309*67e74705SXin Li                             /* VolatileThis */ false);
310*67e74705SXin Li 
311*67e74705SXin Li     if (!SMOR || !SMOR->getMethod()) {
312*67e74705SXin Li       continue;
313*67e74705SXin Li     }
314*67e74705SXin Li 
315*67e74705SXin Li     CUDAFunctionTarget FieldMethodTarget =
316*67e74705SXin Li         IdentifyCUDATarget(SMOR->getMethod());
317*67e74705SXin Li     if (!InferredTarget.hasValue()) {
318*67e74705SXin Li       InferredTarget = FieldMethodTarget;
319*67e74705SXin Li     } else {
320*67e74705SXin Li       bool ResolutionError = resolveCalleeCUDATargetConflict(
321*67e74705SXin Li           InferredTarget.getValue(), FieldMethodTarget,
322*67e74705SXin Li           InferredTarget.getPointer());
323*67e74705SXin Li       if (ResolutionError) {
324*67e74705SXin Li         if (Diagnose) {
325*67e74705SXin Li           Diag(ClassDecl->getLocation(),
326*67e74705SXin Li                diag::note_implicit_member_target_infer_collision)
327*67e74705SXin Li               << (unsigned)CSM << InferredTarget.getValue()
328*67e74705SXin Li               << FieldMethodTarget;
329*67e74705SXin Li         }
330*67e74705SXin Li         MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
331*67e74705SXin Li         return true;
332*67e74705SXin Li       }
333*67e74705SXin Li     }
334*67e74705SXin Li   }
335*67e74705SXin Li 
336*67e74705SXin Li   if (InferredTarget.hasValue()) {
337*67e74705SXin Li     if (InferredTarget.getValue() == CFT_Device) {
338*67e74705SXin Li       MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
339*67e74705SXin Li     } else if (InferredTarget.getValue() == CFT_Host) {
340*67e74705SXin Li       MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
341*67e74705SXin Li     } else {
342*67e74705SXin Li       MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
343*67e74705SXin Li       MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
344*67e74705SXin Li     }
345*67e74705SXin Li   } else {
346*67e74705SXin Li     // If no target was inferred, mark this member as __host__ __device__;
347*67e74705SXin Li     // it's the least restrictive option that can be invoked from any target.
348*67e74705SXin Li     MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
349*67e74705SXin Li     MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
350*67e74705SXin Li   }
351*67e74705SXin Li 
352*67e74705SXin Li   return false;
353*67e74705SXin Li }
354*67e74705SXin Li 
isEmptyCudaConstructor(SourceLocation Loc,CXXConstructorDecl * CD)355*67e74705SXin Li bool Sema::isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD) {
356*67e74705SXin Li   if (!CD->isDefined() && CD->isTemplateInstantiation())
357*67e74705SXin Li     InstantiateFunctionDefinition(Loc, CD->getFirstDecl());
358*67e74705SXin Li 
359*67e74705SXin Li   // (E.2.3.1, CUDA 7.5) A constructor for a class type is considered
360*67e74705SXin Li   // empty at a point in the translation unit, if it is either a
361*67e74705SXin Li   // trivial constructor
362*67e74705SXin Li   if (CD->isTrivial())
363*67e74705SXin Li     return true;
364*67e74705SXin Li 
365*67e74705SXin Li   // ... or it satisfies all of the following conditions:
366*67e74705SXin Li   // The constructor function has been defined.
367*67e74705SXin Li   // The constructor function has no parameters,
368*67e74705SXin Li   // and the function body is an empty compound statement.
369*67e74705SXin Li   if (!(CD->hasTrivialBody() && CD->getNumParams() == 0))
370*67e74705SXin Li     return false;
371*67e74705SXin Li 
372*67e74705SXin Li   // Its class has no virtual functions and no virtual base classes.
373*67e74705SXin Li   if (CD->getParent()->isDynamicClass())
374*67e74705SXin Li     return false;
375*67e74705SXin Li 
376*67e74705SXin Li   // The only form of initializer allowed is an empty constructor.
377*67e74705SXin Li   // This will recursively check all base classes and member initializers
378*67e74705SXin Li   if (!llvm::all_of(CD->inits(), [&](const CXXCtorInitializer *CI) {
379*67e74705SXin Li         if (const CXXConstructExpr *CE =
380*67e74705SXin Li                 dyn_cast<CXXConstructExpr>(CI->getInit()))
381*67e74705SXin Li           return isEmptyCudaConstructor(Loc, CE->getConstructor());
382*67e74705SXin Li         return false;
383*67e74705SXin Li       }))
384*67e74705SXin Li     return false;
385*67e74705SXin Li 
386*67e74705SXin Li   return true;
387*67e74705SXin Li }
388*67e74705SXin Li 
isEmptyCudaDestructor(SourceLocation Loc,CXXDestructorDecl * DD)389*67e74705SXin Li bool Sema::isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *DD) {
390*67e74705SXin Li   // No destructor -> no problem.
391*67e74705SXin Li   if (!DD)
392*67e74705SXin Li     return true;
393*67e74705SXin Li 
394*67e74705SXin Li   if (!DD->isDefined() && DD->isTemplateInstantiation())
395*67e74705SXin Li     InstantiateFunctionDefinition(Loc, DD->getFirstDecl());
396*67e74705SXin Li 
397*67e74705SXin Li   // (E.2.3.1, CUDA 7.5) A destructor for a class type is considered
398*67e74705SXin Li   // empty at a point in the translation unit, if it is either a
399*67e74705SXin Li   // trivial constructor
400*67e74705SXin Li   if (DD->isTrivial())
401*67e74705SXin Li     return true;
402*67e74705SXin Li 
403*67e74705SXin Li   // ... or it satisfies all of the following conditions:
404*67e74705SXin Li   // The destructor function has been defined.
405*67e74705SXin Li   // and the function body is an empty compound statement.
406*67e74705SXin Li   if (!DD->hasTrivialBody())
407*67e74705SXin Li     return false;
408*67e74705SXin Li 
409*67e74705SXin Li   const CXXRecordDecl *ClassDecl = DD->getParent();
410*67e74705SXin Li 
411*67e74705SXin Li   // Its class has no virtual functions and no virtual base classes.
412*67e74705SXin Li   if (ClassDecl->isDynamicClass())
413*67e74705SXin Li     return false;
414*67e74705SXin Li 
415*67e74705SXin Li   // Only empty destructors are allowed. This will recursively check
416*67e74705SXin Li   // destructors for all base classes...
417*67e74705SXin Li   if (!llvm::all_of(ClassDecl->bases(), [&](const CXXBaseSpecifier &BS) {
418*67e74705SXin Li         if (CXXRecordDecl *RD = BS.getType()->getAsCXXRecordDecl())
419*67e74705SXin Li           return isEmptyCudaDestructor(Loc, RD->getDestructor());
420*67e74705SXin Li         return true;
421*67e74705SXin Li       }))
422*67e74705SXin Li     return false;
423*67e74705SXin Li 
424*67e74705SXin Li   // ... and member fields.
425*67e74705SXin Li   if (!llvm::all_of(ClassDecl->fields(), [&](const FieldDecl *Field) {
426*67e74705SXin Li         if (CXXRecordDecl *RD = Field->getType()
427*67e74705SXin Li                                     ->getBaseElementTypeUnsafe()
428*67e74705SXin Li                                     ->getAsCXXRecordDecl())
429*67e74705SXin Li           return isEmptyCudaDestructor(Loc, RD->getDestructor());
430*67e74705SXin Li         return true;
431*67e74705SXin Li       }))
432*67e74705SXin Li     return false;
433*67e74705SXin Li 
434*67e74705SXin Li   return true;
435*67e74705SXin Li }
436*67e74705SXin Li 
437*67e74705SXin Li // With -fcuda-host-device-constexpr, an unattributed constexpr function is
438*67e74705SXin Li // treated as implicitly __host__ __device__, unless:
439*67e74705SXin Li //  * it is a variadic function (device-side variadic functions are not
440*67e74705SXin Li //    allowed), or
441*67e74705SXin Li //  * a __device__ function with this signature was already declared, in which
442*67e74705SXin Li //    case in which case we output an error, unless the __device__ decl is in a
443*67e74705SXin Li //    system header, in which case we leave the constexpr function unattributed.
maybeAddCUDAHostDeviceAttrs(Scope * S,FunctionDecl * NewD,const LookupResult & Previous)444*67e74705SXin Li void Sema::maybeAddCUDAHostDeviceAttrs(Scope *S, FunctionDecl *NewD,
445*67e74705SXin Li                                        const LookupResult &Previous) {
446*67e74705SXin Li   assert(getLangOpts().CUDA && "May be called only for CUDA compilations.");
447*67e74705SXin Li   if (!getLangOpts().CUDAHostDeviceConstexpr || !NewD->isConstexpr() ||
448*67e74705SXin Li       NewD->isVariadic() || NewD->hasAttr<CUDAHostAttr>() ||
449*67e74705SXin Li       NewD->hasAttr<CUDADeviceAttr>() || NewD->hasAttr<CUDAGlobalAttr>())
450*67e74705SXin Li     return;
451*67e74705SXin Li 
452*67e74705SXin Li   // Is D a __device__ function with the same signature as NewD, ignoring CUDA
453*67e74705SXin Li   // attributes?
454*67e74705SXin Li   auto IsMatchingDeviceFn = [&](NamedDecl *D) {
455*67e74705SXin Li     if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(D))
456*67e74705SXin Li       D = Using->getTargetDecl();
457*67e74705SXin Li     FunctionDecl *OldD = D->getAsFunction();
458*67e74705SXin Li     return OldD && OldD->hasAttr<CUDADeviceAttr>() &&
459*67e74705SXin Li            !OldD->hasAttr<CUDAHostAttr>() &&
460*67e74705SXin Li            !IsOverload(NewD, OldD, /* UseMemberUsingDeclRules = */ false,
461*67e74705SXin Li                        /* ConsiderCudaAttrs = */ false);
462*67e74705SXin Li   };
463*67e74705SXin Li   auto It = llvm::find_if(Previous, IsMatchingDeviceFn);
464*67e74705SXin Li   if (It != Previous.end()) {
465*67e74705SXin Li     // We found a __device__ function with the same name and signature as NewD
466*67e74705SXin Li     // (ignoring CUDA attrs).  This is an error unless that function is defined
467*67e74705SXin Li     // in a system header, in which case we simply return without making NewD
468*67e74705SXin Li     // host+device.
469*67e74705SXin Li     NamedDecl *Match = *It;
470*67e74705SXin Li     if (!getSourceManager().isInSystemHeader(Match->getLocation())) {
471*67e74705SXin Li       Diag(NewD->getLocation(),
472*67e74705SXin Li            diag::err_cuda_unattributed_constexpr_cannot_overload_device)
473*67e74705SXin Li           << NewD->getName();
474*67e74705SXin Li       Diag(Match->getLocation(),
475*67e74705SXin Li            diag::note_cuda_conflicting_device_function_declared_here);
476*67e74705SXin Li     }
477*67e74705SXin Li     return;
478*67e74705SXin Li   }
479*67e74705SXin Li 
480*67e74705SXin Li   NewD->addAttr(CUDAHostAttr::CreateImplicit(Context));
481*67e74705SXin Li   NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
482*67e74705SXin Li }
483