Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/Eigen2/Eigen/src/Core/CacheFriendlyProduct.h')
-rw-r--r--extern/Eigen2/Eigen/src/Core/CacheFriendlyProduct.h753
1 files changed, 0 insertions, 753 deletions
diff --git a/extern/Eigen2/Eigen/src/Core/CacheFriendlyProduct.h b/extern/Eigen2/Eigen/src/Core/CacheFriendlyProduct.h
deleted file mode 100644
index b1362b0a80c..00000000000
--- a/extern/Eigen2/Eigen/src/Core/CacheFriendlyProduct.h
+++ /dev/null
@@ -1,753 +0,0 @@
-// This file is part of Eigen, a lightweight C++ template library
-// for linear algebra. Eigen itself is part of the KDE project.
-//
-// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
-//
-// Eigen is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 3 of the License, or (at your option) any later version.
-//
-// Alternatively, you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of
-// the License, or (at your option) any later version.
-//
-// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
-// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License and a copy of the GNU General Public License along with
-// Eigen. If not, see <http://www.gnu.org/licenses/>.
-
-#ifndef EIGEN_CACHE_FRIENDLY_PRODUCT_H
-#define EIGEN_CACHE_FRIENDLY_PRODUCT_H
-
-template <int L2MemorySize,typename Scalar>
-struct ei_L2_block_traits {
- enum {width = 8 * ei_meta_sqrt<L2MemorySize/(64*sizeof(Scalar))>::ret };
-};
-
-#ifndef EIGEN_EXTERN_INSTANTIATIONS
-
-template<typename Scalar>
-static void ei_cache_friendly_product(
- int _rows, int _cols, int depth,
- bool _lhsRowMajor, const Scalar* _lhs, int _lhsStride,
- bool _rhsRowMajor, const Scalar* _rhs, int _rhsStride,
- bool resRowMajor, Scalar* res, int resStride)
-{
- const Scalar* EIGEN_RESTRICT lhs;
- const Scalar* EIGEN_RESTRICT rhs;
- int lhsStride, rhsStride, rows, cols;
- bool lhsRowMajor;
-
- if (resRowMajor)
- {
- lhs = _rhs;
- rhs = _lhs;
- lhsStride = _rhsStride;
- rhsStride = _lhsStride;
- cols = _rows;
- rows = _cols;
- lhsRowMajor = !_rhsRowMajor;
- ei_assert(_lhsRowMajor);
- }
- else
- {
- lhs = _lhs;
- rhs = _rhs;
- lhsStride = _lhsStride;
- rhsStride = _rhsStride;
- rows = _rows;
- cols = _cols;
- lhsRowMajor = _lhsRowMajor;
- ei_assert(!_rhsRowMajor);
- }
-
- typedef typename ei_packet_traits<Scalar>::type PacketType;
-
- enum {
- PacketSize = sizeof(PacketType)/sizeof(Scalar),
- #if (defined __i386__)
- // i386 architecture provides only 8 xmm registers,
- // so let's reduce the max number of rows processed at once.
- MaxBlockRows = 4,
- MaxBlockRows_ClampingMask = 0xFFFFFC,
- #else
- MaxBlockRows = 8,
- MaxBlockRows_ClampingMask = 0xFFFFF8,
- #endif
- // maximal size of the blocks fitted in L2 cache
- MaxL2BlockSize = ei_L2_block_traits<EIGEN_TUNE_FOR_CPU_CACHE_SIZE,Scalar>::width
- };
-
- const bool resIsAligned = (PacketSize==1) || (((resStride%PacketSize) == 0) && (size_t(res)%16==0));
-
- const int remainingSize = depth % PacketSize;
- const int size = depth - remainingSize; // third dimension of the product clamped to packet boundaries
- const int l2BlockRows = MaxL2BlockSize > rows ? rows : MaxL2BlockSize;
- const int l2BlockCols = MaxL2BlockSize > cols ? cols : MaxL2BlockSize;
- const int l2BlockSize = MaxL2BlockSize > size ? size : MaxL2BlockSize;
- const int l2BlockSizeAligned = (1 + std::max(l2BlockSize,l2BlockCols)/PacketSize)*PacketSize;
- const bool needRhsCopy = (PacketSize>1) && ((rhsStride%PacketSize!=0) || (size_t(rhs)%16!=0));
- Scalar* EIGEN_RESTRICT block = 0;
- const int allocBlockSize = l2BlockRows*size;
- block = ei_aligned_stack_new(Scalar, allocBlockSize);
- Scalar* EIGEN_RESTRICT rhsCopy
- = ei_aligned_stack_new(Scalar, l2BlockSizeAligned*l2BlockSizeAligned);
-
- // loops on each L2 cache friendly blocks of the result
- for(int l2i=0; l2i<rows; l2i+=l2BlockRows)
- {
- const int l2blockRowEnd = std::min(l2i+l2BlockRows, rows);
- const int l2blockRowEndBW = l2blockRowEnd & MaxBlockRows_ClampingMask; // end of the rows aligned to bw
- const int l2blockRemainingRows = l2blockRowEnd - l2blockRowEndBW; // number of remaining rows
- //const int l2blockRowEndBWPlusOne = l2blockRowEndBW + (l2blockRemainingRows?0:MaxBlockRows);
-
- // build a cache friendly blocky matrix
- int count = 0;
-
- // copy l2blocksize rows of m_lhs to blocks of ps x bw
- for(int l2k=0; l2k<size; l2k+=l2BlockSize)
- {
- const int l2blockSizeEnd = std::min(l2k+l2BlockSize, size);
-
- for (int i = l2i; i<l2blockRowEndBW/*PlusOne*/; i+=MaxBlockRows)
- {
- // TODO merge the "if l2blockRemainingRows" using something like:
- // const int blockRows = std::min(i+MaxBlockRows, rows) - i;
-
- for (int k=l2k; k<l2blockSizeEnd; k+=PacketSize)
- {
- // TODO write these loops using meta unrolling
- // negligible for large matrices but useful for small ones
- if (lhsRowMajor)
- {
- for (int w=0; w<MaxBlockRows; ++w)
- for (int s=0; s<PacketSize; ++s)
- block[count++] = lhs[(i+w)*lhsStride + (k+s)];
- }
- else
- {
- for (int w=0; w<MaxBlockRows; ++w)
- for (int s=0; s<PacketSize; ++s)
- block[count++] = lhs[(i+w) + (k+s)*lhsStride];
- }
- }
- }
- if (l2blockRemainingRows>0)
- {
- for (int k=l2k; k<l2blockSizeEnd; k+=PacketSize)
- {
- if (lhsRowMajor)
- {
- for (int w=0; w<l2blockRemainingRows; ++w)
- for (int s=0; s<PacketSize; ++s)
- block[count++] = lhs[(l2blockRowEndBW+w)*lhsStride + (k+s)];
- }
- else
- {
- for (int w=0; w<l2blockRemainingRows; ++w)
- for (int s=0; s<PacketSize; ++s)
- block[count++] = lhs[(l2blockRowEndBW+w) + (k+s)*lhsStride];
- }
- }
- }
- }
-
- for(int l2j=0; l2j<cols; l2j+=l2BlockCols)
- {
- int l2blockColEnd = std::min(l2j+l2BlockCols, cols);
-
- for(int l2k=0; l2k<size; l2k+=l2BlockSize)
- {
- // acumulate bw rows of lhs time a single column of rhs to a bw x 1 block of res
- int l2blockSizeEnd = std::min(l2k+l2BlockSize, size);
-
- // if not aligned, copy the rhs block
- if (needRhsCopy)
- for(int l1j=l2j; l1j<l2blockColEnd; l1j+=1)
- {
- ei_internal_assert(l2BlockSizeAligned*(l1j-l2j)+(l2blockSizeEnd-l2k) < l2BlockSizeAligned*l2BlockSizeAligned);
- memcpy(rhsCopy+l2BlockSizeAligned*(l1j-l2j),&(rhs[l1j*rhsStride+l2k]),(l2blockSizeEnd-l2k)*sizeof(Scalar));
- }
-
- // for each bw x 1 result's block
- for(int l1i=l2i; l1i<l2blockRowEndBW; l1i+=MaxBlockRows)
- {
- int offsetblock = l2k * (l2blockRowEnd-l2i) + (l1i-l2i)*(l2blockSizeEnd-l2k) - l2k*MaxBlockRows;
- const Scalar* EIGEN_RESTRICT localB = &block[offsetblock];
-
- for(int l1j=l2j; l1j<l2blockColEnd; l1j+=1)
- {
- const Scalar* EIGEN_RESTRICT rhsColumn;
- if (needRhsCopy)
- rhsColumn = &(rhsCopy[l2BlockSizeAligned*(l1j-l2j)-l2k]);
- else
- rhsColumn = &(rhs[l1j*rhsStride]);
-
- PacketType dst[MaxBlockRows];
- dst[3] = dst[2] = dst[1] = dst[0] = ei_pset1(Scalar(0.));
- if (MaxBlockRows==8)
- dst[7] = dst[6] = dst[5] = dst[4] = dst[0];
-
- PacketType tmp;
-
- for(int k=l2k; k<l2blockSizeEnd; k+=PacketSize)
- {
- tmp = ei_ploadu(&rhsColumn[k]);
- PacketType A0, A1, A2, A3, A4, A5;
- A0 = ei_pload(localB + k*MaxBlockRows);
- A1 = ei_pload(localB + k*MaxBlockRows+1*PacketSize);
- A2 = ei_pload(localB + k*MaxBlockRows+2*PacketSize);
- A3 = ei_pload(localB + k*MaxBlockRows+3*PacketSize);
- if (MaxBlockRows==8) A4 = ei_pload(localB + k*MaxBlockRows+4*PacketSize);
- if (MaxBlockRows==8) A5 = ei_pload(localB + k*MaxBlockRows+5*PacketSize);
- dst[0] = ei_pmadd(tmp, A0, dst[0]);
- if (MaxBlockRows==8) A0 = ei_pload(localB + k*MaxBlockRows+6*PacketSize);
- dst[1] = ei_pmadd(tmp, A1, dst[1]);
- if (MaxBlockRows==8) A1 = ei_pload(localB + k*MaxBlockRows+7*PacketSize);
- dst[2] = ei_pmadd(tmp, A2, dst[2]);
- dst[3] = ei_pmadd(tmp, A3, dst[3]);
- if (MaxBlockRows==8)
- {
- dst[4] = ei_pmadd(tmp, A4, dst[4]);
- dst[5] = ei_pmadd(tmp, A5, dst[5]);
- dst[6] = ei_pmadd(tmp, A0, dst[6]);
- dst[7] = ei_pmadd(tmp, A1, dst[7]);
- }
- }
-
- Scalar* EIGEN_RESTRICT localRes = &(res[l1i + l1j*resStride]);
-
- if (PacketSize>1 && resIsAligned)
- {
- // the result is aligned: let's do packet reduction
- ei_pstore(&(localRes[0]), ei_padd(ei_pload(&(localRes[0])), ei_preduxp(&dst[0])));
- if (PacketSize==2)
- ei_pstore(&(localRes[2]), ei_padd(ei_pload(&(localRes[2])), ei_preduxp(&(dst[2]))));
- if (MaxBlockRows==8)
- {
- ei_pstore(&(localRes[4]), ei_padd(ei_pload(&(localRes[4])), ei_preduxp(&(dst[4]))));
- if (PacketSize==2)
- ei_pstore(&(localRes[6]), ei_padd(ei_pload(&(localRes[6])), ei_preduxp(&(dst[6]))));
- }
- }
- else
- {
- // not aligned => per coeff packet reduction
- localRes[0] += ei_predux(dst[0]);
- localRes[1] += ei_predux(dst[1]);
- localRes[2] += ei_predux(dst[2]);
- localRes[3] += ei_predux(dst[3]);
- if (MaxBlockRows==8)
- {
- localRes[4] += ei_predux(dst[4]);
- localRes[5] += ei_predux(dst[5]);
- localRes[6] += ei_predux(dst[6]);
- localRes[7] += ei_predux(dst[7]);
- }
- }
- }
- }
- if (l2blockRemainingRows>0)
- {
- int offsetblock = l2k * (l2blockRowEnd-l2i) + (l2blockRowEndBW-l2i)*(l2blockSizeEnd-l2k) - l2k*l2blockRemainingRows;
- const Scalar* localB = &block[offsetblock];
-
- for(int l1j=l2j; l1j<l2blockColEnd; l1j+=1)
- {
- const Scalar* EIGEN_RESTRICT rhsColumn;
- if (needRhsCopy)
- rhsColumn = &(rhsCopy[l2BlockSizeAligned*(l1j-l2j)-l2k]);
- else
- rhsColumn = &(rhs[l1j*rhsStride]);
-
- PacketType dst[MaxBlockRows];
- dst[3] = dst[2] = dst[1] = dst[0] = ei_pset1(Scalar(0.));
- if (MaxBlockRows==8)
- dst[7] = dst[6] = dst[5] = dst[4] = dst[0];
-
- // let's declare a few other temporary registers
- PacketType tmp;
-
- for(int k=l2k; k<l2blockSizeEnd; k+=PacketSize)
- {
- tmp = ei_pload(&rhsColumn[k]);
-
- dst[0] = ei_pmadd(tmp, ei_pload(&(localB[k*l2blockRemainingRows ])), dst[0]);
- if (l2blockRemainingRows>=2) dst[1] = ei_pmadd(tmp, ei_pload(&(localB[k*l2blockRemainingRows+ PacketSize])), dst[1]);
- if (l2blockRemainingRows>=3) dst[2] = ei_pmadd(tmp, ei_pload(&(localB[k*l2blockRemainingRows+2*PacketSize])), dst[2]);
- if (l2blockRemainingRows>=4) dst[3] = ei_pmadd(tmp, ei_pload(&(localB[k*l2blockRemainingRows+3*PacketSize])), dst[3]);
- if (MaxBlockRows==8)
- {
- if (l2blockRemainingRows>=5) dst[4] = ei_pmadd(tmp, ei_pload(&(localB[k*l2blockRemainingRows+4*PacketSize])), dst[4]);
- if (l2blockRemainingRows>=6) dst[5] = ei_pmadd(tmp, ei_pload(&(localB[k*l2blockRemainingRows+5*PacketSize])), dst[5]);
- if (l2blockRemainingRows>=7) dst[6] = ei_pmadd(tmp, ei_pload(&(localB[k*l2blockRemainingRows+6*PacketSize])), dst[6]);
- if (l2blockRemainingRows>=8) dst[7] = ei_pmadd(tmp, ei_pload(&(localB[k*l2blockRemainingRows+7*PacketSize])), dst[7]);
- }
- }
-
- Scalar* EIGEN_RESTRICT localRes = &(res[l2blockRowEndBW + l1j*resStride]);
-
- // process the remaining rows once at a time
- localRes[0] += ei_predux(dst[0]);
- if (l2blockRemainingRows>=2) localRes[1] += ei_predux(dst[1]);
- if (l2blockRemainingRows>=3) localRes[2] += ei_predux(dst[2]);
- if (l2blockRemainingRows>=4) localRes[3] += ei_predux(dst[3]);
- if (MaxBlockRows==8)
- {
- if (l2blockRemainingRows>=5) localRes[4] += ei_predux(dst[4]);
- if (l2blockRemainingRows>=6) localRes[5] += ei_predux(dst[5]);
- if (l2blockRemainingRows>=7) localRes[6] += ei_predux(dst[6]);
- if (l2blockRemainingRows>=8) localRes[7] += ei_predux(dst[7]);
- }
-
- }
- }
- }
- }
- }
- if (PacketSize>1 && remainingSize)
- {
- if (lhsRowMajor)
- {
- for (int j=0; j<cols; ++j)
- for (int i=0; i<rows; ++i)
- {
- Scalar tmp = lhs[i*lhsStride+size] * rhs[j*rhsStride+size];
- // FIXME this loop get vectorized by the compiler !
- for (int k=1; k<remainingSize; ++k)
- tmp += lhs[i*lhsStride+size+k] * rhs[j*rhsStride+size+k];
- res[i+j*resStride] += tmp;
- }
- }
- else
- {
- for (int j=0; j<cols; ++j)
- for (int i=0; i<rows; ++i)
- {
- Scalar tmp = lhs[i+size*lhsStride] * rhs[j*rhsStride+size];
- for (int k=1; k<remainingSize; ++k)
- tmp += lhs[i+(size+k)*lhsStride] * rhs[j*rhsStride+size+k];
- res[i+j*resStride] += tmp;
- }
- }
- }
-
- ei_aligned_stack_delete(Scalar, block, allocBlockSize);
- ei_aligned_stack_delete(Scalar, rhsCopy, l2BlockSizeAligned*l2BlockSizeAligned);
-}
-
-#endif // EIGEN_EXTERN_INSTANTIATIONS
-
-/* Optimized col-major matrix * vector product:
- * This algorithm processes 4 columns at onces that allows to both reduce
- * the number of load/stores of the result by a factor 4 and to reduce
- * the instruction dependency. Moreover, we know that all bands have the
- * same alignment pattern.
- * TODO: since rhs gets evaluated only once, no need to evaluate it
- */
-template<typename Scalar, typename RhsType>
-static EIGEN_DONT_INLINE void ei_cache_friendly_product_colmajor_times_vector(
- int size,
- const Scalar* lhs, int lhsStride,
- const RhsType& rhs,
- Scalar* res)
-{
- #ifdef _EIGEN_ACCUMULATE_PACKETS
- #error _EIGEN_ACCUMULATE_PACKETS has already been defined
- #endif
- #define _EIGEN_ACCUMULATE_PACKETS(A0,A13,A2) \
- ei_pstore(&res[j], \
- ei_padd(ei_pload(&res[j]), \
- ei_padd( \
- ei_padd(ei_pmul(ptmp0,EIGEN_CAT(ei_ploa , A0)(&lhs0[j])), \
- ei_pmul(ptmp1,EIGEN_CAT(ei_ploa , A13)(&lhs1[j]))), \
- ei_padd(ei_pmul(ptmp2,EIGEN_CAT(ei_ploa , A2)(&lhs2[j])), \
- ei_pmul(ptmp3,EIGEN_CAT(ei_ploa , A13)(&lhs3[j]))) )))
-
- typedef typename ei_packet_traits<Scalar>::type Packet;
- const int PacketSize = sizeof(Packet)/sizeof(Scalar);
-
- enum { AllAligned = 0, EvenAligned, FirstAligned, NoneAligned };
- const int columnsAtOnce = 4;
- const int peels = 2;
- const int PacketAlignedMask = PacketSize-1;
- const int PeelAlignedMask = PacketSize*peels-1;
-
- // How many coeffs of the result do we have to skip to be aligned.
- // Here we assume data are at least aligned on the base scalar type that is mandatory anyway.
- const int alignedStart = ei_alignmentOffset(res,size);
- const int alignedSize = PacketSize>1 ? alignedStart + ((size-alignedStart) & ~PacketAlignedMask) : 0;
- const int peeledSize = peels>1 ? alignedStart + ((alignedSize-alignedStart) & ~PeelAlignedMask) : alignedStart;
-
- const int alignmentStep = PacketSize>1 ? (PacketSize - lhsStride % PacketSize) & PacketAlignedMask : 0;
- int alignmentPattern = alignmentStep==0 ? AllAligned
- : alignmentStep==(PacketSize/2) ? EvenAligned
- : FirstAligned;
-
- // we cannot assume the first element is aligned because of sub-matrices
- const int lhsAlignmentOffset = ei_alignmentOffset(lhs,size);
-
- // find how many columns do we have to skip to be aligned with the result (if possible)
- int skipColumns = 0;
- if (PacketSize>1)
- {
- ei_internal_assert(size_t(lhs+lhsAlignmentOffset)%sizeof(Packet)==0 || size<PacketSize);
-
- while (skipColumns<PacketSize &&
- alignedStart != ((lhsAlignmentOffset + alignmentStep*skipColumns)%PacketSize))
- ++skipColumns;
- if (skipColumns==PacketSize)
- {
- // nothing can be aligned, no need to skip any column
- alignmentPattern = NoneAligned;
- skipColumns = 0;
- }
- else
- {
- skipColumns = std::min(skipColumns,rhs.size());
- // note that the skiped columns are processed later.
- }
-
- ei_internal_assert((alignmentPattern==NoneAligned) || (size_t(lhs+alignedStart+lhsStride*skipColumns)%sizeof(Packet))==0);
- }
-
- int offset1 = (FirstAligned && alignmentStep==1?3:1);
- int offset3 = (FirstAligned && alignmentStep==1?1:3);
-
- int columnBound = ((rhs.size()-skipColumns)/columnsAtOnce)*columnsAtOnce + skipColumns;
- for (int i=skipColumns; i<columnBound; i+=columnsAtOnce)
- {
- Packet ptmp0 = ei_pset1(rhs[i]), ptmp1 = ei_pset1(rhs[i+offset1]),
- ptmp2 = ei_pset1(rhs[i+2]), ptmp3 = ei_pset1(rhs[i+offset3]);
-
- // this helps a lot generating better binary code
- const Scalar *lhs0 = lhs + i*lhsStride, *lhs1 = lhs + (i+offset1)*lhsStride,
- *lhs2 = lhs + (i+2)*lhsStride, *lhs3 = lhs + (i+offset3)*lhsStride;
-
- if (PacketSize>1)
- {
- /* explicit vectorization */
- // process initial unaligned coeffs
- for (int j=0; j<alignedStart; ++j)
- res[j] += ei_pfirst(ptmp0)*lhs0[j] + ei_pfirst(ptmp1)*lhs1[j] + ei_pfirst(ptmp2)*lhs2[j] + ei_pfirst(ptmp3)*lhs3[j];
-
- if (alignedSize>alignedStart)
- {
- switch(alignmentPattern)
- {
- case AllAligned:
- for (int j = alignedStart; j<alignedSize; j+=PacketSize)
- _EIGEN_ACCUMULATE_PACKETS(d,d,d);
- break;
- case EvenAligned:
- for (int j = alignedStart; j<alignedSize; j+=PacketSize)
- _EIGEN_ACCUMULATE_PACKETS(d,du,d);
- break;
- case FirstAligned:
- if(peels>1)
- {
- Packet A00, A01, A02, A03, A10, A11, A12, A13;
-
- A01 = ei_pload(&lhs1[alignedStart-1]);
- A02 = ei_pload(&lhs2[alignedStart-2]);
- A03 = ei_pload(&lhs3[alignedStart-3]);
-
- for (int j = alignedStart; j<peeledSize; j+=peels*PacketSize)
- {
- A11 = ei_pload(&lhs1[j-1+PacketSize]); ei_palign<1>(A01,A11);
- A12 = ei_pload(&lhs2[j-2+PacketSize]); ei_palign<2>(A02,A12);
- A13 = ei_pload(&lhs3[j-3+PacketSize]); ei_palign<3>(A03,A13);
-
- A00 = ei_pload (&lhs0[j]);
- A10 = ei_pload (&lhs0[j+PacketSize]);
- A00 = ei_pmadd(ptmp0, A00, ei_pload(&res[j]));
- A10 = ei_pmadd(ptmp0, A10, ei_pload(&res[j+PacketSize]));
-
- A00 = ei_pmadd(ptmp1, A01, A00);
- A01 = ei_pload(&lhs1[j-1+2*PacketSize]); ei_palign<1>(A11,A01);
- A00 = ei_pmadd(ptmp2, A02, A00);
- A02 = ei_pload(&lhs2[j-2+2*PacketSize]); ei_palign<2>(A12,A02);
- A00 = ei_pmadd(ptmp3, A03, A00);
- ei_pstore(&res[j],A00);
- A03 = ei_pload(&lhs3[j-3+2*PacketSize]); ei_palign<3>(A13,A03);
- A10 = ei_pmadd(ptmp1, A11, A10);
- A10 = ei_pmadd(ptmp2, A12, A10);
- A10 = ei_pmadd(ptmp3, A13, A10);
- ei_pstore(&res[j+PacketSize],A10);
- }
- }
- for (int j = peeledSize; j<alignedSize; j+=PacketSize)
- _EIGEN_ACCUMULATE_PACKETS(d,du,du);
- break;
- default:
- for (int j = alignedStart; j<alignedSize; j+=PacketSize)
- _EIGEN_ACCUMULATE_PACKETS(du,du,du);
- break;
- }
- }
- } // end explicit vectorization
-
- /* process remaining coeffs (or all if there is no explicit vectorization) */
- for (int j=alignedSize; j<size; ++j)
- res[j] += ei_pfirst(ptmp0)*lhs0[j] + ei_pfirst(ptmp1)*lhs1[j] + ei_pfirst(ptmp2)*lhs2[j] + ei_pfirst(ptmp3)*lhs3[j];
- }
-
- // process remaining first and last columns (at most columnsAtOnce-1)
- int end = rhs.size();
- int start = columnBound;
- do
- {
- for (int i=start; i<end; ++i)
- {
- Packet ptmp0 = ei_pset1(rhs[i]);
- const Scalar* lhs0 = lhs + i*lhsStride;
-
- if (PacketSize>1)
- {
- /* explicit vectorization */
- // process first unaligned result's coeffs
- for (int j=0; j<alignedStart; ++j)
- res[j] += ei_pfirst(ptmp0) * lhs0[j];
-
- // process aligned result's coeffs
- if ((size_t(lhs0+alignedStart)%sizeof(Packet))==0)
- for (int j = alignedStart;j<alignedSize;j+=PacketSize)
- ei_pstore(&res[j], ei_pmadd(ptmp0,ei_pload(&lhs0[j]),ei_pload(&res[j])));
- else
- for (int j = alignedStart;j<alignedSize;j+=PacketSize)
- ei_pstore(&res[j], ei_pmadd(ptmp0,ei_ploadu(&lhs0[j]),ei_pload(&res[j])));
- }
-
- // process remaining scalars (or all if no explicit vectorization)
- for (int j=alignedSize; j<size; ++j)
- res[j] += ei_pfirst(ptmp0) * lhs0[j];
- }
- if (skipColumns)
- {
- start = 0;
- end = skipColumns;
- skipColumns = 0;
- }
- else
- break;
- } while(PacketSize>1);
- #undef _EIGEN_ACCUMULATE_PACKETS
-}
-
-// TODO add peeling to mask unaligned load/stores
-template<typename Scalar, typename ResType>
-static EIGEN_DONT_INLINE void ei_cache_friendly_product_rowmajor_times_vector(
- const Scalar* lhs, int lhsStride,
- const Scalar* rhs, int rhsSize,
- ResType& res)
-{
- #ifdef _EIGEN_ACCUMULATE_PACKETS
- #error _EIGEN_ACCUMULATE_PACKETS has already been defined
- #endif
-
- #define _EIGEN_ACCUMULATE_PACKETS(A0,A13,A2) {\
- Packet b = ei_pload(&rhs[j]); \
- ptmp0 = ei_pmadd(b, EIGEN_CAT(ei_ploa,A0) (&lhs0[j]), ptmp0); \
- ptmp1 = ei_pmadd(b, EIGEN_CAT(ei_ploa,A13)(&lhs1[j]), ptmp1); \
- ptmp2 = ei_pmadd(b, EIGEN_CAT(ei_ploa,A2) (&lhs2[j]), ptmp2); \
- ptmp3 = ei_pmadd(b, EIGEN_CAT(ei_ploa,A13)(&lhs3[j]), ptmp3); }
-
- typedef typename ei_packet_traits<Scalar>::type Packet;
- const int PacketSize = sizeof(Packet)/sizeof(Scalar);
-
- enum { AllAligned=0, EvenAligned=1, FirstAligned=2, NoneAligned=3 };
- const int rowsAtOnce = 4;
- const int peels = 2;
- const int PacketAlignedMask = PacketSize-1;
- const int PeelAlignedMask = PacketSize*peels-1;
- const int size = rhsSize;
-
- // How many coeffs of the result do we have to skip to be aligned.
- // Here we assume data are at least aligned on the base scalar type that is mandatory anyway.
- const int alignedStart = ei_alignmentOffset(rhs, size);
- const int alignedSize = PacketSize>1 ? alignedStart + ((size-alignedStart) & ~PacketAlignedMask) : 0;
- const int peeledSize = peels>1 ? alignedStart + ((alignedSize-alignedStart) & ~PeelAlignedMask) : alignedStart;
-
- const int alignmentStep = PacketSize>1 ? (PacketSize - lhsStride % PacketSize) & PacketAlignedMask : 0;
- int alignmentPattern = alignmentStep==0 ? AllAligned
- : alignmentStep==(PacketSize/2) ? EvenAligned
- : FirstAligned;
-
- // we cannot assume the first element is aligned because of sub-matrices
- const int lhsAlignmentOffset = ei_alignmentOffset(lhs,size);
-
- // find how many rows do we have to skip to be aligned with rhs (if possible)
- int skipRows = 0;
- if (PacketSize>1)
- {
- ei_internal_assert(size_t(lhs+lhsAlignmentOffset)%sizeof(Packet)==0 || size<PacketSize);
-
- while (skipRows<PacketSize &&
- alignedStart != ((lhsAlignmentOffset + alignmentStep*skipRows)%PacketSize))
- ++skipRows;
- if (skipRows==PacketSize)
- {
- // nothing can be aligned, no need to skip any column
- alignmentPattern = NoneAligned;
- skipRows = 0;
- }
- else
- {
- skipRows = std::min(skipRows,res.size());
- // note that the skiped columns are processed later.
- }
- ei_internal_assert((alignmentPattern==NoneAligned) || PacketSize==1
- || (size_t(lhs+alignedStart+lhsStride*skipRows)%sizeof(Packet))==0);
- }
-
- int offset1 = (FirstAligned && alignmentStep==1?3:1);
- int offset3 = (FirstAligned && alignmentStep==1?1:3);
-
- int rowBound = ((res.size()-skipRows)/rowsAtOnce)*rowsAtOnce + skipRows;
- for (int i=skipRows; i<rowBound; i+=rowsAtOnce)
- {
- Scalar tmp0 = Scalar(0), tmp1 = Scalar(0), tmp2 = Scalar(0), tmp3 = Scalar(0);
-
- // this helps the compiler generating good binary code
- const Scalar *lhs0 = lhs + i*lhsStride, *lhs1 = lhs + (i+offset1)*lhsStride,
- *lhs2 = lhs + (i+2)*lhsStride, *lhs3 = lhs + (i+offset3)*lhsStride;
-
- if (PacketSize>1)
- {
- /* explicit vectorization */
- Packet ptmp0 = ei_pset1(Scalar(0)), ptmp1 = ei_pset1(Scalar(0)), ptmp2 = ei_pset1(Scalar(0)), ptmp3 = ei_pset1(Scalar(0));
-
- // process initial unaligned coeffs
- // FIXME this loop get vectorized by the compiler !
- for (int j=0; j<alignedStart; ++j)
- {
- Scalar b = rhs[j];
- tmp0 += b*lhs0[j]; tmp1 += b*lhs1[j]; tmp2 += b*lhs2[j]; tmp3 += b*lhs3[j];
- }
-
- if (alignedSize>alignedStart)
- {
- switch(alignmentPattern)
- {
- case AllAligned:
- for (int j = alignedStart; j<alignedSize; j+=PacketSize)
- _EIGEN_ACCUMULATE_PACKETS(d,d,d);
- break;
- case EvenAligned:
- for (int j = alignedStart; j<alignedSize; j+=PacketSize)
- _EIGEN_ACCUMULATE_PACKETS(d,du,d);
- break;
- case FirstAligned:
- if (peels>1)
- {
- /* Here we proccess 4 rows with with two peeled iterations to hide
- * tghe overhead of unaligned loads. Moreover unaligned loads are handled
- * using special shift/move operations between the two aligned packets
- * overlaping the desired unaligned packet. This is *much* more efficient
- * than basic unaligned loads.
- */
- Packet A01, A02, A03, b, A11, A12, A13;
- A01 = ei_pload(&lhs1[alignedStart-1]);
- A02 = ei_pload(&lhs2[alignedStart-2]);
- A03 = ei_pload(&lhs3[alignedStart-3]);
-
- for (int j = alignedStart; j<peeledSize; j+=peels*PacketSize)
- {
- b = ei_pload(&rhs[j]);
- A11 = ei_pload(&lhs1[j-1+PacketSize]); ei_palign<1>(A01,A11);
- A12 = ei_pload(&lhs2[j-2+PacketSize]); ei_palign<2>(A02,A12);
- A13 = ei_pload(&lhs3[j-3+PacketSize]); ei_palign<3>(A03,A13);
-
- ptmp0 = ei_pmadd(b, ei_pload (&lhs0[j]), ptmp0);
- ptmp1 = ei_pmadd(b, A01, ptmp1);
- A01 = ei_pload(&lhs1[j-1+2*PacketSize]); ei_palign<1>(A11,A01);
- ptmp2 = ei_pmadd(b, A02, ptmp2);
- A02 = ei_pload(&lhs2[j-2+2*PacketSize]); ei_palign<2>(A12,A02);
- ptmp3 = ei_pmadd(b, A03, ptmp3);
- A03 = ei_pload(&lhs3[j-3+2*PacketSize]); ei_palign<3>(A13,A03);
-
- b = ei_pload(&rhs[j+PacketSize]);
- ptmp0 = ei_pmadd(b, ei_pload (&lhs0[j+PacketSize]), ptmp0);
- ptmp1 = ei_pmadd(b, A11, ptmp1);
- ptmp2 = ei_pmadd(b, A12, ptmp2);
- ptmp3 = ei_pmadd(b, A13, ptmp3);
- }
- }
- for (int j = peeledSize; j<alignedSize; j+=PacketSize)
- _EIGEN_ACCUMULATE_PACKETS(d,du,du);
- break;
- default:
- for (int j = alignedStart; j<alignedSize; j+=PacketSize)
- _EIGEN_ACCUMULATE_PACKETS(du,du,du);
- break;
- }
- tmp0 += ei_predux(ptmp0);
- tmp1 += ei_predux(ptmp1);
- tmp2 += ei_predux(ptmp2);
- tmp3 += ei_predux(ptmp3);
- }
- } // end explicit vectorization
-
- // process remaining coeffs (or all if no explicit vectorization)
- // FIXME this loop get vectorized by the compiler !
- for (int j=alignedSize; j<size; ++j)
- {
- Scalar b = rhs[j];
- tmp0 += b*lhs0[j]; tmp1 += b*lhs1[j]; tmp2 += b*lhs2[j]; tmp3 += b*lhs3[j];
- }
- res[i] += tmp0; res[i+offset1] += tmp1; res[i+2] += tmp2; res[i+offset3] += tmp3;
- }
-
- // process remaining first and last rows (at most columnsAtOnce-1)
- int end = res.size();
- int start = rowBound;
- do
- {
- for (int i=start; i<end; ++i)
- {
- Scalar tmp0 = Scalar(0);
- Packet ptmp0 = ei_pset1(tmp0);
- const Scalar* lhs0 = lhs + i*lhsStride;
- // process first unaligned result's coeffs
- // FIXME this loop get vectorized by the compiler !
- for (int j=0; j<alignedStart; ++j)
- tmp0 += rhs[j] * lhs0[j];
-
- if (alignedSize>alignedStart)
- {
- // process aligned rhs coeffs
- if ((size_t(lhs0+alignedStart)%sizeof(Packet))==0)
- for (int j = alignedStart;j<alignedSize;j+=PacketSize)
- ptmp0 = ei_pmadd(ei_pload(&rhs[j]), ei_pload(&lhs0[j]), ptmp0);
- else
- for (int j = alignedStart;j<alignedSize;j+=PacketSize)
- ptmp0 = ei_pmadd(ei_pload(&rhs[j]), ei_ploadu(&lhs0[j]), ptmp0);
- tmp0 += ei_predux(ptmp0);
- }
-
- // process remaining scalars
- // FIXME this loop get vectorized by the compiler !
- for (int j=alignedSize; j<size; ++j)
- tmp0 += rhs[j] * lhs0[j];
- res[i] += tmp0;
- }
- if (skipRows)
- {
- start = 0;
- end = skipRows;
- skipRows = 0;
- }
- else
- break;
- } while(PacketSize>1);
-
- #undef _EIGEN_ACCUMULATE_PACKETS
-}
-
-#endif // EIGEN_CACHE_FRIENDLY_PRODUCT_H