学习使用内在函数——使用 _mm256_sub_ps 的段错误

learning to use intrinsics -- segm fault using _mm256_sub_ps

我正在尝试学习如何使用内部函数。 所以,我的 C 代码是:

void Vor(

    const int NbPoints,
    const int height,
    const int width,
    float * X,
    float * Y,
    int   * V,
    int   * const ouVor )
{

    float Xd , Yd;
    float Distance ,initDistance = FLT_MAX;
    int Threshold;

    int x , y; // pixel coordinates
    int i;

    for ( y = 0; y < height; y++ )
    {
        for ( x = 0; x < width; x++ )
        {
            for ( i = 0; i < NbPoints; i++ )
            {
                Xd = X[ i ] - x;
                Yd = Y[ i ] - y;
                Distance = Xd * Xd + Yd * Yd;

                //if this Point is closer , assign proper threshold
                if ( Distance < initDistance )
                {
                    initDistance = Distance;
                    Threshold = V[ i ];
                }

                *( ouVor + ( x + y * width ) ) = Threshold;

            } /* i */
        } /* x */

    } /* y */


}

现在,使用 openMP 和内在函数。我在做:

void Vor(

    const  int  NbOfPoints,
    const  int  height,
    const  int  width,
    float * restrict X,
    float * restrict Y,
    int   * restrict V,
    int   * restrict ouVor )
{


    __m128 Xd , Yd;

    __m128i Threshold;
    int x , y; // pixel coordinates
    float initDistance = FLT_MAX;

    float * TempDistance = (float*) _mm_malloc( NbOfPoints * sizeof(*TempDistance) ,64 );

    __m128 * SIMDTempDistance = (__m128*) TempDistance;
    __m128 * theX = (__m128*) X;
    __m128 * theY = (__m128*) Y;
    __m128i * theV = (__m128i*) V;
    __m128i * theVor = (__m128i*) ouVor;


        #pragma omp parallel for default( none ) shared( X , Y , V , ouVor ,height , width ,NbOfPoints ) private ( x,y,Xd,Yd,TempDistance ,Threshold ) collapse(2)  
    for ( y = 0; y < height; y++ )
    { 
        for ( x = 0; x < width; x++ )
        {

            __m128 Distance = _mm_load_ps( &initDistance );

            for ( int i = 0; i < NbOfPoints; i++ )
            {
                Xd = _m128_sub_ps( theX[ i ] , x );
                Yd = _m128_sub_ps( theY[ i ] , y );
                SIMDTempDistance[ i ] = _m128_add_ps( Xd * Xd , Yd * Yd );

                __m128 theMin = _m128_gmin_ps( SIMDTempDistance , &Distance );

                Distance = theMin;
                Threshold = theV[ i ];

                } /* i */

                //write result
                *( ouVor + x + y * width ) = Threshold;

            } /* x */

        } /* y */


    _mm_free( TempDistance );

}

我收到一些错误,例如:

function "_m128_sub_ps" declared implicitly
Xd = _m128_sub_ps( theX[ i ] , x );

error: a value of type "int" cannot be assigned to an entity of type "__m128"
Xd = _m128_sub_ps( theX[ i ] , x );

a value of type "__m128i" cannot be assigned to an entity of type "int"
*( ouVor + x + y * width ) = Threshold

(Yd、theMin、SIMDTempDistance 的错误相同)

我该如何克服这些问题?

此外,我删除了 if 语句并使用 _m128_gmin_ps 找到最小值 value.Is 我的实现是否正确?

----------------更新----------------

在 Sourav Ghosh 发表评论后,我搜索了 headers。 我找不到 128 位的任何地方,所以我使用 #include <immintrin.h>

使用 256 位

将几行更正为:

__m256 Distance = _mm256_load_ps( &intiDistance );

__m256 theMin = _mm256_min_ps( SIMDTempDistance[ i ] , &Distance );

以及对 _mm256 而不是 _m256 的所有函数调用,我只收到这些错误:

error: argument of type "int" is incompatible with parameter of type "__m256"
Xd = _mm256_sub_ps( theX[ i ] , x );
Yd = _mm256_sub_ps( theY[ i ] , y );

x 和 y 是整数并在循环中使用。我不知道如何克服这个问题。

-----更新---------------------

我想通了!我在选角.. 我用过:

__m256i xxIdx = _mm256_set1_epi32( x );
__m256  xIdx  = _mm256_castsi256_ps( xxIdx );

现在,我的代码是:

void Vor(

        const  int  NbOfPoints,
        const  int  height,
        const  int  width,
        float * restrict X,
        float * restrict Y,
        int   * restrict V,
        int   * restrict ouVor )
    {



       __m256 Xd , Yd;

       __m256i Threshold;
        int x , y; // pixel coordinates


        float * TempDistance = (float*) _mm_malloc( NbOfPoints * sizeof(*TempDistance) ,64 );

        __m256 * SIMDTempDistance = (__m256*) TempDistance;
        __m256 * theX = (__m256*) X;
        __m256 * theY = (__m256*) Y;
        __m256i * theV = (__m256i*) V;
        __m256i * theVor = (__m256i*) ouVor;


    #pragma omp parallel for default( none ) shared( X , Y , V , ouVor ,height , width ,NbOfPoints ,ouVor ,theX,theY,theV ) private ( x,y,Xd,Yd,TempDistance ,Threshold,SIMDTempDistance ) collapse(2)  

    for ( y = 0; y < height; y++ )
    { 
        for ( x = 0; x < width; x++ )
        {
                float initDistance = FLT_MAX;
                __m256 Distance = _mm256_set1_ps( initDistance );

                for ( int i = 0; i < NbOfPoints; i++ )
                {
                    __m256i xxIdx = _mm256_set1_epi32( x );
                    __m256  xIdx  = _mm256_castsi256_ps( xxIdx );

                    __m256i yyIdx = _mm256_set1_epi32( y );
                    __m256  yIdx  = _mm256_castsi256_ps( yyIdx );

                    Xd = _m256_sub_ps( theX[ i ] , xIdx );
                    Yd = _m256_sub_ps( theY[ i ] , yIdx );
                    SIMDTempDistance[ i ] = _m256_add_ps( Xd * Xd , Yd * Yd );

                    __m256 theMin = _m256_gmin_ps( SIMDTempDistance , Distance );

                    Distance = theMin;
                    Threshold = theV[ i ];

                    } /* i */

                    //write result
                    *( ouVor + x + y * width ) = Threshold;

                } /* x */

            } /* y */


        _mm_free( TempDistance );

    }

我这样编译:

icc -std=c99 -g -openmp -qopt-report=2 -o mycode mycode.c

没关系。

BUt 运行 代码给出了分段错误..

行内:

Xd = _m256_sub_ps( theX[ i ] , xIdx );
Yd = _m256_sub_ps( theY[ i ] , yIdx );

我认为,您缺少一些包含 _m128_sub_ps() 函数前向声明的必需头文件。我们可以假设实际上 _m128_sub_ps() 函数具有 return 类型的 __m128,但是如果没有适当的前向声明,编译器会假设 default return 为 _m128_sub_ps() 函数键入 int。这就是为什么编译器发出

function "_m128_sub_ps" declared implicitly

然后,int return 值被分配给类型为 __m128 的变量,造成了问题。


编辑:

根据更改后的代码,

int x , y; // pixel coordinates

应该是

__m256 x , y; // pixel coordinates

因为 signature of _mm256_sub_ps() 要求两个参数都是 __m256

类型

您对内在名称有点困惑。

对于 128 位 SSE,它只是,例如:

_mm_sub_ps

不是:

_mm128_sub_ps

[混淆可能是因为 256 位 AVX 是 _mm256_sub_ps。]

嗯,我用过:

__m256 LX = _mm256_load_ps( &X[ i ] );
__m256 LY = _mm256_load_ps( &Y[ i ] );

而不是:

Xd = _m256_sub_ps( theX[ i ] , xIdx );
Yd = _m256_sub_ps( theY[ i ] , yIdx );

没关系!