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
20namespace clang {
21SemaOpenCL::SemaOpenCL(Sema &S) : SemaBase(S) {}
22
23void SemaOpenCL::handleNoSVMAttr(Decl *D, const ParsedAttr &AL) {
24 if (getLangOpts().getOpenCLCompatibleVersion() < 200)
25 Diag(Loc: AL.getLoc(), DiagID: diag::err_attribute_requires_opencl_version)
26 << AL << "2.0" << 1;
27 else
28 Diag(Loc: AL.getLoc(), DiagID: diag::warn_opencl_attr_deprecated_ignored)
29 << AL << getLangOpts().getOpenCLVersionString();
30}
31
32void 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(Loc: AL.getLoc(), DiagID: diag::warn_duplicate_declspec)
41 << AL.getAttrName()->getName() << AL.getRange();
42 } else {
43 Diag(Loc: AL.getLoc(), DiagID: 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>(Val: D)) {
60 const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr();
61 if (AL.getAttrName()->getName().contains(Other: "read_write")) {
62 bool ReadWriteImagesUnsupported =
63 (getLangOpts().getOpenCLCompatibleVersion() < 200) ||
64 (getLangOpts().getOpenCLCompatibleVersion() == 300 &&
65 !SemaRef.getOpenCLOptions().isSupported(
66 Ext: "__opencl_c_read_write_images", LO: getLangOpts()));
67 if (ReadWriteImagesUnsupported || DeclTy->isPipeType()) {
68 Diag(Loc: AL.getLoc(), DiagID: 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(A: ::new (getASTContext()) OpenCLAccessAttr(getASTContext(), AL));
77}
78
79void SemaOpenCL::handleSubGroupSize(Decl *D, const ParsedAttr &AL) {
80 uint32_t SGSize;
81 const Expr *E = AL.getArgAsExpr(Arg: 0);
82 if (!SemaRef.checkUInt32Argument(AI: AL, Expr: E, Val&: SGSize))
83 return;
84 if (SGSize == 0) {
85 Diag(Loc: AL.getLoc(), DiagID: 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(Loc: AL.getLoc(), DiagID: diag::warn_duplicate_attribute) << AL;
94
95 D->addAttr(A: ::new (getASTContext())
96 OpenCLIntelReqdSubGroupSizeAttr(getASTContext(), AL, SGSize));
97}
98
99static 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.
105static bool checkBlockArgs(Sema &S, Expr *BlockArg) {
106 const BlockPointerType *BPT =
107 cast<BlockPointerType>(Val: 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>(Val: BlockArg)) {
124 BlockDecl *BD = cast<BlockExpr>(Val: BlockArg)->getBlockDecl();
125 ErrorLoc = BD->getParamDecl(i: ArgCounter)->getBeginLoc();
126 } else if (isa<DeclRefExpr>(Val: BlockArg)) {
127 ErrorLoc = cast<DeclRefExpr>(Val: BlockArg)->getBeginLoc();
128 }
129 S.Diag(Loc: ErrorLoc,
130 DiagID: diag::err_opencl_enqueue_kernel_blocks_non_local_void_args);
131 IllegalParams = true;
132 }
133 }
134
135 return IllegalParams;
136}
137
138bool 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(Ext: "cl_khr_subgroups",
143 LO: getLangOpts()) &&
144 !SemaRef.getOpenCLOptions().isSupported(Ext: "__opencl_c_subgroups",
145 LO: getLangOpts())) {
146 Diag(Loc: Call->getBeginLoc(), DiagID: 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
154bool SemaOpenCL::checkBuiltinNDRangeAndBlock(CallExpr *TheCall) {
155 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 2))
156 return true;
157
158 if (checkSubgroupExt(Call: TheCall))
159 return true;
160
161 // First argument is an ndrange_t type.
162 Expr *NDRangeArg = TheCall->getArg(Arg: 0);
163 if (NDRangeArg->getType().getUnqualifiedType().getAsString() != "ndrange_t") {
164 Diag(Loc: NDRangeArg->getBeginLoc(), DiagID: diag::err_opencl_builtin_expected_type)
165 << TheCall->getDirectCallee() << "'ndrange_t'";
166 return true;
167 }
168
169 Expr *BlockArg = TheCall->getArg(Arg: 1);
170 if (!isBlockPointer(Arg: BlockArg)) {
171 Diag(Loc: BlockArg->getBeginLoc(), DiagID: diag::err_opencl_builtin_expected_type)
172 << TheCall->getDirectCallee() << "block";
173 return true;
174 }
175 return checkBlockArgs(S&: SemaRef, BlockArg);
176}
177
178bool SemaOpenCL::checkBuiltinKernelWorkGroupSize(CallExpr *TheCall) {
179 if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: 1))
180 return true;
181
182 Expr *BlockArg = TheCall->getArg(Arg: 0);
183 if (!isBlockPointer(Arg: BlockArg)) {
184 Diag(Loc: BlockArg->getBeginLoc(), DiagID: diag::err_opencl_builtin_expected_type)
185 << TheCall->getDirectCallee() << "block";
186 return true;
187 }
188 return checkBlockArgs(S&: SemaRef, BlockArg);
189}
190
191/// Diagnose integer type and any valid implicit conversion to it.
192static 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(Loc: E->getBeginLoc(),
197 DiagID: 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, T: IntT, CC: E->getBeginLoc());
203 return false;
204}
205
206static 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, E: TheCall->getArg(Arg: I),
211 IntT: 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.
217static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall,
218 Expr *BlockArg,
219 unsigned NumNonVarArgs) {
220 const BlockPointerType *BPT =
221 cast<BlockPointerType>(Val: 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(Loc: TheCall->getBeginLoc(),
230 DiagID: 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, Start: NumNonVarArgs,
236 End: TotalNumArgs - 1);
237}
238
239bool SemaOpenCL::checkBuiltinEnqueueKernel(CallExpr *TheCall) {
240 ASTContext &Context = getASTContext();
241 unsigned NumArgs = TheCall->getNumArgs();
242
243 if (NumArgs < 4) {
244 Diag(Loc: TheCall->getBeginLoc(), DiagID: 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(Arg: 0);
250 Expr *Arg1 = TheCall->getArg(Arg: 1);
251 Expr *Arg2 = TheCall->getArg(Arg: 2);
252 Expr *Arg3 = TheCall->getArg(Arg: 3);
253
254 // First argument always needs to be a queue_t type.
255 if (!Arg0->getType()->isQueueT()) {
256 Diag(Loc: TheCall->getArg(Arg: 0)->getBeginLoc(),
257 DiagID: 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(Loc: TheCall->getArg(Arg: 1)->getBeginLoc(),
265 DiagID: 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(Loc: TheCall->getArg(Arg: 2)->getBeginLoc(),
273 DiagID: 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(Arg: Arg3)) {
283 Diag(Loc: Arg3->getBeginLoc(), DiagID: 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>(Val: Arg3->getType().getCanonicalType());
290 if (BPT->getPointeeType()->castAs<FunctionProtoType>()->getNumParams() >
291 0) {
292 Diag(Loc: Arg3->getBeginLoc(), DiagID: 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(Arg: Arg3))
299 return (checkBlockArgs(S&: SemaRef, BlockArg: Arg3) ||
300 checkOpenCLEnqueueVariadicArgs(S&: SemaRef, TheCall, BlockArg: Arg3, NumNonVarArgs: 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(Arg: 6);
305 if (!isBlockPointer(Arg: Arg6)) {
306 Diag(Loc: Arg6->getBeginLoc(), DiagID: diag::err_opencl_builtin_expected_type)
307 << TheCall->getDirectCallee() << "block";
308 return true;
309 }
310 if (checkBlockArgs(S&: SemaRef, BlockArg: Arg6))
311 return true;
312
313 // Forth argument has to be any integer type.
314 if (!Arg3->getType()->isIntegerType()) {
315 Diag(Loc: TheCall->getArg(Arg: 3)->getBeginLoc(),
316 DiagID: diag::err_opencl_builtin_expected_type)
317 << TheCall->getDirectCallee() << "integer";
318 return true;
319 }
320 // check remaining common arguments.
321 Expr *Arg4 = TheCall->getArg(Arg: 4);
322 Expr *Arg5 = TheCall->getArg(Arg: 5);
323
324 // Fifth argument is always passed as a pointer to clk_event_t.
325 if (!Arg4->isNullPointerConstant(Ctx&: Context,
326 NPC: Expr::NPC_ValueDependentIsNotNull) &&
327 !Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) {
328 Diag(Loc: TheCall->getArg(Arg: 4)->getBeginLoc(),
329 DiagID: diag::err_opencl_builtin_expected_type)
330 << TheCall->getDirectCallee()
331 << Context.getPointerType(T: Context.OCLClkEventTy);
332 return true;
333 }
334
335 // Sixth argument is always passed as a pointer to clk_event_t.
336 if (!Arg5->isNullPointerConstant(Ctx&: Context,
337 NPC: Expr::NPC_ValueDependentIsNotNull) &&
338 !(Arg5->getType()->isPointerType() &&
339 Arg5->getType()->getPointeeType()->isClkEventT())) {
340 Diag(Loc: TheCall->getArg(Arg: 5)->getBeginLoc(),
341 DiagID: diag::err_opencl_builtin_expected_type)
342 << TheCall->getDirectCallee()
343 << Context.getPointerType(T: Context.OCLClkEventTy);
344 return true;
345 }
346
347 if (NumArgs == 7)
348 return false;
349
350 return checkOpenCLEnqueueVariadicArgs(S&: SemaRef, TheCall, BlockArg: Arg6, NumNonVarArgs: 7);
351 }
352
353 // None of the specific case has been detected, give generic error
354 Diag(Loc: TheCall->getBeginLoc(), DiagID: diag::err_opencl_enqueue_kernel_incorrect_args);
355 return true;
356}
357
358/// Returns OpenCL access qual.
359static OpenCLAccessAttr *getOpenCLArgAccess(const Decl *D) {
360 return D->getAttr<OpenCLAccessAttr>();
361}
362
363/// Returns true if pipe element type is different from the pointer.
364static bool checkPipeArg(Sema &S, CallExpr *Call) {
365 const Expr *Arg0 = Call->getArg(Arg: 0);
366 // First argument type should always be pipe.
367 if (!Arg0->getType()->isPipeType()) {
368 S.Diag(Loc: Call->getBeginLoc(), DiagID: diag::err_opencl_builtin_pipe_first_arg)
369 << Call->getDirectCallee() << Arg0->getSourceRange();
370 return true;
371 }
372 OpenCLAccessAttr *AccessQual =
373 getOpenCLArgAccess(D: cast<DeclRefExpr>(Val: 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(Loc: Arg0->getBeginLoc(),
388 DiagID: 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(Loc: Arg0->getBeginLoc(),
402 DiagID: 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.
414static bool checkPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) {
415 const Expr *Arg0 = Call->getArg(Arg: 0);
416 const Expr *ArgIdx = Call->getArg(Arg: Idx);
417 const PipeType *PipeTy = cast<PipeType>(Val: 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 T1: EltTy, T2: ArgTy->getPointeeType()->getCanonicalTypeInternal())) {
425 S.Diag(Loc: Call->getBeginLoc(), DiagID: diag::err_opencl_builtin_pipe_invalid_arg)
426 << Call->getDirectCallee() << S.Context.getPointerType(T: EltTy)
427 << ArgIdx->getType() << ArgIdx->getSourceRange();
428 return true;
429 }
430 return false;
431}
432
433bool 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(S&: 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(S&: SemaRef, Call, Idx: 1))
444 return true;
445 break;
446
447 case 4: {
448 if (checkPipeArg(S&: 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(Arg: 1)->getType()->isReserveIDT()) {
454 Diag(Loc: Call->getBeginLoc(), DiagID: diag::err_opencl_builtin_pipe_invalid_arg)
455 << Call->getDirectCallee() << getASTContext().OCLReserveIDTy
456 << Call->getArg(Arg: 1)->getType() << Call->getArg(Arg: 1)->getSourceRange();
457 return true;
458 }
459
460 // Check the index.
461 const Expr *Arg2 = Call->getArg(Arg: 2);
462 if (!Arg2->getType()->isIntegerType() &&
463 !Arg2->getType()->isUnsignedIntegerType()) {
464 Diag(Loc: Call->getBeginLoc(), DiagID: 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(S&: SemaRef, Call, Idx: 3))
472 return true;
473 } break;
474 default:
475 Diag(Loc: Call->getBeginLoc(), DiagID: diag::err_opencl_builtin_pipe_arg_num)
476 << Call->getDirectCallee() << Call->getSourceRange();
477 return true;
478 }
479
480 return false;
481}
482
483bool SemaOpenCL::checkBuiltinReserveRWPipe(CallExpr *Call) {
484 if (SemaRef.checkArgCount(Call, DesiredArgCount: 2))
485 return true;
486
487 if (checkPipeArg(S&: SemaRef, Call))
488 return true;
489
490 // Check the reserve size.
491 if (!Call->getArg(Arg: 1)->getType()->isIntegerType() &&
492 !Call->getArg(Arg: 1)->getType()->isUnsignedIntegerType()) {
493 Diag(Loc: Call->getBeginLoc(), DiagID: diag::err_opencl_builtin_pipe_invalid_arg)
494 << Call->getDirectCallee() << getASTContext().UnsignedIntTy
495 << Call->getArg(Arg: 1)->getType() << Call->getArg(Arg: 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
507bool SemaOpenCL::checkBuiltinCommitRWPipe(CallExpr *Call) {
508 if (SemaRef.checkArgCount(Call, DesiredArgCount: 2))
509 return true;
510
511 if (checkPipeArg(S&: SemaRef, Call))
512 return true;
513
514 // Check reserve_id_t.
515 if (!Call->getArg(Arg: 1)->getType()->isReserveIDT()) {
516 Diag(Loc: Call->getBeginLoc(), DiagID: diag::err_opencl_builtin_pipe_invalid_arg)
517 << Call->getDirectCallee() << getASTContext().OCLReserveIDTy
518 << Call->getArg(Arg: 1)->getType() << Call->getArg(Arg: 1)->getSourceRange();
519 return true;
520 }
521
522 return false;
523}
524
525bool SemaOpenCL::checkBuiltinPipePackets(CallExpr *Call) {
526 if (SemaRef.checkArgCount(Call, DesiredArgCount: 1))
527 return true;
528
529 if (!Call->getArg(Arg: 0)->getType()->isPipeType()) {
530 Diag(Loc: Call->getBeginLoc(), DiagID: diag::err_opencl_builtin_pipe_first_arg)
531 << Call->getDirectCallee() << Call->getArg(Arg: 0)->getSourceRange();
532 return true;
533 }
534
535 return false;
536}
537
538bool SemaOpenCL::checkBuiltinToAddr(unsigned BuiltinID, CallExpr *Call) {
539 if (SemaRef.checkArgCount(Call, DesiredArgCount: 1))
540 return true;
541
542 auto RT = Call->getArg(Arg: 0)->getType();
543 if (!RT->isPointerType() ||
544 RT->getPointeeType().getAddressSpace() == LangAS::opencl_constant) {
545 Diag(Loc: Call->getBeginLoc(), DiagID: diag::err_opencl_builtin_to_addr_invalid_arg)
546 << Call->getArg(Arg: 0) << Call->getDirectCallee() << Call->getSourceRange();
547 return true;
548 }
549
550 if (RT->getPointeeType().getAddressSpace() != LangAS::opencl_generic) {
551 Diag(Loc: Call->getArg(Arg: 0)->getBeginLoc(),
552 DiagID: diag::warn_opencl_generic_address_space_arg)
553 << Call->getDirectCallee()->getNameInfo().getAsString()
554 << Call->getArg(Arg: 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 T: getASTContext().getQualifiedType(T: RT.getUnqualifiedType(), Qs: Qual)));
574
575 return false;
576}
577
578} // namespace clang
579