-1

我的目标是仅使用 CPU 并使用 SSE 来实现该算法: 在此处输入图像描述

我的数组大小是 4 的倍数并且它们是对齐的:

const int INPUT_SIGNAL_ARRAY_SIZE = 256896;
const int IMPULSE_RESPONSE_ARRAY_SIZE = 318264;
const int OUTPUT_SIGNAL_ARRAY_SIZE = INPUT_SIGNAL_ARRAY_SIZE + IMPULSE_RESPONSE_ARRAY_SIZE;

__declspec(align(16)) float inputSignal_dArray[INPUT_SIGNAL_ARRAY_SIZE];
__declspec(align(16)) float impulseResponse_dArray[IMPULSE_RESPONSE_ARRAY_SIZE];
__declspec(align(16)) float outputSignal_dArray[OUTPUT_SIGNAL_ARRAY_SIZE];

我已经编写了 CPU“方法”并且它可以正常工作:

//#pragma optimize( "", off )
void computeConvolutionOutputCPU(float* inputSignal, float* impulseResponse, float* outputSignal) {
    float* pInputSignal = inputSignal;
    float* pImpulseResponse = impulseResponse;
    float* pOutputSignal = outputSignal;

    #pragma loop(no_vector)
    for (int i = 0; i < OUTPUT_SIGNAL_ARRAY_SIZE; i++)
    {
        *(pOutputSignal + i) = 0;

        #pragma loop(no_vector)
        for (int j = 0; j < IMPULSE_RESPONSE_ARRAY_SIZE; j++)
        {
            if (i - j >= 0 && i - j < INPUT_SIGNAL_ARRAY_SIZE)
            {
                *(pOutputSignal + i) = *(pOutputSignal + i)  + *(pImpulseResponse + j) *  (*(pInputSignal + i - j));
            }
        }
    }
}
//#pragma optimize( "", on ) 

另一方面,我应该将函数与 SSE 一起使用。我尝试了以下代码:

void computeConvolutionOutputSSE(float* inputSignal, float* impulseResponse, float* outputSignal) {
    __m128* pInputSignal = (__m128*) inputSignal;
    __m128* pImpulseResponse = (__m128*) impulseResponse;
    __m128* pOutputSignal = (__m128*) outputSignal;


    int nOuterLoop = OUTPUT_SIGNAL_ARRAY_SIZE / 4;
    int nInnerLoop = IMPULSE_RESPONSE_ARRAY_SIZE / 4;
    int quarterOfInputSignal = INPUT_SIGNAL_ARRAY_SIZE / 4;

    __m128 m0 = _mm_set_ps1(0);

    for (int i = 0; i < nOuterLoop; i++)
    {
        *(pOutputSignal + i) = m0;
        for (int j = 0; j < nInnerLoop; j++)
        {
            if ((i - j) >= 0 && (i - j) < quarterOfInputSignal)
            {
                *(pOutputSignal + i) = _mm_add_ps(
                    *(pOutputSignal + i), 
                    _mm_mul_ps(*(pImpulseResponse + j), *(pInputSignal + i - j))
                );
            }
        }
    }
}

并且上面的函数工作不正确,并且产生的值与 CPU 不同。

该问题是在 stackoverflow 上指定的,并带有以下评论:

*(pInputSignal + i - j) 在 SSE 的情况下不正确,因为它不是远离当前值的 ij 偏移量,而是 (ij) * 4 。事情是,正如我所记得的那样,除非内在函数从那时起发生了变化,否则以这种方式使用指针的想法是不正确的——在我的时代,在这种情况下,必须将值“加载”到 __m128 的实例中,如 H(J) 和X(IJ) 位于未对齐的位置(和序列中断)。

由于您关心单个浮点数及其顺序,因此最好使用 const float* 和 _mm_loadu_ps 而不是仅仅取消引用(类似于 _mm_load_ps)。这样,您可以轻松地进行未对齐的加载,将您想要的浮点数放入您想要的向量元素位置,并且指针数学的工作方式与标量相同。您只需要考虑到 load(ptr) 实际上会为您提供来自 ptr+0..3 的元素向量。

但我无法使用此信息,因为在这种情况下不知道如何使用 SSE 正确访问数组。

4

1 回答 1

0

您需要 128 位 float32 值,而不是 msvc float。看_mm_broadcast_ss

于 2021-11-15T16:56:18.727 回答