From 308b8b76ceee805c964faf9f2176e3e05532a45b Mon Sep 17 00:00:00 2001 From: Sven van Haastregt Date: Wed, 18 Dec 2019 10:13:51 +0000 Subject: [PATCH] [OpenCL] Add builtin function extension handling Provide a mechanism to attach OpenCL extension information to builtin functions, so that their use can be restricted according to the extension(s) the builtin is part of. Patch by Pierre Gondois and Sven van Haastregt. Differential Revision: https://reviews.llvm.org/D71476 --- clang/lib/Sema/OpenCLBuiltins.td | 43 +++++++++++++------ clang/lib/Sema/SemaLookup.cpp | 14 ++++++ clang/test/SemaOpenCL/fdeclare-opencl-builtins.cl | 23 ++++++++-- clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp | 50 +++++++++++++++++++--- 4 files changed, 106 insertions(+), 24 deletions(-) diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td index 353e0c1..37f3178 100644 --- a/clang/lib/Sema/OpenCLBuiltins.td +++ b/clang/lib/Sema/OpenCLBuiltins.td @@ -40,6 +40,21 @@ def ConstantAS : AddressSpace<"clang::LangAS::opencl_constant">; 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 @@ class Builtin _Signature, list _Attributes = Attr. // 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 @@ foreach name = ["prefetch"] in { // 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 @@ let MinVersion = CL20 in { // 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 index d9b6cb6..0ed51de 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -739,6 +739,18 @@ static void GetOpenCLBuiltinFctOverloads( } } +/// 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 @@ static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR, 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 index 589d04c..000f962 100644 --- 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 @@ kernel void test_pointers(volatile global void *global_p, global const int4 *a) 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 @@ kernel void basic_subgroup(global uint *out) { #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 index 4042c17..dcdc4bf 100644 --- 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 @@ private: // 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 @@ private: // 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 @@ private: // 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 @@ void BuiltinNameEmitter::Emit() { // 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 @@ struct OpenCLBuiltinStruct { 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::GetOverloads() { } } +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 @@ void BuiltinNameEmitter::EmitBuiltinTable() { 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 @@ bool BuiltinNameEmitter::CanReuseSignature( 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; } } -- 2.7.4