[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