我是指令优化的新手.
我对一个简单的函数dotp进行了简单的分析,该函数用于获取两个浮点数组的点积.
C代码如下:
float dotp(
const float x[],
const float y[],
const short n
)
{
short i;
float suma;
suma = 0.0f;
for(i=0; i<n; i++)
{
suma += x[i] * y[i];
}
return suma;
}
Run Code Online (Sandbox Code Playgroud)
我用昂纳雾在网络上提供的测试框架testp.
在这种情况下使用的数组是对齐的:
int n = 2048;
float* z2 = (float*)_mm_malloc(sizeof(float)*n, 64);
char *mem = (char*)_mm_malloc(1<<18,4096);
char *a = mem;
char *b = a+n*sizeof(float);
char *c = b+n*sizeof(float);
float *x = (float*)a;
float *y = (float*)b;
float *z = (float*)c;
Run Code Online (Sandbox Code Playgroud)
然后我调用函数dotp,n = 2048,repeat …
gcc 5.3 with -O3 -mavx -mtune=haswellfor x86-64使得代码处理可能错位的代码变得非常笨重,例如:
// convenient simple example of compiler input
// I'm not actually interested in this for any real program
void floatmul(float *a) {
for (int i=0; i<1024 ; i++)
a[i] *= 2;
}
Run Code Online (Sandbox Code Playgroud)
clang使用未对齐的加载/存储指令,但是gcc执行标量intro/outro和对齐的向量循环:它剥离了第一个最多7个未对齐的迭代,将其完全展开为一个序列
vmovss xmm0, DWORD PTR [rdi]
vaddss xmm0, xmm0, xmm0 ; multiply by two
vmovss DWORD PTR [rdi], xmm0
cmp eax, 1
je .L13
vmovss xmm0, DWORD PTR [rdi+4]
vaddss xmm0, xmm0, xmm0
vmovss …Run Code Online (Sandbox Code Playgroud) 我手动矢量化循环并一次处理4个项目.项目总数可能不是4的倍数,所以我在主循环结束时留下了一些项目.我认为如果计数大于4并且重做某些项目是安全的,我可以使用相同的主矢量化循环执行剩余项目.例如,如果我需要处理10个项目,我可以在三次迭代中处理0123,4567,6789.我找不到任何对这种技术的引用.它是愚蠢但我不明白怎么样?
#include <stdint.h>
#include <stddef.h>
void inc(int32_t const* __restrict in, int32_t* out, size_t count)
{
if (count < 4)
{
for (size_t i = 0; i < count; ++i)
out[i] = in[i] + 42;
}
else
{
typedef int32_t v4i __attribute__ ((vector_size (16), aligned(4)));
for (size_t i = 0;;)
{
for (; i + 4 <= count; i += 4)
{
(v4i&)out[i] = (v4i&)in[i] + 42;
}
if (i == count)
break;
i = count - 4;
}
}
}
Run Code Online (Sandbox Code Playgroud)