繁体   English   中英

MMX操作(加16bit没做)

[英]MMX operation (add 16bit is not done)

我得到了一些包含无符号字符的向量,这些字符代表帧中的像素。 我得到了这个 function 没有改进 MMX 的工作,但我很沮丧 MMX 不起作用......所以:

我需要添加两个无符号字符(总和需要作为 16 位而不是 8 位来完成,因为无符号字符从 0 到 255 已知)并将它们除以 2(右移 1)。 到目前为止我所做的代码如下,但值是错误的,adds_pu16 没有添加 16bit 只是 8:

  MM0 = _mm_setzero_si64();        //all zeros
  MM1 = TO_M64(lv1+k);             //first 8 unsigned chars
  MM2 = TO_M64(lv2+k);             //second 8 unsigned chars

  MM3 =_mm_unpacklo_pi8(MM0,MM1);  //get first 4chars from MM1 and add Zeros
  MM4 =_mm_unpackhi_pi8(MM0,MM1);  //get last 4chars from MM1 and add Zeros

  MM5 =_mm_unpacklo_pi8(MM0,MM2);  //same as above for line 2
  MM6 =_mm_unpackhi_pi8(MM0,MM2);

  MM1 = _mm_adds_pu16(MM3,MM5);    //add both chars as a 16bit sum (255+255 max range)
  MM2 = _mm_adds_pu16(MM4,MM6);

  MM3 = _mm_srai_pi16(MM1,1);      //right shift (division by 2)
  MM4 = _mm_srai_pi16(MM2,1);

  MM1 = _mm_packs_pi16(MM3,MM4);   //pack the 2 MMX registers into one

  v2 = TO_UCHAR(MM1);              //put results in the destination array

新进展:感谢那个king_nak:! 我写了一个我想要做的简单版本:


int main()
{
char A[8]={255,155,2,3,4,5,6,7};
char B[8]={255,155,2,3,4,5,6,7};
char C[8];
char D[8];
char R[8];

__m64* pA=(__m64*) A;

__m64* pB=(__m64*) B;

__m64* pC=(__m64*) C;

__m64* pD=(__m64*) D;

__m64* pR=(__m64*) R;

_mm_empty();

__m64 MM0 = _mm_setzero_si64();

__m64 MM1 = _mm_unpacklo_pi8(*pA,MM0);

__m64 MM2 = _mm_unpackhi_pi8(*pA,MM0);

__m64 MM3 = _mm_unpacklo_pi8(*pB,MM0);

__m64 MM4 = _mm_unpackhi_pi8(*pB,MM0);

__m64 MM5 = _mm_add_pi16(MM1,MM3);

__m64 MM6 = _mm_add_pi16(MM2,MM4);

printf("SUM:\n");

*pC= _mm_add_pi16(MM1,MM3);

*pD= _mm_add_pi16(MM2,MM4);

for(int i=0; i<8; i++) printf("\t%d ", (C[i])); printf("\n");

for(int i=0; i<8; i++) printf("\t%d ", D[i]); printf("\n");

printf("DIV:\n");

*pC= _mm_srai_pi16(MM5,1);

*pD= _mm_srai_pi16(MM6,1);

for(int i=0; i<8; i++) printf("\t%d ", (C[i])); printf("\n");

for(int i=0; i<8; i++) printf("\t%d ", D[i]); printf("\n");

MM1= _mm_srai_pi16(MM5,1);    
MM2= _mm_srai_pi16(MM6,1);

printf("Final Result:\n");
*pR= _mm_packs_pi16(MM1,MM2);
for(int i=0; i<8; i++) printf("\t%d ", (R[i])); printf("\n");

return(0);
}

结果是:

和:

-2  1   54  1   4   0   6   0 

8   0   10  0   12  0   14  0 

分区:

-1  0   -101    0   2   0   3   0 

4   0   5   0   6   0   7   0 

最后结果:

127     127     2   3   4   5   6   7 

好吧,小数字是可以的,而给出 127 的大数字是错误的。 这是一个问题,我做错了什么:s

您应该在_mm_unpacklo_pi8调用中切换操作数。 当您这样做时,值字节位于单词的较高字节中(例如AB00打包到AB00 )。 在加法和移位之后,这些值将大于0x7F ,因此通过 pack 指令饱和到该值。

使用切换操作数,对00AB之类的值进行数学运算,结果将适合有符号字节。

更新:
在您提供其他信息之后,我发现问题出在_mm_packs_pi16 这是汇编指令packsswb ,它将使有符号字节饱和 例如,值 > 127 将设置为 127。 (255+255)>>1是 255,并且(155+155)>>1是 155...
请改用_mm_packs_pu16 这会将值视为无符号字节,并且您会得到所需的结果 (255/155)。

我想我发现了问题:解包指令的 arguments 顺序错误。 如果您将寄存器作为一个整体来看,看起来各个字符都零扩展为短裤,但实际上,它们是零填充的。 只需在每种情况下交换 mm0 和其他寄存器,它就可以工作。

此外,您不需要饱和添加,普通的 PADDW 就足够了。 您将获得的最大值是 0xff+0xff=0x01fe,不必饱和。

编辑:更重要的是,PACKSSWB 并不能完全满足您的要求。 PACKUSWB 是正确的指令,饱和会得到错误的结果。

这是一个解决方案(还用逻辑移位替换了移位,并在某些地方使用了不同的伪寄存器):

mm0=pxor(mm0,mm0) =[00,00,00,00,00,00,00,00]
mm1 =[a0,10,ff,18,7f,f0,ff,cc]
mm2 =[c0,20,ff,00,70,26,ff,01]
mm3=punpcklbw(mm1,mm0) =[00a0,0010,00ff,0018]
mm4=punpckhbw(mm1,mm0) =[007f,00f0,00ff,00cc]
mm5=punpcklbw(mm2,mm0) =[00c0,0020,00ff,0000]
mm6=punpckhbw(mm2,mm0) =[0070,0026,00ff,0001]
mm5=paddw(mm3,mm5) =[0160,0030,01fe,0018]
mm6=paddw(mm4,mm6) =[00ef,0116,01fe,00cd]
mm3=psrlwi(mm5,1) =[00b0,0018,00ff,000c]
mm4=psrlwi(mm6,1) =[0077,008b,00ff,0066]
mm1=packuswb(mm3,mm4) =[b0,18,ff,0c,77,8b,ff,66]

顺便说一句,您不需要 16 位中间值来计算两个 8 位值的平均值。 配方:

(a >> 1) + (b >> 1) + (a & b & 1)

只需要 8 位中间值即可给出正确的结果。 如果您有 8 位向量指令可用,也许您可以利用它来提高吞吐量。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM