From: Xiuli Pan Date: Sat, 9 Jan 2016 12:53:17 +0000 (+0000) Subject: [OpenCL] Pipe type support X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=97f9428a0d4209f43695e87fdbed479eade6dd45;p=clang [OpenCL] Pipe type support Summary: Support for OpenCL 2.0 pipe type. This is a bug-fix version for bader's patch reviews.llvm.org/D14441 Reviewers: pekka.jaaskelainen, Anastasia Subscribers: bader, Anastasia, cfe-commits Differential Revision: http://reviews.llvm.org/D15603 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@257254 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index b66009e909..9140eabe83 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -131,6 +131,7 @@ class ASTContext : public RefCountedBase { mutable llvm::FoldingSet AutoTypes; mutable llvm::FoldingSet AtomicTypes; llvm::FoldingSet AttributedTypes; + mutable llvm::FoldingSet PipeTypes; mutable llvm::FoldingSet QualifiedTemplateNames; mutable llvm::FoldingSet DependentTemplateNames; @@ -1079,6 +1080,9 @@ public: /// blocks. QualType getBlockDescriptorType() const; + /// \brief Return pipe type for the specified type. + QualType getPipeType(QualType T) const; + /// Gets the struct used to keep track of the extended descriptor for /// pointer to blocks. QualType getBlockDescriptorExtendedType() const; diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index e6f758364a..0c25a45c1c 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -978,6 +978,8 @@ DEF_TRAVERSE_TYPE(ObjCObjectPointerType, DEF_TRAVERSE_TYPE(AtomicType, { TRY_TO(TraverseType(T->getValueType())); }) +DEF_TRAVERSE_TYPE(PipeType, { TRY_TO(TraverseType(T->getElementType())); }) + #undef DEF_TRAVERSE_TYPE // ----------------- TypeLoc traversal ----------------- @@ -1206,6 +1208,8 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, DEF_TRAVERSE_TYPELOC(AtomicType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); }) +DEF_TRAVERSE_TYPELOC(PipeType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); }) + #undef DEF_TRAVERSE_TYPELOC // ----------------- Decl traversal ----------------- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 0c08130da6..d63b2c43d5 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1721,6 +1721,7 @@ public: bool isNDRangeT() const; // OpenCL ndrange_t bool isReserveIDT() const; // OpenCL reserve_id_t + bool isPipeType() const; // OpenCL pipe type bool isOpenCLSpecificType() const; // Any OpenCL specific type /// Determines if this type, which must satisfy @@ -5015,6 +5016,41 @@ class AtomicType : public Type, public llvm::FoldingSetNode { } }; +/// PipeType - OpenCL20. +class PipeType : public Type, public llvm::FoldingSetNode { + QualType ElementType; + + PipeType(QualType elemType, QualType CanonicalPtr) : + Type(Pipe, CanonicalPtr, elemType->isDependentType(), + elemType->isInstantiationDependentType(), + elemType->isVariablyModifiedType(), + elemType->containsUnexpandedParameterPack()), + ElementType(elemType) {} + friend class ASTContext; // ASTContext creates these. + +public: + + QualType getElementType() const { return ElementType; } + + bool isSugared() const { return false; } + + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { + ID.AddPointer(T.getAsOpaquePtr()); + } + + + static bool classof(const Type *T) { + return T->getTypeClass() == Pipe; + } + +}; + /// A qualifier set is used to build a set of qualifiers. class QualifierCollector : public Qualifiers { public: @@ -5461,9 +5497,13 @@ inline bool Type::isImageType() const { isImage1dBufferT(); } +inline bool Type::isPipeType() const { + return isa(CanonicalType); +} + inline bool Type::isOpenCLSpecificType() const { return isSamplerT() || isEventT() || isImageType() || isClkEventT() || - isQueueT() || isNDRangeT() || isReserveIDT(); + isQueueT() || isNDRangeT() || isReserveIDT() || isPipeType(); } inline bool Type::isTemplateTypeParmType() const { diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 26feda5d76..29035a4177 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -2033,7 +2033,26 @@ public: } }; +struct PipeTypeLocInfo { + SourceLocation KWLoc; +}; + +class PipeTypeLoc : public ConcreteTypeLoc { +public: + TypeLoc getValueLoc() const { return this->getInnerTypeLoc(); } + + SourceRange getLocalSourceRange() const { return SourceRange(getKWLoc()); } + + SourceLocation getKWLoc() const { return this->getLocalData()->KWLoc; } + void setKWLoc(SourceLocation Loc) { this->getLocalData()->KWLoc = Loc; } + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setKWLoc(Loc); + } + + QualType getInnerType() const { return this->getTypePtr()->getElementType(); } +}; } #endif diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 2549f0bf50..8caf102414 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -104,6 +104,7 @@ NON_CANONICAL_UNLESS_DEPENDENT_TYPE(PackExpansion, Type) TYPE(ObjCObject, Type) TYPE(ObjCInterface, ObjCObjectType) TYPE(ObjCObjectPointer, Type) +TYPE(Pipe, Type) TYPE(Atomic, Type) #ifdef LAST_TYPE diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index db8169531e..6ba482c78e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -7642,6 +7642,10 @@ def err_wrong_sampler_addressspace: Error< "sampler type cannot be used with the __local and __global address space qualifiers">; def err_opencl_global_invalid_addr_space : Error< "program scope variable must reside in %0 address space">; +def err_missing_actual_pipe_type : Error< + "missing actual type specifier for pipe">; +def err_reference_pipe_type : Error < + "pipes packet types cannot be of reference type">; def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">; def err_opencl_kernel_attr : Error<"attribute %0 can only be applied to a kernel function">; diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index 1d59d64d6b..e284171f77 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -36,6 +36,11 @@ namespace clang { TSS_unsigned }; + enum TypeSpecifiersPipe { + TSP_unspecified, + TSP_pipe + }; + /// \brief Specifies the kind of type. enum TypeSpecifierType { TST_unspecified, diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 9252d9947a..65a77accf9 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -519,6 +519,8 @@ KEYWORD(vec_step , KEYOPENCL|KEYALTIVEC|KEYZVECTOR) // OpenMP Type Traits KEYWORD(__builtin_omp_required_simd_align, KEYALL) +KEYWORD(pipe , KEYOPENCL) + // Borland Extensions. KEYWORD(__pascal , KEYALL) diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index e9fdb707f2..064d37b2a0 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -337,6 +337,7 @@ private: unsigned TypeAltiVecPixel : 1; unsigned TypeAltiVecBool : 1; unsigned TypeSpecOwned : 1; + unsigned TypeSpecPipe : 1; // type-qualifiers unsigned TypeQualifiers : 4; // Bitwise OR of TQ. @@ -385,6 +386,7 @@ private: SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc; SourceLocation FS_forceinlineLoc; SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc, ConceptLoc; + SourceLocation TQ_pipeLoc; WrittenBuiltinSpecs writtenBS; void SaveWrittenBuiltinSpecs(); @@ -420,6 +422,7 @@ public: TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false), + TypeSpecPipe(false), TypeQualifiers(TQ_unspecified), FS_inline_specified(false), FS_forceinline_specified(false), @@ -473,6 +476,7 @@ public: bool isTypeAltiVecBool() const { return TypeAltiVecBool; } bool isTypeSpecOwned() const { return TypeSpecOwned; } bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); } + bool isTypeSpecPipe() const { return TypeSpecPipe; } ParsedType getRepAsType() const { assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type"); @@ -532,6 +536,7 @@ public: SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; } SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; } SourceLocation getAtomicSpecLoc() const { return TQ_atomicLoc; } + SourceLocation getPipeLoc() const { return TQ_pipeLoc; } /// \brief Clear out all of the type qualifiers. void ClearTypeQualifiers() { @@ -540,6 +545,7 @@ public: TQ_restrictLoc = SourceLocation(); TQ_volatileLoc = SourceLocation(); TQ_atomicLoc = SourceLocation(); + TQ_pipeLoc = SourceLocation(); } // function-specifier @@ -643,6 +649,9 @@ public: bool SetTypeAltiVecBool(bool isAltiVecBool, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, const PrintingPolicy &Policy); + bool SetTypePipe(bool isPipe, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy); bool SetTypeSpecError(); void UpdateDeclRep(Decl *Rep) { assert(isDeclRep((TST) TypeSpecType)); @@ -1081,7 +1090,7 @@ typedef SmallVector CachedTokens; /// This is intended to be a small value object. struct DeclaratorChunk { enum { - Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren + Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren, Pipe } Kind; /// Loc - The place where this type was defined. @@ -1409,6 +1418,13 @@ struct DeclaratorChunk { } }; + struct PipeTypeInfo : TypeInfoCommon { + /// The access writes. + unsigned AccessWrites : 3; + + void destroy() {} + }; + union { TypeInfoCommon Common; PointerTypeInfo Ptr; @@ -1417,6 +1433,7 @@ struct DeclaratorChunk { FunctionTypeInfo Fun; BlockPointerTypeInfo Cls; MemberPointerTypeInfo Mem; + PipeTypeInfo PipeInfo; }; void destroy() { @@ -1428,6 +1445,7 @@ struct DeclaratorChunk { case DeclaratorChunk::Array: return Arr.destroy(); case DeclaratorChunk::MemberPointer: return Mem.destroy(); case DeclaratorChunk::Paren: return; + case DeclaratorChunk::Pipe: return PipeInfo.destroy(); } } @@ -1526,6 +1544,17 @@ struct DeclaratorChunk { return I; } + /// \brief Return a DeclaratorChunk for a block. + static DeclaratorChunk getPipe(unsigned TypeQuals, + SourceLocation Loc) { + DeclaratorChunk I; + I.Kind = Pipe; + I.Loc = Loc; + I.Cls.TypeQuals = TypeQuals; + I.Cls.AttrList = 0; + return I; + } + static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS, unsigned TypeQuals, SourceLocation Loc) { @@ -2026,6 +2055,7 @@ public: case DeclaratorChunk::Array: case DeclaratorChunk::BlockPointer: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: return false; } llvm_unreachable("Invalid type chunk"); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 279afbe740..c82684ee45 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1269,6 +1269,8 @@ public: SourceLocation Loc, DeclarationName Entity); QualType BuildParenType(QualType T); QualType BuildAtomicType(QualType T, SourceLocation Loc); + QualType BuildPipeType(QualType T, + SourceLocation Loc); TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 16bda6ea03..0dfb8cf371 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -907,7 +907,9 @@ namespace clang { /// \brief A DecayedType record. TYPE_DECAYED = 41, /// \brief An AdjustedType record. - TYPE_ADJUSTED = 42 + TYPE_ADJUSTED = 42, + /// \brief A PipeType record. + TYPE_PIPE = 43 }; /// \brief The type IDs for special types constructed by semantic diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index d4abbe47ca..64386967b2 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1836,6 +1836,13 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Align = static_cast(Width); } } + break; + + case Type::Pipe: { + TypeInfo Info = getTypeInfo(cast(T)->getElementType()); + Width = Info.Width; + Align = Info.Align; + } } @@ -2663,6 +2670,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { case Type::FunctionProto: case Type::BlockPointer: case Type::MemberPointer: + case Type::Pipe: return type; // These types can be variably-modified. All these modifications @@ -3117,6 +3125,32 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef ArgArray, return QualType(FTP, 0); } +/// Return pipe type for the specified type. +QualType ASTContext::getPipeType(QualType T) const { + llvm::FoldingSetNodeID ID; + PipeType::Profile(ID, T); + + void *InsertPos = 0; + if (PipeType *PT = PipeTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(PT, 0); + + // If the pipe element type isn't canonical, this won't be a canonical type + // either, so fill in the canonical type field. + QualType Canonical; + if (!T.isCanonical()) { + Canonical = getPipeType(getCanonicalType(T)); + + // Get the new insert position for the node we care about. + PipeType *NewIP = PipeTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!NewIP && "Shouldn't be in the map!"); + (void)NewIP; + } + PipeType *New = new (*this, TypeAlignment) PipeType(T, Canonical); + Types.push_back(New); + PipeTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + #ifndef NDEBUG static bool NeedsInjectedClassNameType(const RecordDecl *D) { if (!isa(D)) return false; @@ -5857,6 +5891,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::Auto: return; + case Type::Pipe: #define ABSTRACT_TYPE(KIND, BASE) #define TYPE(KIND, BASE) #define DEPENDENT_TYPE(KIND, BASE) \ @@ -7792,6 +7827,24 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, return QualType(); } + case Type::Pipe: + { + // Merge two pointer types, while trying to preserve typedef info + QualType LHSValue = LHS->getAs()->getElementType(); + QualType RHSValue = RHS->getAs()->getElementType(); + if (Unqualified) { + LHSValue = LHSValue.getUnqualifiedType(); + RHSValue = RHSValue.getUnqualifiedType(); + } + QualType ResultType = mergeTypes(LHSValue, RHSValue, false, + Unqualified); + if (ResultType.isNull()) return QualType(); + if (getCanonicalType(LHSValue) == getCanonicalType(ResultType)) + return LHS; + if (getCanonicalType(RHSValue) == getCanonicalType(ResultType)) + return RHS; + return getPipeType(ResultType); + } } llvm_unreachable("Invalid Type::Class!"); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 359db1ba81..916f108179 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -878,6 +878,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, break; } + case Type::Pipe: { + if (!IsStructurallyEquivalent(Context, + cast(T1)->getElementType(), + cast(T2)->getElementType())) + return false; + break; + } + } // end switch return true; diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 8018188a6b..3f6b682f23 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1509,6 +1509,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::ObjCInterface: case Type::ObjCObjectPointer: case Type::Atomic: + case Type::Pipe: llvm_unreachable("type is illegal as a nested name specifier"); case Type::SubstTemplateTypeParmPack: @@ -2682,6 +2683,13 @@ void CXXNameMangler::mangleType(const AtomicType *T) { mangleType(T->getValueType()); } +void CXXNameMangler::mangleType(const PipeType *T) { + // Pipe type mangling rules are described in SPIR 2.0 specification + // A.1 Data types and A.3 Summary of changes + // ::= 8ocl_pipe + Out << "8ocl_pipe"; +} + void CXXNameMangler::mangleIntegerLiteral(QualType T, const llvm::APSInt &Value) { // ::= L E # integer literal diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index d45232b6de..4a45f9e405 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -2428,6 +2428,15 @@ void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, Qualifiers, mangleArtificalTagType(TTK_Struct, TemplateMangling, {"__clang"}); } +void MicrosoftCXXNameMangler::mangleType(const PipeType *T, Qualifiers, + SourceRange Range) { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this OpenCL pipe type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + void MicrosoftMangleContextImpl::mangleCXXName(const NamedDecl *D, raw_ostream &Out) { assert((isa(D) || isa(D)) && diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index a15569ad02..b467dac66b 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -3361,6 +3361,8 @@ static CachedProperties computeCachedProperties(const Type *T) { return Cache::get(cast(T)->getPointeeType()); case Type::Atomic: return Cache::get(cast(T)->getValueType()); + case Type::Pipe: + return Cache::get(cast(T)->getElementType()); } llvm_unreachable("unhandled type class"); @@ -3443,6 +3445,8 @@ static LinkageInfo computeLinkageInfo(const Type *T) { return computeLinkageInfo(cast(T)->getPointeeType()); case Type::Atomic: return computeLinkageInfo(cast(T)->getValueType()); + case Type::Pipe: + return computeLinkageInfo(cast(T)->getElementType()); } llvm_unreachable("unhandled type class"); @@ -3601,6 +3605,7 @@ bool Type::canHaveNullability() const { case Type::ObjCObject: case Type::ObjCInterface: case Type::Atomic: + case Type::Pipe: return false; } llvm_unreachable("bad type kind!"); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 4617e1d380..b202523bda 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -193,6 +193,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::ObjCObject: case Type::ObjCInterface: case Type::Atomic: + case Type::Pipe: CanPrefixQualifiers = true; break; @@ -859,6 +860,15 @@ void TypePrinter::printAtomicBefore(const AtomicType *T, raw_ostream &OS) { } void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) { } +void TypePrinter::printPipeBefore(const PipeType *T, raw_ostream &OS) { + IncludeStrongLifetimeRAII Strong(Policy); + + OS << "pipe"; + spaceBeforePlaceHolder(OS); +} + +void TypePrinter::printPipeAfter(const PipeType *T, raw_ostream &OS) { +} /// Appends the given scope to the end of a string. void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) { if (DC->isTranslationUnit()) return; diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 78e3978e0f..5df8519487 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -2025,6 +2025,11 @@ llvm::DIType *CGDebugInfo::CreateType(const AtomicType *Ty, llvm::DIFile *U) { return getOrCreateType(Ty->getValueType(), U); } +llvm::DIType* CGDebugInfo::CreateType(const PipeType *Ty, + llvm::DIFile *U) { + return getOrCreateType(Ty->getElementType(), U); +} + llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) { const EnumDecl *ED = Ty->getDecl(); @@ -2284,6 +2289,9 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { case Type::Atomic: return CreateType(cast(Ty), Unit); + case Type::Pipe: + return CreateType(cast(Ty), Unit); + case Type::TemplateSpecialization: return CreateType(cast(Ty), Unit); diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 57d5c808f2..a68dd33fa5 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -168,6 +168,7 @@ class CGDebugInfo { llvm::DIType *CreateType(const RValueReferenceType *Ty, llvm::DIFile *Unit); llvm::DIType *CreateType(const MemberPointerType *Ty, llvm::DIFile *F); llvm::DIType *CreateType(const AtomicType *Ty, llvm::DIFile *F); + llvm::DIType *CreateType(const PipeType *Ty, llvm::DIFile *F); /// Get enumeration type. llvm::DIType *CreateEnumType(const EnumType *Ty); llvm::DIType *CreateTypeDefinition(const EnumType *Ty); diff --git a/lib/CodeGen/CGOpenCLRuntime.cpp b/lib/CodeGen/CGOpenCLRuntime.cpp index 8af39ceecd..686678962d 100644 --- a/lib/CodeGen/CGOpenCLRuntime.cpp +++ b/lib/CodeGen/CGOpenCLRuntime.cpp @@ -99,3 +99,14 @@ llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) { llvm::StructType::create(Ctx, "opencl.reserve_id_t"), 0); } } + +llvm::Type *CGOpenCLRuntime::getPipeType() { + if (!PipeTy){ + uint32_t PipeAddrSpc = + CGM.getContext().getTargetAddressSpace(LangAS::opencl_global); + PipeTy = llvm::PointerType::get(llvm::StructType::create( + CGM.getLLVMContext(), "opencl.pipe_t"), PipeAddrSpc); + } + + return PipeTy; +} diff --git a/lib/CodeGen/CGOpenCLRuntime.h b/lib/CodeGen/CGOpenCLRuntime.h index 0c50b92914..f1a7a31064 100644 --- a/lib/CodeGen/CGOpenCLRuntime.h +++ b/lib/CodeGen/CGOpenCLRuntime.h @@ -32,9 +32,10 @@ class CodeGenModule; class CGOpenCLRuntime { protected: CodeGenModule &CGM; + llvm::Type *PipeTy; public: - CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM) {} + CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM), PipeTy(nullptr) {} virtual ~CGOpenCLRuntime(); /// Emit the IR required for a work-group-local variable declaration, and add @@ -44,6 +45,8 @@ public: const VarDecl &D); virtual llvm::Type *convertOpenCLSpecificType(const Type *T); + + virtual llvm::Type *getPipeType(); }; } diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 048a04328f..1047120fae 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -195,6 +195,7 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) { case Type::FunctionNoProto: case Type::Enum: case Type::ObjCObjectPointer: + case Type::Pipe: return TEK_Scalar; // Complexes. @@ -511,7 +512,8 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn, typeQuals += typeQuals.empty() ? "volatile" : " volatile"; } else { uint32_t AddrSpc = 0; - if (ty->isImageType()) + bool isPipe = ty->isPipeType(); + if (ty->isImageType() || isPipe) AddrSpc = CGM.getContext().getTargetAddressSpace(LangAS::opencl_global); @@ -519,7 +521,11 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn, llvm::ConstantAsMetadata::get(Builder.getInt32(AddrSpc))); // Get argument type name. - std::string typeName = ty.getUnqualifiedType().getAsString(Policy); + std::string typeName; + if (isPipe) + typeName = cast(ty)->getElementType().getAsString(Policy); + else + typeName = ty.getUnqualifiedType().getAsString(Policy); // Turn "unsigned type" to "utype" std::string::size_type pos = typeName.find("unsigned"); @@ -528,7 +534,12 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn, argTypeNames.push_back(llvm::MDString::get(Context, typeName)); - std::string baseTypeName = + std::string baseTypeName; + if (isPipe) + baseTypeName = + cast(ty)->getElementType().getCanonicalType().getAsString(Policy); + else + baseTypeName = ty.getUnqualifiedType().getCanonicalType().getAsString(Policy); // Turn "unsigned type" to "utype" @@ -543,12 +554,16 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn, typeQuals = "const"; if (ty.isVolatileQualified()) typeQuals += typeQuals.empty() ? "volatile" : " volatile"; + if (isPipe) + typeQuals = "pipe"; } argTypeQuals.push_back(llvm::MDString::get(Context, typeQuals)); - // Get image access qualifier: - if (ty->isImageType()) { + // Get image and pipe access qualifier: + // FIXME: now image and pipe share the same access qualifier maybe we can + // refine it to OpenCL access qualifier and also handle write_read + if (ty->isImageType()|| ty->isPipeType()) { const OpenCLImageAccessAttr *A = parm->getAttr(); if (A && A->isWriteOnly()) accessQuals.push_back(llvm::MDString::get(Context, "write_only")); @@ -1727,6 +1742,10 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { case Type::Atomic: type = cast(ty)->getValueType(); break; + + case Type::Pipe: + type = cast(ty)->getElementType(); + break; } } while (type->isVariablyModifiedType()); } diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index fcda053205..09d9bf17b3 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -628,6 +628,10 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { } break; } + case Type::Pipe: { + ResultType = CGM.getOpenCLRuntime().getPipeType(); + break; + } } assert(ResultType && "Didn't convert a type?"); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 0c4008f8ee..e02c8dc3a8 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -2715,6 +2715,9 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) { case Type::Auto: llvm_unreachable("Undeduced auto type shouldn't get here"); + case Type::Pipe: + llvm_unreachable("Pipe types shouldn't get here"); + case Type::Builtin: // GCC treats vector and complex types as fundamental types. case Type::Vector: @@ -2939,6 +2942,9 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { case Type::Auto: llvm_unreachable("Undeduced auto type shouldn't get here"); + case Type::Pipe: + llvm_unreachable("Pipe type shouldn't get here"); + case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index e69bb2745c..c64b97d01b 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3326,6 +3326,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___bool: isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID, Policy); break; + case tok::kw_pipe: + if (!getLangOpts().OpenCL || (getLangOpts().OpenCLVersion < 200)) { + // OpenCL 2.0 defined this keyword. OpenCL 1.2 and earlier should + // support the "pipe" word as identifier. + Tok.getIdentifierInfo()->revertTokenIDToIdentifier(); + goto DoneWithDeclSpec; + } + isInvalid = DS.SetTypePipe(true, Loc, PrevSpec, DiagID, Policy); + break; case tok::kw___unknown_anytype: isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc, PrevSpec, DiagID, Policy); @@ -4401,6 +4410,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { switch (Tok.getKind()) { default: return false; + case tok::kw_pipe: + return getLangOpts().OpenCL && (getLangOpts().OpenCLVersion >= 200); + case tok::identifier: // foo::bar // Unfortunate hack to support "Class.factoryMethod" notation. if (getLangOpts().ObjC1 && NextToken().is(tok::period)) @@ -4847,6 +4859,9 @@ static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang, if (Kind == tok::star || Kind == tok::caret) return true; + if ((Kind == tok::kw_pipe) && Lang.OpenCL && (Lang.OpenCLVersion >= 200)) + return true; + if (!Lang.CPlusPlus) return false; @@ -4865,6 +4880,17 @@ static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang, return false; } +// Indicates whether the given declarator is a pipe declarator. +static bool isPipeDeclerator(const Declarator &D) { + const unsigned NumTypes = D.getNumTypeObjects(); + + for (unsigned Idx = 0; Idx != NumTypes; ++Idx) + if (DeclaratorChunk::Pipe == D.getTypeObject(Idx).Kind) + return true; + + return false; +} + /// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator /// is parsed by the function passed to it. Pass null, and the direct-declarator /// isn't parsed at all, making this function effectively parse the C++ @@ -4941,6 +4967,15 @@ void Parser::ParseDeclaratorInternal(Declarator &D, } tok::TokenKind Kind = Tok.getKind(); + + if (D.getDeclSpec().isTypeSpecPipe() && !isPipeDeclerator(D)) { + DeclSpec &DS = D.getMutableDeclSpec(); + + D.AddTypeInfo( + DeclaratorChunk::getPipe(DS.getTypeQualifiers(), DS.getPipeLoc()), + DS.getAttributes(), SourceLocation()); + } + // Not a pointer, C++ reference, or block. if (!isPtrOperatorToken(Kind, getLangOpts(), D.getContext())) { if (DirectDeclParser) @@ -6092,6 +6127,7 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) { case DeclaratorChunk::Reference: case DeclaratorChunk::BlockPointer: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: NeedParens = true; break; case DeclaratorChunk::Array: diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index d664d87040..6f6c4ca584 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -270,6 +270,7 @@ bool Declarator::isDeclarationOfFunction() const { case DeclaratorChunk::Array: case DeclaratorChunk::BlockPointer: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: return false; } llvm_unreachable("Invalid type chunk"); @@ -713,6 +714,22 @@ bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, return false; } +bool DeclSpec::SetTypePipe(bool isPipe, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy) { + + if (TypeSpecType != TST_unspecified) { + PrevSpec = DeclSpec::getSpecifierName((TST)TypeSpecType, Policy); + DiagID = diag::err_invalid_decl_spec_combination; + return true; + } + + if (isPipe) { + TypeSpecPipe = TSP_pipe; + } + return false; +} + bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, const PrintingPolicy &Policy) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 0864984c06..66c0e059d4 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -8256,6 +8256,23 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, for (auto Param : NewFD->params()) checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes); } + for (FunctionDecl::param_iterator PI = NewFD->param_begin(), + PE = NewFD->param_end(); PI != PE; ++PI) { + ParmVarDecl *Param = *PI; + QualType PT = Param->getType(); + + // OpenCL 2.0 pipe restrictions forbids pipe packet types to be non-value + // types. + if (getLangOpts().OpenCLVersion >= 200) { + if(const PipeType *PipeTy = PT->getAs()) { + QualType ElemTy = PipeTy->getElementType(); + if (ElemTy->isReferenceType() || ElemTy->isPointerType()) { + Diag(Param->getTypeSpecStartLoc(), diag::err_reference_pipe_type ); + D.setInvalidType(); + } + } + } + } MarkUnusedFileScopedDecl(NewFD); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 02091a7bd5..4b03baf32a 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -7000,6 +7000,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, case DeclaratorChunk::BlockPointer: case DeclaratorChunk::Reference: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: extendLeft(Before, Chunk.getSourceRange()); break; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 76d0ca56c0..361b0a1b72 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -13140,6 +13140,7 @@ bool Sema::tryCaptureVariable( case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: + case Type::Pipe: llvm_unreachable("type class is never variably-modified!"); case Type::Adjusted: QTy = cast(Ty)->getOriginalType(); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 481ae6cd55..1d7b15c35d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -2616,6 +2616,9 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { case Type::Atomic: T = cast(T)->getValueType().getTypePtr(); continue; + case Type::Pipe: + T = cast(T)->getElementType().getTypePtr(); + continue; } if (Queue.empty()) diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 9775e4d940..57156078c8 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4184,6 +4184,10 @@ bool UnnamedLocalNoLinkageFinder::VisitAtomicType(const AtomicType* T) { return Visit(T->getValueType()); } +bool UnnamedLocalNoLinkageFinder::VisitPipeType(const PipeType* T) { + return false; +} + bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) { if (Tag->getDeclContext()->isFunctionOrMethod()) { S.Diag(SR.getBegin(), diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index cd54920b08..71faafc6bc 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1652,6 +1652,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, case Type::Auto: case Type::DependentTemplateSpecialization: case Type::PackExpansion: + case Type::Pipe: // No template argument deduction for these types return Sema::TDK_Success; } @@ -4964,6 +4965,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, case Type::ObjCObject: case Type::ObjCObjectPointer: case Type::UnresolvedUsing: + case Type::Pipe: #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 61052f06c8..cb67d71f9e 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -750,6 +750,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case DeclaratorChunk::Pointer: case DeclaratorChunk::Reference: case DeclaratorChunk::Paren: + case DeclaratorChunk::Pipe: case DeclaratorChunk::BlockPointer: // These declarator chunks cannot contain any parameter packs. break; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index c70568c23b..f6ad132cde 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -335,6 +335,7 @@ static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator, case DeclaratorChunk::Array: case DeclaratorChunk::Reference: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: return result; // If we do find a function declarator, scan inwards from that, @@ -347,6 +348,7 @@ static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator, case DeclaratorChunk::Array: case DeclaratorChunk::Function: case DeclaratorChunk::Reference: + case DeclaratorChunk::Pipe: continue; case DeclaratorChunk::MemberPointer: @@ -427,6 +429,7 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state, // Don't walk through these. case DeclaratorChunk::Reference: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: goto error; } } @@ -459,6 +462,7 @@ distributeObjCPointerTypeAttrFromDeclarator(TypeProcessingState &state, case DeclaratorChunk::MemberPointer: case DeclaratorChunk::Paren: case DeclaratorChunk::Array: + case DeclaratorChunk::Pipe: continue; case DeclaratorChunk::Function: @@ -520,6 +524,7 @@ static void distributeFunctionTypeAttr(TypeProcessingState &state, case DeclaratorChunk::Array: case DeclaratorChunk::Reference: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: continue; } } @@ -1272,6 +1277,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // value being declared, poison it as invalid so we don't get chains of // errors. declarator.setInvalidType(true); + } else if (S.getLangOpts().OpenCLVersion >= 200 && DS.isTypeSpecPipe()){ + S.Diag(DeclLoc, diag::err_missing_actual_pipe_type) + << DS.getSourceRange(); + declarator.setInvalidType(true); } else { S.Diag(DeclLoc, diag::ext_missing_type_specifier) << DS.getSourceRange(); @@ -1564,7 +1573,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // Apply any type attributes from the decl spec. This may cause the // list of type attributes to be temporarily saved while the type // attributes are pushed around. - processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes().getList()); + // pipe attributes will be handled later ( at GetFullTypeForDeclarator ) + if (!DS.isTypeSpecPipe()) + processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes().getList()); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -1924,6 +1935,21 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, return Context.getRValueReferenceType(T); } +/// \brief Build a Pipe type. +/// +/// \param T The type to which we'll be building a Pipe. +/// +/// \param Loc We do not use it for now. +/// +/// \returns A suitable pipe type, if there are no errors. Otherwise, returns a +/// NULL type. +QualType Sema::BuildPipeType(QualType T, SourceLocation Loc) { + assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType"); + + // Build the pipe type. + return Context.getPipeType(T); +} + /// Check whether the specified array size makes the array type a VLA. If so, /// return true, if not, return the size of the array in SizeVal. static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) { @@ -2393,6 +2419,7 @@ static void inferARCWriteback(TypeProcessingState &state, case DeclaratorChunk::Array: // suppress if written (id[])? case DeclaratorChunk::Function: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: return; } } @@ -2532,6 +2559,7 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy, case DeclaratorChunk::Reference: case DeclaratorChunk::Array: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: // FIXME: We can't currently provide an accurate source location and a // fix-it hint for these. unsigned AtomicQual = RetTy->isAtomicType() ? DeclSpec::TQ_atomic : 0; @@ -3057,6 +3085,7 @@ static PointerDeclaratorKind classifyPointerDeclarator(Sema &S, switch (chunk.Kind) { case DeclaratorChunk::Array: case DeclaratorChunk::Function: + case DeclaratorChunk::Pipe: break; case DeclaratorChunk::BlockPointer: @@ -3305,6 +3334,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorChunk::Array: DiagKind = 2; break; + case DeclaratorChunk::Pipe: + break; } S.Diag(DeclChunk.Loc, DiagId) << DiagKind; @@ -3370,6 +3401,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, switch (chunk.Kind) { case DeclaratorChunk::Array: case DeclaratorChunk::Function: + case DeclaratorChunk::Pipe: break; case DeclaratorChunk::BlockPointer: @@ -3689,6 +3721,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, break; case DeclaratorChunk::Function: case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::Pipe: // These are invalid anyway, so just ignore. break; } @@ -4038,7 +4071,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, break; } - case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::MemberPointer: { // The scope spec must refer to a class, or be dependent. CXXScopeSpec &SS = DeclType.Mem.Scope(); QualType ClsType; @@ -4098,6 +4131,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, break; } + case DeclaratorChunk::Pipe: { + T = S.BuildPipeType(T, DeclType.Loc ); + break; + } + } + if (T.isNull()) { D.setInvalidType(true); T = Context.IntTy; @@ -4392,6 +4431,7 @@ static void transferARCOwnership(TypeProcessingState &state, case DeclaratorChunk::Function: case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Pipe: return; } } @@ -4682,6 +4722,14 @@ namespace { } } + void VisitPipeTypeLoc(PipeTypeLoc TL) { + TL.setKWLoc(DS.getTypeSpecTypeLoc()); + + TypeSourceInfo *TInfo = 0; + Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); + TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc()); + } + void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(Context, DS.getTypeSpecTypeLoc()); @@ -4802,6 +4850,10 @@ namespace { TL.setLParenLoc(Chunk.Loc); TL.setRParenLoc(Chunk.EndLoc); } + void VisitPipeTypeLoc(PipeTypeLoc TL) { + assert(Chunk.Kind == DeclaratorChunk::Pipe); + TL.setKWLoc(Chunk.Loc); + } void VisitTypeLoc(TypeLoc TL) { llvm_unreachable("unsupported TypeLoc kind in declarator!"); @@ -4815,6 +4867,7 @@ static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) { case DeclaratorChunk::Function: case DeclaratorChunk::Array: case DeclaratorChunk::Paren: + case DeclaratorChunk::Pipe: llvm_unreachable("cannot be _Atomic qualified"); case DeclaratorChunk::Pointer: @@ -5738,6 +5791,7 @@ static bool distributeNullabilityTypeAttr(TypeProcessingState &state, // Don't walk through these. case DeclaratorChunk::Reference: + case DeclaratorChunk::Pipe: return false; } } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index e97a262638..b8f977c16b 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1046,6 +1046,9 @@ public: /// Subclasses may override this routine to provide different behavior. QualType RebuildAtomicType(QualType ValueType, SourceLocation KWLoc); + /// \brief Build a new pipe type given its value type. + QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc); + /// \brief Build a new template name given a nested name specifier, a flag /// indicating whether the "template" keyword was provided, and the template /// that the template name refers to. @@ -5324,6 +5327,26 @@ QualType TreeTransform::TransformAtomicType(TypeLocBuilder &TLB, return Result; } +template +QualType TreeTransform::TransformPipeType(TypeLocBuilder &TLB, + PipeTypeLoc TL) { + QualType ValueType = getDerived().TransformType(TLB, TL.getValueLoc()); + if (ValueType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || ValueType != TL.getValueLoc().getType()) { + Result = getDerived().RebuildPipeType(ValueType, TL.getKWLoc()); + if (Result.isNull()) + return QualType(); + } + + PipeTypeLoc NewTL = TLB.push(Result); + NewTL.setKWLoc(TL.getKWLoc()); + + return Result; +} + /// \brief Simple iterator that traverses the template arguments in a /// container that provides a \c getArgLoc() member function. /// @@ -11349,6 +11372,12 @@ QualType TreeTransform::RebuildAtomicType(QualType ValueType, return SemaRef.BuildAtomicType(ValueType, KWLoc); } +template +QualType TreeTransform::RebuildPipeType(QualType ValueType, + SourceLocation KWLoc) { + return SemaRef.BuildPipeType(ValueType, KWLoc); +} + template TemplateName TreeTransform::RebuildTemplateName(CXXScopeSpec &SS, diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index a279475eea..833ff57e4d 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -5640,6 +5640,17 @@ QualType ASTReader::readTypeRecord(unsigned Index) { QualType ValueType = readType(*Loc.F, Record, Idx); return Context.getAtomicType(ValueType); } + + case TYPE_PIPE: { + if (Record.size() != 1) { + Error("Incorrect encoding of pipe type"); + return QualType(); + } + + // Reading the pipe element type. + QualType ElementType = readType(*Loc.F, Record, Idx); + return Context.getPipeType(ElementType); + } } llvm_unreachable("Invalid TypeCode!"); } @@ -5911,6 +5922,9 @@ void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) { TL.setLParenLoc(ReadSourceLocation(Record, Idx)); TL.setRParenLoc(ReadSourceLocation(Record, Idx)); } +void TypeLocReader::VisitPipeTypeLoc(PipeTypeLoc TL) { + TL.setKWLoc(ReadSourceLocation(Record, Idx)); +} TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F, const RecordData &Record, diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index e36e918517..ec04cd6c1f 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -446,6 +446,12 @@ ASTTypeWriter::VisitAtomicType(const AtomicType *T) { Code = TYPE_ATOMIC; } +void +ASTTypeWriter::VisitPipeType(const PipeType *T) { + Writer.AddTypeRef(T->getElementType(), Record); + Code = TYPE_PIPE; +} + namespace { class TypeLocWriter : public TypeLocVisitor { @@ -672,6 +678,9 @@ void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) { Writer.AddSourceLocation(TL.getLParenLoc(), Record); Writer.AddSourceLocation(TL.getRParenLoc(), Record); } +void TypeLocWriter::VisitPipeTypeLoc(PipeTypeLoc TL) { + Writer.AddSourceLocation(TL.getKWLoc(), Record); +} void ASTWriter::WriteTypeAbbrevs() { using namespace llvm; diff --git a/test/CodeGenOpenCL/pipe_types.cl b/test/CodeGenOpenCL/pipe_types.cl new file mode 100644 index 0000000000..547071cf85 --- /dev/null +++ b/test/CodeGenOpenCL/pipe_types.cl @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck %s + +// CHECK: %opencl.pipe_t = type opaque +typedef unsigned char __attribute__((ext_vector_type(3))) uchar3; +typedef int __attribute__((ext_vector_type(4))) int4; + +void test1(read_only pipe int p) { +// CHECK: define void @test1(%opencl.pipe_t* %p) + reserve_id_t rid; +// CHECK: %rid = alloca %opencl.reserve_id_t +} + +void test2(write_only pipe float p) { +// CHECK: define void @test2(%opencl.pipe_t* %p) +} + +void test3(read_only pipe const int p) { +// CHECK: define void @test3(%opencl.pipe_t* %p) +} + +void test4(read_only pipe uchar3 p) { +// CHECK: define void @test4(%opencl.pipe_t* %p) +} + +void test5(read_only pipe int4 p) { +// CHECK: define void @test5(%opencl.pipe_t* %p) +} diff --git a/test/PCH/ocl_types.cl b/test/PCH/ocl_types.cl index d788a32621..21097c4811 100644 --- a/test/PCH/ocl_types.cl +++ b/test/PCH/ocl_types.cl @@ -1,9 +1,9 @@ // Test this without pch. -// RUN: %clang_cc1 -include %S/ocl_types.h -fsyntax-only %s +// RUN: %clang_cc1 -include %S/ocl_types.h -fsyntax-only %s -cl-std=CL2.0 -D__OPENCL_VERSION__=200 // Test with pch. -// RUN: %clang_cc1 -x cl -emit-pch -o %t %S/ocl_types.h -// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s -ast-print +// RUN: %clang_cc1 -x cl -emit-pch -o %t %S/ocl_types.h -cl-std=CL2.0 -D__OPENCL_VERSION__=200 +// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s -ast-print -cl-std=CL2.0 -D__OPENCL_VERSION__=200 void foo1(img1d_t img); @@ -24,3 +24,15 @@ void foo7(smp_t smp) { void foo8(evt_t evt) { evt_t loc_evt; } + +#if __OPENCL_VERSION__ >= 200 + +void foo9(pipe int P) { + int_pipe_function(P); +} + +void foo10(pipe Person P) { + person_pipe_function(P); +} + +#endif diff --git a/test/PCH/ocl_types.h b/test/PCH/ocl_types.h index 93cf4f6644..bdc4bb11c1 100644 --- a/test/PCH/ocl_types.h +++ b/test/PCH/ocl_types.h @@ -44,6 +44,7 @@ typedef image2d_depth_t img2ddep_t; // image2d_array_depth_t typedef image2d_array_depth_t img2darr_dep_t; +#pragma OPENCL EXTENSION cl_khr_gl_msaa_sharing : enable // image2d_msaa_t typedef image2d_msaa_t img2dmsaa_t; @@ -56,4 +57,14 @@ typedef image2d_msaa_depth_t img2dmsaadep_t; // image2d_array_msaa_depth_t typedef image2d_array_msaa_depth_t img2darrmsaadep_t; +// pipe specifier + +typedef struct _person { + int id; + const char *name; +} Person; + +void int_pipe_function(pipe int); + +void person_pipe_function(pipe Person); #endif diff --git a/test/SemaOpenCL/invalid-pipes-cl2.0.cl b/test/SemaOpenCL/invalid-pipes-cl2.0.cl new file mode 100644 index 0000000000..ee36892b93 --- /dev/null +++ b/test/SemaOpenCL/invalid-pipes-cl2.0.cl @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0 + +void test1(pipe int *p){// expected-error {{pipes packet types cannot be of reference type}} +} +void test2(pipe p){// expected-error {{missing actual type specifier for pipe}} +} +void test3(int pipe p){// expected-error {{cannot combine with previous 'int' declaration specifier}} +} diff --git a/test/SemaOpenCL/pipes-1.2-negative.cl b/test/SemaOpenCL/pipes-1.2-negative.cl new file mode 100644 index 0000000000..441a24cf85 --- /dev/null +++ b/test/SemaOpenCL/pipes-1.2-negative.cl @@ -0,0 +1,3 @@ +// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL1.2 + +void foo(read_only pipe int p); // expected-error {{expected parameter declarator}} expected-error {{expected ')'}} expected-note {{to match this '('}} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index dbda13c235..9086c60e18 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1686,6 +1686,10 @@ bool CursorVisitor::VisitAtomicTypeLoc(AtomicTypeLoc TL) { return Visit(TL.getValueLoc()); } +bool CursorVisitor::VisitPipeTypeLoc(PipeTypeLoc TL) { + return Visit(TL.getValueLoc()); +} + #define DEFAULT_TYPELOC_IMPL(CLASS, PARENT) \ bool CursorVisitor::Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ return Visit##PARENT##Loc(TL); \