[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
This commit is contained in:
Xiuli Pan 2016-01-09 12:53:17 +00:00
parent 1539947508
commit 97f9428a0d
43 changed files with 525 additions and 14 deletions

View File

@ -131,6 +131,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<AutoType> AutoTypes;
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
llvm::FoldingSet<AttributedType> AttributedTypes;
mutable llvm::FoldingSet<PipeType> PipeTypes;
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
mutable llvm::FoldingSet<DependentTemplateName> 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;

View File

@ -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 -----------------

View File

@ -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<PipeType>(CanonicalType);
}
inline bool Type::isOpenCLSpecificType() const {
return isSamplerT() || isEventT() || isImageType() || isClkEventT() ||
isQueueT() || isNDRangeT() || isReserveIDT();
isQueueT() || isNDRangeT() || isReserveIDT() || isPipeType();
}
inline bool Type::isTemplateTypeParmType() const {

View File

@ -2033,7 +2033,26 @@ public:
}
};
struct PipeTypeLocInfo {
SourceLocation KWLoc;
};
class PipeTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, PipeTypeLoc, PipeType,
PipeTypeLocInfo> {
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

View File

@ -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

View File

@ -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">;

View File

@ -36,6 +36,11 @@ namespace clang {
TSS_unsigned
};
enum TypeSpecifiersPipe {
TSP_unspecified,
TSP_pipe
};
/// \brief Specifies the kind of type.
enum TypeSpecifierType {
TST_unspecified,

View File

@ -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)

View File

@ -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<Token, 4> 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");

View File

@ -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);

View File

@ -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

View File

@ -1836,6 +1836,13 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Align = static_cast<unsigned>(Width);
}
}
break;
case Type::Pipe: {
TypeInfo Info = getTypeInfo(cast<PipeType>(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<QualType> 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<CXXRecordDecl>(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<PipeType>()->getElementType();
QualType RHSValue = RHS->getAs<PipeType>()->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!");

View File

@ -878,6 +878,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
break;
}
case Type::Pipe: {
if (!IsStructurallyEquivalent(Context,
cast<PipeType>(T1)->getElementType(),
cast<PipeType>(T2)->getElementType()))
return false;
break;
}
} // end switch
return true;

View File

@ -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
// <type> ::= 8ocl_pipe
Out << "8ocl_pipe";
}
void CXXNameMangler::mangleIntegerLiteral(QualType T,
const llvm::APSInt &Value) {
// <expr-primary> ::= L <type> <value number> E # integer literal

View File

@ -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<FunctionDecl>(D) || isa<VarDecl>(D)) &&

View File

@ -3361,6 +3361,8 @@ static CachedProperties computeCachedProperties(const Type *T) {
return Cache::get(cast<ObjCObjectPointerType>(T)->getPointeeType());
case Type::Atomic:
return Cache::get(cast<AtomicType>(T)->getValueType());
case Type::Pipe:
return Cache::get(cast<PipeType>(T)->getElementType());
}
llvm_unreachable("unhandled type class");
@ -3443,6 +3445,8 @@ static LinkageInfo computeLinkageInfo(const Type *T) {
return computeLinkageInfo(cast<ObjCObjectPointerType>(T)->getPointeeType());
case Type::Atomic:
return computeLinkageInfo(cast<AtomicType>(T)->getValueType());
case Type::Pipe:
return computeLinkageInfo(cast<PipeType>(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!");

View File

@ -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;

View File

@ -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<AtomicType>(Ty), Unit);
case Type::Pipe:
return CreateType(cast<PipeType>(Ty), Unit);
case Type::TemplateSpecialization:
return CreateType(cast<TemplateSpecializationType>(Ty), Unit);

View File

@ -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);

View File

@ -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;
}

View File

@ -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();
};
}

View File

@ -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<PipeType>(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<PipeType>(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<OpenCLImageAccessAttr>();
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<AtomicType>(ty)->getValueType();
break;
case Type::Pipe:
type = cast<PipeType>(ty)->getElementType();
break;
}
} while (type->isVariablyModifiedType());
}

View File

@ -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?");

View File

@ -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:

View File

@ -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:

View File

@ -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) {

View File

@ -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<PipeType>()) {
QualType ElemTy = PipeTy->getElementType();
if (ElemTy->isReferenceType() || ElemTy->isPointerType()) {
Diag(Param->getTypeSpecStartLoc(), diag::err_reference_pipe_type );
D.setInvalidType();
}
}
}
}
MarkUnusedFileScopedDecl(NewFD);

View File

@ -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;

View File

@ -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<AdjustedType>(Ty)->getOriginalType();

View File

@ -2616,6 +2616,9 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
case Type::Atomic:
T = cast<AtomicType>(T)->getValueType().getTypePtr();
continue;
case Type::Pipe:
T = cast<PipeType>(T)->getElementType().getTypePtr();
continue;
}
if (Queue.empty())

View File

@ -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(),

View File

@ -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)

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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<Derived>::TransformAtomicType(TypeLocBuilder &TLB,
return Result;
}
template <typename Derived>
QualType TreeTransform<Derived>::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<PipeTypeLoc>(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<Derived>::RebuildAtomicType(QualType ValueType,
return SemaRef.BuildAtomicType(ValueType, KWLoc);
}
template<typename Derived>
QualType TreeTransform<Derived>::RebuildPipeType(QualType ValueType,
SourceLocation KWLoc) {
return SemaRef.BuildPipeType(ValueType, KWLoc);
}
template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,

View File

@ -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,

View File

@ -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<TypeLocWriter> {
@ -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;

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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}}
}

View File

@ -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 '('}}

View File

@ -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); \