]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp
Update mandoc to 20160116
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / Sema / SemaCUDA.cpp
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"
18 #include "clang/Sema/SemaDiagnostic.h"
19 #include "llvm/ADT/Optional.h"
20 #include "llvm/ADT/SmallVector.h"
21 using namespace clang;
22
23 ExprResult 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
41 Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) {
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
63 bool Sema::CheckCUDATarget(const FunctionDecl *Caller,
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
129 resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1,
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
152 bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
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.
166   llvm::SmallVector<const CXXBaseSpecifier *, 16> Bases;
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());
186     Sema::SpecialMemberOverloadResult *SMOR =
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());
230     Sema::SpecialMemberOverloadResult *SMOR =
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 }