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