Index: clang/lib/Sema/OpenCLBuiltins.td =================================================================== --- clang/lib/Sema/OpenCLBuiltins.td +++ clang/lib/Sema/OpenCLBuiltins.td @@ -9,7 +9,7 @@ //===----------------------------------------------------------------------===// // // This file contains TableGen definitions for OpenCL builtin function -// declarations. In case of an unresolved function name in OpenCL, Clang will +// declarations. In case of an unresolved function name in OpenCL, Clang will // check for a function described in this file when -fdeclare-opencl-builtins // is specified. // @@ -40,22 +40,31 @@ def generic_as : AddressSpace<"clang::LangAS::opencl_generic">; -// Qualified Type. Allow to retrieve one ASTContext QualType. -class QualType { +// Qualified Type. Allow to retrieve an ASTContext QualType. +class QualType { // 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 QualType should not be used as such. This is a mean to identify them. + bit IsAbstract = _IsAbstract; } -// Helper class to store type access qualifiers (volatile, const, ...). -class Qualifier { - string QualName = _QualName; + +// Store a list of integer. +class IntList _List> { + string Name = _Name; + list List = _List; } //===----------------------------------------------------------------------===// // OpenCL C classes for types //===----------------------------------------------------------------------===// -// OpenCL types (int, float, ...) +// OpenCL C types (int, float, ...). +// Its Child classes represent concrete types. +// I.e.: VectorType, PointerType, ImageType and GenericType. +// Instances of these child classes should be declared right in Builtin +// function arguments. +// See the definition of the "read_imagef" function as example. class Type { // Name of the Type string Name = _Name; @@ -65,12 +74,10 @@ int VecWidth = 0; // Is pointer bit IsPointer = 0; - // List of qualifiers associated with the type (volatile, ...) - list QualList = []; - // Address space - string AddrSpace = "clang::LangAS::Default"; // Access qualifier. Must be one of ("RO", "WO", "RW"). string AccessQualifier = ""; + // Address space associated. + string AddrSpace = "clang::LangAS::Default"; } // OpenCL vector types (e.g. int2, int3, int16, float8, ...) @@ -91,6 +98,29 @@ let AccessQualifier = _AccessQualifier; } +// Store a list of Types. +class TypeList _Type> { + string Name = _Name; + list List = _Type; +} + +// A GenericType is an abstract type that defines a set of types as a +// combination of types and vector sizes both defined in list components of +// GenericType. +// E.g.: If TypeListField = and VectorList = <0, 2, 4>, then +// then gentype will represent +// _Ty : Name of the GenType +// _TypeList : Types this GenericType can be +// _VectorList : Sizes of the vector for each type of the _TypeList. 0 being a +// scalar. +class GenericType : + Type<_Ty, QualType<"null", 1>> { + // Possible types of the generic type. + TypeList TypeListField = _TypeList; + // Possible vector sizes of the types in the TypeListField. + IntList VectorList = _VectorList; +} + //===----------------------------------------------------------------------===// // OpenCL C class for builtin functions //===----------------------------------------------------------------------===// @@ -107,55 +137,11 @@ Version Version = CL10; } -//===----------------------------------------------------------------------===// -// 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 _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 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_t : Type<"bool", QualType<"BoolTy">>; def char_t : Type<"char", QualType<"CharTy">>; def uchar_t : Type<"uchar", QualType<"UnsignedCharTy">>; @@ -174,30 +160,20 @@ def uintptr_t : Type<"uintptr_t", QualType<"getUIntPtrType()">>; def void_t : Type<"void", 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; - 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; - def float#v#_t : VectorType; - def double#v#_t : VectorType; - def half#v#_t : VectorType; -} +// OpenCL v1.0/1.2/2.0/2.0 s6.1.2: Built-in Vector Data Types. +// VectorTypes are dynamically defined. See the OpenCL 2.0 : 6.13.7 section of +// this file as example. + // 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 { @@ -224,28 +200,56 @@ def sampler_t : Type<"sampler_t", QualType<"OCLSamplerTy">>; def event_t : Type<"event_t", QualType<"OCLEventTy">>; +// Generic types and lists of int. +// Lists of int. +def ListNNonZero : IntList<"ListNNonZero", [2, 3, 4, 8, 16]>; +def ListN : IntList<"ListN", [0, 2, 3, 4, 8, 16]>; + +// Generate basic GenTypes. Names are like: genType_char_zeroList. +foreach Type = [char_t, uchar_t, short_t, ushort_t, + int_t, uint_t, long_t, ulong_t, + float_t, double_t, half_t] in { + foreach List = [ListN, ListNNonZero] in { + def "genType_"#Type.Name#_#List : + GenericType<"genType_"#Type.Name#_#List, + TypeList<"GL"#Type.Name, [Type]>, + List>; + } +} + +// GenType lists definitions. +def GLFoatTypes : TypeList<"FoatTypes", [float_t, double_t, half_t]>; + +// GenType definitions. +def FGenTypeN : GenericType<"FGenTypeN", GLFoatTypes, ListN>; + //===----------------------------------------------------------------------===// // Definitions of OpenCL builtin functions //===----------------------------------------------------------------------===// -// OpenCL v1.2 s6.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 { +//-------------------------------------------------------------------- +// OpenCL v1.1/1.2/2.0 s6.2.3 - Explicit conversions. +// OpenCL v2.0 Extensions s5.1.1 and s6.1.1 - Conversions. + +// Generate the convert_* builtins functions. +foreach RType = [float_t, double_t, half_t, char_t, uchar_t, short_t, + ushort_t, int_t, uint_t, long_t, ulong_t] in { + foreach IType = [float_t, double_t, half_t, char_t, uchar_t, short_t, + ushort_t, int_t, uint_t, long_t, ulong_t] in { foreach sat = ["", "_sat"] in { - foreach rte = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { - def : Builtin<"convert_" # RType.Name # sat # rte, [RType, IType]>; + foreach rnd = ["", "_rte", "_rtn", "_rtp", "_rtz"] in { + def : Builtin<"convert_"#RType.Name#sat#rnd, [RType, IType]>; foreach v = [2, 3, 4, 8, 16] in { - def : Builtin<"convert_" # RType.Name # v # sat # rte, + def : Builtin<"convert_"#RType.Name#v#sat#rnd, [VectorType, - VectorType]>; + VectorType]>; } } } } } + // OpenCL v1.2 s6.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", @@ -258,27 +262,23 @@ foreach name = ["acos", "acosh", "acospi", "asin", "asinh", "asinpi", "atan", "atanh", "atanpi"] in { - foreach type = [float_t, double_t, half_t] in { - defm : Bif1; - } + def : Builtin; } foreach name = ["atan2", "atan2pi"] in { - foreach type = [float_t, double_t, half_t] in { - defm : Bif2; - } + def : Builtin; } foreach name = ["fmax", "fmin"] in { - foreach type = [float_t, double_t, half_t] in { - defm : Bif2; - defm : Bif2; - } + def : Builtin; + def : Builtin; + def : Builtin; + def : Builtin; } // OpenCL v1.2 s6.12.14: Built-in Image Read Functions def read_imagef : Builtin<"read_imagef", - [float4_t, image2d_RO_t, VectorType]>; + [VectorType, image2d_RO_t, VectorType]>; def write_imagef : Builtin<"write_imagef", [void_t, image2d_WO_t, Index: clang/lib/Sema/SemaLookup.cpp =================================================================== --- clang/lib/Sema/SemaLookup.cpp +++ clang/lib/Sema/SemaLookup.cpp @@ -672,76 +672,181 @@ D->dump(); } +/// Helper function to get the QualType instances of the return type and +/// arguments of a function. +/// \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 meaningfull for generic types, otherwise equals 1. +/// +/// \param RetTypes (out) List of the possible return types. +/// +/// \param ArgTypes (out) List of the possible types for the arguments. +static void GetQualTypesForOpenCLBuiltin( + ASTContext &Context, + const OpenCLBuiltinStruct &OpenCLBuiltin, + unsigned &GenTypeMaxCnt, + std::vector &RetTypes, + SmallVector, 5> &ArgTypes) { + // Get the QualType instances of the return types. + RetTypes = OCL2Qual( + Context, + TypeTable[SignatureTable[OpenCLBuiltin.SignTableIndex].TypeTableIndex]); + 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 Ty = OCL2Qual( + Context, + TypeTable[SignatureTable[OpenCLBuiltin.SignTableIndex + Index].TypeTableIndex]); + ArgTypes.push_back(Ty); + GenTypeMaxCnt = (Ty.size() > GenTypeMaxCnt) ? Ty.size() : GenTypeMaxCnt; + } + + // Check that that lengths of the gentypes are compatibles. + if ((GenTypeMaxCnt % RetTypes.size()) != 0) { + goto error_handler; + } + for (unsigned Index = 0; Index < ArgTypes.size(); Index++) { + unsigned TypeCntAtIndex = ArgTypes[Index].size(); + if ((GenTypeMaxCnt % TypeCntAtIndex) != 0) { + goto error_handler; + } + } + + return; + +error_handler: + llvm_unreachable("Lengths of genTypes used are incompatible in the "\ + "definition of the builtin function"); +} + +/// Helper function to create a list of the possible signatures for the +/// function. +/// \param Context (in) The Context instance. +/// +/// \param GenTypeMaxCnt (out)Maximum number of types contained in a generic +/// type used as return type or as argument. +/// Only meaningfull for generic types, otherwise equals 1. +/// +/// \param FunctionList (out) List of the function declarations. +/// +/// \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 &FunctionList, + std::vector &RetTypes, + SmallVector, 5> &ArgTypes) { + FunctionProtoType::ExtProtoInfo PI; + PI.Variadic = false; + + for (unsigned IGenType = 0; IGenType < GenTypeMaxCnt; IGenType++) { + SmallVector ArgList; + + for (unsigned I = 0; I < ArgTypes.size(); I++) { + ArgList.push_back(ArgTypes[I][IGenType%ArgTypes[I].size()]); + } + + FunctionList.push_back( + Context.getFunctionType( + RetTypes[(RetTypes.size() != 1) ? IGenType : 0], + ArgList, PI)); + } +} + /// When trying to resolve a function name, if the isOpenCLBuiltin function -/// defined in "OpenCLBuiltins.inc" returns a non-null , then the -/// identifier is referencing an OpenCL builtin function. Thus, all its -/// prototypes are added to the LookUpResult. +/// defined in "OpenCLBuiltins.inc" returns a non-null pair, then +/// the name is referencing an OpenCL builtin function. Thus, all its +/// signatures are added to the LookUpResult. +/// +/// \param S The sema instance. /// -/// \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) { - - for (unsigned i = 0; i < Len; ++i) { - OpenCLBuiltinDecl &Decl = OpenCLBuiltins[Index - 1 + i]; +/// \param LR The lookupResult instance. +/// +/// \param II The identifier being resolved. +/// +/// \param FctIndex The list of signatures is starting at this index in the +/// OpenCLBuiltins table. +/// +/// \param Len The list of signatures has Len elements. +static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, + LookupResult &LR, + IdentifierInfo *II, + const unsigned FctIndex, + const unsigned Len) { + // "Generic types" (gentypes) are abstract types regrouping a set of types. + // It allows factoring types when declaring OpenCL builtin function overloads. + // E.G.: The following gentype abstacts vectors of the float type. + // genFloatN = {float, float2, float3, float4, float8, float16} + + // Maximum number of types contained in a generic type used as return type or + // as argument. + // Only meaningfull for generic types, otherwise equals 1. + unsigned GenTypeMaxCnt; + // The function has been declared using generic types. + bool HasGenType = false; + + 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; + std::vector RetTypes; + SmallVector, 5> ArgTypes; - FunctionProtoType::ExtProtoInfo PI; - PI.Variadic = false; + GetQualTypesForOpenCLBuiltin(Context, OpenCLBuiltin, GenTypeMaxCnt, + RetTypes, ArgTypes); - // Defined in "OpenCLBuiltins.inc" - 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); + 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 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(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); + 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(FunctionList[Index])) { + SmallVector 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); + 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(); } @@ -771,7 +876,9 @@ 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; } } Index: clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl =================================================================== --- clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl +++ clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl @@ -1,19 +1,32 @@ // 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 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) { @@ -22,7 +35,4 @@ kernel void basic_subgroup(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(); } Index: clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp =================================================================== --- clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp +++ clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp @@ -22,6 +22,59 @@ // referenced by other functions, i.e. "sin", since multiple OpenCL builtins // share the same signature. //===----------------------------------------------------------------------===// +// +// The code generated in "OpenCLBuiltins.inc" has the following structure: +// enum OpenCLTypeID { +// OCLT_double, +// Other types ... +// }; +// +// struct OpenCLTypeStruct { +// Hold information about types (vector size, ...) +// }; +// +// struct OpenCLSignatureStruct { +// Hold indexes of a struct OpenCLTypeStruct table. A list of indexes +// is used to represent a function signature. +// ); +// +// struct OpenCLBuiltinStruct { +// Hold information about builtin functions, where to find the return type and +// types of the arguments. +// }; +// +// static const OpenCLTypeStruct TypeTable[] = { +// {OCLT_double, 2}, // This represents the double2 type. +// Other types with their vector size. +// }; +// +// static const OpenCLSignatureStruct SignatureTable[] = { +// 0, 2, 15, // This is a signature +// Other indexes of a struct OpenCLTypeStruct table, allowing to build a +// signature. +// }; +// +// static const OpenCLBuiltinStruct BuiltinTable[] = { +// // 957 convert_float2_rtn +// { 58, 2 }, // The "convert_float2_rtn" function has one signature at the +// // index 58 of the SignatureTable, and it uses the 2 values +// // after this index. +// { 202, 2 }, +// { 346, 2 }, +// { 490, 2 }, +// Other functions +// }; +// +// static std::pair isOpenCLBuiltin(llvm::StringRef name) { +// Find out whether a string matches an existing OpenCL builtin function name. +// }; +// +// static std::vector +// OCL2Qual(ASTContext &Context, OpenCLTypeStruct Ty) { +// Convert OpenCLTypeStruct types to llvm CanQualType instances. +// }; +// +//===----------------------------------------------------------------------===// #include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" @@ -57,23 +110,47 @@ // The output file. raw_ostream &OS; - // Emit the enums and structs. + + // Helper function for BuiltinNameEmitter::EmitDeclarations. It generates enum + // definitions in the Output string parameter, and save their Record instance + // in the List parameter. + // \param Types (in) List containing the Types to extract. + // + // \param TypesSeen (out) List containing the Types already extracted. + // + // \param Output (out) String containing the enums to emit in the output file. + // + // \param List (out) List to fill with the extracted types. + void EmitTypesEnum(std::vector &Types, + StringMap &TypesSeen, + std::string &Output, + std::vector &List); + + // Emit the enum or struct used in the file generated + // 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. This table contains all the possible types. A type can + // have several attributes (e.g. the size of the vector (if applicable), + // if this is a pointer type, a const type, ...). // 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. + // { OCLT_char, 3, 0, 0, 0, 0, clang::LangAS::Default}, + // is describing the type "char", being a vector of 3 elements. See the + // struct OpenCLTypeStruct for more information. + 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, 15, 12 can represent a function with the signature: + // int func(float, int) + // The "int" type being at the index 12 in the TypeTable. void EmitSignatureTable(); // Emit the OpenCLBuiltins table. This table contains all overloads of @@ -81,10 +158,8 @@ // 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. + // This means that the signature of this acos overload has 1 argument (+1 for + // the return type), stored at index 0 in the OpenCLSignature table. void EmitBuiltinTable(); // Emit a StringMatcher function to check whether a function name is an @@ -102,20 +177,39 @@ // <, 5>, // ... // <, 35>. - std::vector, unsigned>> SignatureSet; + std::vector, 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: // + // cumulative index of the associated signature in the SignaturesList> // E.g.: The function cos: (float cos(float), double cos(double), ...) // <"cos", <, // > // > // ptrToPrototype1 has the following signature: MapVector>> - OverloadInfo; + FctOverloadMap; + + // Contains the map of the possible OpenCL types to their index in the + // TypeTable. + // E.g.: <, 0>, + // , 1>, + // , 2>, + // ...> + MapVector TypeMap; + + // List of the possible OpenCL type names in the same order as in their + // enum OpenCLTypeID. This list doesn't contain generic types. + // Generic types are not part of this list. + // E.g.: , + // , + // ...> + std::vector TypeList; + + // Same as TypeList, but for generic types only. + std::vector GenTypeList; }; } // namespace @@ -129,6 +223,8 @@ GetOverloads(); + // Emit data strucures. + EmitTypeTable(); EmitSignatureTable(); EmitBuiltinTable(); @@ -138,109 +234,178 @@ EmitQualTypeFinder(); } + +void BuiltinNameEmitter::EmitTypesEnum(std::vector &Types, + StringMap &TypesSeen, + std::string &Output, + std::vector &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 the possible type names (float, int, ...). + // Associated vector types (int2, int3, ...) are not considered. 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"; + std::string GenTypeEnums; + std::string TypeEnums; + + // Generic types need to be last in the enum definition, but parsed first. + std::vector GenTypes = + Records.getAllDerivedDefinitions("GenericType"); + EmitTypesEnum(GenTypes, + TypesSeen, + GenTypeEnums, + GenTypeList); + std::vector Types = Records.getAllDerivedDefinitions("Type"); + EmitTypesEnum(Types, + TypesSeen, + TypeEnums, + TypeList); + + OS << TypeEnums; + OS << GenTypeEnums; + OS << "};\n\n"; + + // Strucure definitions. OS << R"( -// Type used in a prototype of an OpenCL builtin function. -struct OpenCLType { +// Store information about types. A function signature reference entries in a +// table of this strucure. +struct OpenCLTypeStruct { // A type (e.g.: float, int, ...) OpenCLTypeID ID; - // Size of vector (if applicable) + // Size of the vector (if applicable, 0 otherwise and for generic types). unsigned VectorWidth; - // Address space of the pointer (if applicable) - LangAS AS; - // Whether the type is a pointer - bool isPointer; }; -// 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; +// Store a type (i.e. int, float, int2, ...). The type is stored as an index of +// a struct OpenCLType table. Multiple entries following each other form a +// signature. +struct OpenCLSignatureStruct { + // Type, stored as an index of a struct OpenCLType table. + unsigned TypeTableIndex; +}; + +// Store one overload of an OpenCL builtin function. Multiple entries of a +// OpenCLBuiltinStruct table allows to have all the overloads. +struct OpenCLBuiltinStruct { + // Index of the signature in the OpenCLTypeStruct table. + unsigned SignTableIndex; + // Type between indexes SignTableIndex and (SignTableIndex + NumTypes - 1) in + // the SignatureTable must be considered to build the signature. + // The first type at index SignTableIndex is the return type. + unsigned NumTypes; }; )"; } + void BuiltinNameEmitter::GetOverloads() { + // Populate the TypeMap. + std::vector 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 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>{})); + if (FctOverloadMap.find(BName) == FctOverloadMap.end()) { + FctOverloadMap.insert(std::make_pair( + BName, + std::vector>{})); } auto Signature = B->getValueAsListOfDefs("Signature"); - auto it = - std::find_if(SignatureSet.begin(), SignatureSet.end(), + auto it = std::find_if( + SignaturesList.begin(), + SignaturesList.end(), [&](const std::pair, unsigned> &a) { return a.first == Signature; }); unsigned SignIndex; - if (it == SignatureSet.end()) { - SignatureSet.push_back(std::make_pair(Signature, CumulativeSignIndex)); + if (it == SignaturesList.end()) { + 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 << "OpenCLType OpenCLSignature[] = {\n"; - for (auto &P : SignatureSet) { + std::vector> Signature; + + OS << "static const OpenCLSignatureStruct SignatureTable[] = {\n"; + for (const auto &P : SignaturesList) { 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"; + for (const Record *R : P.first) { + OS << TypeMap.find(R)->second << ", "; } + OS << "\n"; } OS << "};\n\n"; } + void BuiltinNameEmitter::EmitBuiltinTable() { - 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") + unsigned Index = 0; + + OS << "static const OpenCLBuiltinStruct BuiltinTable[] = {\n"; + for (const auto &FOM : FctOverloadMap) { + + OS << "// " << Index << " " << FOM.first << "\n"; + + for (const auto &Overload : FOM.second) { + OS << " { " + << Overload.second << ", " + << Overload.first->getValueAsListOfDefs("Signature").size() << " },\n"; + Index++; } } OS << "};\n\n"; } + void BuiltinNameEmitter::EmitStringMatcher() { std::vector ValidBuiltins; unsigned CumulativeIndex = 1; - for (auto &i : OverloadInfo) { + for (auto &i : FctOverloadMap) { auto &Ov = i.second; std::string RetStmt; raw_string_ostream SS(RetStmt); @@ -252,27 +417,110 @@ 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) { +/// Find out whether a string matches an existing OpenCL builtin function name. +/// \param name The string to look for. +/// +/// \returns A pair <0, 0> if no name matches. +/// A pair indexing the BuiltinTable if the name is +/// matching an OpenCL builtin function. +static std::pair isOpenCLBuiltin(llvm::StringRef name) { )"; 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 llvm CanQualType. +/// Generic types contain multiple types and vector sizes, thus a vector +/// is returned. +/// \param Context (in) The Context instance. +/// +/// \param Ty (in) The OpenCLTypeStruct instance we want to convert. +/// +/// \returns A vector of QualType corresponding to the given OpenCLTypeStruct. +static std::vector +OCL2Qual(ASTContext &Context, const OpenCLTypeStruct &Ty) { + std::vector QT; + + // A generic type asbtracts multiple types and vectorized types (int, int4, + // float, ...). These variables help doing this. + unsigned GenTypePossibility; + llvm::SmallVector *GenVectorPossibility; )"; + // Generate the possible vector sizes for each generic type. + // The genererated code for the ListListN list is: + // llvm::SmallVector ListListN{0, 2, 3, 4, 8, 16, }; + for (const auto *VectList : Records.getAllDerivedDefinitions("IntList")) { + OS << " llvm::SmallVector List" + << VectList->getValueAsString("Name") << "{"; + for (const auto V : VectList->getValueAsListOfInts("List")) { + OS << V << ", "; + } + OS << "};\n"; + } + + // Start of switch statement over all possible types used in Builtin + // functions. + OS << "\n\n switch (Ty.ID) {\n"; + + // Switch case for generic types. + // The genererated code for the FGenTypeN generic type is: + // case OCLT_FGenTypeN: + // QT.push_back(Context.FloatTy); + // QT.push_back(Context.DoubleTy); + // QT.push_back(Context.HalfTy); + // QT.push_back(Context.FloatTy); + // QT.push_back(Context.DoubleTy); + // QT.push_back(Context.HalfTy); + // QT.push_back(Context.FloatTy); + // QT.push_back(Context.DoubleTy); + // QT.push_back(Context.HalfTy); + // QT.push_back(Context.FloatTy); + // QT.push_back(Context.DoubleTy); + // QT.push_back(Context.HalfTy); + // QT.push_back(Context.FloatTy); + // QT.push_back(Context.DoubleTy); + // QT.push_back(Context.HalfTy); + // QT.push_back(Context.FloatTy); + // QT.push_back(Context.DoubleTy); + // QT.push_back(Context.HalfTy); + // GenTypePossibility = 3; + // GenVectorPossibility = &ListListN; + // break; + for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) { + OS << " case OCLT_" << GenType->getValueAsString("Name") << ":\n"; + + for (uint I = 0; + I < GenType->getValueAsDef("VectorList")->getValueAsListOfInts("List").size(); + I++) { + for (const auto *T : + GenType->getValueAsDef("TypeListField")->getValueAsListOfDefs("List")) { + OS << " QT.push_back(Context." + << T->getValueAsDef("QTName")->getValueAsString("Name") + << ");\n"; + } + } + + OS << " GenTypePossibility = " + << GenType->getValueAsDef("TypeListField")->getValueAsListOfDefs("List").size() + << ";\n"; + OS << " GenVectorPossibility = &List" + << GenType->getValueAsDef("VectorList")->getValueAsString("Name") + << ";\n"; + OS << " break;\n"; + } + + // Switch case for non generic, non image types (int, int4, float, ...). std::vector Types = Records.getAllDerivedDefinitions("Type"); StringMap TypesSeen; @@ -284,30 +532,52 @@ // 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; + // 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 << R"( + default: + QT.push_back(Context.VoidTy); + } // switch (Ty.ID) - OS << " case OCLT_" << T->getValueAsString("Name") << ":\n"; - OS << " RT = Context." << QT->getValueAsString("Name") << ";\n"; - OS << " break;\n"; +)"; + + OS << " // Generate the different vector sizes for each type of the generic type\n"; + OS << " if (Ty.ID >= " << TypeList.size() << ") {\n"; + OS << R"( + for (unsigned I = 0; I < QT.size(); I++) { + if ((*GenVectorPossibility)[I/GenTypePossibility] != 0) { + QT[I] = Context.getExtVectorType( + QT[I], + (*GenVectorPossibility)[I/GenTypePossibility]); + } + } } - OS << " }\n"; +)"; - // Special cases + // Give the right attributes to the types (vector size, pointer type, const, + // volatile). OS << R"( - if (Ty.VectorWidth > 0) - RT = Context.getExtVectorType(RT, Ty.VectorWidth); + unsigned Index = 0; - if (Ty.isPointer) { - RT = Context.getAddrSpaceQualType(RT, Ty.AS); - RT = Context.getPointerType(RT); + if (Ty.VectorWidth > 0) { + for(Index = 0; Index < QT.size(); Index++) { + QT[Index] = Context.getExtVectorType(QT[Index], Ty.VectorWidth); + } } - return RT; -} + return QT; +} // OCL2Qual + )"; } + namespace clang { void EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) {