mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 05:32:28 +08:00
[OpenCL] Introduce ReadPipeType and WritePipeType.
This allows Sema to diagnose passing a read_only pipe to a write_only pipe argument. llvm-svn: 287343
This commit is contained in:
@@ -135,7 +135,8 @@ 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<ReadPipeType> ReadPipeTypes;
|
||||
mutable llvm::FoldingSet<WritePipeType> WritePipeTypes;
|
||||
|
||||
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
|
||||
mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
|
||||
@@ -1120,8 +1121,10 @@ public:
|
||||
/// blocks.
|
||||
QualType getBlockDescriptorType() const;
|
||||
|
||||
/// \brief Return pipe type for the specified type.
|
||||
QualType getPipeType(QualType T) const;
|
||||
/// \brief Return a read_only pipe type for the specified type.
|
||||
QualType getReadPipeType(QualType T) const;
|
||||
/// \brief Return a write_only pipe type for the specified type.
|
||||
QualType getWritePipeType(QualType T) const;
|
||||
|
||||
/// Gets the struct used to keep track of the extended descriptor for
|
||||
/// pointer to blocks.
|
||||
|
||||
@@ -5285,18 +5285,18 @@ class AtomicType : public Type, public llvm::FoldingSetNode {
|
||||
|
||||
/// PipeType - OpenCL20.
|
||||
class PipeType : public Type, public llvm::FoldingSetNode {
|
||||
protected:
|
||||
QualType ElementType;
|
||||
bool isRead;
|
||||
|
||||
PipeType(QualType elemType, QualType CanonicalPtr) :
|
||||
PipeType(QualType elemType, QualType CanonicalPtr, bool isRead) :
|
||||
Type(Pipe, CanonicalPtr, elemType->isDependentType(),
|
||||
elemType->isInstantiationDependentType(),
|
||||
elemType->isVariablyModifiedType(),
|
||||
elemType->containsUnexpandedParameterPack()),
|
||||
ElementType(elemType) {}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
ElementType(elemType), isRead(isRead) {}
|
||||
|
||||
public:
|
||||
|
||||
QualType getElementType() const { return ElementType; }
|
||||
|
||||
bool isSugared() const { return false; }
|
||||
@@ -5311,11 +5311,23 @@ public:
|
||||
ID.AddPointer(T.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == Pipe;
|
||||
}
|
||||
|
||||
bool isReadOnly() const { return isRead; }
|
||||
};
|
||||
|
||||
class ReadPipeType : public PipeType {
|
||||
ReadPipeType(QualType elemType, QualType CanonicalPtr) :
|
||||
PipeType(elemType, CanonicalPtr, true) {}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
};
|
||||
|
||||
class WritePipeType : public PipeType {
|
||||
WritePipeType(QualType elemType, QualType CanonicalPtr) :
|
||||
PipeType(elemType, CanonicalPtr, false) {}
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
};
|
||||
|
||||
/// A qualifier set is used to build a set of qualifiers.
|
||||
|
||||
@@ -1303,7 +1303,9 @@ public:
|
||||
SourceLocation Loc, DeclarationName Entity);
|
||||
QualType BuildParenType(QualType T);
|
||||
QualType BuildAtomicType(QualType T, SourceLocation Loc);
|
||||
QualType BuildPipeType(QualType T,
|
||||
QualType BuildReadPipeType(QualType T,
|
||||
SourceLocation Loc);
|
||||
QualType BuildWritePipeType(QualType T,
|
||||
SourceLocation Loc);
|
||||
|
||||
TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S);
|
||||
|
||||
@@ -905,10 +905,12 @@ namespace clang {
|
||||
TYPE_DECAYED = 41,
|
||||
/// \brief An AdjustedType record.
|
||||
TYPE_ADJUSTED = 42,
|
||||
/// \brief A PipeType record.
|
||||
TYPE_PIPE = 43,
|
||||
/// \brief A ReadPipeType record.
|
||||
TYPE_READ_PIPE = 43,
|
||||
/// \brief An ObjCTypeParamType record.
|
||||
TYPE_OBJC_TYPE_PARAM = 44
|
||||
TYPE_OBJC_TYPE_PARAM = 44,
|
||||
/// \brief A WritePipeType record.
|
||||
TYPE_WRITE_PIPE = 45,
|
||||
};
|
||||
|
||||
/// \brief The type IDs for special types constructed by semantic
|
||||
|
||||
@@ -3338,29 +3338,53 @@ QualType ASTContext::getFunctionTypeInternal(
|
||||
return QualType(FTP, 0);
|
||||
}
|
||||
|
||||
/// Return pipe type for the specified type.
|
||||
QualType ASTContext::getPipeType(QualType T) const {
|
||||
QualType ASTContext::getReadPipeType(QualType T) const {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
PipeType::Profile(ID, T);
|
||||
ReadPipeType::Profile(ID, T);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (PipeType *PT = PipeTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
if (ReadPipeType *PT = ReadPipeTypes.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));
|
||||
Canonical = getReadPipeType(getCanonicalType(T));
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
PipeType *NewIP = PipeTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
ReadPipeType *NewIP = ReadPipeTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(!NewIP && "Shouldn't be in the map!");
|
||||
(void)NewIP;
|
||||
}
|
||||
PipeType *New = new (*this, TypeAlignment) PipeType(T, Canonical);
|
||||
ReadPipeType *New = new (*this, TypeAlignment) ReadPipeType(T, Canonical);
|
||||
Types.push_back(New);
|
||||
PipeTypes.InsertNode(New, InsertPos);
|
||||
ReadPipeTypes.InsertNode(New, InsertPos);
|
||||
return QualType(New, 0);
|
||||
}
|
||||
|
||||
QualType ASTContext::getWritePipeType(QualType T) const {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
WritePipeType::Profile(ID, T);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (WritePipeType *PT = WritePipeTypes.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 = getWritePipeType(getCanonicalType(T));
|
||||
|
||||
// Get the new insert position for the node we care about.
|
||||
WritePipeType *NewIP = WritePipeTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
assert(!NewIP && "Shouldn't be in the map!");
|
||||
(void)NewIP;
|
||||
}
|
||||
WritePipeType *New = new (*this, TypeAlignment) WritePipeType(T, Canonical);
|
||||
Types.push_back(New);
|
||||
WritePipeTypes.InsertNode(New, InsertPos);
|
||||
return QualType(New, 0);
|
||||
}
|
||||
|
||||
@@ -7720,7 +7744,7 @@ bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS,
|
||||
bool CompareUnqualified) {
|
||||
if (getLangOpts().CPlusPlus)
|
||||
return hasSameType(LHS, RHS);
|
||||
|
||||
|
||||
return !mergeTypes(LHS, RHS, false, CompareUnqualified).isNull();
|
||||
}
|
||||
|
||||
@@ -8248,7 +8272,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
|
||||
return LHS;
|
||||
if (getCanonicalType(RHSValue) == getCanonicalType(ResultType))
|
||||
return RHS;
|
||||
return getPipeType(ResultType);
|
||||
return isa<ReadPipeType>(LHS) ? getReadPipeType(ResultType)
|
||||
: getWritePipeType(ResultType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -901,6 +901,10 @@ void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) { }
|
||||
void TypePrinter::printPipeBefore(const PipeType *T, raw_ostream &OS) {
|
||||
IncludeStrongLifetimeRAII Strong(Policy);
|
||||
|
||||
if (T->isReadOnly())
|
||||
OS << "read_only ";
|
||||
else
|
||||
OS << "write_only ";
|
||||
OS << "pipe ";
|
||||
print(T->getElementType(), OS, StringRef());
|
||||
spaceBeforePlaceHolder(OS);
|
||||
|
||||
@@ -2040,7 +2040,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
|
||||
return Context.getRValueReferenceType(T);
|
||||
}
|
||||
|
||||
/// \brief Build a Pipe type.
|
||||
/// \brief Build a Read-only Pipe type.
|
||||
///
|
||||
/// \param T The type to which we'll be building a Pipe.
|
||||
///
|
||||
@@ -2048,11 +2048,20 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
|
||||
///
|
||||
/// \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");
|
||||
QualType Sema::BuildReadPipeType(QualType T, SourceLocation Loc) {
|
||||
return Context.getReadPipeType(T);
|
||||
}
|
||||
|
||||
// Build the pipe type.
|
||||
return Context.getPipeType(T);
|
||||
/// \brief Build a Write-only 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::BuildWritePipeType(QualType T, SourceLocation Loc) {
|
||||
return Context.getWritePipeType(T);
|
||||
}
|
||||
|
||||
/// Check whether the specified array size makes the array type a VLA. If so,
|
||||
@@ -4531,7 +4540,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||
}
|
||||
|
||||
case DeclaratorChunk::Pipe: {
|
||||
T = S.BuildPipeType(T, DeclType.Loc );
|
||||
T = S.BuildReadPipeType(T, DeclType.Loc);
|
||||
processTypeAttrs(state, T, TAL_DeclSpec,
|
||||
D.getDeclSpec().getAttributes().getList());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -6681,6 +6692,11 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const AttributeList &Attr,
|
||||
|
||||
S.Diag(TypedefTy->getDecl()->getLocStart(),
|
||||
diag::note_opencl_typedef_access_qualifier) << PrevAccessQual;
|
||||
} else if (CurType->isPipeType()) {
|
||||
if (Attr.getSemanticSpelling() == OpenCLAccessAttr::Keyword_write_only) {
|
||||
QualType ElemType = CurType->getAs<PipeType>()->getElementType();
|
||||
CurType = S.Context.getWritePipeType(ElemType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1059,7 +1059,8 @@ public:
|
||||
QualType RebuildAtomicType(QualType ValueType, SourceLocation KWLoc);
|
||||
|
||||
/// \brief Build a new pipe type given its value type.
|
||||
QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc);
|
||||
QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc,
|
||||
bool isReadPipe);
|
||||
|
||||
/// \brief Build a new template name given a nested name specifier, a flag
|
||||
/// indicating whether the "template" keyword was provided, and the template
|
||||
@@ -5483,7 +5484,9 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB,
|
||||
|
||||
QualType Result = TL.getType();
|
||||
if (getDerived().AlwaysRebuild() || ValueType != TL.getValueLoc().getType()) {
|
||||
Result = getDerived().RebuildPipeType(ValueType, TL.getKWLoc());
|
||||
const PipeType *PT = Result->getAs<PipeType>();
|
||||
bool isReadPipe = PT->isReadOnly();
|
||||
Result = getDerived().RebuildPipeType(ValueType, TL.getKWLoc(), isReadPipe);
|
||||
if (Result.isNull())
|
||||
return QualType();
|
||||
}
|
||||
@@ -11839,8 +11842,10 @@ QualType TreeTransform<Derived>::RebuildAtomicType(QualType ValueType,
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::RebuildPipeType(QualType ValueType,
|
||||
SourceLocation KWLoc) {
|
||||
return SemaRef.BuildPipeType(ValueType, KWLoc);
|
||||
SourceLocation KWLoc,
|
||||
bool isReadPipe) {
|
||||
return isReadPipe ? SemaRef.BuildReadPipeType(ValueType, KWLoc)
|
||||
: SemaRef.BuildWritePipeType(ValueType, KWLoc);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
|
||||
@@ -5793,7 +5793,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
|
||||
return Context.getAtomicType(ValueType);
|
||||
}
|
||||
|
||||
case TYPE_PIPE: {
|
||||
case TYPE_READ_PIPE: {
|
||||
if (Record.size() != 1) {
|
||||
Error("Incorrect encoding of pipe type");
|
||||
return QualType();
|
||||
@@ -5801,7 +5801,18 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
|
||||
|
||||
// Reading the pipe element type.
|
||||
QualType ElementType = readType(*Loc.F, Record, Idx);
|
||||
return Context.getPipeType(ElementType);
|
||||
return Context.getReadPipeType(ElementType);
|
||||
}
|
||||
|
||||
case TYPE_WRITE_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.getWritePipeType(ElementType);
|
||||
}
|
||||
}
|
||||
llvm_unreachable("Invalid TypeCode!");
|
||||
|
||||
@@ -516,7 +516,10 @@ ASTTypeWriter::VisitAtomicType(const AtomicType *T) {
|
||||
void
|
||||
ASTTypeWriter::VisitPipeType(const PipeType *T) {
|
||||
Record.AddTypeRef(T->getElementType());
|
||||
Code = TYPE_PIPE;
|
||||
if (T->isReadOnly())
|
||||
Code = TYPE_READ_PIPE;
|
||||
else
|
||||
Code = TYPE_WRITE_PIPE;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
// RUN: %clang_cc1 -triple spir64 -cl-std=CL2.0 -ast-dump -ast-dump-filter pipetype %s | FileCheck -strict-whitespace %s
|
||||
typedef pipe int pipetype;
|
||||
// CHECK: PipeType {{.*}} 'pipe int'
|
||||
// CHECK: PipeType {{.*}} 'read_only pipe int'
|
||||
// CHECK-NEXT: BuiltinType {{.*}} 'int'
|
||||
|
||||
typedef read_only pipe int pipetype2;
|
||||
// CHECK: PipeType {{.*}} 'read_only pipe int'
|
||||
// CHECK-NEXT: BuiltinType {{.*}} 'int'
|
||||
|
||||
typedef write_only pipe int pipetype3;
|
||||
// CHECK: PipeType {{.*}} 'write_only pipe int'
|
||||
// CHECK-NEXT: BuiltinType {{.*}} 'int'
|
||||
|
||||
@@ -63,7 +63,14 @@ kernel void k11(read_only write_only image1d_t i){} // expected-error{{multiple
|
||||
kernel void k12(read_only read_only image1d_t i){} // expected-error{{multiple access qualifiers}}
|
||||
|
||||
#if __OPENCL_C_VERSION__ >= 200
|
||||
kernel void k13(read_write pipe int i){} // expected-error{{access qualifier 'read_write' can not be used for 'pipe int'}}
|
||||
kernel void k13(read_write pipe int i){} // expected-error{{access qualifier 'read_write' can not be used for 'read_only pipe int'}}
|
||||
#else
|
||||
kernel void k13(__read_write image1d_t i){} // expected-error{{access qualifier '__read_write' can not be used for '__read_write image1d_t' prior to OpenCL version 2.0}}
|
||||
#endif
|
||||
|
||||
#if __OPENCL_C_VERSION__ >= 200
|
||||
void myPipeWrite(write_only pipe int); // expected-note {{passing argument to parameter here}}
|
||||
kernel void k14(read_only pipe int p) {
|
||||
myPipeWrite(p); // expected-error {{passing 'read_only pipe int' to parameter of incompatible type 'write_only pipe int'}}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -7,16 +7,16 @@ 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}}
|
||||
}
|
||||
void test4() {
|
||||
pipe int p; // expected-error {{type 'pipe int' can only be used as a function parameter}}
|
||||
pipe int p; // expected-error {{type 'read_only pipe int' can only be used as a function parameter}}
|
||||
//TODO: fix parsing of this pipe int (*p);
|
||||
}
|
||||
|
||||
void test5(pipe int p) {
|
||||
p+p; // expected-error{{invalid operands to binary expression ('pipe int' and 'pipe int')}}
|
||||
p=p; // expected-error{{invalid operands to binary expression ('pipe int' and 'pipe int')}}
|
||||
&p; // expected-error{{invalid argument type 'pipe int' to unary expression}}
|
||||
*p; // expected-error{{invalid argument type 'pipe int' to unary expression}}
|
||||
p+p; // expected-error{{invalid operands to binary expression ('read_only pipe int' and 'read_only pipe int')}}
|
||||
p=p; // expected-error{{invalid operands to binary expression ('read_only pipe int' and 'read_only pipe int')}}
|
||||
&p; // expected-error{{invalid argument type 'read_only pipe int' to unary expression}}
|
||||
*p; // expected-error{{invalid argument type 'read_only pipe int' to unary expression}}
|
||||
}
|
||||
|
||||
typedef pipe int pipe_int_t;
|
||||
pipe_int_t test6() {} // expected-error{{declaring function return value of type 'pipe_int_t' (aka 'pipe int') is not allowed}}
|
||||
pipe_int_t test6() {} // expected-error{{declaring function return value of type 'pipe_int_t' (aka 'read_only pipe int') is not allowed}}
|
||||
|
||||
Reference in New Issue
Block a user