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 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 = _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 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 { + // 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 = _QualName; +} + +//===----------------------------------------------------------------------===// +// Classes +//===----------------------------------------------------------------------===// +// OpenCL types (int, float, ...) +class Type { + // 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 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.Name, _Ty.QTName> { + int VecWidth = _VecWidth; +} + +// OpenCL pointer types (int*, float*, ...) +class PointerType : + Type<_Ty.Name, _Ty.QTName> { + int IsPointer = 1; + string AddrSpace = _AS.AddrSpace; +} + +// OpenCL image types (image2d_t, ...) +class ImageType : + Type<_Ty.Name, _QTName> { + let AccessQualifier = _AccessQualifier; +} + +// OpenCL builtin functions (sin, cos, convert_char. ...) +class Builtin _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 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 { + list Modes = !if(_Ty.HasSat, ["", "_sat"], [""]); +} +class RoundingModes { + list 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 _Signature, list _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 _Signature, list _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 _Signature, list _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 _Signature, list _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; + def uchar#v#_t : VectorType; + def short#v#_t : VectorType; + def ushort#v#_t : VectorType; + def "int"#v#_t : VectorType; + def uint#v#_t : VectorType; + def long#v#_t : VectorType; + def ulong#v#_t : VectorType; + let HasRounding = 1 in { + def float#v#_t : VectorType; + def double#v#_t : VectorType; + def half#v#_t : VectorType; // 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, + v>; + def image3d_#v#_t : ImageType, + v>; + def image2d_array#v#_t : ImageType, + v>; + def image1d_#v#_t : ImageType, + v>; + def image1d_buffer#v#_t : ImageType, + v>; + def image1d_array#v#_t : ImageType, + 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.Modes in { + foreach rte = RoundingModes.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, + VectorType]>; + } + } + } + } +} +// 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; +} + +// 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; + } +} + +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; + } +} + +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; + defm : Bif2; + } +} + + +// example 'foo', to show using 'version' +def : Builtin<"foo_version", [int_t, PointerType]>; +let Version = CL20 in { + def : Builtin<"foo_version", [int_t, PointerType]>; +} + +// 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]>; +def write_imagef : Builtin<"write_imagef", + [void_t, + image2d_WO_t, + VectorType, + VectorType]>; Index: clang/lib/Sema/SemaLookup.cpp =================================================================== --- clang/lib/Sema/SemaLookup.cpp +++ clang/lib/Sema/SemaLookup.cpp @@ -46,6 +46,8 @@ #include #include +#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 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(R)) { + SmallVector 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/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/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/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 + +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.: <, 0>, + // <>, + // <, 5>, + // ... + // <, 35>. + std::vector, unsigned>> SignatureSet; + + // Map the name of a builtin function to its signatures. + // Each signature is registered as a pair of: + // + // E.g.: The function cos: (float cos(float), double cos(double), ...) + // <"cos", <, + // > + // > + // ptrToSignature35 points here to the following list: + MapVector>> + 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 Types = Records.getAllDerivedDefinitions("Type"); + StringMap 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 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>{})); + } + + auto Signature = B->getValueAsListOfDefs("Signature"); + auto it = + std::find_if(SignatureSet.begin(), SignatureSet.end(), + [&](const std::pair, 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> 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 isOpenCLBuiltin(llvm::StringRef name); + std::vector 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 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 Types = Records.getAllDerivedDefinitions("Type"); + StringMap 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/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 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/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