Author: Anastasia Stulova Date: 2021-01-06T20:39:57Z New Revision: 4fde2b6a0c080cb2a598383b5850038d67ca6833
URL: https://github.com/llvm/llvm-project/commit/4fde2b6a0c080cb2a598383b5850038d67ca6833 DIFF: https://github.com/llvm/llvm-project/commit/4fde2b6a0c080cb2a598383b5850038d67ca6833.diff LOG: [OpenCL] Add clang extension for function pointers. The new clang internal extension '__cl_clang_function_pointers' allows use of function pointers and other features that have the same functionality: - Use of member function pointers; - Unrestricted use of references to functions; - Virtual member functions. This not a vendor extension and therefore it doesn't require any special target support. Exposing this functionality fully will require vendor or Khronos extension. Tags: #clang Differential Revision: https://reviews.llvm.org/D94021 Added: Modified: clang/docs/LanguageExtensions.rst clang/include/clang/Basic/OpenCLExtensions.def clang/lib/Basic/Targets/AMDGPU.h clang/lib/Basic/Targets/NVPTX.h clang/lib/Parse/ParseDecl.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaType.cpp clang/test/Misc/amdgcn.languageOptsOpenCL.cl clang/test/Misc/nvptx.languageOptsOpenCL.cl clang/test/Misc/r600.languageOptsOpenCL.cl clang/test/Parser/opencl-cxx-virtual.cl clang/test/SemaOpenCL/extension-version.cl clang/test/SemaOpenCL/func.cl clang/test/SemaOpenCLCXX/members.cl Removed: ################################################################################ diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 6280c486ccbb..fd011b101b6e 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1722,6 +1722,58 @@ syntax to be used with ``std::complex`` with the same meaning.) For GCC compatibility, ``__builtin_complex(re, im)`` can also be used to construct a complex number from the given real and imaginary components. +OpenCL Features +=============== + +Clang supports internal OpenCL extensions documented below. + +``__cl_clang_function_pointers`` +-------------------------------- + +With this extension it is possible to enable various language features that +are relying on function pointers using regular OpenCL extension pragma +mechanism detailed in `the OpenCL Extension Specification, +section 1.2 +<https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_Ext.html#extensions-overview>`_. + +In C++ for OpenCL this also enables: + +- Use of member function pointers; + +- Unrestricted use of references to functions; + +- Virtual member functions. + +Such functionality is not conformant and does not guarantee to compile +correctly in any circumstances. It can be used if: + +- the kernel source does not contain call expressions to (member-) function + pointers, or virtual functions. For example this extension can be used in + metaprogramming algorithms to be able to specify/detect types generically. + +- the generated kernel binary does not contain indirect calls because they + are eliminated using compiler optimizations e.g. devirtualization. + +- the selected target supports the function pointer like functionality e.g. + most CPU targets. + +**Example of Use**: + +.. code-block:: c++ + + #pragma OPENCL EXTENSION __cl_clang_function_pointers : enable + void foo() + { + void (*fp)(); // compiled - no diagnostic generated + } + + #pragma OPENCL EXTENSION __cl_clang_function_pointers : disable + void bar() + { + void (*fp)(); // error - pointers to function are not allowed + } + + Builtin Functions ================= diff --git a/clang/include/clang/Basic/OpenCLExtensions.def b/clang/include/clang/Basic/OpenCLExtensions.def index 17d402f300f1..149594ed40b0 100644 --- a/clang/include/clang/Basic/OpenCLExtensions.def +++ b/clang/include/clang/Basic/OpenCLExtensions.def @@ -69,6 +69,7 @@ OPENCLEXT_INTERNAL(cl_khr_subgroups, 200, ~0U) // Clang Extensions. OPENCLEXT_INTERNAL(cl_clang_storage_class_specifiers, 100, ~0U) +OPENCLEXT_INTERNAL(__cl_clang_function_pointers, 100, ~0U) // AMD OpenCL extensions OPENCLEXT_INTERNAL(cl_amd_media_ops, 100, ~0U) diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h index 8b3f30ed70e9..3fdbf320a329 100644 --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -285,6 +285,7 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { void setSupportedOpenCLOpts() override { auto &Opts = getSupportedOpenCLOpts(); Opts.support("cl_clang_storage_class_specifiers"); + Opts.support("__cl_clang_function_pointers"); bool IsAMDGCN = isAMDGCN(getTriple()); diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h index f8d0afdcceae..8e0da6554708 100644 --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -128,6 +128,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo { void setSupportedOpenCLOpts() override { auto &Opts = getSupportedOpenCLOpts(); Opts.support("cl_clang_storage_class_specifiers"); + Opts.support("__cl_clang_function_pointers"); Opts.support("cl_khr_fp64"); Opts.support("cl_khr_byte_addressable_store"); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 780d48958cb9..571164139630 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3630,12 +3630,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw_virtual: // C++ for OpenCL does not allow virtual function qualifier, to avoid // function pointers restricted in OpenCL v2.0 s6.9.a. - if (getLangOpts().OpenCLCPlusPlus) { + if (getLangOpts().OpenCLCPlusPlus && + !getActions().getOpenCLOptions().isEnabled( + "__cl_clang_function_pointers")) { DiagID = diag::err_openclcxx_virtual_function; PrevSpec = Tok.getIdentifierInfo()->getNameStart(); isInvalid = true; - } - else { + } else { isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID); } break; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 73a6aea4fb7e..3a1294ce431f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6748,14 +6748,16 @@ static bool diagnoseOpenCLTypes(Scope *S, Sema &Se, Declarator &D, } // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed. - QualType NR = R; - while (NR->isPointerType() || NR->isMemberFunctionPointerType()) { - if (NR->isFunctionPointerType() || NR->isMemberFunctionPointerType()) { - Se.Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer); - D.setInvalidType(); - return false; + if (!Se.getOpenCLOptions().isEnabled("__cl_clang_function_pointers")) { + QualType NR = R; + while (NR->isPointerType() || NR->isMemberFunctionPointerType()) { + if (NR->isFunctionPointerType() || NR->isMemberFunctionPointerType()) { + Se.Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer); + D.setInvalidType(); + return false; + } + NR = NR->getPointeeType(); } - NR = NR->getPointeeType(); } if (!Se.getOpenCLOptions().isEnabled("cl_khr_fp16")) { diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 3f564541d41d..31018dc1d0e7 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2089,7 +2089,8 @@ QualType Sema::BuildPointerType(QualType T, return QualType(); } - if (T->isFunctionType() && getLangOpts().OpenCL) { + if (T->isFunctionType() && getLangOpts().OpenCL && + !getOpenCLOptions().isEnabled("__cl_clang_function_pointers")) { Diag(Loc, diag::err_opencl_function_pointer); return QualType(); } diff --git a/clang/test/Misc/amdgcn.languageOptsOpenCL.cl b/clang/test/Misc/amdgcn.languageOptsOpenCL.cl index e7cb8d051321..f86195ce75ab 100644 --- a/clang/test/Misc/amdgcn.languageOptsOpenCL.cl +++ b/clang/test/Misc/amdgcn.languageOptsOpenCL.cl @@ -12,7 +12,12 @@ #ifndef cl_clang_storage_class_specifiers #error "Missing cl_clang_storage_class_specifiers define" #endif -#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers: enable +#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable + +#ifndef __cl_clang_function_pointers +#error "Missing __cl_clang_function_pointers define" +#endif +#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable #ifndef cl_khr_fp16 #error "Missing cl_khr_fp16 define" diff --git a/clang/test/Misc/nvptx.languageOptsOpenCL.cl b/clang/test/Misc/nvptx.languageOptsOpenCL.cl index 09e02a835310..05aa971ca277 100644 --- a/clang/test/Misc/nvptx.languageOptsOpenCL.cl +++ b/clang/test/Misc/nvptx.languageOptsOpenCL.cl @@ -20,7 +20,12 @@ #ifndef cl_clang_storage_class_specifiers #error "Missing cl_clang_storage_class_specifiers define" #endif -#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers: enable +#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable + +#ifndef __cl_clang_function_pointers +#error "Missing __cl_clang_function_pointers define" +#endif +#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable #ifdef cl_khr_fp16 #error "Incorrect cl_khr_fp16 define" diff --git a/clang/test/Misc/r600.languageOptsOpenCL.cl b/clang/test/Misc/r600.languageOptsOpenCL.cl index e0d3022f3e4a..2b93e53ee34c 100644 --- a/clang/test/Misc/r600.languageOptsOpenCL.cl +++ b/clang/test/Misc/r600.languageOptsOpenCL.cl @@ -28,7 +28,12 @@ #ifndef cl_clang_storage_class_specifiers #error "Missing cl_clang_storage_class_specifiers define" #endif -#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers: enable +#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable + +#ifndef __cl_clang_function_pointers +#error "Missing __cl_clang_function_pointers define" +#endif +#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable #ifdef cl_khr_fp16 #error "Incorrect cl_khr_fp16 define" diff --git a/clang/test/Parser/opencl-cxx-virtual.cl b/clang/test/Parser/opencl-cxx-virtual.cl index f394a47fadb1..72d463d9c62f 100644 --- a/clang/test/Parser/opencl-cxx-virtual.cl +++ b/clang/test/Parser/opencl-cxx-virtual.cl @@ -1,19 +1,32 @@ // RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -fsyntax-only -verify +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -fsyntax-only -verify -DFUNCPTREXT -// Test that virtual functions and abstract classes are rejected. +#ifdef FUNCPTREXT +#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable +//expected-no-diagnostics +#endif + +// Test that virtual functions and abstract classes are rejected +// unless specific clang extension is used. class virtual_functions { virtual void bad1() {} - //expected-error@-1 {{virtual functions are not supported in C++ for OpenCL}} +#ifndef FUNCPTREXT + //expected-error@-2 {{virtual functions are not supported in C++ for OpenCL}} +#endif virtual void bad2() = 0; - //expected-error@-1 {{virtual functions are not supported in C++ for OpenCL}} - //expected-error@-2 {{'bad2' is not virtual and cannot be declared pure}} +#ifndef FUNCPTREXT + //expected-error@-2 {{virtual functions are not supported in C++ for OpenCL}} + //expected-error@-3 {{'bad2' is not virtual and cannot be declared pure}} +#endif }; template <typename T> class X { virtual T f(); - //expected-error@-1 {{virtual functions are not supported in C++ for OpenCL}} +#ifndef FUNCPTREXT + //expected-error@-2 {{virtual functions are not supported in C++ for OpenCL}} +#endif }; // Test that virtual base classes are allowed. diff --git a/clang/test/SemaOpenCL/extension-version.cl b/clang/test/SemaOpenCL/extension-version.cl index cbffb31e906f..e7a2150b9918 100644 --- a/clang/test/SemaOpenCL/extension-version.cl +++ b/clang/test/SemaOpenCL/extension-version.cl @@ -17,7 +17,12 @@ #ifndef cl_clang_storage_class_specifiers #error "Missing cl_clang_storage_class_specifiers define" #endif -#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers: enable +#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable + +#ifndef __cl_clang_function_pointers +#error "Missing __cl_clang_function_pointers define" +#endif +#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable #ifndef cl_khr_fp16 #error "Missing cl_khr_fp16 define" diff --git a/clang/test/SemaOpenCL/func.cl b/clang/test/SemaOpenCL/func.cl index 83c3b4a6bcf9..0ba5f73486fa 100644 --- a/clang/test/SemaOpenCL/func.cl +++ b/clang/test/SemaOpenCL/func.cl @@ -1,16 +1,26 @@ // RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -triple spir-unknown-unknown +// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -triple spir-unknown-unknown -DFUNCPTREXT + +#ifdef FUNCPTREXT +#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable +#endif // Variadic functions void vararg_f(int, ...); // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}} void __vararg_f(int, ...); typedef void (*vararg_fptr_t)(int, ...); // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}} - // expected-error@-1{{pointers to functions are not allowed}} +#ifndef FUNCPTREXT +// expected-error@-2 {{pointers to functions are not allowed}} +#endif int printf(__constant const char *st, ...); // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}} // Struct type with function pointer field typedef struct s { - void (*f)(struct s *self, int *i); // expected-error{{pointers to functions are not allowed}} + void (*f)(struct s *self, int *i); +#ifndef FUNCPTREXT +// expected-error@-2 {{pointers to functions are not allowed}} +#endif } s_t; //Function pointer @@ -22,7 +32,10 @@ void bar(); void bar() { // declaring a function pointer is an error - void (*fptr)(int); // expected-error{{pointers to functions are not allowed}} + void (*fptr)(int); +#ifndef FUNCPTREXT + // expected-error@-2 {{pointers to functions are not allowed}} +#endif // taking the address of a function is an error foo((void*)foo); // expected-error{{taking address of function is not allowed}} diff --git a/clang/test/SemaOpenCLCXX/members.cl b/clang/test/SemaOpenCLCXX/members.cl index 699619ccbe48..d561445eb8a2 100644 --- a/clang/test/SemaOpenCLCXX/members.cl +++ b/clang/test/SemaOpenCLCXX/members.cl @@ -1,6 +1,13 @@ //RUN: %clang_cc1 %s -triple spir -cl-std=clc++ -verify -fsyntax-only +//RUN: %clang_cc1 %s -triple spir -cl-std=clc++ -verify -fsyntax-only -DFUNCPTREXT + +#ifdef FUNCPTREXT +#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable +//expected-no-diagnostics +#endif // Check that pointer to member functions are diagnosed +// unless specific clang extension is enabled. struct C { void f(int n); }; @@ -12,11 +19,25 @@ template <class T> struct remove_reference<T &> { typedef T type; }; template <typename T> void templ_test() { - typename remove_reference<T>::type *ptr; //expected-error{{pointers to functions are not allowed}} + typename remove_reference<T>::type *ptr; +#ifndef FUNCPTREXT + //expected-error@-2{{pointers to functions are not allowed}} +#endif } void test() { - void (C::*p)(int); //expected-error{{pointers to functions are not allowed}} - p_t p1; //expected-error{{pointers to functions are not allowed}} - templ_test<int (&)()>(); //expected-note{{in instantiation of function template specialization}} + void (C::*p)(int); +#ifndef FUNCPTREXT +//expected-error@-2{{pointers to functions are not allowed}} +#endif + + p_t p1; +#ifndef FUNCPTREXT +//expected-error@-2{{pointers to functions are not allowed}} +#endif + + templ_test<int (&)()>(); +#ifndef FUNCPTREXT +//expected-note@-2{{in instantiation of function template specialization}} +#endif } _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits