我使用英特尔®架构代码分析器(IACA)发现了一些意想不到的东西(对我而言).
以下指令使用[base+index]寻址
addps xmm1, xmmword ptr [rsi+rax*1]
Run Code Online (Sandbox Code Playgroud)
根据IACA没有微熔丝.但是,如果我用[base+offset]这样的
addps xmm1, xmmword ptr [rsi]
Run Code Online (Sandbox Code Playgroud)
IACA报告它确实融合了.
英特尔优化参考手册的第2-11节给出了以下"可以由所有解码器处理的微融合微操作"的示例
FADD DOUBLE PTR [RDI + RSI*8]
Run Code Online (Sandbox Code Playgroud)
和Agner Fog的优化装配手册也给出了使用[base+index]寻址的微操作融合的例子.例如,请参见第12.2节"Core2上的相同示例".那么正确的答案是什么?
我总是听说未对齐的访问很糟糕,因为它们会导致运行时错误并导致程序崩溃或减慢内存访问速度.但是我找不到任何关于它们会减慢速度的实际数据.
假设我在x86上并且有一些(但未知)未对齐访问的共享 - 实际可能的最差减速是什么?如何在不消除所有未对齐访问和比较两个版本代码的运行时间的情况下估算它?
考虑以下代码:
void foo(int* __restrict__ a)
{
int i; int val = 0;
for (i = 0; i < 100; i++) {
val = 2 * i;
a[i] = val;
}
}
Run Code Online (Sandbox Code Playgroud)
这符合(具有最大优化但没有展开或矢量化)...
海湾合作委员会 7.2:
foo(int*):
xor eax, eax
.L2:
mov DWORD PTR [rdi], eax
add eax, 2
add rdi, 4
cmp eax, 200
jne .L2
rep ret
Run Code Online (Sandbox Code Playgroud)
铿锵5.0:
foo(int*): # @foo(int*)
xor eax, eax
.LBB0_1: # =>This Inner Loop Header: Depth=1
mov dword ptr [rdi + 2*rax], eax …Run Code Online (Sandbox Code Playgroud) 旨在提供高性能数字运算的 CPU 最终会采用某种向量指令集。基本上有两种:
SIMD。这在概念上很简单,例如,您不仅拥有一组 64 位寄存器及其上的操作,还拥有第二组 128 位寄存器,并且可以同时对两个 64 位值的短向量进行操作。它在实现中变得复杂,因为您还希望可以选择对四个 32 位值进行操作,然后新一代 CPU 提供 256 位向量,这需要一套全新的指令等。
较旧的 Cray 风格向量指令,其中向量一开始很大,例如 4096 位,但同时操作的元素数量是透明的,并且要在给定操作中使用的元素数量是指令参数。这个想法是,你预先减少一点复杂性,以避免以后出现复杂性。
有人认为选项 2 更好,并且这些论点似乎有道理,例如https://www.sigarch.org/simd-instructions-considered-harmful/
至少乍一看,选项 2 似乎可以完成选项 1 可以做的所有事情,而且更容易,而且总体上更好。
是否存在相反情况的工作负载?SIMD 指令在哪里可以完成 Cray 式向量无法完成的任务,或者可以更快或使用更少的代码完成任务?
我想探索 gcc (10.3) 的自动矢量化。我有以下简短的程序(请参阅https://godbolt.org/z/5v9a53aj6),它计算向量所有元素的总和:
#include <stdio.h>
#define LEN 1024
// -ffast-math -march=tigerlake -O3 -fno-unroll-loops
int
main()
{
float v[LEN] __attribute__ ((aligned(64)));
float s = 0;
for (unsigned int i = 0; i < LEN; i++) s += v[i];
printf("%g\n", s);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我用选项编译-ffast-math -march=tigerlake -O3 -fno-unroll-loops。由于 Tigerlake 处理器具有 avx512,我希望 gcc 自动向量化使用 zmm 寄存器,但它实际上在最内层循环中使用 ymm 寄存器(avx/avx2):
vaddps ymm0, ymm0, YMMWORD PTR [rax]
Run Code Online (Sandbox Code Playgroud)
如果我替换-march=tigerlake为-mavx512f,则使用 zmm 寄存器:
vaddps zmm0, zmm0, ZMMWORD PTR [rax]
Run Code Online (Sandbox Code Playgroud)
如果我只是指定,为什么不使用 …
我有以下Java代码(所有数组在我们调用“arrays”之前都已初始化,并且所有数组的大小均为“arraySize”)
int arraySize = 64;
float[] a;
float[] b;
float[] result;
public void arrays() {
for (int i = 0; i < arraySize; i++) {
result[i] = ((a[i] * b[i] + b[i] - b[i]) / b[i]) +
a[i] + a[i] + a[i] + a[i];
}
}
Run Code Online (Sandbox Code Playgroud)
JIT 的输出是:
# {method} {0x00000001034751a8} 'arrays' '()V' in 'main/ComplexExpression'
# [sp+0x30] (sp of caller)
[Entry Point]
0x000000010c4c55a0: mov 0x8(%rsi),%r10d
0x000000010c4c55a4: movabs $0x800000000,%r11
0x000000010c4c55ae: add %r11,%r10
0x000000010c4c55b1: cmp %r10,%rax
0x000000010c4c55b4: jne 0x000000010c44b780 ; {runtime_call ic_miss_stub} …Run Code Online (Sandbox Code Playgroud)