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 { @@ -82,6 +112,8 @@ string AddrSpace = DefaultAS.Name; // Access qualifier. Must be one of ("RO", "WO", "RW"). string AccessQualifier = ""; + // TypeExtension, if this type can only be used in one extension + TypeExtension Extension = NoTypeExt; } // OpenCL vector types (e.g.: int2, int3, int16, float8, ...) @@ -173,8 +205,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; @@ -199,8 +231,12 @@ def long_t : Type<"long", QualType<"LongTy">>; def ulong_t : Type<"ulong", QualType<"UnsignedLongTy">>; def float_t : Type<"float", QualType<"FloatTy">>; -def double_t : Type<"double", QualType<"DoubleTy">>; -def half_t : Type<"half", QualType<"HalfTy">>; +let Extension = Fp64TypeExt in { + def double_t : Type<"double", QualType<"DoubleTy">>; +} +let Extension = Fp16TypeExt in { + def half_t : Type<"half", QualType<"HalfTy">>; +} def size_t : Type<"size_t", QualType<"getSizeType()">>; def ptrdiff_t : Type<"ptrdiff_t", QualType<"getPointerDiffType()">>; def intptr_t : Type<"intptr_t", QualType<"getIntPtrType()">>; @@ -224,10 +260,12 @@ def image1d_array_t : Type<"image1d_array_t", QualType<"OCLImage1dArray", 1>>; def image2d_depth_t : Type<"image2d_depth_t", QualType<"OCLImage2dDepth", 1>>; def image2d_array_depth_t : Type<"image2d_array_depth_t", QualType<"OCLImage2dArrayDepth", 1>>; -def image2d_msaa_t : Type<"image2d_msaa_t", QualType<"OCLImage2dMSAA", 1>>; -def image2d_array_msaa_t : Type<"image2d_array_msaa_t", QualType<"OCLImage2dArrayMSAA", 1>>; -def image2d_msaa_depth_t : Type<"image2d_msaa_depth_t", QualType<"OCLImage2dMSAADepth", 1>>; -def image2d_array_msaa_depth_t : Type<"image2d_array_msaa_depth_t", QualType<"OCLImage2dArrayMSAADepth", 1>>; +let Extension = MsaaTypeExt in { + def image2d_msaa_t : Type<"image2d_msaa_t", QualType<"OCLImage2dMSAA", 1>>; + def image2d_array_msaa_t : Type<"image2d_array_msaa_t", QualType<"OCLImage2dArrayMSAA", 1>>; + def image2d_msaa_depth_t : Type<"image2d_msaa_depth_t", QualType<"OCLImage2dMSAADepth", 1>>; + def image2d_array_msaa_depth_t : Type<"image2d_array_msaa_depth_t", QualType<"OCLImage2dArrayMSAADepth", 1>>; +} def sampler_t : Type<"sampler_t", QualType<"OCLSamplerTy">>; def event_t : Type<"event_t", QualType<"OCLEventTy">>; @@ -425,19 +463,20 @@ // OpenCL v1.0 s9.5, s9.6, s9.7 - Atomic Functions for 32-bit integers // --- Table 9.1 --- -foreach Type = [int_t, uint_t] 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_t, uint_t] 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]>; + } } } - // OpenCL v1.2 s6.12.2: Math Functions foreach name = ["acos", "acosh", "acospi", "asin", "asinh", "asinpi", Index: clang/lib/Sema/SemaLookup.cpp =================================================================== --- clang/lib/Sema/SemaLookup.cpp +++ clang/lib/Sema/SemaLookup.cpp @@ -757,6 +757,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.SignTableIndex + I].TypeTableIndex].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 @@ -841,6 +878,10 @@ NewDecl->setParams(ParmList); } NewDecl->addAttr(OverloadableAttr::CreateImplicit(Context)); + + // Add extensions + AddExtensions(S, Decl, NewDecl, Index); + LR.addDecl(NewDecl); } } Index: clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl =================================================================== --- clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl +++ clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl @@ -36,6 +36,22 @@ 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); } Index: clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp =================================================================== --- clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp +++ clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp @@ -73,13 +73,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, ...). @@ -99,8 +107,8 @@ // The "int" type being at the index 12 in the TypeTable. void EmitSignatureTable(); - // Emit the OpenCLBuiltins table. This table contains all overloads of - // each function, and is a struct OpenCLBuiltinDecl. + // Emit the BuiltinTable table. This table contains all the overloads of + // each function. // E.g.: // // acos // { 2, 0, "", 100 }, @@ -116,6 +124,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>, @@ -146,16 +159,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. + // 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 @@ -165,19 +187,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(); } @@ -216,18 +241,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"( @@ -267,6 +305,8 @@ // the SignatureTable must be considered to build the signature. // The first type at index SignTableIndex 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. @@ -316,6 +356,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; @@ -384,6 +451,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"; @@ -549,7 +617,7 @@ )"; 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++) { if ((*GenVectorPossibility)[I/GenTypePossibility] != 0) { @@ -601,6 +669,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) {