clang  3.7.0
SemaCUDA.cpp
Go to the documentation of this file.
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/Lex/Preprocessor.h"
19 #include "llvm/ADT/Optional.h"
20 #include "llvm/ADT/SmallVector.h"
21 using namespace clang;
22 
24  MultiExprArg ExecConfig,
25  SourceLocation GGGLoc) {
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
42  if (D->hasAttr<CUDAInvalidTargetAttr>())
43  return CFT_InvalidTarget;
44 
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;
52  } 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;
58  }
59 
60  return CFT_Host;
61 }
62 
64  const FunctionDecl *Callee) {
65  // The CUDADisableTargetCallChecks short-circuits this check: we assume all
66  // cross-target calls are valid.
67  if (getLangOpts().CUDADisableTargetCallChecks)
68  return false;
69 
70  CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller),
71  CalleeTarget = IdentifyCUDATarget(Callee);
72 
73  // If one of the targets is invalid, the check always fails, no matter what
74  // the other target is.
75  if (CallerTarget == CFT_InvalidTarget || CalleeTarget == CFT_InvalidTarget)
76  return true;
77 
78  // CUDA B.1.1 "The __device__ qualifier declares a function that is [...]
79  // Callable from the device only."
80  if (CallerTarget == CFT_Host && CalleeTarget == CFT_Device)
81  return true;
82 
83  // CUDA B.1.2 "The __global__ qualifier declares a function that is [...]
84  // Callable from the host only."
85  // CUDA B.1.3 "The __host__ qualifier declares a function that is [...]
86  // Callable from the host only."
87  if ((CallerTarget == CFT_Device || CallerTarget == CFT_Global) &&
88  (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global))
89  return true;
90 
91  // CUDA B.1.3 "The __device__ and __host__ qualifiers can be used together
92  // however, in which case the function is compiled for both the host and the
93  // device. The __CUDA_ARCH__ macro [...] can be used to differentiate code
94  // paths between host and device."
95  if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice) {
96  // If the caller is implicit then the check always passes.
97  if (Caller->isImplicit()) return false;
98 
99  bool InDeviceMode = getLangOpts().CUDAIsDevice;
100  if (!InDeviceMode && CalleeTarget != CFT_Host)
101  return true;
102  if (InDeviceMode && CalleeTarget != CFT_Device) {
103  // Allow host device functions to call host functions if explicitly
104  // requested.
105  if (CalleeTarget == CFT_Host &&
106  getLangOpts().CUDAAllowHostCallsFromHostDevice) {
107  Diag(Caller->getLocation(),
108  diag::warn_host_calls_from_host_device)
109  << Callee->getNameAsString() << Caller->getNameAsString();
110  return false;
111  }
112 
113  return true;
114  }
115  }
116 
117  return false;
118 }
119 
120 /// When an implicitly-declared special member has to invoke more than one
121 /// base/field special member, conflicts may occur in the targets of these
122 /// members. For example, if one base's member __host__ and another's is
123 /// __device__, it's a conflict.
124 /// This function figures out if the given targets \param Target1 and
125 /// \param Target2 conflict, and if they do not it fills in
126 /// \param ResolvedTarget with a target that resolves for both calls.
127 /// \return true if there's a conflict, false otherwise.
128 static bool
130  Sema::CUDAFunctionTarget Target2,
131  Sema::CUDAFunctionTarget *ResolvedTarget) {
132  if (Target1 == Sema::CFT_Global && Target2 == Sema::CFT_Global) {
133  // TODO: this shouldn't happen, really. Methods cannot be marked __global__.
134  // Clang should detect this earlier and produce an error. Then this
135  // condition can be changed to an assertion.
136  return true;
137  }
138 
139  if (Target1 == Sema::CFT_HostDevice) {
140  *ResolvedTarget = Target2;
141  } else if (Target2 == Sema::CFT_HostDevice) {
142  *ResolvedTarget = Target1;
143  } else if (Target1 != Target2) {
144  return true;
145  } else {
146  *ResolvedTarget = Target1;
147  }
148 
149  return false;
150 }
151 
153  CXXSpecialMember CSM,
154  CXXMethodDecl *MemberDecl,
155  bool ConstRHS,
156  bool Diagnose) {
157  llvm::Optional<CUDAFunctionTarget> InferredTarget;
158 
159  // We're going to invoke special member lookup; mark that these special
160  // members are called from this one, and not from its caller.
161  ContextRAII MethodContext(*this, MemberDecl);
162 
163  // Look for special members in base classes that should be invoked from here.
164  // Infer the target of this member base on the ones it should call.
165  // Skip direct and indirect virtual bases for abstract classes.
167  for (const auto &B : ClassDecl->bases()) {
168  if (!B.isVirtual()) {
169  Bases.push_back(&B);
170  }
171  }
172 
173  if (!ClassDecl->isAbstract()) {
174  for (const auto &VB : ClassDecl->vbases()) {
175  Bases.push_back(&VB);
176  }
177  }
178 
179  for (const auto *B : Bases) {
180  const RecordType *BaseType = B->getType()->getAs<RecordType>();
181  if (!BaseType) {
182  continue;
183  }
184 
185  CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
187  LookupSpecialMember(BaseClassDecl, CSM,
188  /* ConstArg */ ConstRHS,
189  /* VolatileArg */ false,
190  /* RValueThis */ false,
191  /* ConstThis */ false,
192  /* VolatileThis */ false);
193 
194  if (!SMOR || !SMOR->getMethod()) {
195  continue;
196  }
197 
198  CUDAFunctionTarget BaseMethodTarget = IdentifyCUDATarget(SMOR->getMethod());
199  if (!InferredTarget.hasValue()) {
200  InferredTarget = BaseMethodTarget;
201  } else {
202  bool ResolutionError = resolveCalleeCUDATargetConflict(
203  InferredTarget.getValue(), BaseMethodTarget,
204  InferredTarget.getPointer());
205  if (ResolutionError) {
206  if (Diagnose) {
207  Diag(ClassDecl->getLocation(),
208  diag::note_implicit_member_target_infer_collision)
209  << (unsigned)CSM << InferredTarget.getValue() << BaseMethodTarget;
210  }
211  MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
212  return true;
213  }
214  }
215  }
216 
217  // Same as for bases, but now for special members of fields.
218  for (const auto *F : ClassDecl->fields()) {
219  if (F->isInvalidDecl()) {
220  continue;
221  }
222 
223  const RecordType *FieldType =
224  Context.getBaseElementType(F->getType())->getAs<RecordType>();
225  if (!FieldType) {
226  continue;
227  }
228 
229  CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(FieldType->getDecl());
231  LookupSpecialMember(FieldRecDecl, CSM,
232  /* ConstArg */ ConstRHS && !F->isMutable(),
233  /* VolatileArg */ false,
234  /* RValueThis */ false,
235  /* ConstThis */ false,
236  /* VolatileThis */ false);
237 
238  if (!SMOR || !SMOR->getMethod()) {
239  continue;
240  }
241 
242  CUDAFunctionTarget FieldMethodTarget =
243  IdentifyCUDATarget(SMOR->getMethod());
244  if (!InferredTarget.hasValue()) {
245  InferredTarget = FieldMethodTarget;
246  } else {
247  bool ResolutionError = resolveCalleeCUDATargetConflict(
248  InferredTarget.getValue(), FieldMethodTarget,
249  InferredTarget.getPointer());
250  if (ResolutionError) {
251  if (Diagnose) {
252  Diag(ClassDecl->getLocation(),
253  diag::note_implicit_member_target_infer_collision)
254  << (unsigned)CSM << InferredTarget.getValue()
255  << FieldMethodTarget;
256  }
257  MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context));
258  return true;
259  }
260  }
261  }
262 
263  if (InferredTarget.hasValue()) {
264  if (InferredTarget.getValue() == CFT_Device) {
265  MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
266  } else if (InferredTarget.getValue() == CFT_Host) {
267  MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
268  } else {
269  MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
270  MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
271  }
272  } else {
273  // If no target was inferred, mark this member as __host__ __device__;
274  // it's the least restrictive option that can be invoked from any target.
275  MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
276  MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
277  }
278 
279  return false;
280 }
Defines the clang::ASTContext interface.
base_class_range bases()
Definition: DeclCXX.h:713
const LangOptions & getLangOpts() const
Definition: Sema.h:1019
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)
Emit a diagnostic.
Definition: Sema.h:1088
bool inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, CXXSpecialMember CSM, CXXMethodDecl *MemberDecl, bool ConstRHS, bool Diagnose)
Definition: SemaCUDA.cpp:152
SpecialMemberOverloadResult * LookupSpecialMember(CXXRecordDecl *D, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis)
ExprResult ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig=nullptr, bool IsExecConfig=false)
Definition: SemaExpr.cpp:4730
bool hasAttr() const
Definition: DeclBase.h:487
ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, MultiExprArg ExecConfig, SourceLocation GGGLoc)
Definition: SemaCUDA.cpp:23
bool isImplicit() const
Definition: DeclBase.h:503
field_range fields() const
Definition: Decl.h:3349
RecordDecl * getDecl() const
Definition: Type.h:3527
std::string getNameAsString() const
Definition: Decl.h:183
QualType getType() const
Definition: Decl.h:538
bool isAbstract() const
Determine whether this class has a pure virtual function.
Definition: DeclCXX.h:1155
CXXSpecialMember
Kinds of C++ special members.
Definition: Sema.h:965
bool CheckCUDATarget(const FunctionDecl *Caller, const FunctionDecl *Callee)
Definition: SemaCUDA.cpp:63
Defines the clang::Preprocessor interface.
void addAttr(Attr *A)
Definition: DeclBase.h:437
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D)
IdentifyCUDATarget - Determine the CUDA compilation target for this function.
Definition: SemaCUDA.cpp:41
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:1717
static bool resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1, Sema::CUDAFunctionTarget Target2, Sema::CUDAFunctionTarget *ResolvedTarget)
Definition: SemaCUDA.cpp:129
FunctionDecl * getcudaConfigureCallDecl()
Definition: ASTContext.h:1016
const T * getAs() const
Definition: Type.h:5555
Represents a C++ struct/union/class.
Definition: DeclCXX.h:285
CUDAFunctionTarget
Definition: Sema.h:8555
ExprResult ExprError()
Definition: Ownership.h:267
A reference to a declared variable, function, enum, etc. [C99 6.5.1p2].
Definition: Expr.h:899
void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, bool OdrUse=true)
Mark a function referenced, and check whether it is odr-used (C++ [basic.def.odr]p2, C99 6.9p3)
Definition: SemaExpr.cpp:12179
An l-value expression is a reference to an object with independent storage.
Definition: Specifiers.h:99
SourceLocation getLocation() const
Definition: DeclBase.h:372
ASTContext & Context
Definition: Sema.h:295
base_class_range vbases()
Definition: DeclCXX.h:730
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
A RAII object to temporarily push a declaration context.
Definition: Sema.h:601