SIMDContainer.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 #ifndef _EXMAT_SIMDCONTAINER_H
00031 #define _EXMAT_SIMDCONTAINER_H
00032 
00033 
00034 #ifdef _MSC_VER
00035 #   pragma warning( push )
00036 #   pragma warning( disable : 4201 4786 )
00037 #endif  // _MSC_VER
00038 
00039 #include <iterator>
00040 #include "../ErrorCheck.h"
00041 #include "../Iterators.h"
00042 #include "../Allocator.h"
00043 #include "SIMDAlignment.h"
00044 // Borrowing the unroller from assignment.h
00045 #include "../Assignment.h"
00046 
00047 
00048 namespace exmat {
00049 
00050 
00052 namespace SIMD {
00053 
00054 
00056 template<typename T>
00057 struct SIMD_UNIT_Chooser {
00058     typedef NullTag RET;
00059 };
00060 
00061 #if EXMAT_SIMD_FLOAT
00062 template<>
00063 struct SIMD_UNIT_Chooser<float> {
00064     enum {
00065         ALIGN = EXMAT_SIMD_FLOAT_ALIGN
00066     };
00067     typedef EXMAT_SIMD_FLOAT_UNIT RET;
00068 };
00069 #endif  // EXMAT_SIMD_FLOAT
00070 
00071 #if EXMAT_SIMD_DOUBLE
00072 template<>
00073 struct SIMD_UNIT_Chooser<double> {
00074     enum {
00075         ALIGN = EXMAT_SIMD_DOUBLE_ALIGN
00076     };
00077     typedef EXMAT_SIMD_DOUBLE_UNIT RET;
00078 };
00079 #endif  // EXMAT_SIMD_DOUBLE
00080 
00081 
00083 template<int ROWS_, int COLS_, typename T=float>
00084 struct EXMAT_TYPE_ALIGN_PREFIX(EXMAT_SIMD_DEFAULT_ALIGN)
00085 SCon_RM : public SIMDTag, public RowMajorTag
00086 {
00087     typedef typename SIMD_UNIT_Chooser<T>::RET UNIT;
00088     enum {
00089         ALIGNED = true,
00090         ROWS = ROWS_,
00091         COLS = COLS_,
00093         Align = SIMD_UNIT_Chooser<T>::ALIGN,
00095         nElePerUnit = sizeof(UNIT)/sizeof(T),
00097         nUnitPerRow = (COLS+nElePerUnit-1)/nElePerUnit,
00099         nUnit = nUnitPerRow*ROWS,
00100         // Padding at the end of each row
00101         rPadding = (COLS%nElePerUnit == 0) ? 0 : nElePerUnit-COLS%nElePerUnit,
00102         cPadding = 0,
00104         rStride = COLS+rPadding,
00105         cStride = ROWS,
00107         nTotalEle = ROWS*(COLS+rPadding),
00108 
00109         IsLinear = true,            
00110         IsLinearRecursive = true,   
00111         TNOP = 0,                   
00112         ENOP = 0,                   
00113         EXPLevel = 0
00114     };
00115 
00116     union {
00117         UNIT unitData[nUnit];
00118         T data[ROWS][COLS+rPadding];
00119         struct { T x, y, z, w; };
00120     };
00121 
00122     EXMAT_INLINE2 SCon_RM() {
00123         ALIGNMENT_CHECK(sizeof(UNIT));
00124     }
00125 
00126     /************************************************/
00127     // Index function (for internal use, no error checking applied)
00128     EXMAT_INLINE2 T& setAt(size_t i)
00129     {   return *(&data[0][0]+i+i*rPadding/COLS);    }
00130     EXMAT_INLINE2 const T& getAt(size_t i) const
00131     {   return *(&data[0][0]+i+i*rPadding/COLS);    }
00132     EXMAT_INLINE2 T& setAt(size_t i, size_t j)
00133     {   return data[i][j];  }
00134     EXMAT_INLINE2 const T& getAt(size_t i, size_t j) const
00135     {   return data[i][j];  }
00136     EXMAT_INLINE2 UNIT& setUnitAt(size_t i)
00137     {   return unitData[i]; }
00138     EXMAT_INLINE2 const UNIT& getUnitAt(size_t i) const
00139     {   return unitData[i]; }
00140 } EXMAT_TYPE_ALIGN_SUFFIX(EXMAT_SIMD_DEFAULT_ALIGN);
00141 
00142 
00144 template<int ROWS_, int COLS_, typename T=float>
00145 struct EXMAT_TYPE_ALIGN_PREFIX(EXMAT_SIMD_DEFAULT_ALIGN)
00146 SCon_CM : public SIMDTag, public ColMajorTag
00147 {
00148     typedef typename SIMD_UNIT_Chooser<T>::RET UNIT;
00149     enum {
00150         ALIGNED = true,
00151         ROWS = ROWS_,
00152         COLS = COLS_,
00154         Align = SIMD_UNIT_Chooser<T>::ALIGN,
00156         nElePerUnit = sizeof(UNIT)/sizeof(T),
00158         nUnitPerCol = (ROWS+nElePerUnit-1)/nElePerUnit,
00160         nUnit = nUnitPerCol*COLS,
00161         rPadding = 0,
00163         cPadding = (ROWS%nElePerUnit == 0) ? 0 : nElePerUnit-ROWS%nElePerUnit,
00164         rStride = COLS,
00166         cStride = ROWS+cPadding,
00168         nTotalEle = COLS*(ROWS+cPadding),
00169 
00170         IsLinear = true,            
00171         IsLinearRecursive = true,   
00172         TNOP = 0,                   
00173         ENOP = 0,                   
00174         EXPLevel = 0
00175     };
00176 
00177     union {
00178         UNIT unitData[nUnit];
00179         T data[COLS][ROWS+cPadding];
00180         struct { T x, y, z, w; };
00181     };
00182 
00183     EXMAT_INLINE2 SCon_CM() {
00184         ALIGNMENT_CHECK(sizeof(UNIT));
00185     }
00186 
00187     /************************************************/
00188     // Index function (for internal use, no error checking applied)
00189     EXMAT_INLINE2 T& setAt(size_t i)
00190     {   return *(&data[0][0]+i+i*cPadding/ROWS);    }
00191     EXMAT_INLINE2 const T& getAt(size_t i) const
00192     {   return *(&data[0][0]+i+i*cPadding/ROWS);    }
00193     EXMAT_INLINE2 T& setAt(size_t i, size_t j)
00194     {   return data[j][i];  }
00195     EXMAT_INLINE2 const T& getAt(size_t i, size_t j) const
00196     {   return data[j][i];  }
00197     EXMAT_INLINE2 UNIT& setUnitAt(size_t i)
00198     {   return unitData[i]; }
00199     EXMAT_INLINE2 const UNIT& getUnitAt(size_t i) const
00200     {   return unitData[i]; }
00201 } EXMAT_TYPE_ALIGN_SUFFIX(EXMAT_SIMD_DEFAULT_ALIGN);
00202 
00203 
00205 template<int ROWS_, int COLS_, typename T=float>
00206 struct SConCA_RM : public SIMDTag, public RowMajorTag
00207 {
00208     typedef typename SIMD_UNIT_Chooser<T>::RET UNIT;
00209     enum {
00210         ALIGNED = true,
00211         ROWS = ROWS_,
00212         COLS = COLS_,
00214         Align = SIMD_UNIT_Chooser<T>::ALIGN,
00216         nElePerUnit = sizeof(UNIT)/sizeof(T),
00218         nUnitPerRow = (COLS+nElePerUnit-1)/nElePerUnit,
00220         nUnit = nUnitPerRow*ROWS,
00221         // Padding at the end of each row
00222         rPadding = (COLS%nElePerUnit == 0) ? 0 : nElePerUnit-COLS%nElePerUnit,
00223         cPadding = 0,
00225         rStride = COLS+rPadding,
00226         cStride = ROWS,
00228         nTotalEle = ROWS*(COLS+rPadding),
00229 
00230         IsLinear = true,            
00231         IsLinearRecursive = true,   
00232         TNOP = 0,                   
00233         ENOP = 0,                   
00234         EXPLevel = 0
00235     };
00236 
00237     // VC2005 need to init an pointer explicitly first
00238 #if EXMAT_VC2005
00239     UNIT* refPtr;
00240 #   define INIT_REF \
00241     refPtr( (UNIT*)aligned_stack_allocate(sizeof(UNIT)*nUnit) ),    \
00242     unitData( (UNIT (&)[nUnit]) *refPtr),   \
00243     data((T (&)[ROWS][COLS+rPadding])(unitData[0]))
00244 #else
00245 #   define INIT_REF \
00246     unitData( (UNIT (&)[nUnit]) *(UNIT*)aligned_stack_allocate(sizeof(UNIT)*nUnit)),    \
00247     data((T (&)[ROWS][COLS+rPadding])(unitData[0]))
00248 #endif  // EXMAT_VC2005
00249 
00250     // MSVC does not treat multiply union initialization as error
00251 #ifdef  _MSC_VER
00252     union {
00253 #endif
00254         // How to add named element here?
00255         UNIT (&unitData)[nUnit];
00256         T (&data)[ROWS][COLS+rPadding];
00257 #ifdef  _MSC_VER
00258     };
00259 #endif
00260 
00261     EXMAT_INLINE2 SConCA_RM() : INIT_REF {
00262         ALIGNMENT_CHECK(sizeof(UNIT));
00263     }
00264 
00265 #undef INIT_REF
00266 
00267     EXMAT_INLINE2 virtual ~SConCA_RM() {
00268         aligned_stack_free();
00269     }
00270 
00271     /************************************************/
00272     // Index function (for internal use, no error checking applied)
00273     EXMAT_INLINE2 T& setAt(size_t i)
00274     {   return *(&data[0][0]+i+i*rPadding/COLS);    }
00275     EXMAT_INLINE2 const T& getAt(size_t i) const
00276     {   return *(&data[0][0]+i+i*rPadding/COLS);    }
00277     EXMAT_INLINE2 T& setAt(size_t i, size_t j)
00278     {   return data[i][j];  }
00279     EXMAT_INLINE2 const T& getAt(size_t i, size_t j) const
00280     {   return data[i][j];  }
00281     EXMAT_INLINE2 UNIT& setUnitAt(size_t i)
00282     {   return unitData[i]; }
00283     EXMAT_INLINE2 const UNIT& getUnitAt(size_t i) const
00284     {   return unitData[i]; }
00285 };
00286 
00288 template<int ROWS_, int COLS_, typename T=float>
00289 struct SConCA_CM : public SIMDTag, public ColMajorTag
00290 {
00291     typedef typename SIMD_UNIT_Chooser<T>::RET UNIT;
00292     enum {
00293         ALIGNED = true,
00294         ROWS = ROWS_,
00295         COLS = COLS_,
00297         Align = SIMD_UNIT_Chooser<T>::ALIGN,
00299         nElePerUnit = sizeof(UNIT)/sizeof(T),
00301         nUnitPerCol = (ROWS+nElePerUnit-1)/nElePerUnit,
00303         nUnit = nUnitPerCol*COLS,
00304         rPadding = 0,
00306         cPadding = (ROWS%nElePerUnit == 0) ? 0 : nElePerUnit-ROWS%nElePerUnit,
00307         rStride = COLS,
00309         cStride = ROWS+cPadding,
00311         nTotalEle = COLS*(ROWS+cPadding),
00312 
00313         IsLinear = true,            
00314         IsLinearRecursive = true,   
00315         TNOP = 0,                   
00316         ENOP = 0,                   
00317         EXPLevel = 0
00318     };
00319 
00320     // VC2005 need to init an pointer explicitly first
00321 #if EXMAT_VC2005
00322     UNIT* refPtr;
00323 #   define INIT_REF \
00324     refPtr( (UNIT*)aligned_stack_allocate(sizeof(UNIT)*nUnit) ),    \
00325     unitData( (UNIT (&)[nUnit]) *refPtr),   \
00326     data((T (&)[COLS][ROWS+cPadding])(unitData[0]))
00327 #else
00328 #   define INIT_REF \
00329     unitData( (UNIT (&)[nUnit]) *(UNIT*)aligned_stack_allocate(sizeof(UNIT)*nUnit)),    \
00330     data((T (&)[COLS][ROWS+cPadding])(unitData[0]))
00331 #endif  // EXMAT_VC2005
00332 
00333     // MSVC does not treat multiply union initialization as error
00334 #ifdef  _MSC_VER
00335     union {
00336 #endif
00337         UNIT (&unitData)[nUnit];
00338         T (&data)[COLS][ROWS+cPadding];
00339 #ifdef  _MSC_VER
00340     };
00341 #endif
00342 
00343     EXMAT_INLINE2 SConCA_CM() : INIT_REF {
00344         ALIGNMENT_CHECK(sizeof(UNIT));
00345     }
00346 
00347 #undef INIT_REF
00348 
00349     EXMAT_INLINE2 virtual ~SConCA_CM() {
00350         aligned_stack_free();
00351     }
00352 
00353     /************************************************/
00354     // Index function (for internal use, no error checking applied)
00355     EXMAT_INLINE2 T& setAt(size_t i)
00356     {   return *(&data[0][0]+i+i*cPadding/ROWS);    }
00357     EXMAT_INLINE2 const T& getAt(size_t i) const
00358     {   return *(&data[0][0]+i+i*cPadding/ROWS);    }
00359     EXMAT_INLINE2 T& setAt(size_t i, size_t j)
00360     {   return data[j][i];  }
00361     EXMAT_INLINE2 const T& getAt(size_t i, size_t j) const
00362     {   return data[j][i];  }
00363     EXMAT_INLINE2 UNIT& setUnitAt(size_t i)
00364     {   return unitData[i]; }
00365     EXMAT_INLINE2 const UNIT& getUnitAt(size_t i) const
00366     {   return unitData[i]; }
00367 };
00368 
00369 
00371 template<int R, int C, typename T>
00372 struct SConCHooser {
00373     typedef typename IF<
00374         C == 1,
00375         // VC6 fail to do the alignment correctly
00376 #if EXMAT_VC6
00377         SConCA_CM<R,C,T>,
00378         SConCA_RM<R,C,T>
00379 #else
00380         SCon_CM<R,C,T>,
00381         SCon_RM<R,C,T>
00382 #endif  // EXMAT_VC6
00383     >::RET RET;
00384 };
00385 
00386 
00389 template<int ROWS_, int COLS_, typename T=float>
00390 struct EXMAT_TYPE_ALIGN_PREFIX(EXMAT_SIMD_DEFAULT_ALIGN)
00391 SCon : public SConCHooser<ROWS_,COLS_,T>::RET
00392 {
00393     typedef typename SConCHooser<ROWS_,COLS_,T>::RET    super_type;
00394     typedef typename super_type::UNIT                   SIMD_unit_type;
00395     typedef T                   value_type;
00396     typedef value_type&         reference;
00397     typedef const value_type&   const_reference;
00398     typedef value_type*         row_type;
00399     typedef const value_type*   const_row_type;
00400     typedef NullTag             col_type;
00401     typedef size_t              index_type;
00402     typedef typename Loki::TypeTraits<value_type>::ParameterType param_type;
00403     typedef typename Loki::TypeTraits<const value_type>::ParameterType const_param_type;
00404     typedef NullTag             exp_tag;    // It's not an expression, so exp_tag is NullTag
00405 
00406     typedef SCon<ROWS_,COLS_,T>             self_type;
00407     typedef self_type                       rep_type;
00408     typedef mat_iterator<self_type>         iterator;
00409     typedef const_mat_iterator<self_type>   const_iterator;
00410 
00411 #if EXMAT_USING_MEMVAR
00412     using super_type::data;
00413 #endif  // EXMAT_USING_MEMVAR
00414 
00415     enum {
00416         ROWS = ROWS_,
00417         COLS = COLS_,
00418         nTotalEle = super_type::nTotalEle,
00419         nUnit = super_type::nUnit,
00420         rPadding = super_type::rPadding,
00421         cPadding = super_type::cPadding,
00422         rStride = super_type::rStride,
00423         cStride = super_type::cStride
00424     };
00425 
00426     EXMAT_INLINE2 SCon() {
00427         // Give valid values for data with paddings,
00428         // otherwise invalid float will cause floating point exceptions
00429         if(rPadding > 0 || cPadding > 0)
00430             memset(&(this->data[0][0]), 0, sizeof(value_type)*nTotalEle);
00431     }
00432 
00434     EXMAT_INLINE2 SCon(const self_type& x) {
00435         exmat::PNS::Assign_FullUnRollSIMD(*this, x);
00436     }
00437 
00438     EXMAT_INLINE2 explicit SCon(const value_type s) {
00439         SIMD_unit_type scalar = Intrinsics::load1_p(&s);
00440         for(int i=0; i<nUnit; ++i)
00441             this->unitData[i] = scalar;
00442     }
00443 
00444     EXMAT_INLINE2 self_type& operator=(const self_type& x) {
00445         exmat::PNS::Assign_FullUnRollSIMD(*this, x);
00446         return *this;
00447     }
00448 
00449     EXMAT_INLINE2 self_type& operator=(const value_type s) {
00450         SIMD_unit_type scalar = Intrinsics::load1_p(&s);
00451         for(int i=0; i<nUnit; ++i)
00452             this->unitData[i] = scalar;
00453         return *this;
00454     }
00455 
00456     /************************************************/
00457     // Begin / End
00458     EXMAT_INLINE2 iterator begin()
00459     {   return iterator(*this, 0, 0);   }
00460     EXMAT_INLINE2 const_iterator begin() const
00461     {   return const_iterator(*this, 0, 0); }
00462     EXMAT_INLINE2 iterator end()
00463     {   return iterator(*this, rows(), 0);  }
00464     EXMAT_INLINE2 const_iterator end() const
00465     {   return const_iterator(*this, rows(), 0);    }
00466     /************************************************/
00467     // Raw data pointer
00468     EXMAT_INLINE2 value_type* getRawData()
00469     {   return &data[0][0]; }
00470     /************************************************/
00471     // Index operator
00472     EXMAT_INLINE2 T* operator[] (size_t i)
00473     {   return &data[i][0]; }
00474     EXMAT_INLINE2 const T* operator[] (size_t i) const
00475     {   return &data[i][0]; }
00476     /************************************************/
00477     // Dimension information
00478     EXMAT_INLINE2 size_t size() const { return ROWS*COLS; }
00479     EXMAT_INLINE2 size_t rows() const { return ROWS; }
00480     EXMAT_INLINE2 size_t cols() const { return COLS; }
00481 
00482     EXMAT_INLINE2 size_t rstride() const
00483     {   return rStride; }
00484     EXMAT_INLINE2 size_t exstride() const
00485     {   return rPadding;    }
00486 } EXMAT_TYPE_ALIGN_SUFFIX(EXMAT_SIMD_DEFAULT_ALIGN);
00487 
00489 template<class Rep>
00490 struct SSCon : public Rep
00491 {
00492     typedef SSCon<Rep>  self_type;
00493     // Must use self_type as rep_type to enable SIMD specialized expression
00494     typedef self_type   rep_type;
00495     typedef Rep         super_type;
00496 
00497     enum {
00498         IsLinear = Rep::IsLinear,
00499         IsLinearRecursive = Rep::IsLinearRecursive
00500     };
00501 
00503     EXMAT_INLINE2 SSCon() : Rep() {}
00504 
00506 
00507     template<typename T1>
00508     EXMAT_INLINE2 SSCon(T1& t1) : Rep(t1) {}
00509     template<typename T1, typename T2>
00510     EXMAT_INLINE2 SSCon(T1& t1, T2& t2) : Rep(t1, t2) {}
00511     template<typename T1, typename T2, typename T3>
00512     EXMAT_INLINE2 SSCon(T1& t1, T2& t2, T3& t3) : Rep(t1, t2, t3) {}
00513 #if !EXMAT_VC6 && !EXMAT_VC7
00514     template<typename T1, typename T2>
00515     EXMAT_INLINE2 SSCon(const T1& t1, ScalarCon<T2> t2) : Rep(t1, t2) {}
00516     template<typename T1, typename T2>
00517     EXMAT_INLINE2 SSCon(ScalarCon<T1> t1, const T2& t2) : Rep(t1, t2) {}
00518 #endif  // HAVE_PARTIAL_SPECIALIZATION
00519 
00520 
00522     template<typename T1> EXMAT_INLINE2
00523     SSCon& operator=(const T1& t1) {
00524         (*static_cast<Rep*>(this)) = t1;
00525         return *this;
00526     }
00527 };
00528 
00529 
00530 };  // namespace SIMD
00531 
00532     // end of groupCon
00537 
00538 
00539 }   // namespace exmat
00540 
00541 #ifdef  _MSC_VER
00542 #   pragma warning( pop )
00543 #endif  // _MSC_VER
00544 
00545 #endif  // _EXMAT_SIMDCONTAINER_H

Generated on Sat May 6 23:12:01 2006 for Exmat by  doxygen 1.4.6-NO