2

在一个循环中,我必须实现一种剪辑

if ( isLast )
{
    val = ( val < 0 ) ? 0 : val;
    val = ( val > 255 ) ? 255 : val;        
}

然而,这种“剪辑”几乎占据了Neon 循环执行时间的一半。这就是整个循环的样子——

for (row = 0; row < height; row++)
{
  for (col = 0; col < width; col++)
  {
      Int sum;
      //...Calculate the sum
   
      Short val = ( sum + offset ) >> shift;
      if ( isLast )
      {
           val = ( val < 0 ) ? 0 : val;
           val = ( val > 255 ) ? 255 : val;        
      }
      dst[col] = val;
   }

}

这就是在Neon中实现剪辑的方式

     cmp       %10,#1                           //if(isLast)         
     bne       3f                                         
     vmov.i32   %4, d4[0]                       //put val in %4
     cmp       %4,#0                            //if( val < 0 )
     blt       4f                               
     b         5f                               
     4:                                         
     mov       %4,#0                             
     vmov.i32   d4[0],%4                        
     5:                                         
     cmp       %4,%11                          //if( val > maxVal )
     bgt       6f                               
     b         3f                               
     6:                                         
     mov       %4,%11                            
     vmov.i32   d4[0],%4                       
     3:  

     

这是变量到寄存器的映射-

isLast-    %10
maxVal-    %11

有什么建议可以让它更快吗?谢谢

编辑-

剪辑现在看起来像 -

     "cmp       %10,#1                            \n\t"//if(isLast)      
     "bne       3f                                \n\t"          
     "vmin.s32   d4,d4,d13                        \n\t"
     "vmax.s32   d4,d4,d12                        \n\t"
     "3:                                          \n\t" 

//d13 contains maxVal(255)
//d12 contains 0

这部分代码消耗的时间从223ms 下降到了 18ms

4

2 回答 2

8

对 NEON 使用普通比较几乎总是一个坏主意,因为它强制 NEON 寄存器的内容进入通用 ARM 寄存器,这会花费很多周期。

您可以使用 vmin 和 vmax NEON 指令。这是一个将整数数组限制为任何最小值/最大值的小示例。

void clampArray (int minimum,
                 int maximum,
                 int * input,
                 int * output,
                 int numElements)
{
  // get two NEON values with your minimum and maximum in each lane:
  int32x2_t lower  = vdup_n_s32 (minimum);
  int32x2_t higher = vdup_n_s32 (maximum);
  int i;

  for (i=0; i<numElements; i+=2)
  {
    // load two integers
    int32x2_t x = vld1_s32 (&input[i]);

    // clamp against maximum:
    x = vmin_s32 (x, higher);

    // clamp against minimum
    x = vmax_s32 (x, lower);

    // store two integers
    vst1_s32 (&output[i], x);
  }
} 

警告:此代码假定 numElements 始终是 2 的倍数,我尚未对其进行测试。

如果您使用 vminq / vmaxq 指令一次处理四个元素并在每次迭代中加载/存储四个整数,您甚至可以使其更快。

于 2012-07-17T08:45:09.257 回答
3

如果 maxVal 是 UCHAR_MAX、CHAR_MAX、SHORT_MAX 或 USHORT_MAX,您可以简单地使用 neon 从 int 转换为您想要的数据类型,通过饱和转换。

举例

// Will convert four int32 values to signed short values, with saturation.
int16x4_t vqmovn_s32 (int32x4_t) 

// Converts signed short to unsgigned char, with saturation
uint8x8_t vqmovun_s16 (int16x8_t) 

如果您不想使用多数据功能,您仍然可以通过简单地加载和读取其中一条通道来使用这些指令。

于 2012-07-17T06:33:11.580 回答