From e994e74bca49831eb649e7c67955e9de7a1784b6 Mon Sep 17 00:00:00 2001 From: Anastasia Stulova Date: Wed, 5 May 2021 13:18:00 +0100 Subject: [PATCH] [OpenCL] Add clang extension for non-portable kernel parameters. 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 --- clang/docs/LanguageExtensions.rst | 48 ++++++++++++++++++++++++++ clang/include/clang/Basic/OpenCLExtensions.def | 1 + clang/lib/Basic/Targets/AMDGPU.h | 1 + clang/lib/Basic/Targets/NVPTX.h | 1 + clang/lib/Sema/SemaDecl.cpp | 16 ++++++--- clang/test/Misc/amdgcn.languageOptsOpenCL.cl | 5 +++ clang/test/Misc/nvptx.languageOptsOpenCL.cl | 5 +++ clang/test/Misc/r600.languageOptsOpenCL.cl | 5 +++ clang/test/SemaOpenCLCXX/invalid-kernel.clcpp | 36 +++++++++++++++---- 9 files changed, 107 insertions(+), 11 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 5e53828..bdb5b3a 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -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 +`_. +The restrictions can be relaxed using regular OpenCL extension pragma mechanism +detailed in `the OpenCL Extension Specification, section 1.2 +`_. + +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 --------------------------------------------- diff --git a/clang/include/clang/Basic/OpenCLExtensions.def b/clang/include/clang/Basic/OpenCLExtensions.def index 5e2977f..a0f01a2 100644 --- a/clang/include/clang/Basic/OpenCLExtensions.def +++ b/clang/include/clang/Basic/OpenCLExtensions.def @@ -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) diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h index 8ee0ca3..b2d422c 100644 --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -287,6 +287,7 @@ public: 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()); diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h index 9e80473..b7b0aae 100644 --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -133,6 +133,7 @@ public: 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; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 1abb692..c1aa6383 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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 || @@ -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; @@ -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()) diff --git a/clang/test/Misc/amdgcn.languageOptsOpenCL.cl b/clang/test/Misc/amdgcn.languageOptsOpenCL.cl index 1dd3102..7fc4e7e 100644 --- a/clang/test/Misc/amdgcn.languageOptsOpenCL.cl +++ b/clang/test/Misc/amdgcn.languageOptsOpenCL.cl @@ -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 diff --git a/clang/test/Misc/nvptx.languageOptsOpenCL.cl b/clang/test/Misc/nvptx.languageOptsOpenCL.cl index d547f4d..6657c18 100644 --- a/clang/test/Misc/nvptx.languageOptsOpenCL.cl +++ b/clang/test/Misc/nvptx.languageOptsOpenCL.cl @@ -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 diff --git a/clang/test/Misc/r600.languageOptsOpenCL.cl b/clang/test/Misc/r600.languageOptsOpenCL.cl index 2c87370..80c628a 100644 --- a/clang/test/Misc/r600.languageOptsOpenCL.cl +++ b/clang/test/Misc/r600.languageOptsOpenCL.cl @@ -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 diff --git a/clang/test/SemaOpenCLCXX/invalid-kernel.clcpp b/clang/test/SemaOpenCLCXX/invalid-kernel.clcpp index 977d487..9bd1473 100644 --- a/clang/test/SemaOpenCLCXX/invalid-kernel.clcpp +++ b/clang/test/SemaOpenCLCXX/invalid-kernel.clcpp @@ -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}} @@ -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); @@ -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) {} @@ -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 -- 2.7.4