- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试优化一些代码,但我处于有 4 个 vector 的状态 __m256d
我想将它们的总和存储在另一个 __m256d
中.
所以基本上result = [sum(a), sum(b), sum(c), sum(d)]
.我知道有一种方法可以使用 2 hadds 混合和置换来做到这一点,但我意识到 hadd 太贵了。
所以我想知道是否有一个内在可以更快地做到这一点。
最佳答案
三个选项:
vhaddpd
高效 vhaddpd
小-code,不像全矩阵转置那么容易理解
gcc
vector 扩展*,对转置矩阵求和的代码可能如下所示:
#include <stdint.h>
typedef uint64_t v4u64 __attribute__((vector_size(32)));
typedef double v4f64 __attribute__((vector_size(32)));
v4f64 dfoo(v4f64 sv0, v4f64 sv1, v4f64 sv2, v4f64 sv3)
{
v4f64 tv[4];
tv[0] = __builtin_shuffle(sv0, sv1, (v4u64){0,4,2,6});
tv[1] = __builtin_shuffle(sv0, sv1, (v4u64){1,5,3,7});
tv[2] = __builtin_shuffle(sv2, sv3, (v4u64){0,4,2,6});
tv[3] = __builtin_shuffle(sv2, sv3, (v4u64){1,5,3,7});
v4f64 fv[4];
fv[0] = __builtin_shuffle(tv[0], tv[2], (v4u64){0,1,4,5});
fv[1] = __builtin_shuffle(tv[0], tv[2], (v4u64){2,3,6,7});
fv[2] = __builtin_shuffle(tv[1], tv[3], (v4u64){0,1,4,5});
fv[3] = __builtin_shuffle(tv[1], tv[3], (v4u64){2,3,6,7});
return fv[0]+fv[1]+fv[2]+fv[3];
}
gcc-9.2.1
产生以下组件:
dfoo:
vunpcklpd %ymm3, %ymm2, %ymm5
vunpcklpd %ymm1, %ymm0, %ymm4
vunpckhpd %ymm1, %ymm0, %ymm0
vinsertf128 $1, %xmm5, %ymm4, %ymm1
vperm2f128 $49, %ymm5, %ymm4, %ymm4
vunpckhpd %ymm3, %ymm2, %ymm2
vaddpd %ymm4, %ymm1, %ymm1
vinsertf128 $1, %xmm2, %ymm0, %ymm3
vperm2f128 $49, %ymm2, %ymm0, %ymm0
vaddpd %ymm3, %ymm1, %ymm1
vaddpd %ymm0, %ymm1, %ymm0
ret
vunpck[h/l]pd
:1 个周期延迟,每个周期 1 个吞吐量,1 个 uOP 端口 5。 vinsertf128
:3 个周期延迟,每个周期 1 个吞吐量,1 个 uOP 端口 5。 vperm2f128
:3 个周期延迟,每个周期 1 个吞吐量,1 个 uOP 端口 5。 vaddpd
:4 个周期延迟,每个周期 2 个吞吐量,1 个 uOP port01。 vhadd
通过 gcc vector 扩展不容易获得,因此代码需要特定于英特尔的内在函数:
v4f64 dfoo_hadd(v4f64 sv0, v4f64 sv1, v4f64 sv2, v4f64 sv3)
{
v4f64 hv[2];
hv[0] = __builtin_ia32_haddpd256(sv0, sv1); //[00+01, 10+11, 02+03, 12+13]
hv[1] = __builtin_ia32_haddpd256(sv2, sv3); //[20+21, 30+31, 22+23, 32+33]
v4f64 fv[2];
fv[0] = __builtin_shuffle(hv[0], hv[1], (v4u64){0, 1, 4, 5}); //[00+01, 10+11, 20+21, 30+31]
fv[1] = __builtin_shuffle(hv[0], hv[1], (v4u64){2, 3, 6, 7}); //[02+03, 12+13, 22+23, 32+33]
return fv[0] + fv[1]; //[00+01+02+03, 10+11+12+13, 20+21+22+23, 30+31+32+33]
}
dfoo_hadd:
vhaddpd %ymm3, %ymm2, %ymm2
vhaddpd %ymm1, %ymm0, %ymm0
vinsertf128 $1, %xmm2, %ymm0, %ymm1
vperm2f128 $49, %ymm2, %ymm0, %ymm0
vaddpd %ymm0, %ymm1, %ymm0
ret
vhaddpd
:6 个周期延迟,每个周期 0.5 个吞吐量,3 uOPS port01 + 2*port5。 v4f64 dfoo_PC(v4f64 sv0, v4f64 sv1, v4f64 sv2, v4f64 sv3)
{
v4f64 tv[4];
v4f64 av[2];
tv[0] = __builtin_shuffle(sv0, sv1, (v4u64){0,4,2,6});//[00, 10, 02, 12]
tv[1] = __builtin_shuffle(sv0, sv1, (v4u64){1,5,3,7});//[01, 11, 03, 13]
av[0] = tv[0] + tv[1];//[00+01, 10+11, 02+03, 12+13]
tv[2] = __builtin_shuffle(sv2, sv3, (v4u64){0,4,2,6});//[20, 30, 22, 32]
tv[3] = __builtin_shuffle(sv2, sv3, (v4u64){1,5,3,7});//[21, 31, 23, 33]
av[1] = tv[2] + tv[3];//[20+21, 30+31, 22+23, 32+33]
v4f64 fv[2];
fv[0] = __builtin_shuffle(av[0], av[1], (v4u64){0,1,4,5});//[00+01, 10+11, 20+21, 30+31]
fv[1] = __builtin_shuffle(av[0], av[1], (v4u64){2,3,6,7});//[02+03, 12+13, 22+23, 32+33]
return fv[0]+fv[1];//[00+01+02+03, 10+11+12+13, 20+21+22+23, 30+31+32+33]
}
dfoo_PC:
vunpcklpd %ymm1, %ymm0, %ymm4
vunpckhpd %ymm1, %ymm0, %ymm1
vunpcklpd %ymm3, %ymm2, %ymm0
vunpckhpd %ymm3, %ymm2, %ymm2
vaddpd %ymm1, %ymm4, %ymm1
vaddpd %ymm2, %ymm0, %ymm2
vinsertf128 $1, %xmm2, %ymm1, %ymm0
vperm2f128 $49, %ymm2, %ymm1, %ymm1
vaddpd %ymm1, %ymm0, %ymm0
ret
hadd
相同数量的 port5 uOPs -代码。代码在端口 5 上仍然存在瓶颈,延迟约为 16 个周期。
vblendpd
,它有 3 个/周期的吞吐量,1 个周期的延迟,并且可以在端口 015 上执行,但是使用它来替换置换/插入/混洗之一需要 vector 的 128 位 channel 的 64 位移位,即由
vpsrldq/vpslldq
实现,你猜对了它需要一个 port5 uOP(所以这将有助于 32 位 vector
float
,因为
vpsllq/vpsrlq
不需要 port5)。这里没有免费的午餐。
+-*/=><>><<
等),按元素操作。它们还包括一些
__builtin_*
函数,特别是
__builtin_shuffle()
,它具有 3 操作数形式,其中前两个是相同类型 T 的两个(相同长度 N) vector ,它们(逻辑上)连接到该类型 T 的双倍长度 (2N) vector ,第三个是与原始 vector 类型具有相同宽度和长度 (N) 的整数类型 (IT) vector 。结果是原始 vector 的相同类型 T 和宽度 N 的 vector ,元素由整数类型 vector 中的索引选择。
uint64_t
,保留在这里作为上下文:
#include <stdint.h>
typedef uint64_t v4u64 __attribute__((vector_size(32)));
v4u64 foo(v4u64 sv0, v4u64 sv1, v4u64 sv2, v4u64 sv3)
{
v4u64 tv[4];
tv[0] = __builtin_shuffle(sv0, sv1, (v4u64){0,4,2,6});
tv[1] = __builtin_shuffle(sv0, sv1, (v4u64){1,5,3,7});
tv[2] = __builtin_shuffle(sv2, sv3, (v4u64){0,4,2,6});
tv[3] = __builtin_shuffle(sv2, sv3, (v4u64){1,5,3,7});
v4u64 fv[4];
fv[0] = __builtin_shuffle(tv[0], tv[2], (v4u64){0,1,4,5});
fv[1] = __builtin_shuffle(tv[0], tv[2], (v4u64){2,3,6,7});
fv[2] = __builtin_shuffle(tv[1], tv[3], (v4u64){0,1,4,5});
fv[3] = __builtin_shuffle(tv[1], tv[3], (v4u64){2,3,6,7});
return fv[0]+fv[1]+fv[2]+fv[3];
}
gcc-9.2.1
生成的翻译在 skylake-avx2 上可能看起来像这样:
foo:
vpunpcklqdq %ymm3, %ymm2, %ymm5
vpunpcklqdq %ymm1, %ymm0, %ymm4
vpunpckhqdq %ymm3, %ymm2, %ymm2
vpunpckhqdq %ymm1, %ymm0, %ymm0
vperm2i128 $32, %ymm2, %ymm0, %ymm3
vperm2i128 $32, %ymm5, %ymm4, %ymm1
vperm2i128 $49, %ymm2, %ymm0, %ymm0
vperm2i128 $49, %ymm5, %ymm4, %ymm4
vpaddq %ymm4, %ymm1, %ymm1
vpaddq %ymm0, %ymm3, %ymm0
vpaddq %ymm0, %ymm1, %ymm0
ret
vpunpck[h/l]qdq
:1 个周期延迟,每个周期 1 个吞吐量,端口 5。 vperm2i128
:3 个周期延迟,每个周期 1 个吞吐量,端口 5。 vpaddq
:1 个周期延迟,每个周期 3 个吞吐量,端口 015。 关于c++ - SIMD 减少 4 个 vector 而没有 hadd,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60791025/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!