From ad47d5ebe71e02f241a25fe7151a64e5d96dbb65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C5=BDu=C5=BEek?= Date: Sat, 21 Sep 2019 09:53:57 +0100 Subject: [PATCH] Casting accessors 1. Implicit conversion to `const dataT` 2. Type traits for `const` conversions * For resolving access modes 3. Free functions for casting accessors * `static_pointer_cast`, `dynamic_pointer_cast`, `const_pointer_cast`, `reinterpret_pointer_cast` 4. Converting to a type of a different size requires `get_count`, `get_range`, and `get_offset` to return different values than the original accessor 5. Examples for all casts --- README.md | 1 + accessor-cast/index.md | 20 ++ accessor-cast/sycl-2.2/index.md | 318 ++++++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 accessor-cast/index.md create mode 100644 accessor-cast/sycl-2.2/index.md diff --git a/README.md b/README.md index b2a1dc8..258646e 100644 --- a/README.md +++ b/README.md @@ -57,3 +57,4 @@ Each proposal in the table below will be tagged with one of the following states | CP017 | [Host Access](host_access/index.md) | SYCL 1.2.1 vendor extension | 17 September 2018 | 13 December 2018 | _Available since CE 1.0.3_ | | CP018 | [Built-in kernels](builtin_kernels/index.md) | SYCL 1.2.1 vendor extension | 12 October 2018 | 12 October 2018 | _Available since CE 1.0.3_ | | CP019 | [On-chip Memory Allocation](onchip-memory/index.md) | SYCL 1.2.1 vendor extension | 03 December 2018 | 03 December 2018 | _Available since CE 1.0.3_ | +| CP021 | [Casting accessors](accessor-cast/index.md) | SYCL 1.2.1 vendor extension | 21 September 2019 | 21 September 2019 | _Work in Progress_ | diff --git a/accessor-cast/index.md b/accessor-cast/index.md new file mode 100644 index 0000000..2b6a728 --- /dev/null +++ b/accessor-cast/index.md @@ -0,0 +1,20 @@ +# Casting accessors + +| Proposal ID | CP021 | +|-------------|--------| +| Name | Casting accessors | +| Date of Creation | 21 September 2019 | +| Target | SYCL 1.2.1 vendor extension | +| Current Status | _Work in Progress_ | +| Reply-to | Peter Žužek | +| Original author | Peter Žužek | +| Contributors | | + +## Overview + +This paper proposes the addition of pointer casting functions to SYCL +in order to simplify casting of the `accessor` class. + +## Versions + +[Version 1](sycl-2.2/index.md) diff --git a/accessor-cast/sycl-2.2/index.md b/accessor-cast/sycl-2.2/index.md new file mode 100644 index 0000000..b6ff2a0 --- /dev/null +++ b/accessor-cast/sycl-2.2/index.md @@ -0,0 +1,318 @@ +# Casting accessors + +## Motivation + +The current SYCL 1.2.1 specification allows casting buffers +using the `reinterpret` member function. +This essentially provides a different view of the same data, +however it cannot be performed inside a kernel. + +One option would be to cast the `multi_ptr` obtained from an accessor. +However, that is a separate proposal, +plus it would add another layer of first obtaining the pointer +and then using that pointer instead of the accessor. + +## Summary + +This proposal adds an implicit conversion operator +to a const-qualified accessor type +as a member function of the `accessor` class, +and also adds several free functions to the `cl::sycl` namespace +that follow the naming and semantics of the `std::shared_ptr` pointer cast functions +defined by the C++17 standard: https://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast. +In order to help with the `const` conversions +we also propose adding a few type traits. + +## Const casting type traits + +In order to help with casting the const qualifier, +we propose adding a few type traits: +1. `add_const_access` - +resolves any access mode to `access::mode::read`, +except for `access::mode::atomic`, +which resolves to the same mode. +2. `remove_const_access` - +resolves `access::mode::read` to `access::mode::read_write`, +and keeps all other modes the same. +3. `access_mode_from_const` - +takes an access mode and two types +and then decides, based on the types, +whether to use `add_const_access`, `remove_const_access`, or none, +in order to resolve the access mode. + +```cpp +namespace cl { +namespace sycl { + +/// add_const_access +template +struct add_const_access { + static constexpr auto value = access::mode::read; +}; +template <> +struct add_const_access { + static constexpr auto value = access::mode::atomic; +}; + +/// remove_const_access +template +struct remove_const_access { + static constexpr auto value = mode; +}; +template <> +struct remove_const_access { + static constexpr auto value = access::mode::read_write; +}; + +/// access_mode_from_const +template +struct access_mode_from_const { + static constexpr auto value = mode; +}; +template +struct access_mode_from_const< + mode, const oldT, const newT> + : access_mode_from_const< + mode, oldT, newT> {}; +template +struct access_mode_from_const< + mode, const oldT, newT> + : access_mode_from_const< + remove_const_access::value, oldT, newT> {}; +template +struct access_mode_from_const< + mode, oldT, const newT> + : access_mode_from_const< + add_const_access::value, oldT, newT> {}; + +} // namespace sycl +} // namespace cl +``` + +## Conversion operator + +The new interface of the `accessor` class would look like this: + +```cpp +namespace cl { +namespace sycl { + +template +class accessor { + public: + /// All existing members here + + ... + + // Implicit conversion to `const dataT` + operator accessor::value, + accTarget, + isPlaceholder>() const; +}; + +} // namespace sycl +} // namespace cl +``` + +| Member function | Description | +|-----------------|-------------| +| *`operator accessor::value, accTarget, isPlaceholder>() const`* | Returns a new accessor of type `const dataT`. The access mode of the new accessor is a read-only mode. | + +## Conversion functions + +In addition to the conversion operator, +we propose adding the following free functions to the `cl::sycl` namespace: + +```cpp +namespace cl { +namespace sycl { + +// Performs a static_cast of the contained pointer +template +accessor::value, + accTarget, + isPlaceholder> +static_pointer_cast( + const accessor< + dataT, dimensions, accMode, accTarget, isPlaceholder>& + acc); + +// Performs a dynamic_cast of the contained pointer +template +accessor +dynamic_pointer_cast( + const accessor< + dataT, dimensions, accMode, accTarget, isPlaceholder>& + acc); + +// Performs a const_cast of the contained pointer +template +accessor::value, + accTarget, + isPlaceholder> +const_pointer_cast( + const accessor< + dataT, dimensions, accMode, accTarget, isPlaceholder>& + acc); + +// Performs a reinterpret_cast of the contained pointer +template +accessor +reinterpret_pointer_cast( + const accessor< + dataT, dimensions, accMode, accTarget, isPlaceholder>& + acc); + +} // namespace sycl +} // namespace cl +``` + +The following function declarations are simplified +in order to reduce table verbosity. +For full declarations see the code above. + +| Function | Description | +|-----------------|-------------| +| *`template accessor static_pointer_cast(const accessor& acc)`* | Performs a `static_cast` of the underlying pointer `dataT*` contained within `acc` to `dataU*` and returns a new `accessor` instance containing the cast pointer. When casting from a non-`const` to a `const` type, `add_const_access` is used to resolve the access mode. All other template parameters stay the same. This conversion is only valid if the `static_cast` from `dataT*` to `dataU*` is valid. | +| *`template accessor dynamic_pointer_cast(const accessor& acc)`* | Performs a `dynamic_cast` of the underlying pointer `dataT*` contained within `acc` to `dataU*` and returns a new `accessor` instance containing the cast pointer. All other template parameters stay the same. This conversion is only valid if the `dynamic_cast` from `dataT*` to `dataU*` is valid. If `sizeof(dataT) != sizeof(dataU)`, member functions `get_count()`, `get_range()`, and `get_offset()` of the returned accessor return values appropriate to the new type size. | +| *`template accessor const_pointer_cast(const accessor& acc)`* | Performs a `const_cast` of the underlying pointer `dataT*` contained within `acc` to `dataU*` and returns a new `accessor` instance containing the cast pointer. `access_mode_from_const` is used to resolve the access mode. All other template parameters stay the same. This conversion is only valid if the `const_cast` from `dataT*` to `dataU*` is valid. | +| *`template accessor reinterpret_pointer_cast(const accessor& acc)`* | Performs a `reinterpret_cast` of the underlying pointer `dataT*` contained within `acc` to `dataU*` and returns a new `accessor` instance containing the cast pointer. All other template parameters stay the same. This conversion is only valid if the `reinterpret_cast` from `dataT*` to `dataU*` is valid. If `sizeof(dataT) != sizeof(dataU)`, member functions `get_count()`, `get_range()`, and `get_offset()` of the returned accessor return values appropriate to the new type size. | + +## Examples + +All examples use + `dimensions == 1`, + `accTarget == access::target::global_buffer`, + and `isPlaceholder == access::placeholder::false_t`, +but they should generally apply to all accessor types. + +### Simple casts + +```cpp +using namespace cl::sycl; +static constexpr auto accTarget = access::target::global_buffer; + +// Obtain some accessors +accessor + accIntR = + buf.get_access(cgh); +accessor + accIntW = + buf.get_access(cgh); +accessor + accIntRW = + buf.get_access(cgh); +accessor + accIntCR = + buf.get_access(cgh); + +// Conversion operator +auto rAccIntCR = static_cast< + accessor>( + accIntR); +auto rAccIntCW = static_cast< + accessor>( + accIntW); +auto rAccIntCRW = static_cast< + accessor>( + accIntRW); +auto rAccIntCCR = static_cast< + accessor>( + accIntCR); + +// static_pointer_cast +accessor + rAccIntCR2 = static_pointer_cast(accIntR); +accessor + rAccIntCW2 = static_pointer_cast(accIntW); +accessor + rAccIntCRW2 = static_pointer_cast(accIntRW); +accessor + rAccIntCCR2 = static_pointer_cast(accIntCR); + +// const_pointer_cast +accessor + rAccIntR = const_pointer_cast(accIntR); +accessor + rAccIntW = const_pointer_cast(accIntW); +accessor + rAccIntRW = const_pointer_cast(accIntRW); +accessor + rAccIntCR3 = const_pointer_cast(accIntCR); + +// reinterpret_pointer_cast +accessor + rAccFloatR = reinterpret_pointer_cast(accIntR); +accessor + rAccFloatW = reinterpret_pointer_cast(accIntW); +accessor + rAccFloatRW = reinterpret_pointer_cast(accIntRW); +accessor + rAccFloatCR3 = reinterpret_pointer_cast(accIntCR); + +``` + +### `dynamic_pointer_cast` + +All of these examples also use the same access mode for all casts. + +```cpp +using namespace cl::sycl; +static constexpr auto accMode = access::mode::read_write; +static constexpr auto accTarget = access::target::global_buffer; + +struct Base { + virtual void foo() const {} + virtual ~Base(){} +}; +struct Derived : public Base { + void foo() const override {} +}; + +accessor + accBase = + buf.get_access(cgh); + +accessor + accDerived = dynamic_pointer_cast(accBase); +accessor + accBase2 = dynamic_pointer_cast(accDerived); +```