blob: 60338212c694e2c7bc22e976a83a566598629eb3 [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
14#include "clang/Sema/Sema.h"
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/Decl.h"
Reid Klecknerbbc01782014-12-03 21:53:36 +000017#include "clang/Lex/Preprocessor.h"
Eli Bendersky7325e562014-09-03 15:27:03 +000018#include "clang/Sema/SemaDiagnostic.h"
Eli Bendersky9a220fc2014-09-29 20:38:29 +000019#include "llvm/ADT/Optional.h"
20#include "llvm/ADT/SmallVector.h"
Eli Bendersky7325e562014-09-03 15:27:03 +000021using namespace clang;
22
23ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc,
24 MultiExprArg ExecConfig,
25 SourceLocation GGGLoc) {
26 FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl();
27 if (!ConfigDecl)
28 return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use)
29 << "cudaConfigureCall");
30 QualType ConfigQTy = ConfigDecl->getType();
31
32 DeclRefExpr *ConfigDR = new (Context)
33 DeclRefExpr(ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc);
34 MarkFunctionReferenced(LLLLoc, ConfigDecl);
35
36 return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr,
37 /*IsExecConfig=*/true);
38}
39
40/// IdentifyCUDATarget - Determine the CUDA compilation target for this function
41Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) {
Eli Bendersky9a220fc2014-09-29 20:38:29 +000042 if (D->hasAttr<CUDAInvalidTargetAttr>())
43 return CFT_InvalidTarget;
Eli Bendersky7325e562014-09-03 15:27:03 +000044
45 if (D->hasAttr<CUDAGlobalAttr>())
46 return CFT_Global;
47
48 if (D->hasAttr<CUDADeviceAttr>()) {
49 if (D->hasAttr<CUDAHostAttr>())
50 return CFT_HostDevice;
51 return CFT_Device;
Eli Benderskyf2787a02014-09-30 17:38:34 +000052 } else if (D->hasAttr<CUDAHostAttr>()) {
53 return CFT_Host;
54 } else if (D->isImplicit()) {
55 // Some implicit declarations (like intrinsic functions) are not marked.
56 // Set the most lenient target on them for maximal flexibility.
57 return CFT_HostDevice;
Eli Bendersky7325e562014-09-03 15:27:03 +000058 }
59
60 return CFT_Host;
61}
62
Eli Bendersky9a220fc2014-09-29 20:38:29 +000063bool Sema::CheckCUDATarget(const FunctionDecl *Caller,
64 const FunctionDecl *Callee) {
Jacques Pienaar5bdd6772014-12-16 20:12:38 +000065 CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller),
66 CalleeTarget = IdentifyCUDATarget(Callee);
Eli Bendersky9a220fc2014-09-29 20:38:29 +000067
Eli Bendersky9a220fc2014-09-29 20:38:29 +000068 // If one of the targets is invalid, the check always fails, no matter what
69 // the other target is.
70 if (CallerTarget == CFT_InvalidTarget || CalleeTarget == CFT_InvalidTarget)
71 return true;
72
Reid Klecknerbbc01782014-12-03 21:53:36 +000073 // CUDA B.1.1 "The __device__ qualifier declares a function that is [...]
Eli Bendersky7325e562014-09-03 15:27:03 +000074 // Callable from the device only."
75 if (CallerTarget == CFT_Host && CalleeTarget == CFT_Device)
76 return true;
77
Reid Klecknerbbc01782014-12-03 21:53:36 +000078 // CUDA B.1.2 "The __global__ qualifier declares a function that is [...]
Eli Bendersky7325e562014-09-03 15:27:03 +000079 // Callable from the host only."
Reid Klecknerbbc01782014-12-03 21:53:36 +000080 // CUDA B.1.3 "The __host__ qualifier declares a function that is [...]
Eli Bendersky7325e562014-09-03 15:27:03 +000081 // Callable from the host only."
82 if ((CallerTarget == CFT_Device || CallerTarget == CFT_Global) &&
83 (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global))
84 return true;
85
Reid Klecknerbbc01782014-12-03 21:53:36 +000086 // CUDA B.1.3 "The __device__ and __host__ qualifiers can be used together
87 // however, in which case the function is compiled for both the host and the
88 // device. The __CUDA_ARCH__ macro [...] can be used to differentiate code
89 // paths between host and device."
Reid Klecknerbbc01782014-12-03 21:53:36 +000090 if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice) {
Jacques Pienaar5bdd6772014-12-16 20:12:38 +000091 // If the caller is implicit then the check always passes.
92 if (Caller->isImplicit()) return false;
93
94 bool InDeviceMode = getLangOpts().CUDAIsDevice;
Jacques Pienaara50178c2015-02-24 21:45:33 +000095 if (!InDeviceMode && CalleeTarget != CFT_Host)
96 return true;
97 if (InDeviceMode && CalleeTarget != CFT_Device) {
98 // Allow host device functions to call host functions if explicitly
99 // requested.
100 if (CalleeTarget == CFT_Host &&
101 getLangOpts().CUDAAllowHostCallsFromHostDevice) {
102 Diag(Caller->getLocation(),
103 diag::warn_host_calls_from_host_device)
104 << Callee->getNameAsString() << Caller->getNameAsString();
105 return false;
106 }
107
Reid Klecknerbbc01782014-12-03 21:53:36 +0000108 return true;
Jacques Pienaara50178c2015-02-24 21:45:33 +0000109 }
Reid Klecknerbbc01782014-12-03 21:53:36 +0000110 }
Eli Bendersky7325e562014-09-03 15:27:03 +0000111
112 return false;
113}
114
Eli Bendersky9a220fc2014-09-29 20:38:29 +0000115/// When an implicitly-declared special member has to invoke more than one
116/// base/field special member, conflicts may occur in the targets of these
117/// members. For example, if one base's member __host__ and another's is
118/// __device__, it's a conflict.
119/// This function figures out if the given targets \param Target1 and
120/// \param Target2 conflict, and if they do not it fills in
121/// \param ResolvedTarget with a target that resolves for both calls.
122/// \return true if there's a conflict, false otherwise.
123static bool
124resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1,
125 Sema::CUDAFunctionTarget Target2,
126 Sema::CUDAFunctionTarget *ResolvedTarget) {
127 if (Target1 == Sema::CFT_Global && Target2 == Sema::CFT_Global) {
128 // TODO: this shouldn't happen, really. Methods cannot be marked __global__.
129 // Clang should detect this earlier and produce an error. Then this
130 // condition can be changed to an assertion.
131 return true;
132 }
133
134 if (Target1 == Sema::CFT_HostDevice) {
135 *ResolvedTarget = Target2;
136 } else if (Target2 == Sema::CFT_HostDevice) {
137 *ResolvedTarget = Target1;
138 } else if (Target1 != Target2) {
139 return true;
140 } else {
141 *ResolvedTarget = Target1;
142 }
143
144 return false;
145}
146
147bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
148 CXXSpecialMember CSM,
149 CXXMethodDecl *MemberDecl,
150 bool ConstRHS,
151 bool Diagnose) {
152 llvm::Optional<CUDAFunctionTarget> InferredTarget;
153
154 // We're going to invoke special member lookup; mark that these special
155 // members are called from this one, and not from its caller.
156 ContextRAII MethodContext(*this, MemberDecl);
157
158 // Look for special members in base classes that should be invoked from here.
159 // Infer the target of this member base on the ones it should call.
160 // Skip direct and indirect virtual bases for abstract classes.
161 llvm::SmallVector<const CXXBaseSpecifier *, 16> Bases;
162 for (const auto &B : ClassDecl->bases()) {
163 if (!B.isVirtual()) {
164 Bases.push_back(&B);
165 }
166 }
167
168 if (!ClassDecl->isAbstract()) {
169 for (const auto &VB : ClassDecl->vbases()) {
170 Bases.push_back(&VB);
171 }
172 }
173
174 for (const auto *B : Bases) {
175 const RecordType *BaseType = B->getType()->getAs<RecordType>();
176 if (!BaseType) {
177 continue;
178 }
179
180 CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
181 Sema::SpecialMemberOverloadResult *SMOR =
182 LookupSpecialMember(BaseClassDecl, CSM,
183 /* ConstArg */ ConstRHS,
184 /* VolatileArg */ false,
185 /* RValueThis */ false,
186 /* ConstThis */ false,
187 /* VolatileThis */ false);
188
189 if (!SMOR || !SMOR->getMethod()) {
190 continue;
191 }
192
193 CUDAFunctionTarget BaseMethodTarget = IdentifyCUDATarget(SMOR->getMethod());
194 if (!InferredTarget.hasValue()) {
195 InferredTarget = BaseMethodTarget;
196 } else {
197 bool ResolutionError = resolveCalleeCUDATargetConflict(
198 InferredTarget.getValue(), BaseMethodTarget,
199 InferredTarget.getPointer());
200 if (ResolutionError) {
201 if (Diagnose) {
202 Diag(ClassDecl->getLocation(),
203 diag::note_implicit_member_target_infer_collision)
204 << (unsigned)CSM << InferredTarget.getValue() << BaseMethodTarget;
205 }
206 MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
207 return true;
208 }
209 }
210 }
211
212 // Same as for bases, but now for special members of fields.
213 for (const auto *F : ClassDecl->fields()) {
214 if (F->isInvalidDecl()) {
215 continue;
216 }
217
218 const RecordType *FieldType =
219 Context.getBaseElementType(F->getType())->getAs<RecordType>();
220 if (!FieldType) {
221 continue;
222 }
223
224 CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(FieldType->getDecl());
225 Sema::SpecialMemberOverloadResult *SMOR =
226 LookupSpecialMember(FieldRecDecl, CSM,
227 /* ConstArg */ ConstRHS && !F->isMutable(),
228 /* VolatileArg */ false,
229 /* RValueThis */ false,
230 /* ConstThis */ false,
231 /* VolatileThis */ false);
232
233 if (!SMOR || !SMOR->getMethod()) {
234 continue;
235 }
236
237 CUDAFunctionTarget FieldMethodTarget =
238 IdentifyCUDATarget(SMOR->getMethod());
239 if (!InferredTarget.hasValue()) {
240 InferredTarget = FieldMethodTarget;
241 } else {
242 bool ResolutionError = resolveCalleeCUDATargetConflict(
243 InferredTarget.getValue(), FieldMethodTarget,
244 InferredTarget.getPointer());
245 if (ResolutionError) {
246 if (Diagnose) {
247 Diag(ClassDecl->getLocation(),
248 diag::note_implicit_member_target_infer_collision)
249 << (unsigned)CSM << InferredTarget.getValue()
250 << FieldMethodTarget;
251 }
252 MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
253 return true;
254 }
255 }
256 }
257
258 if (InferredTarget.hasValue()) {
259 if (InferredTarget.getValue() == CFT_Device) {
260 MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
261 } else if (InferredTarget.getValue() == CFT_Host) {
262 MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
263 } else {
264 MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
265 MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
266 }
267 } else {
268 // If no target was inferred, mark this member as __host__ __device__;
269 // it's the least restrictive option that can be invoked from any target.
270 MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
271 MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
272 }
273
274 return false;
275}