1*0fca6ea1SDimitry Andric //===--- SemaOpenCL.cpp --- Semantic Analysis for OpenCL constructs -------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric /// \file 9*0fca6ea1SDimitry Andric /// This file implements semantic analysis for OpenCL. 10*0fca6ea1SDimitry Andric /// 11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 12*0fca6ea1SDimitry Andric 13*0fca6ea1SDimitry Andric #include "clang/Sema/SemaOpenCL.h" 14*0fca6ea1SDimitry Andric #include "clang/AST/Attr.h" 15*0fca6ea1SDimitry Andric #include "clang/AST/DeclBase.h" 16*0fca6ea1SDimitry Andric #include "clang/Basic/DiagnosticSema.h" 17*0fca6ea1SDimitry Andric #include "clang/Sema/ParsedAttr.h" 18*0fca6ea1SDimitry Andric #include "clang/Sema/Sema.h" 19*0fca6ea1SDimitry Andric 20*0fca6ea1SDimitry Andric namespace clang { 21*0fca6ea1SDimitry Andric SemaOpenCL::SemaOpenCL(Sema &S) : SemaBase(S) {} 22*0fca6ea1SDimitry Andric 23*0fca6ea1SDimitry Andric void SemaOpenCL::handleNoSVMAttr(Decl *D, const ParsedAttr &AL) { 24*0fca6ea1SDimitry Andric if (getLangOpts().getOpenCLCompatibleVersion() < 200) 25*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version) 26*0fca6ea1SDimitry Andric << AL << "2.0" << 1; 27*0fca6ea1SDimitry Andric else 28*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) 29*0fca6ea1SDimitry Andric << AL << getLangOpts().getOpenCLVersionString(); 30*0fca6ea1SDimitry Andric } 31*0fca6ea1SDimitry Andric 32*0fca6ea1SDimitry Andric void SemaOpenCL::handleAccessAttr(Decl *D, const ParsedAttr &AL) { 33*0fca6ea1SDimitry Andric if (D->isInvalidDecl()) 34*0fca6ea1SDimitry Andric return; 35*0fca6ea1SDimitry Andric 36*0fca6ea1SDimitry Andric // Check if there is only one access qualifier. 37*0fca6ea1SDimitry Andric if (D->hasAttr<OpenCLAccessAttr>()) { 38*0fca6ea1SDimitry Andric if (D->getAttr<OpenCLAccessAttr>()->getSemanticSpelling() == 39*0fca6ea1SDimitry Andric AL.getSemanticSpelling()) { 40*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::warn_duplicate_declspec) 41*0fca6ea1SDimitry Andric << AL.getAttrName()->getName() << AL.getRange(); 42*0fca6ea1SDimitry Andric } else { 43*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers) 44*0fca6ea1SDimitry Andric << D->getSourceRange(); 45*0fca6ea1SDimitry Andric D->setInvalidDecl(true); 46*0fca6ea1SDimitry Andric return; 47*0fca6ea1SDimitry Andric } 48*0fca6ea1SDimitry Andric } 49*0fca6ea1SDimitry Andric 50*0fca6ea1SDimitry Andric // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that 51*0fca6ea1SDimitry Andric // an image object can be read and written. OpenCL v2.0 s6.13.6 - A kernel 52*0fca6ea1SDimitry Andric // cannot read from and write to the same pipe object. Using the read_write 53*0fca6ea1SDimitry Andric // (or __read_write) qualifier with the pipe qualifier is a compilation error. 54*0fca6ea1SDimitry Andric // OpenCL v3.0 s6.8 - For OpenCL C 2.0, or with the 55*0fca6ea1SDimitry Andric // __opencl_c_read_write_images feature, image objects specified as arguments 56*0fca6ea1SDimitry Andric // to a kernel can additionally be declared to be read-write. 57*0fca6ea1SDimitry Andric // C++ for OpenCL 1.0 inherits rule from OpenCL C v2.0. 58*0fca6ea1SDimitry Andric // C++ for OpenCL 2021 inherits rule from OpenCL C v3.0. 59*0fca6ea1SDimitry Andric if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) { 60*0fca6ea1SDimitry Andric const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); 61*0fca6ea1SDimitry Andric if (AL.getAttrName()->getName().contains("read_write")) { 62*0fca6ea1SDimitry Andric bool ReadWriteImagesUnsupported = 63*0fca6ea1SDimitry Andric (getLangOpts().getOpenCLCompatibleVersion() < 200) || 64*0fca6ea1SDimitry Andric (getLangOpts().getOpenCLCompatibleVersion() == 300 && 65*0fca6ea1SDimitry Andric !SemaRef.getOpenCLOptions().isSupported( 66*0fca6ea1SDimitry Andric "__opencl_c_read_write_images", getLangOpts())); 67*0fca6ea1SDimitry Andric if (ReadWriteImagesUnsupported || DeclTy->isPipeType()) { 68*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::err_opencl_invalid_read_write) 69*0fca6ea1SDimitry Andric << AL << PDecl->getType() << DeclTy->isImageType(); 70*0fca6ea1SDimitry Andric D->setInvalidDecl(true); 71*0fca6ea1SDimitry Andric return; 72*0fca6ea1SDimitry Andric } 73*0fca6ea1SDimitry Andric } 74*0fca6ea1SDimitry Andric } 75*0fca6ea1SDimitry Andric 76*0fca6ea1SDimitry Andric D->addAttr(::new (getASTContext()) OpenCLAccessAttr(getASTContext(), AL)); 77*0fca6ea1SDimitry Andric } 78*0fca6ea1SDimitry Andric 79*0fca6ea1SDimitry Andric void SemaOpenCL::handleSubGroupSize(Decl *D, const ParsedAttr &AL) { 80*0fca6ea1SDimitry Andric uint32_t SGSize; 81*0fca6ea1SDimitry Andric const Expr *E = AL.getArgAsExpr(0); 82*0fca6ea1SDimitry Andric if (!SemaRef.checkUInt32Argument(AL, E, SGSize)) 83*0fca6ea1SDimitry Andric return; 84*0fca6ea1SDimitry Andric if (SGSize == 0) { 85*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::err_attribute_argument_is_zero) 86*0fca6ea1SDimitry Andric << AL << E->getSourceRange(); 87*0fca6ea1SDimitry Andric return; 88*0fca6ea1SDimitry Andric } 89*0fca6ea1SDimitry Andric 90*0fca6ea1SDimitry Andric OpenCLIntelReqdSubGroupSizeAttr *Existing = 91*0fca6ea1SDimitry Andric D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>(); 92*0fca6ea1SDimitry Andric if (Existing && Existing->getSubGroupSize() != SGSize) 93*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; 94*0fca6ea1SDimitry Andric 95*0fca6ea1SDimitry Andric D->addAttr(::new (getASTContext()) 96*0fca6ea1SDimitry Andric OpenCLIntelReqdSubGroupSizeAttr(getASTContext(), AL, SGSize)); 97*0fca6ea1SDimitry Andric } 98*0fca6ea1SDimitry Andric 99*0fca6ea1SDimitry Andric static inline bool isBlockPointer(Expr *Arg) { 100*0fca6ea1SDimitry Andric return Arg->getType()->isBlockPointerType(); 101*0fca6ea1SDimitry Andric } 102*0fca6ea1SDimitry Andric 103*0fca6ea1SDimitry Andric /// OpenCL C v2.0, s6.13.17.2 - Checks that the block parameters are all local 104*0fca6ea1SDimitry Andric /// void*, which is a requirement of device side enqueue. 105*0fca6ea1SDimitry Andric static bool checkBlockArgs(Sema &S, Expr *BlockArg) { 106*0fca6ea1SDimitry Andric const BlockPointerType *BPT = 107*0fca6ea1SDimitry Andric cast<BlockPointerType>(BlockArg->getType().getCanonicalType()); 108*0fca6ea1SDimitry Andric ArrayRef<QualType> Params = 109*0fca6ea1SDimitry Andric BPT->getPointeeType()->castAs<FunctionProtoType>()->getParamTypes(); 110*0fca6ea1SDimitry Andric unsigned ArgCounter = 0; 111*0fca6ea1SDimitry Andric bool IllegalParams = false; 112*0fca6ea1SDimitry Andric // Iterate through the block parameters until either one is found that is not 113*0fca6ea1SDimitry Andric // a local void*, or the block is valid. 114*0fca6ea1SDimitry Andric for (ArrayRef<QualType>::iterator I = Params.begin(), E = Params.end(); 115*0fca6ea1SDimitry Andric I != E; ++I, ++ArgCounter) { 116*0fca6ea1SDimitry Andric if (!(*I)->isPointerType() || !(*I)->getPointeeType()->isVoidType() || 117*0fca6ea1SDimitry Andric (*I)->getPointeeType().getQualifiers().getAddressSpace() != 118*0fca6ea1SDimitry Andric LangAS::opencl_local) { 119*0fca6ea1SDimitry Andric // Get the location of the error. If a block literal has been passed 120*0fca6ea1SDimitry Andric // (BlockExpr) then we can point straight to the offending argument, 121*0fca6ea1SDimitry Andric // else we just point to the variable reference. 122*0fca6ea1SDimitry Andric SourceLocation ErrorLoc; 123*0fca6ea1SDimitry Andric if (isa<BlockExpr>(BlockArg)) { 124*0fca6ea1SDimitry Andric BlockDecl *BD = cast<BlockExpr>(BlockArg)->getBlockDecl(); 125*0fca6ea1SDimitry Andric ErrorLoc = BD->getParamDecl(ArgCounter)->getBeginLoc(); 126*0fca6ea1SDimitry Andric } else if (isa<DeclRefExpr>(BlockArg)) { 127*0fca6ea1SDimitry Andric ErrorLoc = cast<DeclRefExpr>(BlockArg)->getBeginLoc(); 128*0fca6ea1SDimitry Andric } 129*0fca6ea1SDimitry Andric S.Diag(ErrorLoc, 130*0fca6ea1SDimitry Andric diag::err_opencl_enqueue_kernel_blocks_non_local_void_args); 131*0fca6ea1SDimitry Andric IllegalParams = true; 132*0fca6ea1SDimitry Andric } 133*0fca6ea1SDimitry Andric } 134*0fca6ea1SDimitry Andric 135*0fca6ea1SDimitry Andric return IllegalParams; 136*0fca6ea1SDimitry Andric } 137*0fca6ea1SDimitry Andric 138*0fca6ea1SDimitry Andric bool SemaOpenCL::checkSubgroupExt(CallExpr *Call) { 139*0fca6ea1SDimitry Andric // OpenCL device can support extension but not the feature as extension 140*0fca6ea1SDimitry Andric // requires subgroup independent forward progress, but subgroup independent 141*0fca6ea1SDimitry Andric // forward progress is optional in OpenCL C 3.0 __opencl_c_subgroups feature. 142*0fca6ea1SDimitry Andric if (!SemaRef.getOpenCLOptions().isSupported("cl_khr_subgroups", 143*0fca6ea1SDimitry Andric getLangOpts()) && 144*0fca6ea1SDimitry Andric !SemaRef.getOpenCLOptions().isSupported("__opencl_c_subgroups", 145*0fca6ea1SDimitry Andric getLangOpts())) { 146*0fca6ea1SDimitry Andric Diag(Call->getBeginLoc(), diag::err_opencl_requires_extension) 147*0fca6ea1SDimitry Andric << 1 << Call->getDirectCallee() 148*0fca6ea1SDimitry Andric << "cl_khr_subgroups or __opencl_c_subgroups"; 149*0fca6ea1SDimitry Andric return true; 150*0fca6ea1SDimitry Andric } 151*0fca6ea1SDimitry Andric return false; 152*0fca6ea1SDimitry Andric } 153*0fca6ea1SDimitry Andric 154*0fca6ea1SDimitry Andric bool SemaOpenCL::checkBuiltinNDRangeAndBlock(CallExpr *TheCall) { 155*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, 2)) 156*0fca6ea1SDimitry Andric return true; 157*0fca6ea1SDimitry Andric 158*0fca6ea1SDimitry Andric if (checkSubgroupExt(TheCall)) 159*0fca6ea1SDimitry Andric return true; 160*0fca6ea1SDimitry Andric 161*0fca6ea1SDimitry Andric // First argument is an ndrange_t type. 162*0fca6ea1SDimitry Andric Expr *NDRangeArg = TheCall->getArg(0); 163*0fca6ea1SDimitry Andric if (NDRangeArg->getType().getUnqualifiedType().getAsString() != "ndrange_t") { 164*0fca6ea1SDimitry Andric Diag(NDRangeArg->getBeginLoc(), diag::err_opencl_builtin_expected_type) 165*0fca6ea1SDimitry Andric << TheCall->getDirectCallee() << "'ndrange_t'"; 166*0fca6ea1SDimitry Andric return true; 167*0fca6ea1SDimitry Andric } 168*0fca6ea1SDimitry Andric 169*0fca6ea1SDimitry Andric Expr *BlockArg = TheCall->getArg(1); 170*0fca6ea1SDimitry Andric if (!isBlockPointer(BlockArg)) { 171*0fca6ea1SDimitry Andric Diag(BlockArg->getBeginLoc(), diag::err_opencl_builtin_expected_type) 172*0fca6ea1SDimitry Andric << TheCall->getDirectCallee() << "block"; 173*0fca6ea1SDimitry Andric return true; 174*0fca6ea1SDimitry Andric } 175*0fca6ea1SDimitry Andric return checkBlockArgs(SemaRef, BlockArg); 176*0fca6ea1SDimitry Andric } 177*0fca6ea1SDimitry Andric 178*0fca6ea1SDimitry Andric bool SemaOpenCL::checkBuiltinKernelWorkGroupSize(CallExpr *TheCall) { 179*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, 1)) 180*0fca6ea1SDimitry Andric return true; 181*0fca6ea1SDimitry Andric 182*0fca6ea1SDimitry Andric Expr *BlockArg = TheCall->getArg(0); 183*0fca6ea1SDimitry Andric if (!isBlockPointer(BlockArg)) { 184*0fca6ea1SDimitry Andric Diag(BlockArg->getBeginLoc(), diag::err_opencl_builtin_expected_type) 185*0fca6ea1SDimitry Andric << TheCall->getDirectCallee() << "block"; 186*0fca6ea1SDimitry Andric return true; 187*0fca6ea1SDimitry Andric } 188*0fca6ea1SDimitry Andric return checkBlockArgs(SemaRef, BlockArg); 189*0fca6ea1SDimitry Andric } 190*0fca6ea1SDimitry Andric 191*0fca6ea1SDimitry Andric /// Diagnose integer type and any valid implicit conversion to it. 192*0fca6ea1SDimitry Andric static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) { 193*0fca6ea1SDimitry Andric // Taking into account implicit conversions, 194*0fca6ea1SDimitry Andric // allow any integer. 195*0fca6ea1SDimitry Andric if (!E->getType()->isIntegerType()) { 196*0fca6ea1SDimitry Andric S.Diag(E->getBeginLoc(), 197*0fca6ea1SDimitry Andric diag::err_opencl_enqueue_kernel_invalid_local_size_type); 198*0fca6ea1SDimitry Andric return true; 199*0fca6ea1SDimitry Andric } 200*0fca6ea1SDimitry Andric // Potentially emit standard warnings for implicit conversions if enabled 201*0fca6ea1SDimitry Andric // using -Wconversion. 202*0fca6ea1SDimitry Andric S.CheckImplicitConversion(E, IntT, E->getBeginLoc()); 203*0fca6ea1SDimitry Andric return false; 204*0fca6ea1SDimitry Andric } 205*0fca6ea1SDimitry Andric 206*0fca6ea1SDimitry Andric static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall, 207*0fca6ea1SDimitry Andric unsigned Start, unsigned End) { 208*0fca6ea1SDimitry Andric bool IllegalParams = false; 209*0fca6ea1SDimitry Andric for (unsigned I = Start; I <= End; ++I) 210*0fca6ea1SDimitry Andric IllegalParams |= checkOpenCLEnqueueIntType(S, TheCall->getArg(I), 211*0fca6ea1SDimitry Andric S.Context.getSizeType()); 212*0fca6ea1SDimitry Andric return IllegalParams; 213*0fca6ea1SDimitry Andric } 214*0fca6ea1SDimitry Andric 215*0fca6ea1SDimitry Andric /// OpenCL v2.0, s6.13.17.1 - Check that sizes are provided for all 216*0fca6ea1SDimitry Andric /// 'local void*' parameter of passed block. 217*0fca6ea1SDimitry Andric static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall, 218*0fca6ea1SDimitry Andric Expr *BlockArg, 219*0fca6ea1SDimitry Andric unsigned NumNonVarArgs) { 220*0fca6ea1SDimitry Andric const BlockPointerType *BPT = 221*0fca6ea1SDimitry Andric cast<BlockPointerType>(BlockArg->getType().getCanonicalType()); 222*0fca6ea1SDimitry Andric unsigned NumBlockParams = 223*0fca6ea1SDimitry Andric BPT->getPointeeType()->castAs<FunctionProtoType>()->getNumParams(); 224*0fca6ea1SDimitry Andric unsigned TotalNumArgs = TheCall->getNumArgs(); 225*0fca6ea1SDimitry Andric 226*0fca6ea1SDimitry Andric // For each argument passed to the block, a corresponding uint needs to 227*0fca6ea1SDimitry Andric // be passed to describe the size of the local memory. 228*0fca6ea1SDimitry Andric if (TotalNumArgs != NumBlockParams + NumNonVarArgs) { 229*0fca6ea1SDimitry Andric S.Diag(TheCall->getBeginLoc(), 230*0fca6ea1SDimitry Andric diag::err_opencl_enqueue_kernel_local_size_args); 231*0fca6ea1SDimitry Andric return true; 232*0fca6ea1SDimitry Andric } 233*0fca6ea1SDimitry Andric 234*0fca6ea1SDimitry Andric // Check that the sizes of the local memory are specified by integers. 235*0fca6ea1SDimitry Andric return checkOpenCLEnqueueLocalSizeArgs(S, TheCall, NumNonVarArgs, 236*0fca6ea1SDimitry Andric TotalNumArgs - 1); 237*0fca6ea1SDimitry Andric } 238*0fca6ea1SDimitry Andric 239*0fca6ea1SDimitry Andric bool SemaOpenCL::checkBuiltinEnqueueKernel(CallExpr *TheCall) { 240*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext(); 241*0fca6ea1SDimitry Andric unsigned NumArgs = TheCall->getNumArgs(); 242*0fca6ea1SDimitry Andric 243*0fca6ea1SDimitry Andric if (NumArgs < 4) { 244*0fca6ea1SDimitry Andric Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_few_args_at_least) 245*0fca6ea1SDimitry Andric << 0 << 4 << NumArgs << /*is non object*/ 0; 246*0fca6ea1SDimitry Andric return true; 247*0fca6ea1SDimitry Andric } 248*0fca6ea1SDimitry Andric 249*0fca6ea1SDimitry Andric Expr *Arg0 = TheCall->getArg(0); 250*0fca6ea1SDimitry Andric Expr *Arg1 = TheCall->getArg(1); 251*0fca6ea1SDimitry Andric Expr *Arg2 = TheCall->getArg(2); 252*0fca6ea1SDimitry Andric Expr *Arg3 = TheCall->getArg(3); 253*0fca6ea1SDimitry Andric 254*0fca6ea1SDimitry Andric // First argument always needs to be a queue_t type. 255*0fca6ea1SDimitry Andric if (!Arg0->getType()->isQueueT()) { 256*0fca6ea1SDimitry Andric Diag(TheCall->getArg(0)->getBeginLoc(), 257*0fca6ea1SDimitry Andric diag::err_opencl_builtin_expected_type) 258*0fca6ea1SDimitry Andric << TheCall->getDirectCallee() << getASTContext().OCLQueueTy; 259*0fca6ea1SDimitry Andric return true; 260*0fca6ea1SDimitry Andric } 261*0fca6ea1SDimitry Andric 262*0fca6ea1SDimitry Andric // Second argument always needs to be a kernel_enqueue_flags_t enum value. 263*0fca6ea1SDimitry Andric if (!Arg1->getType()->isIntegerType()) { 264*0fca6ea1SDimitry Andric Diag(TheCall->getArg(1)->getBeginLoc(), 265*0fca6ea1SDimitry Andric diag::err_opencl_builtin_expected_type) 266*0fca6ea1SDimitry Andric << TheCall->getDirectCallee() << "'kernel_enqueue_flags_t' (i.e. uint)"; 267*0fca6ea1SDimitry Andric return true; 268*0fca6ea1SDimitry Andric } 269*0fca6ea1SDimitry Andric 270*0fca6ea1SDimitry Andric // Third argument is always an ndrange_t type. 271*0fca6ea1SDimitry Andric if (Arg2->getType().getUnqualifiedType().getAsString() != "ndrange_t") { 272*0fca6ea1SDimitry Andric Diag(TheCall->getArg(2)->getBeginLoc(), 273*0fca6ea1SDimitry Andric diag::err_opencl_builtin_expected_type) 274*0fca6ea1SDimitry Andric << TheCall->getDirectCallee() << "'ndrange_t'"; 275*0fca6ea1SDimitry Andric return true; 276*0fca6ea1SDimitry Andric } 277*0fca6ea1SDimitry Andric 278*0fca6ea1SDimitry Andric // With four arguments, there is only one form that the function could be 279*0fca6ea1SDimitry Andric // called in: no events and no variable arguments. 280*0fca6ea1SDimitry Andric if (NumArgs == 4) { 281*0fca6ea1SDimitry Andric // check that the last argument is the right block type. 282*0fca6ea1SDimitry Andric if (!isBlockPointer(Arg3)) { 283*0fca6ea1SDimitry Andric Diag(Arg3->getBeginLoc(), diag::err_opencl_builtin_expected_type) 284*0fca6ea1SDimitry Andric << TheCall->getDirectCallee() << "block"; 285*0fca6ea1SDimitry Andric return true; 286*0fca6ea1SDimitry Andric } 287*0fca6ea1SDimitry Andric // we have a block type, check the prototype 288*0fca6ea1SDimitry Andric const BlockPointerType *BPT = 289*0fca6ea1SDimitry Andric cast<BlockPointerType>(Arg3->getType().getCanonicalType()); 290*0fca6ea1SDimitry Andric if (BPT->getPointeeType()->castAs<FunctionProtoType>()->getNumParams() > 291*0fca6ea1SDimitry Andric 0) { 292*0fca6ea1SDimitry Andric Diag(Arg3->getBeginLoc(), diag::err_opencl_enqueue_kernel_blocks_no_args); 293*0fca6ea1SDimitry Andric return true; 294*0fca6ea1SDimitry Andric } 295*0fca6ea1SDimitry Andric return false; 296*0fca6ea1SDimitry Andric } 297*0fca6ea1SDimitry Andric // we can have block + varargs. 298*0fca6ea1SDimitry Andric if (isBlockPointer(Arg3)) 299*0fca6ea1SDimitry Andric return (checkBlockArgs(SemaRef, Arg3) || 300*0fca6ea1SDimitry Andric checkOpenCLEnqueueVariadicArgs(SemaRef, TheCall, Arg3, 4)); 301*0fca6ea1SDimitry Andric // last two cases with either exactly 7 args or 7 args and varargs. 302*0fca6ea1SDimitry Andric if (NumArgs >= 7) { 303*0fca6ea1SDimitry Andric // check common block argument. 304*0fca6ea1SDimitry Andric Expr *Arg6 = TheCall->getArg(6); 305*0fca6ea1SDimitry Andric if (!isBlockPointer(Arg6)) { 306*0fca6ea1SDimitry Andric Diag(Arg6->getBeginLoc(), diag::err_opencl_builtin_expected_type) 307*0fca6ea1SDimitry Andric << TheCall->getDirectCallee() << "block"; 308*0fca6ea1SDimitry Andric return true; 309*0fca6ea1SDimitry Andric } 310*0fca6ea1SDimitry Andric if (checkBlockArgs(SemaRef, Arg6)) 311*0fca6ea1SDimitry Andric return true; 312*0fca6ea1SDimitry Andric 313*0fca6ea1SDimitry Andric // Forth argument has to be any integer type. 314*0fca6ea1SDimitry Andric if (!Arg3->getType()->isIntegerType()) { 315*0fca6ea1SDimitry Andric Diag(TheCall->getArg(3)->getBeginLoc(), 316*0fca6ea1SDimitry Andric diag::err_opencl_builtin_expected_type) 317*0fca6ea1SDimitry Andric << TheCall->getDirectCallee() << "integer"; 318*0fca6ea1SDimitry Andric return true; 319*0fca6ea1SDimitry Andric } 320*0fca6ea1SDimitry Andric // check remaining common arguments. 321*0fca6ea1SDimitry Andric Expr *Arg4 = TheCall->getArg(4); 322*0fca6ea1SDimitry Andric Expr *Arg5 = TheCall->getArg(5); 323*0fca6ea1SDimitry Andric 324*0fca6ea1SDimitry Andric // Fifth argument is always passed as a pointer to clk_event_t. 325*0fca6ea1SDimitry Andric if (!Arg4->isNullPointerConstant(Context, 326*0fca6ea1SDimitry Andric Expr::NPC_ValueDependentIsNotNull) && 327*0fca6ea1SDimitry Andric !Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) { 328*0fca6ea1SDimitry Andric Diag(TheCall->getArg(4)->getBeginLoc(), 329*0fca6ea1SDimitry Andric diag::err_opencl_builtin_expected_type) 330*0fca6ea1SDimitry Andric << TheCall->getDirectCallee() 331*0fca6ea1SDimitry Andric << Context.getPointerType(Context.OCLClkEventTy); 332*0fca6ea1SDimitry Andric return true; 333*0fca6ea1SDimitry Andric } 334*0fca6ea1SDimitry Andric 335*0fca6ea1SDimitry Andric // Sixth argument is always passed as a pointer to clk_event_t. 336*0fca6ea1SDimitry Andric if (!Arg5->isNullPointerConstant(Context, 337*0fca6ea1SDimitry Andric Expr::NPC_ValueDependentIsNotNull) && 338*0fca6ea1SDimitry Andric !(Arg5->getType()->isPointerType() && 339*0fca6ea1SDimitry Andric Arg5->getType()->getPointeeType()->isClkEventT())) { 340*0fca6ea1SDimitry Andric Diag(TheCall->getArg(5)->getBeginLoc(), 341*0fca6ea1SDimitry Andric diag::err_opencl_builtin_expected_type) 342*0fca6ea1SDimitry Andric << TheCall->getDirectCallee() 343*0fca6ea1SDimitry Andric << Context.getPointerType(Context.OCLClkEventTy); 344*0fca6ea1SDimitry Andric return true; 345*0fca6ea1SDimitry Andric } 346*0fca6ea1SDimitry Andric 347*0fca6ea1SDimitry Andric if (NumArgs == 7) 348*0fca6ea1SDimitry Andric return false; 349*0fca6ea1SDimitry Andric 350*0fca6ea1SDimitry Andric return checkOpenCLEnqueueVariadicArgs(SemaRef, TheCall, Arg6, 7); 351*0fca6ea1SDimitry Andric } 352*0fca6ea1SDimitry Andric 353*0fca6ea1SDimitry Andric // None of the specific case has been detected, give generic error 354*0fca6ea1SDimitry Andric Diag(TheCall->getBeginLoc(), diag::err_opencl_enqueue_kernel_incorrect_args); 355*0fca6ea1SDimitry Andric return true; 356*0fca6ea1SDimitry Andric } 357*0fca6ea1SDimitry Andric 358*0fca6ea1SDimitry Andric /// Returns OpenCL access qual. 359*0fca6ea1SDimitry Andric static OpenCLAccessAttr *getOpenCLArgAccess(const Decl *D) { 360*0fca6ea1SDimitry Andric return D->getAttr<OpenCLAccessAttr>(); 361*0fca6ea1SDimitry Andric } 362*0fca6ea1SDimitry Andric 363*0fca6ea1SDimitry Andric /// Returns true if pipe element type is different from the pointer. 364*0fca6ea1SDimitry Andric static bool checkPipeArg(Sema &S, CallExpr *Call) { 365*0fca6ea1SDimitry Andric const Expr *Arg0 = Call->getArg(0); 366*0fca6ea1SDimitry Andric // First argument type should always be pipe. 367*0fca6ea1SDimitry Andric if (!Arg0->getType()->isPipeType()) { 368*0fca6ea1SDimitry Andric S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_first_arg) 369*0fca6ea1SDimitry Andric << Call->getDirectCallee() << Arg0->getSourceRange(); 370*0fca6ea1SDimitry Andric return true; 371*0fca6ea1SDimitry Andric } 372*0fca6ea1SDimitry Andric OpenCLAccessAttr *AccessQual = 373*0fca6ea1SDimitry Andric getOpenCLArgAccess(cast<DeclRefExpr>(Arg0)->getDecl()); 374*0fca6ea1SDimitry Andric // Validates the access qualifier is compatible with the call. 375*0fca6ea1SDimitry Andric // OpenCL v2.0 s6.13.16 - The access qualifiers for pipe should only be 376*0fca6ea1SDimitry Andric // read_only and write_only, and assumed to be read_only if no qualifier is 377*0fca6ea1SDimitry Andric // specified. 378*0fca6ea1SDimitry Andric switch (Call->getDirectCallee()->getBuiltinID()) { 379*0fca6ea1SDimitry Andric case Builtin::BIread_pipe: 380*0fca6ea1SDimitry Andric case Builtin::BIreserve_read_pipe: 381*0fca6ea1SDimitry Andric case Builtin::BIcommit_read_pipe: 382*0fca6ea1SDimitry Andric case Builtin::BIwork_group_reserve_read_pipe: 383*0fca6ea1SDimitry Andric case Builtin::BIsub_group_reserve_read_pipe: 384*0fca6ea1SDimitry Andric case Builtin::BIwork_group_commit_read_pipe: 385*0fca6ea1SDimitry Andric case Builtin::BIsub_group_commit_read_pipe: 386*0fca6ea1SDimitry Andric if (!(!AccessQual || AccessQual->isReadOnly())) { 387*0fca6ea1SDimitry Andric S.Diag(Arg0->getBeginLoc(), 388*0fca6ea1SDimitry Andric diag::err_opencl_builtin_pipe_invalid_access_modifier) 389*0fca6ea1SDimitry Andric << "read_only" << Arg0->getSourceRange(); 390*0fca6ea1SDimitry Andric return true; 391*0fca6ea1SDimitry Andric } 392*0fca6ea1SDimitry Andric break; 393*0fca6ea1SDimitry Andric case Builtin::BIwrite_pipe: 394*0fca6ea1SDimitry Andric case Builtin::BIreserve_write_pipe: 395*0fca6ea1SDimitry Andric case Builtin::BIcommit_write_pipe: 396*0fca6ea1SDimitry Andric case Builtin::BIwork_group_reserve_write_pipe: 397*0fca6ea1SDimitry Andric case Builtin::BIsub_group_reserve_write_pipe: 398*0fca6ea1SDimitry Andric case Builtin::BIwork_group_commit_write_pipe: 399*0fca6ea1SDimitry Andric case Builtin::BIsub_group_commit_write_pipe: 400*0fca6ea1SDimitry Andric if (!(AccessQual && AccessQual->isWriteOnly())) { 401*0fca6ea1SDimitry Andric S.Diag(Arg0->getBeginLoc(), 402*0fca6ea1SDimitry Andric diag::err_opencl_builtin_pipe_invalid_access_modifier) 403*0fca6ea1SDimitry Andric << "write_only" << Arg0->getSourceRange(); 404*0fca6ea1SDimitry Andric return true; 405*0fca6ea1SDimitry Andric } 406*0fca6ea1SDimitry Andric break; 407*0fca6ea1SDimitry Andric default: 408*0fca6ea1SDimitry Andric break; 409*0fca6ea1SDimitry Andric } 410*0fca6ea1SDimitry Andric return false; 411*0fca6ea1SDimitry Andric } 412*0fca6ea1SDimitry Andric 413*0fca6ea1SDimitry Andric /// Returns true if pipe element type is different from the pointer. 414*0fca6ea1SDimitry Andric static bool checkPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { 415*0fca6ea1SDimitry Andric const Expr *Arg0 = Call->getArg(0); 416*0fca6ea1SDimitry Andric const Expr *ArgIdx = Call->getArg(Idx); 417*0fca6ea1SDimitry Andric const PipeType *PipeTy = cast<PipeType>(Arg0->getType()); 418*0fca6ea1SDimitry Andric const QualType EltTy = PipeTy->getElementType(); 419*0fca6ea1SDimitry Andric const PointerType *ArgTy = ArgIdx->getType()->getAs<PointerType>(); 420*0fca6ea1SDimitry Andric // The Idx argument should be a pointer and the type of the pointer and 421*0fca6ea1SDimitry Andric // the type of pipe element should also be the same. 422*0fca6ea1SDimitry Andric if (!ArgTy || 423*0fca6ea1SDimitry Andric !S.Context.hasSameType( 424*0fca6ea1SDimitry Andric EltTy, ArgTy->getPointeeType()->getCanonicalTypeInternal())) { 425*0fca6ea1SDimitry Andric S.Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) 426*0fca6ea1SDimitry Andric << Call->getDirectCallee() << S.Context.getPointerType(EltTy) 427*0fca6ea1SDimitry Andric << ArgIdx->getType() << ArgIdx->getSourceRange(); 428*0fca6ea1SDimitry Andric return true; 429*0fca6ea1SDimitry Andric } 430*0fca6ea1SDimitry Andric return false; 431*0fca6ea1SDimitry Andric } 432*0fca6ea1SDimitry Andric 433*0fca6ea1SDimitry Andric bool SemaOpenCL::checkBuiltinRWPipe(CallExpr *Call) { 434*0fca6ea1SDimitry Andric // OpenCL v2.0 s6.13.16.2 - The built-in read/write 435*0fca6ea1SDimitry Andric // functions have two forms. 436*0fca6ea1SDimitry Andric switch (Call->getNumArgs()) { 437*0fca6ea1SDimitry Andric case 2: 438*0fca6ea1SDimitry Andric if (checkPipeArg(SemaRef, Call)) 439*0fca6ea1SDimitry Andric return true; 440*0fca6ea1SDimitry Andric // The call with 2 arguments should be 441*0fca6ea1SDimitry Andric // read/write_pipe(pipe T, T*). 442*0fca6ea1SDimitry Andric // Check packet type T. 443*0fca6ea1SDimitry Andric if (checkPipePacketType(SemaRef, Call, 1)) 444*0fca6ea1SDimitry Andric return true; 445*0fca6ea1SDimitry Andric break; 446*0fca6ea1SDimitry Andric 447*0fca6ea1SDimitry Andric case 4: { 448*0fca6ea1SDimitry Andric if (checkPipeArg(SemaRef, Call)) 449*0fca6ea1SDimitry Andric return true; 450*0fca6ea1SDimitry Andric // The call with 4 arguments should be 451*0fca6ea1SDimitry Andric // read/write_pipe(pipe T, reserve_id_t, uint, T*). 452*0fca6ea1SDimitry Andric // Check reserve_id_t. 453*0fca6ea1SDimitry Andric if (!Call->getArg(1)->getType()->isReserveIDT()) { 454*0fca6ea1SDimitry Andric Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) 455*0fca6ea1SDimitry Andric << Call->getDirectCallee() << getASTContext().OCLReserveIDTy 456*0fca6ea1SDimitry Andric << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); 457*0fca6ea1SDimitry Andric return true; 458*0fca6ea1SDimitry Andric } 459*0fca6ea1SDimitry Andric 460*0fca6ea1SDimitry Andric // Check the index. 461*0fca6ea1SDimitry Andric const Expr *Arg2 = Call->getArg(2); 462*0fca6ea1SDimitry Andric if (!Arg2->getType()->isIntegerType() && 463*0fca6ea1SDimitry Andric !Arg2->getType()->isUnsignedIntegerType()) { 464*0fca6ea1SDimitry Andric Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) 465*0fca6ea1SDimitry Andric << Call->getDirectCallee() << getASTContext().UnsignedIntTy 466*0fca6ea1SDimitry Andric << Arg2->getType() << Arg2->getSourceRange(); 467*0fca6ea1SDimitry Andric return true; 468*0fca6ea1SDimitry Andric } 469*0fca6ea1SDimitry Andric 470*0fca6ea1SDimitry Andric // Check packet type T. 471*0fca6ea1SDimitry Andric if (checkPipePacketType(SemaRef, Call, 3)) 472*0fca6ea1SDimitry Andric return true; 473*0fca6ea1SDimitry Andric } break; 474*0fca6ea1SDimitry Andric default: 475*0fca6ea1SDimitry Andric Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_arg_num) 476*0fca6ea1SDimitry Andric << Call->getDirectCallee() << Call->getSourceRange(); 477*0fca6ea1SDimitry Andric return true; 478*0fca6ea1SDimitry Andric } 479*0fca6ea1SDimitry Andric 480*0fca6ea1SDimitry Andric return false; 481*0fca6ea1SDimitry Andric } 482*0fca6ea1SDimitry Andric 483*0fca6ea1SDimitry Andric bool SemaOpenCL::checkBuiltinReserveRWPipe(CallExpr *Call) { 484*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(Call, 2)) 485*0fca6ea1SDimitry Andric return true; 486*0fca6ea1SDimitry Andric 487*0fca6ea1SDimitry Andric if (checkPipeArg(SemaRef, Call)) 488*0fca6ea1SDimitry Andric return true; 489*0fca6ea1SDimitry Andric 490*0fca6ea1SDimitry Andric // Check the reserve size. 491*0fca6ea1SDimitry Andric if (!Call->getArg(1)->getType()->isIntegerType() && 492*0fca6ea1SDimitry Andric !Call->getArg(1)->getType()->isUnsignedIntegerType()) { 493*0fca6ea1SDimitry Andric Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) 494*0fca6ea1SDimitry Andric << Call->getDirectCallee() << getASTContext().UnsignedIntTy 495*0fca6ea1SDimitry Andric << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); 496*0fca6ea1SDimitry Andric return true; 497*0fca6ea1SDimitry Andric } 498*0fca6ea1SDimitry Andric 499*0fca6ea1SDimitry Andric // Since return type of reserve_read/write_pipe built-in function is 500*0fca6ea1SDimitry Andric // reserve_id_t, which is not defined in the builtin def file , we used int 501*0fca6ea1SDimitry Andric // as return type and need to override the return type of these functions. 502*0fca6ea1SDimitry Andric Call->setType(getASTContext().OCLReserveIDTy); 503*0fca6ea1SDimitry Andric 504*0fca6ea1SDimitry Andric return false; 505*0fca6ea1SDimitry Andric } 506*0fca6ea1SDimitry Andric 507*0fca6ea1SDimitry Andric bool SemaOpenCL::checkBuiltinCommitRWPipe(CallExpr *Call) { 508*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(Call, 2)) 509*0fca6ea1SDimitry Andric return true; 510*0fca6ea1SDimitry Andric 511*0fca6ea1SDimitry Andric if (checkPipeArg(SemaRef, Call)) 512*0fca6ea1SDimitry Andric return true; 513*0fca6ea1SDimitry Andric 514*0fca6ea1SDimitry Andric // Check reserve_id_t. 515*0fca6ea1SDimitry Andric if (!Call->getArg(1)->getType()->isReserveIDT()) { 516*0fca6ea1SDimitry Andric Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_invalid_arg) 517*0fca6ea1SDimitry Andric << Call->getDirectCallee() << getASTContext().OCLReserveIDTy 518*0fca6ea1SDimitry Andric << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); 519*0fca6ea1SDimitry Andric return true; 520*0fca6ea1SDimitry Andric } 521*0fca6ea1SDimitry Andric 522*0fca6ea1SDimitry Andric return false; 523*0fca6ea1SDimitry Andric } 524*0fca6ea1SDimitry Andric 525*0fca6ea1SDimitry Andric bool SemaOpenCL::checkBuiltinPipePackets(CallExpr *Call) { 526*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(Call, 1)) 527*0fca6ea1SDimitry Andric return true; 528*0fca6ea1SDimitry Andric 529*0fca6ea1SDimitry Andric if (!Call->getArg(0)->getType()->isPipeType()) { 530*0fca6ea1SDimitry Andric Diag(Call->getBeginLoc(), diag::err_opencl_builtin_pipe_first_arg) 531*0fca6ea1SDimitry Andric << Call->getDirectCallee() << Call->getArg(0)->getSourceRange(); 532*0fca6ea1SDimitry Andric return true; 533*0fca6ea1SDimitry Andric } 534*0fca6ea1SDimitry Andric 535*0fca6ea1SDimitry Andric return false; 536*0fca6ea1SDimitry Andric } 537*0fca6ea1SDimitry Andric 538*0fca6ea1SDimitry Andric bool SemaOpenCL::checkBuiltinToAddr(unsigned BuiltinID, CallExpr *Call) { 539*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(Call, 1)) 540*0fca6ea1SDimitry Andric return true; 541*0fca6ea1SDimitry Andric 542*0fca6ea1SDimitry Andric auto RT = Call->getArg(0)->getType(); 543*0fca6ea1SDimitry Andric if (!RT->isPointerType() || 544*0fca6ea1SDimitry Andric RT->getPointeeType().getAddressSpace() == LangAS::opencl_constant) { 545*0fca6ea1SDimitry Andric Diag(Call->getBeginLoc(), diag::err_opencl_builtin_to_addr_invalid_arg) 546*0fca6ea1SDimitry Andric << Call->getArg(0) << Call->getDirectCallee() << Call->getSourceRange(); 547*0fca6ea1SDimitry Andric return true; 548*0fca6ea1SDimitry Andric } 549*0fca6ea1SDimitry Andric 550*0fca6ea1SDimitry Andric if (RT->getPointeeType().getAddressSpace() != LangAS::opencl_generic) { 551*0fca6ea1SDimitry Andric Diag(Call->getArg(0)->getBeginLoc(), 552*0fca6ea1SDimitry Andric diag::warn_opencl_generic_address_space_arg) 553*0fca6ea1SDimitry Andric << Call->getDirectCallee()->getNameInfo().getAsString() 554*0fca6ea1SDimitry Andric << Call->getArg(0)->getSourceRange(); 555*0fca6ea1SDimitry Andric } 556*0fca6ea1SDimitry Andric 557*0fca6ea1SDimitry Andric RT = RT->getPointeeType(); 558*0fca6ea1SDimitry Andric auto Qual = RT.getQualifiers(); 559*0fca6ea1SDimitry Andric switch (BuiltinID) { 560*0fca6ea1SDimitry Andric case Builtin::BIto_global: 561*0fca6ea1SDimitry Andric Qual.setAddressSpace(LangAS::opencl_global); 562*0fca6ea1SDimitry Andric break; 563*0fca6ea1SDimitry Andric case Builtin::BIto_local: 564*0fca6ea1SDimitry Andric Qual.setAddressSpace(LangAS::opencl_local); 565*0fca6ea1SDimitry Andric break; 566*0fca6ea1SDimitry Andric case Builtin::BIto_private: 567*0fca6ea1SDimitry Andric Qual.setAddressSpace(LangAS::opencl_private); 568*0fca6ea1SDimitry Andric break; 569*0fca6ea1SDimitry Andric default: 570*0fca6ea1SDimitry Andric llvm_unreachable("Invalid builtin function"); 571*0fca6ea1SDimitry Andric } 572*0fca6ea1SDimitry Andric Call->setType(getASTContext().getPointerType( 573*0fca6ea1SDimitry Andric getASTContext().getQualifiedType(RT.getUnqualifiedType(), Qual))); 574*0fca6ea1SDimitry Andric 575*0fca6ea1SDimitry Andric return false; 576*0fca6ea1SDimitry Andric } 577*0fca6ea1SDimitry Andric 578*0fca6ea1SDimitry Andric } // namespace clang 579