矩阵转置的SSE汇编优化艺术以及ARM cortext 汇编优化

10 篇文章 0 订阅

转至http://blog.csdn.net/feixiang_john/article/details/8438658

平时我们做图像处理或者视频处理, 很多地方会用到矩阵转置:

比如: DCT变换, 图像旋转, 图像滤波, 以及一些数据的内存行和列的交换等, 会大量使用转置这个动作.

然而由于数据量很大,处理速度很慢!如何来提高处理速度呢?

下面看看分析: 

HEVC中有个地方是如下这样实现(直接行和列对应的位置交换):

  1. Pel  tmp;  
  2. for (k=0;k<blkSize-1;k++)  
  3. {  
  4.   for (l=k+1;l<blkSize;l++)  
  5.   {  
  6.     tmp                 = pDst[k*dstStride+l];  
  7.     pDst[k*dstStride+l] = pDst[l*dstStride+k];  
  8.     pDst[l*dstStride+k] = tmp;  
  9.   }  
  10. }  


 

如何用汇编来实现呢?

我们先用SSE汇编来实现一个8X8的矩阵转置吧: 这里输入地址pSrc_128[i] 和输出地址pDst_128[i]可以相同也可以不同:

相同的话就是原地转置, 不同的话就是非原地转置.

  1.   __m128i* m_pSrc_tmp = pSrc_128[i];  
  2.   __m128i* m_pDst_tmp = pDst_128[i];  
  3.   __m128i Org_8_0,Org_8_1, Org_8_2, Org_8_3;  
  4.   __m128i tttt1,tttt2,tttt3,tttt4,tttt33,tttt44;  
  5.   __m128i tttt5,tttt6, tttt7, tttt8;  
  6.   int stride_ii = dstStride>>3;  
  7. //one  
  8.   Org_8_0 = _mm_load_si128(m_pSrc_tmp);  
  9.   m_pSrc_tmp+=8;  
  10.   Org_8_1 = _mm_load_si128(m_pSrc_tmp);  
  11.   m_pSrc_tmp+=8;  
  12.   Org_8_2 = _mm_load_si128(m_pSrc_tmp);  
  13.   m_pSrc_tmp+=8;  
  14.   Org_8_3 = _mm_load_si128(m_pSrc_tmp);  
  15.   m_pSrc_tmp+=8;  
  16.   
  17.   tttt1 = _mm_unpacklo_epi16(Org_8_0, Org_8_1);  
  18.   tttt2 = _mm_unpacklo_epi16(Org_8_2, Org_8_3);  
  19.   tttt3 = _mm_unpackhi_epi16(Org_8_0, Org_8_1);  
  20.   tttt4 = _mm_unpackhi_epi16(Org_8_2, Org_8_3);  
  21.   
  22.   tttt5 = _mm_unpacklo_epi32(tttt1, tttt2);  
  23.   tttt6 = _mm_unpackhi_epi32(tttt1, tttt2);  
  24.   
  25.   Org_8_0 = _mm_load_si128(m_pSrc_tmp);  
  26.   m_pSrc_tmp+=8;;   
  27.   Org_8_1 = _mm_load_si128(m_pSrc_tmp);  
  28.   m_pSrc_tmp+=8;  
  29.   Org_8_2 = _mm_load_si128(m_pSrc_tmp);  
  30.   m_pSrc_tmp+=8;   
  31.   Org_8_3 = _mm_load_si128(m_pSrc_tmp);  
  32.   //m_pSrc_tmp+=8;  
  33.   
  34.   tttt1 = _mm_unpacklo_epi16(Org_8_0, Org_8_1);  
  35.   tttt2 = _mm_unpacklo_epi16(Org_8_2, Org_8_3);  
  36.   tttt33 = _mm_unpackhi_epi16(Org_8_0, Org_8_1);  
  37.   tttt44 = _mm_unpackhi_epi16(Org_8_2, Org_8_3);  
  38.   
  39.   tttt7 = _mm_unpacklo_epi32(tttt1, tttt2);  
  40.   tttt8 = _mm_unpackhi_epi32(tttt1, tttt2);  
  41.   
  42.   tttt1 = _mm_unpacklo_epi64(tttt5, tttt7);  
  43.   tttt2 = _mm_unpackhi_epi64(tttt5, tttt7);  
  44.   _mm_storeu_si128(m_pDst_tmp, tttt1);  
  45.   m_pDst_tmp+=stride_ii;  
  46.   _mm_storeu_si128(m_pDst_tmp, tttt2);  
  47.   m_pDst_tmp+=stride_ii;  
  48.   tttt5 = _mm_unpacklo_epi64(tttt6, tttt8);  
  49.   tttt7 = _mm_unpackhi_epi64(tttt6, tttt8);  
  50.   _mm_storeu_si128(m_pDst_tmp, tttt5);  
  51.   m_pDst_tmp+=stride_ii;  
  52.   _mm_storeu_si128(m_pDst_tmp, tttt7);  
  53.   m_pDst_tmp+=stride_ii;  
  54.   
  55. //tow  
  56.   tttt5 = _mm_unpacklo_epi32(tttt3, tttt4);  
  57.   tttt6 = _mm_unpackhi_epi32(tttt3, tttt4);  
  58.   
  59.   tttt7 = _mm_unpacklo_epi32(tttt33, tttt44);  
  60.   tttt8 = _mm_unpackhi_epi32(tttt33, tttt44);  
  61.   
  62.   tttt1 = _mm_unpacklo_epi64(tttt5, tttt7);  
  63.   tttt2 = _mm_unpackhi_epi64(tttt5, tttt7);  
  64.   _mm_storeu_si128(m_pDst_tmp, tttt1);  
  65.   m_pDst_tmp+=stride_ii;  
  66.   _mm_storeu_si128(m_pDst_tmp, tttt2);  
  67.   m_pDst_tmp+=stride_ii;  
  68.   tttt5 = _mm_unpacklo_epi64(tttt6, tttt8);  
  69.   tttt7 = _mm_unpackhi_epi64(tttt6, tttt8);  
  70.   _mm_storeu_si128(m_pDst_tmp, tttt5);  
  71.   m_pDst_tmp+=stride_ii;  
  72.   _mm_storeu_si128(m_pDst_tmp, tttt7);  


要实现的是NXN的转置,如何实现呢:

基于8X8来实现NXN的块或者图像的转置:

这里先把NXN划分为size_case 个8X8, 然后循环调用8X8的转置!

 

  1.  __m128i* pDst_128[64];  
  2.  __m128i* pSrc_128[64];  
  3.  int size_case = (blkSize>>3);  
  4.  dstStride = dstStride_tmp;  
  5.  for(int y = 0; y<size_case; y++)//对所有8x8的块进行地址映射  
  6.   for(int x = 0; x<size_case; x++)  
  7.   {  
  8.    pSrc_128[y*size_case + x] = (__m128i*)(pDst + 8*x + y*8*64);  
  9.    pDst_128[y*size_case + x] = (__m128i*)(rpDst + 8*y + x*8*dstStride);  
  10.   }  
  11.   
  12.  size_case = size_case*size_case;  
  13.  for(int  i = 0;i <size_case; i++)//开始转置  
  14.  {  
  15.   
  16.     8x8转置的代码:  
  17.   
  18. }  

通过比较, 用SSE汇编优化实现转置比用纯 C代码实现的转置速度快5倍左右! 

 

同样在ARM cortext上的汇编优化也是基于这个原理:

主要循环体代码如下:

  1. VTRN.16 q8, q9  
  2. VTRN.16 q10, q11  
  3. VTRN.16 q4, q5  
  4. VTRN.16 q6, q7  
  5. VTRN.32 q8, q10  
  6. VTRN.32 q9, q11  
  7. VTRN.32 q4, q6  
  8. VTRN.32 q5, q7  
  9. VSWP d17, d8  
  10. VSWP d19, d10  
  11. VSWP d21, d12  
  12. VSWP d23, d14     


感兴趣的可以自己调试下!

 

当然DSP上也是同样的方法, 只是涉及到的指令不同而已!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值