diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td --- a/clang/lib/Sema/OpenCLBuiltins.td +++ b/clang/lib/Sema/OpenCLBuiltins.td @@ -40,6 +40,21 @@ def LocalAS : AddressSpace<"clang::LangAS::opencl_local">; def GenericAS : AddressSpace<"clang::LangAS::opencl_generic">; +// OpenCL language extension. +class AbstractExtension { + // One or more OpenCL extensions, space separated. Each extension must be + // a valid extension name for the opencl extension pragma. + string ExtName = _Ext; +} + +// Extension associated to a builtin function. +class FunctionExtension : AbstractExtension<_Ext>; + +// FunctionExtension definitions. +def FuncExtNone : FunctionExtension<"">; +def FuncExtKhrSubgroups : FunctionExtension<"cl_khr_subgroups">; +def FuncExtKhrGlobalInt32BaseAtomics : FunctionExtension<"cl_khr_global_int32_base_atomics">; +def FuncExtKhrGlobalInt32ExtendedAtomics : FunctionExtension<"cl_khr_global_int32_extended_atomics">; // Qualified Type. These map to ASTContext::QualType. class QualType { @@ -198,14 +213,14 @@ // 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 = ""; // Function attribute __attribute__((pure)) bit IsPure = _Attributes[0]; // Function attribute __attribute__((const)) bit IsConst = _Attributes[1]; // Function attribute __attribute__((convergent)) bit IsConv = _Attributes[2]; + // OpenCL extensions to which the function belongs. + FunctionExtension Extension = FuncExtNone; // Version of OpenCL from which the function is available (e.g.: CL10). // MinVersion is inclusive. Version MinVersion = CL10; @@ -862,17 +877,19 @@ // Functions that use memory_order and cl_mem_fence_flags enums are not // declared here as the TableGen backend does not handle enums. -// 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 = FuncExtKhrGlobalInt32BaseAtomics 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]>; + } } } @@ -1077,7 +1094,7 @@ // OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions let MinVersion = CL20 in { - let Extension = "cl_khr_subgroups" in { + let Extension = FuncExtKhrSubgroups in { def get_sub_group_size : Builtin<"get_sub_group_size", [UInt]>; def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [UInt]>; def get_num_sub_groups : Builtin<"get_num_sub_groups", [UInt]>; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -739,6 +739,18 @@ } } +/// Add extensions to the function declaration. +/// \param S (in/out) The Sema instance. +/// \param BIDecl (in) Description of the builtin. +/// \param FDecl (in/out) FunctionDecl instance. +static void AddOpenCLExtensions(Sema &S, const OpenCLBuiltinStruct &BIDecl, + FunctionDecl *FDecl) { + // Fetch extension associated with a function prototype. + StringRef E = FunctionExtensionTable[BIDecl.Extension]; + if (E != "") + S.setOpenCLExtensionForDecl(FDecl, E); +} + /// When trying to resolve a function name, if isOpenCLBuiltin() returns a /// non-null pair, then the name is referencing an OpenCL /// builtin function. Add all candidate signatures to the LookUpResult. @@ -827,6 +839,8 @@ if (!S.getLangOpts().OpenCLCPlusPlus) NewOpenCLBuiltin->addAttr(OverloadableAttr::CreateImplicit(Context)); + AddOpenCLExtensions(S, OpenCLBuiltin, NewOpenCLBuiltin); + LR.addDecl(NewOpenCLBuiltin); } } diff --git a/clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl b/clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl --- a/clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl +++ b/clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl @@ -7,10 +7,6 @@ // RUN: %clang_cc1 %s -triple spir -verify -pedantic -Wconversion -Werror -fsyntax-only -cl-std=CLC++ -fdeclare-opencl-builtins -DNO_HEADER // RUN: %clang_cc1 %s -triple spir -verify -pedantic -Wconversion -Werror -fsyntax-only -cl-std=CLC++ -fdeclare-opencl-builtins -finclude-default-header -#if defined(__OPENCL_CPP_VERSION__) || __OPENCL_C_VERSION__ >= CL_VERSION_2_0 -// expected-no-diagnostics -#endif - // Test the -fdeclare-opencl-builtins option. #pragma OPENCL EXTENSION cl_khr_fp16 : enable @@ -43,6 +39,20 @@ prefetch(a, 2); atom_add((volatile __global int *)global_p, i); +#if !defined(__OPENCL_CPP_VERSION__) && __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); } @@ -113,6 +123,11 @@ #if !defined(__OPENCL_CPP_VERSION__) && __OPENCL_C_VERSION__ < CL_VERSION_2_0 // expected-error@-2{{implicit declaration of function 'get_sub_group_size' is invalid in OpenCL}} // expected-error@-3{{implicit conversion changes signedness: 'int' to 'uint' (aka 'unsigned int')}} +#elif defined(__OPENCL_CPP_VERSION__) +// expected-error@-5{{no matching function for call to 'get_sub_group_size'}} +// expected-note@-6{{candidate unavailable as it requires OpenCL extension 'cl_khr_subgroups' to be enabled}} +#else +// expected-error@-8{{use of declaration 'get_sub_group_size' requires cl_khr_subgroups extension to be enabled}} #endif } diff --git a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp --- a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp +++ b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp @@ -26,6 +26,11 @@ // // * Structs and enums to represent types and function signatures. // +// * const char *FunctionExtensionTable[] +// List of space-separated OpenCL extensions. A builtin references an +// entry in this table when the builtin requires a particular (set of) +// extension(s) to be enabled. +// // * OpenCLTypeStruct TypeTable[] // Type information for return types and arguments. // @@ -133,6 +138,9 @@ // function names. void GroupBySignature(); + // Emit the FunctionExtensionTable that lists all function extensions. + void EmitExtensionTable(); + // Emit the TypeTable containing all types used by OpenCL builtins. void EmitTypeTable(); @@ -150,12 +158,13 @@ // each function, and is a struct OpenCLBuiltinDecl. // E.g.: // // 891 convert_float2_rtn - // { 58, 2, 100, 0 }, + // { 58, 2, 3, 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 SignatureTable. The last two values represent the minimum (1.0) and - // maximum (0, meaning no max version) OpenCL version in which this overload - // is supported. + // the SignatureTable. This prototype requires extension "3" in the + // FunctionExtensionTable. The last two values represent the minimum (1.0) + // and maximum (0, meaning no max version) OpenCL version in which this + // overload is supported. void EmitBuiltinTable(); // Emit a StringMatcher function to check whether a function name is an @@ -191,6 +200,10 @@ // Contains the map of OpenCL types to their index in the TypeTable. MapVector TypeMap; + // List of OpenCL function extensions mapping extension strings to + // an index into the FunctionExtensionTable. + StringMap FunctionExtensionIndex; + // List of OpenCL type names in the same order as in enum OpenCLTypeID. // This list does not contain generic types. std::vector TypeList; @@ -227,16 +240,18 @@ // Emit enums and structs. EmitDeclarations(); + // Parse the Records to populate the internal lists. GetOverloads(); GroupBySignature(); // Emit tables. + EmitExtensionTable(); EmitTypeTable(); EmitSignatureTable(); EmitBuiltinTable(); + // Emit functions. EmitStringMatcher(); - EmitQualTypeFinder(); } @@ -323,6 +338,8 @@ const bool IsConst; // Function attribute __attribute__((convergent)) const bool IsConv; + // OpenCL extension(s) required for this overload. + const unsigned short Extension; // First OpenCL version in which this overload was introduced (e.g. CL20). const unsigned short MinVersion; // First OpenCL version in which this overload was removed (e.g. CL20). @@ -413,6 +430,23 @@ } } +void BuiltinNameEmitter::EmitExtensionTable() { + OS << "static const char *FunctionExtensionTable[] = {\n"; + unsigned Index = 0; + std::vector FuncExtensions = + Records.getAllDerivedDefinitions("FunctionExtension"); + + for (const auto &FE : FuncExtensions) { + // Emit OpenCL extension table entry. + OS << " // " << Index << ": " << FE->getName() << "\n" + << " \"" << FE->getValueAsString("ExtName") << "\",\n"; + + // Record index of this extension. + FunctionExtensionIndex[FE->getName()] = Index++; + } + OS << "};\n\n"; +} + void BuiltinNameEmitter::EmitTypeTable() { OS << "static const OpenCLTypeStruct TypeTable[] = {\n"; for (const auto &T : TypeMap) { @@ -463,11 +497,13 @@ OS << "\n"; for (const auto &Overload : SLM.second.Signatures) { + StringRef ExtName = Overload.first->getValueAsDef("Extension")->getName(); OS << " { " << Overload.second << ", " << Overload.first->getValueAsListOfDefs("Signature").size() << ", " << (Overload.first->getValueAsBit("IsPure")) << ", " << (Overload.first->getValueAsBit("IsConst")) << ", " << (Overload.first->getValueAsBit("IsConv")) << ", " + << FunctionExtensionIndex[ExtName] << ", " << Overload.first->getValueAsDef("MinVersion")->getValueAsInt("ID") << ", " << Overload.first->getValueAsDef("MaxVersion")->getValueAsInt("ID") @@ -496,8 +532,8 @@ Rec2->getValueAsDef("MinVersion")->getValueAsInt("ID") && Rec->getValueAsDef("MaxVersion")->getValueAsInt("ID") == Rec2->getValueAsDef("MaxVersion")->getValueAsInt("ID") && - Rec->getValueAsString("Extension") == - Rec2->getValueAsString("Extension")) { + Rec->getValueAsDef("Extension")->getName() == + Rec2->getValueAsDef("Extension")->getName()) { return true; } }