0

SIMDと並行して配列の要素を合計しようとしています。ロックを回避するために、_mm_add_epi32 が例外をスローしているため、常に 16 バイトに整列されているとは限らない、結合可能なスレッド ローカルを使用しています。

concurrency::combinable<__m128i> sum_combine;

int length = 40; // multiple of 8
concurrency::parallel_for(0, length , 8, [&](int it)
{

    __m128i v1 = _mm_load_si128(reinterpret_cast<__m128i*>(input_arr + it));
    __m128i v2 = _mm_load_si128(reinterpret_cast<__m128i*>(input_arr + it + sizeof(uint32_t)));

    auto temp = _mm_add_epi32(v1, v2);

    auto &sum = sum_combine.local();   // here is the problem 


    TRACE(L"%d\n", it);
    TRACE(L"add %x\n", &sum);

    ASSERT(((unsigned long)&sum & 15) == 0);

    sum = _mm_add_epi32(temp, sum);
}
);

ここにppl.hからのcombinableの定義があります

template<typename _Ty>
class combinable
{
private:

// Disable warning C4324: structure was padded due to __declspec(align())
// This padding is expected and necessary.
#pragma warning(push)
#pragma warning(disable: 4324)
    __declspec(align(64))
    struct _Node
    {
        unsigned long _M_key;
        _Ty _M_value;                   // this might not be aligned on 16 bytes
        _Node* _M_chain;

        _Node(unsigned long _Key, _Ty _InitialValue)
            : _M_key(_Key), _M_value(_InitialValue), _M_chain(NULL)
        {
        }
    };

位置合わせに問題がなく、コードが正常に機能することもありますが、ほとんどの場合は機能しません

以下を使用しようとしましたが、これはコンパイルされません

union combine 
{
        unsigned short x[sizeof(__m128i) / sizeof(unsigned int)];
        __m128i y;
};

concurrency::combinable<combine> sum_combine;
then auto &sum = sum_combine.local().y; 

アライメントの問題を修正するための提案はありますが、まだ組み合わせ可能なものを使用しています。

x64 では、デフォルトの 16 バイト アラインメントにより問題なく動作します。x86 では、アライメントの問題が存在することがあります。

4

2 に答える 2

1

unaligned load を使用して合計をロードしました

auto &sum = sum_combine.local();


#if !defined(_M_X64) 

if (((unsigned long)&sum & 15) != 0)
{
    // just for breakpoint means, sum  is unaligned.
    int a = 5;
}
auto sum_temp = _mm_loadu_si128(&sum);
sum = _mm_add_epi32(temp, sum_temp);

#else

sum = _mm_add_epi32(temp, sum);

#endif
于 2015-07-12T15:48:14.307 に答える