xref: /freebsd-src/contrib/llvm-project/clang/lib/Sema/SemaOpenCL.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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