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