Skip to content

Commit

Permalink
[OpenCL] Add clang extension for non-portable kernel parameters.
Browse files Browse the repository at this point in the history
Added __cl_clang_non_portable_kernel_param_types extension that
allows using non-portable types as kernel parameters. This allows
bypassing the portability guarantees from the restrictions specified
in C++ for OpenCL v1.0 s2.4.

Currently this only disables the restrictions related to the data
layout. The programmer should ensure the compiler generates the same
layout for host and device or otherwise the argument should only be
accessed on the device side. This extension could be extended to other
case (e.g. permitting size_t) if desired in the future.

Patch by olestrohm (Ole Strohm)!

https://reviews.llvm.org/D101168
  • Loading branch information
Anastasia Stulova committed May 5, 2021
1 parent f6ef409 commit e994e74
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 11 deletions.
48 changes: 48 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1813,6 +1813,54 @@ supporting the variadic arguments e.g. majority of CPU targets.
#pragma OPENCL EXTENSION __cl_clang_variadic_functions : disable
void bar(int a, ...); // error - variadic prototype is not allowed
``__cl_clang_non_portable_kernel_param_types``
---------------------------------------------
With this extension it is possible to enable the use of some restricted types
in kernel parameters specified in `C++ for OpenCL v1.0 s2.4
<https://www.khronos.org/opencl/assets/CXX_for_OpenCL.html#kernel_function>`_.
The restrictions can be relaxed 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>`_.
This is not a conformant behavior and it can only be used when the
kernel arguments are not accessed on the host side or the data layout/size
between the host and device is known to be compatible.
**Example of Use**:
.. code-block:: c++
// Plain Old Data type.
struct Pod {
int a;
int b;
};
// Not POD type because of the constructor.
// Standard layout type because there is only one access control.
struct OnlySL {
int a;
int b;
NotPod() : a(0), b(0) {}
};
// Not standard layout type because of two different access controls.
struct NotSL {
int a;
private:
int b;
}
kernel void kernel_main(
Pod a,
#pragma OPENCL EXTENSION __cl_clang_non_portable_kernel_param_types : enable
OnlySL b,
global NotSL *c,
#pragma OPENCL EXTENSION __cl_clang_non_portable_kernel_param_types : disable
global OnlySL *d,
);
Legacy 1.x atomics with generic address space
---------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/OpenCLExtensions.def
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ OPENCL_EXTENSION(cl_khr_subgroups, true, 200)
OPENCL_EXTENSION(cl_clang_storage_class_specifiers, true, 100)
OPENCL_EXTENSION(__cl_clang_function_pointers, true, 100)
OPENCL_EXTENSION(__cl_clang_variadic_functions, true, 100)
OPENCL_EXTENSION(__cl_clang_non_portable_kernel_param_types, true, 100)

// AMD OpenCL extensions
OPENCL_EXTENSION(cl_amd_media_ops, true, 100)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/AMDGPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
Opts["cl_clang_storage_class_specifiers"] = true;
Opts["__cl_clang_variadic_functions"] = true;
Opts["__cl_clang_function_pointers"] = true;
Opts["__cl_clang_non_portable_kernel_param_types"] = true;

bool IsAMDGCN = isAMDGCN(getTriple());

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/NVPTX.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo {
Opts["cl_clang_storage_class_specifiers"] = true;
Opts["__cl_clang_function_pointers"] = true;
Opts["__cl_clang_variadic_functions"] = true;
Opts["__cl_clang_non_portable_kernel_param_types"] = true;

Opts["cl_khr_fp64"] = true;
Opts["cl_khr_byte_addressable_store"] = true;
Expand Down
16 changes: 12 additions & 4 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8662,6 +8662,9 @@ static bool isOpenCLSizeDependentType(ASTContext &C, QualType Ty) {
}

static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
if (PT->isDependentType())
return InvalidKernelParam;

if (PT->isPointerType() || PT->isReferenceType()) {
QualType PointeeType = PT->getPointeeType();
if (PointeeType.getAddressSpace() == LangAS::opencl_generic ||
Expand All @@ -8684,8 +8687,11 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
// Moreover the types used in parameters of the kernel functions must be:
// Standard layout types for pointer parameters. The same applies to
// reference if an implementation supports them in kernel parameters.
if (S.getLangOpts().OpenCLCPlusPlus && !PointeeType->isAtomicType() &&
!PointeeType->isVoidType() && !PointeeType->isStandardLayoutType())
if (S.getLangOpts().OpenCLCPlusPlus &&
!S.getOpenCLOptions().isAvailableOption(
"__cl_clang_non_portable_kernel_param_types", S.getLangOpts()) &&
!PointeeType->isAtomicType() && !PointeeType->isVoidType() &&
!PointeeType->isStandardLayoutType())
return InvalidKernelParam;

return PtrKernelParam;
Expand Down Expand Up @@ -8725,8 +8731,10 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) {
// Moreover the types used in parameters of the kernel functions must be:
// Trivial and standard-layout types C++17 [basic.types] (plain old data
// types) for parameters passed by value;
if (S.getLangOpts().OpenCLCPlusPlus && !PT->isOpenCLSpecificType() &&
!PT.isPODType(S.Context))
if (S.getLangOpts().OpenCLCPlusPlus &&
!S.getOpenCLOptions().isAvailableOption(
"__cl_clang_non_portable_kernel_param_types", S.getLangOpts()) &&
!PT->isOpenCLSpecificType() && !PT.isPODType(S.Context))
return InvalidKernelParam;

if (PT->isRecordType())
Expand Down
5 changes: 5 additions & 0 deletions clang/test/Misc/amdgcn.languageOptsOpenCL.cl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
#endif
#pragma OPENCL EXTENSION __cl_clang_variadic_functions : enable

#ifndef __cl_clang_non_portable_kernel_param_types
#error "Missing __cl_clang_non_portable_kernel_param_types define"
#endif
#pragma OPENCL EXTENSION __cl_clang_non_portable_kernel_param_types : enable

#ifndef cl_khr_fp16
#error "Missing cl_khr_fp16 define"
#endif
Expand Down
5 changes: 5 additions & 0 deletions clang/test/Misc/nvptx.languageOptsOpenCL.cl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
#endif
#pragma OPENCL EXTENSION __cl_clang_variadic_functions : enable

#ifndef __cl_clang_non_portable_kernel_param_types
#error "Missing __cl_clang_non_portable_kernel_param_types define"
#endif
#pragma OPENCL EXTENSION __cl_clang_non_portable_kernel_param_types : enable

#ifdef cl_khr_fp16
#error "Incorrect cl_khr_fp16 define"
#endif
Expand Down
5 changes: 5 additions & 0 deletions clang/test/Misc/r600.languageOptsOpenCL.cl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
#endif
#pragma OPENCL EXTENSION __cl_clang_variadic_functions : enable

#ifndef __cl_clang_non_portable_kernel_param_types
#error "Missing __cl_clang_non_portable_kernel_param_types define"
#endif
#pragma OPENCL EXTENSION __cl_clang_non_portable_kernel_param_types : enable

#ifdef cl_khr_fp16
#error "Incorrect cl_khr_fp16 define"
#endif
Expand Down
36 changes: 29 additions & 7 deletions clang/test/SemaOpenCLCXX/invalid-kernel.clcpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
// RUN: %clang_cc1 %s -pedantic -verify -fsyntax-only
// RUN: %clang_cc1 %s -pedantic -verify -fsyntax-only -triple spir-unknown-unknown
// RUN: %clang_cc1 %s -pedantic -verify -fsyntax-only -triple spir-unknown-unknown -DUNSAFEKERNELPARAMETER

#ifdef UNSAFEKERNELPARAMETER
#pragma OPENCL EXTENSION __cl_clang_non_portable_kernel_param_types : enable
#endif

struct C {
kernel void m(); //expected-error{{kernel functions cannot be class members}}
Expand All @@ -24,8 +29,10 @@ kernel void int_p_p(__global int *__global *in);
kernel void int_p_r(__global int *__global &in);
kernel void int_p_p_r(__global int *__global *__global &in);

// expected-error@+1{{'__private atomic_int' (aka '__private _Atomic(int)') cannot be used as the type of a kernel parameter}}
kernel void k_atomic_v(atomic_int in);
#ifndef UNSAFEKERNELPARAMETER
// expected-error@-2{{'__private atomic_int' (aka '__private _Atomic(int)') cannot be used as the type of a kernel parameter}}
#endif
kernel void k_atomic_p(__global atomic_int *in);
kernel void k_atomic_r(__global atomic_int &in);

Expand Down Expand Up @@ -56,7 +63,10 @@ struct StandardLayout {
StandardLayout(int a, int b) : a(a), b(b) {}
};

kernel void standard_v(StandardLayout in) {} //expected-error{{'__private StandardLayout' cannot be used as the type of a kernel parameter}}
kernel void standard_v(StandardLayout in) {}
#ifndef UNSAFEKERNELPARAMETER
//expected-error@-2{{'__private StandardLayout' cannot be used as the type of a kernel parameter}}
#endif
kernel void standard_p(__global StandardLayout *in) {}
kernel void standard_p_p(__global StandardLayout *__global *in) {}
kernel void standard_r(__global StandardLayout &in) {}
Expand All @@ -67,7 +77,19 @@ private:
int b;
};

kernel void trivial_v(Trivial in) {} //expected-error{{'__private Trivial' cannot be used as the type of a kernel parameter}}
kernel void trivial_p(__global Trivial *in) {} //expected-error{{'__global Trivial *__private' cannot be used as the type of a kernel parameter}}
kernel void trivial_p_p(__global Trivial *__global *in) {} //expected-error{{'__global Trivial *__global *__private' cannot be used as the type of a kernel parameter}}
kernel void trivial_r(__global Trivial &in) {} //expected-error{{'__global Trivial &__private' cannot be used as the type of a kernel parameter}}
kernel void trivial_v(Trivial in) {}
#ifndef UNSAFEKERNELPARAMETER
//expected-error@-2{{'__private Trivial' cannot be used as the type of a kernel parameter}}
#endif
kernel void trivial_p(__global Trivial *in) {}
#ifndef UNSAFEKERNELPARAMETER
//expected-error@-2{{'__global Trivial *__private' cannot be used as the type of a kernel parameter}}
#endif
kernel void trivial_p_p(__global Trivial *__global *in) {}
#ifndef UNSAFEKERNELPARAMETER
//expected-error@-2{{'__global Trivial *__global *__private' cannot be used as the type of a kernel parameter}}
#endif
kernel void trivial_r(__global Trivial &in) {}
#ifndef UNSAFEKERNELPARAMETER
//expected-error@-2{{'__global Trivial &__private' cannot be used as the type of a kernel parameter}}
#endif

0 comments on commit e994e74

Please sign in to comment.