Index: include/clang/AST/OperationKinds.def =================================================================== --- include/clang/AST/OperationKinds.def +++ include/clang/AST/OperationKinds.def @@ -321,6 +321,9 @@ // Convert a zero value for OpenCL event_t initialization. CAST_OPERATION(ZeroToOCLEvent) +// Convert a zero value for OpenCL queue_t initialization. +CAST_OPERATION(ZeroToOCLQueue) + // Convert a pointer to a different address space. CAST_OPERATION(AddressSpaceConversion) Index: include/clang/Sema/Initialization.h =================================================================== --- include/clang/Sema/Initialization.h +++ include/clang/Sema/Initialization.h @@ -724,6 +724,8 @@ SK_StdInitializerListConstructorCall, /// \brief Initialize an OpenCL sampler from an integer. SK_OCLSamplerInit, + /// \brief Initialize queue_t from 0. + SK_OCLZeroQueue, /// \brief Passing zero to a function where OpenCL event_t is expected. SK_OCLZeroEvent }; @@ -1110,6 +1112,9 @@ /// constant. void AddOCLZeroEventStep(QualType T); + /// \brief Add a step to initialize an OpenCL queue_t from 0. + void AddOCLZeroQueueStep(QualType T); + /// \brief Add steps to unwrap a initializer list for a reference around a /// single element and rewrap it at the end. void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic); Index: include/clang/Sema/Overload.h =================================================================== --- include/clang/Sema/Overload.h +++ include/clang/Sema/Overload.h @@ -83,6 +83,7 @@ ICK_TransparentUnionConversion, ///< Transparent Union Conversions ICK_Writeback_Conversion, ///< Objective-C ARC writeback conversion ICK_Zero_Event_Conversion, ///< Zero constant to event (OpenCL1.2 6.12.10) + ICK_Zero_Queue_Conversion, ///< Zero constant to queue ICK_C_Only_Conversion, ///< Conversions allowed in C, but not C++ ICK_Incompatible_Pointer_Conversion, ///< C-only conversion between pointers /// with incompatible types Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -1603,6 +1603,7 @@ case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: case CK_ZeroToOCLEvent: + case CK_ZeroToOCLQueue: case CK_IntToOCLSampler: assert(!getType()->isBooleanType() && "unheralded conversion to bool"); goto CheckNoBasePath; Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -8257,6 +8257,7 @@ case CK_IntegralComplexToFloatingComplex: case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLEvent: + case CK_ZeroToOCLQueue: case CK_NonAtomicToAtomic: case CK_AddressSpaceConversion: case CK_IntToOCLSampler: @@ -8749,6 +8750,7 @@ case CK_CopyAndAutoreleaseBlockObject: case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLEvent: + case CK_ZeroToOCLQueue: case CK_NonAtomicToAtomic: case CK_AddressSpaceConversion: case CK_IntToOCLSampler: Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -3755,6 +3755,8 @@ ConvertType(E->getType())); return MakeAddrLValue(V, E->getType(), LV.getAlignmentSource()); } + case CK_ZeroToOCLQueue: + llvm_unreachable("NULL to OpenCL queue lvalue cast is not valid"); case CK_ZeroToOCLEvent: llvm_unreachable("NULL to OpenCL event lvalue cast is not valid"); } Index: lib/CodeGen/CGExprAgg.cpp =================================================================== --- lib/CodeGen/CGExprAgg.cpp +++ lib/CodeGen/CGExprAgg.cpp @@ -749,6 +749,7 @@ case CK_CopyAndAutoreleaseBlockObject: case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLEvent: + case CK_ZeroToOCLQueue: case CK_AddressSpaceConversion: case CK_IntToOCLSampler: llvm_unreachable("cast kind invalid for aggregate types"); Index: lib/CodeGen/CGExprComplex.cpp =================================================================== --- lib/CodeGen/CGExprComplex.cpp +++ lib/CodeGen/CGExprComplex.cpp @@ -480,6 +480,7 @@ case CK_CopyAndAutoreleaseBlockObject: case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLEvent: + case CK_ZeroToOCLQueue: case CK_AddressSpaceConversion: case CK_IntToOCLSampler: llvm_unreachable("invalid cast kind for complex value"); Index: lib/CodeGen/CGExprConstant.cpp =================================================================== --- lib/CodeGen/CGExprConstant.cpp +++ lib/CodeGen/CGExprConstant.cpp @@ -752,6 +752,7 @@ case CK_FloatingToBoolean: case CK_FloatingCast: case CK_ZeroToOCLEvent: + case CK_ZeroToOCLQueue: return nullptr; } llvm_unreachable("Invalid CastKind"); Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -1574,6 +1574,11 @@ return llvm::Constant::getNullValue(ConvertType(DestTy)); } + case CK_ZeroToOCLQueue: { + assert(DestTy->isQueueT() && "CK_ZeroToOCLQueue cast on non queue_t type"); + return llvm::Constant::getNullValue(ConvertType(DestTy)); + } + case CK_IntToOCLSampler: return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF); Index: lib/Edit/RewriteObjCFoundationAPI.cpp =================================================================== --- lib/Edit/RewriteObjCFoundationAPI.cpp +++ lib/Edit/RewriteObjCFoundationAPI.cpp @@ -1076,6 +1076,7 @@ case CK_CopyAndAutoreleaseBlockObject: case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLEvent: + case CK_ZeroToOCLQueue: case CK_IntToOCLSampler: return false; Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -9621,6 +9621,18 @@ return ResultTy; } + if (getLangOpts().OpenCLVersion >= 200) { + if (LHSIsNull && RHSType->isQueueT()) { + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); + return ResultTy; + } + + if (LHSType->isQueueT() && RHSIsNull) { + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); + return ResultTy; + } + } + return InvalidOperands(Loc, LHS, RHS); } Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -3882,6 +3882,12 @@ From->getValueKind()).get(); break; + case ICK_Zero_Queue_Conversion: + From = ImpCastExprToType(From, ToType, + CK_ZeroToOCLQueue, + From->getValueKind()).get(); + break; + case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: case ICK_Function_To_Pointer: Index: lib/Sema/SemaInit.cpp =================================================================== --- lib/Sema/SemaInit.cpp +++ lib/Sema/SemaInit.cpp @@ -3073,6 +3073,7 @@ case SK_StdInitializerListConstructorCall: case SK_OCLSamplerInit: case SK_OCLZeroEvent: + case SK_OCLZeroQueue: break; case SK_ConversionSequence: @@ -3334,6 +3335,13 @@ Steps.push_back(S); } +void InitializationSequence::AddOCLZeroQueueStep(QualType T) { + Step S; + S.Kind = SK_OCLZeroQueue; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::RewrapReferenceInitList(QualType T, InitListExpr *Syntactic) { assert(Syntactic->getNumInits() == 1 && @@ -4981,6 +4989,20 @@ return true; } +static bool TryOCLZeroQueueInitialization(Sema &S, + InitializationSequence &Sequence, + QualType DestType, + Expr *Initializer) { + if (!S.getLangOpts().OpenCL || S.getLangOpts().OpenCLVersion < 200 || + !DestType->isQueueT() || + !Initializer->isIntegerConstantExpr(S.getASTContext()) || + (Initializer->EvaluateKnownConstInt(S.getASTContext()) != 0)) + return false; + + Sequence.AddOCLZeroQueueStep(DestType); + return true; +} + InitializationSequence::InitializationSequence(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -5179,6 +5201,9 @@ if (TryOCLZeroEventInitialization(S, *this, DestType, Initializer)) return; + if (TryOCLZeroQueueInitialization(S, *this, DestType, Initializer)) + return; + // Handle initialization in C AddCAssignmentStep(DestType); MaybeProduceObjCObject(S, *this, Entity); @@ -6414,7 +6439,8 @@ case SK_ProduceObjCObject: case SK_StdInitializerList: case SK_OCLSamplerInit: - case SK_OCLZeroEvent: { + case SK_OCLZeroEvent: + case SK_OCLZeroQueue: { assert(Args.size() == 1); CurInit = Args[0]; if (!CurInit.get()) return ExprError(); @@ -7088,6 +7114,15 @@ CurInit.get()->getValueKind()); break; } + case SK_OCLZeroQueue: { + assert(Step->Type->isQueueT() && + "Event initialization on non queue type."); + + CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type, + CK_ZeroToOCLQueue, + CurInit.get()->getValueKind()); + break; + } } } @@ -7873,6 +7908,10 @@ case SK_OCLZeroEvent: OS << "OpenCL event_t from zero"; break; + + case SK_OCLZeroQueue: + OS << "OpenCL queue_t from zero"; + break; } OS << " [" << S->Type.getAsString() << ']'; Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -1781,6 +1781,11 @@ From->EvaluateKnownConstInt(S.getASTContext()) == 0) { SCS.Second = ICK_Zero_Event_Conversion; FromType = ToType; + } else if (ToType->isQueueT() && + From->isIntegerConstantExpr(S.getASTContext()) && + (From->EvaluateKnownConstInt(S.getASTContext()) == 0)) { + SCS.Second = ICK_Zero_Queue_Conversion; + FromType = ToType; } else { // No second conversion required. SCS.Second = ICK_Identity; @@ -5155,6 +5160,7 @@ case ICK_Function_Conversion: case ICK_Integral_Promotion: case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere. + case ICK_Zero_Queue_Conversion: return true; case ICK_Boolean_Conversion: Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -341,6 +341,7 @@ case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: case CK_ZeroToOCLEvent: + case CK_ZeroToOCLQueue: case CK_IntToOCLSampler: case CK_LValueBitCast: { // Delegate to SValBuilder to process. Index: test/CodeGenOpenCL/null_queue.cl =================================================================== --- /dev/null +++ test/CodeGenOpenCL/null_queue.cl @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -O0 -cl-std=CL2.0 -emit-llvm %s -o - | FileCheck %s +extern queue_t get_default_queue(); + +bool compare() { + return 0 == get_default_queue() && + get_default_queue() == 0; + // CHECK: icmp eq %opencl.queue_t* null, %{{.*}} + // CHECK: icmp eq %opencl.queue_t* %{{.*}}, null +} + +void func(queue_t q); + +void init() { + queue_t q = 0; + func(0); + // CHECK: store %opencl.queue_t* null, %opencl.queue_t** %q + // CHECK: call void @func(%opencl.queue_t* null) +} Index: test/SemaOpenCL/null_queue.cl =================================================================== --- /dev/null +++ test/SemaOpenCL/null_queue.cl @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -pedantic -fsyntax-only +extern queue_t get_default_queue(); + +bool compare() { + return 1 == get_default_queue() && // expected-error{{invalid operands to binary expression ('int' and 'queue_t')}} + get_default_queue() == 1; // expected-error{{invalid operands to binary expression ('queue_t' and 'int')}} +} + +void init() { + queue_t q1 = 1; // expected-error{{initializing 'queue_t' with an expression of incompatible type 'int'}} + queue_t q = 0; +} Index: test/SemaOpenCL/queue_t_overload.cl =================================================================== --- /dev/null +++ test/SemaOpenCL/queue_t_overload.cl @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -pedantic -fsyntax-only + +void __attribute__((overloadable)) foo(queue_t, __local char *); // expected-note {{candidate function not viable: no known conversion from 'int' to 'queue_t' for 1st argument}} // expected-note {{candidate function}} +void __attribute__((overloadable)) foo(queue_t, __local float *); // expected-note {{candidate function not viable: no known conversion from 'int' to 'queue_t' for 1st argument}} // expected-note {{candidate function}} + +void kernel ker(__local char *src1, __local float *src2, __global int *src3) { + queue_t q; + foo(q, src1); + foo(0, src2); + foo(q, src3); // expected-error {{call to 'foo' is ambiguous}} + foo(1, src3); // expected-error {{no matching function for call to 'foo'}} +}