页: 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}
我没有发现这种内在因素。
页: 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-比数减半。 接受。
(作为AVX2版本的一个备选组成部分,希望扩大至_m256i
结果——它对于<代码>_m256i的投入来说,如何有效地做到这一点是不言而喻的。) 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
和2x
pmaddwd
,因此,非多面指示的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条<代码>去除dqa。 https://godbolt.org/z/7Gxn67d8h
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 ...
I m trying to implement some inline assembler (in C/C++ code) to take advantage of SSE. I d like to copy and duplicate values (from an XMM register, or from memory) to another XMM register. For ...
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-...
Our server application does a lot of integer tests in a hot code path, currently we use the following function: inline int IsInteger(double n) { return n-floor(n) < 1e-8 } This function is ...
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 ...
Usually I work with 3D vectors using following types: typedef vec3_t float[3]; initializing vectors using smth. like: vec3_t x_basis = {1.0, 0.0, 0.0}; vec3_t y_basis = {0.0, 1.0, 0.0}; vec3_t ...
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 ...
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 ...