Implement A.noalias() = B * C without temporaries

* Wrap expression inside EvalToTemp in copy_using_evaluators() if we
  assume aliasing for that expression (that is, for products)
* Remove temporary kludge of evaluating expression to temporary in
  AllAtOnce traversal
* Implement EvalToTemp expression object
This commit is contained in:
Jitse Niesen 2012-06-29 13:54:09 +01:00
parent d0b873822f
commit 746378868a
3 changed files with 77 additions and 8 deletions

View File

@ -617,12 +617,8 @@ struct copy_using_evaluator_impl<DstXprType, SrcXprType, AllAtOnceTraversal, NoU
SrcEvaluatorType srcEvaluator(src);
// Evaluate rhs in temporary to prevent aliasing problems in a = a * a;
// TODO: Be smarter about this
// TODO: Do not pass the xpr object to evalTo()
typename DstXprType::PlainObject tmp;
typename evaluator<typename DstXprType::PlainObject>::type tmpEvaluator(tmp);
srcEvaluator.evalTo(tmpEvaluator, tmp);
copy_using_evaluator(dst, tmp);
srcEvaluator.evalTo(dstEvaluator, dst);
}
};
@ -640,11 +636,33 @@ const DstXprType& copy_using_evaluator(const NoAlias<DstXprType, StorageBase>& d
return noalias_copy_using_evaluator(dst.expression(), src.derived());
}
template<typename XprType, int AssumeAliasing = evaluator_traits<XprType>::AssumeAliasing>
struct AddEvalIfAssumingAliasing;
template<typename XprType>
struct AddEvalIfAssumingAliasing<XprType, 0>
{
static const XprType& run(const XprType& xpr)
{
return xpr;
}
};
template<typename XprType>
struct AddEvalIfAssumingAliasing<XprType, 1>
{
static const EvalToTemp<XprType> run(const XprType& xpr)
{
return EvalToTemp<XprType>(xpr);
}
};
template<typename DstXprType, typename SrcXprType>
EIGEN_STRONG_INLINE
const DstXprType& copy_using_evaluator(const EigenBase<DstXprType>& dst, const EigenBase<SrcXprType>& src)
{
return noalias_copy_using_evaluator(dst.const_cast_derived(), src.derived());
return noalias_copy_using_evaluator(dst.const_cast_derived(),
AddEvalIfAssumingAliasing<SrcXprType>::run(src.derived()));
}
template<typename DstXprType, typename SrcXprType>

View File

@ -40,6 +40,10 @@ struct evaluator_traits
// 1 if evaluator_impl<T>::evalTo() exists
// 0 if evaluator_impl<T> allows coefficient-based access
static const int HasEvalTo = 0;
// 1 if assignment A = B assumes aliasing when B is of type T and thus B needs to be evaluated into a
// temporary; 0 if not.
static const int AssumeAliasing = 0;
};
// expression class for evaluating nested expression to a temporary
@ -245,17 +249,62 @@ struct evaluator_impl<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols> >
// -------------------- EvalToTemp --------------------
template<typename ArgType>
struct traits<EvalToTemp<ArgType> >
: public traits<ArgType>
{ };
template<typename ArgType>
class EvalToTemp
: public dense_xpr_base<EvalToTemp<ArgType> >::type
{
public:
typedef typename dense_xpr_base<EvalToTemp>::type Base;
EIGEN_GENERIC_PUBLIC_INTERFACE(EvalToTemp)
EvalToTemp(const ArgType& arg)
: m_arg(arg)
{ }
const ArgType& arg() const
{
return m_arg;
}
Index rows() const
{
return m_arg.rows();
}
Index cols() const
{
return m_arg.cols();
}
private:
const ArgType& m_arg;
};
template<typename ArgType>
struct evaluator_impl<EvalToTemp<ArgType> >
: evaluator_impl<typename ArgType::PlainObject>
{
typedef EvalToTemp<ArgType> XprType;
typedef typename ArgType::PlainObject PlainObject;
typedef evaluator_impl<PlainObject> BaseType;
evaluator_impl(const XprType& xpr)
: BaseType(m_result)
{
noalias_copy_using_evaluator(m_result, xpr.arg());
};
// this constructor is used when nesting an EvalTo evaluator in another evaluator
evaluator_impl(const ArgType& arg)
: BaseType(m_result)
{
copy_using_evaluator(m_result, arg);
noalias_copy_using_evaluator(m_result, arg);
};
protected:

View File

@ -56,7 +56,9 @@ struct product_evaluator_traits_dispatcher;
template<typename Lhs, typename Rhs>
struct evaluator_traits<Product<Lhs, Rhs> >
: product_evaluator_traits_dispatcher<Product<Lhs, Rhs>, typename ProductReturnType<Lhs, Rhs>::Type>
{ };
{
static const int AssumeAliasing = 1;
};
// Case 1: Evaluate all at once
//