Gcc 使用icc编译器时,答案不正确

Gcc 使用icc编译器时,答案不正确,gcc,clang,openmp,avx,icc,Gcc,Clang,Openmp,Avx,Icc,当我在mac上使用icc编译器时,我无法获得与其他编译器(如gcc、clang)相同的答案。 使用icc编译器,结果如下 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 预期的答案在这里 1.000000e+00 2.000000e+00 3.000000e+00 4.000000e+00 2.500000e+01 3.000000e+

当我在mac上使用icc编译器时,我无法获得与其他编译器(如gcc、clang)相同的答案。 使用icc编译器,结果如下

0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00
0.000000e+00
预期的答案在这里

1.000000e+00
2.000000e+00
3.000000e+00
4.000000e+00
2.500000e+01
3.000000e+01
3.500000e+01
4.000000e+01
我是这样编译的:

  • icc:
    icc test1.c-fopenmp-mavx-Wall
  • gcc:
    gcctest1.c-fopenmp-mavx-Wall
  • 叮当声:
    叮当声test1.c-fopenmp-mavx-Wall
我的代码如下:

#include "stdio.h"
#include "time.h"
#include "math.h"
#include "stdlib.h"
#include "omp.h"
#include "x86intrin.h"

void dd_m_dd(double *ahi, double *bhi, double *chi, int m, int n)
{

    int j;
    #pragma omp parallel
    {
        __m256d vahi,vbhi,vchi;
        #pragma omp for private(vahi,vbhi,vchi)
        for (j = 0; j < m*n; j+=4) {

            vbhi = _mm256_broadcast_sd(&bhi[j]);
            vahi = _mm256_load_pd(&ahi[j]);
            vchi = _mm256_load_pd(&chi[j]);

            vchi=vahi*vbhi;

            chi[j]=vchi[0];
            chi[j+1]=vchi[1];
            chi[j+2]=vchi[2];
            chi[j+3]=vchi[3];

        }
    }
}

int main(int argc, const char * argv[]){
    // Matrix Vector Product with DD

    // set variables
    int m;
    double* xhi;
    double* yhi;
    double* z;
    int i;

    m=(int)pow(2,3);
    // main program

    // set vector or matrix
    xhi=(double *)malloc(sizeof(double) * m*1);
    yhi=(double *)malloc(sizeof(double) * m*1);
    z=(double *)malloc(sizeof(double) * m*1);
    //preset
    for (i=0;i<m;i++) {
        xhi[i]=i+1;
        yhi[i]=i+1;
        z[i]=0;
    }

    dd_m_dd(xhi,yhi,z,m,1);

    for (i=0;i<m;i++) {
        printf("%e\n",z[i]);
    }

    free(xhi);
    free(yhi);
    free(z);
    return 0;
}
#包括“stdio.h”
#包括“time.h”
#包括“math.h”
#包括“stdlib.h”
#包括“omp.h”
#包括“x86intrin.h”
无效数据(双*ahi,双*bhi,双*chi,整数m,整数n)
{
int j;
#pragma-omp并行
{
__m256d vahi、vbhi、vchi;
#pragma omp专用(vahi、vbhi、vchi)
对于(j=0;j对于(i=0;i我不习惯于向量内部函数,但这看起来很可疑:

    chi[j]=vchi[0];
    chi[j+1]=vchi[1];
    chi[j+2]=vchi[2];
    chi[j+3]=vchi[3];
事实上,用看起来非常适合该作业的函数替换它,即
\u mm256\u store\u pd()
似乎可以解决问题

您的函数现在看起来可能是这样的(还有一些风格上的修正)


这里不再存储旧的cppcon视频,但我认为icc默认启用了
-ffast math
。我不知道这是否会对您的示例起作用,但可能值得测试。我建议使用
-march=native
,而不仅仅是
-mavx
,为您的目标机器进行调优,而不仅仅是在为gene进行调优时启用AVXric(尤其是gcc)。
vchi=\u mm256\u load\u pd(&chi[j]);
立即被
vchi=vahi*vbhi;
覆盖,这看起来是错误的;你是想用
+=
来添加而不是赋值吗?不妨这样做(vahi,vdhi
@Zboson是的,我在写我的答案时对此很好奇,但是因为我对这些东西很熟悉,我更喜欢使用OP的原始方法。现在,出于好奇,我尝试了
*
\u mm256\u mul\u pd()
的比较,结果发现编译器用这两种方法生成的代码完全相同(这并不让我感到惊讶,TBH)。现在哪一个更好,IDK…@Zboson:实现GNU C扩展的编译器定义了GNU C本机向量,所以
\uuu m256d vchi=vahi*vbhi;
被定义为垂直SIMD乘法(
vmulpd
)顺便说一句,Gilles:我们不知道chi是否对齐,所以应该使用
\u mm256\u storeu\u pd
。但是,GNU C本机向量扩展定义了
vchi[1]
语法来实现OP的期望。(不能保证它使用一个
vmovupd
完成4个元素的高效编译,但这并不能解释正确性问题。)re:哪一个更好?
*
运算符可读性更好,但除非您使用Agner Fog的VCL这样的包装库,否则无法移植到MSVC。它也会让您在整数向量方面遇到麻烦,因为这些向量是根据
long
定义的,所以您可以得到
paddq
或其他任何东西,不管它是否来自
set1_epi8
set1_epi64
。Agner Fog的VCL对于整数向量的不同元素宽度具有不同的类型,因此您可以在那里使用
v1+v2
v1*v2
。@PeterCordes,我个人尽可能尝试使用所有向量扩展或所有内部函数。在OP的情况下,只需要广播内部函数如果指针是32字节对齐的,则使用ICC(但不使用GCC或Clang)。
void dd_m_dd(double *ahi, double *bhi, double *chi, int m, int n) {

    #pragma omp parallel for
    for (int j = 0; j < m*n; j+=4) {

        __m256d vbhi = _mm256_broadcast_sd(&bhi[j]);
        __m256d vahi = _mm256_load_pd(&ahi[j]);

        __m256d vchi=vahi*vbhi;

        _mm256_store_pd( &chi[j], vchi );
    }
}
double *xhi=(double *)aligned_alloc(256, sizeof(double) * m*1);
double *yhi=(double *)aligned_alloc(256, sizeof(double) * m*1);
double *z=(double *)aligned_alloc(256, sizeof(double) * m*1);