首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用Altivec将向量存储到内存中未对齐的位置

如何使用Altivec将向量存储到内存中未对齐的位置
EN

Stack Overflow用户
提问于 2016-02-10 14:04:45
回答 1查看 356关注 0票数 5

我从教程了解到,未对齐的加载和存储可能如下所示:

代码语言:javascript
复制
//Load a vector from an unaligned location in memory
__vector unsigned char LoadUnaligned(const unsigned char * src )
{
    __vector unsigned char permuteVector = vec_lvsl(0, src);
    __vector unsigned char low = vec_ld( 0, src);
    __vector unsigned char high = vec_ld( 16, src);
    return vec_perm( low, high, permuteVector);
}

//Store a vector to an unaligned location in memory
void StoreUnaligned(__vector unsigned char v, __vector unsigned char * dst)
{
    //Load the surrounding area
    __vector unsigned char low = vec_ld( 0, dst);
    __vector unsigned char high = vec_ld( 16, dst);
    //Prepare the constants that we need
    __vector unsigned char permuteVector = vec_lvsr( 0, (int*) dst);
    __vector signed char oxFF = vec_splat_s8( -1 );
    __vector signed char ox00 = vec_splat_s8( 0 );
    //Make a mask for which parts of the vectors to swap out
    __vector unsigned char mask = vec_perm( ox00, oxFF, permuteVector );
    //Right rotate our input data
    v = vec_perm( v, v, permuteVector );
    //Insert our data into the low and high vectors
    low = vec_sel( v, low, mask );
    high = vec_sel( high, v, mask );
    //Store the two aligned result vectors
    vec_st( low, 0, dst);
    vec_st( high, 16, dst);
}

看起来糟透了。这么多的工作,为了存储一个向量!并且具有适当的性能损失。

代码语言:javascript
复制
void SomeFuncA(const unsigned char * src, size_t size, unsigned char * dst)
{
    for(size_t i = 0; i < size; i += 16)
    {
        __vector unsigned char a = vec_ld(0, src + i);
        //simple work
        vec_st(a, 0, dst + i);
    }    
}

void SomeFuncU(const unsigned char * src, size_t size, unsigned char * dst)
{
    for(size_t i = 0; i < size; i += 16)
    {
        __vector unsigned char a = LoadUnaligned(src + i);
        //simple work
        StoreUnaligned(dst + i, a);
    }    
}

第二个函数的工作速度是第一个函数的3-4倍。因为我无法控制输入和输出内存的对齐,所以我必须实现这两个版本。如何将未对齐情况下的性能损失降到最低?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-02-10 14:30:17

首先,我想提到的是,如果您多次将Altivec向量保存到未对齐内存,则不需要只在开始和结束时在数组中间保存以前的内存状态。因此,在Simd库中有一个有用的函数和类,它实现了这个功能:

代码语言:javascript
复制
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;
};

它的使用将类似于:

代码语言:javascript
复制
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);
    //simple work
    _dst.First(a);// save first block 
    for(size_t i = 16; i < size; i += 16)
    {
        __vector unsigned char a = Load<align>(src + i);
        //simple work
        _dst.Next(a);// save body 
    }
    _dst.Flush();  // save tail      
}

与对齐版本相比,性能损失将达到30-40%。当然,这是令人不快的,但却是容忍的。

另外的优点是减少了代码-所有功能(对齐和未对齐)都有相同的实现。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35317341

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档