-
Notifications
You must be signed in to change notification settings - Fork 17
Casting multi_ptr pointers #85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ProGTX
wants to merge
16
commits into
codeplaysoftware:master
Choose a base branch
from
ProGTX:ProGTX/multi_ptr_cast
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
1f7ec12
Initial draft for casting `multi_ptr`
ProGTX 1e0dd51
Basic conversion functions
ProGTX c774023
Minor formatting changes
ProGTX 3734c02
Specializations for `void` and `const void`
ProGTX d0aa1ee
Tables and descriptions
ProGTX d2072d9
Made adding `const` conversion implicit
ProGTX 19e9d2c
Simple cast examples
ProGTX 58c313c
More examples
ProGTX 593a7a9
Updated dates and main table entry
ProGTX 3f7f07d
Use `multi_ptr<const>` for `vec::load`
ProGTX aea310e
More examples
ProGTX 53a7e20
Addressed most comments
ProGTX 76e795b
Removed parts that were merged as SYCL 1.2.1 errata
ProGTX f0602ae
Updated date
ProGTX 8a4975d
Removed vendor namespace
ProGTX bdf6159
Some fixes to examples
ProGTX File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Casting multi_ptr pointers | ||
|
||
| Proposal ID | CP016 | | ||
|-------------|--------| | ||
| Name | Casting multi_ptr pointers | | ||
| Date of Creation | 19 December 2018 | | ||
| Target | SYCL 1.2.1 vendor extension | | ||
| Current Status | _Work in Progress_ | | ||
| Reply-to | Peter Žužek <[email protected]> | | ||
| Original author | Peter Žužek <[email protected]> | | ||
| Contributors | Ruyman Reyes <[email protected]> | | ||
|
||
## Overview | ||
|
||
This paper proposes the addition of pointer casting functions to SYCL | ||
in order to simplify casting of the `multi_ptr` class. | ||
|
||
## Versions | ||
|
||
[Version 1](sycl-2.2/index.md) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
# Casting multi_ptr pointers | ||
|
||
## Motivation | ||
|
||
The current SYCL 1.2.1 specification contains the `multi_ptr` class | ||
which is designed mostly for OpenCL interoperability | ||
and calling certain functions which rely on OpenCL builtins. | ||
The `multi_ptr` class has two template parameters: | ||
`ElementType` as the type of the underlying data, | ||
and `Space` to designate the address space of the pointer. | ||
It is not allowed to cast pointers to a different address space, | ||
but casting pointers to a different underlying type is completely valid C++, | ||
within the type restrictions for the cast. | ||
|
||
Programmers wanting to cast `multi_ptr<A, Space>` to `multi_ptr<B, Space>` | ||
don't have many options to do so in SYCL 1.2.1. | ||
There are only two specified casts in SYCL 1.2.1: | ||
* Using `static_cast` to cast `multi_ptr<A, Space>` to `multi_ptr<void, Space>` | ||
(defined through an explicit conversion operator) | ||
* Using `static_cast` to cast `multi_ptr<void, Space>` to `multi_ptr<B, Space>` | ||
(defined through an explicit conversion operator) | ||
|
||
Therefore, the only option to perform a cast from | ||
`multi_ptr<A, Space>` to `multi_ptr<B, Space>` | ||
is to use both casts like so: | ||
```cpp | ||
// Using global_ptr here to simplify the code | ||
// decltype(multiPtrA) == global_ptr<A> | ||
auto multiPtrB = static_cast<global_ptr<B>>( | ||
static_cast<global_ptr<void>>(multiPtrA)); | ||
``` | ||
|
||
This is problematic on a few levels: | ||
* Verbosity | ||
* Only allows static casts | ||
* Allows casting the underlying `A*` pointer to a `B*` pointer | ||
even if the type system forbids it | ||
* Does not handle `const` qualifiers | ||
|
||
Therefore, there is a clear need to provide more casting options for the `multi_ptr` class | ||
in order to make the casting safer and easier to use. | ||
|
||
## Summary | ||
|
||
This proposal adds a few explicit conversion operators | ||
as member functions of the `multi_ptr` 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. | ||
|
||
## Explicit conversion operators | ||
|
||
The new interface of the `multi_ptr` class would look like this: | ||
|
||
```cpp | ||
namespace cl { | ||
namespace sycl { | ||
|
||
template <typename ElementType, access::address_space Space> | ||
class multi_ptr { | ||
public: | ||
/// All existing members here | ||
|
||
... | ||
|
||
// Explicit conversion to `multi_ptr<ElementTypeU, Space>` | ||
template <typename ElementTypeU> | ||
explicit operator multi_ptr<ElementTypeU, Space>() const; | ||
|
||
// Implicit conversion to `multi_ptr<const ElementType, Space>` | ||
operator multi_ptr<const ElementType, Space>() const; | ||
}; | ||
|
||
} // namespace sycl | ||
} // namespace cl | ||
``` | ||
|
||
The conversion operator to `multi_ptr<ElementTypeU, Space>` replaces | ||
the existing explicit conversion to `multi_ptr<void, Space>`. | ||
|
||
| Member function | Description | | ||
|-----------------|-------------| | ||
| *`template <typename ElementTypeU> explicit operator multi_ptr<ElementTypeU, Space>() const`* | Performs a static cast of the underlying pointer `ElementType*` to `ElementTypeU*` and returns a new `multi_ptr` instance containing the cast pointer. The address space stays the same. This conversion is only valid if the `static_cast` from `ElementType*` to `ElementTypeU*` is valid. | | ||
| *`operator multi_ptr<const ElementType, Space>() const`* | Performs a static cast of the underlying pointer `ElementType*` to `const ElementType*` and returns a new `multi_ptr` instance containing the cast pointer. The address space stays the same. This conversion is implicit because it is always valid to add a `const` qualifier. | | ||
|
||
## Conversion functions | ||
|
||
In addition to the conversion operators, | ||
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 <typename ElementTypeU, typename ElementTypeT, access::address_space Space> | ||
multi_ptr<ElementTypeU, Space> | ||
static_pointer_cast(const multi_ptr<ElementTypeT, Space>& multiPtr); | ||
|
||
// Performs a dynamic_cast of the contained pointer | ||
template <typename ElementTypeU, typename ElementTypeT, access::address_space Space> | ||
multi_ptr<ElementTypeU, Space> | ||
dynamic_pointer_cast(const multi_ptr<ElementTypeT, Space>& multiPtr); | ||
|
||
// Performs a const_cast of the contained pointer | ||
template <typename ElementTypeU, typename ElementTypeT, access::address_space Space> | ||
multi_ptr<ElementTypeU, Space> | ||
const_pointer_cast(const multi_ptr<ElementTypeT, Space>& multiPtr); | ||
|
||
// Performs a reinterpret_cast of the contained pointer | ||
template <typename ElementTypeU, typename ElementTypeT, access::address_space Space> | ||
multi_ptr<ElementTypeU, Space> | ||
reinterpret_pointer_cast(const multi_ptr<ElementTypeT, Space>& multiPtr); | ||
|
||
} // namespace sycl | ||
} // namespace cl | ||
``` | ||
|
||
In the table below, each function has the following template parameters: | ||
```cpp | ||
template <typename ElementTypeU, typename ElementTypeT, access::address_space Space> | ||
``` | ||
|
||
| Function | Description | | ||
|-----------------|-------------| | ||
| *`multi_ptr<ElementTypeU, Space> static_pointer_cast(const multi_ptr<ElementTypeT, Space>& multiPtr)`* | Performs a `static_cast` of the underlying pointer `ElementTypeT*` contained within `multiPtr` to `ElementTypeU*` and returns a new `multi_ptr` instance containing the cast pointer. The address space stays the same. This conversion is only valid if the `static_cast` from `ElementType*` to `ElementTypeU*` is valid. | | ||
| *`multi_ptr<ElementTypeU, Space> dynamic_pointer_cast(const multi_ptr<ElementTypeT, Space>& multiPtr)`* | Performs a `dynamic_cast` of the underlying pointer `ElementTypeT*` contained within `multiPtr` to `ElementTypeU*` and returns a new `multi_ptr` instance containing the cast pointer. The address space stays the same. This conversion is only valid if the `dynamic_cast` from `ElementType*` to `ElementTypeU*` is valid. | | ||
| *`multi_ptr<ElementTypeU, Space> const_pointer_cast(const multi_ptr<ElementTypeT, Space>& multiPtr)`* | Performs a `const_cast` of the underlying pointer `ElementTypeT*` contained within `multiPtr` to `ElementTypeU*` and returns a new `multi_ptr` instance containing the cast pointer. The address space stays the same. This conversion is only valid if the `const_cast` from `ElementType*` to `ElementTypeU*` is valid. | | ||
| *`multi_ptr<ElementTypeU, Space> reinterpret_pointer_cast(const multi_ptr<ElementTypeT, Space>& multiPtr)`* | Performs a `reinterpret_cast` of the underlying pointer `ElementTypeT*` contained within `multiPtr` to `ElementTypeU*` and returns a new `multi_ptr` instance containing the cast pointer. The address space stays the same. This conversion is only valid if the `reinterpret_cast` from `ElementType*` to `ElementTypeU*` is valid. | | ||
|
||
## Examples | ||
|
||
### Simple casts | ||
|
||
These examples focus on `global_ptr` for brevity, | ||
but the same operation is valid on any other `multi_ptr` type. | ||
|
||
```cpp | ||
using namespace cl::sycl; | ||
|
||
const global_ptr<int> ptrInt = get_some_global_ptr<int>(); | ||
|
||
// Conversion operator | ||
auto ptrVoid1 = static_cast<global_ptr<void>>(ptrInt); | ||
auto ptrConstInt1 = static_cast<global_ptr<const int>>(ptrInt); | ||
|
||
// static_pointer_cast | ||
global_ptr<void> ptrVoid2 = | ||
static_pointer_cast<void>(ptrInt); | ||
global_ptr<const int> ptrConstInt2 = | ||
static_pointer_cast<const int>(ptrInt); | ||
|
||
// const_pointer_cast | ||
global_ptr<const int> ptrConstInt3 = | ||
const_pointer_cast<const int>(ptrInt); | ||
// global_ptr<int> ptrIntStripConst = | ||
// static_cast<global_ptr<int>>(ptrConstInt1); // illegal | ||
global_ptr<int> ptrIntStripConst = | ||
const_pointer_cast<int>(ptrConstInt1); | ||
|
||
// reinterpret_pointer_cast | ||
global_ptr<float> ptrFloat4 = | ||
reinterpret_pointer_cast<float>(ptrInt); | ||
global_ptr<void> ptrVoid4 = | ||
reinterpret_pointer_cast<void>(ptrInt); | ||
global_ptr<const int> ptrConstInt4 = | ||
reinterpret_pointer_cast<const int>(ptrInt); | ||
``` | ||
|
||
### `dynamic_pointer_cast` | ||
|
||
```cpp | ||
struct Base { | ||
virtual void foo() const {} | ||
virtual ~Base(){} | ||
}; | ||
struct Derived : public Base { | ||
void foo() const override {} | ||
}; | ||
|
||
using namespace cl::sycl; | ||
const global_ptr<Base> ptrBase = get_some_global_ptr<Base>(); | ||
|
||
auto ptrDerived = dynamic_pointer_cast<Derived>(ptrBase); | ||
auto ptrBase1 = dynamic_pointer_cast<Base>(ptrDerived); | ||
``` | ||
|
||
### Passing `multi_ptr` to functions | ||
|
||
```cpp | ||
using namespace cl::sycl; | ||
|
||
template <typename ElementType, access::address_space Space> | ||
void function_taking_ptr(const multi_ptr<ElementType, Space>& ptr); | ||
template <typename ElementType, access::address_space Space> | ||
void function_taking_const_ptr(const multi_ptr<const ElementType, Space>& ptr); | ||
|
||
const global_ptr<int> ptrInt = get_some_global_ptr<int>(); | ||
|
||
function_taking_ptr(ptrInt); | ||
// Implicit conversion to global_ptr<const int>: | ||
function_taking_const_ptr(ptrInt); | ||
|
||
const global_ptr<float> ptrFloat = get_some_global_ptr<float>(); | ||
|
||
// Convert float to int pointer | ||
function_taking_ptr(reinterpret_ptr_cast<int>(ptrFloat)); | ||
// First explicit conversion to global_ptr<int> | ||
// and then implicit conversion to global_ptr<const int>: | ||
function_taking_const_ptr(reinterpret_ptr_cast<int>(ptrFloat)); | ||
|
||
``` |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.