如何使用SSE Intrinsic减去同一数组的两个不同部分?

如何使用SSE Intrinsic减去同一数组的两个不同部分?,c,arrays,gcc,optimization,sse,C,Arrays,Gcc,Optimization,Sse,我有一个循环,里面有另一个循环,通过数组进行计算。我想使用SSE优化代码,但是有多个部分让我困惑,其中最大的部分在问题标题中说明 原代码: for (int j = 0; j < N; j++) { for (int i = 0; i < N; i++) { float kx = a[j] - a[i]; float ky = b[j] - b[i]; float kz = c[j] - c[i]; float

我有一个循环,里面有另一个循环,通过数组进行计算。我想使用SSE优化代码,但是有多个部分让我困惑,其中最大的部分在问题标题中说明

原代码:

for (int j = 0; j < N; j++) {
    for (int i = 0; i < N; i++) {
        float kx = a[j] - a[i];
        float ky = b[j] - b[i];
        float kz = c[j] - c[i];
        float k2 = kx*kx + ky*ky + kz*kz + eps;
        float k2inv = 1.0f / sqrt(k2);
        float k6inv = k2inv * k2inv * k2inv;
        float s = m[j] * k6inv;
        ax[i] += s * kx;
        ay[i] += s * ky;
        az[i] += s * kz;    
    }
}
for(int j=0;j
如何将此代码转换为SSE指令?我想到的代码如下,但当我意识到我需要减去同一数组的两部分后,我完全被难倒了:

我的尝试:

float *x = malloc(sizeof(float) * N);
float *y = malloc(sizeof(float) * N);
float *z = malloc(sizeof(float) * N); 

for (int j = 0; j < N; j++) {
    for (int i = 0; i < N; i++) {
        __m128 rxj = _mm_load_ps(x+j);
        __m128 rxi = _mm_load_ps(x+i);
        __m128 ry = _mm_load_ps(y+j);
        __m128 ry = _mm_load_ps(y+i);
        __m128 rz = _mm_load_ps(z+j);
        __m128 rz = _mm_load_ps(z+i);
    }
}
float*x=malloc(sizeof(float)*N);
浮点数*y=malloc(sizeof(float)*N);
float*z=malloc(sizeof(float)*N);
对于(int j=0;j
我认为您不需要任何新的数组来矢量化。应用
restrict
关键字(并将
sqrt
更改为
sqrtf
)后,您的原始源代码(但不是gcc 5.3)。您可能只需要使用OpenMP pragma或其他工具来启用i或j上的自动矢量化

// auto-vectorizes with clang and icc, but not gcc :/
void ffunc(float *restrict ax, float *restrict ay, float *restrict az,
           const float *a, const float *b, const float *c,
           int N, float eps, const float *restrict m)
{
  for (int j = 0; j < N; j++) {
    for (int i = 0; i < N; i++) {
        float kx = a[j] - a[i];
        float ky = b[j] - b[i];
        float kz = c[j] - c[i];
        float k2 = kx*kx + ky*ky + kz*kz + eps;
#if 1   // better code when rsqrtps is used (with a refinement step)
        float k2inv = 1.0f / sqrtf(k2);
        float k6inv = k2inv * k2inv * k2inv;
        float s = m[j] * k6inv;
#else   // maybe better code when rcpps isn't used
        float k2sqrt = sqrtf(k2);
        float k6sqrt = k2sqrt * k2sqrt * k2sqrt;
        float s = m[j] / k6sqrt;
#endif
        ax[i] += s * kx;
        ay[i] += s * ky;
        az[i] += s * kz;    
    }
  }
}

做相同数量的除法(1),但少一次乘法。

我认为不需要任何新的数组来矢量化。应用
restrict
关键字(并将
sqrt
更改为
sqrtf
)后,您的原始源代码(但不是gcc 5.3)。您可能只需要使用OpenMP pragma或其他工具来启用i或j上的自动矢量化

// auto-vectorizes with clang and icc, but not gcc :/
void ffunc(float *restrict ax, float *restrict ay, float *restrict az,
           const float *a, const float *b, const float *c,
           int N, float eps, const float *restrict m)
{
  for (int j = 0; j < N; j++) {
    for (int i = 0; i < N; i++) {
        float kx = a[j] - a[i];
        float ky = b[j] - b[i];
        float kz = c[j] - c[i];
        float k2 = kx*kx + ky*ky + kz*kz + eps;
#if 1   // better code when rsqrtps is used (with a refinement step)
        float k2inv = 1.0f / sqrtf(k2);
        float k6inv = k2inv * k2inv * k2inv;
        float s = m[j] * k6inv;
#else   // maybe better code when rcpps isn't used
        float k2sqrt = sqrtf(k2);
        float k6sqrt = k2sqrt * k2sqrt * k2sqrt;
        float s = m[j] / k6sqrt;
#endif
        ax[i] += s * kx;
        ay[i] += s * ky;
        az[i] += s * kz;    
    }
  }
}

做相同数量的除法(一),但少一次乘法。

未来读者:请参阅了解后续。未来读者:请参阅了解后续。Gcc确实使用--param vect max version for alias checks=20进行矢量化,但不确定结果有多好。@MarcGlisse:内部循环看起来与clang类似,但是有大量的介绍/介绍。clang通常只使用未对齐的加载/存储,因此当输入恰好在运行时对齐时,代码将全速运行。gcc的策略只有在未对齐的输入实际上很常见且问题规模很大的情况下才是最优的。现代x86 CPU在硬件中具有足够快的未对齐支持。(由于Nehalem,
movups
在对齐数据上使用时与
movaps
一样快。)Gcc确实使用--param vect max version for alias checks=20进行矢量化,但不确定结果有多好。@marglisse:内部循环看起来与clang类似,但有大量的导入/导出。clang通常只使用未对齐的加载/存储,因此当输入恰好在运行时对齐时,代码将全速运行。gcc的策略只有在未对齐的输入实际上很常见且问题规模很大的情况下才是最优的。现代x86 CPU在硬件中具有足够快的未对齐支持。(自从Nehalem以来,
movups
在对齐数据上使用时与
movaps
一样快。)