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

原创 2012年12月27日 09:19:45

 

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

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

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

下面看看分析: 

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

      Pel  tmp;
      for (k=0;k<blkSize-1;k++)
      {
        for (l=k+1;l<blkSize;l++)
        {
          tmp                 = pDst[k*dstStride+l];
          pDst[k*dstStride+l] = pDst[l*dstStride+k];
          pDst[l*dstStride+k] = tmp;
        }
      }


 

如何用汇编来实现呢?

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

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

  __m128i* m_pSrc_tmp = pSrc_128[i];
  __m128i* m_pDst_tmp = pDst_128[i];
  __m128i Org_8_0,Org_8_1, Org_8_2, Org_8_3;
  __m128i tttt1,tttt2,tttt3,tttt4,tttt33,tttt44;
  __m128i tttt5,tttt6, tttt7, tttt8;
  int stride_ii = dstStride>>3;
//one
  Org_8_0 = _mm_load_si128(m_pSrc_tmp);
  m_pSrc_tmp+=8;
  Org_8_1 = _mm_load_si128(m_pSrc_tmp);
  m_pSrc_tmp+=8;
  Org_8_2 = _mm_load_si128(m_pSrc_tmp);
  m_pSrc_tmp+=8;
  Org_8_3 = _mm_load_si128(m_pSrc_tmp);
  m_pSrc_tmp+=8;

  tttt1 = _mm_unpacklo_epi16(Org_8_0, Org_8_1);
  tttt2 = _mm_unpacklo_epi16(Org_8_2, Org_8_3);
  tttt3 = _mm_unpackhi_epi16(Org_8_0, Org_8_1);
  tttt4 = _mm_unpackhi_epi16(Org_8_2, Org_8_3);

  tttt5 = _mm_unpacklo_epi32(tttt1, tttt2);
  tttt6 = _mm_unpackhi_epi32(tttt1, tttt2);

  Org_8_0 = _mm_load_si128(m_pSrc_tmp);
  m_pSrc_tmp+=8;; 
  Org_8_1 = _mm_load_si128(m_pSrc_tmp);
  m_pSrc_tmp+=8;
  Org_8_2 = _mm_load_si128(m_pSrc_tmp);
  m_pSrc_tmp+=8; 
  Org_8_3 = _mm_load_si128(m_pSrc_tmp);
  //m_pSrc_tmp+=8;

  tttt1 = _mm_unpacklo_epi16(Org_8_0, Org_8_1);
  tttt2 = _mm_unpacklo_epi16(Org_8_2, Org_8_3);
  tttt33 = _mm_unpackhi_epi16(Org_8_0, Org_8_1);
  tttt44 = _mm_unpackhi_epi16(Org_8_2, Org_8_3);

  tttt7 = _mm_unpacklo_epi32(tttt1, tttt2);
  tttt8 = _mm_unpackhi_epi32(tttt1, tttt2);

  tttt1 = _mm_unpacklo_epi64(tttt5, tttt7);
  tttt2 = _mm_unpackhi_epi64(tttt5, tttt7);
  _mm_storeu_si128(m_pDst_tmp, tttt1);
  m_pDst_tmp+=stride_ii;
  _mm_storeu_si128(m_pDst_tmp, tttt2);
  m_pDst_tmp+=stride_ii;
  tttt5 = _mm_unpacklo_epi64(tttt6, tttt8);
  tttt7 = _mm_unpackhi_epi64(tttt6, tttt8);
  _mm_storeu_si128(m_pDst_tmp, tttt5);
  m_pDst_tmp+=stride_ii;
  _mm_storeu_si128(m_pDst_tmp, tttt7);
  m_pDst_tmp+=stride_ii;

//tow
  tttt5 = _mm_unpacklo_epi32(tttt3, tttt4);
  tttt6 = _mm_unpackhi_epi32(tttt3, tttt4);

  tttt7 = _mm_unpacklo_epi32(tttt33, tttt44);
  tttt8 = _mm_unpackhi_epi32(tttt33, tttt44);

  tttt1 = _mm_unpacklo_epi64(tttt5, tttt7);
  tttt2 = _mm_unpackhi_epi64(tttt5, tttt7);
  _mm_storeu_si128(m_pDst_tmp, tttt1);
  m_pDst_tmp+=stride_ii;
  _mm_storeu_si128(m_pDst_tmp, tttt2);
  m_pDst_tmp+=stride_ii;
  tttt5 = _mm_unpacklo_epi64(tttt6, tttt8);
  tttt7 = _mm_unpackhi_epi64(tttt6, tttt8);
  _mm_storeu_si128(m_pDst_tmp, tttt5);
  m_pDst_tmp+=stride_ii;
  _mm_storeu_si128(m_pDst_tmp, tttt7);


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

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

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

 

  __m128i* pDst_128[64];
  __m128i* pSrc_128[64];
  int size_case = (blkSize>>3);
  dstStride = dstStride_tmp;
  for(int y = 0; y<size_case; y++)//对所有8x8的块进行地址映射
   for(int x = 0; x<size_case; x++)
   {
    pSrc_128[y*size_case + x] = (__m128i*)(pDst + 8*x + y*8*64);
    pDst_128[y*size_case + x] = (__m128i*)(rpDst + 8*y + x*8*dstStride);
   }

  size_case = size_case*size_case;
  for(int  i = 0;i <size_case; i++)//开始转置
  {

     8x8转置的代码:

 }

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

 

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

主要循环体代码如下:

	VTRN.16 q8, q9
	VTRN.16 q10, q11
	VTRN.16 q4, q5
	VTRN.16 q6, q7
	VTRN.32 q8, q10
	VTRN.32 q9, q11
	VTRN.32 q4, q6
	VTRN.32 q5, q7
	VSWP d17, d8
	VSWP d19, d10
	VSWP d21, d12
	VSWP d23, d14	


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

 

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

 

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

SIMD(MMX/SSE/AVX)变量命名规范心得

【转载】:SIMD(MMX/SSE/AVX)变量命名规范心得 当使用Intrinsics函数来操作SIMD指令集(MMX/SSE/AVX等)时,会面对不同长度的SIMD数据类型,其中又分为多...
  • Real_Myth
  • Real_Myth
  • 2016年03月08日 16:41
  • 1601

sse转neon

sse转neon
  • jacke121
  • jacke121
  • 2017年02月16日 16:30
  • 1654

ARM NEON 指令

在初学NDK时,接触到 HelloNeon例程,了解到 Neon是ARMv7-AR 系列中引入的并行模块,可以让你同时操作8个16位数据或4个32位数据,在信号处理,图像处理,视频编解码优化方面有很高...
  • Tonyfield
  • Tonyfield
  • 2013年02月21日 11:25
  • 9878

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

原文地址:http://blog.csdn.net/feixiang_john/article/details/8438658 平时我们做图像处理或者视频处理, 很多地方会用到矩阵转置: 比如: ...
  • HEVC_CJL
  • HEVC_CJL
  • 2013年01月03日 14:05
  • 2415

ARM处理器NEON编程及优化技巧——矩阵乘法的实例

ARM的NEON协处理器技术是一个64/128-bit的混合SIMD架构,用于加速包括视频编码解码、音频解码编码、3D图像、语音和图像等多媒体和信号处理应用。本文主要介绍如何使用NEON的汇编程序来写...
  • ceasar11
  • ceasar11
  • 2014年02月19日 11:47
  • 1994

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

原文地址:http://blog.csdn.net/feixiang_john/article/details/8438658 平时我们做图像处理或者视频处理, 很多地方会用到矩阵转置: 比如: ...
  • HEVC_CJL
  • HEVC_CJL
  • 2013年01月03日 14:05
  • 2415

单数据多指令(SIMD) MMX SSE AVX

概述 SIMD是指单指令多数据技术,它已经成为Intel处理器的重要性能扩展。目前Intel处理器支持的SIMD技术包括MMX,SSE,AVX. MMX提供了8个64bit的寄存器进行SIMD操作,S...
  • dellme99
  • dellme99
  • 2013年12月30日 11:07
  • 2548

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

转至http://blog.csdn.net/feixiang_john/article/details/8438658 平时我们做图像处理或者视频处理, 很多地方会用到矩阵转置: 比...
  • DiffenYu
  • DiffenYu
  • 2013年01月05日 12:48
  • 768

使用MMX/SSE汇编指令集优化视频开发

1、汇编指令集 目前大部分的PC机采用的都是Intel或者AMD的CPU,其支持的多媒体汇编指令有: MMX:多媒体扩展指令(MultiMedia eXtention),该指令由Intel在1996年...
  • shaqoneal
  • shaqoneal
  • 2015年05月26日 17:16
  • 2350

一个卓有成效的汇编优化范例--使用SSE2指令优化进制转化

本文通过一个64位整数转化为16进制字符串的函数,讲述程序优化的的一些方法。本文包括3个C语言的版本和1个SSE2汇编的版本。性能最强的SSE2版本的性能竟达原始C版函数的性能的21倍。...
  • liangbch
  • liangbch
  • 2015年08月05日 22:10
  • 1222
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:矩阵转置的SSE汇编优化艺术以及ARM cortext 汇编优化
举报原因:
原因补充:

(最多只允许输入30个字)