Pierre updated this revision to Diff 196591.
Pierre marked 10 inline comments as done.
Pierre added a comment.

In this new patch:

- Documentation has been added
- The multiclasses in OpenCLBuiltins.td filehave been slighly changed to have a 
more generic way to generate function prototypes
- In ClangOpenCLBuiltinEmitter.cpp, the code of the Emit() function has been 
shifted to functions
- In SemaLookUp.cpp, the OCL2Qual function, used to retrieve the QualType 
instance of a type, is now generated by Tablegen backend


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60763/new/

https://reviews.llvm.org/D60763

Files:
  clang/include/clang/Basic/CMakeLists.txt
  clang/include/clang/Basic/OpenCLBuiltins.td
  clang/lib/Sema/SemaLookup.cpp
  clang/test/SemaOpenCL/builtin-new.cl
  clang/utils/TableGen/CMakeLists.txt
  clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
  clang/utils/TableGen/TableGen.cpp
  clang/utils/TableGen/TableGenBackends.h

Index: clang/utils/TableGen/TableGenBackends.h
===================================================================
--- clang/utils/TableGen/TableGenBackends.h
+++ clang/utils/TableGen/TableGenBackends.h
@@ -80,6 +80,7 @@
 void EmitTestPragmaAttributeSupportedAttributes(llvm::RecordKeeper &Records,
                                                 llvm::raw_ostream &OS);
 
+void EmitClangOpenCLBuiltins(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
 } // end namespace clang
 
 #endif
Index: clang/utils/TableGen/TableGen.cpp
===================================================================
--- clang/utils/TableGen/TableGen.cpp
+++ clang/utils/TableGen/TableGen.cpp
@@ -61,7 +61,8 @@
   GenDiagDocs,
   GenOptDocs,
   GenDataCollectors,
-  GenTestPragmaAttributeSupportedAttributes
+  GenTestPragmaAttributeSupportedAttributes,
+  GenClangOpenCLBuiltins,
 };
 
 namespace {
@@ -163,7 +164,9 @@
         clEnumValN(GenTestPragmaAttributeSupportedAttributes,
                    "gen-clang-test-pragma-attribute-supported-attributes",
                    "Generate a list of attributes supported by #pragma clang "
-                   "attribute for testing purposes")));
+                   "attribute for testing purposes"),
+        clEnumValN(GenClangOpenCLBuiltins, "gen-clang-opencl-builtins",
+                   "Generate OpenCL builtin handlers")));
 
 cl::opt<std::string>
 ClangComponent("clang-component",
@@ -293,6 +296,9 @@
   case GenTestPragmaAttributeSupportedAttributes:
     EmitTestPragmaAttributeSupportedAttributes(Records, OS);
     break;
+  case GenClangOpenCLBuiltins:
+    EmitClangOpenCLBuiltins(Records, OS);
+    break;
   }
 
   return false;
Index: clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
===================================================================
--- /dev/null
+++ clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
@@ -0,0 +1,320 @@
+//===- ClangOpenCLBuiltinEmitter.cpp - Generate Clang OpenCL Builtin handling
+//=-*- C++ -*--=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits Clang OpenCL builtin functions checking code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <set>
+
+using namespace llvm;
+
+namespace {
+class BuiltinNameEmitter {
+public:
+  BuiltinNameEmitter(RecordKeeper &Records, raw_ostream &OS)
+      : Records(Records), OS(OS) {}
+
+  void Emit();
+
+private:
+  RecordKeeper &Records;
+  raw_ostream &OS;
+
+  void EmitDeclarations();
+  void GetOverloads();
+  void EmitSignatureTable();
+  void EmitBuiltinTable();
+  void EmitStringMatcher();
+  void EmitQualTypeFinder();
+
+  // Contains a list of the available signatures, regardless the name of the
+  // function. Each pair consists in a signature and a cumulative index.
+  // E.g.:  <<float, float>, 0>,
+  //        <<float, int, int, 2>>,
+  //        <<float>, 5>,
+  //        ...
+  //        <<double, double>, 35>.
+  std::vector<std::pair<std::vector<Record *>, unsigned>> SignatureSet;
+
+  // Map the name of a builtin function to its signatures.
+  // Each signature is registered as a pair of:
+  // <pointer to a list of types (a signature),
+  // cumulative index of the associated signature in the SignatureSet>
+  // E.g.:  The function cos: (float cos(float), double cos(double), ...)
+  //        <"cos", <<ptrToSignature5, 5>,
+  //                <ptrToSignature35, 35>>
+  //                <ptrToSignature79, 79>>
+  // ptrToSignature35 points here to the following list: <double, double>
+  MapVector<StringRef, std::vector<std::pair<const Record *, unsigned>>>
+        OverloadInfo;
+};
+} // namespace
+
+void BuiltinNameEmitter::Emit() {
+  // Generate the file containing OpenCL builtin functions checking code.
+
+  emitSourceFileHeader("OpenCL Builtin handling", OS);
+
+  OS << "#include \"llvm/ADT/StringRef.h\"\n\n";
+
+  EmitDeclarations();
+
+  GetOverloads();
+
+  EmitSignatureTable();
+
+  EmitBuiltinTable();
+
+  EmitStringMatcher();
+
+  EmitQualTypeFinder();
+}
+
+
+void BuiltinNameEmitter::EmitDeclarations() {
+  // Emit the enum/ struct used in the file generated
+
+  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));
+  }
+  OS << "};\n";
+
+  OS << R"(
+
+// Store information about a type used in a prototype of an OpenCL builtin
+// functions. With a table of this struct, a signature can be retrieved.
+struct OpenCLType {
+  // A type (e.g.: float, int, ...)
+  OpenCLTypeID ID;
+  // Size of the vector (if applicable)
+  unsigned VectorWidth;
+  // 0 if the type is not a pointer
+  unsigned isPointer;
+  // Address space of the pointer (if applicable)
+  clang::LangAS AS;
+};
+
+// Store 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;
+};
+
+)";
+}
+
+void BuiltinNameEmitter::GetOverloads() {
+  // Parse the Records generated by TableGen to feed the OverloadInfo and
+  // SignatureSet
+
+  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(
+          BName, std::vector<std::pair<const Record *, unsigned>>{}));
+    }
+
+    auto Signature = B->getValueAsListOfDefs("Signature");
+    auto it =
+        std::find_if(SignatureSet.begin(), SignatureSet.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));
+      SignIndex = CumulativeSignIndex;
+      CumulativeSignIndex += Signature.size();
+    } else {
+      SignIndex = it->second;
+    }
+    OverloadInfo[BName].push_back(std::make_pair(B, SignIndex));
+  }
+}
+
+
+void BuiltinNameEmitter::EmitSignatureTable() {
+  // Emit the OpenCLSignature table. This table contains all the possible
+  // signature, and is a struct OpenCLType. A signature is composed of a
+  // return type (mandatory), and arguments of the function.
+  // E.g.:
+  // // 12
+  // { OCLT_uchar, 4, 0, clang::LangAS::Default, },
+  // { OCLT_float, 4, 0, clang::LangAS::Default, },
+  // This means that at the index 12 in the table, is available the signature:
+  //    -returning a uchar vector of 4 elements.
+  //    -taking as first argument a float vector of 4 elements.
+
+  std::vector<std::vector<Record *>> Signature;
+
+  OS << "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->getValueAsInt("IsPointer") << ", " << R->getValueAsString("AddrSpace")
+         << ", "
+         << "}, ";
+      OS << "\n";
+    }
+  }
+  OS << "};\n\n";
+}
+
+
+
+void BuiltinNameEmitter::EmitBuiltinTable() {
+  // Emit the OpenCLBuiltins table. This table contains all the overloads of
+  // each function, and is a struct OpenCLBuiltinDecl.
+  // E.g.:
+  // // acos
+  //   { 1, 0, "", 100 },
+  // This means that the signature of acos, defined in OpenCL version 1.0 and
+  // not belonging to any extension, has a signature with 1 argument, stored at
+  // index 0 in the OpenCLSignature table.
+
+  OS << "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")
+         << " },\n";
+    }
+  }
+  OS << "};\n\n";
+}
+
+void BuiltinNameEmitter::EmitStringMatcher() {
+  // Construct a StringMatcher function to check whether a function is part of
+  // OpenCL builtin functions. The prototype of the function is:
+  // std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef name);
+  std::vector<StringMatcher::StringPair> validBuiltins;
+  unsigned CumulativeIndex = 1;
+  for (auto &i : OverloadInfo) {
+    auto &Ov = i.second;
+    std::string RetStmt;
+    raw_string_ostream SS(RetStmt);
+    SS << "return std::make_pair(" << CumulativeIndex << ", " << Ov.size()
+       << ");";
+    SS.flush();
+    CumulativeIndex += Ov.size();
+
+    validBuiltins.push_back(StringMatcher::StringPair(i.first, RetStmt));
+  }
+
+  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.
+std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef name) { ;
+
+)";
+
+  StringMatcher("name", validBuiltins, OS).Emit(0, true);
+
+  OS << "  return std::make_pair(0, 0);\n";
+  OS << "}\n";
+}
+
+void BuiltinNameEmitter::EmitQualTypeFinder() {
+  // Construct a function returning the clang QualType instance associated with
+  // the TableGen Record Type. The prototype of the function is:
+  // static QualType OCL2Qual(ASTContext &Context, OpenCLType Ty);
+  // TODO: Should not need clang::
+  OS << R"(
+
+static clang::QualType OCL2Qual(clang::ASTContext &Context, OpenCLType Ty) {
+  clang::QualType RT = Context.VoidTy;
+  switch (Ty.ID) {;
+
+)";
+
+  std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
+  StringMap<bool> TypesSeen;
+
+  for (const auto *T : Types) {
+    // Check we haven't seen this Type
+    if (TypesSeen.find(T->getValueAsString("Name")) != TypesSeen.end())
+      continue;
+    TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true));
+
+    // Check the Type doesn't have an "abstract" QualType
+    auto QT = T->getValueAsDef("QTName");
+    if (QT->getValueAsString("AccessMethod") == "null")
+      continue;
+
+    OS << "\t\tcase OCLT_" << T->getValueAsString("Name") << ":\n";
+    if (QT->getValueAsString("AccessMethod") == "field") {
+      OS << "\t\t\tRT = Context." << QT->getValueAsString("Name") << ";\n";
+    } else {
+      OS << "\t\t\tRT = Context." << QT->getValueAsString("Name") << "();\n";
+    }
+    OS << "\t\t\tbreak;\n";
+  }
+  OS << "\t}\n";
+
+  // Special cases
+  OS << R"(
+
+  if (Ty.VectorWidth > 0)
+    RT = Context.getExtVectorType(RT, Ty.VectorWidth);
+
+  if (Ty.isPointer != 0) {
+    RT = Context.getAddrSpaceQualType(RT, Ty.AS);
+    RT = Context.getPointerType(RT);
+  }
+
+  return RT;
+}
+
+)";
+}
+
+namespace clang {
+
+void EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) {
+  BuiltinNameEmitter NameChecker(Records, OS);
+  NameChecker.Emit();
+}
+
+} // end namespace clang
Index: clang/utils/TableGen/CMakeLists.txt
===================================================================
--- clang/utils/TableGen/CMakeLists.txt
+++ clang/utils/TableGen/CMakeLists.txt
@@ -8,6 +8,7 @@
   ClangCommentHTMLTagsEmitter.cpp
   ClangDataCollectorsEmitter.cpp
   ClangDiagnosticsEmitter.cpp
+  ClangOpenCLBuiltinEmitter.cpp
   ClangOptionDocEmitter.cpp
   ClangSACheckersEmitter.cpp
   NeonEmitter.cpp
Index: clang/test/SemaOpenCL/builtin-new.cl
===================================================================
--- /dev/null
+++ clang/test/SemaOpenCL/builtin-new.cl
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 %s -triple spir -verify -pedantic -fsyntax-only -cl-std=CL1.2 -DCL12
+// RUN: %clang_cc1 %s -triple spir -verify -pedantic -fsyntax-only -cl-std=CL2.0 -DCL20
+
+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 unsigned int uint;
+
+kernel void test(global float4* buf, global int4* res)
+{
+  res[0] = convert_int4(buf[0]);
+}
+
+kernel void test2(global int* bar) {
+  bar[0] = foo_version(bar);
+}
+
+kernel void test3(constant int* bar, global int* baz) {
+  baz[0] = foo_version(bar);
+#ifdef CL12
+// expected-error@-2{{passing '__constant int *' to parameter of type '__global int *' changes address space of pointer}}
+#endif
+}
+
+kernel void test4(image2d_t img, int2 coord, global float4* out) {
+  out[0] = read_imagef(img, coord);
+}
+
+kernel void test5(write_only image2d_t img, int2 coord, float4 colour) {
+  write_imagef(img, coord, colour);
+}
+
+#ifdef CL20
+kernel void test6(global uint* out) {
+  out[0] = get_sub_group_size();
+// expected-error@-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();
+}
+#endif
Index: clang/lib/Sema/SemaLookup.cpp
===================================================================
--- clang/lib/Sema/SemaLookup.cpp
+++ clang/lib/Sema/SemaLookup.cpp
@@ -46,6 +46,8 @@
 #include <utility>
 #include <vector>
 
+#include "clang/Basic/OpenCLBuiltins.inc"
+
 using namespace clang;
 using namespace sema;
 
@@ -670,6 +672,78 @@
     D->dump();
 }
 
+static void InsertOCLBuiltinDeclarations(Sema &S,
+                                         LookupResult &LR,
+                                         IdentifierInfo *II,
+                                         unsigned Index,
+                                         unsigned Len) {
+  // Once it is known the identifier is referencing an OpenCL builting function,
+  // add all its prototypes to the LookUpResult.
+
+  for (unsigned i = 0; i < Len; ++i) {
+    OpenCLBuiltinDecl &Decl = OpenCLBuiltins[Index - 1 + i];
+    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;
+
+    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);
+    }
+
+    QualType R = Context.getFunctionType(RT, ArgTypes, PI);
+    SourceLocation Loc = LR.getNameLoc();
+
+    // TODO: This part is taken from Sema::LazilyCreateBuiltin,
+    // maybe refactor it.
+    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);
+      }
+      New->setParams(Params);
+    }
+
+    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)
+    LR.resolveKind();
+}
+
 /// Lookup a builtin function, when name lookup would otherwise
 /// fail.
 static bool LookupBuiltin(Sema &S, LookupResult &R) {
@@ -692,6 +766,15 @@
         }
       }
 
+      // Check if this is an OpenCL Builtin, and if so, insert the declarations.
+      if (S.getLangOpts().OpenCL) {
+        auto Index = isOpenCLBuiltin(II->getName());
+        if (Index.first) {
+          InsertOCLBuiltinDeclarations(S, R, II, Index.first, Index.second);
+          return true;
+        }
+      }
+
       // If this is a builtin on this (or all) targets, create the decl.
       if (unsigned BuiltinID = II->getBuiltinID()) {
         // In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined
Index: clang/include/clang/Basic/OpenCLBuiltins.td
===================================================================
--- /dev/null
+++ clang/include/clang/Basic/OpenCLBuiltins.td
@@ -0,0 +1,342 @@
+//==--- OpenCLBuiltins.td - OpenCL builtin definitions --------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  The file is organized as:
+//    -Base definitions: base classes/ definitions required in sections below
+//    -Classes
+//    -Multiclasses
+//    -Definitions:
+//      *Type
+//        -6.1.1    : Built-in Scalar Data Types
+//        -6.1.2    : Built-in Vector Data Types
+//        -6.1.3    : Other Built-in Data Types
+//      *Builtin
+//        -6.2.3    : Explicit Conversions
+//        -6.12.1   : Work-Item Functions
+//        -6.12.2   : Math Functions
+//        -6.12.14  : Built-in Image Read Functions
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+//                            Base definitions
+//===----------------------------------------------------------------------===//
+// Versions of OpenCL
+class Version<int _Version> {
+  int Version = _Version;
+}
+def CL10: Version<100>;
+def CL11: Version<110>;
+def CL12: Version<120>;
+def CL20: Version<200>;
+
+// Address spaces. Pointer types need to be assigned an address space. It can be
+// one of:
+// 0 :: Default
+// 0 :: opencl_private
+// 1 :: opencl_global
+// 2 :: opencl_constant
+// 3 :: opencl_local
+// 4 :: opencl_generic
+// (Following address spaces are not available for OpenCL)
+// 5 :: cuda_device
+// 6 :: cuda_constant
+// 7 :: cuda_shared
+class AddressSpace<string _AS> {
+  string AddrSpace = _AS;
+}
+def default_as    : AddressSpace<"clang::LangAS::Default">;
+def private_as    : AddressSpace<"clang::LangAS::opencl_private">;
+def global_as     : AddressSpace<"clang::LangAS::opencl_global">;
+def constant_as   : AddressSpace<"clang::LangAS::opencl_constant">;
+def local_as      : AddressSpace<"clang::LangAS::opencl_local">;
+def generic_as    : AddressSpace<"clang::LangAS::opencl_generic">;
+
+
+// Qualified Type. Allow to retrieve one ASTContext Qualtype.
+class QualType<string _AccessMethod,string _Name> {
+  // How to get the QualType. Can be one of ("field", "func")
+  string AccessMethod = _AccessMethod;
+  // Name of the field / function
+  string Name = _Name;
+}
+
+// Helper class to store type  access qualifiers (volatile, const, ...)
+class Qualifier<string _QualName> {
+  string QualName = _QualName;
+}
+
+//===----------------------------------------------------------------------===//
+//                            Classes
+//===----------------------------------------------------------------------===//
+// OpenCL types (int, float, ...)
+class Type<string _Name, QualType _QTName> {
+  // Name of the Type
+  string Name = _Name;
+  // QualType associated with this type
+  QualType QTName = _QTName;
+  // Size of the vector (if applicable)
+  int VecWidth = 0;
+  // Is pointer
+  int IsPointer = 0;
+  // List of qualifiers associated with the type (volatile, ...)
+  list<Qualifier> QualList = [];
+  // Address space associated
+  string AddrSpace = "clang::LangAS::Default";
+  // Functions returning a floating point number can be postfixed with the
+  // rounding method used (_rte, _rtp, _rtn, _rtz) to round the result.
+  int HasRounding = 0;
+  // Functions returning an integer type number (char, int, long, ...) can be
+  // postfixed with _sat to saturate the result.
+  int HasSat = 0;
+  // Function arguments can have ab access qualifiers (read_only, ...). Can be
+  // one of ("RO", "WO", "RW")
+  string AccessQualifier = "";
+}
+
+// OpenCL vector types (int2, int3, int16, float8, ...)
+class VectorType<Type _Ty, int _VecWidth> : Type<_Ty.Name, _Ty.QTName> {
+  int VecWidth = _VecWidth;
+}
+
+// OpenCL pointer types (int*, float*, ...)
+class PointerType<Type _Ty, AddressSpace _AS = global_as> :
+                                      Type<_Ty.Name, _Ty.QTName> {
+  int IsPointer = 1;
+  string AddrSpace = _AS.AddrSpace;
+}
+
+// OpenCL image types (image2d_t, ...)
+class ImageType<Type _Ty, QualType _QTName, string _AccessQualifier> :
+                                              Type<_Ty.Name, _QTName> {
+  let AccessQualifier = _AccessQualifier;
+}
+
+// OpenCL builtin functions (sin, cos, convert_char. ...)
+class Builtin<string _Name, list<Type> _Signature> {
+  // Name of the builtin function
+  string Name = _Name;
+  // List of types used by the function. The first one is the return type and
+  // the following are the arguments. The list must have at least one elements
+  // (the return type).
+  list<Type> Signature = _Signature;
+  // Extension of OpenCL to which the function belongs (cl_khr_subgroups, ...)
+  string Extension = "";
+  // Version of OpenCL to which the function belongs (CL10, ...)
+  Version Version = CL10;
+}
+
+// Helper classes for the convert_* BIFs.
+class SatModes<Type _Ty> {
+  list<string> Modes = !if(_Ty.HasSat, ["", "_sat"], [""]);
+}
+class RoundingModes<Type _Ty1, Type _Ty2> {
+  list<string> Modes = !if(!or(_Ty1.HasRounding, _Ty2.HasRounding),
+                          ["", "_rte", "_rtz", "_rtp", "_rtn"],
+                          [""]);
+}
+
+//===----------------------------------------------------------------------===//
+//                            Multiclass definitions
+//===----------------------------------------------------------------------===//
+// multiclass BifX: Creates builtins class instances for OpenCL builtin
+//                  functions with X arguments.
+// _Name      :: Name of the FunctionNoProto
+// _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
+//===----------------------------------------------------------------------===//
+// ========== Type definitions ==========
+// Types available in OpenCL
+
+// 6.1.1 : Built-in Scalar Data Types
+def bool_t        : Type<"bool", QualType<"field", "BoolTy">>;
+let HasSat = 1 in {
+  def char_t    : Type<"char", QualType<"field", "CharTy">>;
+  def uchar_t   : Type<"uchar", QualType<"field", "UnsignedCharTy">>;
+  def short_t   : Type<"short", QualType<"field", "ShortTy">>;
+  def ushort_t  : Type<"ushort", QualType<"field", "UnsignedShortTy">>;
+  def int_t     : Type<"int", QualType<"field", "IntTy">>;
+  def uint_t    : Type<"uint", QualType<"field", "UnsignedIntTy">>;
+  def long_t    : Type<"long", QualType<"field", "LongTy">>;
+  def ulong_t   : Type<"ulong", QualType<"field", "UnsignedLongTy">>;
+}
+let HasRounding = 1 in {
+  def float_t   : Type<"float", QualType<"field", "FloatTy">>;
+  def double_t  : Type<"double", QualType<"field", "DoubleTy">>;
+  def half_t    : Type<"half", QualType<"field", "HalfTy">>;
+}
+def size_t        : Type<"size_t",  QualType<"func", "getSizeType">>;
+def ptrdiff_t     : Type<"ptrdiff_t", QualType<"func", "getPointerDiffType">>;
+def intptr_t      : Type<"intptr_t", QualType<"func", "getIntPtrType">>;
+def uintptr_t     : Type<"uintptr_t", QualType<"func", "getUIntPtrType">>;
+def void_t        : Type<"void", QualType<"field", "VoidTy">>;
+
+// 6.1.2 : Built-in Vector Data Types
+// TODO: Can maybe be generated from the original definition in the .def file
+foreach v = [2, 3, 4, 8, 16] in {
+  def char#v#_t    : VectorType<char_t, v>;
+  def uchar#v#_t   : VectorType<uchar_t, v>;
+  def short#v#_t   : VectorType<short_t, v>;
+  def ushort#v#_t  : VectorType<ushort_t, v>;
+  def "int"#v#_t   : VectorType<int_t, v>;
+  def uint#v#_t    : VectorType<uint_t, v>;
+  def long#v#_t    : VectorType<long_t, v>;
+  def ulong#v#_t   : VectorType<ulong_t, v>;
+  let HasRounding = 1 in {
+    def float#v#_t   : VectorType<float_t, v>;
+    def double#v#_t  : VectorType<double_t, v>;
+    def half#v#_t    : VectorType<half_t, v>;   // TODO halfx is not part of the OpenCL1.2 spec
+  }
+}
+
+// 6.1.3 : Other Built-in Data Types
+// These first definition without a real QualType are "abstract".
+def image2d_t         : Type<"image2d_t", QualType<"null", "null""Ty">>;
+def image3d_t         : Type<"image3d_t", QualType<"null", "null""Ty">>;
+def image2d_array_t   : Type<"image2d_array_t", QualType<"null", "null">>;
+def image1d_t         : Type<"image1d_t", QualType<"null", "null">>;
+def image1d_buffer_t  : Type<"image1d_buffer_t", QualType<"null", "null">>;
+def image1d_array_t   : Type<"image1d_array_t", QualType<"null", "null">>;
+// These definitions are used: the QualType is defined.
+foreach v = ["RO", "WO", "RW"] in {
+    def image2d_#v#_t       : ImageType<image2d_t, QualType<"field",
+                                                    "OCLImage2d"#v#"Ty">,
+                                                    v>;
+    def image3d_#v#_t       : ImageType<image3d_t, QualType<"field",
+                                                    "OCLImage3d"#v#"Ty">,
+                                                    v>;
+    def image2d_array#v#_t  : ImageType<image2d_array_t, QualType<"field",
+                                                    "OCLImage2dArray"#v#"Ty">,
+                                                    v>;
+    def image1d_#v#_t       : ImageType<image1d_t, QualType<"field",
+                                                    "OCLImage1d"#v#"Ty">,
+                                                    v>;
+    def image1d_buffer#v#_t : ImageType<image1d_buffer_t, QualType<"field",
+                                                    "OCLImage1dBuffer"#v#"Ty">,
+                                                    v>;
+    def image1d_array#v#_t  : ImageType<image1d_array_t, QualType<"field",
+                                                    "OCLImage1dArray"#v#"Ty">,
+                                                    v>;
+}
+
+def sampler_t         : Type<"sampler_t", QualType<"field", "OCLSamplerTy">>;
+def event_t           : Type<"event_t", QualType<"field", "OCLEventTy">>;
+
+// ========== Builtin definitions ==========
+// This section defines builtin functions found in the OpenCL 1.2 specification
+
+// 6.2.3 : Explicit Conversions
+// Generate the convert_ builtins.
+foreach RType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t,
+                int_t, uint_t, long_t, ulong_t] in {
+  foreach IType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t,
+                   int_t, uint_t, long_t, ulong_t] in {
+    foreach sat = SatModes<RType>.Modes in {
+      foreach rte = RoundingModes<RType, IType>.Modes in {
+        def : Builtin<"convert_"  # RType.Name # sat # rte,
+                                            [RType, IType]>;
+        foreach v = [2, 3, 4, 8, 16] in {
+          def : Builtin<"convert_" # RType.Name # v # sat # rte,
+                                                            [VectorType<RType, v>,
+                                                              VectorType<IType,
+                                                              v>]>;
+        }
+      }
+    }
+  }
+}
+// 6.12.1 : Work-Item Functions
+def get_work_dim : Builtin<"get_work_dim", [uint_t]>;
+foreach name = ["get_global_size", "get_global_id", "get_local_size",
+                "get_local_id", "get_num_groups", "get_group_id",
+                "get_global_offset"] in {
+  def : Builtin<name, [size_t, uint_t]>;
+}
+
+// 6.12.2 : Math Functions
+foreach name = ["acos", "acosh", "acospi",
+                "asin", "asinh", "asinpi",
+                "atan", "atanh", "atanpi"] in {
+  foreach type = [float_t, double_t, half_t] in {  // TODO halfx is not part of the OpenCL1.2 spec
+    defm : Bif1<name, [type, type], [1, 1]>;
+  }
+}
+
+foreach name = ["atan2", "atan2pi"] in {
+  foreach type = [float_t, double_t, half_t] in {  // TODO halfx is not part of the OpenCL1.2 spec
+    defm : Bif2<name, [type, type, type], [1, 1, 1]>;
+  }
+}
+
+foreach name = ["fmax", "fmin"] in {
+  foreach type = [float_t, double_t, half_t] in {  // TODO halfx is not part of the OpenCL1.2 spec
+    defm : Bif2<name, [type, type, type], [1, 1, 1]>;
+    defm : Bif2<name, [type, type, type], [1, 1, 0]>;
+  }
+}
+
+
+// example 'foo', to show using 'version'
+def : Builtin<"foo_version", [int_t, PointerType<int_t, global_as>]>;
+let Version = CL20 in {
+  def : Builtin<"foo_version", [int_t, PointerType<int_t, constant_as>]>;
+}
+
+// Example showing 'Extension'
+let Extension = "cl_khr_subgroups" in {
+  def get_sub_group_size : Builtin<"get_sub_group_size", [uint_t]>;
+}
+// 6.12.14 : Built-in Image Read Functions
+def read_imagef : Builtin<"read_imagef",
+                          [float4_t, image2d_RO_t, VectorType<int_t, 2>]>;
+def write_imagef : Builtin<"write_imagef",
+                            [void_t,
+                              image2d_WO_t,
+                              VectorType<int_t, 2>,
+                              VectorType<float_t, 4>]>;
Index: clang/include/clang/Basic/CMakeLists.txt
===================================================================
--- clang/include/clang/Basic/CMakeLists.txt
+++ clang/include/clang/Basic/CMakeLists.txt
@@ -41,6 +41,12 @@
   TARGET ClangAttrHasAttributeImpl
   )
 
+clang_tablegen(OpenCLBuiltins.inc
+  -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ -gen-clang-opencl-builtins
+  SOURCE OpenCLBuiltins.td
+  TARGET ClangOpenCLBuiltinsImpl
+  )
+
 # ARM NEON
 clang_tablegen(arm_neon.inc -gen-arm-neon-sema
   SOURCE arm_neon.td
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to