Reply to topic

[SOLVED] mingw/tdm-4.4.0 and Eigen2.0.2: unaligned array assertion

hrehf
Registered Member
Posts
1
Karma
0
I'm getting an "unaligned array assert" on win32/mingw/gcc.exe (TDM-1 mingw32) 4.4.0 (from http://www.tdragon.net/recentgcc/ ), even though my class / use of eigen is very simple. MSVC works fine. Eigen version is 2.0.2

Stacktrace (Quaternion not created 16byte aligned!):
Code: Select all
#0  0x00422492 in ei_matrix_array (this=0x22f938)
    at lib/eigen2/Eigen/src/Core/MatrixStorage.h:43
#1  0x00422919 in ei_matrix_storage (this=0x22f938)
    at lib/eigen2/Eigen/src/Core/MatrixStorage.h:76
#2  0x00423004 in Matrix (this=0x22f938)
    at lib/eigen2/Eigen/src/Core/Matrix.h:287
#3  0x0042222e in Quaternion (this=0x22f938, w=0, x=0, y=0, z=1)   struct ei_matrix_array
{
  EIGEN_ALIGN_128 T array[Size];

  ei_matrix_array()
  {
    //===========================================
    //hrehfeld debugging quaternion ====================
    std::cout (array) & 0xf) == 0
              && "this assertion is explained here: http://eigen.tuxfamily.org/dox/UnalignedArrayAssert.html  **** READ THIS WEB PAGE !!! ****");
    #endif
  }

  ei_matrix_array(ei_constructor_without_unaligned_array_assert) {}
};


Which confirmed that it was being created unaligned:
Code: Select all
creating aligned array at 0x22f938


Code: Select all
[00:32] (bjacob): look how this class has only a data member with the EIGEN_ALIGN_128 declarator
[00:33] (bjacob): so any object should be created at an address that's a multiple of 16 bytes


We then added #warnings to Eigen/src/Core/util/Macros.h:
Code: Select all
#if !EIGEN_ARCH_WANTS_ALIGNMENT
#define EIGEN_ALIGN_128
//hrehfeld
#warning !EIGEN_ARCH_WANTS_ALIGNMENT
#elif (defined __GNUC__)
#define EIGEN_ALIGN_128 __attribute__((aligned(16)))
//hrehfeld
#warning GNUC
#elif (defined _MSC_VER)
#define EIGEN_ALIGN_128 __declspec(align(16))
//hrehfeld
#warning MSC_VER
#else
#error Please tell me what is the equivalent of __attribute__((aligned(16))) for your compiler
#endif
 

to see what path was taken (GNUC):
Code: Select all
g++ -D MINGW -D __cplusplus -g -Wall -Ilib  -Ilib/eigen2/  -Isrc  -Isrc/gl  -Ilib/glm  -Ic:/usr/boost  -o bin/debug/src/Camera.o -c src/Camera.cpp
In file included from lib/eigen2/Eigen/Core:90,
                 from src/Camera.h:12,
                 from src/Camera.cpp:9:
lib/eigen2/Eigen/src/Core/util/Macros.h:177:2: warning: #warning GNUC



To make 100% sure, we then replace the EIGEN_ALIGN_128 with the attribute() thing:
Code: Select all
template  struct ei_matrix_array
{
        //hrehfeld
        __attribute__((aligned(16))) T array[Size];
//  EIGEN_ALIGN_128 T array[Size];
 
  ei_matrix_array()
  {
    //hrehfeld debugging quaternion
    std::cout (array) & 0xf) == 0
              && "this assertion is explained here: http://eigen.tuxfamily.org/dox/UnalignedArrayAssert.html  **** READ THIS WEB PAGE !!! ****");
    #endif
  }
 
  ei_matrix_array(ei_constructor_without_unaligned_array_assert) {}
};

which still just got us
Code: Select all
 creating aligned array at 0x22f938


We confirmed this also happens with Vector4f (excerpt from RotateView()):
Code: Select all
                std::cout (array) & 0xf) == 0 && "this assertion is explained here: http://eigen.tuxfamily.org/dox/UnalignedArrayAssert.html  **** READ THIS WEB PAGE !!! ****", file lib/eigen2/Eigen/src/Core/MatrixStorage.h, line 46


My Macros.h edit:
Code: Select all
// if the compiler is GNUC, disable 16 byte alignment on exotic archs that probably don't need it, and on which
// it may be extra trouble to get aligned memory allocation to work (example: on ARM, overloading new[] is a PITA
// because extra memory must be allocated for bookkeeping).
// if the compiler is not GNUC, just cross fingers that the architecture isn't too exotic, because we don't want
// to keep track of all the different preprocessor symbols for all compilers.
#if !defined(__GNUC__) || defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ia64__)
  //hrehfeld
  //#define EIGEN_ARCH_WANTS_ALIGNMENT 1
  #define EIGEN_ARCH_WANTS_ALIGNMENT 0
#else
  #ifdef EIGEN_VECTORIZE
    #error Vectorization enabled, but the architecture is not listed among those for which we require 16 byte alignment. If you added vectorization for another architecture, you also need to edit this list.
  #endif
  #define EIGEN_ARCH_WANTS_ALIGNMENT 0
  #ifndef EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
    #define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
  #endif
#endif

Last edited by ggael on Sun Jun 21, 2009 12:49 pm, edited 1 time in total.
User avatar bjacob
Registered Member
Posts
658
Karma
3
I can at least help regarding this:

hrehf wrote:Update:

Huh. I just tried setting EIGEN_ARCH_WANTS_ALIGNMENT to 0 in Macros.h as a workaround, and I'm still getting the assertion, even though the other path in the macros gets taken:
Code: Select all
g++ -D MINGW -D __cplusplus -g -Wall -Ilib  -Ilib/eigen2/  -Isrc  -Isrc/gl  -Ilib/glm  -Ic:/usr/boost  -o bin/debug/src/Camera.o -c src/Camera.cpp
In file included from lib/eigen2/Eigen/Core:90,
                 from src/Camera.h:12,
                 from src/Camera.cpp:9:
lib/eigen2/Eigen/src/Core/util/Macros.h:175:2: warning: #warning !EIGEN_ARCH_WANTS_ALIGNMENT

Code: Select all
0, 0, 0, 1
Vector4f
creating aligned array at 0x22f934
Assertion failed: (reinterpret_cast(array) & 0xf) == 0 && "this assertion is explained here: http://eigen.tuxfamily.org/dox/UnalignedArrayAssert.html  **** READ THIS WEB PAGE !!! ****", file lib/eigen2/Eigen/src/Core/MatrixStorage.h, line 46


My Macros.h edit:
Code: Select all
// if the compiler is GNUC, disable 16 byte alignment on exotic archs that probably don't need it, and on which
// it may be extra trouble to get aligned memory allocation to work (example: on ARM, overloading new[] is a PITA
// because extra memory must be allocated for bookkeeping).
// if the compiler is not GNUC, just cross fingers that the architecture isn't too exotic, because we don't want
// to keep track of all the different preprocessor symbols for all compilers.
#if !defined(__GNUC__) || defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ia64__)
  //hrehfeld
  //#define EIGEN_ARCH_WANTS_ALIGNMENT 1
  #define EIGEN_ARCH_WANTS_ALIGNMENT 0
#else
  #ifdef EIGEN_VECTORIZE
    #error Vectorization enabled, but the architecture is not listed among those for which we require 16 byte alignment. If you added vectorization for another architecture, you also need to edit this list.
  #endif
  #define EIGEN_ARCH_WANTS_ALIGNMENT 0
  #ifndef EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
    #define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
  #endif
#endif



I forgot to mention but you also had to #define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT

Actually the very simplest thing to do is to make this #if fail, by turning it into a "#if 0" !

Code: Select all
// if the compiler is GNUC, disable 16 byte alignment on exotic archs that probably don't need it, and on which
// it may be extra trouble to get aligned memory allocation to work (example: on ARM, overloading new[] is a PITA
// because extra memory must be allocated for bookkeeping).
// if the compiler is not GNUC, just cross fingers that the architecture isn't too exotic, because we don't want
// to keep track of all the different preprocessor symbols for all compilers.
#if 0 // !defined(__GNUC__) || defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ia64__)
  #define EIGEN_ARCH_WANTS_ALIGNMENT 1
#else
  #ifdef EIGEN_VECTORIZE
    #error Vectorization enabled, but the architecture is not listed among those for which we require 16 byte alignment. If you added vectorization for another architecture, you also need to edit this list.
  #endif
  #define EIGEN_ARCH_WANTS_ALIGNMENT 0
  #ifndef EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
    #define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
  #endif
#endif


For the rest, I confirm that I am very very puzzled by this situation and any help from a third person would be most welcome !!!

As explained by the reportedr, we have traced the problem to a __attribute__ NOT being honored, but then we can't reproduce this in a simple test case.

Last edited by bjacob on Sun Jun 21, 2009 12:10 am, edited 1 time in total.


Join us on Eigen's IRC channel: #eigen on irc.freenode.net
Have a serious interest in Eigen? Then join the mailing list!
User avatar ggael
Moderator
Posts
3447
Karma
19
OS
The problem is that on windows function calls are 4-bytes aligned. GCC assumes a 16-byte alignment and therefore, by default, it does not generate any extra code to get a 16 byte aligned stack when needed. One can enforce that on a per function basis with:

Code: Select all
__attribute__((force_align_arg_pointer)) void my_function(...) {}


So I guess we could add a macro:

Code: Select all
#if
#define EIGEN_REALIGN_STACK __attribute__((force_align_arg_pointer))
#else
#define EIGEN_REALIGN_STACK
#endif


and users who want to support MINGW will have to add EIGEN_REALIGN_STACK in front of the declaration of all functions using aligned Eigen objects as local variables.

edit:

another solution is to use the option:
Code: Select all
-mpreferred-stack-boundary=2

which tells GCC to expect a 8-byte aligned stack, and so it automatically realigns the stack when needed.

Last edited by ggael on Sun Jun 21, 2009 12:24 pm, edited 1 time in total.
User avatar bjacob
Registered Member
Posts
658
Karma
3
Thanks a lot to Gael!! Maybe this is a bit better:

Code: Select all
-mpreferred-stack-boundary=3


the idea is that this aligns to 8 bytes (8=2^3) so this should give better performance with double's.


Join us on Eigen's IRC channel: #eigen on irc.freenode.net
Have a serious interest in Eigen? Then join the mailing list!

 
Reply to topic

Bookmarks



Who is online

Registered users: Baidu [Spider], BigaAl, Bing [Bot], dcihon, giygas, Google [Bot], Majestic-12 [Bot], nachtgold, Sogou [Bot]