标签: simd

包装System.Numerics.VectorX代价昂贵 - 为什么?

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)

c# simd ryujit

25
推荐指数
1
解决办法
511
查看次数

如何使用SIMD实现atoi?

我想尝试使用SIMD指令编写atoi实现,包含在RapidJSON(C++ JSON /写库)中.它目前在其他地方有一些SSE2和SSE4.2优化.

如果是速度增益,atoi则可以并行执行多个结果.字符串最初来自JSON数据的缓冲区,因此多atoi函数将不得不进行任何所需的调配.

我想出的算法如下:

  1. 我可以用以下方式初始化长度为N的向量:[10 ^ N..10 ^ 1]
  2. 我将缓冲区中的每个字符转换为整数并将它们放在另一个向量中.
  3. 我将有效数字向量中的每个数字乘以数字向量中的匹配数,并将结果相加.

我的目标是x86和x86-64架构.

我知道AVX2支持三个操作数Fused Multiply-Add,所以我将能够执行Sum = Number*有效数字+和.
那是我到目前为止的地方.
我的算法是否正确?有没有更好的办法?
是否有使用任何SIMD指令集的atoi参考实现?

c++ x86 sse simd atoi

25
推荐指数
2
解决办法
3598
查看次数

你能以多快的速度进行线性搜索?

我正在寻找优化这种线性搜索:

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个之后将数组元素初始化为适当的数组,如果这样可以加快搜索速度.

不,不允许二进制搜索,只能进行线性搜索.

编辑:我在博客文章中总结有关此主题的所有知识.

c optimization search simd linear-search

24
推荐指数
5
解决办法
1万
查看次数

如何将128位立即数移动到XMM寄存器

关于这一点已经存在一个问题,但它被关闭为"含糊不清",所以我开了一个新的 - 我找到了答案,也许它也会帮助其他人.

问题是:如何编写汇编代码序列来初始化具有128位立即(常量)值的XMM寄存器?

x86 assembly sse simd

24
推荐指数
5
解决办法
2万
查看次数

英特尔AVX:256位版本的点积,用于双精度浮点变量

英特尔高级矢量扩展指令集(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)

c++ performance simd avx

24
推荐指数
3
解决办法
1万
查看次数

CPU SIMD与GPU SIMD?

GPU使用SIMD范例,即,相同的代码部分将并行执行,并应用于数据集的各种元素.

但是,CPU也使用SIMD,并提供指令级并行.例如,据我所知,类似SSE的指令将处理具有并行性的数据元素.

虽然SIMD范例似乎在GPU和CPU中的使用方式不同,但GPU的SIMD功率是否比CPU更多?

在哪种方式中,CPU中的并行计算能力比GPU中的并行计算能力"弱"?

谢谢

parallel-processing cpu gpu simd

24
推荐指数
2
解决办法
1万
查看次数

在运行中生成矢量常数的最佳指令序列是什么?

"最佳"意味着最少的指令(或最少的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空间.)

x86 assembly sse simd avx

24
推荐指数
1
解决办法
1733
查看次数

GCC无法像C阵列一样优化对齐的std :: array

以下是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)

c++ optimization gcc simd memory-alignment

24
推荐指数
1
解决办法
3914
查看次数

为什么 GCC 生成有条件执行 SIMD 实现的代码?

以下代码生成的程序集在使用-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)

c++ gcc simd auto-vectorization

24
推荐指数
1
解决办法
1116
查看次数

如何实现AVX2中的收集指令?

假设我正在使用AVX2的VGATHERDPS - 这应该使用8个DWORD索引加载8个单精度浮点数.

当要加载的数据存在于不同的缓存行中时会发生什么?指令是作为硬件循环实现的,它逐个获取缓存行吗?或者,它是否可以立即向多个缓存行发出负载?

我读了几篇论述前者的文章(这是对我更有意义的文章),但我想更多地了解这一点.

链接到一篇论文:http://arxiv.org/pdf/1401.7494.pdf

ram intel simd avx avx2

23
推荐指数
2
解决办法
5205
查看次数