Index: clang/lib/Sema/OpenCLBuiltins.td =================================================================== --- clang/lib/Sema/OpenCLBuiltins.td +++ clang/lib/Sema/OpenCLBuiltins.td @@ -40,6 +40,36 @@ def LocalAS : AddressSpace<"clang::LangAS::opencl_local">; def GenericAS : AddressSpace<"clang::LangAS::opencl_generic">; +// Extension to OpenCL language. +// The AbstractExtension class is designed to be abstract: only instances of +// TypeExtension and FctExtension should used. +// Functions can belong to an extension because: +// * one of its return type/ argumentsthe belongs to an extension +// E.g.: "cl_khr_fp16", associated with the "half" type. +// * the function is itself part of an extension +// E.g.: "cl_khr_subgroups" for the "get_sub_group_size" function +class AbstractExtension { + // Custom name represetning the set of extensions in the ExtName field. + string ID = _ID; + // Name of the OpenCL extensions, space separated and less than 64 chars long. + string ExtName = _Ext; +} +class TypeExtension : AbstractExtension<_ID, _Ext>; +class FctExtension : AbstractExtension<_ID, _Ext>; + +// TypeExtension definitions +def NoTypeExt : TypeExtension<"null" ,"">; +def Fp16TypeExt : TypeExtension<"fp16", "cl_khr_fp16">; +def Fp64TypeExt : TypeExtension<"fp64", "cl_khr_fp64">; +def MsaaTypeExt : TypeExtension<"msaa", "cl_khr_gl_msaa_sharing">; + +// FctExtension definitions +def NoFctExt : FctExtension<"null" ,"">; +def GlobalInt32BaseAtomicsFctExt : FctExtension<"GlobalInt32BaseAtomicsFctExt", "cl_khr_global_int32_base_atomics">; +def GlobalInt32ExtendedAtomicsFctExt : FctExtension<"GlobalInt32ExtendedAtomicsFctExt", "cl_khr_global_int32_extended_atomics">; +// Multiple extensions +def GlobalInt32BaseAndExtendedAtomicsFctExt : FctExtension<"GlobalInt32BaseAndExtendedAtomicsFctExt", "cl_khr_global_int32_base_atomics cl_khr_global_int32_extended_atomics">; + // Qualified Type. Allow to retrieve an ASTContext QualType. class QualType { @@ -84,6 +114,8 @@ string AccessQualifier = ""; // Address space associated. string AddrSpace = DefaultAS.Name; + // TypeExtension, if this type can only be used in one extension + TypeExtension Extension = NoTypeExt; } // OpenCL vector types (e.g.: int2, int3, int16, float8, ...). @@ -95,6 +127,7 @@ let IsConst = _Ty.IsConst; let IsVolatile = _Ty.IsVolatile; let AddrSpace = _Ty.AddrSpace; + let Extension = _Ty.Extension; } // OpenCL pointer types (e.g.: int*, float*, ...) @@ -107,6 +140,7 @@ let IsConst = _Ty.IsConst; let IsVolatile = _Ty.IsVolatile; let AccessQualifier = _Ty.AccessQualifier; + let Extension = _Ty.Extension; } // OpenCL const types (e.g.: const int) @@ -118,6 +152,7 @@ let IsVolatile = _Ty.IsVolatile; let AccessQualifier = _Ty.AccessQualifier; let AddrSpace = _Ty.AddrSpace; + let Extension = _Ty.Extension; } // OpenCL volatile types (e.g.: volatile int) @@ -129,6 +164,7 @@ let IsConst = _Ty.IsConst; let AccessQualifier = _Ty.AccessQualifier; let AddrSpace = _Ty.AddrSpace; + let Extension = _Ty.Extension; } // OpenCL image types (e.g.: image2d) @@ -141,6 +177,7 @@ let IsConst = _Ty.IsConst; let IsVolatile = _Ty.IsVolatile; let AddrSpace = _Ty.AddrSpace; + let Extension = _Ty.Extension; } // Store a list of Types. @@ -178,8 +215,8 @@ // the following are the arguments. The list must have at least one element // (the return type). list Signature = _Signature; - // OpenCL Extension to which the function belongs (cl_khr_subgroups, ...) - string Extension = ""; + // OpenCL extensions to which the function belongs (e.g.: cl_khr_subgroups) + FctExtension Extension = NoFctExt; // Version of OpenCL from which the function is available (e.g.: CL10). // MinVersion is inclusive. Version MinVersion = CL10; @@ -204,8 +241,12 @@ def Long : Type<"long", QualType<"LongTy">>; def ULong : Type<"ulong", QualType<"UnsignedLongTy">>; def Float : Type<"float", QualType<"FloatTy">>; -def Double : Type<"double", QualType<"DoubleTy">>; -def Half : Type<"half", QualType<"HalfTy">>; +let Extension = Fp64TypeExt in { + def Double : Type<"double", QualType<"DoubleTy">>; +} +let Extension = Fp16TypeExt in { + def Half : Type<"half", QualType<"HalfTy">>; +} def Size : Type<"size", QualType<"getSizeType()">>; def PtrDiff : Type<"ptrdiff_t", QualType<"getPointerDiffType()">>; def IntPtr : Type<"intptr_t", QualType<"getIntPtrType()">>; @@ -229,10 +270,12 @@ def Image1dArray : Type<"image1d_array_t", QualType<"OCLImage1dArray", 1>>; def Image2dDepth : Type<"image2d_depth_t", QualType<"OCLImage2dDepth", 1>>; def Image2dArrayDepth : Type<"image2d_array_depth_t", QualType<"OCLImage2dArrayDepth", 1>>; -def Image2dMsaa : Type<"image2d_msaa_t", QualType<"OCLImage2dMSAA", 1>>; -def Image2dArrayMsaa : Type<"image2d_array_msaa_t", QualType<"OCLImage2dArrayMSAA", 1>>; -def Image2dMsaaDepth : Type<"image2d_msaa_depth_t", QualType<"OCLImage2dMSAADepth", 1>>; -def Image2dArrayMsaaDepth : Type<"image2d_array_msaa_depth_t", QualType<"OCLImage2dArrayMSAADepth", 1>>; +let Extension = MsaaTypeExt in { + def Image2dMsaa : Type<"image2d_msaa_t", QualType<"OCLImage2dMSAA", 1>>; + def Image2dArrayMsaa : Type<"image2d_array_msaa_t", QualType<"OCLImage2dArrayMSAA", 1>>; + def Image2dMsaaDepth : Type<"image2d_msaa_depth_t", QualType<"OCLImage2dMSAADepth", 1>>; + def Image2dArrayMsaaDepth : Type<"image2d_array_msaa_depth_t", QualType<"OCLImage2dArrayMSAADepth", 1>>; +} def Sampler : Type<"Sampler", QualType<"OCLSamplerTy">>; def Event : Type<"Event", QualType<"OCLEventTy">>; @@ -423,22 +466,25 @@ } } + //-------------------------------------------------------------------- // OpenCL v2.0 s6.13.11 - Atomics Functions. // Functions are using memory_order and cl_mem_fence_flags typedefs, // which make them not declarable here. -// OpenCL v1.0 s9.5, s9.6, s9.7 - Atomic Functions for 32-bit integers. +// OpenCL v1.0 s9.5, s9.6, s9.7 - Atomic Functions for 32-bit integers // --- Table 9.1 --- -foreach Type = [Int, UInt] in { - foreach name = ["atom_add", "atom_sub", "atom_xchg"] in { - def : Builtin, GlobalAS>, Type]>; - } - foreach name = ["atom_inc", "atom_dec"] in { - def : Builtin, GlobalAS>]>; - } - foreach name = ["atom_cmpxchg"] in { - def : Builtin, GlobalAS>, Type, Type]>; +let Extension = GlobalInt32BaseAtomicsFctExt in { + foreach Type = [Int, UInt] in { + foreach name = ["atom_add", "atom_sub", "atom_xchg"] in { + def : Builtin, GlobalAS>, Type]>; + } + foreach name = ["atom_inc", "atom_dec"] in { + def : Builtin, GlobalAS>]>; + } + foreach name = ["atom_cmpxchg"] in { + def : Builtin, GlobalAS>, Type, Type]>; + } } } Index: clang/lib/Sema/SemaLookup.cpp =================================================================== --- clang/lib/Sema/SemaLookup.cpp +++ clang/lib/Sema/SemaLookup.cpp @@ -760,6 +760,43 @@ } } + +/// Helper function to add extensions to the function declaration. +/// +/// \param S (in/out) The Sema instance +/// +/// \param Decl (in) Prototype of the considered function +/// +/// \param FctDecl (in) FunctionDecl instance +/// +/// \param Index (in) Index of the Gentype processed +void AddExtensions(Sema &S, + const OpenCLBuiltinStruct &Decl, + FunctionDecl *FctDecl, + unsigned Index) { + std::vector ExtensionList; + + // Fetch extensions associated with a function prototype, + // (e.g. cl_khr_subgroups) + ExtensionList.push_back(FctExtensionTable[Decl.Extension]); + + // Fetch extensions associated with a type + // (e.g. cl_khr_fp16 for "half") + for (unsigned I = 0; I < Decl.NumTypes; I++) { + std::vector TmpExtList = GetTypeExtensions( + TypeTable[SignatureTable[Decl.SigTableIndex + I]].ID); + ExtensionList.push_back(TmpExtList[Index%TmpExtList.size()]); + } + + if (ExtensionList.size()) { + for (const auto &E : ExtensionList) { + if (E != "") + S.setOpenCLExtensionForDecl(FctDecl, E); + } + } +} + + /// When trying to resolve a function name, if the isOpenCLBuiltin function /// defined in "OpenCLBuiltins.inc" returns a non-null pair, then /// the name is referencing an OpenCL builtin function. Thus, all its @@ -848,6 +885,10 @@ NewOpenCLBuiltin->setParams(ParmList); } NewOpenCLBuiltin->addAttr(OverloadableAttr::CreateImplicit(Context)); + + // Add extensions + AddExtensions(S, OpenCLBuiltin, NewOpenCLBuiltin, Index); + LR.addDecl(NewOpenCLBuiltin); } } Index: clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl =================================================================== --- clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl +++ clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl @@ -5,10 +5,6 @@ // 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 -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 -// expected-no-diagnostics -#endif - // Test the -fdeclare-opencl-builtins option. #pragma OPENCL EXTENSION cl_khr_fp16 : enable @@ -36,10 +32,43 @@ int i; unsigned int ui; + atom_add((volatile __global int *) global_p, i); +#if __OPENCL_C_VERSION__ < CL_VERSION_1_1 +// expected-error@-2{{no matching function for call to 'atom_add'}} + +// There are two potential definitions of the function "atom_add", both are +// currently disabled because the associated extension is disabled. +// expected-note@-6{{candidate unavailable as it requires OpenCL extension 'cl_khr_global_int32_base_atomics' to be enabled}} +// expected-note@-7{{candidate unavailable as it requires OpenCL extension 'cl_khr_global_int32_base_atomics' to be enabled}} +#endif + + + +#if __OPENCL_C_VERSION__ < CL_VERSION_1_1 +#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable +#endif + atom_add((volatile __global int *) global_p, i); atom_cmpxchg((volatile __global unsigned int *) global_p, ui, ui); } + +kernel void basic_floating_point_extension() { + #pragma OPENCL EXTENSION cl_khr_fp16 : disable + #pragma OPENCL EXTENSION cl_khr_fp64 : disable + + half h; + // expected-error@-1{{declaring variable of type 'half' is not allowed}} + + double d; + #if __OPENCL_C_VERSION__ < CL_VERSION_1_2 + // expected-error@-2{{use of type 'double' requires cl_khr_fp64 extension to be enabled}} + #endif + + #pragma OPENCL EXTENSION cl_khr_fp16 : enable + #pragma OPENCL EXTENSION cl_khr_fp64 : enable +} + kernel void basic_conversion() { double d; float f; Index: clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp =================================================================== --- clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp +++ clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp @@ -30,6 +30,11 @@ // ... // Other types. // }; // +// enum OpenCLFctExtensionID { +// OCLE_GlobalInt32BaseAndExtendedAtomicsFctExt, +// ... // Other extension IDs. +// }; +// // struct OpenCLTypeStruct { // // Hold information about types (vector size, ...). // }; @@ -39,6 +44,21 @@ // // and types of the arguments. // }; // +// static const char FctExtensionTable[][128] = { +// // 1 : OCLE_GlobalInt32BaseAtomicsFctExt +// "cl_khr_global_int32_base_atomics", // Extension name corresponding to an +// // enum OpenCLFctExtensionID, here: +// // OCLE_GlobalInt32BaseAtomicsFctExt. +// ... // Other "function" extensions +// }; +// +// static const char TypeExtensionTable[][32] = { +// // 5 : OCLT_half +// "cl_khr_fp16", // Extension name corresponding to an enum OpenCLTypeID, +// // here: OCLT_half. +// ... // Other "type" extensions +// }; +// // static const OpenCLTypeStruct TypeTable[] = { // { OCLT_double, 2, 0, 0, 0, 0, clang::LangAS::Default}, // // This represents the double type, with a vector width of 2, @@ -56,14 +76,16 @@ // // static const OpenCLBuiltinStruct BuiltinTable[] = { // // 891 convert_float2_rtn -// { 38, 2, 100, 0 }, // The "convert_float2_rtn" function has one signature -// // at the index 891 of the SignatureTable, it uses the 2 -// // values after this index. The first value is the -// // return type. -// // This prototype is available from OpenCL C version 1.0 -// // to the last available version (0 meaning all). -// { 182, 2, 100, 0 }, -// { 326, 2, 100, 0 }, +// { 38, 2, OCLE_null, 100, 0 }, +// // The "convert_float2_rtn" function has one signature at the index 891 of +// // the SignatureTable, it uses the 2 values after this index. The first value +// // is the return type. +// // This prototype doesn't rely on any extension (OCLE_null). +// // This prototype is available from OpenCL C version 1.0 to the last +// // available version (0 meaning all). +// // +// { 182, 2, OCLE_null, 100, 0 }, +// { 326, 2, OCLE_null, 100, 0 }, // ... // Other functions and signatures. // }; // @@ -164,13 +186,21 @@ std::vector &List); // Emit the enum or struct used in the file generated - // Populate the TypeList at the same time. + // Populate the TypeExtensionList and FctExtensionList at the same time. void EmitDeclarations(); // Parse the Records generated by TableGen to populate the SignaturesList, // FctOverloadMap and TypeMap. void GetOverloads(); + // Emit the FctExtensionTable and the TypeExtensionTable. + // FctExtensionTable maps enums OpenCLFctExtensionID to their extension. + // TypeExtensionTable maps OpenCLTypeID enums (not being generic types) to + // their extension. + // GenTypeExtensionTable maps OpenCLTypeID enums (generic type indexes) to + // their extension. + void EmitExtensionTable(); + // 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, ...). @@ -194,10 +224,11 @@ // each function, and is a struct OpenCLBuiltinDecl. // E.g.: // // 891 convert_float2_rtn - // { 38, 2, 100, 0 }, + // { 38, 2, OCLE_null, 100, 0 }, // This means that the signature of this convert_float2_rtn overload has // 1 argument (+1 for the return type), stored at index 58 in // the OpenCLSignature table. + // This prototype doesn't rely on any extension (OCLE_null). // Trailing values add information about the version. void EmitBuiltinTable(); @@ -214,6 +245,11 @@ // the TableGen Record Type. void EmitQualTypeFinder(); + // Build a function returning the list of extension associated with the Types + // used in its signature. The prototype of the function created is: + // static std::vector GetTypeExtensions(enum OpenCLTypeID ID); + void EmitExtensionFinder(); + // Contains a list of the available signatures, without the name of the // function. Each pair consists of a signature and a cumulative index. // E.g.: <, 0>, @@ -244,16 +280,25 @@ // ...> MapVector TypeMap; + // List of the possible OpenCL function extensions, in the same order as in + // the enum OpenCLFctExtensionID. + // E,g, <>, + // ...> + MapVector FctExtensionList; + // List of the possible OpenCL type names in the same order as in their // enum OpenCLTypeID. This list doesn't contain generic types. + // It allows to associate a type name to the extension it is bound to. + // Records can be a subclass of the Type class (i.e.: a VectorType), the only + // two fields that matter are the name and TypeExtension. // Generic types are not part of this list. - // E.g.: , - // , + // E.g.: , + // , // ...> - std::vector TypeList; + std::vector TypeExtensionList; - // Same as TypeList, but for generic types only. - std::vector GenTypeList; + // Same as TypeExtensionList, but for generic types only. + std::vector GenTypeExtensionList; }; } // namespace @@ -263,19 +308,22 @@ OS << "#include \"llvm/ADT/StringRef.h\"\n"; OS << "using namespace clang;\n\n"; + // Emit the enum and struct EmitDeclarations(); + // Parse the Records to populate the internal lists GetOverloads(); // Emit data strucures. + EmitExtensionTable(); EmitTypeTable(); EmitSignatureTable(); - EmitBuiltinTable(); + // Emit functions EmitStringMatcher(); - EmitQualTypeFinder(); + EmitExtensionFinder(); } @@ -314,18 +362,31 @@ EmitTypesEnum(GenTypes, TypesSeen, GenTypeEnums, - GenTypeList); + GenTypeExtensionList); std::vector Types = Records.getAllDerivedDefinitions("Type"); EmitTypesEnum(Types, TypesSeen, TypeEnums, - TypeList); + TypeExtensionList); OS << TypeEnums; OS << GenTypeEnums; OS << "};\n\n"; + + // Enum of the possible extensions associated with functions. + unsigned Index = 0; + OS << "enum OpenCLFctExtensionID {\n"; + std::vector FctExtensions = + Records.getAllDerivedDefinitions("FctExtension"); + for (const auto *FE : FctExtensions) { + OS << " OCLE_" + FE->getValueAsString("ID") << ",\n"; + // Save the extension names and their index at the same time + FctExtensionList.insert(std::make_pair(FE, Index++)); + } + OS << "};\n\n"; + // Strucure definitions. OS << R"( @@ -357,6 +418,8 @@ // the SignatureTable must be considered to build the signature. // The first type at index SigTableIndex is the return type. unsigned NumTypes; + // Extension to which the signature belongs (e.g.: cl_khr_subgroups) + enum OpenCLFctExtensionID Extension; // Version in which it was introduced (e.g.: CL20). MinVersion is inclusive. unsigned MinVersion; // Version in which it was introduced (e.g.: CL20). MaxVersion is exclusive. @@ -406,6 +469,33 @@ } +void BuiltinNameEmitter::EmitExtensionTable() { + // Emit the table of extension names bound to functions + // E.g.: cl_khr_subgroups + OS << "static const char FctExtensionTable[][128] = {\n"; + for (const auto &FE : FctExtensionList) { + OS << "// " << FE.second + << " : OCLE_" << FE.first->getValueAsString("ID") << "\n"; + OS << "\"" << FE.first->getValueAsString("ExtName") << "\",\n"; + } + OS << "};\n\n"; + + // Emit the table of extension names bound to types. + // E.g.: cl_khr_fp64 + unsigned Index = 0; + + OS << "static const char TypeExtensionTable[][32] = {\n"; + for (const auto &TE : TypeExtensionList) { + OS << "// " << Index++ + << " : OCLT_" << TE->getValueAsString("Name") << "\n"; + OS << "\"" + << TE->getValueAsDef("Extension")->getValueAsString("ExtName") + << "\",\n"; + } + OS << "};\n\n"; +} + + void BuiltinNameEmitter::EmitTypeTable() { // Access Qualifier unsigned AQ; @@ -477,6 +567,7 @@ OS << " { " << Overload.second << ", " << Overload.first->getValueAsListOfDefs("Signature").size() << ", " + << "OCLE_" << Overload.first->getValueAsDef("Extension")->getValueAsString("ID") << ", " << Overload.first->getValueAsDef("MinVersion")->getValueAsInt("Name") << ", " << Overload.first->getValueAsDef("MaxVersion")->getValueAsInt("Name") << " },\n"; @@ -524,7 +615,7 @@ void BuiltinNameEmitter::EmitQualifierSpecifier() { OS << " // Generate the different vector sizes for each type " << "of the generic type\n"; - OS << " if (Ty.ID >= " << TypeList.size() << ") {\n"; + OS << " if (Ty.ID >= " << TypeExtensionList.size() << ") {\n"; OS << R"( for (unsigned I = 0; I < QT.size(); I++) { // For scalars, size is 1. @@ -773,6 +864,41 @@ } +void BuiltinNameEmitter::EmitExtensionFinder() { + OS << R"( +static std::vector GetTypeExtensions(enum OpenCLTypeID ID) { + std::vector ExtensionList; +)"; + + OS << " if (ID < " << TypeExtensionList.size() << ") {\n"; + + OS << R"( + ExtensionList.push_back(TypeExtensionTable[ID]); + return ExtensionList; + } else { + switch (ID) { +)"; + + for (const auto > : GenTypeExtensionList) { + OS << " case OCLT_" << GT->getValueAsString("Name") << ":\n"; + for (const auto &TE : + GT->getValueAsDef("TypeListField")->getValueAsListOfDefs("List")) { + OS << " ExtensionList.push_back(TypeExtensionTable[OCLT_" + << TE->getValueAsString("Name") << "]);\n"; + } + OS << " break;\n"; + } + OS << R"( + default: + break; + } + } + return ExtensionList; +} +)"; +} + + namespace clang { void EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) {