restrict(amp) restrictions part 2 of N – compound types

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 around compound types.

In amp-restricted functions, compound types are only allowed to be recursively built upon supported fundamental types and other supported compound types. For example, the element type of an array must be a supported type. Therefore, for example, a char array is not supported since char is not a supported fundamental type (as per the previous section).

There are some extra restrictions on compound types:

·         Enumeration types must have underlying types consisting of int, unsigned int, long, or unsigned long;

·         Pointer or reference types are not allowed to be used to construct other compound types, e.g.

o   Pointer to pointer is not allowed;

o   Pointers or references are not allowed  for data members of classes, structs, and unions, or for array elements with two exceptions: concurrency::array&  and concurrency::graphics::texture&  are allowed as data members;


Pointers and references are not supported by the DirectX 11 programming model. However, they are useful to express many programming patterns, and are used pervasively in many existing C/C++ applications. Not supporting pointers or references would hurt C++ AMP’s usability, especially when porting existing algorithms over. So in C++ AMP we emulate pointers on top of DirectX 11: we use static analysis to track what pointers point to and replace dereferences with direct accesses to source variables. But nested pointers could result in inefficient code due to the conservative nature of the static analysis algorithm. So we decided to only support top level pointer/reference types in v1, which seems a good balance of usability and performance.


·         The data members of classes, structs, and unions, and the array elements must be naturally aligned, i.e., aligned on its size, and the alignment must be at least 32-bit;

·         The data members of classes, structs, and unions  are not allowed to be bitfields;

These two restrictions were introduced to make sure that the memory representation of an object in host memory interpreted by C++ is same as on GPU memory so that we don’t need to repackage the data while passing data across the CPU/GPU boundary and to emulate memory accesses on GPU, which could be very inefficient. Normally you won’t hit this restriction since most types supported for amp have natural alignments that are at least 32-bit. The two special cases to watch out are bool and empty classes (and structs and unions, as well pure lambdas). For example,

class A1      // supported for amp


    bool m1;

    int  m2;



class A2    // not supported since m2 has 8-bit alignment


    bool m1;

    bool m2;



If you use A2 in an amp restricted function, you would get the following error message:

error C3581: ‘A2’: unsupported type in amp restricted code
        base class, data member or array element must be at least 4 byte aligned

To use A2 in an amp restricted function, you could use __declspec(align(#)) to change the data member’s alignment, e.g.

class A3    // supported for amp since m2 now has 32-bit alignment


    bool m1;

    __declspec(align(4)) bool m2;



Note that in order to align each individual element of an array using __declspec(align(#)) requires a bit more effort, e.g., to use array of bools,

__declspec(align(4)) bool a1[10]; // not supported since this __declspec(align(4))

                                  // applies to the whole array


typedef __declspec(align(4)) struct S{ bool m;} ALIGNED_BOOL;

ALIGNED_BOOL a2[10]; // supported since each array element is now 32-bit aligned



·         Classes may have base classes, but is not allowed to have virtual base classes or any virtual member functions;

·         Pointers or references to functions, and pointers to member functions are not allowed;

These last two restrictions are due to the fact that function calls are not supported by some GPU hardware yet

Comments (2)

  1. Arman Schwarz says:

    You say that

    "Pointers or references are not allowed  for data members of classes, structs, and unions, or for array elements with two exceptions: concurrency::array&  and concurrency::graphics::texture&  are allowed as data members"

    However, I have been unable to get my compiler (VC++11) to accept compound types with references to array objects. Here is some code that reproduces the problem:

    #include <amp.h>

    struct A


    A(concurrency::array<unsigned int,1>* input) : arr(*input) {}

    concurrency::array<unsigned int,1>& arr;


    int main()


    // the template vector will be used to fill the arrays of each instance of A

    std::vector<unsigned int> template_vector(100,0);

    // the A_vec object will contain a series of "A" instances

    std::vector<A> A_vec;

    for (unsigned i = 0; i != 10; ++i)


    // build the concurrency::array on the heap

    auto arr_input = new concurrency::array<unsigned int,1>(100,template_vector);

    // use it to construct a new instance of "A" on the back of A_vec:



    // attempt to create an array_view from the vector "A" instances we just created:

    concurrency::array_view<A> carrview(10,A_vec); // error C2973: 'Concurrency::array_view<_Value_type>' : invalid template argument 'A'

    return 0;


  2. Arman Schwarz says:

    I've posted the issue at the forums (…/36e72d5e-2a72-48ac-8aa2-7d016731153c) as well.