[OpenCL] Refactor read_only/write_only pipes.

This adds the access qualifier to the Pipe Type, rather than using a class
hierarchy. 

It also fixes mergeTypes for Pipes, by disallowing merges. Only identical
pipe types can be merged. The test case in invalid-pipes-cl2.0.cl is added
to check that.

llvm-svn: 288332
This commit is contained in:
Joey Gouly 2016-12-01 11:30:49 +00:00
parent bbd6f7af33
commit e3c85de6df
7 changed files with 40 additions and 84 deletions

View File

@ -135,8 +135,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<AutoType> AutoTypes;
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
llvm::FoldingSet<AttributedType> AttributedTypes;
mutable llvm::FoldingSet<ReadPipeType> ReadPipeTypes;
mutable llvm::FoldingSet<WritePipeType> WritePipeTypes;
mutable llvm::FoldingSet<PipeType> PipeTypes;
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
@ -1012,6 +1011,8 @@ private:
QualType getTypeDeclTypeSlow(const TypeDecl *Decl) const;
QualType getPipeType(QualType T, bool ReadOnly) const;
public:
/// \brief Return the uniqued reference to the type for an address space
/// qualified type with the specified type and address space.

View File

@ -5285,7 +5285,6 @@ class AtomicType : public Type, public llvm::FoldingSetNode {
/// PipeType - OpenCL20.
class PipeType : public Type, public llvm::FoldingSetNode {
protected:
QualType ElementType;
bool isRead;
@ -5295,6 +5294,7 @@ protected:
elemType->isVariablyModifiedType(),
elemType->containsUnexpandedParameterPack()),
ElementType(elemType), isRead(isRead) {}
friend class ASTContext; // ASTContext creates these.
public:
QualType getElementType() const { return ElementType; }
@ -5304,11 +5304,12 @@ public:
QualType desugar() const { return QualType(this, 0); }
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getElementType());
Profile(ID, getElementType(), isReadOnly());
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
static void Profile(llvm::FoldingSetNodeID &ID, QualType T, bool isRead) {
ID.AddPointer(T.getAsOpaquePtr());
ID.AddBoolean(isRead);
}
static bool classof(const Type *T) {
@ -5318,18 +5319,6 @@ public:
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.
class QualifierCollector : public Qualifiers {
public:

View File

@ -905,12 +905,10 @@ namespace clang {
TYPE_DECAYED = 41,
/// \brief An AdjustedType record.
TYPE_ADJUSTED = 42,
/// \brief A ReadPipeType record.
TYPE_READ_PIPE = 43,
/// \brief A PipeType record.
TYPE_PIPE = 43,
/// \brief An ObjCTypeParamType record.
TYPE_OBJC_TYPE_PARAM = 44,
/// \brief A WritePipeType record.
TYPE_WRITE_PIPE = 45,
TYPE_OBJC_TYPE_PARAM = 44
};
/// \brief The type IDs for special types constructed by semantic

View File

@ -3338,54 +3338,37 @@ QualType ASTContext::getFunctionTypeInternal(
return QualType(FTP, 0);
}
QualType ASTContext::getReadPipeType(QualType T) const {
QualType ASTContext::getPipeType(QualType T, bool ReadOnly) const {
llvm::FoldingSetNodeID ID;
ReadPipeType::Profile(ID, T);
PipeType::Profile(ID, T, ReadOnly);
void *InsertPos = 0;
if (ReadPipeType *PT = ReadPipeTypes.FindNodeOrInsertPos(ID, InsertPos))
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 = getReadPipeType(getCanonicalType(T));
Canonical = getPipeType(getCanonicalType(T), ReadOnly);
// Get the new insert position for the node we care about.
ReadPipeType *NewIP = ReadPipeTypes.FindNodeOrInsertPos(ID, InsertPos);
PipeType *NewIP = PipeTypes.FindNodeOrInsertPos(ID, InsertPos);
assert(!NewIP && "Shouldn't be in the map!");
(void)NewIP;
}
ReadPipeType *New = new (*this, TypeAlignment) ReadPipeType(T, Canonical);
PipeType *New = new (*this, TypeAlignment) PipeType(T, Canonical, ReadOnly);
Types.push_back(New);
ReadPipeTypes.InsertNode(New, InsertPos);
PipeTypes.InsertNode(New, InsertPos);
return QualType(New, 0);
}
QualType ASTContext::getReadPipeType(QualType T) const {
return getPipeType(T, true);
}
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);
return getPipeType(T, false);
}
#ifndef NDEBUG
@ -8260,22 +8243,9 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
}
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 isa<ReadPipeType>(LHS) ? getReadPipeType(ResultType)
: getWritePipeType(ResultType);
assert(LHS != RHS &&
"Equivalent pipe types should have already been handled!");
return QualType();
}
}

View File

@ -5793,27 +5793,18 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
return Context.getAtomicType(ValueType);
}
case TYPE_READ_PIPE: {
if (Record.size() != 1) {
case TYPE_PIPE: {
if (Record.size() != 2) {
Error("Incorrect encoding of pipe type");
return QualType();
}
// Reading the pipe element type.
QualType ElementType = readType(*Loc.F, Record, Idx);
return Context.getReadPipeType(ElementType);
unsigned ReadOnly = Record[1];
return Context.getPipeType(ElementType, ReadOnly);
}
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!");
}

View File

@ -516,10 +516,8 @@ ASTTypeWriter::VisitAtomicType(const AtomicType *T) {
void
ASTTypeWriter::VisitPipeType(const PipeType *T) {
Record.AddTypeRef(T->getElementType());
if (T->isReadOnly())
Code = TYPE_READ_PIPE;
else
Code = TYPE_WRITE_PIPE;
Record.push_back(T->isReadOnly());
Code = TYPE_PIPE;
}
namespace {

View File

@ -28,3 +28,12 @@ bool test_id_comprision(void) {
reserve_id_t id1, id2;
return (id1 == id2); // expected-error {{invalid operands to binary expression ('reserve_id_t' and 'reserve_id_t')}}
}
// Tests ASTContext::mergeTypes rejects this.
int f(pipe int x, int y); // expected-note {{previous declaration is here}}
int f(x, y) // expected-error {{conflicting types for 'f}}
pipe short x;
int y;
{
return y;
}