你有一个三(或四)个浮点数的向量.总结它们的最快方法是什么?
SSE(movaps,shuffle,add,movd)总是比x87快吗?SSE4.2中的水平加法说明值得吗?移动到FPU的成本是多少,然后是faddp,faddp?什么是最快的特定指令序列?
"尝试安排事情,这样你可以一次总结四个向量"将不被接受作为答案.:-)
我有一个大型(> 250个文件)库的源,它大量使用STL容器和字符串.我需要在有限堆的嵌入式环境中运行它,所以我想确保这个库本身在其堆使用方面受到限制.
显而易见的解决方案是创建一个分配器,但是修改整个代码库以包含分配器模板参数是最后的一项重要工作,如果我想要使用新版本的源,这是不可取的.全局替换new和delete是不可行的,因为这会影响整个图像,而不仅仅是这个库.
我的下一个想法是一个愚蠢的C宏技巧,但这似乎不太可能,虽然我承认不是一个聪明的宏作者.
所以我认为"在编译时是否有编译器或编译指示开关来指定allocator <>类"?但我对任何事情都持开放态度.
我要问的下一个问题是,如果有人能提出解决方案,那么如何在包含该库的文件集中对新/删除做同样的事情.
我正在使用gcc 3.4.4工具链在Cygwin下运行它,目标是VxWorks,如果这引发了任何想法.
Arstechnia最近有一篇文章为什么一些编程语言比其他语言更快.它比较了Fortran和C,并提到了求和数组.在Fortran中,假设数组不重叠,从而允许进一步优化.在C/C++中,指向相同类型的指针可能会重叠,因此通常不能使用此优化.但是,在C/C++中,可以使用restrictor __restrict关键字告诉编译器不要假设指针重叠.所以我开始研究自动矢量化.
以下代码在GCC和MSVC中进行矢量化
void dot_int(int *a, int *b, int *c, int n) {
for(int i=0; i<n; i++) {
c[i] = a[i] + b[i];
}
}
Run Code Online (Sandbox Code Playgroud)
我使用和不使用重叠数组测试了它,它得到了正确的结果.但是,我使用SSE手动向量化循环的方式不能处理重叠数组.
int i=0;
for(; i<n-3; i+=4) {
__m128i a4 = _mm_loadu_si128((__m128i*)&a[i]);
__m128i b4 = _mm_loadu_si128((__m128i*)&b[i]);
__m128i c4 = _mm_add_epi32(a4,b4);
_mm_storeu_si128((__m128i*)c, c4);
}
for(; i<n; i++) {
c[i] = a[i] + b[i];
}
Run Code Online (Sandbox Code Playgroud)
接下来我尝试使用__restrict.我假设由于编译器可以假设数组不重叠,它不会处理重叠数组,但GCC和MSVC仍然可以获得重叠数组的正确结果,即使是__restrict.
void dot_int_restrict(int * __restrict a, int * __restrict b, int * __restrict c, …Run Code Online (Sandbox Code Playgroud) 我正在尝试将我的代码设置为自动向量化,但它无法正常工作.
int _tmain(int argc, _TCHAR* argv[])
{
const int N = 4096;
float x[N];
float y[N];
float sum = 0;
//create random values for x and y
for (int i = 0; i < N; i++)
{
x[i] = rand() >> 1;
y[i] = rand() >> 1;
}
for (int i = 0; i < N; i++){
sum += x[i] * y[i];
}
}
Run Code Online (Sandbox Code Playgroud)
这里没有循环矢量化,但我真的只对第二个循环感兴趣.
我正在使用visual studio express 2013并且正在编译/O2和/Qvec-report:2(报告循环是否被矢量化)选项.编译时,我收到以下消息:
--- Analyzing function: main
c:\users\...\documents\visual studio 2013\projects\intrin3\intrin3\intrin3.cpp(28) …Run Code Online (Sandbox Code Playgroud) 对于以下循环,如果我告诉它使用关联数学,例如,GCC将仅对循环进行矢量化-Ofast.
float sumf(float *x)
{
x = (float*)__builtin_assume_aligned(x, 64);
float sum = 0;
for(int i=0; i<2048; i++) sum += x[i];
return sum;
}
Run Code Online (Sandbox Code Playgroud)
这是装配 -Ofast -mavx
sumf(float*):
vxorps %xmm0, %xmm0, %xmm0
leaq 8192(%rdi), %rax
.L2:
vaddps (%rdi), %ymm0, %ymm0
addq $32, %rdi
cmpq %rdi, %rax
jne .L2
vhaddps %ymm0, %ymm0, %ymm0
vhaddps %ymm0, %ymm0, %ymm1
vperm2f128 $1, %ymm1, %ymm1, %ymm0
vaddps %ymm1, %ymm0, %ymm0
vzeroupper
ret
Run Code Online (Sandbox Code Playgroud)
这清楚地表明循环已被矢量化.
但是这个循环也有一个依赖链.为了克服添加的延迟,我需要在x86_64上展开并执行至少三次部分和(不包括Skylake,需要展开八次并使用需要在Haswell和Broadwell上展开10次的FMA指令进行添加) .据我所知,我可以展开循环-funroll-loops.
这是装配-Ofast -mavx -funroll-loops.
sumf(float*):
vxorps …Run Code Online (Sandbox Code Playgroud) 我正在寻找一种最佳方法来计算 a __m256ior中所有打包的 32 位整数的总和__m512i。为了计算n 个元素的总和,我经常使用log2(n) vpaddd和vpermd函数,然后提取最终结果。但是,这不是我认为的最佳选择。
编辑:在速度/周期减少方面最佳/最佳。