AVX 4位整数

use*_*837 5 c c++ vectorization intrinsics avx

我需要执行以下操作:

 w[i] = scale * v[i] + point
Run Code Online (Sandbox Code Playgroud)

比例和点是固定的,而是v[]4比特整数的向量.

我需要计算w[]任意输入向量v[],我想使用AVX内在函数来加速进程.但是,v[i]是一个4位整数的向量.

问题是如何使用内在函数对4位整数执行操作?我可以使用8位整数并以这种方式执行操作,但有没有办法执行以下操作:

[a,b] + [c,d] = [a+b,c+d]

[a,b] * [c,d] = [a * b,c * d]
Run Code Online (Sandbox Code Playgroud)

(忽略溢出)

使用AVX内在函数,其中[...,...]是一个8位整数,a,b,c,d是4位整数?

如果是的话,是否有可能举一个简短的例子说明它如何起作用?

cht*_*htz 5

只是部分答案(仅添加)和伪代码(应该很容易扩展到AVX2内在函数):

uint8_t a, b;          // input containing two nibbles each

uint8_t c = a + b;     // add with (unwanted) carry between nibbles
uint8_t x = a ^ b ^ c; // bits which are result of a carry
x &= 0x10;             // only bit 4 is of interest
c -= x;                // undo carry of lower to upper nibble
Run Code Online (Sandbox Code Playgroud)

如果已知ab未知第4位未设置(即上半字节的最低位),则可以省略其计算x.

至于乘法:scale对于所有产品,如果相同,你可以通过一些移位和加/减来消除(在必要时屏蔽溢出位).否则,我担心你需要掩盖每个16位字的4位,进行操作,并在最后将它们拼凑在一起.伪码(没有AVX 8bit乘法,所以我们需要用16bit字操作):

uint16_t m0=0xf, m1=0xf0, m2=0xf00, m3=0xf000; // masks for each nibble

uint16_t a, b; // input containing 4 nibbles each.

uint16_t p0 = (a*b) & m0; // lowest nibble, does not require masking a,b
uint16_t p1 = ((a>>4) * (b&m1)) & m1;
uint16_t p2 = ((a>>8) * (b&m2)) & m2;
uint16_t p3 = ((a>>12)* (b&m3)) & m3;

uint16_t result = p0 | p1 | p2 | p3;  // join results together 
Run Code Online (Sandbox Code Playgroud)

  • SWAR添加的好方法.这是'VPADDB'之后的4个额外操作(2个VPXOR,1个VPAND,一个VPSUBB).第一个xor可以与add并行运行,因此总延迟= 4c.显而易见的替代方案是屏蔽高低半字节的OR和OR:低半字节的VPADB + VPAND(屏蔽输出),高半字节的2xVPAND + VPADB(屏蔽输入).然后VPOR合并.延迟= 3c,uops = 6总计,或者不仅仅是一个VPADDB.因此,你的方法减少了1个uop,但是dep链的长度增加了1.所以它很适合循环遍历循环迭代是独立的两个数组. (2认同)