Skip to content

Commit 4fde2b6

Browse files
author
Anastasia Stulova
committed
[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
1 parent badc760 commit 4fde2b6

File tree

14 files changed

+153
-27
lines changed

14 files changed

+153
-27
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,6 +1722,58 @@ syntax to be used with ``std::complex`` with the same meaning.)
17221722
For GCC compatibility, ``__builtin_complex(re, im)`` can also be used to
17231723
construct a complex number from the given real and imaginary components.
17241724
1725+
OpenCL Features
1726+
===============
1727+
1728+
Clang supports internal OpenCL extensions documented below.
1729+
1730+
``__cl_clang_function_pointers``
1731+
--------------------------------
1732+
1733+
With this extension it is possible to enable various language features that
1734+
are relying on function pointers using regular OpenCL extension pragma
1735+
mechanism detailed in `the OpenCL Extension Specification,
1736+
section 1.2
1737+
<https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_Ext.html#extensions-overview>`_.
1738+
1739+
In C++ for OpenCL this also enables:
1740+
1741+
- Use of member function pointers;
1742+
1743+
- Unrestricted use of references to functions;
1744+
1745+
- Virtual member functions.
1746+
1747+
Such functionality is not conformant and does not guarantee to compile
1748+
correctly in any circumstances. It can be used if:
1749+
1750+
- the kernel source does not contain call expressions to (member-) function
1751+
pointers, or virtual functions. For example this extension can be used in
1752+
metaprogramming algorithms to be able to specify/detect types generically.
1753+
1754+
- the generated kernel binary does not contain indirect calls because they
1755+
are eliminated using compiler optimizations e.g. devirtualization.
1756+
1757+
- the selected target supports the function pointer like functionality e.g.
1758+
most CPU targets.
1759+
1760+
**Example of Use**:
1761+
1762+
.. code-block:: c++
1763+
1764+
#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
1765+
void foo()
1766+
{
1767+
void (*fp)(); // compiled - no diagnostic generated
1768+
}
1769+
1770+
#pragma OPENCL EXTENSION __cl_clang_function_pointers : disable
1771+
void bar()
1772+
{
1773+
void (*fp)(); // error - pointers to function are not allowed
1774+
}
1775+
1776+
17251777
Builtin Functions
17261778
=================
17271779

clang/include/clang/Basic/OpenCLExtensions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ OPENCLEXT_INTERNAL(cl_khr_subgroups, 200, ~0U)
6969

7070
// Clang Extensions.
7171
OPENCLEXT_INTERNAL(cl_clang_storage_class_specifiers, 100, ~0U)
72+
OPENCLEXT_INTERNAL(__cl_clang_function_pointers, 100, ~0U)
7273

7374
// AMD OpenCL extensions
7475
OPENCLEXT_INTERNAL(cl_amd_media_ops, 100, ~0U)

clang/lib/Basic/Targets/AMDGPU.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
285285
void setSupportedOpenCLOpts() override {
286286
auto &Opts = getSupportedOpenCLOpts();
287287
Opts.support("cl_clang_storage_class_specifiers");
288+
Opts.support("__cl_clang_function_pointers");
288289

289290
bool IsAMDGCN = isAMDGCN(getTriple());
290291

clang/lib/Basic/Targets/NVPTX.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
128128
void setSupportedOpenCLOpts() override {
129129
auto &Opts = getSupportedOpenCLOpts();
130130
Opts.support("cl_clang_storage_class_specifiers");
131+
Opts.support("__cl_clang_function_pointers");
131132

132133
Opts.support("cl_khr_fp64");
133134
Opts.support("cl_khr_byte_addressable_store");

clang/lib/Parse/ParseDecl.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3630,12 +3630,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
36303630
case tok::kw_virtual:
36313631
// C++ for OpenCL does not allow virtual function qualifier, to avoid
36323632
// function pointers restricted in OpenCL v2.0 s6.9.a.
3633-
if (getLangOpts().OpenCLCPlusPlus) {
3633+
if (getLangOpts().OpenCLCPlusPlus &&
3634+
!getActions().getOpenCLOptions().isEnabled(
3635+
"__cl_clang_function_pointers")) {
36343636
DiagID = diag::err_openclcxx_virtual_function;
36353637
PrevSpec = Tok.getIdentifierInfo()->getNameStart();
36363638
isInvalid = true;
3637-
}
3638-
else {
3639+
} else {
36393640
isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID);
36403641
}
36413642
break;

clang/lib/Sema/SemaDecl.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6748,14 +6748,16 @@ static bool diagnoseOpenCLTypes(Scope *S, Sema &Se, Declarator &D,
67486748
}
67496749

67506750
// OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed.
6751-
QualType NR = R;
6752-
while (NR->isPointerType() || NR->isMemberFunctionPointerType()) {
6753-
if (NR->isFunctionPointerType() || NR->isMemberFunctionPointerType()) {
6754-
Se.Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer);
6755-
D.setInvalidType();
6756-
return false;
6751+
if (!Se.getOpenCLOptions().isEnabled("__cl_clang_function_pointers")) {
6752+
QualType NR = R;
6753+
while (NR->isPointerType() || NR->isMemberFunctionPointerType()) {
6754+
if (NR->isFunctionPointerType() || NR->isMemberFunctionPointerType()) {
6755+
Se.Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer);
6756+
D.setInvalidType();
6757+
return false;
6758+
}
6759+
NR = NR->getPointeeType();
67576760
}
6758-
NR = NR->getPointeeType();
67596761
}
67606762

67616763
if (!Se.getOpenCLOptions().isEnabled("cl_khr_fp16")) {

clang/lib/Sema/SemaType.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2089,7 +2089,8 @@ QualType Sema::BuildPointerType(QualType T,
20892089
return QualType();
20902090
}
20912091

2092-
if (T->isFunctionType() && getLangOpts().OpenCL) {
2092+
if (T->isFunctionType() && getLangOpts().OpenCL &&
2093+
!getOpenCLOptions().isEnabled("__cl_clang_function_pointers")) {
20932094
Diag(Loc, diag::err_opencl_function_pointer);
20942095
return QualType();
20952096
}

clang/test/Misc/amdgcn.languageOptsOpenCL.cl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@
1212
#ifndef cl_clang_storage_class_specifiers
1313
#error "Missing cl_clang_storage_class_specifiers define"
1414
#endif
15-
#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers: enable
15+
#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable
16+
17+
#ifndef __cl_clang_function_pointers
18+
#error "Missing __cl_clang_function_pointers define"
19+
#endif
20+
#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
1621

1722
#ifndef cl_khr_fp16
1823
#error "Missing cl_khr_fp16 define"

clang/test/Misc/nvptx.languageOptsOpenCL.cl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@
2020
#ifndef cl_clang_storage_class_specifiers
2121
#error "Missing cl_clang_storage_class_specifiers define"
2222
#endif
23-
#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers: enable
23+
#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable
24+
25+
#ifndef __cl_clang_function_pointers
26+
#error "Missing __cl_clang_function_pointers define"
27+
#endif
28+
#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
2429

2530
#ifdef cl_khr_fp16
2631
#error "Incorrect cl_khr_fp16 define"

clang/test/Misc/r600.languageOptsOpenCL.cl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@
2828
#ifndef cl_clang_storage_class_specifiers
2929
#error "Missing cl_clang_storage_class_specifiers define"
3030
#endif
31-
#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers: enable
31+
#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable
32+
33+
#ifndef __cl_clang_function_pointers
34+
#error "Missing __cl_clang_function_pointers define"
35+
#endif
36+
#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
3237

3338
#ifdef cl_khr_fp16
3439
#error "Incorrect cl_khr_fp16 define"

clang/test/Parser/opencl-cxx-virtual.cl

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
11
// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -fsyntax-only -verify
2+
// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -fsyntax-only -verify -DFUNCPTREXT
23

3-
// Test that virtual functions and abstract classes are rejected.
4+
#ifdef FUNCPTREXT
5+
#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
6+
//expected-no-diagnostics
7+
#endif
8+
9+
// Test that virtual functions and abstract classes are rejected
10+
// unless specific clang extension is used.
411
class virtual_functions {
512
virtual void bad1() {}
6-
//expected-error@-1 {{virtual functions are not supported in C++ for OpenCL}}
13+
#ifndef FUNCPTREXT
14+
//expected-error@-2 {{virtual functions are not supported in C++ for OpenCL}}
15+
#endif
716

817
virtual void bad2() = 0;
9-
//expected-error@-1 {{virtual functions are not supported in C++ for OpenCL}}
10-
//expected-error@-2 {{'bad2' is not virtual and cannot be declared pure}}
18+
#ifndef FUNCPTREXT
19+
//expected-error@-2 {{virtual functions are not supported in C++ for OpenCL}}
20+
//expected-error@-3 {{'bad2' is not virtual and cannot be declared pure}}
21+
#endif
1122
};
1223

1324
template <typename T>
1425
class X {
1526
virtual T f();
16-
//expected-error@-1 {{virtual functions are not supported in C++ for OpenCL}}
27+
#ifndef FUNCPTREXT
28+
//expected-error@-2 {{virtual functions are not supported in C++ for OpenCL}}
29+
#endif
1730
};
1831

1932
// Test that virtual base classes are allowed.

clang/test/SemaOpenCL/extension-version.cl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717
#ifndef cl_clang_storage_class_specifiers
1818
#error "Missing cl_clang_storage_class_specifiers define"
1919
#endif
20-
#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers: enable
20+
#pragma OPENCL EXTENSION cl_clang_storage_class_specifiers : enable
21+
22+
#ifndef __cl_clang_function_pointers
23+
#error "Missing __cl_clang_function_pointers define"
24+
#endif
25+
#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
2126

2227
#ifndef cl_khr_fp16
2328
#error "Missing cl_khr_fp16 define"

clang/test/SemaOpenCL/func.cl

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -triple spir-unknown-unknown
2+
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -triple spir-unknown-unknown -DFUNCPTREXT
3+
4+
#ifdef FUNCPTREXT
5+
#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
6+
#endif
27

38
// Variadic functions
49
void vararg_f(int, ...); // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}}
510
void __vararg_f(int, ...);
611
typedef void (*vararg_fptr_t)(int, ...); // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}}
7-
// expected-error@-1{{pointers to functions are not allowed}}
12+
#ifndef FUNCPTREXT
13+
// expected-error@-2 {{pointers to functions are not allowed}}
14+
#endif
815
int printf(__constant const char *st, ...); // expected-error {{invalid prototype, variadic arguments are not allowed in OpenCL}}
916

1017
// Struct type with function pointer field
1118
typedef struct s
1219
{
13-
void (*f)(struct s *self, int *i); // expected-error{{pointers to functions are not allowed}}
20+
void (*f)(struct s *self, int *i);
21+
#ifndef FUNCPTREXT
22+
// expected-error@-2 {{pointers to functions are not allowed}}
23+
#endif
1424
} s_t;
1525

1626
//Function pointer
@@ -22,7 +32,10 @@ void bar();
2232
void bar()
2333
{
2434
// declaring a function pointer is an error
25-
void (*fptr)(int); // expected-error{{pointers to functions are not allowed}}
35+
void (*fptr)(int);
36+
#ifndef FUNCPTREXT
37+
// expected-error@-2 {{pointers to functions are not allowed}}
38+
#endif
2639

2740
// taking the address of a function is an error
2841
foo((void*)foo); // expected-error{{taking address of function is not allowed}}

clang/test/SemaOpenCLCXX/members.cl

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
//RUN: %clang_cc1 %s -triple spir -cl-std=clc++ -verify -fsyntax-only
2+
//RUN: %clang_cc1 %s -triple spir -cl-std=clc++ -verify -fsyntax-only -DFUNCPTREXT
3+
4+
#ifdef FUNCPTREXT
5+
#pragma OPENCL EXTENSION __cl_clang_function_pointers : enable
6+
//expected-no-diagnostics
7+
#endif
28

39
// Check that pointer to member functions are diagnosed
10+
// unless specific clang extension is enabled.
411
struct C {
512
void f(int n);
613
};
@@ -12,11 +19,25 @@ template <class T> struct remove_reference<T &> { typedef T type; };
1219

1320
template <typename T>
1421
void templ_test() {
15-
typename remove_reference<T>::type *ptr; //expected-error{{pointers to functions are not allowed}}
22+
typename remove_reference<T>::type *ptr;
23+
#ifndef FUNCPTREXT
24+
//expected-error@-2{{pointers to functions are not allowed}}
25+
#endif
1626
}
1727

1828
void test() {
19-
void (C::*p)(int); //expected-error{{pointers to functions are not allowed}}
20-
p_t p1; //expected-error{{pointers to functions are not allowed}}
21-
templ_test<int (&)()>(); //expected-note{{in instantiation of function template specialization}}
29+
void (C::*p)(int);
30+
#ifndef FUNCPTREXT
31+
//expected-error@-2{{pointers to functions are not allowed}}
32+
#endif
33+
34+
p_t p1;
35+
#ifndef FUNCPTREXT
36+
//expected-error@-2{{pointers to functions are not allowed}}
37+
#endif
38+
39+
templ_test<int (&)()>();
40+
#ifndef FUNCPTREXT
41+
//expected-note@-2{{in instantiation of function template specialization}}
42+
#endif
2243
}

0 commit comments

Comments
 (0)