restrict(amp) restrictions part 6 of N – pointer operations and casting

This post assumes and requires that you have read the introductory post to this series which also includes a table of content. With that out of the way let’s look at restrictions with pointer operations and casting.

Since pointers in C++ AMP are actually emulated on top of the DirectX 11 platform which does not support pointers, to prevent patterns that may result in extremely inefficient emulated code, we disallow casting a pointer to an integral type, nor an integral type to a pointer. This restriction applies to reinterpret_cast as well as to C-style casts. Note that the implicit casting from constant 0 to any pointer type and from any pointer type to bool is still allowed, and is treated as the null pointer just like regular C++. For example,

    int n1 = 4;
int *p1 = 0; // legal: 0 -> int*
    int *p2 = reinterpret_cast<int*>(n1); // illegal: int -> int *
    int n2 = (int)p2; // illegal: int* –> int
    void *p3 = p1; // legal: int* -> void*
    if (p2) n1 = 5; // legal: int* -> bool

In addition, casting away constness from a pointer or reference will result in a compiler warning and/or undefined behavior. This is because we rely on constness to decide what kind of underlying GPU memory access mode (read-only or writable) to use and try to exploit readonliness as much as possible to achieve better performance. Casting away constness may result in writing into a read-only GPU buffer, which is not allowed. For example,

    extent<1> e(10);

    array<int, 1> a(e);

    array<int, 1> b(e);

    const array<int, 1> &ra = a;

    parallel_for_each(a.extent, [&] (index<1> idx) restrict(amp){

        b[idx] = idx[0];

        int *p = (int *)(&ra[idx]); // ra[idx] returns a “const int&”, cast &ra[idx]
// to “int*” triggers a warning

        *p = idx[0]; // it's undefined whether the value of idx[0] is written into ra[idx]

    });

Finally, pointer arithmetic is not allowed to be performed on pointers to bool values since that will result in invalid pointers pointing to an unaligned data region.

struct A

    {

        bool flag;

        int data;

    };

 

    A a;

    bool *p1 = &(a.flag);

    bool *p2 = p1++; // illegal, p2 now points to unaligned data region

    bool b = *(p2); // undefined!