Intel® C++ Compiler
Community support and assistance for creating C++ code that runs on platforms based on Intel® processors.

Restrict pointer in vectors

Matthieu_Brucher
Beginner
897 Views

Hi,

I tried to put restricted pointers in a vector, but it failed on Linux (gcc 4.4.6 headers):

#include <vector>
typedef double *restrict RestrictedDoubleP;

int main()
{
std::vector<RestrictedDoubleP> c;

return 0;
}

The errors:

$ icpc -restrict toto.cpp
/usr/include/c++/4.4.6/ext/new_allocator.h(95): error: no instance of overloaded function "operator delete" matches the argument list
argument types are: (RestrictedDoubleP *)
{ ::operator delete(__p); }
^
detected during:
instantiation of "void __gnu_cxx::new_allocator<_Tp>::deallocate(__gnu_cxx::new_allocator<_Tp>::pointer, __gnu_cxx::new_allocator<_Tp>::size_type={size_t={unsigned long}}) [with _Tp=RestrictedDoubleP={double *__restrict__}]" at line 146 of "/usr/include/c++/4.4.6/bits/stl_vector.h"
instantiation of "void std::_Vector_base<_Tp, _Alloc>::_M_deallocate(_Alloc::rebind<_Tp>::other::pointer, size_t={unsigned long}) [with _Tp=RestrictedDoubleP={double *__restrict__}, _Alloc=std::allocator<RestrictedDoubleP={double *__restrict__}>]" at line 132 of "/usr/include/c++/4.4.6/bits/stl_vector.h"
instantiation of "std::_Vector_base<_Tp, _Alloc>::~_Vector_base() [with _Tp=RestrictedDoubleP={double *__restrict__}, _Alloc=std::allocator<RestrictedDoubleP={double *__restrict__}>]" at line 208 of "/usr/include/c++/4.4.6/bits/stl_vector.h"
instantiation of "std::vector<_Tp, _Alloc>::vector() [with _Tp=RestrictedDoubleP={double *__restrict__}, _Alloc=std::allocator<RestrictedDoubleP={double *__restrict__}>]" at line 7 of "toto.cpp"

compilation aborted for toto.cpp (code 2)

Is there a reason why it can't work?

0 Kudos
13 Replies
SergeyKostrov
Valued Contributor II
897 Views
>>...new_allocator.h(95): error: no instance of overloaded function "operator delete" matches the argument list >>argument types are: (RestrictedDoubleP *) >>{ ::operator delete(__p); } There are rules for declaration C++ operators new and delete. It means, their declarations should match to each other. For example, if a new operator is declared as follows: ... void * operator new( size_t uiSize, char *pszFileName, int iLineNum ); ... Then a matching delete operator should be declared like ( with the same types (!) for 2nd and 3rd arguments ): ... void operator delete( void *pObject, char *pszFileName, int iLineNum ); ... and so, on. I consider it as a problem with application of the restric keyword in STL library and you could try a different solution, like: ... restrict int *piMemory = ( restrict int * )new int[ 16 ]; ... or similar but for a variable of vector type.
0 Kudos
Matthieu_Brucher
Beginner
897 Views

Hi,

Unfortunately, this is a small excerpt of a huge application and I can't modify the usage of the vector<float*> :/

I guess I will have to rely on the -fno-alias flag and hope that the application doesn't have anything strange!

0 Kudos
SergeyKostrov
Valued Contributor II
897 Views
>>...I guess I will have to rely on the -fno-alias flag and hope that the application doesn't have anything strange! If that workaround works for you then use it. Take into account that there are No C/C++ compilers at the moment that automatically generate a delete C++ operator matching to a new C++ operator.
0 Kudos
Matthieu_Brucher
Beginner
897 Views

It is rather a strong hypothesis (that I already seen being wrong int his application) to use -fno-alias.

It strange to be able to create an object and not having the compiler being able to destroy it. And then there is the issue of the builtin_memmove that also can't get a pointer to a restrict pointer!

0 Kudos
SergeyKostrov
Valued Contributor II
897 Views
>>...It strange to be able to create an object and not having the compiler being able to destroy it... C/C++ compilers Do Not destroy dynamically allocated objects. A Software Developer must create a code that uses some functionality ( delete C++ operator in your case ) to deallocate the memory and then C/C++ compiler generates codes. This is by design of dynamic operations and don't mix it with automatic allocation on the stack or static / global allocations. >>...And then there is the issueof the builtin_memmove that also can't get a pointer to a restrict pointer! More details? How is it used?
0 Kudos
Matthieu_Brucher
Beginner
897 Views

Of course, waht I meant was being able to instantiate values but not destroying them (no matter what generates what).

And oops for the second question, I removed the code generating it... I think it was a resize ont he vector that triggered it. Anyway, if it is not possible to put restricted pointers in a vector, it isn't useful to resize this vector!

0 Kudos
SergeyKostrov
Valued Contributor II
897 Views
>>...Anyway, if it is not possible to put restricted pointers in a vector, it isn't useful to resize this vector!.. It is a good point. Now, let's take a look at your code: >>typedef double *restrict RestrictedDoubleP; >> >>int main() >>{ >>std::vector< RestrictedDoubleP > c; >>... and my question is Why do you need a vector ( an array ) of restricted pointers?
0 Kudos
Matthieu_Brucher
Beginner
897 Views

This is how the code works, I don't have a saying in using vectors of pointers to float. The only thing I know is that the float arrays are different.

0 Kudos
jeff_keasler
Beginner
897 Views

You can't declare a restricted pointer in a vector because the restrict keyword is silently ignored on all class/structure members defined in a persistent scope.  This means any vector that is defined globally, or on the heap with a new operator, will not honor your restrict keyword since the base pointer of a vector is stored as a class member.

0 Kudos
SergeyKostrov
Valued Contributor II
896 Views
>>...in a vector because the restrict keyword is silently ignored on all class/structure members defined in a persistent scope... >>... >>...This means any vector that is defined globally, or on the heap with a new operator, will not honor your restrict keyword... The vector c ( see initial post or 3rd post from this one ) is declared locally and memory is allocated from the stack and C++ operator new is Not used in that case. In the 2nd post of the thread there is a clear explanation why the compilation error happened and it is Not related to restrict specificator.
0 Kudos
jeff_keasler
Beginner
896 Views

Sergey Kostrov wrote:

>>...in a vector because the restrict keyword is silently ignored on all class/structure members defined in a persistent scope...
>>...
>>...This means any vector that is defined globally, or on the heap with a new operator, will not honor your restrict keyword...

The vector c ( see initial post or 3rd post from this one ) is declared locally and memory is allocated from the stack and C++ operator new is Not used in that case. In the 2nd post of the thread there is a clear explanation why the compilation error happened and it is Not related to restrict specificator.

Sergey, I should have been clearer in my follow-up.  I added the non-sequitor information about restrict because I know other people search these boards with keywords and I thought "vector" and "restrict" might be something that frustrated people would search for.  There are very few people outside the language committee who know that restrict is silently ignored in a persistent scope, and I was just trying to spread the word.

-Jeff

0 Kudos
jimdempseyatthecove
Honored Contributor III
897 Views

>>There are very few people outside the language committee who know that restrict is silently ignored in a persistent scope, and I was just trying to spread the word.

The above can be read two ways, and I would like clarification.

a) Silently ignores a placement requirement (enforcement) on data, however "restrict" attribute still attached to variable (iow code may or may not work).

b) Silently removes "restrict" attribute from variable.

Jim Dempsey

0 Kudos
jeff_keasler
Beginner
896 Views

jimdempseyatthecove wrote:

>>There are very few people outside the language committee who know that restrict is silently ignored in a persistent scope, and I was just trying to spread the word.

The above can be read two ways, and I would like clarification.

a) Silently ignores a placement requirement (enforcement) on data, however "restrict" attribute still attached to variable (iow code may or may not work).

b) Silently removes "restrict" attribute from variable.

Jim Dempsey

Jim, I'm not sure which option the compiler chooses internally, but the net effect is as if (b) had occurred.  Here is an example:

typedef double* __restrict__  Real_ptr ;

class MyVec {
public:
  MyVec(Indx_type _len ) : len(_len) {
    vec = (Real_ptr) new double[len];
  }

  double &operator[] (Indx_type i) {
    return vec;
  }

  Indx_type len;
  Real_ptr vec;
};


MyVec g_out1(128), g_out2(128), g_out3(128), g_in1(128), g_in2(128) ;

void T16_RestrictFails_SIMDFails(Indx_type len) {
   for (Indx_type i=0; i<len ; ++i) {
      g_out1 = g_in1 + g_in2 ;
      g_out2 = g_in1 - g_in2 ;
      g_out3 = g_in1 * g_in2 ;
   }
}

void T17_RestrictWorks_SIMDWorks_AlignFails(Indx_type len) {
   MyVec l_out1(len), l_out2(len), l_out3(len), l_in1(len), l_in2(len);
   for (Indx_type i=0; i<len ; ++i) {
      l_out1 = l_in1 + l_in2 ;
      l_out2 = l_in1 - l_in2 ;
      l_out3 = l_in1 * l_in2 ;
   }
}

We will be discussing potential ways toi address this deficiency with the compiler team on Friday.  We need all the support  we can get from other users to have Intel provide some form of workaround for this.  It would be nice if we could get automatic SIMDization for all of our structs/classes, not just the ones declared and defined on the stack. :)

0 Kudos
Reply