sse - 将字节相乘以产生 16 位,无需移位
问题描述
仍在学习 SIMD 的艺术,我有一个问题:我有两个压缩的 8 位寄存器,我想将它们与_mm_maddubs_epi16
( pmaddubsw
) 相乘以获得一个 16 位的压缩寄存器。
我知道这些字节总是会产生小于 256 的数字,所以我想避免浪费剩余的 8 位。例如,结果_mm_maddubs_epi16(v1, v2)
应该写在r
where XX
is,而不是 where it will be(用 表示__
)。
v1 (04, 00, 0e, 00, 04, 00, 04, 00, 0a, 00, 0f, 00, 05, 00, 01, 00)
v2 (04, 00, 0e, 00, 04, 00, 04, 00, 0a, 00, 0f, 00, 05, 00, 01, 00)
r (__, XX, __, XX, __, XX, __, XX, __, XX, __, XX, __, XX, __, XX)
我可以在不改变结果的情况下做到这一点吗?
附言。我没有好的处理器,我仅限于 AVX 指令。
解决方案
在您的矢量图中,最高元素是在左边还是在右边?位置是XX
在结果的最高有效字节还是最低有效字节中pmaddubsw
?
要从每个单词的高字节输入中获取单词低字节的结果:
使用_mm_mulhi_epu16
这样你就可以有效地做(v1 << 8) * (v2 << 8) >> 16
,在输入字的相反字节中产生结果。 由于您说乘积严格小于 256,因此您将在每个 16 位字的低字节中得到 8 位结果。
(如果您的输入是有符号的,请使用_mm_mulhi_epi16
,但是否定结果将被符号扩展为完整的 16 位。)
从低字节的输入中获取单词高字节的结果
您需要更改加载/创建输入之一的方式,而不是
MSB LSB | MSB LSB
v1_lo (00, 04, 00, 0e, 00, 04, 00, 04, 00, 0a, 00, 0f, 00, 05, 00, 01)
element# 15 14 13 12 ... 0
你有这个:(两者都使用英特尔的符号,其中左元素是最大的数字,所以向量像_mm_slli_epi128
图中的左移字节一样移动)。
MSB LSB | MSB LSB
v1_hi (04, 00, 0e, 00, 04, 00, 04, 00, 0a, 00, 0f, 00, 05, 00, 01, 00)
element# 15 14 13 12 ... 0
在v2
每个单词元素的高半部分仍然有其非零字节,简单地说_mm_mullo_epi16(v1_hi, v2)
,您将(v1 * v2) << 8
免费获得。
如果您已经用零解包字节以获得 v1 和 v2,则以另一种方式解包。如果您使用pmovzx
( _mm_cvtepu8_epi16
),则切换到使用_mm_unpacklo_epi8(_mm_setzero_si128(), packed_v1 )
。
如果您以这种已经零填充的形式从内存中加载这些向量,请使用 1 个字节的未对齐加载偏移量,以便零在相反的位置结束。
如果您真正想要的是从没有以零开始解包的输入字节开始,我认为您无法避免这种情况。或者,如果您要屏蔽而不是解包(通过使用来节省 shuffle-port 吞吐量_mm_and_si128
),您可能需要在某个地方进行转换。但是,您可以移位而不是屏蔽一种方式,使用v1_hi = _mm_slli_epi16(v, 8)
: 以字粒度左移 8 位将使低字节保持为零。
推荐阅读
- terraform - Lambda 资源中变量引用的 Terraform 错误,甚至不会被创建
- java - 如何使用 JOptionPane 创建菜单
- java - 通过 Java 程序发送电子邮件
- android - 如何对齐两个相邻的按钮?
- php - 将关联数组传递到 Laravel 5.8 中的 where caluse
- python - PyDotPlus 无法解析节点属性中带有 '\"' 的点
- angularjs - 如何停止对同一网址的双重请求
- python - TFRecords 解析:无法解析序列化示例
- ruby-on-rails - 如何在 Rails 中按第二个订单 belongs_to 分组?
- c# - 最大化/调整大小以显示 Windows-10 C# UWP 应用程序的分辨率?