Anastasia created this revision.
Anastasia added a reviewer: mantognini.
Herald added subscribers: ebevhan, kerbowa, yaxunl, nhaehnle, jvesely, 
jholewinski.
Anastasia requested review of this revision.

This feature is primarily important in C++ mode because it opens up more 
opportunities to describe metaprogramming algorithms with function types. It 
can also be used to facilitate virtual functions.

This is clang and not a vendor extension and therefore it is only intended for 
internal or experimental use. The full feature will require changes in vendor 
toolchains that can be provided in the future via either vendor extensions or 
Khronos extensions.


https://reviews.llvm.org/D94021

Files:
  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

Index: clang/test/SemaOpenCLCXX/members.cl
===================================================================
--- clang/test/SemaOpenCLCXX/members.cl
+++ 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 <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
 }
Index: clang/test/SemaOpenCL/func.cl
===================================================================
--- clang/test/SemaOpenCL/func.cl
+++ 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()
 {
   // 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}}
Index: clang/test/SemaOpenCL/extension-version.cl
===================================================================
--- clang/test/SemaOpenCL/extension-version.cl
+++ 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"
Index: clang/test/Parser/opencl-cxx-virtual.cl
===================================================================
--- clang/test/Parser/opencl-cxx-virtual.cl
+++ 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.
Index: clang/test/Misc/r600.languageOptsOpenCL.cl
===================================================================
--- clang/test/Misc/r600.languageOptsOpenCL.cl
+++ 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"
Index: clang/test/Misc/nvptx.languageOptsOpenCL.cl
===================================================================
--- clang/test/Misc/nvptx.languageOptsOpenCL.cl
+++ 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"
Index: clang/test/Misc/amdgcn.languageOptsOpenCL.cl
===================================================================
--- clang/test/Misc/amdgcn.languageOptsOpenCL.cl
+++ 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"
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -2089,7 +2089,8 @@
     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();
   }
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -6747,14 +6747,16 @@
   }
 
   // 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")) {
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -3630,12 +3630,13 @@
     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;
Index: clang/lib/Basic/Targets/NVPTX.h
===================================================================
--- clang/lib/Basic/Targets/NVPTX.h
+++ clang/lib/Basic/Targets/NVPTX.h
@@ -128,6 +128,7 @@
   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");
Index: clang/lib/Basic/Targets/AMDGPU.h
===================================================================
--- clang/lib/Basic/Targets/AMDGPU.h
+++ clang/lib/Basic/Targets/AMDGPU.h
@@ -285,6 +285,7 @@
   void setSupportedOpenCLOpts() override {
     auto &Opts = getSupportedOpenCLOpts();
     Opts.support("cl_clang_storage_class_specifiers");
+    Opts.support("__cl_clang_function_pointers");
 
     bool IsAMDGCN = isAMDGCN(getTriple());
 
Index: clang/include/clang/Basic/OpenCLExtensions.def
===================================================================
--- clang/include/clang/Basic/OpenCLExtensions.def
+++ clang/include/clang/Basic/OpenCLExtensions.def
@@ -69,6 +69,7 @@
 
 // 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)
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -1722,6 +1722,55 @@
 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
 =================
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D94021: [OpenCL]... Anastasia Stulova via Phabricator via cfe-commits

Reply via email to