]> granicus.if.org Git - clang/commitdiff
[OpenCL] Introduce ReadPipeType and WritePipeType.
authorJoey Gouly <joey.gouly@gmail.com>
Fri, 18 Nov 2016 14:10:54 +0000 (14:10 +0000)
committerJoey Gouly <joey.gouly@gmail.com>
Fri, 18 Nov 2016 14:10:54 +0000 (14:10 +0000)
This allows Sema to diagnose passing a read_only pipe to a
write_only pipe argument.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@287343 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/Type.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/ASTContext.cpp
lib/AST/TypePrinter.cpp
lib/Sema/SemaType.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/Misc/ast-dump-pipe.cl
test/SemaOpenCL/access-qualifier.cl
test/SemaOpenCL/invalid-pipes-cl2.0.cl

index 5e70ea1c204d7db29b01319d7249241bd59cb076..64f3870a68c25189fa2e0c11b9069db02f71e243 100644 (file)
@@ -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.
index a33799837aaf17eeb086b3e5fb196cd993f6d9e0..0a0a32511f1a351e9502833cd81713515787bf5d 100644 (file)
@@ -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.
index 818624b7dc4688e96946679888f8c65a4d8c861a..b81b424e8a6dbb4887794458b43997df59f07450 100644 (file)
@@ -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);
index a3be723af91bdb75725469e729341aa93fd1a617..9b8581b5ca5097e67a1789964061ba92adefe612 100644 (file)
@@ -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
index c48ab9a44a404bf48578516eab4b72ed99cc0fda..622898dde27a630d2eb4661bd314fe9224ce88b6 100644 (file)
@@ -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);
   }
   }
 
index 3372d334f66f0f1dd8ce692f82224373543f6db5..cccc908763212c1e2141149327a3af4e359fb52a 100644 (file)
@@ -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);
index 8dada8ca949c562523643e31c73c7f453f74108b..181a3818abe97d40c048969708a8939b72f12543 100644 (file)
@@ -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);
+    }
   }
 }
 
index 26d7222445b0ac3a746565e6322af5d2a1c33107..a52234663d73d48a95723f8b9d41d4e61ca828a4 100644 (file)
@@ -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>
index 35065d0fc1e4719660f76b4f14c07eb3143f6b18..f97571b7e800ffb8f00c92eaccbcf9a022af3eeb 100644 (file)
@@ -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!");
index e34347d206417a6e2534be01089095a5b3754ed4..f60a24cecb2465b79336164a2a92beec51ace0c6 100644 (file)
@@ -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 {
index 1690e5c17a0536d82849668f540ffff82094f926..ceed2f6f8992a7b67c7960a5988b1922236a57ad 100644 (file)
@@ -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'
index 7e5c70f915f64cbd2cd5f7cd0790e2e0e67cd072..7bc974109f3cc42b77bf1075ec45f12b6b4f27ce 100644 (file)
@@ -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
index 1993df5c44d41a227b727ccb63cb80873111dae8..96874a089c9c1b0590e757a4fdc1d0c1d5e72104 100644 (file)
@@ -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}}