Index: include/clang/Basic/Builtins.h =================================================================== --- include/clang/Basic/Builtins.h +++ include/clang/Basic/Builtins.h @@ -36,6 +36,7 @@ CXX_LANG = 0x4, // builtin for cplusplus only. OBJC_LANG = 0x8, // builtin for objective-c and objective-c++ MS_LANG = 0x10, // builtin requires MS mode. + OCLC_LANG = 0x20,// builtin for OpenCL C only. ALL_LANGUAGES = C_LANG | CXX_LANG | OBJC_LANG, // builtin for all languages. ALL_GNU_LANGUAGES = ALL_LANGUAGES | GNU_LANG, // builtin requires GNU mode. ALL_MS_LANGUAGES = ALL_LANGUAGES | MS_LANG // builtin requires MS mode. Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -1252,6 +1252,32 @@ BUILTIN(__builtin_nontemporal_store, "v.", "t") BUILTIN(__builtin_nontemporal_load, "v.", "t") +// OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions. +// We need the generic prototype, since the packet type could be anything. +LANGBUILTIN(read_pipe, "i.", "tn", OCLC_LANG) +LANGBUILTIN(write_pipe, "i.", "tn", OCLC_LANG) + +LANGBUILTIN(reserve_read_pipe, "i.", "tn", OCLC_LANG) +LANGBUILTIN(reserve_write_pipe, "i.", "tn", OCLC_LANG) + +LANGBUILTIN(commit_write_pipe, "v.", "tn", OCLC_LANG) +LANGBUILTIN(commit_read_pipe, "v.", "tn", OCLC_LANG) + +LANGBUILTIN(sub_group_reserve_read_pipe, "i.", "tn", OCLC_LANG) +LANGBUILTIN(sub_group_reserve_write_pipe, "i.", "tn", OCLC_LANG) + +LANGBUILTIN(sub_group_commit_read_pipe, "v.", "tn", OCLC_LANG) +LANGBUILTIN(sub_group_commit_write_pipe, "v.", "tn", OCLC_LANG) + +LANGBUILTIN(work_group_reserve_read_pipe, "i.", "tn", OCLC_LANG) +LANGBUILTIN(work_group_reserve_write_pipe, "i.", "tn", OCLC_LANG) + +LANGBUILTIN(work_group_commit_read_pipe, "v.", "tn", OCLC_LANG) +LANGBUILTIN(work_group_commit_write_pipe, "v.", "tn", OCLC_LANG) + +LANGBUILTIN(get_pipe_num_packets, "Ui.", "tn", OCLC_LANG) +LANGBUILTIN(get_pipe_max_packets, "Ui.", "tn", OCLC_LANG) + #undef BUILTIN #undef LIBBUILTIN #undef LANGBUILTIN Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -7659,6 +7659,16 @@ def err_opencl_implicit_vector_conversion : Error< "implicit conversions between vector types (%0 and %1) are not permitted">; +// OpenCL v2.0 s6.13.6 -- Builtin Pipe Functions +def err_opencl_builtin_pipe_first_arg : Error< + "first argument to %0 must be a pipe type">; +def err_opencl_builtin_pipe_arg_num : Error< + "invalid number of arguments to function: %0">; +def err_opencl_builtin_pipe_invalid_arg : Error< + "invalid argument type to function %0 (expecting %1)">; +def err_opencl_builtin_pipe_invalid_access_modifier : Error< + "invalid pipe access modifier (expecting %0)">; + // OpenCL Section 6.8.g def err_opencl_unknown_type_specifier : Error< "OpenCL does not support the '%0' %select{type qualifier|storage class specifier}1">; Index: lib/Basic/Builtins.cpp =================================================================== --- lib/Basic/Builtins.cpp +++ lib/Basic/Builtins.cpp @@ -69,7 +69,8 @@ bool MSModeUnsupported = !LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG); bool ObjCUnsupported = !LangOpts.ObjC1 && BuiltinInfo.Langs == OBJC_LANG; - return !BuiltinsUnsupported && !MathBuiltinsUnsupported && + bool OclCUnsupported = !LangOpts.OpenCL && BuiltinInfo.Langs == OCLC_LANG; + return !BuiltinsUnsupported && !MathBuiltinsUnsupported && !OclCUnsupported && !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported; } Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -1963,6 +1963,135 @@ return RValue::get(llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy)); break; } + + case Builtin::BIread_pipe: + case Builtin::BIwrite_pipe: { + llvm::LLVMContext &Ctxt = getLLVMContext(); + Value *Arg0 = EmitScalarExpr(E->getArg(0)), + *Arg1 = EmitScalarExpr(E->getArg(1)); + + // Type of the generic packet parameter. + llvm::Type *I8PTy = llvm::PointerType::get(llvm::Type::getInt8Ty(Ctxt), 4U); + + // Testing which overloaded version we should generate the call for. + if (2U == E->getNumArgs()) { + // The name is hard-coded for now, since we would like to avoid the + // AST rewrite for the infinite user define types. + const char *Name = + (BuiltinID == Builtin::BIread_pipe) ? "read_pipe_2" : "write_pipe_2"; + // Re-Creating the function type for this call, since the original type + // is variadic, we make them to be generic type. + llvm::Type *ArgTys[] = {Arg0->getType(), I8PTy}; + llvm::FunctionType *FTy = llvm::FunctionType::get( + Int32Ty, llvm::ArrayRef(ArgTys), false); + Value *BCast = Builder.CreatePointerCast(Arg1, I8PTy); + return RValue::get(Builder.CreateCall( + CGM.CreateRuntimeFunction(FTy, Name), {Arg0, BCast})); + } else { + assert(4 == E->getNumArgs() && + "Illegal number of parameters to pipe function"); + const char *Name = + (BuiltinID == Builtin::BIread_pipe) ? "read_pipe_4" : "write_pipe_4"; + + llvm::Type *ArgTys[] = {Arg0->getType(), Arg1->getType(), Int32Ty, I8PTy}; + Value *Arg2 = EmitScalarExpr(E->getArg(2)), + *Arg3 = EmitScalarExpr(E->getArg(3)); + llvm::FunctionType *FTy = llvm::FunctionType::get( + Int32Ty, llvm::ArrayRef(ArgTys), false); + Value *BCast = Builder.CreatePointerCast(Arg3, I8PTy); + // We know the third argument is an integer type, but we may need to cast + // it to i32. + if (Arg2->getType() != Int32Ty) + Arg2 = Builder.CreateZExtOrTrunc(Arg2, Int32Ty); + return RValue::get(Builder.CreateCall( + CGM.CreateRuntimeFunction(FTy, Name), {Arg0, Arg1, Arg2, BCast})); + } + } + case Builtin::BIreserve_read_pipe: + case Builtin::BIreserve_write_pipe: + case Builtin::BIwork_group_reserve_read_pipe: + case Builtin::BIwork_group_reserve_write_pipe: + case Builtin::BIsub_group_reserve_read_pipe: + case Builtin::BIsub_group_reserve_write_pipe: { + // Composing the mangled name for the function. + const char *Name; + if (BuiltinID == Builtin::BIreserve_read_pipe) + Name = "reserve_read_pipe"; + else if (BuiltinID == Builtin::BIreserve_write_pipe) + Name = "reserve_write_pipe"; + else if (BuiltinID == Builtin::BIwork_group_reserve_read_pipe) + Name = "work_group_reserve_read_pipe"; + else if (BuiltinID == Builtin::BIwork_group_reserve_write_pipe) + Name = "work_group_reserve_write_pipe"; + else if (BuiltinID == Builtin::BIsub_group_reserve_read_pipe) + Name = "sub_group_reserve_read_pipe"; + else + Name = "sub_group_reserve_write_pipe"; + + Value *Arg0 = EmitScalarExpr(E->getArg(0)), + *Arg1 = EmitScalarExpr(E->getArg(1)); + llvm::Type *ReservedIDTy = ConvertType(getContext().OCLReserveIDTy); + + // Building the generic function prototype. + llvm::Type *ArgTys[] = {Arg0->getType(), Int32Ty}; + llvm::FunctionType *FTy = llvm::FunctionType::get( + ReservedIDTy, llvm::ArrayRef(ArgTys), false); + // We know the second argument is an integer type, but we may need to cast + // it to i32. + if (Arg1->getType() != Int32Ty) + Arg1 = Builder.CreateZExtOrTrunc(Arg1, Int32Ty); + return RValue::get( + Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name), {Arg0, Arg1})); + } + case Builtin::BIcommit_read_pipe: + case Builtin::BIcommit_write_pipe: + case Builtin::BIwork_group_commit_read_pipe: + case Builtin::BIwork_group_commit_write_pipe: + case Builtin::BIsub_group_commit_read_pipe: + case Builtin::BIsub_group_commit_write_pipe: { + const char *Name; + if (BuiltinID == Builtin::BIcommit_read_pipe) + Name = "commit_read_pipe"; + else if (BuiltinID == Builtin::BIcommit_write_pipe) + Name = "commit_write_pipe"; + else if (BuiltinID == Builtin::BIwork_group_commit_read_pipe) + Name = "work_group_commit_read_pipe"; + else if (BuiltinID == Builtin::BIwork_group_commit_write_pipe) + Name = "work_group_commit_write_pipe"; + else if (BuiltinID == Builtin::BIsub_group_commit_read_pipe) + Name = "sub_group_commit_read_pipe"; + else + Name = "sub_group_commit_write_pipe"; + + Value *Arg0 = EmitScalarExpr(E->getArg(0)), + *Arg1 = EmitScalarExpr(E->getArg(1)); + + // Building the generic function prototype. + llvm::Type *ArgTys[] = {Arg0->getType(), Arg1->getType()}; + llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), + llvm::ArrayRef(ArgTys), false); + + return RValue::get( + Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name), {Arg0, Arg1})); + } + case Builtin::BIget_pipe_num_packets: + case Builtin::BIget_pipe_max_packets: { + const char *Name; + if (BuiltinID == Builtin::BIget_pipe_num_packets) + Name = "get_pipe_num_packets"; + else + Name = "get_pipe_max_packets"; + + // Building the generic function prototype. + Value *Arg0 = EmitScalarExpr(E->getArg(0)); + llvm::Type *ArgTys[] = {Arg0->getType()}; + llvm::FunctionType *FTy = llvm::FunctionType::get( + Int32Ty, llvm::ArrayRef(ArgTys), false); + + return RValue::get( + Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name), {Arg0})); + } } // If this is an alias for a lib function (e.g. __builtin_sin), emit Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -258,6 +258,195 @@ return false; } +/// Returns readable name for a call. +static StringRef getFunctionName(CallExpr *Call) { + return cast(Call->getCalleeDecl())->getName(); +} + +/// Returns OpenCL access qual. +// TODO: Refine OpenCLImageAccessAttr to OpenCLAccessAttr since pipe can use +// it too +static OpenCLImageAccessAttr *getOpenCLArgAccess(const Decl *D) { + if (D->hasAttr()) + return D->getAttr(); + return nullptr; +} + +/// Returns true if pipe element type is different from the pointer. +static bool checkOpenCLPipeArg(Sema &S, CallExpr *Call) { + const Expr *Arg0 = Call->getArg(0); + // First argument type should always be pipe. + if (!Arg0->getType()->isPipeType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg) + << getFunctionName(Call) << Arg0->getSourceRange(); + return true; + } + OpenCLImageAccessAttr *AccessQual = + getOpenCLArgAccess(cast(Arg0)->getDecl()); + // Validates the access modifier is compatible with the call. + // From OpenCL C Specification 6.13.16 the access qualifiers for + // pipe should only be read_only and write_only, and assumed to + // be read_only if no qualifier is specified. + bool isValid = true; + // TODO: Now we check for all the pipe builtin with access qualifier, but in + // OpenCL spec does not tell about group functions, need to fix after get + // clarify from Khronos. + bool ReadOnly = getFunctionName(Call).find("read") != StringRef::npos; + if (ReadOnly) + isValid = AccessQual == nullptr || AccessQual->isReadOnly(); + else + isValid = AccessQual != nullptr && AccessQual->isWriteOnly(); + if (!isValid) { + const char *AM = ReadOnly ? "read_only" : "write_only"; + S.Diag(Arg0->getLocStart(), + diag::err_opencl_builtin_pipe_invalid_access_modifier) + << AM << Arg0->getSourceRange(); + return true; + } + + return false; +} + +/// Returns true if pipe element type is different from the pointer. +static bool checkOpenCLPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { + const Expr *Arg0 = Call->getArg(0); + const Expr *ArgIdx = Call->getArg(Idx); + const PipeType *PipeTy = cast(Arg0->getType()); + const Type *EltTy = PipeTy->getElementType().getTypePtr(); + const PointerType *ArgTy = + dyn_cast(ArgIdx->getType().getTypePtr()); + // The Idx argument should be a pointer and the type of the pointer and + // the type of pipe element should also be the same. + if (!ArgTy || EltTy != ArgTy->getPointeeType().getTypePtr()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << getFunctionName(Call) + << S.Context.getPointerType(PipeTy->getElementType()) + << ArgIdx->getSourceRange(); + return true; + } + return false; +} + +// \brief Performs semantic analysis for the read/write_pipe call. +// \param S Reference to the semantic analyzer. +// \param Call A pointer to the builtin call. +// \return True if a semantic error has been found, false otherwise. +static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { + // Two kinds of read/write pipe + // From OpenCL C Specification 6.13.16.2 the built-in read/write + // functions have following forms. + switch (Call->getNumArgs()) { + case 2: { + if (checkOpenCLPipeArg(S, Call)) + return true; + // The call with 2 arguments should be + // read/write_pipe(pipe T, T*) + // check packet type T + if (checkOpenCLPipePacketType(S, Call, 1)) + return true; + } break; + + case 4: { + if (checkOpenCLPipeArg(S, Call)) + return true; + // The call with 4 arguments should be + // read/write_pipe(pipe T, reserve_id_t, uint, T*) + // check reserve_id_t + if (!Call->getArg(1)->getType()->isReserveIDT()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << getFunctionName(Call) << S.Context.OCLReserveIDTy + << Call->getArg(1)->getSourceRange(); + return true; + } + + // check the index + const Expr *Arg2 = Call->getArg(2); + if (!Arg2->getType()->isIntegerType() && + !Arg2->getType()->isUnsignedIntegerType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << getFunctionName(Call) << S.Context.UnsignedIntTy + << Arg2->getSourceRange(); + return true; + } + + // check packet type T + if (checkOpenCLPipePacketType(S, Call, 3)) + return true; + } break; + default: + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_arg_num) + << getFunctionName(Call) << Call->getSourceRange(); + return true; + } + + return false; +} + +// \brief Performs a semantic analysis on the {work_group_/sub_group_ +// /_}reserve_{read/write}_pipe +// \param S Reference to the semantic analyzer. +// \param Call The call to the builtin function to be analyzed. +// \return True if a semantic error was found, false otherwise. +static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { + if (checkArgCount(S, Call, 2)) + return true; + + if (checkOpenCLPipeArg(S, Call)) + return true; + + // check the reverse size + if (!Call->getArg(1)->getType()->isIntegerType() && + !Call->getArg(1)->getType()->isUnsignedIntegerType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << getFunctionName(Call) << S.Context.UnsignedIntTy + << Call->getArg(1)->getSourceRange(); + return true; + } + + return false; +} + +// \brief Performs a semantic analysis on {work_group_/sub_group_ +// /_}commit_{read/write}_pipe +// \param S Reference to the semantic analyzer. +// \param Call The call to the builtin function to be analyzed. +// \return True if a semantic error was found, false otherwise. +static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { + if (checkArgCount(S, Call, 2)) + return true; + + if (checkOpenCLPipeArg(S, Call)) + return true; + + // check reserve_id_t + if (!Call->getArg(1)->getType()->isReserveIDT()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << getFunctionName(Call) << S.Context.OCLReserveIDTy + << Call->getArg(1)->getSourceRange(); + return true; + } + + return false; +} + +// \brief Performs a semantic analysis on the call to built-in Pipe +// Query Functions. +// \param S Reference to the semantic analyzer. +// \param Call The call to the builtin function to be analyzed. +// \return True if a semantic error was found, false otherwise. +static bool SemaBuiltinPipePacketes(Sema &S, CallExpr *Call) { + if (checkArgCount(S, Call, 1)) + return true; + + if (!Call->getArg(0)->getType()->isPipeType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg) + << getFunctionName(Call) << Call->getArg(0)->getSourceRange(); + return true; + } + + return false; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -563,6 +752,40 @@ TheCall->setType(Context.VoidPtrTy); break; + case Builtin::BIread_pipe: + case Builtin::BIwrite_pipe: + // Since those two functions are declared with var args, therefore we need + // a semantic check for the argument. + if (SemaBuiltinRWPipe(*this, TheCall)) + return ExprError(); + break; + case Builtin::BIreserve_read_pipe: + case Builtin::BIreserve_write_pipe: + case Builtin::BIwork_group_reserve_read_pipe: + case Builtin::BIwork_group_reserve_write_pipe: + case Builtin::BIsub_group_reserve_read_pipe: + case Builtin::BIsub_group_reserve_write_pipe: + if (SemaBuiltinReserveRWPipe(*this, TheCall)) + return ExprError(); + // Since return type of reserve_read/write_pipe built-in function is + // reserve_id_t, which is not defined in the builtin def, we used int as + // return type and need to override the return type of these functions + TheCall->setType(Context.OCLReserveIDTy); + break; + case Builtin::BIcommit_read_pipe: + case Builtin::BIcommit_write_pipe: + case Builtin::BIwork_group_commit_read_pipe: + case Builtin::BIwork_group_commit_write_pipe: + case Builtin::BIsub_group_commit_read_pipe: + case Builtin::BIsub_group_commit_write_pipe: + if (SemaBuiltinCommitRWPipe(*this, TheCall)) + return ExprError(); + break; + case Builtin::BIget_pipe_num_packets: + case Builtin::BIget_pipe_max_packets: + if (SemaBuiltinPipePacketes(*this, TheCall)) + return ExprError(); + break; } Index: test/CodeGenOpenCL/pipe_builtin.cl =================================================================== --- /dev/null +++ test/CodeGenOpenCL/pipe_builtin.cl @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck %s + +// CHECK: %opencl.pipe_t = type opaque +// CHECK: %opencl.reserve_id_t = type opaque + +void test1(read_only pipe int p, global int *ptr) { + // CHECK: call i32 @read_pipe_2(%opencl.pipe_t* %{{.*}}, i8 addrspace(4)* %{{.*}}) + read_pipe(p, ptr); + // CHECK: call %opencl.reserve_id_t* @reserve_read_pipe(%opencl.pipe_t* %{{.*}}, i32 {{.*}}) + reserve_id_t rid = reserve_read_pipe(p, 2); + // CHECK: call i32 @read_pipe_4(%opencl.pipe_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}, i32 {{.*}}, i8 addrspace(4)* %{{.*}}) + read_pipe(p, rid, 2, ptr); + // CHECK: call void @commit_read_pipe(%opencl.pipe_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}) + commit_read_pipe(p, rid); +} + +void test2(write_only pipe int p, global int *ptr) { + // CHECK: call i32 @write_pipe_2(%opencl.pipe_t* %{{.*}}, i8 addrspace(4)* %{{.*}}) + write_pipe(p, ptr); + // CHECK: call %opencl.reserve_id_t* @reserve_write_pipe(%opencl.pipe_t* %{{.*}}, i32 {{.*}}) + reserve_id_t rid = reserve_write_pipe(p, 2); + // CHECK: call i32 @write_pipe_4(%opencl.pipe_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}, i32 {{.*}}, i8 addrspace(4)* %{{.*}}) + write_pipe(p, rid, 2, ptr); + // CHECK: call void @commit_write_pipe(%opencl.pipe_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}) + commit_write_pipe(p, rid); +} + +void test3(read_only pipe int p, global int *ptr) { + // CHECK: call %opencl.reserve_id_t* @work_group_reserve_read_pipe(%opencl.pipe_t* %{{.*}}, i32 {{.*}}) + reserve_id_t rid = work_group_reserve_read_pipe(p, 2); + // CHECK: call void @work_group_commit_read_pipe(%opencl.pipe_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}) + work_group_commit_read_pipe(p, rid); +} + +void test4(write_only pipe int p, global int *ptr) { + // CHECK: call %opencl.reserve_id_t* @work_group_reserve_write_pipe(%opencl.pipe_t* %{{.*}}, i32 {{.*}}) + reserve_id_t rid = work_group_reserve_write_pipe(p, 2); + // CHECK: call void @work_group_commit_write_pipe(%opencl.pipe_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}) + work_group_commit_write_pipe(p, rid); +} + +void test5(read_only pipe int p, global int *ptr) { + // CHECK: call %opencl.reserve_id_t* @sub_group_reserve_read_pipe(%opencl.pipe_t* %{{.*}}, i32 {{.*}}) + reserve_id_t rid = sub_group_reserve_read_pipe(p, 2); + // CHECK: call void @sub_group_commit_read_pipe(%opencl.pipe_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}) + sub_group_commit_read_pipe(p, rid); +} + +void test6(write_only pipe int p, global int *ptr) { + // CHECK: call %opencl.reserve_id_t* @sub_group_reserve_write_pipe(%opencl.pipe_t* %{{.*}}, i32 {{.*}}) + reserve_id_t rid = sub_group_reserve_write_pipe(p, 2); + // CHECK: call void @sub_group_commit_write_pipe(%opencl.pipe_t* %{{.*}}, %opencl.reserve_id_t* %{{.*}}) + sub_group_commit_write_pipe(p, rid); +} + +void test7(write_only pipe int p, global int *ptr) { + // CHECK: call i32 @get_pipe_num_packets(%opencl.pipe_t* %{{.*}}) + *ptr = get_pipe_num_packets(p); + // CHECK: call i32 @get_pipe_max_packets(%opencl.pipe_t* %{{.*}}) + *ptr = get_pipe_max_packets(p); +} Index: test/SemaOpenCL/invalid-pipe-builtin-cl2.0.cl =================================================================== --- /dev/null +++ test/SemaOpenCL/invalid-pipe-builtin-cl2.0.cl @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0 + +void test1(read_only pipe int p, global int* ptr){ + int tmp; + reserve_id_t rid; + + // read/write_pipe + read_pipe(tmp, p); // expected-error {{first argument to read_pipe must be a pipe type}} + read_pipe(p); // expected-error {{invalid number of arguments to function: read_pipe}} + read_pipe(p, tmp, tmp, ptr); // expected-error {{invalid argument type to function read_pipe (expecting 'reserve_id_t')}} + read_pipe(p, rid, rid, ptr); // expected-error {{invalid argument type to function read_pipe (expecting 'unsigned int')}} + read_pipe(p, tmp); // expected-error {{invalid argument type to function read_pipe (expecting 'int *')}} + write_pipe(p, ptr); // expected-error {{invalid pipe access modifier (expecting write_only)}} + write_pipe(p, rid, tmp, ptr); // expected-error {{invalid pipe access modifier (expecting write_only)}} + + // reserve_read/write_pipe + reserve_read_pipe(p, ptr); // expected-error{{invalid argument type to function reserve_read_pipe (expecting 'unsigned int')}} + work_group_reserve_read_pipe(tmp, tmp); // expected-error{{first argument to work_group_reserve_read_pipe must be a pipe type}} + sub_group_reserve_write_pipe(p, tmp); // expected-error{{invalid pipe access modifier (expecting write_only)}} + + // commit_read/write_pipe + commit_read_pipe(tmp, rid); // expected-error{{first argument to commit_read_pipe must be a pipe type}} + work_group_commit_read_pipe(p, tmp); // expected-error{{invalid argument type to function work_group_commit_read_pipe (expecting 'reserve_id_t')}} + sub_group_commit_write_pipe(p, tmp); // expected-error{{nvalid pipe access modifier (expecting write_only)}} +} + +void test2(write_only pipe int p, global int* ptr){ + int tmp; + reserve_id_t rid; + + // read/write_pipe + write_pipe(tmp, p); // expected-error {{first argument to write_pipe must be a pipe type}} + write_pipe(p); // expected-error {{invalid number of arguments to function: write_pipe}} + write_pipe(p, tmp, tmp, ptr); // expected-error {{invalid argument type to function write_pipe (expecting 'reserve_id_t')}} + write_pipe(p, rid, rid, ptr); // expected-error {{invalid argument type to function write_pipe (expecting 'unsigned int')}} + write_pipe(p, tmp); // expected-error {{invalid argument type to function write_pipe (expecting 'int *')}} + read_pipe(p, ptr); // expected-error {{invalid pipe access modifier (expecting read_only)}} + read_pipe(p, rid, tmp, ptr); // expected-error {{invalid pipe access modifier (expecting read_only)}} + + // reserve_read/write_pipe + reserve_write_pipe(p, ptr); // expected-error{{invalid argument type to function reserve_write_pipe (expecting 'unsigned int')}} + work_group_reserve_write_pipe(tmp, tmp); // expected-error{{first argument to work_group_reserve_write_pipe must be a pipe type}} + sub_group_reserve_read_pipe(p, tmp); // expected-error{{invalid pipe access modifier (expecting read_only)}} + + // commit_read/write_pipe + commit_write_pipe(tmp, rid); // expected-error{{first argument to commit_write_pipe must be a pipe type}} + work_group_commit_write_pipe(p, tmp); // expected-error{{invalid argument type to function work_group_commit_write_pipe (expecting 'reserve_id_t')}} + sub_group_commit_read_pipe(p, tmp); // expected-error{{nvalid pipe access modifier (expecting read_only)}} +} + +void test3(){ + int tmp; + get_pipe_num_packets(tmp); // expected-error {{first argument to get_pipe_num_packets must be a pipe type}} + get_pipe_max_packets(tmp); // expected-error {{first argument to get_pipe_max_packets must be a pipe type}} +}