[llvm-branch-commits] [clang] 4fde2b6 - [OpenCL] Add clang extension for function pointers.

Anastasia Stulova via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jan 6 12:45:09 PST 2021


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 at -1 {{virtual functions are not supported in C++ for OpenCL}}
+#ifndef FUNCPTREXT
+  //expected-error at -2 {{virtual functions are not supported in C++ for OpenCL}}
+#endif
 
   virtual void bad2() = 0;
-  //expected-error at -1 {{virtual functions are not supported in C++ for OpenCL}}
-  //expected-error at -2 {{'bad2' is not virtual and cannot be declared pure}}
+#ifndef FUNCPTREXT
+  //expected-error at -2 {{virtual functions are not supported in C++ for OpenCL}}
+  //expected-error at -3 {{'bad2' is not virtual and cannot be declared pure}}
+#endif
 };
 
 template <typename T>
 class X {
   virtual T f();
-  //expected-error at -1 {{virtual functions are not supported in C++ for OpenCL}}
+#ifndef FUNCPTREXT
+  //expected-error at -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 at -1{{pointers to functions are not allowed}}
+#ifndef FUNCPTREXT
+// expected-error at -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 at -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 at -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 at -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 at -2{{pointers to functions are not allowed}}
+#endif
+
+  p_t p1;
+#ifndef FUNCPTREXT
+//expected-error at -2{{pointers to functions are not allowed}}
+#endif
+
+  templ_test<int (&)()>();
+#ifndef FUNCPTREXT
+//expected-note at -2{{in instantiation of function template specialization}}
+#endif
 }


        


More information about the llvm-branch-commits mailing list