- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
由于_mm_moveh_ps
没有AVX版本,我通常使用_mm256_shuffle_ps(a, b, 0x44)
作为AVX寄存器的替代品。但是,我记得在其他问题中读过,如果可能的话,应该首选没有控制整数的 swizzle 指令(例如 _mm256_unpacklo_ps 或 _mm_moveh_ps )(出于某种原因我不知道) )。昨天,我想到另一种选择可能是使用以下内容:
_mm256_castpd_ps(_mm256_unpacklo_pd(_mm256_castps_pd(a), _mm256_castps_pd(b)));
由于强制转换应该是无操作的,因此就性能而言,这比使用 _mm256_shuffle_ps
更好\等于\更差吗?
另外,如果情况确实如此,如果有人能用简单的语言解释一下(我对汇编和微体系结构的理解非常有限)为什么人们应该更喜欢没有控制整数的指令,那就太好了。
提前致谢
附加说明:Clang 实际上将 shuffle 优化为 vunpcklpd
:https://godbolt.org/z/9XFP8D如此看来,我的想法还不算太糟糕。然而,GCC 和 ICC 创建了 shuffle 指令。
最佳答案
避免立即数可节省 1 个字节的机器代码大小;就这样。出于性能考虑,它位于列表的底部,但由于这个原因,所有其他相同的洗牌(例如带有隐式“控制”的 _mm256_unpacklo_pd
)都比直接控制字节稍好一些。
(但是在另一个 vector 中获取控制操作数,例如 vpermilps
can 或 vpermd
require 通常更糟糕,除非您在长时间运行中遇到一些奇怪的前端瓶颈循环,并且可以在循环外加载 shuffle 控制。不太合理,此时您必须在 asm 中手动编写才能关心代码大小/对齐;在 C++ 中,这仍然不是您真正可以做到的直接控制。)
Since the casts are supposed to be no-ops, is this better\equal\worse than using
_mm256_shuffle_ps
regarding performance?
根据 uops.info 的测试,Ice Lake 的速度为 2/时钟 vshufps
与 1/时钟 vunpcklpd
在真实硬件上,在端口 1 或端口 5 上运行。一定使用_mm256_shuffle_ps
。在早期的 CPU 上,微不足道的额外代码大小成本实际上可能根本不会造成任何损害,而且为了 ICL 的 future 利益,可能是值得的,除非您确定端口 5 不会成为瓶颈。
Ice Lake 在端口 1 上有一个第二个洗牌单元,可以处理一些常见的 XMM 和 channel 内 YMM 洗牌,包括 vpshufb
以及一些 2 输入洗牌,例如 vshufps
。我不知道为什么它不只是使用该控制 vector 将 vunpcklpd
解码为 vshufps
,或者设法在端口 1 上运行该 shuffle。我们知道 shuffle 硬件它本身可以进行洗牌,所以我想这只是控制硬件设置隐式洗牌的问题,以某种方式将操作码映射到洗牌控制。
除此之外,它在较旧的 AVX CPU 上相同或更好;没有 CPU 会因在其他 PS 指令之间使用 PD 混洗而受到惩罚。现有 CPU 上唯一的不同是代码大小。 K8 和 Core 2 等旧版 CPU 的 pd
洗牌速度比 ps
更快,但没有采用 AVX 的 CPU 的洗牌单元具有该弱点。此外,AVX 非破坏性指令级别差异的操作数必须是目标。
正如您从 Godbolt 链接中看到的,随机播放之前/之后的额外指令为零。 “cast”内在函数不进行转换,只是重新解释以保持 C++ 类型系统满意,因为英特尔决定为 __m256
与 __m256d
(与 __m256i
),而不是使用一种通用 YMM 类型。不过,他们选择不像 ARM 那样拥有单独的 uint8x16
与 uint32x4
vector ;对于整数 SIMD,只需 __m256i
。
所以编译器不需要为强制转换发出额外的指令,实际上这是事实;他们不会引入额外的 vmovaps
/apd
寄存器拷贝或类似的东西。
如果您使用 clang,您可以方便地编写它,然后让 clang 的随机优化器为您发出 vunpcklpd
。或者在其他情况下,无论如何它都会做;有时它会做出比源更糟糕的选择,但通常它会做得很好。
Clang 在使用 -march=icelake-client
时出现此错误,即使您编写 _mm256_shuffle_ps
,仍然使用 vunpcklpd
。 (或者根据周围的代码,可能会将洗牌优化为其他内容的一部分。)
关于c++ - _mm_moveh_ps 的 AVX 等效项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58954801/
我正在尝试优化一些矩阵计算,我想知道是否可以在编译时检测 SSE/SSE2/AVX/AVX2/AVX-512/AVX-128-FMA/KCVI[ 1] 是否由编译器启用?非常适合 GCC 和 Clan
我想仅使用avx而不是avx2来实现64位转置操作。它应该这样做: // in = Hh Hl Lh Ll // | X | // out = Hh Lh Hl Ll 这就是使
如果我有一个 AVX 寄存器,里面有 4 个 double 值,我想将它的反向存储在另一个寄存器中,是否可以用一个内部命令来实现? 例如:如果我在 SSE 寄存器中有 4 个 float ,我可以使用
最初我试图重现 Agner Fog 的微体系结构指南部分“YMM 和 ZMM 向量指令的预热期”中描述的效果,它说: The processor turns off the upper parts o
我的 C++ 代码使用 SSE,现在我想改进它以支持 AVX(当它可用时)。因此,我检测 AVX 何时可用并调用使用 AVX 命令的函数。我使用 Win7 SP1 + VS2010 SP1 和带有 A
我有一大块内存,比如说 256 KiB 或更长。我想计算整个 block 中 1 位的数量,或者换句话说:将所有字节的“总体计数”值相加。 我知道 AVX-512 有一个 VPOPCNTDQ inst
有多快 tensorflow-gpu与没有 AVX 和 AVX2 相比,有 AVX 和 AVX2 吗? 我试图使用谷歌找到答案,但没有成功。很难重新编译tensorflow-gpu对于 Windows
为什么avx sqrt(非压缩)指令有三个操作数? vsqrtsd xmm1, xmm2, xmm3 这是否意味着类似于 xmm1=xmm2=sqrt(xmm3)? 编辑:下面的详细答案但总之流水线的
我正在研究Intel intrinsics guide的展开和压缩操作。我对这两个概念感到困惑: 对于__m128d _mm_mask_expand_pd (__m128d src, __mmask8
我在 Intel Intrinsic Guide v2.7 中找不到它们。您知道 AVX 或 AVX2 指令集是否支持它们吗? 最佳答案 原始 AVX 指令集中没有分散或收集指令。 AVX2 添加了收
我正在尝试将函数转换为 AVX 版本。函数本身基本上只是比较浮点数并返回真/假取决于计算。 这是原始函数: bool testSingle(float* thisFloat, float* other
我遇到了 AVX 内部指令 _mm256_testc_pd() 的一个非常奇怪的行为。在这里你可以看到这个功能的描述 https://software.intel.com/sites/landingp
我有一个 256 位 AVX 寄存器,其中包含 4 个单精度复数,存储为实数、虚数、实数、虚数等。我目前正在将整个 256 位寄存器写回内存并在那里求和,但这似乎效率低下. 如何使用 AVX(或 AV
#include "stdio.h" #include "math.h" #include "stdlib.h" #include "x86intrin.h" void dd_m(double *cl
有没有办法对 AVX 寄存器进行水平异或——特别是对 256 位寄存器的四个 64 位组件进行异或? 目标是获得 AVX 寄存器的所有 4 个 64 位组件的异或。它本质上与水平添加( _mm256_
当我尝试使用 AVX 获取数据时,出现运行时错误 - 段错误: int i = 0; const int sz = 9; size_t *src1 = (size_t *)_mm_malloc(sz*
当我尝试使用 AVX 展开最简单的循环时,出现运行时错误 - 段错误: const int sz = 9; float *src = (float *)_mm_malloc(sz*
我想将两个 256 位 vector (__m256d) 合并为一个 256位 vector ,通过省略每个 64 位 double 的上半部分。 所以,如果在下面,a_i, b_i, ... 是 3
我测试了以下简单的功能 void mul(double *a, double *b) { for (int i = 0; i #include #include #include #defi
_mm_i32gather_epi32() 的当前英特尔内在函数指南将每个子词的计算地址描述为: addr := base_addr + SignExtend64(vindex[m+31:m]) *
我是一名优秀的程序员,十分优秀!