簡體   English   中英

在 C++ 中使用 SSE2 SIMD 對兩個數組求和的正確方法

[英]The correct way to sum two arrays with SSE2 SIMD in C++

讓我們從包括以下內容開始:

#include <vector>
#include <random>
using namespace std;

現在,假設有以下三個std:vector<float>

N = 1048576;
vector<float> a(N);
vector<float> b(N);
vector<float> c(N);

default_random_engine randomGenerator(time(0));
uniform_real_distribution<float> diceroll(0.0f, 1.0f);
for(int i-0; i<N; i++)
{
    a[i] = diceroll(randomGenerator);
    b[i] = diceroll(randomGenerator);
}

現在,假設需要按元素對ab求和並將結果存儲在c ,標量形式如下所示:

for(int i=0; i<N; i++)
{
    c[i] = a[i] + b[i];
}

上面代碼的 SSE2 向量化版本是什么,記住輸入是上面定義的ab (即作為float的集合),而輸出是c (也是float的集合)?

經過大量研究,我得出了以下結論:

for(int i=0; i<N; i+=4)
{
    float a_toload[4] = { a[i], a[i + 1], a[i + 2], a[i + 3] };
    float b_toload[4] = { b[i], b[i + 1], b[i + 2], b[i + 3] };
    __m128 loaded_a = _mm_loadu_ps(a_toload);
    __m128 loaded_b = _mm_loadu_ps(b_toload);

    float result[4] = { 0, 0, 0, 0 };
    _mm_storeu_ps(result, _mm_add_ps(loaded_a , loaded_b));
    c[i] = result[0];
    c[i + 1] = result[1];
    c[i + 2] = result[2];
    c[i + 3] = result[3];
}

然而,這看起來真的很麻煩,而且肯定效率很低:上面的 SIMD 版本實際上比初始標量版本慢了三倍(當然,在微軟 VS15 的發布模式下,經過 100 萬次迭代后測量,優化,不僅僅是 12)。

您的 for 循環可以簡化為

const int aligendN = N - N % 4;
for (int i = 0; i < alignedN; i+=4) {
    _mm_storeu_ps(&c[i], 
                  _mm_add_ps(_mm_loadu_ps(&a[i]), 
                  _mm_loadu_ps(&b[i])));
}
for (int i = alignedN; i < N; ++i) {
    c[i] = a[i] + b[i];
}

一些額外的解釋:

  1. 處理最后幾個浮點數的小循環很常見,當N%4 != 0或 N 在編譯時未知時,這是強制性的。
  2. 我注意到您選擇了未對齊的版本加載/存儲,與對齊版本相比,損失很小。 我在 stackoverflow 上找到了這個鏈接: SSE 未對齊的內在負載是否比 x64_64 Intel CPU 上的內在對齊負載慢?

您不需要將中間數組加載到 SSE 寄存器。 只需直接從您的陣列加載。

auto loaded_a = _mm_loadu_ps(&a[i]);
auto loaded_b = _mm_loadu_ps(&b[i]);
_mm_storeu_ps(&c[i], _mm_add_ps(loaded_a, loaded_b));

您也可以省略兩個loaded變量並將它們合並到 add 中,盡管編譯器應該為您這樣做。

您需要小心這一點,因為如果向量大小不是 4 的倍數,它將無法正常工作(您將訪問數組末尾,導致未定義行為,並且寫入超過c的末尾可能會損壞)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM