File: vsip/impl/simd/expr_iterator.hpp
    1| /* Copyright (c) 2006 by CodeSourcery, Inc.  All rights reserved. */
    2| 
    3| /** @file    vsip/impl/simd/expr_iterator.hpp
    4|     @author  Stefan Seefeld
    5|     @date    2006-07-18
    6|     @brief   VSIPL++ Library: SIMD expression iterators.
    7| 
    8| */
    9| 
   10| #ifndef VSIP_IMPL_SIMD_EXPR_ITERATOR_HPP
   11| #define VSIP_IMPL_SIMD_EXPR_ITERATOR_HPP
   12| 
   13| /***********************************************************************
   14|   Included Files
   15| ***********************************************************************/
   16| 
   17| #include <vsip/support.hpp>
   18| #include <vsip/impl/simd/simd.hpp>
   19| #include <vsip/impl/expr_operations.hpp>
   20| #include <vsip/impl/metaprogramming.hpp>
   21| 
   22| /***********************************************************************
   23|   Definitions
   24| ***********************************************************************/
   25| 
   26| namespace vsip
   27| {
   28| namespace impl
   29| {
   30| namespace simd
   31| {
   32| 
   33| template <typename T,                  // value_type
   34|           template <typename> class O> // operator
   35| struct Unary_operator_map
   36| {
   37|   // The general case, in particular unary functors, are not supported.
   38|   static bool const is_supported = false;
   39| };
   40| 
   41| template <typename T> 
   42| struct Unary_operator_map<T, op::Plus>
   43| {
   44|   typedef typename Simd_traits<T>::simd_type simd_type;
   45|   static bool const is_supported = true;
   46|   static simd_type 
   47|   apply(simd_type const &op)
   48|   return Simd_traits<T>::add(Simd_traits<T>::zero(), op);}
   49| };
   50| 
   51| template <typename T> 
   52| struct Unary_operator_map<T, op::Minus>
   53| {
   54|   typedef typename Simd_traits<T>::simd_type simd_type;
   55|   static bool const is_supported = true;
   56|   static simd_type 
   57|   apply(simd_type const &op)
   58|   return Simd_traits<T>::sub(Simd_traits<T>::zero(), op);}
   59| };
   60| 
   61| template <typename T,                            // value_type
   62|           template <typename, typename> class O> // operator
   63| struct Binary_operator_map
   64| {
   65|   // The general case, in particular binary functors, are not supported.
   66|   static bool const is_supported = false;
   67| };
   68| 
   69| template <typename T>
   70| struct Binary_operator_map<T, op::Add>
   71| {
   72|   typedef typename Simd_traits<T>::simd_type simd_type;
   73|   static bool const is_supported = true;
   74|   static simd_type 
   75|   apply(simd_type const &left, simd_type const &right)
   76|   return Simd_traits<T>::add(leftright);}
   77| };
   78| 
   79| template <typename T>
   80| struct Binary_operator_map<T, op::Sub>
   81| {
   82|   typedef typename Simd_traits<T>::simd_type simd_type;
   83|   static bool const is_supported = true;
   84|   static simd_type 
   85|   apply(simd_type const &left, simd_type const &right)
   86|   return Simd_traits<T>::sub(leftright);}
   87| };
   88| 
   89| template <typename T>
   90| struct Binary_operator_map<T, op::Mult>
   91| {
   92|   typedef typename Simd_traits<T>::simd_type simd_type;
   93|   static bool const is_supported = true;
   94|   static simd_type 
   95|   apply(simd_type const &left, simd_type const &right)
   96|   return Simd_traits<T>::mul(leftright);}
   97| };
   98| 
   99| template <typename T>
  100| struct Binary_operator_map<T, op::Div>
  101| {
  102|   typedef typename Simd_traits<T>::simd_type simd_type;
  103|   static bool const is_supported = true;
  104|   static simd_type 
  105|   apply(simd_type const &left, simd_type const &right)
  106|   return Simd_traits<T>::div(leftright);}
  107| };
  108| 
  109| // Access trait for direct access to contiguous aligned memory.
  110| template <typename T> struct Direct_access_traits 
  111| {
  112|   typedef T value_type;
  113| };
  114| 
  115| // Access trait for direct lvalue access to contiguous aligned memory.
  116| template <typename T> struct LValue_access_traits 
  117| {
  118|   typedef T value_type;
  119| };
  120| 
  121| // Access trait for unaccelerated access. Either non-contiguous or not aligned.
  122| template <typename T> struct Indirect_access_traits 
  123| {
  124|   typedef T value_type;
  125| };
  126| 
  127| // Access trait for scalar blocks.
  128| template <typename T> struct Scalar_access_traits 
  129| {
  130|   typedef T value_type;
  131| };
  132| 
  133| template <typename T> struct Complex_inter_access_traits 
  134| {
  135|   typedef T value_type;
  136| };
  137| 
  138| template <typename T> struct Complex_split_access_traits 
  139| 
  140|   typedef T value_type;
  141| };
  142| 
  143| // Access trait for unary expressions.
  144| template <typename ProxyT,             // operatory proxy
  145|           template <typename> class O> // operator
  146| struct Unary_access_traits
  147| {
  148|   typedef typename ProxyT::value_type value_type;
  149| };
  150| 
  151| // Access trait for binary expressions. Both operands have the same value_type.
  152| // TODO: Support (T, std::complex<T>) and (std::complex<T>, T) binary 
  153| // operations.
  154| template <typename L,                            // left operator proxy
  155|           typename R,                            // right operator proxy
  156|           template <typename, typename> class O> // operator
  157| struct Binary_access_traits
  158| {
  159|   typedef typename Type_equal<typename L::value_type,
  160|                             typename R::value_type>::type value_type;
  161| };
  162| 
  163| template <typename T> class Proxy;
  164| 
  165| // Optimized proxy for direct SIMD access to block data, i.e. the data
  166| // is contiguous (unit stride) and correctly aligned.
  167| template <typename T>
  168| class Proxy<Direct_access_traits<T> >
  169| {
  170| public:
  171|   typedef T value_type;
  172|   typedef typename Simd_traits<value_type>::simd_type simd_type;
  173| 
  174|   Proxy(value_type const *ptr) : ptr_(ptr) {}
  175| 
  176|   simd_type load() const { return Simd_traits<value_type>::load(ptr_);}
  177| 
  178|   void increment(length_type n = 1) { ptr_ += n * Simd_traits<value_type>::vec_size;}
  179| 
  180| private:
  181|   value_type const *ptr_;
  182| };
  183| 
  184| // Optimized proxy for direct SIMD access to writable block data, i.e. 
  185| // the data is contiguous (unit stride) and correctly aligned.
  186| template <typename T>
  187| class Proxy<LValue_access_traits<T> >
  188| {
  189| public:
  190|   typedef T value_type;
  191|   typedef typename Simd_traits<value_type>::simd_type simd_type;
  192| 
  193|   Proxy(value_type *ptr) : ptr_(ptr) {}
  194|   template <typename T1>
  195|   Proxy operator = (Proxy<T1> const &o) 
  196|   {
  197|     store(o.load());
  198|     return *this;
  199|   }
  200| 
  201|   simd_type 
  202|   load() const { return Simd_traits<value_type>::load(ptr_);}
  203|   void 
  204|   store(simd_type const &value) 
  205|   { Simd_traits<value_type>::store(ptr_value);}
  206| 
  207|   void increment(length_type n = 1) { ptr_ += n * Simd_traits<value_type>::vec_size;}
  208| 
  209| private:
  210|   value_type *ptr_;
  211| };
  212| 
  213| template <typename T>
  214| class Proxy<Scalar_access_traits<T> >
  215| {
  216| public:
  217|   typedef T value_type;
  218|   typedef typename Simd_traits<value_type>::simd_type simd_type;
  219| 
  220|   Proxy(value_type value) : value_(value) {}
  221| 
  222|   simd_type load() const 
  223|   return Simd_traits<value_type>::load_scalar_all(value_);}
  224| 
  225|   void increment(length_type) {}
  226| 
  227| private:
  228|   value_type value_;
  229| };
  230| 
  231| // Proxy for unary expressions.
  232| template <typename ProxyT, template <typename> class O>
  233| class Proxy<Unary_access_traits<ProxyT, O> >
  234| {
  235| public:
  236|   typedef Unary_access_traits<ProxyT, O> access_traits;
  237|   typedef typename access_traits::value_type value_type;
  238|   typedef typename Simd_traits<value_type>::simd_type simd_type;
  239| 
  240|   Proxy(ProxyT const &o) : op_(o) {}
  241| 
  242|   simd_type load() const 
  243|   {
  244|     simd_type op = op_.load();
  245|     return Unary_operator_map<value_type, O>::apply(op);
  246|   }
  247| 
  248|   void increment(length_type n = 1) { op_.increment(n);}
  249| 
  250| private:
  251|   ProxyT op_;
  252| };
  253| 
  254| // Proxy for binary expressions. The two proxy operands L and R are 
  255| // combined using binary operator O.
  256| template <typename L, typename R, template <typename, typename> class O>
  257| class Proxy<Binary_access_traits<L, R, O> >
  258| {
  259| public:
  260|   typedef Binary_access_traits<L, R, O> access_traits;
  261|   typedef typename access_traits::value_type value_type;
  262|   typedef typename Simd_traits<value_type>::simd_type simd_type;
  263| 
  264|   Proxy(L const &l, R const &r) : left_(l), right_(r) {}
  265| 
  266|   L const &left() const { return left_;}
  267|   R const &right() const { return right_;}
  268| 
  269|   simd_type load() const 
  270|   {
  271|     simd_type l = left_.load();
  272|     simd_type r = right_.load();
  273|     return Binary_operator_map<value_type, O>::apply(lr);
  274|   }
  275| 
  276|   void increment(length_type n = 1)
  277|   {
  278|     left_.increment(n);
  279|     right_.increment(n);
  280|   }
  281| 
  282| private:
  283|   left_;
  284|   right_;
  285| };
  286| 
  287| // Proxy for ternary 'multiply-add' expression (a * b + c)
  288| template <typename A, typename B, typename C>
  289| class Proxy<Binary_access_traits<Proxy<Binary_access_traits<A, B, op::Mult> >,
  290|                       C, op::Add> >
  291| {
  292| public:
  293|   typedef Proxy<Binary_access_traits<A, B, op::Mult> > AB;
  294|   typedef Binary_access_traits<AB, C, op::Add> access_traits;
  295|   typedef typename access_traits::value_type value_type;
  296|   typedef typename Simd_traits<value_type>::simd_type simd_type;
  297| 
  298|   Proxy(AB const &left, C const &right)
  299|     : left_(left), right_(right) {}
  300| 
  301|   AB const &left() const { return left_;}
  302|   C const &right() const { return right_;}
  303| 
  304|   simd_type load() const 
  305|   {
  306|     simd_type a = left_.left().load();
  307|     simd_type b = left_.right().load();
  308|     simd_type c = right_.load();
  309|     return Simd_traits<value_type>::fma(abc);
  310|   }
  311| 
  312|   void increment(length_type n = 1)
  313|   {
  314|     left_.increment(n);
  315|     right_.increment(n);
  316|   }
  317| 
  318| private:
  319|   AB left_;
  320|   right_;
  321| };
  322| 
  323| // Proxy for ternary 'add-multiply' expression (a + b * c)
  324| template <typename A, typename B, typename C>
  325| class Proxy<Binary_access_traits<A,
  326|                               Proxy<Binary_access_traits<B, C, op::Mult> >,
  327|                op::Add> >
  328| {
  329| public:
  330|   typedef Proxy<Binary_access_traits<B, C, op::Mult> > BC;
  331|   typedef Binary_access_traits<A, BC, op::Add> access_traits;
  332|   typedef typename access_traits::value_type value_type;
  333|   typedef typename Simd_traits<value_type>::simd_type simd_type;
  334| 
  335|   Proxy(A const &left, BC const &right)
  336|     : left_(left), right_(right) {}
  337| 
  338|   A const &left() const { return left_;}
  339|   BC const &right() const { return right_;}
  340| 
  341|   simd_type load() const 
  342|   {
  343|     simd_type a = left_.load();
  344|     simd_type b = right_.left().load();
  345|     simd_type c = right_.right().load();
  346|     return Simd_traits<value_type>::fma(bca);
  347|   }
  348| 
  349|   void increment(length_type n = 1)
  350|   {
  351|     left_.increment(n);
  352|     right_.increment(n);
  353|   }
  354| 
  355| private:
  356|   left_;
  357|   BC right_;
  358| };
  359| 
  360| // Proxy for quaternary 'add-multiply' expression (a * b + c * d)
  361| // (needed for disambiguation).
  362| template <typename A, typename B, typename C, typename D>
  363| class Proxy<Binary_access_traits<Proxy<Binary_access_traits<A, B, op::Mult> >,
  364|                               Proxy<Binary_access_traits<C, D, op::Mult> >,
  365|                op::Add> >
  366| {
  367| public:
  368|   typedef Proxy<Binary_access_traits<A, B, op::Mult> > AB;
  369|   typedef Proxy<Binary_access_traits<C, D, op::Mult> > CD;
  370|   typedef Binary_access_traits<AB, CD, op::Add> access_traits;
  371|   typedef typename access_traits::value_type value_type;
  372|   typedef typename Simd_traits<value_type>::simd_type simd_type;
  373| 
  374|   Proxy(AB const &left, CD const &right)
  375|     : left_(left), right_(right) {}
  376| 
  377|   AB const &left() const { return left_;}
  378|   CD const &right() const { return right_;}
  379| 
  380|   simd_type load() const 
  381|   {
  382|     // Implement 'a * b + c * d' as '(a*b) + c * d'.
  383|     simd_type ab = left_.load();
  384|     simd_type c = right_.left().load();
  385|     simd_type d = right_.right().load();
  386|     return Simd_traits<value_type>::fma(cdab);
  387|   }
  388| 
  389|   void increment(length_type n = 1)
  390|   {
  391|     left_.increment(n);
  392|     right_.increment(n);
  393|   }
  394| 
  395| private:
  396|   AB left_;
  397|   CD right_;
  398| };
  399| 
  400| template <typename T>
  401| struct Iterator
  402| {
  403| public:
  404|   Iterator(Proxy<T> const &c) : cursor_(c) {}
  405|   bool operator== (Iterator const &i) const { return cursor_ == i.cursor_;}
  406|   bool operator!= (Iterator const &i) const { return !(*this==i);}
  407|   Proxy<T> &operator* () { return cursor_;}
  408|   Proxy<T> *operator-> () { return &cursor_;}
  409|   Iterator &operator++() { cursor_.increment(); return *this;}
  410|   Iterator operator++(int) { Iterator i(*this); cursor_.increment(); return i;}
  411|   Iterator &operator+=(length_type n) { cursor_.increment(n); return *this;}
  412| 
  413| private:
  414|   Proxy<T> cursor_;
  415| };
  416| 
  417| template <typename T>
  418| inline Iterator<T> 
  419| operator+(Iterator<T> const i, length_type n) 
  420| {
  421|   Iterator<T> r(i);
  422|   r += n;
  423|   return r;
  424| }
  425| 
  426| // namespace vsip::impl::simd
  427| // namespace vsip::impl
  428| // namespace vsip
  429| 
  430| #endif