Assignment.h

Go to the documentation of this file.
00001 /*
00002  * Expression Template Matrix Library
00003  *
00004  * Copyright (C) 2004 - 2006 Ricky Lung <mtlung@users.sourceforge.net>
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 
00022 
00030 #ifdef _MSC_VER
00031 #   pragma once
00032 #   pragma warning( push )
00033 #   pragma warning( disable : 4512 4714 4786 )
00034 #endif  // _MSC_VER
00035 
00036 #ifndef _EXMAT_ASSIGNMENT_H
00037 #define _EXMAT_ASSIGNMENT_H
00038 
00039 #include "Metaprogramming.h"
00040 #include "Expression.h"         // Include expression for some static analysis
00041 #include "Container/Container.h"
00042 
00043 #include "ExpTmp.h"
00044 #include "AliasAnalyser.h"
00045 
00046 
00047 namespace exmat {
00048 
00049 template<class Rep, class ErrChecker_> class Mat;
00050 
00051 namespace PNS {
00052 
00053     /************************************************/
00057     //{@
00058     template<class MAT1, class MAT2>
00059     struct Assign_UnRollRowCol_ENV {
00060         EXMAT_INLINE2 Assign_UnRollRowCol_ENV(MAT1& A, const MAT2& B) : A_(A), B_(B) {}
00061         MAT1& A_;
00062         const MAT2& B_;
00063     };
00064     template<class MAT1, class MAT2>
00065     struct Assign_UnRoll_ENV {
00066         EXMAT_INLINE2 Assign_UnRoll_ENV(MAT1& A, const MAT2& B) : A_(A), B_(B) {}
00067         MAT1& A_;
00068         const MAT2& B_;
00069         typename MAT1::index_type i;
00070     };
00071 
00073     template<class MAT1, class MAT2, int row_=0, int col_=0>
00074     struct Assign_UnRollRowCol_STAT {
00075         typedef LinearBinExpSize<MAT1, MAT2> BINEXPSize;
00076         enum {
00077             ROWS = BINEXPSize::ROWS,
00078             COLS = BINEXPSize::COLS,
00079             r = col_ == COLS ? row_+1 : row_,
00080             c = col_ < COLS ? col_ : 0
00081         };
00082         EXMAT_INLINE2 static void
00083         exec(Assign_UnRollRowCol_ENV<MAT1, MAT2>& env) {
00084             typedef typename MAT1::value_type value_type;
00085             env.A_.setAt(r, c) = (value_type)(env.B_.getAt(r, c));
00086         }
00087         typedef Assign_UnRollRowCol_STAT<MAT1, MAT2, r, c+1> Next;
00088         enum { Condition = (r < ROWS && c < COLS) };
00089     };
00090 
00092     template<class MAT1, class MAT2, int r=0>
00093     struct Assign_UnRollRow_STAT {
00094         typedef LinearBinExpSize<MAT1, MAT2> BINEXPSize;
00095         enum {
00096             ROWS = BINEXPSize::ROWS
00097         };
00098         EXMAT_INLINE2 static void
00099         exec(Assign_UnRoll_ENV<MAT1, MAT2>& env) {
00100             env.A_.setAt(r, env.i) = env.B_.getAt(r, env.i);
00101         }
00102         typedef Assign_UnRollRow_STAT<MAT1, MAT2, r+1> Next;
00103         enum { Condition = (r < ROWS) };
00104     };
00105 
00107     template<class MAT1, class MAT2, int c=0>
00108     struct Assign_UnRollCol_STAT {
00109         typedef LinearBinExpSize<MAT1, MAT2> BINEXPSize;
00110         enum {      // BINEXP::LinearStaticColMat should not be NullTag
00111             COLS = BINEXPSize::COLS
00112         };
00113         EXMAT_INLINE2 static void
00114         exec(Assign_UnRoll_ENV<MAT1, MAT2>& env) {
00115             env.A_.setAt(env.i, c) = env.B_.getAt(env.i, c);
00116         }
00117         typedef Assign_UnRollCol_STAT<MAT1, MAT2, c+1> Next;
00118         enum { Condition = (c < COLS) };
00119     };
00120 
00122     template<class MAT1, class MAT2> EXMAT_INLINE2
00123     static void Assign_FullUnRoll(MAT1& A, const MAT2& B) {
00124         Assign_UnRollRowCol_ENV<MAT1, MAT2> env(A, B);
00125         EWHILE1<Assign_UnRollRowCol_STAT<MAT1, MAT2> >::exec(env);
00126     }
00128     template<class MAT1, class MAT2> EXMAT_INLINE2
00129     static void Assign_FullUnRollRow(MAT1& A, const MAT2& B) {
00130         Assign_UnRoll_ENV<MAT1, MAT2> env(A, B);
00131         typename MAT1::index_type cols_ = A.cols();
00132         for(env.i=0; env.i<cols_; ++env.i )
00133             EWHILE1<Assign_UnRollRow_STAT<MAT1, MAT2> >::exec(env);
00134     }
00136     template<class MAT1, class MAT2> EXMAT_INLINE2
00137     static void Assign_FullUnRollCol(MAT1& A, const MAT2& B) {
00138         Assign_UnRoll_ENV<MAT1, MAT2> env(A, B);
00139         typename MAT1::index_type rows_ = A.rows();
00140         for(env.i=0; env.i<rows_; ++env.i )
00141             EWHILE1<Assign_UnRollCol_STAT<MAT1, MAT2> >::exec(env);
00142     }
00146     template<class MAT1, class MAT2> EXMAT_INLINE1
00147     static void Assign_PartialUnRoll(MAT1& A, const MAT2& B) {
00148         typedef typename MAT1::index_type index_type;
00149         index_type rows_ = A.rows();
00150         index_type cols_ = A.cols();
00151         for(index_type i=0; i<rows_; ++i ) {
00152             register int n=(cols_+7)/8;
00153             int j = -1;
00154             switch(cols_%8) {
00155                 case 0: do{ A.setAt(i, j) = B.getAt(i, ++j);
00156                 case 7:     A.setAt(i, j) = B.getAt(i, ++j);
00157                 case 6:     A.setAt(i, j) = B.getAt(i, ++j);
00158                 case 5:     A.setAt(i, j) = B.getAt(i, ++j);
00159                 case 4:     A.setAt(i, j) = B.getAt(i, ++j);
00160                 case 3:     A.setAt(i, j) = B.getAt(i, ++j);
00161                 case 2:     A.setAt(i, j) = B.getAt(i, ++j);
00162                 case 1:     A.setAt(i, j) = B.getAt(i, ++j);
00163                 } while(--n>0);
00164             }
00165         }
00166     }
00168     template<class MAT1, class MAT2> EXMAT_INLINE1
00169     static void Assign_NoUnRoll(MAT1& A, const MAT2& B) {
00170         typedef typename MAT1::index_type index_type;
00171         typedef typename MAT1::value_type value_type;
00172         index_type rows_ = A.rows();
00173         index_type cols_ = A.cols();
00174         for(index_type i=0; i<rows_; ++i ) {
00175             for(index_type j=0; j<cols_; ++j )
00176                 A.setAt(i, j) = value_type(B.getAt(i, j));
00177         }
00178     }
00180     template<class MAT1, class MAT2, int i=0>
00181     struct Assign_UnRollSIMDSTAT {
00182         enum {
00183             nUnits = MAT1::nUnit,
00184         };
00185         EXMAT_INLINE2 static void
00186         exec(Assign_UnRollRowCol_ENV<MAT1, MAT2>& env) {
00187             env.A_.setUnitAt(i) = env.B_.getUnitAt(i);
00188         }
00189         typedef Assign_UnRollSIMDSTAT<MAT1, MAT2, i+1> Next;
00190         enum { Condition = (i < nUnits) };
00191     };
00193     template<class MAT1, class MAT2> EXMAT_INLINE2
00194     static void Assign_FullUnRollSIMD(MAT1& A, const MAT2& B) {
00195         Assign_UnRollRowCol_ENV<MAT1, MAT2> env(A, B);
00196         EWHILE1<Assign_UnRollSIMDSTAT<MAT1, MAT2> >::exec(env);
00197     }
00199 
00201     struct ASSIGN_TYPE {
00202         enum  {
00203             Ass_NoUnRoll = 0,
00204             Ass_FullUnRollRow = 1,
00205             Ass_FullUnRollCol = 2,
00206             Ass_FullUnRoll = 3,
00207             Ass_SIMD = 4
00208         };
00209     };
00210 
00211     /************************************************/
00216     template<class MAT1, class MAT2> EXMAT_INLINE2 static
00217     void Assign(MAT1& A, const MAT2& B, Int2Type<ASSIGN_TYPE::Ass_FullUnRoll>) {
00218 #if ENABLE_UNROLLING
00219         Assign_FullUnRoll(A, B);
00220 #else
00221         Assign_NoUnRoll(A, B);
00222 #endif
00223     }
00224     template<class MAT1, class MAT2> EXMAT_INLINE2 static
00225     void Assign(MAT1& A, const MAT2& B, Int2Type<ASSIGN_TYPE::Ass_FullUnRollRow>) {
00226 #if ENABLE_UNROLLING
00227         Assign_FullUnRollRow(A, B);
00228 #else
00229         Assign_NoUnRoll(A, B);
00230 #endif
00231     }
00232     template<class MAT1, class MAT2> EXMAT_INLINE2 static
00233     void Assign(MAT1& A, const MAT2& B, Int2Type<ASSIGN_TYPE::Ass_FullUnRollCol>) {
00234 #if ENABLE_UNROLLING
00235         Assign_FullUnRollCol(A, B);
00236 #else
00237         Assign_NoUnRoll(A, B);
00238 #endif
00239     }
00240     template<class MAT1, class MAT2> EXMAT_INLINE2 static
00241     void Assign(MAT1& A, const MAT2& B, Int2Type<ASSIGN_TYPE::Ass_NoUnRoll>) {
00242         Assign_NoUnRoll(A, B);
00243         // PartialUnRoll seems didn't help much
00244 //      Assign_PartialUnRoll(A, B);
00245     }
00246     template<class MAT1, class MAT2> EXMAT_INLINE2 static
00247     void Assign(MAT1& A, const MAT2& B, Int2Type<ASSIGN_TYPE::Ass_SIMD>) {
00248         enum {
00249             WholeAssign =
00250                 IsDerivedFrom<MAT2, MulExpTag>::RET &&
00251                 !MAT2::IsLinearRecursive &&
00252                 MAT2::EXPLevel == 2,
00253         };
00254         Assign_SIMD_inner(A, B, Int2Type<WholeAssign>());
00255     }
00256     template<class MAT1, class MAT2> EXMAT_INLINE2 static
00257     void Assign_SIMD_inner(MAT1& A, const MAT2& B, Int2Type<true> WholeAssign) {
00258 #if EXMAT_ENABLE_SIMD
00259         typedef typename MAT1::value_type value_type;
00260         exmat::SIMD::SIMDMatMul(A, B.leftOp, B.rightOp, Type2Type<value_type>());
00261 //      std::cout << "SIMDMatMul is called.\n";
00262 #else
00263         Assign_NoUnRoll(A, B);
00264 #endif  // EXMAT_ENABLE_SIMD
00265     }
00266     template<class MAT1, class MAT2> EXMAT_INLINE2 static
00267     void Assign_SIMD_inner(MAT1& A, const MAT2& B, Int2Type<false> WholeAssign) {
00268         Assign_FullUnRollSIMD(A, B);
00269         //for(size_t i=0; i<MAT1::nUnit; ++i)
00270         //  A.setUnitAt(i) = B.getUnitAt(i);
00271     }
00273 
00274 };
00275 
00276 
00278 struct ASSIGN_ANALYSIS {
00279     enum {
00280         NONE        = 1 << 0,
00281         ALIAS       = 1 << 1,
00282         TEMPORARY   = 1 << 2
00283     };
00284 };
00285 
00286 template<class Mat1, class Mat2> EXMAT_INLINE2 static
00287 void CopyDimension_inner(Mat1& dest, const Mat2& src, Int2Type<false>, Int2Type<false>) {
00288 }
00289 template<class Mat1, class Mat2> EXMAT_INLINE0 static
00290 void CopyDimension_inner(Mat1& dest, const Mat2& src, Int2Type<true>, Int2Type<false>) {
00291     dest.resize(src.rows());
00292 }
00293 template<class Mat1, class Mat2> EXMAT_INLINE0 static
00294 void CopyDimension_inner(Mat1& dest, const Mat2& src, Int2Type<false>, Int2Type<true>) {
00295     dest.resize(src.cols());
00296 }
00297 template<class Mat1, class Mat2> EXMAT_INLINE0 static
00298 void CopyDimension_inner(Mat1& dest, const Mat2& src, Int2Type<true>, Int2Type<true>) {
00299     dest.resize(src.rows(), src.cols());
00300 }
00301 // Resize dest to the same dimension as src, if any dimension of dest is dynamic
00302 template<class Mat1, class Mat2> EXMAT_INLINE0 static
00303 void CopyDimension(Mat1& dest, const Mat2& src) {
00304     CopyDimension_inner(dest, src, Int2Type<Mat1::ROWS==0>(), Int2Type<Mat1::COLS==0>());
00305 }
00306 
00307 template<class Rep1, class Rep2, class EC1, class EC2> EXMAT_INLINE2 static
00308 void assign(Mat<Rep1,EC1>& dest, const Mat<Rep2,EC2>& exp, int assign_type=EXMAT_DEFAULT_ANALYSIS)
00309 {
00310     using namespace exmat::PNS;
00311 #if ENABLE_ALIAS_ANALYSIS
00312     if((assign_type & ASSIGN_ANALYSIS::ALIAS) != 0) {
00313         if(IsAliased(dest, exp)) {
00314             typename GetAliasTmpType<Mat<Rep1,EC1> >::RET tmp;
00315             // Resize tmp if it's dynamic sized
00316             CopyDimension(tmp, dest);
00317             // Assign exp to tmp first.
00318 // The compilation won't stop for VC release build when using recursive inline.
00319 // Recursive inlining unimplemented for GNUC
00320 #   if EXMAT_VC6 || EXMAT_VC7 || EXMAT_VC2003 || EXMAT_VC2005 || EXMAT_GNUC
00321 #       if ENABLE_TMP_ANALYSIS
00322             if((assign_type & ASSIGN_ANALYSIS::TEMPORARY) != 0)
00323                 parseExp(tmp, exp);
00324             else
00325 #       endif   // ENABLE_TMP_ANALYSIS
00326                 GetAliasTmpType<Mat<Rep1,EC1> >::RET::AssignDispatcher(tmp, exp);
00327 #   else
00328             // Assign exp to tmp, without alias analysis by calling assign recursively
00329             assign(tmp, exp, (assign_type & ~ASSIGN_ANALYSIS::ALIAS));
00330 #   endif
00331             // Copy tmp back to dest
00332             Mat<Rep1,EC1>::AssignDispatcher(dest, tmp);
00333             return;
00334         }
00335     }
00336 #endif  // ENABLE_ALIAS_ANALYSIS
00337 
00338 #if ENABLE_TMP_ANALYSIS
00339     if((assign_type & ASSIGN_ANALYSIS::TEMPORARY) != 0) {
00340         parseExp(dest, exp);
00341         return;
00342     }
00343 #endif  // ENABLE_TMP_ANALYSIS
00344     
00345     Mat<Rep1,EC1>::AssignDispatcher(dest, exp);
00346 }
00347 
00348 
00349 }   // namespace exmat
00350 
00351 #if _MSC_VER
00352 #   pragma warning( pop )
00353 #endif  // EXMAT_VC
00354 
00355 #endif  // _EXMAT_ASSIGNMENT_H

Generated on Sat May 6 23:11:54 2006 for Exmat by  doxygen 1.4.6-NO