Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用内部函数初始化uu m128i常量的最快方法?_C_Visual C++_Sse_Intrinsics_Micro Optimization - Fatal编程技术网

C 使用内部函数初始化uu m128i常量的最快方法?

C 使用内部函数初始化uu m128i常量的最快方法?,c,visual-c++,sse,intrinsics,micro-optimization,C,Visual C++,Sse,Intrinsics,Micro Optimization,目前,我有一个uu m128i变量,我们称它为X。我想用一个128位的常量值对其进行异或运算,然后将值保存回X。因此,本质上,对于某个常数C,X^=C 目前,我正在做以下工作: X=_-mm\u-xor\u-si128(X,_-mm\u-set\u-epi64x(C\u-a,C\u-b)) 它从异或的C的两个64位部分构建一个\uuuu m128i 我的问题是,这似乎不是为xor初始化_m128i常量的最有效方法。尝试从一个对齐的数组加载会更好吗?还是其他方法 我目前在Visual Studio

目前,我有一个uu m128i变量,我们称它为
X
。我想用一个128位的常量值对其进行异或运算,然后将值保存回
X
。因此,本质上,对于某个常数
C
,X^=C

目前,我正在做以下工作:

X=_-mm\u-xor\u-si128(X,_-mm\u-set\u-epi64x(C\u-a,C\u-b))

它从异或的
C
的两个64位部分构建一个
\uuuu m128i

我的问题是,这似乎不是为xor初始化_m128i常量的最有效方法。尝试从一个对齐的数组加载会更好吗?还是其他方法


我目前在Visual Studio中与MSVC合作。

这个答案纯粹是关于常量
C
的情况。如果您有非常量输入,则它们来自何处(内存、寄存器、最近的计算,您可能首先在向量寄存器中执行这些计算?)以及您对结果向量所做的操作都很重要。将单独的标量变量混入/移出SIMD向量有点糟糕,需要在ALU端口瓶颈与存储/重新加载的延迟和吞吐量(以及标量->向量的存储转发暂停)之间进行权衡。不过,在asm中,存储/重新加载对于从SIMD向量中获取大量小元素非常有用,因为您确实需要它们


对于常量
C_a
C_b
,即使是MSVC也能通过
\u mm_集
在常量传播方面做得很好。因此,编写特定于实现的初始值设定项(如

请记住,性能的真正决定因素是可以诱使编译器生成的程序集,而不是用来生成的内部函数。

#include <immintrin.h>

__m128i xor_const(__m128i v) {
    return _mm_xor_si128(v, _mm_set_epi64x(0x789abc, 0x123456));
}
我们可以看到,
\u mm_set
在静态存储中编译为一个16字节的常量,就像我们想要的那样。未能使用px或xmm0、xmm1是令人惊讶的,但与GCC和/或clang相比。同样,作为一个大函数的一部分,当它有寄存器选择时,我们可能没有额外的
movdqa
。如果xor在循环中,那么在循环外加载一次就是我们想要的。这不是MSVC的最新版本;GOODBET只具有最新的MSVC版本,安装在C++中,而不是C,但您标记了C.


相比之下,GCC9.2-O3编译为在所有CPU上都有效的预期内存源PXOR

xor_const:
        pxor    xmm0, XMMWORD PTR .LC0[rip]
        ret

.section .rodata    # Godbolt strips out stuff like section directive; re-added manually
.LC0:
        .quad   1193046
        .quad   7903932

您可能会让编译器发出相同的asm,其中包含一个保持常量的静态数组
alignas(16)
array,并从中加载
\u mm\u load\u si128()
。但是为什么要麻烦呢


要避免的一件事是写入
静态常量m128i C=\u mm\u集…
-编译器对此非常愚蠢,不会将
\u mm\u集
折叠到
\u m128i
的静态常量初始值设定项中。C编译器将拒绝编译非常量静态初始值设定项。C++编译器将保留一些BSS空间,运行一个类似于构造函数的函数,从只读常量复制到该BSS空间,因为<>代码> MyMyStuts在这种情况下不能完全优化。

< P>这纯粹是关于常数<代码> C<代码>的情况。如果您有非常量输入,则它们来自何处(内存、寄存器、最近的计算,您可能首先在向量寄存器中执行这些计算?)以及您对结果向量所做的操作都很重要。将单独的标量变量混入/移出SIMD向量有点糟糕,需要在ALU端口瓶颈与存储/重新加载的延迟和吞吐量(以及标量->向量的存储转发暂停)之间进行权衡。不过,在asm中,存储/重新加载对于从SIMD向量中获取大量小元素非常有用,因为您确实需要它们


对于常量
C_a
C_b
,即使是MSVC也能通过
\u mm_集
在常量传播方面做得很好。因此,编写特定于实现的初始值设定项(如

请记住,性能的真正决定因素是可以诱使编译器生成的程序集,而不是用来生成的内部函数。

#include <immintrin.h>

__m128i xor_const(__m128i v) {
    return _mm_xor_si128(v, _mm_set_epi64x(0x789abc, 0x123456));
}
我们可以看到,
\u mm_set
在静态存储中编译为一个16字节的常量,就像我们想要的那样。未能使用px或xmm0、xmm1是令人惊讶的,但与GCC和/或clang相比。同样,作为一个大函数的一部分,当它有寄存器选择时,我们可能没有额外的
movdqa
。如果xor在循环中,那么在循环外加载一次就是我们想要的。这不是MSVC的最新版本;GOODBET只具有最新的MSVC版本,安装在C++中,而不是C,但您标记了C.


相比之下,GCC9.2-O3编译为在所有CPU上都有效的预期内存源PXOR

xor_const:
        pxor    xmm0, XMMWORD PTR .LC0[rip]
        ret

.section .rodata    # Godbolt strips out stuff like section directive; re-added manually
.LC0:
        .quad   1193046
        .quad   7903932

您可能会让编译器发出相同的asm,其中包含一个保持常量的静态数组
alignas(16)
array,并从中加载
\u mm\u load\u si128()
。但是为什么要麻烦呢

要避免的一件事是写入
静态常量m128i C=\u mm\u集…
-编译器对此非常愚蠢,不会将
\u mm\u集
折叠到
\u m128i
的静态常量初始值设定项中。C编译器将拒绝编译非常量静态初始值设定项。C++编译器将保留一些BSS空间,运行一个类似于构造函数的函数,从只读常量复制到该BSS空间,因为<>代码> MyMyStuts在这种情况下不能完全优化。

谢谢,这里有很多很棒的信息,我现在仍然在更详细地介绍这一切。看起来,在当前的实现中,我从代码段中的一个常量(
cs:xmmword…
)获得了一个
movdqa
)。我要走了