]> git.sesse.net Git - x264/blobdiff - common/ppc/ppccommon.h
Bump dates to 2013
[x264] / common / ppc / ppccommon.h
index 26aeb5287cd1641334af99d3072641361c6897a2..f88d36081b8b74b21113abbd877d8e152a1d85ad 100644 (file)
@@ -1,10 +1,9 @@
 /*****************************************************************************
- * ppccommon.h: h264 encoder
+ * ppccommon.h: ppc utility macros
  *****************************************************************************
- * Copyright (C) 2003 Laurent Aimar
- * $Id: ppccommon.h,v 1.1 2004/06/03 19:27:07 fenrir Exp $
+ * Copyright (C) 2003-2013 x264 project
  *
- * Authors: Eric Petit <titer@m0k.org>
+ * Authors: Eric Petit <eric.petit@lapsus.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
+ *
+ * This program is also available under a commercial proprietary license.
+ * For more information, contact us at licensing@x264.com.
  *****************************************************************************/
 
+#if HAVE_ALTIVEC_H
+#include <altivec.h>
+#endif
+
 /***********************************************************************
  * For constant vectors, use parentheses on OS X and braces on Linux
  **********************************************************************/
-#ifdef SYS_MACOSX
+#if defined(__APPLE__) && __GNUC__ < 4
 #define CV(a...) (a)
 #else
 #define CV(a...) {a}
 #define vec_u32_t vector unsigned int
 #define vec_s32_t vector signed int
 
+typedef union {
+  uint32_t s[4];
+  vec_u32_t v;
+} vec_u32_u;
+
+typedef union {
+  uint16_t s[8];
+  vec_u16_t v;
+} vec_u16_u;
+
+typedef union {
+  int16_t s[8];
+  vec_s16_t v;
+} vec_s16_u;
+
+typedef union {
+  uint8_t s[16];
+  vec_u8_t v;
+} vec_u8_u;
+
 /***********************************************************************
  * Null vector
  **********************************************************************/
-#define LOAD_ZERO vec_u8_t zerov = vec_splat_u8( 0 )
+#define LOAD_ZERO const vec_u8_t zerov = vec_splat_u8( 0 )
 
 #define zero_u8v  (vec_u8_t)  zerov
 #define zero_s8v  (vec_s8_t)  zerov
 #define zero_s32v (vec_s32_t) zerov
 
 /***********************************************************************
- * Conversions
+ * 8 <-> 16 bits conversions
  **********************************************************************/
-static inline vec_u16_t vec_u8_to_u16( vec_u8_t v )
-{
-    LOAD_ZERO;
-    return (vec_u16_t) vec_mergeh( zero_u8v, v );
-}
-static inline vec_u8_t vec_u16_to_u8( vec_u16_t v )
-{
-    LOAD_ZERO;
-    return (vec_u8_t) vec_pack( v, zero_u16v );
-}
-#define vec_u8_to_s16(v) (vec_s16_t) vec_u8_to_u16(v)
-#define vec_s16_to_u8(v) vec_u16_to_u8( (vec_u16_t) v )
+#define vec_u8_to_u16_h(v) (vec_u16_t) vec_mergeh( zero_u8v, (vec_u8_t) v )
+#define vec_u8_to_u16_l(v) (vec_u16_t) vec_mergel( zero_u8v, (vec_u8_t) v )
+#define vec_u8_to_s16_h(v) (vec_s16_t) vec_mergeh( zero_u8v, (vec_u8_t) v )
+#define vec_u8_to_s16_l(v) (vec_s16_t) vec_mergel( zero_u8v, (vec_u8_t) v )
+
+#define vec_u8_to_u16(v) vec_u8_to_u16_h(v)
+#define vec_u8_to_s16(v) vec_u8_to_s16_h(v)
+
+#define vec_u16_to_u8(v) vec_pack( v, zero_u16v )
+#define vec_s16_to_u8(v) vec_packsu( v, zero_s16v )
 
-/***********************************************************************
- * vec_load16
- **********************************************************************/
-static inline vec_u8_t vec_load16( uint8_t * p )
-{
-    if( (long) p & 0xF )
-    {
-        vec_u8_t hv, lv, perm;
-        hv   = vec_ld( 0, p );
-        lv   = vec_ld( 16, p );
-        perm = vec_lvsl( 0, p );
-        return vec_perm( hv, lv, perm );
-    }
-    return vec_ld( 0, p );
-}
 
 /***********************************************************************
- * vec_load8
+ * 16 <-> 32 bits conversions
  **********************************************************************/
-static inline vec_u8_t vec_load8( uint8_t * p )
-{
-    long align = (long) p & 0xF;
-
-    if( align )
-    {
-        vec_u8_t hv, perm;
-        hv   = vec_ld( 0, p );
-        perm = vec_lvsl( 0, p );
-        if( align > 8 )
-        {
-            vec_u8_t lv;
-            lv = vec_ld( 16, p );
-            return vec_perm( hv, lv, perm );
-        }
-        return vec_perm( hv, hv, perm );
-    }
-    return vec_ld( 0, p );
-}
+#define vec_u16_to_u32_h(v) (vec_u32_t) vec_mergeh( zero_u16v, (vec_u16_t) v )
+#define vec_u16_to_u32_l(v) (vec_u32_t) vec_mergel( zero_u16v, (vec_u16_t) v )
+#define vec_u16_to_s32_h(v) (vec_s32_t) vec_mergeh( zero_u16v, (vec_u16_t) v )
+#define vec_u16_to_s32_l(v) (vec_s32_t) vec_mergel( zero_u16v, (vec_u16_t) v )
+
+#define vec_u16_to_u32(v) vec_u16_to_u32_h(v)
+#define vec_u16_to_s32(v) vec_u16_to_s32_h(v)
+
+#define vec_u32_to_u16(v) vec_pack( v, zero_u32v )
+#define vec_s32_to_u16(v) vec_packsu( v, zero_s32v )
+
 
 /***********************************************************************
- * vec_load4
+ * PREP_LOAD: declares two vectors required to perform unaligned loads
+ * VEC_LOAD:  loads n bytes from u8 * p into vector v of type t where o is from original src offset
+ * VEC_LOAD:_G: loads n bytes from u8 * p into vectory v of type t - use when offset is not known
+ * VEC_LOAD_OFFSET: as above, but with offset vector known in advance
  **********************************************************************/
-static inline vec_u8_t vec_load4( uint8_t * p )
-{
-    long align = (long) p & 0xF;
-
-    if( align )
-    {
-        vec_u8_t hv, perm;
-        hv   = vec_ld( 0, p );
-        perm = vec_lvsl( 0, p );
-        if( align > 12 )
-        {
-            vec_u8_t lv;
-            lv = vec_ld( 16, p );
-            return vec_perm( hv, lv, perm );
-        }
-        return vec_perm( hv, hv, perm );
-    }
-    return vec_ld( 0, p );
-}
+#define PREP_LOAD     \
+    vec_u8_t _hv, _lv
+
+#define PREP_LOAD_SRC( src )              \
+    vec_u8_t _##src##_ = vec_lvsl(0, src)
+
+#define VEC_LOAD_G( p, v, n, t )                 \
+    _hv = vec_ld( 0, p );                        \
+    v   = (t) vec_lvsl( 0, p );                  \
+    _lv = vec_ld( n - 1, p );                    \
+    v   = (t) vec_perm( _hv, _lv, (vec_u8_t) v )
+
+#define VEC_LOAD( p, v, n, t, g )                   \
+    _hv = vec_ld( 0, p );                           \
+    _lv = vec_ld( n - 1, p );                       \
+    v = (t) vec_perm( _hv, _lv, (vec_u8_t) _##g##_ )
+
+#define VEC_LOAD_OFFSET( p, v, n, t, o )         \
+    _hv = vec_ld( 0, p);                         \
+    _lv = vec_ld( n - 1, p );                    \
+    v   = (t) vec_perm( _hv, _lv, (vec_u8_t) o )
+
+#define VEC_LOAD_PARTIAL( p, v, n, t, g)               \
+    _hv = vec_ld( 0, p);                               \
+    v   = (t) vec_perm( _hv, _hv, (vec_u8_t) _##g##_ )
+
 
 /***********************************************************************
- * vec_store16
+ * PREP_STORE##n: declares required vectors to store n bytes to a
+ *                potentially unaligned address
+ * VEC_STORE##n:  stores n bytes from vector v to address p
  **********************************************************************/
-static inline void vec_store16( vec_u8_t v, uint8_t * p )
-{
-    if( (long) p & 0xF )
-    {
-        vec_u8_t hv, lv, tmp1, tmp2;
-        hv   = vec_ld( 0, p );
-        lv   = vec_ld( 16, p );
-        tmp2 = vec_lvsl( 0, p );
-        tmp1 = vec_perm( lv, hv, tmp2 );
-        tmp2 = vec_lvsr( 0, p );
-        hv   = vec_perm( tmp1, v, tmp2 );
-        lv   = vec_perm( v, tmp1, tmp2 );
-        vec_st( lv, 16, p );
-        vec_st( hv, 0, p );
-        return;
-    }
-    vec_st( v, 0, p );
-}
+#define PREP_STORE16 \
+    vec_u8_t _tmp1v  \
+
+#define PREP_STORE16_DST( dst )             \
+    vec_u8_t _##dst##l_ = vec_lvsl(0, dst); \
+    vec_u8_t _##dst##r_ = vec_lvsr(0, dst);
+
+#define VEC_STORE16( v, p, o )                           \
+    _hv    = vec_ld( 0, p );                             \
+    _lv    = vec_ld( 15, p );                            \
+    _tmp1v = vec_perm( _lv, _hv, _##o##l_ );             \
+    _lv    = vec_perm( (vec_u8_t) v, _tmp1v, _##o##r_ ); \
+    vec_st( _lv, 15, (uint8_t *) p );                    \
+    _hv    = vec_perm( _tmp1v, (vec_u8_t) v, _##o##r_ ); \
+    vec_st( _hv, 0, (uint8_t *) p )
+
+
+#define PREP_STORE8 \
+    vec_u8_t _tmp3v \
+
+#define VEC_STORE8( v, p )                \
+    _tmp3v = vec_lvsl(0, p);              \
+    v = vec_perm(v, v, _tmp3v);           \
+    vec_ste((vec_u32_t)v,0,(uint32_t*)p); \
+    vec_ste((vec_u32_t)v,4,(uint32_t*)p)
+
+
+#define PREP_STORE4                                        \
+    PREP_STORE16;                                          \
+    vec_u8_t _tmp2v, _tmp3v;                               \
+    const vec_u8_t sel =                                   \
+        (vec_u8_t) CV(-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0)
+
+#define VEC_STORE4( v, p )                      \
+    _tmp3v = vec_lvsr( 0, p );                  \
+    v      = vec_perm( v, v, _tmp3v );          \
+    _lv    = vec_ld( 3, p );                    \
+    _tmp1v = vec_perm( sel, zero_u8v, _tmp3v ); \
+    _lv    = vec_sel( _lv, v, _tmp1v );         \
+    vec_st( _lv, 3, p );                        \
+    _hv    = vec_ld( 0, p );                    \
+    _tmp2v = vec_perm( zero_u8v, sel, _tmp3v ); \
+    _hv    = vec_sel( _hv, v, _tmp2v );         \
+    vec_st( _hv, 0, p )
 
 /***********************************************************************
- * vec_store8
+ * VEC_TRANSPOSE_8
+ ***********************************************************************
+ * Transposes a 8x8 matrix of s16 vectors
  **********************************************************************/
-static inline void vec_store8( vec_u8_t v, uint8_t * p )
-{
-    LOAD_ZERO;
-    long     align;
-    vec_u8_t hv, sel;
-
-    align = (long) p & 0xF;
-    hv    = vec_ld( 0, p );
-    sel   = (vec_u8_t) CV(-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0);
-
-    if( align )
-    {
-        vec_u8_t perm;
-        perm = vec_lvsr( 0, p );
-        v    = vec_perm( v, v, perm );
-        if( align > 8 )
-        {
-            vec_u8_t lv, hsel, lsel;
-            lv   = vec_ld( 16, p );
-            hsel = vec_perm( zero_u8v, sel, perm );
-            lsel = vec_perm( sel, zero_u8v, perm );
-            hv   = vec_sel( hv, v, hsel );
-            lv   = vec_sel( lv, v, lsel );
-            vec_st( lv, 16, p );
-        }
-        else
-        {
-            sel = vec_perm( sel, sel, perm );
-            hv  = vec_sel( hv, v, sel );
-        }
-    }
-    else
-    {
-        hv = vec_sel( hv, v, sel );
-    }
-    vec_st( hv, 0, p );
-}
+#define VEC_TRANSPOSE_8(a0,a1,a2,a3,a4,a5,a6,a7,b0,b1,b2,b3,b4,b5,b6,b7) \
+    b0 = vec_mergeh( a0, a4 ); \
+    b1 = vec_mergel( a0, a4 ); \
+    b2 = vec_mergeh( a1, a5 ); \
+    b3 = vec_mergel( a1, a5 ); \
+    b4 = vec_mergeh( a2, a6 ); \
+    b5 = vec_mergel( a2, a6 ); \
+    b6 = vec_mergeh( a3, a7 ); \
+    b7 = vec_mergel( a3, a7 ); \
+    a0 = vec_mergeh( b0, b4 ); \
+    a1 = vec_mergel( b0, b4 ); \
+    a2 = vec_mergeh( b1, b5 ); \
+    a3 = vec_mergel( b1, b5 ); \
+    a4 = vec_mergeh( b2, b6 ); \
+    a5 = vec_mergel( b2, b6 ); \
+    a6 = vec_mergeh( b3, b7 ); \
+    a7 = vec_mergel( b3, b7 ); \
+    b0 = vec_mergeh( a0, a4 ); \
+    b1 = vec_mergel( a0, a4 ); \
+    b2 = vec_mergeh( a1, a5 ); \
+    b3 = vec_mergel( a1, a5 ); \
+    b4 = vec_mergeh( a2, a6 ); \
+    b5 = vec_mergel( a2, a6 ); \
+    b6 = vec_mergeh( a3, a7 ); \
+    b7 = vec_mergel( a3, a7 )
 
 /***********************************************************************
- * vec_transpose8x8
+ * VEC_TRANSPOSE_4
+ ***********************************************************************
+ * Transposes a 4x4 matrix of s16 vectors.
+ * Actually source and destination are 8x4. The low elements of the
+ * source are discarded and the low elements of the destination mustn't
+ * be used.
  **********************************************************************/
-static inline void vec_transpose8x8( vec_s16_t * a, vec_s16_t * b )
-{
-    b[0] = vec_mergeh( a[0], a[4] );
-    b[1] = vec_mergel( a[0], a[4] );
-    b[2] = vec_mergeh( a[1], a[5] );
-    b[3] = vec_mergel( a[1], a[5] );
-    b[4] = vec_mergeh( a[2], a[6] );
-    b[5] = vec_mergel( a[2], a[6] );
-    b[6] = vec_mergeh( a[3], a[7] );
-    b[7] = vec_mergel( a[3], a[7] );
-    a[0] = vec_mergeh( b[0], b[4] );
-    a[1] = vec_mergel( b[0], b[4] );
-    a[2] = vec_mergeh( b[1], b[5] );
-    a[3] = vec_mergel( b[1], b[5] );
-    a[4] = vec_mergeh( b[2], b[6] );
-    a[5] = vec_mergel( b[2], b[6] );
-    a[6] = vec_mergeh( b[3], b[7] );
-    a[7] = vec_mergel( b[3], b[7] );
-    b[0] = vec_mergeh( a[0], a[4] );
-    b[1] = vec_mergel( a[0], a[4] );
-    b[2] = vec_mergeh( a[1], a[5] );
-    b[3] = vec_mergel( a[1], a[5] );
-    b[4] = vec_mergeh( a[2], a[6] );
-    b[5] = vec_mergel( a[2], a[6] );
-    b[6] = vec_mergeh( a[3], a[7] );
-    b[7] = vec_mergel( a[3], a[7] );
-}
+#define VEC_TRANSPOSE_4(a0,a1,a2,a3,b0,b1,b2,b3) \
+    b0 = vec_mergeh( a0, a0 ); \
+    b1 = vec_mergeh( a1, a0 ); \
+    b2 = vec_mergeh( a2, a0 ); \
+    b3 = vec_mergeh( a3, a0 ); \
+    a0 = vec_mergeh( b0, b2 ); \
+    a1 = vec_mergel( b0, b2 ); \
+    a2 = vec_mergeh( b1, b3 ); \
+    a3 = vec_mergel( b1, b3 ); \
+    b0 = vec_mergeh( a0, a2 ); \
+    b1 = vec_mergel( a0, a2 ); \
+    b2 = vec_mergeh( a1, a3 ); \
+    b3 = vec_mergel( a1, a3 )
 
 /***********************************************************************
- * vec_transpose4x4
+ * VEC_DIFF_H
+ ***********************************************************************
+ * p1, p2:    u8 *
+ * i1, i2, n: int
+ * d:         s16v
+ *
+ * Loads n bytes from p1 and p2, do the diff of the high elements into
+ * d, increments p1 and p2 by i1 and i2 into known offset g
  **********************************************************************/
-static inline void vec_transpose4x4( vec_s16_t * a, vec_s16_t * b )
-{
-#define WHATEVER a[0]
-    b[0] = vec_mergeh( a[0], WHATEVER );
-    b[1] = vec_mergeh( a[1], WHATEVER );
-    b[2] = vec_mergeh( a[2], WHATEVER );
-    b[3] = vec_mergeh( a[3], WHATEVER );
-    a[0] = vec_mergeh( b[0], b[2] );
-    a[1] = vec_mergel( b[0], b[2] );
-    a[2] = vec_mergeh( b[1], b[3] );
-    a[3] = vec_mergel( b[1], b[3] );
-    b[0] = vec_mergeh( a[0], a[2] );
-    b[1] = vec_mergel( a[0], a[2] );
-    b[2] = vec_mergeh( a[1], a[3] );
-    b[3] = vec_mergel( a[1], a[3] );
-#undef WHATEVER
-}
+#define PREP_DIFF           \
+    LOAD_ZERO;              \
+    PREP_LOAD;              \
+    vec_s16_t pix1v, pix2v;
+
+
+#define VEC_DIFF_H(p1,i1,p2,i2,n,d,g)               \
+    VEC_LOAD_PARTIAL( p1, pix1v, n, vec_s16_t, p1); \
+    pix1v = vec_u8_to_s16( pix1v );                 \
+    VEC_LOAD( p2, pix2v, n, vec_s16_t, g);          \
+    pix2v = vec_u8_to_s16( pix2v );                 \
+    d     = vec_sub( pix1v, pix2v );                \
+    p1   += i1;                                     \
+    p2   += i2
+
+#define VEC_DIFF_H_OFFSET(p1,i1,p2,i2,n,d,g1,g2)    \
+    pix1v = (vec_s16_t)vec_perm( vec_ld( 0, p1 ), zero_u8v, _##g1##_ );\
+    pix1v = vec_u8_to_s16( pix1v );                 \
+    VEC_LOAD( p2, pix2v, n, vec_s16_t, g2);         \
+    pix2v = vec_u8_to_s16( pix2v );                 \
+    d     = vec_sub( pix1v, pix2v );                \
+    p1   += i1;                                     \
+    p2   += i2
+
 
 /***********************************************************************
- * vec_hadamar
+ * VEC_DIFF_HL
  ***********************************************************************
- * b[0] = a[0] + a[1] + a[2] + a[3]
- * b[1] = a[0] + a[1] - a[2] - a[3]
- * b[2] = a[0] - a[1] - a[2] + a[3]
- * b[3] = a[0] - a[1] + a[2] - a[3]
+ * p1, p2: u8 *
+ * i1, i2: int
+ * dh, dl: s16v
+ *
+ * Loads 16 bytes from p1 and p2, do the diff of the high elements into
+ * dh, the diff of the low elements into dl, increments p1 and p2 by i1
+ * and i2
  **********************************************************************/
-static inline void vec_hadamar( vec_s16_t * a, vec_s16_t * b )
-{
-    b[2] = vec_add( a[0], a[1] );
-    b[3] = vec_add( a[2], a[3] );
-    a[0] = vec_sub( a[0], a[1] );
-    a[2] = vec_sub( a[2], a[3] );
-    b[0] = vec_add( b[2], b[3] );
-    b[1] = vec_sub( b[2], b[3] );
-    b[2] = vec_sub( a[0], a[2] );
-    b[3] = vec_add( a[0], a[2] );
-}
+#define VEC_DIFF_HL(p1,i1,p2,i2,dh,dl)       \
+    pix1v = (vec_s16_t)vec_ld(0, p1);        \
+    temp0v = vec_u8_to_s16_h( pix1v );       \
+    temp1v = vec_u8_to_s16_l( pix1v );       \
+    VEC_LOAD( p2, pix2v, 16, vec_s16_t, p2); \
+    temp2v = vec_u8_to_s16_h( pix2v );       \
+    temp3v = vec_u8_to_s16_l( pix2v );       \
+    dh     = vec_sub( temp0v, temp2v );      \
+    dl     = vec_sub( temp1v, temp3v );      \
+    p1    += i1;                             \
+    p2    += i2
+
+/***********************************************************************
+* VEC_DIFF_H_8BYTE_ALIGNED
+***********************************************************************
+* p1, p2:    u8 *
+* i1, i2, n: int
+* d:         s16v
+*
+* Loads n bytes from p1 and p2, do the diff of the high elements into
+* d, increments p1 and p2 by i1 and i2
+* Slightly faster when we know we are loading/diffing 8bytes which
+* are 8 byte aligned. Reduces need for two loads and two vec_lvsl()'s
+**********************************************************************/
+#define PREP_DIFF_8BYTEALIGNED \
+LOAD_ZERO;                     \
+vec_s16_t pix1v, pix2v;        \
+vec_u8_t pix1v8, pix2v8;       \
+vec_u8_t permPix1, permPix2;   \
+permPix1 = vec_lvsl(0, pix1);  \
+permPix2 = vec_lvsl(0, pix2);  \
+
+#define VEC_DIFF_H_8BYTE_ALIGNED(p1,i1,p2,i2,n,d)     \
+pix1v8 = vec_perm(vec_ld(0,p1), zero_u8v, permPix1);  \
+pix2v8 = vec_perm(vec_ld(0, p2), zero_u8v, permPix2); \
+pix1v = vec_u8_to_s16( pix1v8 );                      \
+pix2v = vec_u8_to_s16( pix2v8 );                      \
+d = vec_sub( pix1v, pix2v);                           \
+p1 += i1;                                             \
+p2 += i2;