* more cleaning in Product

* make Matrix2f (and similar) vectorized using linear path
* fix a couple of warnings and compilation issues with ICC and gcc 3.3/3.4
  (cannot get Transform compiles with gcc 3.3/3.4, see the FIXME)
This commit is contained in:
Gael Guennebaud 2008-06-19 23:00:51 +00:00
parent 82c3cea1d5
commit fb4a151982
7 changed files with 112 additions and 136 deletions

View File

@ -238,7 +238,7 @@ template<typename Derived1, typename Derived2>
struct ei_assign_impl<Derived1, Derived2, NoVectorization, InnerUnrolling> struct ei_assign_impl<Derived1, Derived2, NoVectorization, InnerUnrolling>
{ {
static void run(Derived1 &dst, const Derived2 &src) static void run(Derived1 &dst, const Derived2 &src)
{ {
const bool rowMajor = int(Derived1::Flags)&RowMajorBit; const bool rowMajor = int(Derived1::Flags)&RowMajorBit;
const int innerSize = rowMajor ? Derived1::ColsAtCompileTime : Derived1::RowsAtCompileTime; const int innerSize = rowMajor ? Derived1::ColsAtCompileTime : Derived1::RowsAtCompileTime;
const int outerSize = rowMajor ? dst.rows() : dst.cols(); const int outerSize = rowMajor ? dst.rows() : dst.cols();
@ -268,7 +268,7 @@ struct ei_assign_impl<Derived1, Derived2, InnerVectorization, NoUnrolling>
const int row = rowMajor ? j : i; const int row = rowMajor ? j : i;
const int col = rowMajor ? i : j; const int col = rowMajor ? i : j;
dst.template writePacket<Aligned>(row, col, src.template packet<Aligned>(row, col)); dst.template writePacket<Aligned>(row, col, src.template packet<Aligned>(row, col));
} }
} }
} }
}; };
@ -351,23 +351,25 @@ struct ei_assign_impl<Derived1, Derived2, LinearVectorization, CompleteUnrolling
{ {
inline static void run(Derived1 &dst, const Derived2 &src) inline static void run(Derived1 &dst, const Derived2 &src)
{ {
const int size = Derived1::SizeAtCompileTime; enum {
const int packetSize = ei_packet_traits<typename Derived1::Scalar>::size; size = Derived1::SizeAtCompileTime,
const int alignedSize = (size/packetSize)*packetSize; packetSize = ei_packet_traits<typename Derived1::Scalar>::size,
const bool rowMajor = Derived1::Flags&RowMajorBit; alignedSize = (int(size)/int(packetSize))*int(packetSize),
const int innerSize = rowMajor ? Derived1::ColsAtCompileTime : Derived1::RowsAtCompileTime; rowMajor = int(Derived1::Flags)&RowMajorBit,
const int outerSize = rowMajor ? Derived1::RowsAtCompileTime : Derived1::ColsAtCompileTime; innerSize = int(rowMajor) ? int(Derived1::ColsAtCompileTime) : int(Derived1::RowsAtCompileTime),
int index = 0; outerSize = int(rowMajor) ? int(Derived1::RowsAtCompileTime) : int(Derived1::ColsAtCompileTime)
};
// do the vectorizable part of the assignment // do the vectorizable part of the assignment
ei_assign_innervec_CompleteUnrolling<Derived1, Derived2, 0, alignedSize>::run(dst, src); ei_assign_innervec_CompleteUnrolling<Derived1, Derived2, 0, alignedSize>::run(dst, src);
// now we must do the rest without vectorization. // now we must do the rest without vectorization.
const int k = alignedSize/innerSize; enum {
const int i = alignedSize%innerSize; k = int(alignedSize)/int(innerSize),
i = int(alignedSize)%int(innerSize)
};
// do the remainder of the current row or col // do the remainder of the current row or col
ei_assign_novec_InnerUnrolling<Derived1, Derived2, i, innerSize>::run(dst, src, k); ei_assign_novec_InnerUnrolling<Derived1, Derived2, i, int(k)<int(outerSize) ? int(innerSize) : 0>::run(dst, src, k);
// do the remaining rows or cols // do the remaining rows or cols
for(int j = k+1; j < outerSize; j++) for(int j = k+1; j < outerSize; j++)

View File

@ -101,8 +101,8 @@ template<typename MatrixType> class DiagonalCoeffs
* *
* \sa class DiagonalCoeffs */ * \sa class DiagonalCoeffs */
template<typename Derived> template<typename Derived>
DiagonalCoeffs<Derived> inline DiagonalCoeffs<Derived>
inline MatrixBase<Derived>::diagonal() MatrixBase<Derived>::diagonal()
{ {
return DiagonalCoeffs<Derived>(derived()); return DiagonalCoeffs<Derived>(derived());
} }

View File

@ -201,14 +201,21 @@ template<typename LhsNested, typename RhsNested, int ProductMode> class Product
ei_assert(lhs.cols() == rhs.rows()); ei_assert(lhs.cols() == rhs.rows());
} }
/** \internal */ /** \internal
template<typename DestDerived> * compute \a res += \c *this using the cache friendly product.
void _cacheFriendlyEval(DestDerived& res) const; */
/** \internal */
template<typename DestDerived> template<typename DestDerived>
void _cacheFriendlyEvalAndAdd(DestDerived& res) const; void _cacheFriendlyEvalAndAdd(DestDerived& res) const;
/** \internal
* \returns whether it is worth it to use the cache friendly product.
*/
inline bool _useCacheFriendlyProduct() const {
return _rows()>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
&& _cols()>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
&& m_lhs.cols()>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD;
}
private: private:
inline int _rows() const { return m_lhs.rows(); } inline int _rows() const { return m_lhs.rows(); }
@ -229,7 +236,7 @@ template<typename LhsNested, typename RhsNested, int ProductMode> class Product
return res; return res;
} }
template<typename Lhs_, typename Rhs_, int EvalMode_, typename DestDerived_, bool DirectAccess_> template<typename Lhs_, typename Rhs_, int ProductMode_, typename DestDerived_, bool DirectAccess_>
friend struct ei_cache_friendly_selector; friend struct ei_cache_friendly_selector;
protected: protected:
@ -419,7 +426,10 @@ template<typename Lhs,typename Rhs>
inline Derived& inline Derived&
MatrixBase<Derived>::operator+=(const Flagged<Product<Lhs,Rhs,CacheFriendlyProduct>, 0, EvalBeforeNestingBit | EvalBeforeAssigningBit>& other) MatrixBase<Derived>::operator+=(const Flagged<Product<Lhs,Rhs,CacheFriendlyProduct>, 0, EvalBeforeNestingBit | EvalBeforeAssigningBit>& other)
{ {
other._expression()._cacheFriendlyEvalAndAdd(const_cast_derived()); if (other._expression()._useCacheFriendlyProduct())
other._expression()._cacheFriendlyEvalAndAdd(const_cast_derived());
else
lazyAssign(derived() + other._expression());
return derived(); return derived();
} }
@ -427,7 +437,15 @@ template<typename Derived>
template<typename Lhs, typename Rhs> template<typename Lhs, typename Rhs>
inline Derived& MatrixBase<Derived>::lazyAssign(const Product<Lhs,Rhs,CacheFriendlyProduct>& product) inline Derived& MatrixBase<Derived>::lazyAssign(const Product<Lhs,Rhs,CacheFriendlyProduct>& product)
{ {
product._cacheFriendlyEval(derived()); if (product._useCacheFriendlyProduct())
{
setZero();
product._cacheFriendlyEvalAndAdd(derived());
}
else
{
lazyAssign<Product<Lhs,Rhs,CacheFriendlyProduct> >(product);
}
return derived(); return derived();
} }
@ -472,61 +490,22 @@ template<typename T> struct ei_product_copy_lhs
>::ret type; >::ret type;
}; };
template<typename Lhs, typename Rhs, int EvalMode> template<typename Lhs, typename Rhs, int ProductMode>
template<typename DestDerived> template<typename DestDerived>
inline void Product<Lhs,Rhs,EvalMode>::_cacheFriendlyEval(DestDerived& res) const inline void Product<Lhs,Rhs,ProductMode>::_cacheFriendlyEvalAndAdd(DestDerived& res) const
{ {
if ( _rows()>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD typedef typename ei_product_copy_lhs<_LhsNested>::type LhsCopy;
&& _cols()>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD typedef typename ei_unref<LhsCopy>::type _LhsCopy;
&& m_lhs.cols()>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD typedef typename ei_product_copy_rhs<_RhsNested>::type RhsCopy;
) typedef typename ei_unref<RhsCopy>::type _RhsCopy;
{ LhsCopy lhs(m_lhs);
res.setZero(); RhsCopy rhs(m_rhs);
typedef typename ei_product_copy_lhs<_LhsNested>::type LhsCopy; ei_cache_friendly_product<Scalar>(
typedef typename ei_unref<LhsCopy>::type _LhsCopy; _rows(), _cols(), lhs.cols(),
typedef typename ei_product_copy_rhs<_RhsNested>::type RhsCopy; _LhsCopy::Flags&RowMajorBit, &(lhs.const_cast_derived().coeffRef(0,0)), lhs.stride(),
typedef typename ei_unref<RhsCopy>::type _RhsCopy; _RhsCopy::Flags&RowMajorBit, &(rhs.const_cast_derived().coeffRef(0,0)), rhs.stride(),
LhsCopy lhs(m_lhs); Flags&RowMajorBit, &(res.coeffRef(0,0)), res.stride()
RhsCopy rhs(m_rhs); );
ei_cache_friendly_product<Scalar>(
_rows(), _cols(), lhs.cols(),
_LhsCopy::Flags&RowMajorBit, &(lhs.const_cast_derived().coeffRef(0,0)), lhs.stride(),
_RhsCopy::Flags&RowMajorBit, &(rhs.const_cast_derived().coeffRef(0,0)), rhs.stride(),
Flags&RowMajorBit, &(res.coeffRef(0,0)), res.stride()
);
}
else
{
res = Product<_LhsNested,_RhsNested,NormalProduct>(m_lhs, m_rhs).lazy();
}
}
template<typename Lhs, typename Rhs, int EvalMode>
template<typename DestDerived>
inline void Product<Lhs,Rhs,EvalMode>::_cacheFriendlyEvalAndAdd(DestDerived& res) const
{
if ( _rows()>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
&& _cols()>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
&& m_lhs.cols()>=EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
)
{
typedef typename ei_product_copy_lhs<_LhsNested>::type LhsCopy;
typedef typename ei_unref<LhsCopy>::type _LhsCopy;
typedef typename ei_product_copy_rhs<_RhsNested>::type RhsCopy;
typedef typename ei_unref<RhsCopy>::type _RhsCopy;
LhsCopy lhs(m_lhs);
RhsCopy rhs(m_rhs);
ei_cache_friendly_product<Scalar>(
_rows(), _cols(), lhs.cols(),
_LhsCopy::Flags&RowMajorBit, &(lhs.const_cast_derived().coeffRef(0,0)), lhs.stride(),
_RhsCopy::Flags&RowMajorBit, &(rhs.const_cast_derived().coeffRef(0,0)), rhs.stride(),
Flags&RowMajorBit, &(res.coeffRef(0,0)), res.stride()
);
}
else
{
res += Product<_LhsNested,_RhsNested,NormalProduct>(m_lhs, m_rhs).lazy();
}
} }
#endif // EIGEN_PRODUCT_H #endif // EIGEN_PRODUCT_H

View File

@ -101,8 +101,8 @@ MatrixBase<Derived>::redux(const BinaryOp& func) const
* \sa trace() * \sa trace()
*/ */
template<typename Derived> template<typename Derived>
typename ei_traits<Derived>::Scalar inline typename ei_traits<Derived>::Scalar
inline MatrixBase<Derived>::sum() const MatrixBase<Derived>::sum() const
{ {
return this->redux(Eigen::ei_scalar_sum_op<Scalar>()); return this->redux(Eigen::ei_scalar_sum_op<Scalar>());
} }
@ -114,8 +114,8 @@ inline MatrixBase<Derived>::sum() const
* \sa diagonal(), sum() * \sa diagonal(), sum()
*/ */
template<typename Derived> template<typename Derived>
typename ei_traits<Derived>::Scalar inline typename ei_traits<Derived>::Scalar
inline MatrixBase<Derived>::trace() const MatrixBase<Derived>::trace() const
{ {
return diagonal().sum(); return diagonal().sum();
} }
@ -123,8 +123,8 @@ inline MatrixBase<Derived>::trace() const
/** \returns the minimum of all coefficients of *this /** \returns the minimum of all coefficients of *this
*/ */
template<typename Derived> template<typename Derived>
typename ei_traits<Derived>::Scalar inline typename ei_traits<Derived>::Scalar
inline MatrixBase<Derived>::minCoeff() const MatrixBase<Derived>::minCoeff() const
{ {
return this->redux(Eigen::ei_scalar_min_op<Scalar>()); return this->redux(Eigen::ei_scalar_min_op<Scalar>());
} }
@ -132,8 +132,8 @@ inline MatrixBase<Derived>::minCoeff() const
/** \returns the maximum of all coefficients of *this /** \returns the maximum of all coefficients of *this
*/ */
template<typename Derived> template<typename Derived>
typename ei_traits<Derived>::Scalar inline typename ei_traits<Derived>::Scalar
inline MatrixBase<Derived>::maxCoeff() const MatrixBase<Derived>::maxCoeff() const
{ {
return this->redux(Eigen::ei_scalar_max_op<Scalar>()); return this->redux(Eigen::ei_scalar_max_op<Scalar>());
} }

View File

@ -156,10 +156,10 @@ class ei_corrected_matrix_flags
? SuggestedFlags&RowMajorBit ? SuggestedFlags&RowMajorBit
: Cols > 1 ? RowMajorBit : 0, : Cols > 1 ? RowMajorBit : 0,
is_big = MaxRows == Dynamic || MaxCols == Dynamic, is_big = MaxRows == Dynamic || MaxCols == Dynamic,
inner_size = row_major_bit ? Cols : Rows, linear_size = Cols * Rows,
packet_access_bit packet_access_bit
= ei_packet_traits<Scalar>::size > 1 = ei_packet_traits<Scalar>::size > 1
&& (is_big || inner_size%ei_packet_traits<Scalar>::size==0) && (is_big || linear_size%ei_packet_traits<Scalar>::size==0)
? PacketAccessBit : 0 ? PacketAccessBit : 0
}; };

View File

@ -28,8 +28,8 @@
/** \returns the cross product of \c *this and \a other */ /** \returns the cross product of \c *this and \a other */
template<typename Derived> template<typename Derived>
template<typename OtherDerived> template<typename OtherDerived>
typename ei_eval<Derived>::type inline typename ei_eval<Derived>::type
inline MatrixBase<Derived>::cross(const MatrixBase<OtherDerived>& other) const MatrixBase<Derived>::cross(const MatrixBase<OtherDerived>& other) const
{ {
// Note that there is no need for an expression here since the compiler // Note that there is no need for an expression here since the compiler
// optimize such a small temporary very well (even within a complex expression) // optimize such a small temporary very well (even within a complex expression)

View File

@ -62,6 +62,47 @@ protected:
int OtherCols=Other::ColsAtCompileTime> int OtherCols=Other::ColsAtCompileTime>
struct ei_transform_product_impl; struct ei_transform_product_impl;
// FIXME these specializations of ei_transform_product_impl does not work with gcc 3.3 and 3.4 because
// Dim depends on a template parameter. Replacing Dim by 3 (for the 3D case) works.
// note that these specializations have to be defined here,
// otherwise some compilers (at least ICC and NVCC) complain about
// the use of Dim in the specialization parameters.
template<typename Other>
struct ei_transform_product_impl<Other,Dim+1,Dim+1>
{
typedef typename Transform<Scalar,Dim>::MatrixType MatrixType;
typedef typename ProductReturnType<MatrixType,Other>::Type ResultType;
static ResultType run(const Transform<Scalar,Dim>& tr, const Other& other)
{ return tr.matrix() * other; }
};
template<typename Other>
struct ei_transform_product_impl<Other,Dim+1,1>
{
typedef typename Transform<Scalar,Dim>::MatrixType MatrixType;
typedef typename ProductReturnType<MatrixType,Other>::Type ResultType;
static ResultType run(const Transform<Scalar,Dim>& tr, const Other& other)
{ return tr.matrix() * other; }
};
template<typename Other>
struct ei_transform_product_impl<Other,Dim,1>
{
typedef typename Transform<Scalar,Dim>::AffineMatrixRef MatrixType;
typedef const CwiseUnaryOp<
ei_scalar_multiple_op<Scalar>,
NestByValue<CwiseBinaryOp<
ei_scalar_sum_op<Scalar>,
NestByValue<typename ProductReturnType<NestByValue<MatrixType>,Other>::Type >,
NestByValue<typename Transform<Scalar,Dim>::VectorRef> > >
> ResultType;
// FIXME shall we offer an optimized version when the last row is know to be 0,0...,0,1 ?
static ResultType run(const Transform<Scalar,Dim>& tr, const Other& other)
{ return ((tr.affine().nestByValue() * other).nestByValue() + tr.translation().nestByValue()).nestByValue()
* (Scalar(1) / ( (tr.matrix().template block<1,Dim>(Dim,0) * other).coeff(0) + tr.matrix().coeff(Dim,Dim))); }
};
public: public:
/** Default constructor without initialization of the coefficients. */ /** Default constructor without initialization of the coefficients. */
@ -103,13 +144,7 @@ public:
inline VectorRef translation() { return m_matrix.template block<Dim,1>(0,Dim); } inline VectorRef translation() { return m_matrix.template block<Dim,1>(0,Dim); }
template<typename OtherDerived> template<typename OtherDerived>
struct TransformProductReturnType const typename ei_transform_product_impl<OtherDerived>::ResultType
{
typedef typename ei_transform_product_impl<OtherDerived>::ResultType Type;
};
template<typename OtherDerived>
const typename TransformProductReturnType<OtherDerived>::Type
operator * (const MatrixBase<OtherDerived> &other) const; operator * (const MatrixBase<OtherDerived> &other) const;
/** Contatenates two transformations */ /** Contatenates two transformations */
@ -192,7 +227,7 @@ QMatrix Transform<Scalar,Dim>::toQMatrix(void) const
template<typename Scalar, int Dim> template<typename Scalar, int Dim>
template<typename OtherDerived> template<typename OtherDerived>
const typename Transform<Scalar,Dim>::template TransformProductReturnType<OtherDerived>::Type const typename Transform<Scalar,Dim>::template ei_transform_product_impl<OtherDerived>::ResultType
Transform<Scalar,Dim>::operator*(const MatrixBase<OtherDerived> &other) const Transform<Scalar,Dim>::operator*(const MatrixBase<OtherDerived> &other) const
{ {
return ei_transform_product_impl<OtherDerived>::run(*this,other.derived()); return ei_transform_product_impl<OtherDerived>::run(*this,other.derived());
@ -373,44 +408,4 @@ Transform<Scalar,Dim>::fromPositionOrientationScale(const MatrixBase<PositionDer
return *this; return *this;
} }
//----------
template<typename Scalar, int Dim>
template<typename Other>
struct Transform<Scalar,Dim>::ei_transform_product_impl<Other,Dim+1,Dim+1>
{
typedef typename Transform<Scalar,Dim>::MatrixType MatrixType;
typedef typename ProductReturnType<MatrixType,Other>::Type ResultType;
static ResultType run(const Transform<Scalar,Dim>& tr, const Other& other)
{ return tr.matrix() * other; }
};
template<typename Scalar, int Dim>
template<typename Other>
struct Transform<Scalar,Dim>::ei_transform_product_impl<Other,Dim+1,1>
{
typedef typename Transform<Scalar,Dim>::MatrixType MatrixType;
typedef typename ProductReturnType<MatrixType,Other>::Type ResultType;
static ResultType run(const Transform<Scalar,Dim>& tr, const Other& other)
{ return tr.matrix() * other; }
};
template<typename Scalar, int Dim>
template<typename Other>
struct Transform<Scalar,Dim>::ei_transform_product_impl<Other,Dim,1>
{
typedef typename Transform<Scalar,Dim>::AffineMatrixRef MatrixType;
typedef const CwiseUnaryOp<
ei_scalar_multiple_op<Scalar>,
NestByValue<CwiseBinaryOp<
ei_scalar_sum_op<Scalar>,
NestByValue<typename ProductReturnType<NestByValue<MatrixType>,Other>::Type >,
NestByValue<typename Transform<Scalar,Dim>::VectorRef> > >
> ResultType;
// FIXME shall we offer an optimized version when the last row is know to be 0,0...,0,1 ?
static ResultType run(const Transform<Scalar,Dim>& tr, const Other& other)
{ return ((tr.affine().nestByValue() * other).nestByValue() + tr.translation().nestByValue()).nestByValue()
* (Scalar(1) / ( (tr.matrix().template block<1,Dim>(Dim,0) * other).coeff(0) + tr.matrix().coeff(Dim,Dim))); }
};
#endif // EIGEN_TRANSFORM_H #endif // EIGEN_TRANSFORM_H