TL; DR:为什么包装System.Numerics.Vectors类型很昂贵,有什么我可以做的吗?
考虑以下代码:
[MethodImpl(MethodImplOptions.NoInlining)]
private static long GetIt(long a, long b)
{
var x = AddThem(a, b);
return x;
}
private static long AddThem(long a, long b)
{
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
这将JIT转换为(x64):
00007FFDA3F94500 lea rax,[rcx+rdx]
00007FFDA3F94504 ret
Run Code Online (Sandbox Code Playgroud)
和x86:
00EB2E20 push ebp
00EB2E21 mov ebp,esp
00EB2E23 mov eax,dword ptr [ebp+10h]
00EB2E26 mov edx,dword ptr [ebp+14h]
00EB2E29 add eax,dword ptr [ebp+8]
00EB2E2C adc edx,dword ptr [ebp+0Ch]
00EB2E2F pop ebp
00EB2E30 ret 10h
Run Code Online (Sandbox Code Playgroud)
现在,如果我将它包装在一个结构中,例如
public struct SomeWrapper
{
public long …Run Code Online (Sandbox Code Playgroud) 我想尝试使用SIMD指令编写atoi实现,包含在RapidJSON(C++ JSON 读 /写库)中.它目前在其他地方有一些SSE2和SSE4.2优化.
如果是速度增益,atoi则可以并行执行多个结果.字符串最初来自JSON数据的缓冲区,因此多atoi函数将不得不进行任何所需的调配.
我想出的算法如下:
我的目标是x86和x86-64架构.
我知道AVX2支持三个操作数Fused Multiply-Add,所以我将能够执行Sum = Number*有效数字+和.
那是我到目前为止的地方.
我的算法是否正确?有没有更好的办法?
是否有使用任何SIMD指令集的atoi参考实现?
我正在寻找优化这种线性搜索:
static int
linear (const int *arr, int n, int key)
{
int i = 0;
while (i < n) {
if (arr [i] >= key)
break;
++i;
}
return i;
}
Run Code Online (Sandbox Code Playgroud)
数组已排序,函数应返回大于或等于键的第一个元素的索引.它们的数组不大(低于200个元素),并且会为大量搜索准备一次.如果需要,可以在第n个之后将数组元素初始化为适当的数组,如果这样可以加快搜索速度.
不,不允许二进制搜索,只能进行线性搜索.
关于这一点已经存在一个问题,但它被关闭为"含糊不清",所以我开了一个新的 - 我找到了答案,也许它也会帮助其他人.
问题是:如何编写汇编代码序列来初始化具有128位立即(常量)值的XMM寄存器?
英特尔高级矢量扩展指令集(AVX)在256位版本(YMM寄存器)中不提供双精度浮点变量的点积."为什么?" 问题已在另一个论坛(此处)和Stack Overflow(此处)进行了简要处理.但我面临的问题是如何以有效的方式用其他AVX指令替换这条缺失的指令?
对于单精度浮点变量,存在256位版本的点积(此处参考):
__m256 _mm256_dp_ps(__m256 m1, __m256 m2, const int mask);
Run Code Online (Sandbox Code Playgroud)
我们的想法是找到这个缺失指令的有效等价物:
__m256d _mm256_dp_pd(__m256d m1, __m256d m2, const int mask);
Run Code Online (Sandbox Code Playgroud)
更具体地说,我想从__m128(四个浮点数)转换为__m256d(4个双精度数)的代码使用以下指令:
__m128 val0 = ...; // Four float values
__m128 val1 = ...; //
__m128 val2 = ...; //
__m128 val3 = ...; //
__m128 val4 = ...; //
__m128 res = _mm_or_ps( _mm_dp_ps(val1, val0, 0xF1),
_mm_or_ps( _mm_dp_ps(val2, val0, 0xF2),
_mm_or_ps( _mm_dp_ps(val3, val0, 0xF4),
_mm_dp_ps(val4, …Run Code Online (Sandbox Code Playgroud) GPU使用SIMD范例,即,相同的代码部分将并行执行,并应用于数据集的各种元素.
但是,CPU也使用SIMD,并提供指令级并行.例如,据我所知,类似SSE的指令将处理具有并行性的数据元素.
虽然SIMD范例似乎在GPU和CPU中的使用方式不同,但GPU的SIMD功率是否比CPU更多?
在哪种方式中,CPU中的并行计算能力比GPU中的并行计算能力"弱"?
谢谢
"最佳"意味着最少的指令(或最少的uops,如果任何指令解码到多个uop).机器码大小(以字节为单位)是相同insn计数的平局.
恒定生成本质上是一个新的依赖链的开始,所以延迟很重要.在循环内生成常量也很不寻常,因此吞吐量和执行端口需求也几乎无关紧要.
生成常量而不是加载它们需要更多指令(除了全零或全一),因此它会占用宝贵的uop-cache空间.这可能是比数据缓存更有限的资源.
Agner Fog优秀的优化装配指南涵盖了这一点Section 13.4.表13.10具有用于产生向量序列,每一个元素是0,1,2,3,4,-1,或-2,与从8位到64位单元大小.表13.11具有用于产生一些浮点值序列(0.0,0.5,1.0,1.5,2.0,-2.0,和位掩码为符号位.)
Agner Fog的序列仅使用SSE2,无论是设计还是因为它尚未更新一段时间.
使用短的非显而易见的指令序列可以生成哪些其他常量? (具有不同移位计数的进一步扩展是显而易见的而不是"有趣的".)是否有更好的序列用于生成Agner Fog列出的常量?
如何将128位immediates移动到XMM寄存器说明了将任意128b常量放入指令流的一些方法,但这通常是不合理的(它不会节省任何空间,并占用大量的uop-cache空间.)
以下是GCC 6和7在使用时无法优化的一些代码std::array:
#include <array>
static constexpr size_t my_elements = 8;
class Foo
{
public:
#ifdef C_ARRAY
typedef double Vec[my_elements] alignas(32);
#else
typedef std::array<double, my_elements> Vec alignas(32);
#endif
void fun1(const Vec&);
Vec v1{{}};
};
void Foo::fun1(const Vec& __restrict__ v2)
{
for (unsigned i = 0; i < my_elements; ++i)
{
v1[i] += v2[i];
}
}
Run Code Online (Sandbox Code Playgroud)
编译上面的g++ -std=c++14 -O3 -march=haswell -S -DC_ARRAY代码会产生很好的代码:
vmovapd ymm0, YMMWORD PTR [rdi]
vaddpd ymm0, ymm0, YMMWORD PTR [rsi]
vmovapd YMMWORD PTR [rdi], ymm0 …Run Code Online (Sandbox Code Playgroud) 以下代码生成的程序集在使用-O3. 为了完整起见,代码始终在 GCC 13.2 中执行 SIMD,而从不在 clang 17.0.1 中执行 SIMD。
#include <array>
__attribute__((noinline)) void fn(std::array<int, 4>& lhs, const std::array<int, 4>& rhs)
{
for (std::size_t idx = 0; idx != 4; ++idx) {
lhs[idx] = lhs[idx] + rhs[idx];
}
}
Run Code Online (Sandbox Code Playgroud)
这是Godbolt 中的链接。
这是 GCC 12.3 的实际汇编(使用 -O3):
fn(std::array<int, 4ul>&, std::array<int, 4ul> const&):
lea rdx, [rsi+4]
mov rax, rdi
sub rax, rdx
cmp rax, 8
jbe .L2
movdqu xmm0, XMMWORD PTR [rsi]
movdqu xmm1, XMMWORD PTR [rdi]
paddd …Run Code Online (Sandbox Code Playgroud) 假设我正在使用AVX2的VGATHERDPS - 这应该使用8个DWORD索引加载8个单精度浮点数.
当要加载的数据存在于不同的缓存行中时会发生什么?指令是作为硬件循环实现的,它逐个获取缓存行吗?或者,它是否可以立即向多个缓存行发出负载?
我读了几篇论述前者的文章(这是对我更有意义的文章),但我想更多地了解这一点.
链接到一篇论文:http://arxiv.org/pdf/1401.7494.pdf