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