Eli Bendersky | 7325e56 | 2014-09-03 15:27:03 +0000 | [diff] [blame] | 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" |
Artem Belevich | 97c01c3 | 2016-02-02 22:29:48 +0000 | [diff] [blame] | 17 | #include "clang/AST/ExprCXX.h" |
Reid Kleckner | bbc0178 | 2014-12-03 21:53:36 +0000 | [diff] [blame] | 18 | #include "clang/Lex/Preprocessor.h" |
Eli Bendersky | 7325e56 | 2014-09-03 15:27:03 +0000 | [diff] [blame] | 19 | #include "clang/Sema/SemaDiagnostic.h" |
Eli Bendersky | 9a220fc | 2014-09-29 20:38:29 +0000 | [diff] [blame] | 20 | #include "llvm/ADT/Optional.h" |
| 21 | #include "llvm/ADT/SmallVector.h" |
Eli Bendersky | 7325e56 | 2014-09-03 15:27:03 +0000 | [diff] [blame] | 22 | using namespace clang; |
| 23 | |
| 24 | ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, |
| 25 | MultiExprArg ExecConfig, |
| 26 | SourceLocation GGGLoc) { |
| 27 | FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl(); |
| 28 | if (!ConfigDecl) |
| 29 | return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use) |
| 30 | << "cudaConfigureCall"); |
| 31 | QualType ConfigQTy = ConfigDecl->getType(); |
| 32 | |
| 33 | DeclRefExpr *ConfigDR = new (Context) |
| 34 | DeclRefExpr(ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc); |
| 35 | MarkFunctionReferenced(LLLLoc, ConfigDecl); |
| 36 | |
| 37 | return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr, |
| 38 | /*IsExecConfig=*/true); |
| 39 | } |
| 40 | |
| 41 | /// IdentifyCUDATarget - Determine the CUDA compilation target for this function |
| 42 | Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) { |
Eli Bendersky | 9a220fc | 2014-09-29 20:38:29 +0000 | [diff] [blame] | 43 | if (D->hasAttr<CUDAInvalidTargetAttr>()) |
| 44 | return CFT_InvalidTarget; |
Eli Bendersky | 7325e56 | 2014-09-03 15:27:03 +0000 | [diff] [blame] | 45 | |
| 46 | if (D->hasAttr<CUDAGlobalAttr>()) |
| 47 | return CFT_Global; |
| 48 | |
| 49 | if (D->hasAttr<CUDADeviceAttr>()) { |
| 50 | if (D->hasAttr<CUDAHostAttr>()) |
| 51 | return CFT_HostDevice; |
| 52 | return CFT_Device; |
Eli Bendersky | f2787a0 | 2014-09-30 17:38:34 +0000 | [diff] [blame] | 53 | } else if (D->hasAttr<CUDAHostAttr>()) { |
| 54 | return CFT_Host; |
| 55 | } else if (D->isImplicit()) { |
| 56 | // Some implicit declarations (like intrinsic functions) are not marked. |
| 57 | // Set the most lenient target on them for maximal flexibility. |
| 58 | return CFT_HostDevice; |
Eli Bendersky | 7325e56 | 2014-09-03 15:27:03 +0000 | [diff] [blame] | 59 | } |
| 60 | |
| 61 | return CFT_Host; |
| 62 | } |
| 63 | |
Artem Belevich | 94a55e8 | 2015-09-22 17:22:59 +0000 | [diff] [blame] | 64 | // * CUDA Call preference table |
| 65 | // |
| 66 | // F - from, |
| 67 | // T - to |
| 68 | // Ph - preference in host mode |
| 69 | // Pd - preference in device mode |
| 70 | // H - handled in (x) |
Artem Belevich | 1860910 | 2016-02-12 18:29:18 +0000 | [diff] [blame^] | 71 | // Preferences: N:native, HD:host-device, SS:same side, WS:wrong side, --:never. |
Artem Belevich | 94a55e8 | 2015-09-22 17:22:59 +0000 | [diff] [blame] | 72 | // |
Artem Belevich | 1860910 | 2016-02-12 18:29:18 +0000 | [diff] [blame^] | 73 | // | F | T | Ph | Pd | H | |
| 74 | // |----+----+-----+-----+-----+ |
| 75 | // | d | d | N | N | (c) | |
| 76 | // | d | g | -- | -- | (a) | |
| 77 | // | d | h | -- | -- | (e) | |
| 78 | // | d | hd | HD | HD | (b) | |
| 79 | // | g | d | N | N | (c) | |
| 80 | // | g | g | -- | -- | (a) | |
| 81 | // | g | h | -- | -- | (e) | |
| 82 | // | g | hd | HD | HD | (b) | |
| 83 | // | h | d | -- | -- | (e) | |
| 84 | // | h | g | N | N | (c) | |
| 85 | // | h | h | N | N | (c) | |
| 86 | // | h | hd | HD | HD | (b) | |
| 87 | // | hd | d | WS | SS | (d) | |
| 88 | // | hd | g | SS | -- |(d/a)| |
| 89 | // | hd | h | SS | WS | (d) | |
| 90 | // | hd | hd | HD | HD | (b) | |
Artem Belevich | 94a55e8 | 2015-09-22 17:22:59 +0000 | [diff] [blame] | 91 | |
| 92 | Sema::CUDAFunctionPreference |
| 93 | Sema::IdentifyCUDAPreference(const FunctionDecl *Caller, |
| 94 | const FunctionDecl *Callee) { |
| 95 | assert(getLangOpts().CUDATargetOverloads && |
| 96 | "Should not be called w/o enabled target overloads."); |
| 97 | |
| 98 | assert(Callee && "Callee must be valid."); |
| 99 | CUDAFunctionTarget CalleeTarget = IdentifyCUDATarget(Callee); |
| 100 | CUDAFunctionTarget CallerTarget = |
| 101 | (Caller != nullptr) ? IdentifyCUDATarget(Caller) : Sema::CFT_Host; |
| 102 | |
| 103 | // If one of the targets is invalid, the check always fails, no matter what |
| 104 | // the other target is. |
| 105 | if (CallerTarget == CFT_InvalidTarget || CalleeTarget == CFT_InvalidTarget) |
| 106 | return CFP_Never; |
| 107 | |
| 108 | // (a) Can't call global from some contexts until we support CUDA's |
| 109 | // dynamic parallelism. |
| 110 | if (CalleeTarget == CFT_Global && |
| 111 | (CallerTarget == CFT_Global || CallerTarget == CFT_Device || |
| 112 | (CallerTarget == CFT_HostDevice && getLangOpts().CUDAIsDevice))) |
| 113 | return CFP_Never; |
| 114 | |
Artem Belevich | 1860910 | 2016-02-12 18:29:18 +0000 | [diff] [blame^] | 115 | // (b) Calling HostDevice is OK for everyone. |
| 116 | if (CalleeTarget == CFT_HostDevice) |
| 117 | return CFP_HostDevice; |
| 118 | |
| 119 | // (c) Best case scenarios |
Artem Belevich | 94a55e8 | 2015-09-22 17:22:59 +0000 | [diff] [blame] | 120 | if (CalleeTarget == CallerTarget || |
| 121 | (CallerTarget == CFT_Host && CalleeTarget == CFT_Global) || |
| 122 | (CallerTarget == CFT_Global && CalleeTarget == CFT_Device)) |
Artem Belevich | 1860910 | 2016-02-12 18:29:18 +0000 | [diff] [blame^] | 123 | return CFP_Native; |
Artem Belevich | 94a55e8 | 2015-09-22 17:22:59 +0000 | [diff] [blame] | 124 | |
| 125 | // (d) HostDevice behavior depends on compilation mode. |
| 126 | if (CallerTarget == CFT_HostDevice) { |
Artem Belevich | 1860910 | 2016-02-12 18:29:18 +0000 | [diff] [blame^] | 127 | // It's OK to call a compilation-mode matching function from an HD one. |
| 128 | if ((getLangOpts().CUDAIsDevice && CalleeTarget == CFT_Device) || |
| 129 | (!getLangOpts().CUDAIsDevice && |
| 130 | (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global))) |
| 131 | return CFP_SameSide; |
| 132 | |
| 133 | // We'll allow calls to non-mode-matching functions if target call |
| 134 | // checks are disabled. This is needed to avoid complaining about |
| 135 | // HD->H calls when we compile for device side and vice versa. |
| 136 | if (getLangOpts().CUDADisableTargetCallChecks) |
| 137 | return CFP_WrongSide; |
| 138 | |
| 139 | return CFP_Never; |
Artem Belevich | 94a55e8 | 2015-09-22 17:22:59 +0000 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | // (e) Calling across device/host boundary is not something you should do. |
| 143 | if ((CallerTarget == CFT_Host && CalleeTarget == CFT_Device) || |
| 144 | (CallerTarget == CFT_Device && CalleeTarget == CFT_Host) || |
| 145 | (CallerTarget == CFT_Global && CalleeTarget == CFT_Host)) |
Artem Belevich | 1860910 | 2016-02-12 18:29:18 +0000 | [diff] [blame^] | 146 | return CFP_Never; |
Artem Belevich | 94a55e8 | 2015-09-22 17:22:59 +0000 | [diff] [blame] | 147 | |
| 148 | llvm_unreachable("All cases should've been handled by now."); |
| 149 | } |
| 150 | |
Eli Bendersky | 9a220fc | 2014-09-29 20:38:29 +0000 | [diff] [blame] | 151 | bool Sema::CheckCUDATarget(const FunctionDecl *Caller, |
| 152 | const FunctionDecl *Callee) { |
Artem Belevich | 94a55e8 | 2015-09-22 17:22:59 +0000 | [diff] [blame] | 153 | // With target overloads enabled, we only disallow calling |
| 154 | // combinations with CFP_Never. |
| 155 | if (getLangOpts().CUDATargetOverloads) |
| 156 | return IdentifyCUDAPreference(Caller,Callee) == CFP_Never; |
| 157 | |
Eli Bendersky | 4bdc50e | 2015-04-15 22:27:06 +0000 | [diff] [blame] | 158 | // The CUDADisableTargetCallChecks short-circuits this check: we assume all |
| 159 | // cross-target calls are valid. |
| 160 | if (getLangOpts().CUDADisableTargetCallChecks) |
| 161 | return false; |
| 162 | |
Jacques Pienaar | 5bdd677 | 2014-12-16 20:12:38 +0000 | [diff] [blame] | 163 | CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller), |
| 164 | CalleeTarget = IdentifyCUDATarget(Callee); |
Eli Bendersky | 9a220fc | 2014-09-29 20:38:29 +0000 | [diff] [blame] | 165 | |
Eli Bendersky | 9a220fc | 2014-09-29 20:38:29 +0000 | [diff] [blame] | 166 | // If one of the targets is invalid, the check always fails, no matter what |
| 167 | // the other target is. |
| 168 | if (CallerTarget == CFT_InvalidTarget || CalleeTarget == CFT_InvalidTarget) |
| 169 | return true; |
| 170 | |
Reid Kleckner | bbc0178 | 2014-12-03 21:53:36 +0000 | [diff] [blame] | 171 | // CUDA B.1.1 "The __device__ qualifier declares a function that is [...] |
Eli Bendersky | 7325e56 | 2014-09-03 15:27:03 +0000 | [diff] [blame] | 172 | // Callable from the device only." |
| 173 | if (CallerTarget == CFT_Host && CalleeTarget == CFT_Device) |
| 174 | return true; |
| 175 | |
Reid Kleckner | bbc0178 | 2014-12-03 21:53:36 +0000 | [diff] [blame] | 176 | // CUDA B.1.2 "The __global__ qualifier declares a function that is [...] |
Eli Bendersky | 7325e56 | 2014-09-03 15:27:03 +0000 | [diff] [blame] | 177 | // Callable from the host only." |
Reid Kleckner | bbc0178 | 2014-12-03 21:53:36 +0000 | [diff] [blame] | 178 | // CUDA B.1.3 "The __host__ qualifier declares a function that is [...] |
Eli Bendersky | 7325e56 | 2014-09-03 15:27:03 +0000 | [diff] [blame] | 179 | // Callable from the host only." |
| 180 | if ((CallerTarget == CFT_Device || CallerTarget == CFT_Global) && |
| 181 | (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global)) |
| 182 | return true; |
| 183 | |
Reid Kleckner | bbc0178 | 2014-12-03 21:53:36 +0000 | [diff] [blame] | 184 | // CUDA B.1.3 "The __device__ and __host__ qualifiers can be used together |
| 185 | // however, in which case the function is compiled for both the host and the |
| 186 | // device. The __CUDA_ARCH__ macro [...] can be used to differentiate code |
| 187 | // paths between host and device." |
Reid Kleckner | bbc0178 | 2014-12-03 21:53:36 +0000 | [diff] [blame] | 188 | if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice) { |
Jacques Pienaar | 5bdd677 | 2014-12-16 20:12:38 +0000 | [diff] [blame] | 189 | // If the caller is implicit then the check always passes. |
| 190 | if (Caller->isImplicit()) return false; |
| 191 | |
| 192 | bool InDeviceMode = getLangOpts().CUDAIsDevice; |
Jacques Pienaar | a50178c | 2015-02-24 21:45:33 +0000 | [diff] [blame] | 193 | if (!InDeviceMode && CalleeTarget != CFT_Host) |
| 194 | return true; |
| 195 | if (InDeviceMode && CalleeTarget != CFT_Device) { |
| 196 | // Allow host device functions to call host functions if explicitly |
| 197 | // requested. |
| 198 | if (CalleeTarget == CFT_Host && |
| 199 | getLangOpts().CUDAAllowHostCallsFromHostDevice) { |
| 200 | Diag(Caller->getLocation(), |
| 201 | diag::warn_host_calls_from_host_device) |
| 202 | << Callee->getNameAsString() << Caller->getNameAsString(); |
| 203 | return false; |
| 204 | } |
| 205 | |
Reid Kleckner | bbc0178 | 2014-12-03 21:53:36 +0000 | [diff] [blame] | 206 | return true; |
Jacques Pienaar | a50178c | 2015-02-24 21:45:33 +0000 | [diff] [blame] | 207 | } |
Reid Kleckner | bbc0178 | 2014-12-03 21:53:36 +0000 | [diff] [blame] | 208 | } |
Eli Bendersky | 7325e56 | 2014-09-03 15:27:03 +0000 | [diff] [blame] | 209 | |
| 210 | return false; |
| 211 | } |
| 212 | |
Artem Belevich | 94a55e8 | 2015-09-22 17:22:59 +0000 | [diff] [blame] | 213 | template <typename T, typename FetchDeclFn> |
| 214 | static void EraseUnwantedCUDAMatchesImpl(Sema &S, const FunctionDecl *Caller, |
| 215 | llvm::SmallVectorImpl<T> &Matches, |
| 216 | FetchDeclFn FetchDecl) { |
| 217 | assert(S.getLangOpts().CUDATargetOverloads && |
| 218 | "Should not be called w/o enabled target overloads."); |
| 219 | if (Matches.size() <= 1) |
| 220 | return; |
| 221 | |
| 222 | // Find the best call preference among the functions in Matches. |
| 223 | Sema::CUDAFunctionPreference P, BestCFP = Sema::CFP_Never; |
| 224 | for (auto const &Match : Matches) { |
| 225 | P = S.IdentifyCUDAPreference(Caller, FetchDecl(Match)); |
| 226 | if (P > BestCFP) |
| 227 | BestCFP = P; |
| 228 | } |
| 229 | |
| 230 | // Erase all functions with lower priority. |
| 231 | for (unsigned I = 0, N = Matches.size(); I != N;) |
| 232 | if (S.IdentifyCUDAPreference(Caller, FetchDecl(Matches[I])) < BestCFP) { |
| 233 | Matches[I] = Matches[--N]; |
| 234 | Matches.resize(N); |
| 235 | } else { |
| 236 | ++I; |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | void Sema::EraseUnwantedCUDAMatches(const FunctionDecl *Caller, |
| 241 | SmallVectorImpl<FunctionDecl *> &Matches){ |
| 242 | EraseUnwantedCUDAMatchesImpl<FunctionDecl *>( |
| 243 | *this, Caller, Matches, [](const FunctionDecl *item) { return item; }); |
| 244 | } |
| 245 | |
| 246 | void Sema::EraseUnwantedCUDAMatches(const FunctionDecl *Caller, |
| 247 | SmallVectorImpl<DeclAccessPair> &Matches) { |
| 248 | EraseUnwantedCUDAMatchesImpl<DeclAccessPair>( |
| 249 | *this, Caller, Matches, [](const DeclAccessPair &item) { |
| 250 | return dyn_cast<FunctionDecl>(item.getDecl()); |
| 251 | }); |
| 252 | } |
| 253 | |
| 254 | void Sema::EraseUnwantedCUDAMatches( |
| 255 | const FunctionDecl *Caller, |
| 256 | SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>> &Matches){ |
| 257 | EraseUnwantedCUDAMatchesImpl<std::pair<DeclAccessPair, FunctionDecl *>>( |
| 258 | *this, Caller, Matches, |
| 259 | [](const std::pair<DeclAccessPair, FunctionDecl *> &item) { |
| 260 | return dyn_cast<FunctionDecl>(item.second); |
| 261 | }); |
| 262 | } |
| 263 | |
Eli Bendersky | 9a220fc | 2014-09-29 20:38:29 +0000 | [diff] [blame] | 264 | /// When an implicitly-declared special member has to invoke more than one |
| 265 | /// base/field special member, conflicts may occur in the targets of these |
| 266 | /// members. For example, if one base's member __host__ and another's is |
| 267 | /// __device__, it's a conflict. |
| 268 | /// This function figures out if the given targets \param Target1 and |
| 269 | /// \param Target2 conflict, and if they do not it fills in |
| 270 | /// \param ResolvedTarget with a target that resolves for both calls. |
| 271 | /// \return true if there's a conflict, false otherwise. |
| 272 | static bool |
| 273 | resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1, |
| 274 | Sema::CUDAFunctionTarget Target2, |
| 275 | Sema::CUDAFunctionTarget *ResolvedTarget) { |
Justin Lebar | c66a106 | 2016-01-20 00:26:57 +0000 | [diff] [blame] | 276 | // Only free functions and static member functions may be global. |
| 277 | assert(Target1 != Sema::CFT_Global); |
| 278 | assert(Target2 != Sema::CFT_Global); |
Eli Bendersky | 9a220fc | 2014-09-29 20:38:29 +0000 | [diff] [blame] | 279 | |
| 280 | if (Target1 == Sema::CFT_HostDevice) { |
| 281 | *ResolvedTarget = Target2; |
| 282 | } else if (Target2 == Sema::CFT_HostDevice) { |
| 283 | *ResolvedTarget = Target1; |
| 284 | } else if (Target1 != Target2) { |
| 285 | return true; |
| 286 | } else { |
| 287 | *ResolvedTarget = Target1; |
| 288 | } |
| 289 | |
| 290 | return false; |
| 291 | } |
| 292 | |
| 293 | bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, |
| 294 | CXXSpecialMember CSM, |
| 295 | CXXMethodDecl *MemberDecl, |
| 296 | bool ConstRHS, |
| 297 | bool Diagnose) { |
| 298 | llvm::Optional<CUDAFunctionTarget> InferredTarget; |
| 299 | |
| 300 | // We're going to invoke special member lookup; mark that these special |
| 301 | // members are called from this one, and not from its caller. |
| 302 | ContextRAII MethodContext(*this, MemberDecl); |
| 303 | |
| 304 | // Look for special members in base classes that should be invoked from here. |
| 305 | // Infer the target of this member base on the ones it should call. |
| 306 | // Skip direct and indirect virtual bases for abstract classes. |
| 307 | llvm::SmallVector<const CXXBaseSpecifier *, 16> Bases; |
| 308 | for (const auto &B : ClassDecl->bases()) { |
| 309 | if (!B.isVirtual()) { |
| 310 | Bases.push_back(&B); |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | if (!ClassDecl->isAbstract()) { |
| 315 | for (const auto &VB : ClassDecl->vbases()) { |
| 316 | Bases.push_back(&VB); |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | for (const auto *B : Bases) { |
| 321 | const RecordType *BaseType = B->getType()->getAs<RecordType>(); |
| 322 | if (!BaseType) { |
| 323 | continue; |
| 324 | } |
| 325 | |
| 326 | CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); |
| 327 | Sema::SpecialMemberOverloadResult *SMOR = |
| 328 | LookupSpecialMember(BaseClassDecl, CSM, |
| 329 | /* ConstArg */ ConstRHS, |
| 330 | /* VolatileArg */ false, |
| 331 | /* RValueThis */ false, |
| 332 | /* ConstThis */ false, |
| 333 | /* VolatileThis */ false); |
| 334 | |
| 335 | if (!SMOR || !SMOR->getMethod()) { |
| 336 | continue; |
| 337 | } |
| 338 | |
| 339 | CUDAFunctionTarget BaseMethodTarget = IdentifyCUDATarget(SMOR->getMethod()); |
| 340 | if (!InferredTarget.hasValue()) { |
| 341 | InferredTarget = BaseMethodTarget; |
| 342 | } else { |
| 343 | bool ResolutionError = resolveCalleeCUDATargetConflict( |
| 344 | InferredTarget.getValue(), BaseMethodTarget, |
| 345 | InferredTarget.getPointer()); |
| 346 | if (ResolutionError) { |
| 347 | if (Diagnose) { |
| 348 | Diag(ClassDecl->getLocation(), |
| 349 | diag::note_implicit_member_target_infer_collision) |
| 350 | << (unsigned)CSM << InferredTarget.getValue() << BaseMethodTarget; |
| 351 | } |
| 352 | MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context)); |
| 353 | return true; |
| 354 | } |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | // Same as for bases, but now for special members of fields. |
| 359 | for (const auto *F : ClassDecl->fields()) { |
| 360 | if (F->isInvalidDecl()) { |
| 361 | continue; |
| 362 | } |
| 363 | |
| 364 | const RecordType *FieldType = |
| 365 | Context.getBaseElementType(F->getType())->getAs<RecordType>(); |
| 366 | if (!FieldType) { |
| 367 | continue; |
| 368 | } |
| 369 | |
| 370 | CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(FieldType->getDecl()); |
| 371 | Sema::SpecialMemberOverloadResult *SMOR = |
| 372 | LookupSpecialMember(FieldRecDecl, CSM, |
| 373 | /* ConstArg */ ConstRHS && !F->isMutable(), |
| 374 | /* VolatileArg */ false, |
| 375 | /* RValueThis */ false, |
| 376 | /* ConstThis */ false, |
| 377 | /* VolatileThis */ false); |
| 378 | |
| 379 | if (!SMOR || !SMOR->getMethod()) { |
| 380 | continue; |
| 381 | } |
| 382 | |
| 383 | CUDAFunctionTarget FieldMethodTarget = |
| 384 | IdentifyCUDATarget(SMOR->getMethod()); |
| 385 | if (!InferredTarget.hasValue()) { |
| 386 | InferredTarget = FieldMethodTarget; |
| 387 | } else { |
| 388 | bool ResolutionError = resolveCalleeCUDATargetConflict( |
| 389 | InferredTarget.getValue(), FieldMethodTarget, |
| 390 | InferredTarget.getPointer()); |
| 391 | if (ResolutionError) { |
| 392 | if (Diagnose) { |
| 393 | Diag(ClassDecl->getLocation(), |
| 394 | diag::note_implicit_member_target_infer_collision) |
| 395 | << (unsigned)CSM << InferredTarget.getValue() |
| 396 | << FieldMethodTarget; |
| 397 | } |
| 398 | MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context)); |
| 399 | return true; |
| 400 | } |
| 401 | } |
| 402 | } |
| 403 | |
| 404 | if (InferredTarget.hasValue()) { |
| 405 | if (InferredTarget.getValue() == CFT_Device) { |
| 406 | MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); |
| 407 | } else if (InferredTarget.getValue() == CFT_Host) { |
| 408 | MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); |
| 409 | } else { |
| 410 | MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); |
| 411 | MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); |
| 412 | } |
| 413 | } else { |
| 414 | // If no target was inferred, mark this member as __host__ __device__; |
| 415 | // it's the least restrictive option that can be invoked from any target. |
| 416 | MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); |
| 417 | MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); |
| 418 | } |
| 419 | |
| 420 | return false; |
| 421 | } |
Artem Belevich | 97c01c3 | 2016-02-02 22:29:48 +0000 | [diff] [blame] | 422 | |
| 423 | bool Sema::isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD) { |
| 424 | if (!CD->isDefined() && CD->isTemplateInstantiation()) |
| 425 | InstantiateFunctionDefinition(Loc, CD->getFirstDecl()); |
| 426 | |
| 427 | // (E.2.3.1, CUDA 7.5) A constructor for a class type is considered |
| 428 | // empty at a point in the translation unit, if it is either a |
| 429 | // trivial constructor |
| 430 | if (CD->isTrivial()) |
| 431 | return true; |
| 432 | |
| 433 | // ... or it satisfies all of the following conditions: |
| 434 | // The constructor function has been defined. |
| 435 | // The constructor function has no parameters, |
| 436 | // and the function body is an empty compound statement. |
| 437 | if (!(CD->hasTrivialBody() && CD->getNumParams() == 0)) |
| 438 | return false; |
| 439 | |
| 440 | // Its class has no virtual functions and no virtual base classes. |
| 441 | if (CD->getParent()->isDynamicClass()) |
| 442 | return false; |
| 443 | |
| 444 | // The only form of initializer allowed is an empty constructor. |
| 445 | // This will recursively checks all base classes and member initializers |
| 446 | if (!llvm::all_of(CD->inits(), [&](const CXXCtorInitializer *CI) { |
| 447 | if (const CXXConstructExpr *CE = |
| 448 | dyn_cast<CXXConstructExpr>(CI->getInit())) |
| 449 | return isEmptyCudaConstructor(Loc, CE->getConstructor()); |
| 450 | return false; |
| 451 | })) |
| 452 | return false; |
| 453 | |
| 454 | return true; |
| 455 | } |