代码之家  ›  专栏  ›  技术社区  ›  senseiwa

乘以字节产生16位,不移位

  •  1
  • senseiwa  · 技术社区  · 7 年前

    在学习simd的艺术的同时,我还有一个问题:我有两个打包的8位寄存器,我想用它来乘法加法 _mm_maddubs_epi16 ( pmaddubsw )获得16位压缩寄存器。

    我知道这些字节会产生 总是 一个小于256的数字,所以我想避免浪费剩下的8位。例如,结果 _mm_maddubs_epi16(v1, v2) 结果应该写在 r 哪里 XX 是,而不是它将在何处(用 __ )

    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指令。

    2 回复  |  直到 7 年前
        1
  •  3
  •   Peter Cordes    7 年前

    在向量图中,最高的元素是在左边还是在右边?是 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
    

    您可以这样做:(两种方法都使用Intel的表示法,其中左边的元素是最高的数字,因此向量移动就像 _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字节的未对齐加载偏移量,使零以相反的位置结束。


    如果您真正想要的是从没有用零开始解包的输入字节开始,我认为您不能避免这种情况。或者如果是屏蔽而不是解包(通过使用 _mm_and_si128 相反,你可能需要换个地方。你可以换班 相反 但是,使用 v1_hi = _mm_slli_epi16(v, 8) :字粒度左移8将使低位字节置零。

        2
  •  0
  •   aqrit    7 年前

    换档 v1 v2 然后使用 _mm_mullo_epi16() .

    可能的xy问题?我猜是这样的 _mm_unpacklo_epi8() _mm_packus_epi16() 可能对你有用。

    推荐文章