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