First of all, I want to note that if you save the Altivec vector to unchanged memory many times, you do not need to save the previous state of memory in the middle of the array only at the beginning and at the end. Thus, there is a useful function and class in the Simd Library that implement this functionality:
typedef __vector uint8_t v128_u8; const v128_u8 K8_00 = vec_splat_u8(0x00); const v128_u8 K8_FF = vec_splat_u8(0xFF); template <bool align> inline v128_u8 Load(const uint8_t * p); template <> inline v128_u8 Load<false>(const uint8_t * p) { v128_u8 lo = vec_ld(0, p); v128_u8 hi = vec_ld(16, p); return vec_perm(lo, hi, vec_lvsl(0, p)); } template <> inline v128_u8 Load<true>(const uint8_t * p) { return vec_ld(0, p); } template <bool align> struct Storer; template <> struct Storer<true> { template <class T> Storer(T * ptr) :_ptr((uint8_t*)ptr) { } template <class T> inline void First(T value) { vec_st((v128_u8)value, 0, _ptr); } template <class T> inline void Next(T value) { _ptr += 16; vec_st((v128_u8)value, 0, _ptr); } inline void Flush() { } private: uint8_t * _ptr; }; template <> struct Storer<false> { template <class T> inline Storer(T * ptr) :_ptr((uint8_t*)ptr) { _perm = vec_lvsr(0, _ptr); _mask = vec_perm(K8_00, K8_FF, _perm); } template <class T> inline void First(T value) { _last = (v128_u8)value; v128_u8 background = vec_ld(0, _ptr); v128_u8 foreground = vec_perm(_last, _last, _perm); vec_st(vec_sel(background, foreground, _mask), 0, _ptr); } template <class T> inline void Next(T value) { _ptr += 16; vec_st(vec_perm(_last, (v128_u8)value, _perm), 0, _ptr); _last = (v128_u8)value; } inline void Flush() { v128_u8 background = vec_ld(16, _ptr); v128_u8 foreground = vec_perm(_last, _last, _perm); vec_st(vec_sel(foreground, background, _mask), 16, _ptr); } private: uint8_t * _ptr; v128_u8 _perm; v128_u8 _mask; v128_u8 _last; };
Its use will be as follows:
template<bool align> void SomeFunc(const unsigned char * src, size_t size, unsigned char * dst) { Storer<align> _dst(dst); __vector unsigned char a = Load<align>(src);
Loss of performance will be 30-40% compared to the aligned version. This is unpleasant, of course, but bearable.
An additional advantage is code reduction - all functions (aligned and not aligned) have the same implementation.