aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Eigen/src/Core/Matrix.h26
-rw-r--r--Eigen/src/Core/util/Memory.h47
-rw-r--r--Eigen/src/Geometry/AlignedBox.h3
-rw-r--r--Eigen/src/Geometry/Hyperplane.h3
-rw-r--r--Eigen/src/Geometry/ParametrizedLine.h3
-rw-r--r--Eigen/src/Geometry/Quaternion.h2
-rw-r--r--Eigen/src/Geometry/Scaling.h2
-rw-r--r--Eigen/src/Geometry/Transform.h3
-rw-r--r--Eigen/src/Geometry/Translation.h2
-rw-r--r--doc/TopicLazyEvaluation.dox12
-rw-r--r--doc/UnalignedArrayAssert.dox102
-rw-r--r--test/unalignedassert.cpp12
12 files changed, 150 insertions, 67 deletions
diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h
index f990167c3..666d25cd9 100644
--- a/Eigen/src/Core/Matrix.h
+++ b/Eigen/src/Core/Matrix.h
@@ -135,31 +135,7 @@ class Matrix
public:
enum { NeedsToAlign = (Options&Matrix_AutoAlign) == Matrix_AutoAlign
&& SizeAtCompileTime!=Dynamic && ((sizeof(Scalar)*SizeAtCompileTime)%16)==0 };
- typedef typename ei_meta_if<NeedsToAlign, ei_byte_forcing_aligned_malloc, char>::ret ByteAlignedAsNeeded;
- void *operator new(size_t size) throw()
- {
- return ei_aligned_malloc<ByteAlignedAsNeeded>(size);
- }
-
- void *operator new(size_t, void *ptr) throw()
- {
- return ptr;
- }
-
- void *operator new[](size_t size) throw()
- {
- return ei_aligned_malloc<ByteAlignedAsNeeded>(size);
- }
-
- void *operator new[](size_t, void *ptr) throw()
- {
- return ptr;
- }
-
- void operator delete(void * ptr) { ei_aligned_free(static_cast<ByteAlignedAsNeeded *>(ptr), 0); }
- void operator delete[](void * ptr) { ei_aligned_free(static_cast<ByteAlignedAsNeeded *>(ptr), 0); }
-
- public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
EIGEN_STRONG_INLINE int rows() const { return m_storage.rows(); }
EIGEN_STRONG_INLINE int cols() const { return m_storage.cols(); }
diff --git a/Eigen/src/Core/util/Memory.h b/Eigen/src/Core/util/Memory.h
index c8341dae4..12cb5a837 100644
--- a/Eigen/src/Core/util/Memory.h
+++ b/Eigen/src/Core/util/Memory.h
@@ -144,6 +144,33 @@ inline static int ei_alignmentOffset(const Scalar* ptr, int maxOffset)
#define ei_aligned_stack_free(PTR,TYPE,SIZE) ei_aligned_free(PTR,SIZE)
#endif
+#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF__INTERNAL(NeedsToAlign, TYPENAME) \
+ typedef TYPENAME Eigen::ei_meta_if<(NeedsToAlign), \
+ Eigen::ei_byte_forcing_aligned_malloc, \
+ char \
+ >::ret Eigen_ByteAlignedAsNeeded; \
+ void *operator new(size_t size) throw() { \
+ return ei_aligned_malloc<Eigen_ByteAlignedAsNeeded>(size); \
+ } \
+ void *operator new(size_t, void *ptr) throw() { \
+ return ptr; \
+ } \
+ void *operator new[](size_t size) throw() { \
+ return ei_aligned_malloc<Eigen_ByteAlignedAsNeeded>(size); \
+ } \
+ void *operator new[](size_t, void *ptr) throw() { \
+ return ptr; \
+ } \
+ void operator delete(void * ptr) { ei_aligned_free(static_cast<Eigen_ByteAlignedAsNeeded *>(ptr), 0); } \
+ void operator delete[](void * ptr) { ei_aligned_free(static_cast<Eigen_ByteAlignedAsNeeded *>(ptr), 0); }
+#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW \
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF__INTERNAL(true, )
+#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)\
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF__INTERNAL(NeedsToAlign, typename)
+#define EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE(Type,Size)\
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(((Size)!=Eigen::Dynamic) && ((sizeof(Type)*(Size))%16==0))
+
+
/** \class WithAlignedOperatorNew
*
* \brief Enforces instances of inherited classes to be 16 bytes aligned when allocated with operator new
@@ -185,27 +212,9 @@ inline static int ei_alignmentOffset(const Scalar* ptr, int maxOffset)
*/
struct WithAlignedOperatorNew
{
- void *operator new(size_t size) throw()
- {
- return ei_aligned_malloc<ei_byte_forcing_aligned_malloc>(size);
- }
-
- void *operator new[](size_t size) throw()
- {
- return ei_aligned_malloc<ei_byte_forcing_aligned_malloc>(size);
- }
-
- void operator delete(void * ptr) { ei_aligned_free(static_cast<ei_byte_forcing_aligned_malloc *>(ptr), 0); }
- void operator delete[](void * ptr) { ei_aligned_free(static_cast<ei_byte_forcing_aligned_malloc *>(ptr), 0); }
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
-template<typename T, int SizeAtCompileTime,
- bool NeedsToAlign = (SizeAtCompileTime!=Dynamic) && ((sizeof(T)*SizeAtCompileTime)%16==0)>
-struct ei_with_aligned_operator_new : public WithAlignedOperatorNew {};
-
-template<typename T, int SizeAtCompileTime>
-struct ei_with_aligned_operator_new<T,SizeAtCompileTime,false> {};
-
/** \class ei_new_allocator
*
* \brief stl compatible allocator to use with with fixed-size vector and matrix types
diff --git a/Eigen/src/Geometry/AlignedBox.h b/Eigen/src/Geometry/AlignedBox.h
index 1ff5774da..e0f820765 100644
--- a/Eigen/src/Geometry/AlignedBox.h
+++ b/Eigen/src/Geometry/AlignedBox.h
@@ -39,10 +39,9 @@
*/
template <typename _Scalar, int _AmbientDim>
class AlignedBox
- : public ei_with_aligned_operator_new<_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1>
{
public:
-
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE(_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1)
enum { AmbientDimAtCompileTime = _AmbientDim };
typedef _Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
diff --git a/Eigen/src/Geometry/Hyperplane.h b/Eigen/src/Geometry/Hyperplane.h
index 1ffdd2323..a3425f6cb 100644
--- a/Eigen/src/Geometry/Hyperplane.h
+++ b/Eigen/src/Geometry/Hyperplane.h
@@ -45,10 +45,9 @@
*/
template <typename _Scalar, int _AmbientDim>
class Hyperplane
- : public ei_with_aligned_operator_new<_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1>
{
public:
-
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE(_Scalar,_AmbientDim==Dynamic ? Dynamic : _AmbientDim+1)
enum { AmbientDimAtCompileTime = _AmbientDim };
typedef _Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
diff --git a/Eigen/src/Geometry/ParametrizedLine.h b/Eigen/src/Geometry/ParametrizedLine.h
index f8b506c36..da30c8e82 100644
--- a/Eigen/src/Geometry/ParametrizedLine.h
+++ b/Eigen/src/Geometry/ParametrizedLine.h
@@ -41,10 +41,9 @@
*/
template <typename _Scalar, int _AmbientDim>
class ParametrizedLine
- : public ei_with_aligned_operator_new<_Scalar,_AmbientDim>
{
public:
-
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE(_Scalar,_AmbientDim)
enum { AmbientDimAtCompileTime = _AmbientDim };
typedef _Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
diff --git a/Eigen/src/Geometry/Quaternion.h b/Eigen/src/Geometry/Quaternion.h
index fc259645a..31ea9ef36 100644
--- a/Eigen/src/Geometry/Quaternion.h
+++ b/Eigen/src/Geometry/Quaternion.h
@@ -59,13 +59,13 @@ template<typename _Scalar> struct ei_traits<Quaternion<_Scalar> >
template<typename _Scalar>
class Quaternion : public RotationBase<Quaternion<_Scalar>,3>
- , public ei_with_aligned_operator_new<_Scalar,4>
{
typedef RotationBase<Quaternion<_Scalar>,3> Base;
typedef Matrix<_Scalar, 4, 1> Coefficients;
Coefficients m_coeffs;
public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE(_Scalar,4)
using Base::operator*;
diff --git a/Eigen/src/Geometry/Scaling.h b/Eigen/src/Geometry/Scaling.h
index 06c073502..d46296707 100644
--- a/Eigen/src/Geometry/Scaling.h
+++ b/Eigen/src/Geometry/Scaling.h
@@ -41,9 +41,9 @@
*/
template<typename _Scalar, int _Dim>
class Scaling
- : public ei_with_aligned_operator_new<_Scalar,_Dim>
{
public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE(_Scalar,_Dim)
/** dimension of the space */
enum { Dim = _Dim };
/** the scalar type of the coefficients */
diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h
index aa8cd5766..fc7f5b002 100644
--- a/Eigen/src/Geometry/Transform.h
+++ b/Eigen/src/Geometry/Transform.h
@@ -61,10 +61,9 @@ struct ei_transform_product_impl;
*/
template<typename _Scalar, int _Dim>
class Transform
- : public ei_with_aligned_operator_new<_Scalar,_Dim==Dynamic ? Dynamic : (_Dim+1)*(_Dim+1)>
{
public:
-
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE(_Scalar,_Dim==Dynamic ? Dynamic : (_Dim+1)*(_Dim+1))
enum {
Dim = _Dim, ///< space dimension in which the transformation holds
HDim = _Dim+1 ///< size of a respective homogeneous vector
diff --git a/Eigen/src/Geometry/Translation.h b/Eigen/src/Geometry/Translation.h
index 577352635..ab8ce3899 100644
--- a/Eigen/src/Geometry/Translation.h
+++ b/Eigen/src/Geometry/Translation.h
@@ -41,9 +41,9 @@
*/
template<typename _Scalar, int _Dim>
class Translation
- : public ei_with_aligned_operator_new<_Scalar,_Dim>
{
public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE(_Scalar,_Dim)
/** dimension of the space */
enum { Dim = _Dim };
/** the scalar type of the coefficients */
diff --git a/doc/TopicLazyEvaluation.dox b/doc/TopicLazyEvaluation.dox
index 752ae5943..7df9824ba 100644
--- a/doc/TopicLazyEvaluation.dox
+++ b/doc/TopicLazyEvaluation.dox
@@ -26,7 +26,7 @@ So in the basic example,
\code matrix1 = matrix2 + matrix3; \endcode
-Eigen chooses lazy evaluation. Thus the arrays are traversed only once, producing optimized code. If you really want to force immediate evaluation, use \link MatrixBase::eval() eval() \endlink:
+Eigen chooses lazy evaluation. Thus the arrays are traversed only once, producing optimized code. If you really want to force immediate evaluation, use \link MatrixBase::eval() eval()\endlink:
\code matrix1 = (matrix2 + matrix3).eval(); \endcode
@@ -36,25 +36,25 @@ Here is now a more involved example:
Eigen chooses lazy evaluation at every stage in that example, which is clearly the correct choice. In fact, lazy evaluation is the "default choice" and Eigen will choose it except in a few circumstances.
-<b>The first circumstance</b> in which Eigen chooses immediate evaluation, is when it sees an assignment <tt>a = b;</tt> and the expression \c b has the evaluate-before-assigning \link flags flag \endlink. The most importat example of such an expression is the \link Product matrix product expression \endlink. For example, when you do
+<b>The first circumstance</b> in which Eigen chooses immediate evaluation, is when it sees an assignment <tt>a = b;</tt> and the expression \c b has the evaluate-before-assigning \link flags flag\endlink. The most important example of such an expression is the \link Product matrix product expression\endlink. For example, when you do
\code matrix = matrix * matrix; \endcode
Eigen first evaluates <tt>matrix * matrix</tt> into a temporary matrix, and then copies it into the original \c matrix. This guarantees a correct result as we saw above that lazy evaluation gives wrong results with matrix products. It also doesn't cost much, as the cost of the matrix product itself is much higher.
-What if you know what you are doing and want to force lazy evaluation? Then use \link MatrixBase::lazy() .lazy() \endlink instead. Here is an example:
+What if you know what you are doing and want to force lazy evaluation? Then use \link MatrixBase::lazy() .lazy()\endlink instead. Here is an example:
\code matrix1 = (matrix2 * matrix2).lazy(); \endcode
-Here, since we know that matrix2 is not the same matrix as matrix1, we know that lazy evaluation is not dangerous, so we may force lazy evaluation. Concretely, the effect of lazy() here is to remove the evaluate-before-assigning \link flags flag \endlink and also the evaluate-before-nesting \link flags flag \endlink which we now discuss.
+Here, since we know that matrix2 is not the same matrix as matrix1, we know that lazy evaluation is not dangerous, so we may force lazy evaluation. Concretely, the effect of lazy() here is to remove the evaluate-before-assigning \link flags flag\endlink and also the evaluate-before-nesting \link flags flag\endlink which we now discuss.
-<b>The second circumstance</b> in which Eigen chooses immediate evaluation, is when it sees a nested expression such as <tt>a + b</tt> where \c b is already an expression having the evaluate-before-nesting \link flags flag \endlink. Again, the most importat example of such an expression is the \link Product matrix product expression \endlink. For example, when you do
+<b>The second circumstance</b> in which Eigen chooses immediate evaluation, is when it sees a nested expression such as <tt>a + b</tt> where \c b is already an expression having the evaluate-before-nesting \link flags flag\endlink. Again, the most important example of such an expression is the \link Product matrix product expression\endlink. For example, when you do
\code matrix1 = matrix2 + matrix3 * matrix4; \endcode
the product <tt>matrix3 * matrix4</tt> gets evaluated immediately into a temporary matrix. Indeed, experiments showed that it is often beneficial for performance to evaluate immediately matrix products when they are nested into bigger expressions.
-Again, \link MatrixBase::lazy() .lazy() \endlink can be used to force lazy evaluation here.
+Again, \link MatrixBase::lazy() .lazy()\endlink can be used to force lazy evaluation here.
<b>The third circumstance</b> in which Eigen chooses immediate evaluation, is when its cost model shows that the total cost of an operation is reduced if a sub-expression gets evaluated into a temporary. Indeed, in certain cases, an intermediate result is sufficiently costly to compute and is reused sufficiently many times, that is worth "caching". Here is an example:
diff --git a/doc/UnalignedArrayAssert.dox b/doc/UnalignedArrayAssert.dox
index dddd00bb6..8fdd74fae 100644
--- a/doc/UnalignedArrayAssert.dox
+++ b/doc/UnalignedArrayAssert.dox
@@ -6,9 +6,11 @@ namespace Eigen {
- \ref what
- \ref how
- \ref why
+ - \ref stillstuck
+ - \ref stillstillstuck
- \ref movetotop
- \ref bugineigen
-
+ - \ref nomacro
<hr>
\section what What kind of code made this assertion fail?
@@ -43,14 +45,16 @@ By "vectorizable fixed-size Eigen object" we mean an Eigen matrix or vector of f
\section how How to fix this bug?
-Very easy, you just need to let your class Foo publicly inherit Eigen::WithAlignedOperatorNew, like this:
+Very easy, you just need to put a EIGEN_MAKE_ALIGNED_OPERATOR_NEW macro in a public part of your class, like this:
\code
-class Foo : public Eigen::WithAlignedOperatorNew
+class Foo
{
...
Eigen::Vector2d v;
...
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
...
@@ -91,25 +95,68 @@ The alignment attribute of the member v is then relative to the start of the cla
The solution is to let class Foo have an aligned "operator new", as we showed in the previous section.
+\section stillstuck It still doesn't work!
+
+If you followed these instructions and you still get this assertion failure, the most likely cause is that you are passing some Eigen objects (or classes containing Eigen objects) by value. Something like
+
+\code
+void my_function(Eigen::Vector2d v);
+\endcode
+
+This will easily make this assertion fail because when the parameter v is passed to the function, it is copied onto the stack at a location that may be unaligned. Normally the compiler will catch that (since v has an alignment modifier) but we have seen cases where MSVC let that compile without catching this error.
+
+Anyway, the solution is then to pass the parameter by reference instead of passing it by value:
+
+\code
+void my_function(const Eigen::Vector2d& v);
+\endcode
+
+Likewise if you have a class having a Eigen object as member:
+
+\code
+struct Foo
+{
+ Eigen::Vector2d v;
+};
+void my_function(Foo v);
+\endcode
+
+This function also needs to be rewritten like this:
+\code
+void my_function(const Foo& v);
+\endcode
+
+Notice that passing objects by value is always a bad idea, as it is inefficient to copy the parameters onto the stack. So this change is something that you should do anyway.
+
+On the other hand, there is no problem with functions that return objects by value.
+
+\section stillstillstuck It still, STILL doesn't work!
+
+Then you may have found a bug in Eigen. Please report it to our mailing list. Ideally, you would attach to your report a self-contained test case.
+
\section movetotop Should I then put all the members of Eigen types at the beginning of my class?
No, that's not needed. Since Eigen takes care of declaring 128-bit alignment, all members that need it are automatically 128-bit aligned relatively to the class. So when you have code like
\code
-class Foo : public Eigen::WithAlignedOperatorNew
+class Foo
{
double x;
Eigen::Vector2d v;
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
\endcode
it will work just fine. You do \b not need to rewrite it as
\code
-class Foo : public Eigen::WithAlignedOperatorNew
+class Foo
{
Eigen::Vector2d v;
double x;
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
\endcode
@@ -121,6 +168,51 @@ Dynamic-size matrices and vectors, such as Eigen::VectorXd, allocate dynamically
No, it's not our bug. It's more like an inherent problem of the C++ language -- though it must be said that any other existing language probably has the same problem. The problem is that there is no way that you can specify an aligned "operator new" that would propagate to classes having you as member data.
+\section nomacro I don't like macros! Any solution with inheritance?
+
+Yes, you can let your class Foo publicly inherit Eigen::WithAlignedOperatorNew, like this:
+
+\code
+class Foo : public Eigen::WithAlignedOperatorNew
+{
+ ...
+ Eigen::Vector2d v;
+ ...
+};
+
+...
+
+Foo *foo = new Foo;
+\endcode
+
+This solution gives the same result as the macro. It has the disadvantage that if Foo already had a base class, you are now doing multiple inheritance, and this situation is sometimes handled wrongly by certain compilers -- we've been having trouble with MSVC. The solution with the macro is therefore safer.
+
+\section conditional What if I want to do this conditionnally (depending on template parameters) ?
+
+For this situation, we offer the macro EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign). It will generate aligned operators like EIGEN_MAKE_ALIGNED_OPERATOR_NEW if NeedsToAlign is true. It will generate operators with the default alignment if NeedsToAlign is false.
+
+Example:
+
+\code
+template<int n> class Foo
+{
+ typedef Eigen::Matrix<float,n,1> Vector;
+ enum { NeedsToAlign = (sizeof(Vector)%16)==0 };
+ ...
+ Vector v;
+ ...
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
+};
+
+...
+
+Foo<4> *foo4 = new Foo<4>; // foo4 is guaranteed to be 128bit-aligned
+Foo<3> *foo3 = new Foo<3>; // foo3 has only the system default alignment guarantee
+\endcode
+
+Nore that the argument of EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF must depend on some template parameter(s). Passing an argument that does not depend on any template parameter will give a compilation error. Anyway if the argument does not depend on any template parameter, you could use EIGEN_MAKE_ALIGNED_OPERATOR_NEW instead.
+
*/
}
diff --git a/test/unalignedassert.cpp b/test/unalignedassert.cpp
index 0b5bf0c77..2d0b5a015 100644
--- a/test/unalignedassert.cpp
+++ b/test/unalignedassert.cpp
@@ -61,8 +61,9 @@ struct Good7 : Eigen::WithAlignedOperatorNew
float f; // make the struct have sizeof%16!=0 to make it a little more tricky when we allow an array of 2 such objects
};
-struct Good8 : Eigen::WithAlignedOperatorNew
+struct Good8
{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
float f; // try the f at first -- the EIGEN_ALIGN_128 attribute of m should make that still work
Matrix4f m;
};
@@ -73,6 +74,13 @@ struct Good9
float f;
};
+template<bool Align> struct Depends
+{
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(Align)
+ Vector2d m;
+ float f;
+};
+
template<typename T>
void check_unalignedassert_good()
{
@@ -104,6 +112,8 @@ void unalignedassert()
check_unalignedassert_good<Good7>();
check_unalignedassert_good<Good8>();
check_unalignedassert_good<Good9>();
+ check_unalignedassert_good<Depends<true> >();
+ VERIFY_RAISES_ASSERT(check_unalignedassert_bad<Depends<false> >());
}
void test_unalignedassert()