r369253 - [OpenCL] Add generic type handling for builtin functions

Sven van Haastregt via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 19 04:56:03 PDT 2019


Author: svenvh
Date: Mon Aug 19 04:56:03 2019
New Revision: 369253

URL: http://llvm.org/viewvc/llvm-project?rev=369253&view=rev
Log:
[OpenCL] Add generic type handling for builtin functions

Generic types are an abstraction of type sets.  It mimics the way
functions are defined in the OpenCL specification.  For example,
floatN can abstract all the vector sizes of the float type.

This allows to
 * stick more closely to the specification, which uses generic types;
 * factorize definitions of functions with numerous prototypes in the
   tablegen file; and
 * reduce the memory impact of functions with many overloads.

Patch by Pierre Gondois and Sven van Haastregt.

Differential Revision: https://reviews.llvm.org/D65456

Modified:
    cfe/trunk/lib/Sema/OpenCLBuiltins.td
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/test/SemaOpenCL/fdeclare-opencl-builtins.cl
    cfe/trunk/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp

Modified: cfe/trunk/lib/Sema/OpenCLBuiltins.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/OpenCLBuiltins.td?rev=369253&r1=369252&r2=369253&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/OpenCLBuiltins.td (original)
+++ cfe/trunk/lib/Sema/OpenCLBuiltins.td Mon Aug 19 04:56:03 2019
@@ -40,11 +40,15 @@ def LocalAS      : AddressSpace<"clang::
 def GenericAS    : AddressSpace<"clang::LangAS::opencl_generic">;
 
 
-// Qualified Type. Allow to retrieve one ASTContext QualType.
-class QualType<string _Name> {
+// Qualified Type.  These map to ASTContext::QualType.
+class QualType<string _Name, bit _IsAbstract=0> {
   // Name of the field or function in a clang::ASTContext
   // E.g. Name="IntTy" for the int type, and "getIntPtrType()" for an intptr_t
   string Name = _Name;
+  // Some QualTypes in this file represent an abstract type for which there is
+  // no corresponding AST QualType, e.g. a GenType or an `image2d_t` type
+  // without access qualifiers.
+  bit IsAbstract = _IsAbstract;
 }
 
 // Helper class to store type access qualifiers (volatile, const, ...).
@@ -52,25 +56,35 @@ class Qualifier<string _QualName> {
   string QualName = _QualName;
 }
 
+// List of integers.
+class IntList<string _Name, list<int> _List> {
+  string Name = _Name;
+  list<int> List = _List;
+}
+
 //===----------------------------------------------------------------------===//
 //                      OpenCL C classes for types
 //===----------------------------------------------------------------------===//
-// OpenCL types (int, float, ...)
+// OpenCL C basic data types (int, float, image2d_t, ...).
+// Its Child classes can represent concrete types (e.g.: VectorType) or
+// custom types (e.g.: GenType).
+// Instances of these child classes should be used in Builtin function
+// arguments.  See the definition of the "read_imagef" function as example.
 class Type<string _Name, QualType _QTName> {
-  // Name of the Type
+  // Name of the Type.
   string Name = _Name;
-  // QualType associated with this type
+  // QualType associated with this type.
   QualType QTName = _QTName;
-  // Size of the vector (if applicable)
-  int VecWidth = 0;
-  // Is pointer
+  // Size of the vector (if applicable).
+  int VecWidth = 1;
+  // Is a pointer.
   bit IsPointer = 0;
   // List of qualifiers associated with the type (volatile, ...)
   list<Qualifier> QualList = [];
-  // Address space
-  string AddrSpace = "clang::LangAS::Default";
   // Access qualifier. Must be one of ("RO", "WO", "RW").
   string AccessQualifier = "";
+  // Address space.
+  string AddrSpace = "clang::LangAS::Default";
 }
 
 // OpenCL vector types (e.g. int2, int3, int16, float8, ...)
@@ -78,7 +92,7 @@ class VectorType<Type _Ty, int _VecWidth
   int VecWidth = _VecWidth;
 }
 
-// OpenCL pointer types (e.g. int*, float*, ...)
+// OpenCL pointer types (e.g. int*, float*, ...).
 class PointerType<Type _Ty, AddressSpace _AS = GlobalAS> :
                                       Type<_Ty.Name, _Ty.QTName> {
   bit IsPointer = 1;
@@ -91,6 +105,50 @@ class ImageType<Type _Ty, QualType _QTNa
   let AccessQualifier = _AccessQualifier;
 }
 
+// List of Types.
+class TypeList<string _Name, list<Type> _Type> {
+  string Name = _Name;
+  list<Type> List = _Type;
+}
+
+// A GenericType is an abstract type that defines a set of types as a
+// combination of Types and vector sizes.
+//
+// E.g.: If TypeList = <int, float> and VectorList = <1, 2, 4>, then it
+//       represents <int, int2, int4, float, float2, float4>.
+// _Ty          : Name of the GenType.
+// _TypeList    : List of basic data Types.
+// _VectorList  : Sizes of the vector for each type of the _TypeList, 1 being a
+//                scalar.
+//
+// Some rules apply when using multiple GenericType arguments in a declaration:
+//   1. The number of vector sizes must be equal or 1 for all gentypes in a
+//      declaration.
+//   2. The number of Types must be equal or 1 for all gentypes in a
+//      declaration.
+//   3. Generic types are combined by iterating over all generic types at once.
+//      For example, for the following GenericTypes
+//        GenT1 = GenericType<half, [1, 2]> and
+//        GenT2 = GenericType<float, int, [1, 2]>
+//      A declaration f(GenT1, GenT2) results in the combinations
+//        f(half, float), f(half2, float2), f(half, int), f(half2, int2) .
+//   4. "sgentype" from the OpenCL specification is supported by specifying
+//      a single vector size.
+//      For example, for the following GenericTypes
+//        GenT = GenericType<half, int, [1, 2]> and
+//        SGenT = GenericType<half, int, [1]>
+//      A declaration f(GenT, SGenT) results in the combinations
+//        f(half, half), f(half2, half), f(int, int), f(int2, int) .
+class GenericType<string _Ty, TypeList _TypeList, IntList _VectorList> :
+                                            Type<_Ty, QualType<"null", 1>> {
+  // Possible element types of the generic type.
+  TypeList TypeList = _TypeList;
+  // Possible vector sizes of the types in the TypeList.
+  IntList VectorList = _VectorList;
+  // The VecWidth field is ignored for GenericTypes. Use VectorList instead.
+  let VecWidth = 0;
+}
+
 //===----------------------------------------------------------------------===//
 //                      OpenCL C class for builtin functions
 //===----------------------------------------------------------------------===//
@@ -108,54 +166,10 @@ class Builtin<string _Name, list<Type> _
 }
 
 //===----------------------------------------------------------------------===//
-//                           Multiclass definitions
-//===----------------------------------------------------------------------===//
-// multiclass BifN: Creates Builtin class instances for OpenCL builtin
-//                  functions with N arguments.
-// _Name      : Name of the function
-// _Signature : Signature of the function (list of the Type used by the
-//              function, the first one being the return type).
-// _IsVector  : List of bit indicating if the type in the _Signature at the
-//              same index is to be a vector in the multiple overloads. The
-//              list must have at least one non-zero value.
-multiclass Bif0<string _Name, list<Type> _Signature, list<bit> _IsVector> {
-  def : Builtin<_Name, _Signature>;
-  foreach v = [2, 3, 4, 8, 16] in {
-    def : Builtin<_Name,
-                  [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0])]>;
-  }
-}
-multiclass Bif1<string _Name, list<Type> _Signature, list<bit> _IsVector> {
-  def : Builtin<_Name, _Signature>;
-  foreach v = [2, 3, 4, 8, 16] in {
-    def : Builtin<_Name,
-                  [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]),
-                  !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1])]>;
-  }
-}
-multiclass Bif2<string _Name, list<Type> _Signature, list<bit> _IsVector> {
-  def : Builtin<_Name, _Signature>;
-  foreach v = [2, 3, 4, 8, 16] in {
-    def : Builtin<_Name,
-                  [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]),
-                  !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1]),
-                  !if(_IsVector[2], VectorType<_Signature[2], v>, _Signature[2])]>;
-  }
-}
-multiclass Bif3<string _Name, list<Type> _Signature, list<bit> _IsVector> {
-  def : Builtin<_Name, _Signature>;
-  foreach v = [2, 3, 4, 8, 16] in {
-    def : Builtin<_Name,
-                  [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]),
-                  !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1]),
-                  !if(_IsVector[2], VectorType<_Signature[2], v>, _Signature[2]),
-                  !if(_IsVector[3], VectorType<_Signature[3], v>, _Signature[3])]>;
-  }
-}
-//===----------------------------------------------------------------------===//
 //                 Definitions of OpenCL C types
 //===----------------------------------------------------------------------===//
-// OpenCL v1.2 s6.1.1: Built-in Scalar Data Types
+
+// OpenCL v1.0/1.2/2.0 s6.1.1: Built-in Scalar Data Types.
 def Bool      : Type<"bool",      QualType<"BoolTy">>;
 def Char      : Type<"char",      QualType<"CharTy">>;
 def UChar     : Type<"uchar",     QualType<"UnsignedCharTy">>;
@@ -174,30 +188,18 @@ def IntPtr    : Type<"intptr_t",  QualTy
 def UIntPtr   : Type<"uintPtr_t", QualType<"getUIntPtrType()">>;
 def Void      : Type<"void_t",    QualType<"VoidTy">>;
 
-// OpenCL v1.2 s6.1.2: Built-in Vector Data Types
-foreach v = [2, 3, 4, 8, 16] in {
-  def char#v#_t    : VectorType<Char, v>;
-  def uchar#v#_t   : VectorType<UChar, v>;
-  def short#v#_t   : VectorType<Short, v>;
-  def ushort#v#_t  : VectorType<UShort, v>;
-  def "int"#v#_t   : VectorType<Int, v>;
-  def uint#v#_t    : VectorType<UInt, v>;
-  def long#v#_t    : VectorType<Long, v>;
-  def ulong#v#_t   : VectorType<ULong, v>;
-  def float#v#_t   : VectorType<Float, v>;
-  def double#v#_t  : VectorType<Double, v>;
-  def half#v#_t    : VectorType<Half, v>;
-}
+// OpenCL v1.0/1.2/2.0 s6.1.2: Built-in Vector Data Types.
+// Built-in vector data types are created by TableGen's OpenCLBuiltinEmitter.
 
 // OpenCL v1.2 s6.1.3: Other Built-in Data Types
 // These definitions with a "null" name are "abstract". They should not
 // be used in definitions of Builtin functions.
-def image2d_t         : Type<"image2d_t", QualType<"null">>;
-def image3d_t         : Type<"image3d_t", QualType<"null">>;
-def image2d_array_t   : Type<"image2d_array_t", QualType<"null">>;
-def image1d_t         : Type<"image1d_t", QualType<"null">>;
-def image1d_buffer_t  : Type<"image1d_buffer_t", QualType<"null">>;
-def image1d_array_t   : Type<"image1d_array_t", QualType<"null">>;
+def image2d_t         : Type<"image2d_t", QualType<"null", 1>>;
+def image3d_t         : Type<"image3d_t", QualType<"null", 1>>;
+def image2d_array_t   : Type<"image2d_array_t", QualType<"null", 1>>;
+def image1d_t         : Type<"image1d_t", QualType<"null", 1>>;
+def image1d_buffer_t  : Type<"image1d_buffer_t", QualType<"null", 1>>;
+def image1d_array_t   : Type<"image1d_array_t", QualType<"null", 1>>;
 // Unlike the few functions above, the following definitions can be used
 // in definitions of Builtin functions (they have a QualType with a name).
 foreach v = ["RO", "WO", "RW"] in {
@@ -225,6 +227,49 @@ def Sampler           : Type<"Sampler",
 def Event             : Type<"Event", QualType<"OCLEventTy">>;
 
 //===----------------------------------------------------------------------===//
+//                 Definitions of OpenCL gentype variants
+//===----------------------------------------------------------------------===//
+// The OpenCL specification often uses "gentype" in builtin function
+// declarations to indicate that a builtin function is available with various
+// argument and return types.  The types represented by "gentype" vary between
+// different parts of the specification.  The following definitions capture
+// the different type lists for gentypes in different parts of the
+// specification.
+
+// Vector width lists.
+def VecAndScalar: IntList<"VecAndScalar", [1, 2, 3, 4, 8, 16]>;
+def VecNoScalar : IntList<"VecNoScalar", [2, 3, 4, 8, 16]>;
+def Vec1        : IntList<"Vec1", [1]>;
+
+// Type lists.
+def TLFloat : TypeList<"TLFloat", [Float, Double, Half]>;
+
+def TLAllInts : TypeList<"TLAllInts", [Char, UChar, Short, UShort, Int, UInt, Long, ULong]>;
+
+// GenType definitions for multiple base types (e.g. all floating point types,
+// or all integer types).
+// All integer
+def AIGenType1             : GenericType<"AIGenType1", TLAllInts, Vec1>;
+def AIGenTypeN             : GenericType<"AIGenTypeN", TLAllInts, VecAndScalar>;
+def AIGenTypeNNoScalar     : GenericType<"AIGenTypeNNoScalar", TLAllInts, VecNoScalar>;
+// Float
+def FGenTypeN              : GenericType<"FGenTypeN", TLFloat, VecAndScalar>;
+
+// GenType definitions for every single base type (e.g. fp32 only).
+// Names are like: GenTypeFloatVecAndScalar.
+foreach Type = [Char, UChar, Short, UShort,
+                Int, UInt, Long, ULong,
+                Float, Double, Half] in {
+  foreach VecSizes = [VecAndScalar, VecNoScalar] in {
+    def "GenType" # Type # VecSizes :
+              GenericType<"GenType" # Type # VecSizes,
+                          TypeList<"GL" # Type.Name, [Type]>,
+                          VecSizes>;
+  }
+}
+
+
+//===----------------------------------------------------------------------===//
 //                 Definitions of OpenCL builtin functions
 //===----------------------------------------------------------------------===//
 //--------------------------------------------------------------------
@@ -261,27 +306,29 @@ foreach name = ["get_global_size", "get_
 foreach name = ["acos", "acosh", "acospi",
                 "asin", "asinh", "asinpi",
                 "atan", "atanh", "atanpi"] in {
-  foreach type = [Float, Double, Half] in {
-    defm : Bif1<name, [type, type], [1, 1]>;
-  }
+  def : Builtin<name, [FGenTypeN, FGenTypeN]>;
 }
 
 foreach name = ["atan2", "atan2pi"] in {
-  foreach type = [Float, Double, Half] in {
-    defm : Bif2<name, [type, type, type], [1, 1, 1]>;
-  }
+  def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>;
 }
 
 foreach name = ["fmax", "fmin"] in {
-  foreach type = [Float, Double, Half] in {
-    defm : Bif2<name, [type, type, type], [1, 1, 1]>;
-    defm : Bif2<name, [type, type, type], [1, 1, 0]>;
-  }
+  def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>;
+  def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float]>;
+  def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double]>;
+  def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half]>;
+}
+
+// OpenCL v1.1 s6.11.3, v1.2 s6.12.3, v2.0 s6.13.3 - Integer Functions
+foreach name = ["max", "min"] in {
+  def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN]>;
+  def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1]>;
 }
 
 // OpenCL v1.2 s6.12.14: Built-in Image Read Functions
 def read_imagef : Builtin<"read_imagef",
-                          [float4_t, image2d_RO_t, VectorType<Int, 2>]>;
+                          [VectorType<Float, 4>, image2d_RO_t, VectorType<Int, 2>]>;
 def write_imagef : Builtin<"write_imagef",
                            [Void,
                             image2d_WO_t,

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=369253&r1=369252&r2=369253&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Mon Aug 19 04:56:03 2019
@@ -673,76 +673,148 @@ LLVM_DUMP_METHOD void LookupResult::dump
     D->dump();
 }
 
-/// When trying to resolve a function name, if the isOpenCLBuiltin function
-/// defined in "OpenCLBuiltins.inc" returns a non-null <Index, Len>, then the
-/// identifier is referencing an OpenCL builtin function. Thus, all its
-/// prototypes are added to the LookUpResult.
-///
-/// \param S The Sema instance
-/// \param LR  The LookupResult instance
-/// \param II  The identifier being resolved
-/// \param Index  The list of prototypes starts at Index in OpenCLBuiltins[]
-/// \param Len  The list of prototypes has Len elements
-static void InsertOCLBuiltinDeclarations(Sema &S, LookupResult &LR,
-                                         IdentifierInfo *II, unsigned Index,
-                                         unsigned Len) {
+/// Get the QualType instances of the return type and arguments for an OpenCL
+/// builtin function signature.
+/// \param Context (in) The Context instance.
+/// \param OpenCLBuiltin (in) The signature currently handled.
+/// \param GenTypeMaxCnt (out) Maximum number of types contained in a generic
+///        type used as return type or as argument.
+///        Only meaningful for generic types, otherwise equals 1.
+/// \param RetTypes (out) List of the possible return types.
+/// \param ArgTypes (out) List of the possible argument types.  For each
+///        argument, ArgTypes contains QualTypes for the Cartesian product
+///        of (vector sizes) x (types) .
+static void GetQualTypesForOpenCLBuiltin(
+    ASTContext &Context, const OpenCLBuiltinStruct &OpenCLBuiltin,
+    unsigned &GenTypeMaxCnt, std::vector<QualType> &RetTypes,
+    SmallVector<std::vector<QualType>, 5> &ArgTypes) {
+  // Get the QualType instances of the return types.
+  unsigned Sig = SignatureTable[OpenCLBuiltin.SigTableIndex];
+  OCL2Qual(Context, TypeTable[Sig], RetTypes);
+  GenTypeMaxCnt = RetTypes.size();
+
+  // Get the QualType instances of the arguments.
+  // First type is the return type, skip it.
+  for (unsigned Index = 1; Index < OpenCLBuiltin.NumTypes; Index++) {
+    std::vector<QualType> Ty;
+    OCL2Qual(Context,
+        TypeTable[SignatureTable[OpenCLBuiltin.SigTableIndex + Index]], Ty);
+    ArgTypes.push_back(Ty);
+    GenTypeMaxCnt = (Ty.size() > GenTypeMaxCnt) ? Ty.size() : GenTypeMaxCnt;
+  }
+}
+
+/// Create a list of the candidate function overloads for an OpenCL builtin
+/// function.
+/// \param Context (in) The ASTContext instance.
+/// \param GenTypeMaxCnt (in) Maximum number of types contained in a generic
+///        type used as return type or as argument.
+///        Only meaningful for generic types, otherwise equals 1.
+/// \param FunctionList (out) List of FunctionTypes.
+/// \param RetTypes (in) List of the possible return types.
+/// \param ArgTypes (in) List of the possible types for the arguments.
+static void
+GetOpenCLBuiltinFctOverloads(ASTContext &Context, unsigned GenTypeMaxCnt,
+                             std::vector<QualType> &FunctionList,
+                             std::vector<QualType> &RetTypes,
+                             SmallVector<std::vector<QualType>, 5> &ArgTypes) {
+  FunctionProtoType::ExtProtoInfo PI;
+  PI.Variadic = false;
+
+  // Create FunctionTypes for each (gen)type.
+  for (unsigned IGenType = 0; IGenType < GenTypeMaxCnt; IGenType++) {
+    SmallVector<QualType, 5> ArgList;
+
+    for (unsigned A = 0; A < ArgTypes.size(); A++) {
+      // Builtins such as "max" have an "sgentype" argument that represents
+      // the corresponding scalar type of a gentype.  The number of gentypes
+      // must be a multiple of the number of sgentypes.
+      assert(GenTypeMaxCnt % ArgTypes[A].size() == 0 &&
+             "argument type count not compatible with gentype type count");
+      unsigned Idx = IGenType % ArgTypes[A].size();
+      ArgList.push_back(ArgTypes[A][Idx]);
+    }
 
-  for (unsigned i = 0; i < Len; ++i) {
-    const OpenCLBuiltinDecl &Decl = OpenCLBuiltins[Index - 1 + i];
+    FunctionList.push_back(Context.getFunctionType(
+        RetTypes[(RetTypes.size() != 1) ? IGenType : 0], ArgList, PI));
+  }
+}
+
+/// When trying to resolve a function name, if isOpenCLBuiltin() returns a
+/// non-null <Index, Len> pair, then the name is referencing an OpenCL
+/// builtin function.  Add all candidate signatures to the LookUpResult.
+///
+/// \param S (in) The Sema instance.
+/// \param LR (inout) The LookupResult instance.
+/// \param II (in) The identifier being resolved.
+/// \param FctIndex (in) Starting index in the BuiltinTable.
+/// \param Len (in) The signature list has Len elements.
+static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR,
+                                                  IdentifierInfo *II,
+                                                  const unsigned FctIndex,
+                                                  const unsigned Len) {
+  // The builtin function declaration uses generic types (gentype).
+  bool HasGenType = false;
+
+  // Maximum number of types contained in a generic type used as return type or
+  // as argument.  Only meaningful for generic types, otherwise equals 1.
+  unsigned GenTypeMaxCnt;
+
+  for (unsigned SignatureIndex = 0; SignatureIndex < Len; SignatureIndex++) {
+    const OpenCLBuiltinStruct &OpenCLBuiltin =
+        BuiltinTable[FctIndex + SignatureIndex];
     ASTContext &Context = S.Context;
 
-    // Ignore this BIF if the version is incorrect.
-    if (Context.getLangOpts().OpenCLVersion < Decl.Version)
-      continue;
-
-    FunctionProtoType::ExtProtoInfo PI;
-    PI.Variadic = false;
-
-    // Defined in "OpenCLBuiltins.inc"
-    QualType RT = OCL2Qual(Context, OpenCLSignature[Decl.ArgTableIndex]);
-
-    SmallVector<QualType, 5> ArgTypes;
-    for (unsigned I = 1; I < Decl.NumArgs; I++) {
-      QualType Ty = OCL2Qual(Context, OpenCLSignature[Decl.ArgTableIndex + I]);
-      ArgTypes.push_back(Ty);
+    std::vector<QualType> RetTypes;
+    SmallVector<std::vector<QualType>, 5> ArgTypes;
+
+    // Obtain QualType lists for the function signature.
+    GetQualTypesForOpenCLBuiltin(Context, OpenCLBuiltin, GenTypeMaxCnt,
+                                 RetTypes, ArgTypes);
+    if (GenTypeMaxCnt > 1) {
+      HasGenType = true;
     }
 
-    QualType R = Context.getFunctionType(RT, ArgTypes, PI);
-    SourceLocation Loc = LR.getNameLoc();
+    // Create function overload for each type combination.
+    std::vector<QualType> FunctionList;
+    GetOpenCLBuiltinFctOverloads(Context, GenTypeMaxCnt, FunctionList, RetTypes,
+                                 ArgTypes);
 
-    // TODO: This part is taken from Sema::LazilyCreateBuiltin,
-    // maybe refactor it.
+    SourceLocation Loc = LR.getNameLoc();
     DeclContext *Parent = Context.getTranslationUnitDecl();
-    FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, R,
-                                             /*TInfo=*/nullptr, SC_Extern,
-                                             false, R->isFunctionProtoType());
-    New->setImplicit();
-
-    // Create Decl objects for each parameter, adding them to the
-    // FunctionDecl.
-    if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) {
-      SmallVector<ParmVarDecl *, 16> Params;
-      for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
-        ParmVarDecl *Parm =
-            ParmVarDecl::Create(Context, New, SourceLocation(),
-                                SourceLocation(), nullptr, FT->getParamType(i),
-                                /*TInfo=*/nullptr, SC_None, nullptr);
-        Parm->setScopeInfo(0, i);
-        Params.push_back(Parm);
+    FunctionDecl *NewOpenCLBuiltin;
+
+    for (unsigned Index = 0; Index < GenTypeMaxCnt; Index++) {
+      NewOpenCLBuiltin = FunctionDecl::Create(
+          Context, Parent, Loc, Loc, II, FunctionList[Index],
+          /*TInfo=*/nullptr, SC_Extern, false,
+          FunctionList[Index]->isFunctionProtoType());
+      NewOpenCLBuiltin->setImplicit();
+
+      // Create Decl objects for each parameter, adding them to the
+      // FunctionDecl.
+      if (const FunctionProtoType *FP =
+              dyn_cast<FunctionProtoType>(FunctionList[Index])) {
+        SmallVector<ParmVarDecl *, 16> ParmList;
+        for (unsigned IParm = 0, e = FP->getNumParams(); IParm != e; ++IParm) {
+          ParmVarDecl *Parm = ParmVarDecl::Create(
+              Context, NewOpenCLBuiltin, SourceLocation(), SourceLocation(),
+              nullptr, FP->getParamType(IParm),
+              /*TInfo=*/nullptr, SC_None, nullptr);
+          Parm->setScopeInfo(0, IParm);
+          ParmList.push_back(Parm);
+        }
+        NewOpenCLBuiltin->setParams(ParmList);
       }
-      New->setParams(Params);
+      if (!S.getLangOpts().OpenCLCPlusPlus) {
+        NewOpenCLBuiltin->addAttr(OverloadableAttr::CreateImplicit(Context));
+      }
+      LR.addDecl(NewOpenCLBuiltin);
     }
-
-    New->addAttr(OverloadableAttr::CreateImplicit(Context));
-
-    if (strlen(Decl.Extension))
-      S.setOpenCLExtensionForDecl(New, Decl.Extension);
-
-    LR.addDecl(New);
   }
 
   // If we added overloads, need to resolve the lookup result.
-  if (Len > 1)
+  if (Len > 1 || HasGenType)
     LR.resolveKind();
 }
 
@@ -772,7 +844,8 @@ static bool LookupBuiltin(Sema &S, Looku
       if (S.getLangOpts().OpenCL && S.getLangOpts().DeclareOpenCLBuiltins) {
         auto Index = isOpenCLBuiltin(II->getName());
         if (Index.first) {
-          InsertOCLBuiltinDeclarations(S, R, II, Index.first, Index.second);
+          InsertOCLBuiltinDeclarationsFromTable(S, R, II, Index.first - 1,
+                                                Index.second);
           return true;
         }
       }

Modified: cfe/trunk/test/SemaOpenCL/fdeclare-opencl-builtins.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaOpenCL/fdeclare-opencl-builtins.cl?rev=369253&r1=369252&r2=369253&view=diff
==============================================================================
--- cfe/trunk/test/SemaOpenCL/fdeclare-opencl-builtins.cl (original)
+++ cfe/trunk/test/SemaOpenCL/fdeclare-opencl-builtins.cl Mon Aug 19 04:56:03 2019
@@ -1,28 +1,41 @@
 // RUN: %clang_cc1 %s -triple spir -verify -pedantic -fsyntax-only -cl-std=CL2.0 -fdeclare-opencl-builtins -DNO_HEADER
 // RUN: %clang_cc1 %s -triple spir -verify -pedantic -fsyntax-only -cl-std=CL2.0 -fdeclare-opencl-builtins -finclude-default-header
+// expected-no-diagnostics
 
 // Test the -fdeclare-opencl-builtins option.
 
 // Provide typedefs when invoking clang without -finclude-default-header.
 #ifdef NO_HEADER
+typedef char char2 __attribute__((ext_vector_type(2)));
+typedef char char4 __attribute__((ext_vector_type(4)));
 typedef float float4 __attribute__((ext_vector_type(4)));
-typedef int int4 __attribute__((ext_vector_type(4)));
 typedef int int2 __attribute__((ext_vector_type(2)));
+typedef int int4 __attribute__((ext_vector_type(4)));
+typedef long long2 __attribute__((ext_vector_type(2)));
 typedef unsigned int uint;
 typedef __SIZE_TYPE__ size_t;
 #endif
 
-kernel void basic_conversion(global float4 *buf, global int4 *res) {
-  res[0] = convert_int4(buf[0]);
+kernel void basic_conversion() {
+  double d;
+  float f;
+  char2 c2;
+  long2 l2;
+  float4 f4;
+  int4 i4;
+
+  f = convert_float(d);
+  d = convert_double_sat_rtp(f);
+  l2 = convert_long2_rtz(c2);
+  i4 = convert_int4_sat(f4);
 }
 
-kernel void basic_readonly_image_type(__read_only image2d_t img, int2 coord, global float4 *out) {
-  out[0] = read_imagef(img, coord);
+char4 test_int(char c, char4 c4) {
+  char m = max(c, c);
+  char4 m4 = max(c4, c4);
+  return max(c4, c);
 }
 
 kernel void basic_subgroup(global uint *out) {
   out[0] = get_sub_group_size();
-// expected-error at -1{{use of declaration 'get_sub_group_size' requires cl_khr_subgroups extension to be enabled}}
-#pragma OPENCL EXTENSION cl_khr_subgroups : enable
-  out[1] = get_sub_group_size();
 }

Modified: cfe/trunk/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp?rev=369253&r1=369252&r2=369253&view=diff
==============================================================================
--- cfe/trunk/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp (original)
+++ cfe/trunk/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp Mon Aug 19 04:56:03 2019
@@ -15,12 +15,39 @@
 //
 // For a successful lookup of e.g. the "cos" builtin, isOpenCLBuiltin("cos")
 // returns a pair <Index, Len>.
-// OpenCLBuiltins[Index] to OpenCLBuiltins[Index + Len] contains the pairs
+// BuiltinTable[Index] to BuiltinTable[Index + Len] contains the pairs
 // <SigIndex, SigLen> of the overloads of "cos".
-// OpenCLSignature[SigIndex] to OpenCLSignature[SigIndex + SigLen] contains
-// one of the signatures of "cos". The OpenCLSignature entry can be
-// referenced by other functions, i.e. "sin", since multiple OpenCL builtins
-// share the same signature.
+// SignatureTable[SigIndex] to SignatureTable[SigIndex + SigLen] contains
+// one of the signatures of "cos". The SignatureTable entry can be
+// referenced by other functions, e.g. "sin", to exploit the fact that
+// many OpenCL builtins share the same signature.
+//
+// The file generated by this TableGen emitter contains the following:
+//
+//  * Structs and enums to represent types and function signatures.
+//
+//  * OpenCLTypeStruct TypeTable[]
+//    Type information for return types and arguments.
+//
+//  * unsigned SignatureTable[]
+//    A list of types representing function signatures.  Each entry is an index
+//    into the above TypeTable.  Multiple entries following each other form a
+//    signature, where the first entry is the return type and subsequent
+//    entries are the argument types.
+//
+//  * OpenCLBuiltinStruct BuiltinTable[]
+//    Each entry represents one overload of an OpenCL builtin function and
+//    consists of an index into the SignatureTable and the number of arguments.
+//
+//  * std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name)
+//    Find out whether a string matches an existing OpenCL builtin function
+//    name and return an index into BuiltinTable and the number of overloads.
+//
+//  * void OCL2Qual(ASTContext&, OpenCLTypeStruct, std::vector<QualType>&)
+//    Convert an OpenCLTypeStruct type to a list of QualType instances.
+//    One OpenCLTypeStruct can represent multiple types, primarily when using
+//    GenTypes.
+//
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ADT/MapVector.h"
@@ -57,34 +84,47 @@ private:
   // The output file.
   raw_ostream &OS;
 
-  // Emit the enums and structs.
+  // Helper function for BuiltinNameEmitter::EmitDeclarations.  Generate enum
+  // definitions in the Output string parameter, and save their Record instances
+  // in the List parameter.
+  // \param Types (in) List containing the Types to extract.
+  // \param TypesSeen (inout) List containing the Types already extracted.
+  // \param Output (out) String containing the enums to emit in the output file.
+  // \param List (out) List containing the extracted Types, except the Types in
+  //        TypesSeen.
+  void ExtractEnumTypes(std::vector<Record *> &Types,
+                        StringMap<bool> &TypesSeen, std::string &Output,
+                        std::vector<const Record *> &List);
+
+  // Emit the enum or struct used in the generated file.
+  // Populate the TypeList at the same time.
   void EmitDeclarations();
 
-  // Parse the Records generated by TableGen and populate OverloadInfo and
-  // SignatureSet.
+  // Parse the Records generated by TableGen to populate the SignaturesList,
+  // FctOverloadMap and TypeMap.
   void GetOverloads();
 
-  // Emit the OpenCLSignature table. This table contains all possible
-  // signatures, and is a struct OpenCLType. A signature is composed of a
-  // return type (mandatory), followed by zero or more argument types.
+  // Emit the TypeTable containing all types used by OpenCL builtins.
+  void EmitTypeTable();
+
+  // Emit the SignatureTable. This table contains all the possible signatures.
+  // A signature is stored as a list of indexes of the TypeTable.
+  // The first index references the return type (mandatory), and the followings
+  // reference its arguments.
   // E.g.:
-  // // 12
-  // { OCLT_uchar, 4, clang::LangAS::Default, false },
-  // { OCLT_float, 4, clang::LangAS::Default, false },
-  // This means that index 12 represents a signature
-  //   - returning a uchar vector of 4 elements, and
-  //   - taking as first argument a float vector of 4 elements.
+  // 15, 2, 15 can represent a function with the signature:
+  // int func(float, int)
+  // The "int" type being at the index 15 in the TypeTable.
   void EmitSignatureTable();
 
-  // Emit the OpenCLBuiltins table. This table contains all overloads of
+  // Emit the BuiltinTable table. This table contains all the overloads of
   // each function, and is a struct OpenCLBuiltinDecl.
   // E.g.:
-  // // acos
-  //   { 2, 0, "", 100 },
-  // This means that the signature of this acos overload is defined in OpenCL
-  // version 1.0 (100) and does not belong to any extension ("").  It has a
-  // 1 argument (+1 for the return type), stored at index 0 in the
-  // OpenCLSignature table.
+  // // convert_float2_rtn
+  //   { 58, 2 },
+  // This means that the signature of this convert_float2_rtn overload has
+  // 1 argument (+1 for the return type), stored at index 58 in
+  // the SignatureTable.
   void EmitBuiltinTable();
 
   // Emit a StringMatcher function to check whether a function name is an
@@ -102,20 +142,30 @@ private:
   //        <<float>, 5>,
   //        ...
   //        <<double, double>, 35>.
-  std::vector<std::pair<std::vector<Record *>, unsigned>> SignatureSet;
+  std::vector<std::pair<std::vector<Record *>, unsigned>> SignaturesList;
 
   // Map the name of a builtin function to its prototypes (instances of the
   // TableGen "Builtin" class).
   // Each prototype is registered as a pair of:
   //   <pointer to the "Builtin" instance,
-  //    cumulative index of the associated signature in the SignatureSet>
+  //    cumulative index of the associated signature in the SignaturesList>
   // E.g.:  The function cos: (float cos(float), double cos(double), ...)
   //        <"cos", <<ptrToPrototype0, 5>,
-  //                <ptrToPrototype1, 35>>
-  //                <ptrToPrototype2, 79>>
+  //                 <ptrToPrototype1, 35>,
+  //                 <ptrToPrototype2, 79>>
   // ptrToPrototype1 has the following signature: <double, double>
   MapVector<StringRef, std::vector<std::pair<const Record *, unsigned>>>
-      OverloadInfo;
+      FctOverloadMap;
+
+  // Contains the map of OpenCL types to their index in the TypeTable.
+  MapVector<const Record *, unsigned> TypeMap;
+
+  // List of OpenCL type names in the same order as in enum OpenCLTypeID.
+  // This list does not contain generic types.
+  std::vector<const Record *> TypeList;
+
+  // Same as TypeList, but for generic types only.
+  std::vector<const Record *> GenTypeList;
 };
 } // namespace
 
@@ -125,12 +175,14 @@ void BuiltinNameEmitter::Emit() {
   OS << "#include \"llvm/ADT/StringRef.h\"\n";
   OS << "using namespace clang;\n\n";
 
+  // Emit enums and structs.
   EmitDeclarations();
 
   GetOverloads();
 
+  // Emit tables.
+  EmitTypeTable();
   EmitSignatureTable();
-
   EmitBuiltinTable();
 
   EmitStringMatcher();
@@ -138,100 +190,191 @@ void BuiltinNameEmitter::Emit() {
   EmitQualTypeFinder();
 }
 
+void BuiltinNameEmitter::ExtractEnumTypes(std::vector<Record *> &Types,
+                                          StringMap<bool> &TypesSeen,
+                                          std::string &Output,
+                                          std::vector<const Record *> &List) {
+  raw_string_ostream SS(Output);
+
+  for (const auto *T : Types) {
+    if (TypesSeen.find(T->getValueAsString("Name")) == TypesSeen.end()) {
+      SS << "  OCLT_" + T->getValueAsString("Name") << ",\n";
+      // Save the type names in the same order as their enum value. Note that
+      // the Record can be a VectorType or something else, only the name is
+      // important.
+      List.push_back(T);
+      TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true));
+    }
+  }
+  SS.flush();
+}
+
 void BuiltinNameEmitter::EmitDeclarations() {
+  // Enum of scalar type names (float, int, ...) and generic type sets.
   OS << "enum OpenCLTypeID {\n";
-  std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
+
   StringMap<bool> TypesSeen;
-  for (const auto *T : Types) {
-    if (TypesSeen.find(T->getValueAsString("Name")) == TypesSeen.end())
-      OS << "  OCLT_" + T->getValueAsString("Name") << ",\n";
-    TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true));
-  }
+  std::string GenTypeEnums;
+  std::string TypeEnums;
+
+  // Extract generic types and non-generic types separately, to keep
+  // gentypes at the end of the enum which simplifies the special handling
+  // for gentypes in SemaLookup.
+  std::vector<Record *> GenTypes =
+      Records.getAllDerivedDefinitions("GenericType");
+  ExtractEnumTypes(GenTypes, TypesSeen, GenTypeEnums, GenTypeList);
+
+  std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
+  ExtractEnumTypes(Types, TypesSeen, TypeEnums, TypeList);
+
+  OS << TypeEnums;
+  OS << GenTypeEnums;
   OS << "};\n";
 
+  // Structure definitions.
   OS << R"(
 
-// Type used in a prototype of an OpenCL builtin function.
-struct OpenCLType {
-  // A type (e.g.: float, int, ...)
-  OpenCLTypeID ID;
-  // Size of vector (if applicable)
-  unsigned VectorWidth;
-  // Address space of the pointer (if applicable)
-  LangAS AS;
-  // Whether the type is a pointer
-  bool isPointer;
+// Represents a return type or argument type.
+struct OpenCLTypeStruct {
+  // A type (e.g. float, int, ...)
+  const OpenCLTypeID ID;
+  // Vector size (if applicable; 0 for scalars and generic types).
+  const unsigned VectorWidth;
 };
 
 // One overload of an OpenCL builtin function.
-struct OpenCLBuiltinDecl {
-  // Number of arguments for the signature
-  unsigned NumArgs;
-  // Index in the OpenCLSignature table to get the required types
-  unsigned ArgTableIndex;
-  // Extension to which it belongs (e.g. cl_khr_subgroups)
-  const char *Extension;
-  // Version in which it was introduced (e.g. CL20)
-  unsigned Version;
+struct OpenCLBuiltinStruct {
+  // Index of the signature in the OpenCLTypeStruct table.
+  const unsigned SigTableIndex;
+  // Entries between index SigTableIndex and (SigTableIndex + NumTypes - 1) in
+  // the SignatureTable represent the complete signature.  The first type at
+  // index SigTableIndex is the return type.
+  const unsigned NumTypes;
 };
 
 )";
 }
 
+// Verify that the combination of GenTypes in a signature is supported.
+// To simplify the logic for creating overloads in SemaLookup, only allow
+// a signature to contain different GenTypes if these GenTypes represent
+// the same number of actual scalar or vector types.
+//
+// Exit with a fatal error if an unsupported construct is encountered.
+static void VerifySignature(const std::vector<Record *> &Signature,
+                            const Record *BuiltinRec) {
+  unsigned GenTypeVecSizes = 1;
+  unsigned GenTypeTypes = 1;
+
+  for (const auto *T : Signature) {
+    // Check all GenericType arguments in this signature.
+    if (T->isSubClassOf("GenericType")) {
+      // Check number of vector sizes.
+      unsigned NVecSizes =
+          T->getValueAsDef("VectorList")->getValueAsListOfInts("List").size();
+      if (NVecSizes != GenTypeVecSizes && NVecSizes != 1) {
+        if (GenTypeVecSizes > 1) {
+          // We already saw a gentype with a different number of vector sizes.
+          PrintFatalError(BuiltinRec->getLoc(),
+              "number of vector sizes should be equal or 1 for all gentypes "
+              "in a declaration");
+        }
+        GenTypeVecSizes = NVecSizes;
+      }
+
+      // Check number of data types.
+      unsigned NTypes =
+          T->getValueAsDef("TypeList")->getValueAsListOfDefs("List").size();
+      if (NTypes != GenTypeTypes && NTypes != 1) {
+        if (GenTypeTypes > 1) {
+          // We already saw a gentype with a different number of types.
+          PrintFatalError(BuiltinRec->getLoc(),
+              "number of types should be equal or 1 for all gentypes "
+              "in a declaration");
+        }
+        GenTypeTypes = NTypes;
+      }
+    }
+  }
+}
+
 void BuiltinNameEmitter::GetOverloads() {
+  // Populate the TypeMap.
+  std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
+  unsigned I = 0;
+  for (const auto &T : Types) {
+    TypeMap.insert(std::make_pair(T, I++));
+  }
+
+  // Populate the SignaturesList and the FctOverloadMap.
   unsigned CumulativeSignIndex = 0;
   std::vector<Record *> Builtins = Records.getAllDerivedDefinitions("Builtin");
   for (const auto *B : Builtins) {
     StringRef BName = B->getValueAsString("Name");
-    if (OverloadInfo.find(BName) == OverloadInfo.end()) {
-      OverloadInfo.insert(std::make_pair(
+    if (FctOverloadMap.find(BName) == FctOverloadMap.end()) {
+      FctOverloadMap.insert(std::make_pair(
           BName, std::vector<std::pair<const Record *, unsigned>>{}));
     }
 
     auto Signature = B->getValueAsListOfDefs("Signature");
+    // Reuse signatures to avoid unnecessary duplicates.
     auto it =
-        std::find_if(SignatureSet.begin(), SignatureSet.end(),
+        std::find_if(SignaturesList.begin(), SignaturesList.end(),
                      [&](const std::pair<std::vector<Record *>, unsigned> &a) {
                        return a.first == Signature;
                      });
     unsigned SignIndex;
-    if (it == SignatureSet.end()) {
-      SignatureSet.push_back(std::make_pair(Signature, CumulativeSignIndex));
+    if (it == SignaturesList.end()) {
+      VerifySignature(Signature, B);
+      SignaturesList.push_back(std::make_pair(Signature, CumulativeSignIndex));
       SignIndex = CumulativeSignIndex;
       CumulativeSignIndex += Signature.size();
     } else {
       SignIndex = it->second;
     }
-    OverloadInfo[BName].push_back(std::make_pair(B, SignIndex));
+    FctOverloadMap[BName].push_back(std::make_pair(B, SignIndex));
   }
 }
 
+void BuiltinNameEmitter::EmitTypeTable() {
+  OS << "static const OpenCLTypeStruct TypeTable[] = {\n";
+  for (const auto &T : TypeMap) {
+    OS << "  // " << T.second << "\n";
+    OS << "  {OCLT_" << T.first->getValueAsString("Name") << ", "
+       << T.first->getValueAsInt("VecWidth") << "},\n";
+  }
+  OS << "};\n\n";
+}
+
 void BuiltinNameEmitter::EmitSignatureTable() {
-  OS << "static const OpenCLType OpenCLSignature[] = {\n";
-  for (auto &P : SignatureSet) {
-    OS << "// " << P.second << "\n";
-    for (Record *R : P.first) {
-      OS << "{ OCLT_" << R->getValueAsString("Name") << ", "
-         << R->getValueAsInt("VecWidth") << ", "
-         << R->getValueAsString("AddrSpace") << ", "
-         << R->getValueAsBit("IsPointer") << "},";
-      OS << "\n";
+  // Store a type (e.g. int, float, int2, ...). The type is stored as an index
+  // of a struct OpenCLType table. Multiple entries following each other form a
+  // signature.
+  OS << "static const unsigned SignatureTable[] = {\n";
+  for (const auto &P : SignaturesList) {
+    OS << "  // " << P.second << "\n  ";
+    for (const Record *R : P.first) {
+      OS << TypeMap.find(R)->second << ", ";
     }
+    OS << "\n";
   }
   OS << "};\n\n";
 }
 
 void BuiltinNameEmitter::EmitBuiltinTable() {
-  OS << "static const OpenCLBuiltinDecl OpenCLBuiltins[] = {\n";
-  for (auto &i : OverloadInfo) {
-    StringRef Name = i.first;
-    OS << "// " << Name << "\n";
-    for (auto &Overload : i.second) {
-      OS << "  { " << Overload.first->getValueAsListOfDefs("Signature").size()
-         << ", " << Overload.second << ", " << '"'
-         << Overload.first->getValueAsString("Extension") << "\", "
-         << Overload.first->getValueAsDef("Version")->getValueAsInt("Version")
+  unsigned Index = 0;
+
+  OS << "static const OpenCLBuiltinStruct BuiltinTable[] = {\n";
+  for (const auto &FOM : FctOverloadMap) {
+
+    OS << "  // " << (Index + 1) << ": " << FOM.first << "\n";
+
+    for (const auto &Overload : FOM.second) {
+      OS << "  { "
+         << Overload.second << ", "
+         << Overload.first->getValueAsListOfDefs("Signature").size()
          << " },\n";
+         Index++;
     }
   }
   OS << "};\n\n";
@@ -240,7 +383,7 @@ void BuiltinNameEmitter::EmitBuiltinTabl
 void BuiltinNameEmitter::EmitStringMatcher() {
   std::vector<StringMatcher::StringPair> ValidBuiltins;
   unsigned CumulativeIndex = 1;
-  for (auto &i : OverloadInfo) {
+  for (auto &i : FctOverloadMap) {
     auto &Ov = i.second;
     std::string RetStmt;
     raw_string_ostream SS(RetStmt);
@@ -253,26 +396,87 @@ void BuiltinNameEmitter::EmitStringMatch
   }
 
   OS << R"(
-// Return 0 if name is not a recognized OpenCL builtin, or an index
-// into a table of declarations if it is an OpenCL builtin.
-static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef name) {
+// Find out whether a string matches an existing OpenCL builtin function name.
+// Returns: A pair <0, 0> if no name matches.
+//          A pair <Index, Len> indexing the BuiltinTable if the name is
+//          matching an OpenCL builtin function.
+static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name) {
 
 )";
 
-  StringMatcher("name", ValidBuiltins, OS).Emit(0, true);
+  StringMatcher("Name", ValidBuiltins, OS).Emit(0, true);
 
   OS << "  return std::make_pair(0, 0);\n";
-  OS << "}\n";
+  OS << "} // isOpenCLBuiltin\n";
 }
 
 void BuiltinNameEmitter::EmitQualTypeFinder() {
   OS << R"(
 
-static QualType OCL2Qual(ASTContext &Context, OpenCLType Ty) {
-  QualType RT = Context.VoidTy;
-  switch (Ty.ID) {
+// Convert an OpenCLTypeStruct type to a list of QualTypes.
+// Generic types represent multiple types and vector sizes, thus a vector
+// is returned. The conversion is done in two steps:
+// Step 1: A switch statement fills a vector with scalar base types for the
+//         Cartesian product of (vector sizes) x (types) for generic types,
+//         or a single scalar type for non generic types.
+// Step 2: Qualifiers and other type properties such as vector size are
+//         applied.
+static void OCL2Qual(ASTContext &Context, const OpenCLTypeStruct &Ty,
+                     std::vector<QualType> &QT) {
+  // Number of scalar types in the GenType.
+  unsigned GenTypeNumTypes;
+  // Pointer to the list of vector sizes for the GenType.
+  llvm::SmallVector<unsigned, 6> *GenVectorSizes;
 )";
 
+  // Generate list of vector sizes for each generic type.
+  for (const auto *VectList : Records.getAllDerivedDefinitions("IntList")) {
+    OS << "  llvm::SmallVector<unsigned, 6> List"
+       << VectList->getValueAsString("Name") << "{";
+    for (const auto V : VectList->getValueAsListOfInts("List")) {
+      OS << V << ", ";
+    }
+    OS << "};\n";
+  }
+
+  // Step 1.
+  // Start of switch statement over all types.
+  OS << "\n  switch (Ty.ID) {\n";
+
+  // Switch cases for generic types.
+  for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) {
+    OS << "    case OCLT_" << GenType->getValueAsString("Name") << ":\n";
+
+    // Build the Cartesian product of (vector sizes) x (types).  Only insert
+    // the plain scalar types for now; other type information such as vector
+    // size and type qualifiers will be added after the switch statement.
+    for (unsigned I = 0; I < GenType->getValueAsDef("VectorList")
+                                 ->getValueAsListOfInts("List")
+                                 .size();
+         I++) {
+      for (const auto *T :
+           GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")) {
+        OS << "      QT.push_back(Context."
+           << T->getValueAsDef("QTName")->getValueAsString("Name") << ");\n";
+      }
+    }
+    // GenTypeNumTypes is the number of types in the GenType
+    // (e.g. float/double/half).
+    OS << "      GenTypeNumTypes = "
+       << GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")
+              .size()
+       << ";\n";
+    // GenVectorSizes is the list of vector sizes for this GenType.
+    // QT contains GenTypeNumTypes * #GenVectorSizes elements.
+    OS << "      GenVectorSizes = &List"
+       << GenType->getValueAsDef("VectorList")->getValueAsString("Name")
+       << ";\n";
+    OS << "      break;\n";
+  }
+
+  // Switch cases for non generic, non image types (int, int4, float, ...).
+  // Only insert the plain scalar type; vector information and type qualifiers
+  // are added in step 2.
   std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
   StringMap<bool> TypesSeen;
 
@@ -284,28 +488,47 @@ static QualType OCL2Qual(ASTContext &Con
 
     // Check the Type does not have an "abstract" QualType
     auto QT = T->getValueAsDef("QTName");
-    if (QT->getValueAsString("Name") == "null")
+    if (QT->getValueAsBit("IsAbstract") == 1)
       continue;
-
-    OS << "  case OCLT_" << T->getValueAsString("Name") << ":\n";
-    OS << "    RT = Context." << QT->getValueAsString("Name") << ";\n";
-    OS << "    break;\n";
+    // Emit the cases for non generic, non image types.
+    OS << "    case OCLT_" << T->getValueAsString("Name") << ":\n";
+    OS << "      QT.push_back(Context." << QT->getValueAsString("Name")
+       << ");\n";
+    OS << "      break;\n";
   }
-  OS << "  }\n";
 
-  // Special cases
-  OS << R"(
-  if (Ty.VectorWidth > 0)
-    RT = Context.getExtVectorType(RT, Ty.VectorWidth);
+  // End of switch statement.
+  OS << "  } // end of switch (Ty.ID)\n\n";
 
-  if (Ty.isPointer) {
-    RT = Context.getAddrSpaceQualType(RT, Ty.AS);
-    RT = Context.getPointerType(RT);
+  // Step 2.
+  // Add ExtVector types if this was a generic type, as the switch statement
+  // above only populated the list with scalar types.  This completes the
+  // construction of the Cartesian product of (vector sizes) x (types).
+  OS << "  // Construct the different vector types for each generic type.\n";
+  OS << "  if (Ty.ID >= " << TypeList.size() << ") {";
+  OS << R"(
+    for (unsigned I = 0; I < QT.size(); I++) {
+      // For scalars, size is 1.
+      if ((*GenVectorSizes)[I / GenTypeNumTypes] != 1) {
+        QT[I] = Context.getExtVectorType(QT[I],
+                          (*GenVectorSizes)[I / GenTypeNumTypes]);
+      }
+    }
   }
+)";
 
-  return RT;
-}
+  // Assign the right attributes to the types (e.g. vector size).
+  OS << R"(
+  // Set vector size for non-generic vector types.
+  if (Ty.VectorWidth > 1) {
+    for (unsigned Index = 0; Index < QT.size(); Index++) {
+      QT[Index] = Context.getExtVectorType(QT[Index], Ty.VectorWidth);
+    }
+  }
 )";
+
+  // End of the "OCL2Qual" function.
+  OS << "\n} // OCL2Qual\n";
 }
 
 namespace clang {




More information about the cfe-commits mailing list