clang API Documentation

SemaCUDA.cpp
Go to the documentation of this file.
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 }