forked from OSchip/llvm-project
[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
This commit is contained in:
parent
badc7606b0
commit
4fde2b6a0c
|
@ -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
|
||||
=================
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -285,6 +285,7 @@ public:
|
|||
void setSupportedOpenCLOpts() override {
|
||||
auto &Opts = getSupportedOpenCLOpts();
|
||||
Opts.support("cl_clang_storage_class_specifiers");
|
||||
Opts.support("__cl_clang_function_pointers");
|
||||
|
||||
bool IsAMDGCN = isAMDGCN(getTriple());
|
||||
|
||||
|
|
|
@ -128,6 +128,7 @@ public:
|
|||
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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue