C 为什么load_ps()可以在一台电脑上工作,而不能在另一台电脑上工作?

C 为什么load_ps()可以在一台电脑上工作,而不能在另一台电脑上工作?,c,x86,intel,simd,avx,C,X86,Intel,Simd,Avx,我编写了以下代码来缩放一组数字: #include <stdio.h> #include <stdlib.h> #include <math.h> #include "immintrin.h" void scale(struct problem_param prob_param, float* features) { int i,j,k; for (j = 0; j < prob_param.Nr_ft; j++)

我编写了以下代码来缩放一组数字:

 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
 #include "immintrin.h"

 void scale(struct problem_param prob_param, float* features)
 {
    int i,j,k;
    for (j = 0; j < prob_param.Nr_ft; j++)
    {
        __m256      range_vec ,low_up_vec , low_vec,tmp_vec;
        __m256      feat_min_vec, feat_vec;
        unsigned    count           = prob_param.Size;
        unsigned    offset          = j * prob_param.Size;
        float       feature_max     = features[offset];
        float       feature_min     = features[offset];
        /*
         * Look for min and max of each feature.
         */
        for ( i = 1; i < prob_param.Size ; i++)
        {
            if (features[i + offset] > feature_max )        feature_max = features[i + offset];

            if (features[i + offset] < feature_min )    feature_min = features[i + offset];
        }
        printf("feature : %u \t min = %f \t max = %f \n",j,feature_min,feature_max);
        /*
         * Set the range.
         * Set constant vectors for the vector instructions.
         */
        float       range   = feature_max - feature_min;
        feat_min_vec        = _mm256_set1_ps (feature_min);
        range_vec           = _mm256_set1_ps (range);
        low_up_vec          = _mm256_set1_ps (prob_param.upper_limit - prob_param.lower_limit);
        low_vec             = _mm256_set1_ps (prob_param.lower_limit);
        /*
         * Normalising
         * -----------
         * Head
         */
        for ( i = 0; i < prob_param.Size && count >= 7 ; i+=8)
        {
            feat_vec    = _mm256_load_ps(&features[i + offset]);
            tmp_vec     = _mm256_sub_ps(feat_vec,feat_min_vec);
            tmp_vec     = _mm256_mul_ps(tmp_vec,low_up_vec);
            tmp_vec     = _mm256_div_ps(tmp_vec,range_vec);
            feat_vec    = _mm256_add_ps(tmp_vec,low_vec);

            _mm256_store_ps (&features[i + offset], feat_vec);

            count -=8;
        }
        /*
         * Normalising
         * -----------
         * Tail
         */
        for ( k = i; k < prob_param.Size ; k++)
        {
            features[k + offset] = prob_param.lower_limit + (prob_param.upper_limit - prob_param.lower_limit) * (features[k + offset] - feature_min) / range;
        }
    }
#包括
#包括
#包括
#包括“immintrin.h”
空隙比例(结构问题参数问题参数、浮动*特征)
{
int i,j,k;
对于(j=0;j特征[U最大值)特征[U最大值=特征[i+偏移];
如果(特征[i+偏移]=7;i+=8)
{
feat_vec=_mm256_load_ps(&features[i+偏移量]);
tmp_vec=_mm256_sub_ps(功绩、功绩);
tmp_vec=_mm256_mul_ps(tmp_vec,low_up_vec);
tmp_vec=_mm256_div_ps(tmp_vec,range_vec);
功绩向量=_mm256_add_ps(tmp_vec,low_vec);
_mm256_-store_-ps(功能[i+偏移量]、专长向量和特征);
计数-=8;
}
/*
*正常化
* -----------
*尾巴
*/
对于(k=i;k
这是负责缩放的函数,我这样称呼它:

#include <stdio.h>
#include <stdlib.h>

#include "data.h" 
#include "common.h"

#define     training_size       3089
#define     number_features     4
#define     low                 -1.0
#define     up                  1.0
float* feature_array;

int main()
{
  struct problem_param pp;

  pp.Size           =       training_size;
  pp.Nr_ft          =       number_features;
  pp.lower_limit    =       low;
  pp.upper_limit    =       up;

posix_memalign((void **) &feature_array, 32, (size_t) training_size * number_features *sizeof(float));

scale(pp,feature_array);

return EXIT_SUCCESS;
}
#包括
#包括
#包括“data.h”
#包括“common.h”
#定义培训单元尺寸3089
#定义数字功能4
#定义低-1.0
#向上定义1.0
浮点*特征_数组;
int main()
{
结构问题_参数pp;
pp.尺寸=培训尺寸;
pp.Nr_ft=数量特征;
pp.下限=低;
pp.上限=上升;
posix_memalign((void**)和feature_数组,32,(size_t)training_size*number_features*sizeof(float));
比例(pp,特征_阵列);
返回退出成功;
}

我用我的MacBook Pro Core i5 Haswell测试了这段代码,它可以正常工作,但当我用ASUS Core I7 Haswell测试它时,它显示了加载的分段错误。我缺少什么吗?

偏移量的值(因此
I+偏移量
)并不总是8的倍数(在上面的示例中,它等于0、3089、6178、9267),因此您的加载和存储内部函数通常会发生错位

最简单的解决方案是用
\u mm256\u loadu\u ps
代替
\u mm256\u loadu\u ps
,用
\u mm256\u storeu\u ps
代替
\u mm256\u store\u ps

至于为什么在你的MacBook Pro上会出现这种情况,我的猜测是clang在背后生成了未对齐的加载/存储指令,从而隐藏了问题,直到你尝试在使用不同编译器的系统上运行代码

更新:我刚刚通过编译和分解生成的代码(在Haswell MacBook Pro上,macOS 10.13.4和Xcode 9.3.1)验证了上述假设:


请注意,使用
vmovups
而不是
vmovaps
时,
offset
(因此
i+offset
)的值并不总是8的倍数(在上面的示例中,它等于0、3089、6178、9267),因此加载和存储内部函数通常会不对齐

最简单的解决方案是用
\u mm256\u loadu\u ps
代替
\u mm256\u loadu\u ps
,用
\u mm256\u storeu\u ps
代替
\u mm256\u store\u ps

至于为什么在你的MacBook Pro上会出现这种情况,我的猜测是clang在背后生成了未对齐的加载/存储指令,从而隐藏了问题,直到你尝试在使用不同编译器的系统上运行代码

更新:我刚刚通过编译和分解生成的代码(在Haswell MacBook Pro上,macOS 10.13.4和Xcode 9.3.1)验证了上述假设:


注意使用
vmovups
而不是
vmovaps

注意,将
float**
强制转换为
void**
是不合适的。相反,您确实应该使用一个临时
void*
变量。我猜您可能在某个地方有一个与
load\ps
相关的UB URE…注意,强制转换
是不合适的e> float**
void**
。相反,你真的应该使用一个临时
void*
变量。我猜你在某个地方有一个与
加载相关的UBURE。。。
>>> vmovups (%r14,%r13,4), %ymm0
    vsubps  192(%rsp), %ymm0, %ymm0 ## 32-byte Folded Reload
    vmulps  448(%rsp), %ymm0, %ymm0 ## 32-byte Folded Reload
    vdivps  384(%rsp), %ymm0, %ymm0 ## 32-byte Folded Reload
    vaddps  416(%rsp), %ymm0, %ymm0 ## 32-byte Folded Reload
>>> vmovups %ymm0, (%r14,%r13,4)