clang API Documentation
00001 //===--- SemaCUDA.cpp - Semantic Analysis for CUDA constructs -------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 /// \file 00010 /// \brief This file implements semantic analysis for CUDA constructs. 00011 /// 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "clang/Sema/Sema.h" 00015 #include "clang/AST/ASTContext.h" 00016 #include "clang/AST/Decl.h" 00017 #include "clang/Sema/SemaDiagnostic.h" 00018 #include "llvm/ADT/Optional.h" 00019 #include "llvm/ADT/SmallVector.h" 00020 using namespace clang; 00021 00022 ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, 00023 MultiExprArg ExecConfig, 00024 SourceLocation GGGLoc) { 00025 FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl(); 00026 if (!ConfigDecl) 00027 return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use) 00028 << "cudaConfigureCall"); 00029 QualType ConfigQTy = ConfigDecl->getType(); 00030 00031 DeclRefExpr *ConfigDR = new (Context) 00032 DeclRefExpr(ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc); 00033 MarkFunctionReferenced(LLLLoc, ConfigDecl); 00034 00035 return ActOnCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr, 00036 /*IsExecConfig=*/true); 00037 } 00038 00039 /// IdentifyCUDATarget - Determine the CUDA compilation target for this function 00040 Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) { 00041 if (D->hasAttr<CUDAInvalidTargetAttr>()) 00042 return CFT_InvalidTarget; 00043 00044 if (D->hasAttr<CUDAGlobalAttr>()) 00045 return CFT_Global; 00046 00047 if (D->hasAttr<CUDADeviceAttr>()) { 00048 if (D->hasAttr<CUDAHostAttr>()) 00049 return CFT_HostDevice; 00050 return CFT_Device; 00051 } else if (D->hasAttr<CUDAHostAttr>()) { 00052 return CFT_Host; 00053 } else if (D->isImplicit()) { 00054 // Some implicit declarations (like intrinsic functions) are not marked. 00055 // Set the most lenient target on them for maximal flexibility. 00056 return CFT_HostDevice; 00057 } 00058 00059 return CFT_Host; 00060 } 00061 00062 bool Sema::CheckCUDATarget(const FunctionDecl *Caller, 00063 const FunctionDecl *Callee) { 00064 return CheckCUDATarget(IdentifyCUDATarget(Caller), 00065 IdentifyCUDATarget(Callee)); 00066 } 00067 00068 bool Sema::CheckCUDATarget(CUDAFunctionTarget CallerTarget, 00069 CUDAFunctionTarget CalleeTarget) { 00070 // If one of the targets is invalid, the check always fails, no matter what 00071 // the other target is. 00072 if (CallerTarget == CFT_InvalidTarget || CalleeTarget == CFT_InvalidTarget) 00073 return true; 00074 00075 // CUDA B.1.1 "The __device__ qualifier declares a function that is... 00076 // Callable from the device only." 00077 if (CallerTarget == CFT_Host && CalleeTarget == CFT_Device) 00078 return true; 00079 00080 // CUDA B.1.2 "The __global__ qualifier declares a function that is... 00081 // Callable from the host only." 00082 // CUDA B.1.3 "The __host__ qualifier declares a function that is... 00083 // Callable from the host only." 00084 if ((CallerTarget == CFT_Device || CallerTarget == CFT_Global) && 00085 (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global)) 00086 return true; 00087 00088 if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice) 00089 return true; 00090 00091 return false; 00092 } 00093 00094 /// When an implicitly-declared special member has to invoke more than one 00095 /// base/field special member, conflicts may occur in the targets of these 00096 /// members. For example, if one base's member __host__ and another's is 00097 /// __device__, it's a conflict. 00098 /// This function figures out if the given targets \param Target1 and 00099 /// \param Target2 conflict, and if they do not it fills in 00100 /// \param ResolvedTarget with a target that resolves for both calls. 00101 /// \return true if there's a conflict, false otherwise. 00102 static bool 00103 resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1, 00104 Sema::CUDAFunctionTarget Target2, 00105 Sema::CUDAFunctionTarget *ResolvedTarget) { 00106 if (Target1 == Sema::CFT_Global && Target2 == Sema::CFT_Global) { 00107 // TODO: this shouldn't happen, really. Methods cannot be marked __global__. 00108 // Clang should detect this earlier and produce an error. Then this 00109 // condition can be changed to an assertion. 00110 return true; 00111 } 00112 00113 if (Target1 == Sema::CFT_HostDevice) { 00114 *ResolvedTarget = Target2; 00115 } else if (Target2 == Sema::CFT_HostDevice) { 00116 *ResolvedTarget = Target1; 00117 } else if (Target1 != Target2) { 00118 return true; 00119 } else { 00120 *ResolvedTarget = Target1; 00121 } 00122 00123 return false; 00124 } 00125 00126 bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, 00127 CXXSpecialMember CSM, 00128 CXXMethodDecl *MemberDecl, 00129 bool ConstRHS, 00130 bool Diagnose) { 00131 llvm::Optional<CUDAFunctionTarget> InferredTarget; 00132 00133 // We're going to invoke special member lookup; mark that these special 00134 // members are called from this one, and not from its caller. 00135 ContextRAII MethodContext(*this, MemberDecl); 00136 00137 // Look for special members in base classes that should be invoked from here. 00138 // Infer the target of this member base on the ones it should call. 00139 // Skip direct and indirect virtual bases for abstract classes. 00140 llvm::SmallVector<const CXXBaseSpecifier *, 16> Bases; 00141 for (const auto &B : ClassDecl->bases()) { 00142 if (!B.isVirtual()) { 00143 Bases.push_back(&B); 00144 } 00145 } 00146 00147 if (!ClassDecl->isAbstract()) { 00148 for (const auto &VB : ClassDecl->vbases()) { 00149 Bases.push_back(&VB); 00150 } 00151 } 00152 00153 for (const auto *B : Bases) { 00154 const RecordType *BaseType = B->getType()->getAs<RecordType>(); 00155 if (!BaseType) { 00156 continue; 00157 } 00158 00159 CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); 00160 Sema::SpecialMemberOverloadResult *SMOR = 00161 LookupSpecialMember(BaseClassDecl, CSM, 00162 /* ConstArg */ ConstRHS, 00163 /* VolatileArg */ false, 00164 /* RValueThis */ false, 00165 /* ConstThis */ false, 00166 /* VolatileThis */ false); 00167 00168 if (!SMOR || !SMOR->getMethod()) { 00169 continue; 00170 } 00171 00172 CUDAFunctionTarget BaseMethodTarget = IdentifyCUDATarget(SMOR->getMethod()); 00173 if (!InferredTarget.hasValue()) { 00174 InferredTarget = BaseMethodTarget; 00175 } else { 00176 bool ResolutionError = resolveCalleeCUDATargetConflict( 00177 InferredTarget.getValue(), BaseMethodTarget, 00178 InferredTarget.getPointer()); 00179 if (ResolutionError) { 00180 if (Diagnose) { 00181 Diag(ClassDecl->getLocation(), 00182 diag::note_implicit_member_target_infer_collision) 00183 << (unsigned)CSM << InferredTarget.getValue() << BaseMethodTarget; 00184 } 00185 MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context)); 00186 return true; 00187 } 00188 } 00189 } 00190 00191 // Same as for bases, but now for special members of fields. 00192 for (const auto *F : ClassDecl->fields()) { 00193 if (F->isInvalidDecl()) { 00194 continue; 00195 } 00196 00197 const RecordType *FieldType = 00198 Context.getBaseElementType(F->getType())->getAs<RecordType>(); 00199 if (!FieldType) { 00200 continue; 00201 } 00202 00203 CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(FieldType->getDecl()); 00204 Sema::SpecialMemberOverloadResult *SMOR = 00205 LookupSpecialMember(FieldRecDecl, CSM, 00206 /* ConstArg */ ConstRHS && !F->isMutable(), 00207 /* VolatileArg */ false, 00208 /* RValueThis */ false, 00209 /* ConstThis */ false, 00210 /* VolatileThis */ false); 00211 00212 if (!SMOR || !SMOR->getMethod()) { 00213 continue; 00214 } 00215 00216 CUDAFunctionTarget FieldMethodTarget = 00217 IdentifyCUDATarget(SMOR->getMethod()); 00218 if (!InferredTarget.hasValue()) { 00219 InferredTarget = FieldMethodTarget; 00220 } else { 00221 bool ResolutionError = resolveCalleeCUDATargetConflict( 00222 InferredTarget.getValue(), FieldMethodTarget, 00223 InferredTarget.getPointer()); 00224 if (ResolutionError) { 00225 if (Diagnose) { 00226 Diag(ClassDecl->getLocation(), 00227 diag::note_implicit_member_target_infer_collision) 00228 << (unsigned)CSM << InferredTarget.getValue() 00229 << FieldMethodTarget; 00230 } 00231 MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context)); 00232 return true; 00233 } 00234 } 00235 } 00236 00237 if (InferredTarget.hasValue()) { 00238 if (InferredTarget.getValue() == CFT_Device) { 00239 MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); 00240 } else if (InferredTarget.getValue() == CFT_Host) { 00241 MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); 00242 } else { 00243 MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); 00244 MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); 00245 } 00246 } else { 00247 // If no target was inferred, mark this member as __host__ __device__; 00248 // it's the least restrictive option that can be invoked from any target. 00249 MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); 00250 MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); 00251 } 00252 00253 return false; 00254 }