English 中文(简体)
超过128条轨道的经签字的16轨喷洒媒介,扩展到32个轨道元素
原标题:Multiply 128-bit vectors of signed 16-bit integers, widening to 32-bit elements

页: 1 每一条均包含8xint16_t (sign)

__mm128i a = {a0,...,a7}
__mm128i b = {b0,...,b7}

我想增加8个内容。 每一乘数的结果是int32_t。 因此,每个登记册只有4个结果:

__mm128i c0 = {a0*b0,...,a3*b3}
__mm128i c1 = {a4*b4,...,a7*b7}

我没有发现这种内在因素。

问题回答

SSE2有16-bit “mul_hi”,可回收产品的一半。 16项高分辨率和16项低分辨率结合到32项无包装的轨道上。

    __m128i lo = _mm_mullo_epi16(a, b);
    __m128i hi = _mm_mulhi_epi16(a, b);
    __m128i c0 = _mm_unpacklo_epi16(lo, hi);
    __m128i c1 = _mm_unpackhi_epi16(lo, hi);

s 回答<>a>指出,它易于作为<代码>pmullw+pmulhw,且不包装文件/hi将每32个比值产品中的16-比数减半。 接受。


Mostly obsolete answer - only useful if odd/even interleaved is useful

(作为AVX2版本的一个备选组成部分,希望扩大至_m256i结果——它对于<代码>_m256i的投入来说,如何有效地做到这一点是不言而喻的。) m128i 您应将每一投入扩大到8x 32-bit,vpmovzxwd (_mm256_cvtepu16_epi32)和使用

x86 仅扩大16x16-> 32-bit SIMD 成倍于pmaddwd,横向增加产品的配对。 因此,它不能直接使用,但如果其中一种产品产生零,那么,在这句子中,你拥有两个经签字的16位星级的32倍产品。

You could unpack (with zero-extension) both inputs (4 shuffles) to feed 2 pmaddwd instruction. Unpacking with zero-extension is cheaper for the high half, since _mm_unpackhi_epi16 against _mm_setzero_si128() is cheaper than manually doing sign extension with an arithmetic right shift, or doing extra work to feed the high half to _mm_cvtepi16_epi32 (pmovsxwd).

如果你使用<代码>pmulld(32x32->32-bit multi),你只需要或希望签署延期,但你希望避免这种情况,因为这在英特尔邮联(每部指示2 uops)上放缓。 https://uops.info/

标有<代码>pmaddwd>的16-bit签名的批量0至32-bit>的多面正读a0*b0 + 0*0,按每个要素计算。 如果您签署这些投入,你可以做如下工作:a0*b0 + -1*-1,这就是为什么如果你重新做这一优化工作,你需要零敲响。


如果不包给你奇/文具,自<>0× garbage = 0以来,这种工作效率更高,那么我们只需要2项指示(加上一些登记副本),以编制2份投入表,其中无一为les。 (在32个轨道词中,如psrld) 将需要改变两种投入,以保持多模版的正确方向。

   __m128i a, b;  // inputs

   __m128i even_mask = _mm_set1_epi32(0x0000FFFF);
   __m128i a_even = _mm_and_si128(a, even_mask);
   __m128i b_odd = _mm_andnot_si128(even_mask, b);  

  // only need to mask one input to each multiply: 0 x garbage = 0
   __m128i prod_even = _mm_madd_epi16(a_even, b);  // { a0*b0, a2*b2, a4*b4, a6*b6 }
   __m128i prod_odd  = _mm_madd_epi16(a, b_odd);   // { a1*b1, a3*b3, a5*b5, a7*b7 } 

这两种方式只能掩盖<条码>a;这两种方法最终都含有相同的<条码> 滚动式<>/条码>指示,以复制一份登记册,至少可以销毁<条码>/<>>和<条码>>所载输入登记册。 无论最后一点投入(在非正常状态下),它确实有宝贵的优势,而另一个国家有时间已经蒙上面罩,并愿意挖掘其中的多功能。 这在旧的CPU中更为令人感兴趣,只有1/clock 输入pmaddwd(例如,在Skylake之前的Intel;


单单/单项产品可能是你想要的更好的起点,因为它只需要2个更细的子才能相互连接<条码>。

  __m128i prod_low  = _mm_unpacklo_epi32(prod_even, prod_odd); // { a0*b0, a1*b1, a2*b2, a3*b3 }
  __m128i prod_high = _mm_unpackhi_epi32(prod_even, prod_odd);

这是2个双向和2个<代码>pmaddwd和2xpunpckdq

第2x条(<代码>pmovzxwd、2xpunpckhwd和2xpmaddwd,因此,非多面指示的4条都将是sh。 如果周围的代码也需要任何les子,那么对第5号港的压力就会减少,而英特尔CPU拥有有限的put子(特别是在Ice湖之前)。

利用PAND,我们需要一种病媒的固定,但4x shuffle路只需要一个零的登记册。 我只看一看一线看看看看看看是否需要多读<条码>。 由于<代码>pmovzxwd,4x shuffle 可能具有这一优势。

4x shuffle 办法就是这样,并且是,可证明效率更高,除非周围代码还使用许多sh子,在sh子执行单位中形成瓶颈。

   __m128i a, b;  // inputs

   __m128i a_lo = _mm_cvtepu16_epi32(a);
   __m128i b_lo = _mm_cvtepu16_epi32(b);

   __m128i a_hi = _mm_unpackhi_epi16(a, _mm_setzero_si128());  // unpack(zero, a) would work equally well but compile less efficiently
   __m128i b_hi = _mm_unpackhi_epi16(b, _mm_setzero_si128());

   __m128i prod_lo = _mm_madd_epi16(a_lo, b_lo);  // { a0*b0, a1*b1, a2*b2, a3*b3 }
   __m128i prod_hi = _mm_madd_epi16(a_hi, b_hi);

马达加斯加 这并没有检验它们如何渗入 lo体,例如,编造者可以超出其固定负荷。 但即便如此,4x条手法也减少了指示。 Clang “optimizes” the and/andnot to 2x pblendw, which is 1 uop for port 5 only on British CPUs before Ice Lake. 这也许仍然比固定电话要好,而不是像在 lo。

但无论如何,四轮uff法没有附加的<条码>移动卡登记复印指示,因此,其成本低于在不同港口分配实际工作的前端带宽。


@chtz建议prod_odd=_mm_sub_epi32(_mm_madd_epi16(a, b), prod_even);而不是pandn。 这比以往更重要,但当我们必须与AVX进行汇编时,却节省了2条<代码>去除dqahttps://godbolt.org/z/7Gxn67d8h





相关问题
Intel Intrinsic: Convert int16 x 8 to : int32 x 8

In RAM I have 8 x (int16). I read it with: __m128i RawInt16 = _mm_load_si128 (pSrc); I have to convert RawInt16 into 2 registers of 4 x (int32) My code is: __m128i Zero = { 0,0,0,0,0,0,0,0 }; _mm128i ...

VC++ SSE intrinsic optimisation weirdness

I am performing a scattered read of 8-bit data from a file (De-Interleaving a 64 channel wave file). I am then combining them to be a single stream of bytes. The problem I m having is with my re-...

Fast Image Manipulation using SSE instructions?

I am writing a graphics library in C and I would like to utilize SSE instructions to speed up some of the functions. How would I go about doing this? I am using the GCC compiler so I can rely on ...

Benchmarking SSE instructions

I m benchmarking some SSE code (multiplying 4 floats by 4 floats) against traditional C code doing the same thing. I think my benchmark code must be incorrect in some way because it seems to say that ...

SSE2: How to reduce a _m128 to a word

What s the best way ( sse2 ) to reduce a _m128 ( 4 words a b c d) to one word? I want the low part of each _m128 components: int result = ( _m128.a & 0x000000ff ) << 24 | ( _m128.b ...

热门标签