AssignEvaluator.h 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra.
  3. //
  4. // Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@gmail.com>
  5. // Copyright (C) 2011-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
  6. // Copyright (C) 2011-2012 Jitse Niesen <jitse@maths.leeds.ac.uk>
  7. //
  8. // This Source Code Form is subject to the terms of the Mozilla
  9. // Public License v. 2.0. If a copy of the MPL was not distributed
  10. // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
  11. #ifndef EIGEN_ASSIGN_EVALUATOR_H
  12. #define EIGEN_ASSIGN_EVALUATOR_H
  13. namespace Eigen {
  14. // This implementation is based on Assign.h
  15. namespace internal {
  16. /***************************************************************************
  17. * Part 1 : the logic deciding a strategy for traversal and unrolling *
  18. ***************************************************************************/
  19. // copy_using_evaluator_traits is based on assign_traits
  20. template <typename DstEvaluator, typename SrcEvaluator, typename AssignFunc>
  21. struct copy_using_evaluator_traits
  22. {
  23. typedef typename DstEvaluator::XprType Dst;
  24. typedef typename Dst::Scalar DstScalar;
  25. enum {
  26. DstFlags = DstEvaluator::Flags,
  27. SrcFlags = SrcEvaluator::Flags
  28. };
  29. public:
  30. enum {
  31. DstAlignment = DstEvaluator::Alignment,
  32. SrcAlignment = SrcEvaluator::Alignment,
  33. DstHasDirectAccess = (DstFlags & DirectAccessBit) == DirectAccessBit,
  34. JointAlignment = EIGEN_PLAIN_ENUM_MIN(DstAlignment,SrcAlignment)
  35. };
  36. private:
  37. enum {
  38. InnerSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::SizeAtCompileTime)
  39. : int(DstFlags)&RowMajorBit ? int(Dst::ColsAtCompileTime)
  40. : int(Dst::RowsAtCompileTime),
  41. InnerMaxSize = int(Dst::IsVectorAtCompileTime) ? int(Dst::MaxSizeAtCompileTime)
  42. : int(DstFlags)&RowMajorBit ? int(Dst::MaxColsAtCompileTime)
  43. : int(Dst::MaxRowsAtCompileTime),
  44. OuterStride = int(outer_stride_at_compile_time<Dst>::ret),
  45. MaxSizeAtCompileTime = Dst::SizeAtCompileTime
  46. };
  47. // TODO distinguish between linear traversal and inner-traversals
  48. typedef typename find_best_packet<DstScalar,Dst::SizeAtCompileTime>::type LinearPacketType;
  49. typedef typename find_best_packet<DstScalar,InnerSize>::type InnerPacketType;
  50. enum {
  51. LinearPacketSize = unpacket_traits<LinearPacketType>::size,
  52. InnerPacketSize = unpacket_traits<InnerPacketType>::size
  53. };
  54. public:
  55. enum {
  56. LinearRequiredAlignment = unpacket_traits<LinearPacketType>::alignment,
  57. InnerRequiredAlignment = unpacket_traits<InnerPacketType>::alignment
  58. };
  59. private:
  60. enum {
  61. DstIsRowMajor = DstFlags&RowMajorBit,
  62. SrcIsRowMajor = SrcFlags&RowMajorBit,
  63. StorageOrdersAgree = (int(DstIsRowMajor) == int(SrcIsRowMajor)),
  64. MightVectorize = bool(StorageOrdersAgree)
  65. && (int(DstFlags) & int(SrcFlags) & ActualPacketAccessBit)
  66. && bool(functor_traits<AssignFunc>::PacketAccess),
  67. MayInnerVectorize = MightVectorize
  68. && int(InnerSize)!=Dynamic && int(InnerSize)%int(InnerPacketSize)==0
  69. && int(OuterStride)!=Dynamic && int(OuterStride)%int(InnerPacketSize)==0
  70. && (EIGEN_UNALIGNED_VECTORIZE || int(JointAlignment)>=int(InnerRequiredAlignment)),
  71. MayLinearize = bool(StorageOrdersAgree) && (int(DstFlags) & int(SrcFlags) & LinearAccessBit),
  72. MayLinearVectorize = bool(MightVectorize) && bool(MayLinearize) && bool(DstHasDirectAccess)
  73. && (EIGEN_UNALIGNED_VECTORIZE || (int(DstAlignment)>=int(LinearRequiredAlignment)) || MaxSizeAtCompileTime == Dynamic),
  74. /* If the destination isn't aligned, we have to do runtime checks and we don't unroll,
  75. so it's only good for large enough sizes. */
  76. MaySliceVectorize = bool(MightVectorize) && bool(DstHasDirectAccess)
  77. && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=(EIGEN_UNALIGNED_VECTORIZE?InnerPacketSize:(3*InnerPacketSize)))
  78. /* slice vectorization can be slow, so we only want it if the slices are big, which is
  79. indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block
  80. in a fixed-size matrix
  81. However, with EIGEN_UNALIGNED_VECTORIZE and unrolling, slice vectorization is still worth it */
  82. };
  83. public:
  84. enum {
  85. Traversal = int(MayLinearVectorize) && (LinearPacketSize>InnerPacketSize) ? int(LinearVectorizedTraversal)
  86. : int(MayInnerVectorize) ? int(InnerVectorizedTraversal)
  87. : int(MayLinearVectorize) ? int(LinearVectorizedTraversal)
  88. : int(MaySliceVectorize) ? int(SliceVectorizedTraversal)
  89. : int(MayLinearize) ? int(LinearTraversal)
  90. : int(DefaultTraversal),
  91. Vectorized = int(Traversal) == InnerVectorizedTraversal
  92. || int(Traversal) == LinearVectorizedTraversal
  93. || int(Traversal) == SliceVectorizedTraversal
  94. };
  95. typedef typename conditional<int(Traversal)==LinearVectorizedTraversal, LinearPacketType, InnerPacketType>::type PacketType;
  96. private:
  97. enum {
  98. ActualPacketSize = int(Traversal)==LinearVectorizedTraversal ? LinearPacketSize
  99. : Vectorized ? InnerPacketSize
  100. : 1,
  101. UnrollingLimit = EIGEN_UNROLLING_LIMIT * ActualPacketSize,
  102. MayUnrollCompletely = int(Dst::SizeAtCompileTime) != Dynamic
  103. && int(Dst::SizeAtCompileTime) * (int(DstEvaluator::CoeffReadCost)+int(SrcEvaluator::CoeffReadCost)) <= int(UnrollingLimit),
  104. MayUnrollInner = int(InnerSize) != Dynamic
  105. && int(InnerSize) * (int(DstEvaluator::CoeffReadCost)+int(SrcEvaluator::CoeffReadCost)) <= int(UnrollingLimit)
  106. };
  107. public:
  108. enum {
  109. Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal))
  110. ? (
  111. int(MayUnrollCompletely) ? int(CompleteUnrolling)
  112. : int(MayUnrollInner) ? int(InnerUnrolling)
  113. : int(NoUnrolling)
  114. )
  115. : int(Traversal) == int(LinearVectorizedTraversal)
  116. ? ( bool(MayUnrollCompletely) && ( EIGEN_UNALIGNED_VECTORIZE || (int(DstAlignment)>=int(LinearRequiredAlignment)))
  117. ? int(CompleteUnrolling)
  118. : int(NoUnrolling) )
  119. : int(Traversal) == int(LinearTraversal)
  120. ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling)
  121. : int(NoUnrolling) )
  122. #if EIGEN_UNALIGNED_VECTORIZE
  123. : int(Traversal) == int(SliceVectorizedTraversal)
  124. ? ( bool(MayUnrollInner) ? int(InnerUnrolling)
  125. : int(NoUnrolling) )
  126. #endif
  127. : int(NoUnrolling)
  128. };
  129. #ifdef EIGEN_DEBUG_ASSIGN
  130. static void debug()
  131. {
  132. std::cerr << "DstXpr: " << typeid(typename DstEvaluator::XprType).name() << std::endl;
  133. std::cerr << "SrcXpr: " << typeid(typename SrcEvaluator::XprType).name() << std::endl;
  134. std::cerr.setf(std::ios::hex, std::ios::basefield);
  135. std::cerr << "DstFlags" << " = " << DstFlags << " (" << demangle_flags(DstFlags) << " )" << std::endl;
  136. std::cerr << "SrcFlags" << " = " << SrcFlags << " (" << demangle_flags(SrcFlags) << " )" << std::endl;
  137. std::cerr.unsetf(std::ios::hex);
  138. EIGEN_DEBUG_VAR(DstAlignment)
  139. EIGEN_DEBUG_VAR(SrcAlignment)
  140. EIGEN_DEBUG_VAR(LinearRequiredAlignment)
  141. EIGEN_DEBUG_VAR(InnerRequiredAlignment)
  142. EIGEN_DEBUG_VAR(JointAlignment)
  143. EIGEN_DEBUG_VAR(InnerSize)
  144. EIGEN_DEBUG_VAR(InnerMaxSize)
  145. EIGEN_DEBUG_VAR(LinearPacketSize)
  146. EIGEN_DEBUG_VAR(InnerPacketSize)
  147. EIGEN_DEBUG_VAR(ActualPacketSize)
  148. EIGEN_DEBUG_VAR(StorageOrdersAgree)
  149. EIGEN_DEBUG_VAR(MightVectorize)
  150. EIGEN_DEBUG_VAR(MayLinearize)
  151. EIGEN_DEBUG_VAR(MayInnerVectorize)
  152. EIGEN_DEBUG_VAR(MayLinearVectorize)
  153. EIGEN_DEBUG_VAR(MaySliceVectorize)
  154. std::cerr << "Traversal" << " = " << Traversal << " (" << demangle_traversal(Traversal) << ")" << std::endl;
  155. EIGEN_DEBUG_VAR(SrcEvaluator::CoeffReadCost)
  156. EIGEN_DEBUG_VAR(UnrollingLimit)
  157. EIGEN_DEBUG_VAR(MayUnrollCompletely)
  158. EIGEN_DEBUG_VAR(MayUnrollInner)
  159. std::cerr << "Unrolling" << " = " << Unrolling << " (" << demangle_unrolling(Unrolling) << ")" << std::endl;
  160. std::cerr << std::endl;
  161. }
  162. #endif
  163. };
  164. /***************************************************************************
  165. * Part 2 : meta-unrollers
  166. ***************************************************************************/
  167. /************************
  168. *** Default traversal ***
  169. ************************/
  170. template<typename Kernel, int Index, int Stop>
  171. struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling
  172. {
  173. // FIXME: this is not very clean, perhaps this information should be provided by the kernel?
  174. typedef typename Kernel::DstEvaluatorType DstEvaluatorType;
  175. typedef typename DstEvaluatorType::XprType DstXprType;
  176. enum {
  177. outer = Index / DstXprType::InnerSizeAtCompileTime,
  178. inner = Index % DstXprType::InnerSizeAtCompileTime
  179. };
  180. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  181. {
  182. kernel.assignCoeffByOuterInner(outer, inner);
  183. copy_using_evaluator_DefaultTraversal_CompleteUnrolling<Kernel, Index+1, Stop>::run(kernel);
  184. }
  185. };
  186. template<typename Kernel, int Stop>
  187. struct copy_using_evaluator_DefaultTraversal_CompleteUnrolling<Kernel, Stop, Stop>
  188. {
  189. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { }
  190. };
  191. template<typename Kernel, int Index_, int Stop>
  192. struct copy_using_evaluator_DefaultTraversal_InnerUnrolling
  193. {
  194. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index outer)
  195. {
  196. kernel.assignCoeffByOuterInner(outer, Index_);
  197. copy_using_evaluator_DefaultTraversal_InnerUnrolling<Kernel, Index_+1, Stop>::run(kernel, outer);
  198. }
  199. };
  200. template<typename Kernel, int Stop>
  201. struct copy_using_evaluator_DefaultTraversal_InnerUnrolling<Kernel, Stop, Stop>
  202. {
  203. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, Index) { }
  204. };
  205. /***********************
  206. *** Linear traversal ***
  207. ***********************/
  208. template<typename Kernel, int Index, int Stop>
  209. struct copy_using_evaluator_LinearTraversal_CompleteUnrolling
  210. {
  211. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel& kernel)
  212. {
  213. kernel.assignCoeff(Index);
  214. copy_using_evaluator_LinearTraversal_CompleteUnrolling<Kernel, Index+1, Stop>::run(kernel);
  215. }
  216. };
  217. template<typename Kernel, int Stop>
  218. struct copy_using_evaluator_LinearTraversal_CompleteUnrolling<Kernel, Stop, Stop>
  219. {
  220. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { }
  221. };
  222. /**************************
  223. *** Inner vectorization ***
  224. **************************/
  225. template<typename Kernel, int Index, int Stop>
  226. struct copy_using_evaluator_innervec_CompleteUnrolling
  227. {
  228. // FIXME: this is not very clean, perhaps this information should be provided by the kernel?
  229. typedef typename Kernel::DstEvaluatorType DstEvaluatorType;
  230. typedef typename DstEvaluatorType::XprType DstXprType;
  231. typedef typename Kernel::PacketType PacketType;
  232. enum {
  233. outer = Index / DstXprType::InnerSizeAtCompileTime,
  234. inner = Index % DstXprType::InnerSizeAtCompileTime,
  235. SrcAlignment = Kernel::AssignmentTraits::SrcAlignment,
  236. DstAlignment = Kernel::AssignmentTraits::DstAlignment
  237. };
  238. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  239. {
  240. kernel.template assignPacketByOuterInner<DstAlignment, SrcAlignment, PacketType>(outer, inner);
  241. enum { NextIndex = Index + unpacket_traits<PacketType>::size };
  242. copy_using_evaluator_innervec_CompleteUnrolling<Kernel, NextIndex, Stop>::run(kernel);
  243. }
  244. };
  245. template<typename Kernel, int Stop>
  246. struct copy_using_evaluator_innervec_CompleteUnrolling<Kernel, Stop, Stop>
  247. {
  248. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&) { }
  249. };
  250. template<typename Kernel, int Index_, int Stop, int SrcAlignment, int DstAlignment>
  251. struct copy_using_evaluator_innervec_InnerUnrolling
  252. {
  253. typedef typename Kernel::PacketType PacketType;
  254. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel, Index outer)
  255. {
  256. kernel.template assignPacketByOuterInner<DstAlignment, SrcAlignment, PacketType>(outer, Index_);
  257. enum { NextIndex = Index_ + unpacket_traits<PacketType>::size };
  258. copy_using_evaluator_innervec_InnerUnrolling<Kernel, NextIndex, Stop, SrcAlignment, DstAlignment>::run(kernel, outer);
  259. }
  260. };
  261. template<typename Kernel, int Stop, int SrcAlignment, int DstAlignment>
  262. struct copy_using_evaluator_innervec_InnerUnrolling<Kernel, Stop, Stop, SrcAlignment, DstAlignment>
  263. {
  264. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &, Index) { }
  265. };
  266. /***************************************************************************
  267. * Part 3 : implementation of all cases
  268. ***************************************************************************/
  269. // dense_assignment_loop is based on assign_impl
  270. template<typename Kernel,
  271. int Traversal = Kernel::AssignmentTraits::Traversal,
  272. int Unrolling = Kernel::AssignmentTraits::Unrolling>
  273. struct dense_assignment_loop;
  274. /************************
  275. *** Default traversal ***
  276. ************************/
  277. template<typename Kernel>
  278. struct dense_assignment_loop<Kernel, DefaultTraversal, NoUnrolling>
  279. {
  280. EIGEN_DEVICE_FUNC static void EIGEN_STRONG_INLINE run(Kernel &kernel)
  281. {
  282. for(Index outer = 0; outer < kernel.outerSize(); ++outer) {
  283. for(Index inner = 0; inner < kernel.innerSize(); ++inner) {
  284. kernel.assignCoeffByOuterInner(outer, inner);
  285. }
  286. }
  287. }
  288. };
  289. template<typename Kernel>
  290. struct dense_assignment_loop<Kernel, DefaultTraversal, CompleteUnrolling>
  291. {
  292. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  293. {
  294. typedef typename Kernel::DstEvaluatorType::XprType DstXprType;
  295. copy_using_evaluator_DefaultTraversal_CompleteUnrolling<Kernel, 0, DstXprType::SizeAtCompileTime>::run(kernel);
  296. }
  297. };
  298. template<typename Kernel>
  299. struct dense_assignment_loop<Kernel, DefaultTraversal, InnerUnrolling>
  300. {
  301. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  302. {
  303. typedef typename Kernel::DstEvaluatorType::XprType DstXprType;
  304. const Index outerSize = kernel.outerSize();
  305. for(Index outer = 0; outer < outerSize; ++outer)
  306. copy_using_evaluator_DefaultTraversal_InnerUnrolling<Kernel, 0, DstXprType::InnerSizeAtCompileTime>::run(kernel, outer);
  307. }
  308. };
  309. /***************************
  310. *** Linear vectorization ***
  311. ***************************/
  312. // The goal of unaligned_dense_assignment_loop is simply to factorize the handling
  313. // of the non vectorizable beginning and ending parts
  314. template <bool IsAligned = false>
  315. struct unaligned_dense_assignment_loop
  316. {
  317. // if IsAligned = true, then do nothing
  318. template <typename Kernel>
  319. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel&, Index, Index) {}
  320. };
  321. template <>
  322. struct unaligned_dense_assignment_loop<false>
  323. {
  324. // MSVC must not inline this functions. If it does, it fails to optimize the
  325. // packet access path.
  326. // FIXME check which version exhibits this issue
  327. #if EIGEN_COMP_MSVC
  328. template <typename Kernel>
  329. static EIGEN_DONT_INLINE void run(Kernel &kernel,
  330. Index start,
  331. Index end)
  332. #else
  333. template <typename Kernel>
  334. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel,
  335. Index start,
  336. Index end)
  337. #endif
  338. {
  339. for (Index index = start; index < end; ++index)
  340. kernel.assignCoeff(index);
  341. }
  342. };
  343. template<typename Kernel>
  344. struct dense_assignment_loop<Kernel, LinearVectorizedTraversal, NoUnrolling>
  345. {
  346. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  347. {
  348. const Index size = kernel.size();
  349. typedef typename Kernel::Scalar Scalar;
  350. typedef typename Kernel::PacketType PacketType;
  351. enum {
  352. requestedAlignment = Kernel::AssignmentTraits::LinearRequiredAlignment,
  353. packetSize = unpacket_traits<PacketType>::size,
  354. dstIsAligned = int(Kernel::AssignmentTraits::DstAlignment)>=int(requestedAlignment),
  355. dstAlignment = packet_traits<Scalar>::AlignedOnScalar ? int(requestedAlignment)
  356. : int(Kernel::AssignmentTraits::DstAlignment),
  357. srcAlignment = Kernel::AssignmentTraits::JointAlignment
  358. };
  359. const Index alignedStart = dstIsAligned ? 0 : internal::first_aligned<requestedAlignment>(kernel.dstDataPtr(), size);
  360. const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize;
  361. unaligned_dense_assignment_loop<dstIsAligned!=0>::run(kernel, 0, alignedStart);
  362. for(Index index = alignedStart; index < alignedEnd; index += packetSize)
  363. kernel.template assignPacket<dstAlignment, srcAlignment, PacketType>(index);
  364. unaligned_dense_assignment_loop<>::run(kernel, alignedEnd, size);
  365. }
  366. };
  367. template<typename Kernel>
  368. struct dense_assignment_loop<Kernel, LinearVectorizedTraversal, CompleteUnrolling>
  369. {
  370. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  371. {
  372. typedef typename Kernel::DstEvaluatorType::XprType DstXprType;
  373. typedef typename Kernel::PacketType PacketType;
  374. enum { size = DstXprType::SizeAtCompileTime,
  375. packetSize =unpacket_traits<PacketType>::size,
  376. alignedSize = (size/packetSize)*packetSize };
  377. copy_using_evaluator_innervec_CompleteUnrolling<Kernel, 0, alignedSize>::run(kernel);
  378. copy_using_evaluator_DefaultTraversal_CompleteUnrolling<Kernel, alignedSize, size>::run(kernel);
  379. }
  380. };
  381. /**************************
  382. *** Inner vectorization ***
  383. **************************/
  384. template<typename Kernel>
  385. struct dense_assignment_loop<Kernel, InnerVectorizedTraversal, NoUnrolling>
  386. {
  387. typedef typename Kernel::PacketType PacketType;
  388. enum {
  389. SrcAlignment = Kernel::AssignmentTraits::SrcAlignment,
  390. DstAlignment = Kernel::AssignmentTraits::DstAlignment
  391. };
  392. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  393. {
  394. const Index innerSize = kernel.innerSize();
  395. const Index outerSize = kernel.outerSize();
  396. const Index packetSize = unpacket_traits<PacketType>::size;
  397. for(Index outer = 0; outer < outerSize; ++outer)
  398. for(Index inner = 0; inner < innerSize; inner+=packetSize)
  399. kernel.template assignPacketByOuterInner<DstAlignment, SrcAlignment, PacketType>(outer, inner);
  400. }
  401. };
  402. template<typename Kernel>
  403. struct dense_assignment_loop<Kernel, InnerVectorizedTraversal, CompleteUnrolling>
  404. {
  405. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  406. {
  407. typedef typename Kernel::DstEvaluatorType::XprType DstXprType;
  408. copy_using_evaluator_innervec_CompleteUnrolling<Kernel, 0, DstXprType::SizeAtCompileTime>::run(kernel);
  409. }
  410. };
  411. template<typename Kernel>
  412. struct dense_assignment_loop<Kernel, InnerVectorizedTraversal, InnerUnrolling>
  413. {
  414. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  415. {
  416. typedef typename Kernel::DstEvaluatorType::XprType DstXprType;
  417. typedef typename Kernel::AssignmentTraits Traits;
  418. const Index outerSize = kernel.outerSize();
  419. for(Index outer = 0; outer < outerSize; ++outer)
  420. copy_using_evaluator_innervec_InnerUnrolling<Kernel, 0, DstXprType::InnerSizeAtCompileTime,
  421. Traits::SrcAlignment, Traits::DstAlignment>::run(kernel, outer);
  422. }
  423. };
  424. /***********************
  425. *** Linear traversal ***
  426. ***********************/
  427. template<typename Kernel>
  428. struct dense_assignment_loop<Kernel, LinearTraversal, NoUnrolling>
  429. {
  430. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  431. {
  432. const Index size = kernel.size();
  433. for(Index i = 0; i < size; ++i)
  434. kernel.assignCoeff(i);
  435. }
  436. };
  437. template<typename Kernel>
  438. struct dense_assignment_loop<Kernel, LinearTraversal, CompleteUnrolling>
  439. {
  440. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  441. {
  442. typedef typename Kernel::DstEvaluatorType::XprType DstXprType;
  443. copy_using_evaluator_LinearTraversal_CompleteUnrolling<Kernel, 0, DstXprType::SizeAtCompileTime>::run(kernel);
  444. }
  445. };
  446. /**************************
  447. *** Slice vectorization ***
  448. ***************************/
  449. template<typename Kernel>
  450. struct dense_assignment_loop<Kernel, SliceVectorizedTraversal, NoUnrolling>
  451. {
  452. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  453. {
  454. typedef typename Kernel::Scalar Scalar;
  455. typedef typename Kernel::PacketType PacketType;
  456. enum {
  457. packetSize = unpacket_traits<PacketType>::size,
  458. requestedAlignment = int(Kernel::AssignmentTraits::InnerRequiredAlignment),
  459. alignable = packet_traits<Scalar>::AlignedOnScalar || int(Kernel::AssignmentTraits::DstAlignment)>=sizeof(Scalar),
  460. dstIsAligned = int(Kernel::AssignmentTraits::DstAlignment)>=int(requestedAlignment),
  461. dstAlignment = alignable ? int(requestedAlignment)
  462. : int(Kernel::AssignmentTraits::DstAlignment)
  463. };
  464. const Scalar *dst_ptr = kernel.dstDataPtr();
  465. if((!bool(dstIsAligned)) && (UIntPtr(dst_ptr) % sizeof(Scalar))>0)
  466. {
  467. // the pointer is not aligend-on scalar, so alignment is not possible
  468. return dense_assignment_loop<Kernel,DefaultTraversal,NoUnrolling>::run(kernel);
  469. }
  470. const Index packetAlignedMask = packetSize - 1;
  471. const Index innerSize = kernel.innerSize();
  472. const Index outerSize = kernel.outerSize();
  473. const Index alignedStep = alignable ? (packetSize - kernel.outerStride() % packetSize) & packetAlignedMask : 0;
  474. Index alignedStart = ((!alignable) || bool(dstIsAligned)) ? 0 : internal::first_aligned<requestedAlignment>(dst_ptr, innerSize);
  475. for(Index outer = 0; outer < outerSize; ++outer)
  476. {
  477. const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask);
  478. // do the non-vectorizable part of the assignment
  479. for(Index inner = 0; inner<alignedStart ; ++inner)
  480. kernel.assignCoeffByOuterInner(outer, inner);
  481. // do the vectorizable part of the assignment
  482. for(Index inner = alignedStart; inner<alignedEnd; inner+=packetSize)
  483. kernel.template assignPacketByOuterInner<dstAlignment, Unaligned, PacketType>(outer, inner);
  484. // do the non-vectorizable part of the assignment
  485. for(Index inner = alignedEnd; inner<innerSize ; ++inner)
  486. kernel.assignCoeffByOuterInner(outer, inner);
  487. alignedStart = numext::mini((alignedStart+alignedStep)%packetSize, innerSize);
  488. }
  489. }
  490. };
  491. #if EIGEN_UNALIGNED_VECTORIZE
  492. template<typename Kernel>
  493. struct dense_assignment_loop<Kernel, SliceVectorizedTraversal, InnerUnrolling>
  494. {
  495. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE void run(Kernel &kernel)
  496. {
  497. typedef typename Kernel::DstEvaluatorType::XprType DstXprType;
  498. typedef typename Kernel::PacketType PacketType;
  499. enum { size = DstXprType::InnerSizeAtCompileTime,
  500. packetSize =unpacket_traits<PacketType>::size,
  501. vectorizableSize = (size/packetSize)*packetSize };
  502. for(Index outer = 0; outer < kernel.outerSize(); ++outer)
  503. {
  504. copy_using_evaluator_innervec_InnerUnrolling<Kernel, 0, vectorizableSize, 0, 0>::run(kernel, outer);
  505. copy_using_evaluator_DefaultTraversal_InnerUnrolling<Kernel, vectorizableSize, size>::run(kernel, outer);
  506. }
  507. }
  508. };
  509. #endif
  510. /***************************************************************************
  511. * Part 4 : Generic dense assignment kernel
  512. ***************************************************************************/
  513. // This class generalize the assignment of a coefficient (or packet) from one dense evaluator
  514. // to another dense writable evaluator.
  515. // It is parametrized by the two evaluators, and the actual assignment functor.
  516. // This abstraction level permits to keep the evaluation loops as simple and as generic as possible.
  517. // One can customize the assignment using this generic dense_assignment_kernel with different
  518. // functors, or by completely overloading it, by-passing a functor.
  519. template<typename DstEvaluatorTypeT, typename SrcEvaluatorTypeT, typename Functor, int Version = Specialized>
  520. class generic_dense_assignment_kernel
  521. {
  522. protected:
  523. typedef typename DstEvaluatorTypeT::XprType DstXprType;
  524. typedef typename SrcEvaluatorTypeT::XprType SrcXprType;
  525. public:
  526. typedef DstEvaluatorTypeT DstEvaluatorType;
  527. typedef SrcEvaluatorTypeT SrcEvaluatorType;
  528. typedef typename DstEvaluatorType::Scalar Scalar;
  529. typedef copy_using_evaluator_traits<DstEvaluatorTypeT, SrcEvaluatorTypeT, Functor> AssignmentTraits;
  530. typedef typename AssignmentTraits::PacketType PacketType;
  531. EIGEN_DEVICE_FUNC generic_dense_assignment_kernel(DstEvaluatorType &dst, const SrcEvaluatorType &src, const Functor &func, DstXprType& dstExpr)
  532. : m_dst(dst), m_src(src), m_functor(func), m_dstExpr(dstExpr)
  533. {
  534. #ifdef EIGEN_DEBUG_ASSIGN
  535. AssignmentTraits::debug();
  536. #endif
  537. }
  538. EIGEN_DEVICE_FUNC Index size() const { return m_dstExpr.size(); }
  539. EIGEN_DEVICE_FUNC Index innerSize() const { return m_dstExpr.innerSize(); }
  540. EIGEN_DEVICE_FUNC Index outerSize() const { return m_dstExpr.outerSize(); }
  541. EIGEN_DEVICE_FUNC Index rows() const { return m_dstExpr.rows(); }
  542. EIGEN_DEVICE_FUNC Index cols() const { return m_dstExpr.cols(); }
  543. EIGEN_DEVICE_FUNC Index outerStride() const { return m_dstExpr.outerStride(); }
  544. EIGEN_DEVICE_FUNC DstEvaluatorType& dstEvaluator() { return m_dst; }
  545. EIGEN_DEVICE_FUNC const SrcEvaluatorType& srcEvaluator() const { return m_src; }
  546. /// Assign src(row,col) to dst(row,col) through the assignment functor.
  547. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Index row, Index col)
  548. {
  549. m_functor.assignCoeff(m_dst.coeffRef(row,col), m_src.coeff(row,col));
  550. }
  551. /// \sa assignCoeff(Index,Index)
  552. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Index index)
  553. {
  554. m_functor.assignCoeff(m_dst.coeffRef(index), m_src.coeff(index));
  555. }
  556. /// \sa assignCoeff(Index,Index)
  557. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeffByOuterInner(Index outer, Index inner)
  558. {
  559. Index row = rowIndexByOuterInner(outer, inner);
  560. Index col = colIndexByOuterInner(outer, inner);
  561. assignCoeff(row, col);
  562. }
  563. template<int StoreMode, int LoadMode, typename PacketType>
  564. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacket(Index row, Index col)
  565. {
  566. m_functor.template assignPacket<StoreMode>(&m_dst.coeffRef(row,col), m_src.template packet<LoadMode,PacketType>(row,col));
  567. }
  568. template<int StoreMode, int LoadMode, typename PacketType>
  569. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacket(Index index)
  570. {
  571. m_functor.template assignPacket<StoreMode>(&m_dst.coeffRef(index), m_src.template packet<LoadMode,PacketType>(index));
  572. }
  573. template<int StoreMode, int LoadMode, typename PacketType>
  574. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignPacketByOuterInner(Index outer, Index inner)
  575. {
  576. Index row = rowIndexByOuterInner(outer, inner);
  577. Index col = colIndexByOuterInner(outer, inner);
  578. assignPacket<StoreMode,LoadMode,PacketType>(row, col);
  579. }
  580. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Index rowIndexByOuterInner(Index outer, Index inner)
  581. {
  582. typedef typename DstEvaluatorType::ExpressionTraits Traits;
  583. return int(Traits::RowsAtCompileTime) == 1 ? 0
  584. : int(Traits::ColsAtCompileTime) == 1 ? inner
  585. : int(DstEvaluatorType::Flags)&RowMajorBit ? outer
  586. : inner;
  587. }
  588. EIGEN_DEVICE_FUNC static EIGEN_STRONG_INLINE Index colIndexByOuterInner(Index outer, Index inner)
  589. {
  590. typedef typename DstEvaluatorType::ExpressionTraits Traits;
  591. return int(Traits::ColsAtCompileTime) == 1 ? 0
  592. : int(Traits::RowsAtCompileTime) == 1 ? inner
  593. : int(DstEvaluatorType::Flags)&RowMajorBit ? inner
  594. : outer;
  595. }
  596. EIGEN_DEVICE_FUNC const Scalar* dstDataPtr() const
  597. {
  598. return m_dstExpr.data();
  599. }
  600. protected:
  601. DstEvaluatorType& m_dst;
  602. const SrcEvaluatorType& m_src;
  603. const Functor &m_functor;
  604. // TODO find a way to avoid the needs of the original expression
  605. DstXprType& m_dstExpr;
  606. };
  607. /***************************************************************************
  608. * Part 5 : Entry point for dense rectangular assignment
  609. ***************************************************************************/
  610. template<typename DstXprType,typename SrcXprType, typename Functor>
  611. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
  612. void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const Functor &/*func*/)
  613. {
  614. EIGEN_ONLY_USED_FOR_DEBUG(dst);
  615. EIGEN_ONLY_USED_FOR_DEBUG(src);
  616. eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols());
  617. }
  618. template<typename DstXprType,typename SrcXprType, typename T1, typename T2>
  619. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
  620. void resize_if_allowed(DstXprType &dst, const SrcXprType& src, const internal::assign_op<T1,T2> &/*func*/)
  621. {
  622. Index dstRows = src.rows();
  623. Index dstCols = src.cols();
  624. if(((dst.rows()!=dstRows) || (dst.cols()!=dstCols)))
  625. dst.resize(dstRows, dstCols);
  626. eigen_assert(dst.rows() == dstRows && dst.cols() == dstCols);
  627. }
  628. template<typename DstXprType, typename SrcXprType, typename Functor>
  629. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src, const Functor &func)
  630. {
  631. typedef evaluator<DstXprType> DstEvaluatorType;
  632. typedef evaluator<SrcXprType> SrcEvaluatorType;
  633. SrcEvaluatorType srcEvaluator(src);
  634. // NOTE To properly handle A = (A*A.transpose())/s with A rectangular,
  635. // we need to resize the destination after the source evaluator has been created.
  636. resize_if_allowed(dst, src, func);
  637. DstEvaluatorType dstEvaluator(dst);
  638. typedef generic_dense_assignment_kernel<DstEvaluatorType,SrcEvaluatorType,Functor> Kernel;
  639. Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived());
  640. dense_assignment_loop<Kernel>::run(kernel);
  641. }
  642. template<typename DstXprType, typename SrcXprType>
  643. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src)
  644. {
  645. call_dense_assignment_loop(dst, src, internal::assign_op<typename DstXprType::Scalar,typename SrcXprType::Scalar>());
  646. }
  647. /***************************************************************************
  648. * Part 6 : Generic assignment
  649. ***************************************************************************/
  650. // Based on the respective shapes of the destination and source,
  651. // the class AssignmentKind determine the kind of assignment mechanism.
  652. // AssignmentKind must define a Kind typedef.
  653. template<typename DstShape, typename SrcShape> struct AssignmentKind;
  654. // Assignement kind defined in this file:
  655. struct Dense2Dense {};
  656. struct EigenBase2EigenBase {};
  657. template<typename,typename> struct AssignmentKind { typedef EigenBase2EigenBase Kind; };
  658. template<> struct AssignmentKind<DenseShape,DenseShape> { typedef Dense2Dense Kind; };
  659. // This is the main assignment class
  660. template< typename DstXprType, typename SrcXprType, typename Functor,
  661. typename Kind = typename AssignmentKind< typename evaluator_traits<DstXprType>::Shape , typename evaluator_traits<SrcXprType>::Shape >::Kind,
  662. typename EnableIf = void>
  663. struct Assignment;
  664. // The only purpose of this call_assignment() function is to deal with noalias() / "assume-aliasing" and automatic transposition.
  665. // Indeed, I (Gael) think that this concept of "assume-aliasing" was a mistake, and it makes thing quite complicated.
  666. // So this intermediate function removes everything related to "assume-aliasing" such that Assignment
  667. // does not has to bother about these annoying details.
  668. template<typename Dst, typename Src>
  669. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
  670. void call_assignment(Dst& dst, const Src& src)
  671. {
  672. call_assignment(dst, src, internal::assign_op<typename Dst::Scalar,typename Src::Scalar>());
  673. }
  674. template<typename Dst, typename Src>
  675. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
  676. void call_assignment(const Dst& dst, const Src& src)
  677. {
  678. call_assignment(dst, src, internal::assign_op<typename Dst::Scalar,typename Src::Scalar>());
  679. }
  680. // Deal with "assume-aliasing"
  681. template<typename Dst, typename Src, typename Func>
  682. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
  683. void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if< evaluator_assume_aliasing<Src>::value, void*>::type = 0)
  684. {
  685. typename plain_matrix_type<Src>::type tmp(src);
  686. call_assignment_no_alias(dst, tmp, func);
  687. }
  688. template<typename Dst, typename Src, typename Func>
  689. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
  690. void call_assignment(Dst& dst, const Src& src, const Func& func, typename enable_if<!evaluator_assume_aliasing<Src>::value, void*>::type = 0)
  691. {
  692. call_assignment_no_alias(dst, src, func);
  693. }
  694. // by-pass "assume-aliasing"
  695. // When there is no aliasing, we require that 'dst' has been properly resized
  696. template<typename Dst, template <typename> class StorageBase, typename Src, typename Func>
  697. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
  698. void call_assignment(NoAlias<Dst,StorageBase>& dst, const Src& src, const Func& func)
  699. {
  700. call_assignment_no_alias(dst.expression(), src, func);
  701. }
  702. template<typename Dst, typename Src, typename Func>
  703. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
  704. void call_assignment_no_alias(Dst& dst, const Src& src, const Func& func)
  705. {
  706. enum {
  707. NeedToTranspose = ( (int(Dst::RowsAtCompileTime) == 1 && int(Src::ColsAtCompileTime) == 1)
  708. || (int(Dst::ColsAtCompileTime) == 1 && int(Src::RowsAtCompileTime) == 1)
  709. ) && int(Dst::SizeAtCompileTime) != 1
  710. };
  711. typedef typename internal::conditional<NeedToTranspose, Transpose<Dst>, Dst>::type ActualDstTypeCleaned;
  712. typedef typename internal::conditional<NeedToTranspose, Transpose<Dst>, Dst&>::type ActualDstType;
  713. ActualDstType actualDst(dst);
  714. // TODO check whether this is the right place to perform these checks:
  715. EIGEN_STATIC_ASSERT_LVALUE(Dst)
  716. EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(ActualDstTypeCleaned,Src)
  717. EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename ActualDstTypeCleaned::Scalar,typename Src::Scalar);
  718. Assignment<ActualDstTypeCleaned,Src,Func>::run(actualDst, src, func);
  719. }
  720. template<typename Dst, typename Src>
  721. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
  722. void call_assignment_no_alias(Dst& dst, const Src& src)
  723. {
  724. call_assignment_no_alias(dst, src, internal::assign_op<typename Dst::Scalar,typename Src::Scalar>());
  725. }
  726. template<typename Dst, typename Src, typename Func>
  727. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
  728. void call_assignment_no_alias_no_transpose(Dst& dst, const Src& src, const Func& func)
  729. {
  730. // TODO check whether this is the right place to perform these checks:
  731. EIGEN_STATIC_ASSERT_LVALUE(Dst)
  732. EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Dst,Src)
  733. EIGEN_CHECK_BINARY_COMPATIBILIY(Func,typename Dst::Scalar,typename Src::Scalar);
  734. Assignment<Dst,Src,Func>::run(dst, src, func);
  735. }
  736. template<typename Dst, typename Src>
  737. EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
  738. void call_assignment_no_alias_no_transpose(Dst& dst, const Src& src)
  739. {
  740. call_assignment_no_alias_no_transpose(dst, src, internal::assign_op<typename Dst::Scalar,typename Src::Scalar>());
  741. }
  742. // forward declaration
  743. template<typename Dst, typename Src> void check_for_aliasing(const Dst &dst, const Src &src);
  744. // Generic Dense to Dense assignment
  745. // Note that the last template argument "Weak" is needed to make it possible to perform
  746. // both partial specialization+SFINAE without ambiguous specialization
  747. template< typename DstXprType, typename SrcXprType, typename Functor, typename Weak>
  748. struct Assignment<DstXprType, SrcXprType, Functor, Dense2Dense, Weak>
  749. {
  750. EIGEN_DEVICE_FUNC
  751. static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const Functor &func)
  752. {
  753. #ifndef EIGEN_NO_DEBUG
  754. internal::check_for_aliasing(dst, src);
  755. #endif
  756. call_dense_assignment_loop(dst, src, func);
  757. }
  758. };
  759. // Generic assignment through evalTo.
  760. // TODO: not sure we have to keep that one, but it helps porting current code to new evaluator mechanism.
  761. // Note that the last template argument "Weak" is needed to make it possible to perform
  762. // both partial specialization+SFINAE without ambiguous specialization
  763. template< typename DstXprType, typename SrcXprType, typename Functor, typename Weak>
  764. struct Assignment<DstXprType, SrcXprType, Functor, EigenBase2EigenBase, Weak>
  765. {
  766. EIGEN_DEVICE_FUNC
  767. static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::assign_op<typename DstXprType::Scalar,typename SrcXprType::Scalar> &/*func*/)
  768. {
  769. Index dstRows = src.rows();
  770. Index dstCols = src.cols();
  771. if((dst.rows()!=dstRows) || (dst.cols()!=dstCols))
  772. dst.resize(dstRows, dstCols);
  773. eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols());
  774. src.evalTo(dst);
  775. }
  776. // NOTE The following two functions are templated to avoid their instanciation if not needed
  777. // This is needed because some expressions supports evalTo only and/or have 'void' as scalar type.
  778. template<typename SrcScalarType>
  779. EIGEN_DEVICE_FUNC
  780. static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::add_assign_op<typename DstXprType::Scalar,SrcScalarType> &/*func*/)
  781. {
  782. Index dstRows = src.rows();
  783. Index dstCols = src.cols();
  784. if((dst.rows()!=dstRows) || (dst.cols()!=dstCols))
  785. dst.resize(dstRows, dstCols);
  786. eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols());
  787. src.addTo(dst);
  788. }
  789. template<typename SrcScalarType>
  790. EIGEN_DEVICE_FUNC
  791. static EIGEN_STRONG_INLINE void run(DstXprType &dst, const SrcXprType &src, const internal::sub_assign_op<typename DstXprType::Scalar,SrcScalarType> &/*func*/)
  792. {
  793. Index dstRows = src.rows();
  794. Index dstCols = src.cols();
  795. if((dst.rows()!=dstRows) || (dst.cols()!=dstCols))
  796. dst.resize(dstRows, dstCols);
  797. eigen_assert(dst.rows() == src.rows() && dst.cols() == src.cols());
  798. src.subTo(dst);
  799. }
  800. };
  801. } // namespace internal
  802. } // end namespace Eigen
  803. #endif // EIGEN_ASSIGN_EVALUATOR_H