使用ARM NEON指令查找数组的最小值和最大值

时间:2014-10-28 14:36:34

标签: arm neon

我有以下代码,我想使用ARM NEON指令进行优化。我该如何实现它? 谢谢你的回答

unsigned char someVector[] = {1, 2, 4, 1, 2, 0, 8, 100};
unsigned char maxVal = 0, minVal = 255;
for (int i = 0; i < sizeof(someVector); i++)
{
    if (someVector[i] < minVal)
    {
        minVal = someVector[i];
    }
    else if (someVector[i] > maxVal)
    {
        maxVal = someVector[i];
    }
}

2 个答案:

答案 0 :(得分:1)

以下是如何在大型数组中查找min和max的高度优化示例。如果size小于128,则函数返回:

/*
 * minmax.S
 *
 *  Created on: 2014. 10. 29.
 *      Author: Jake Lee
 */


// unsigned int minmax(unsigned char *pSrc, unsigned int size);

    .text
    .arm
    .global minmax

    pSrc    .req    r0
    size    .req    r1

    qmin1   .req    q0
        dmina   .req    d0
        dminb   .req    d1

    qmax1   .req    q1
        dmaxa   .req    d2
        dmaxb   .req    d3

    qmin2   .req    q2
    qmax2   .req    q3

    .align 5
    .func
minmax:
    subs    size, size, #128
    bxmi    lr
    vmov.i8     qmin1, #0xff
    vmov.i8     qmax1, #0
    vmov.i8     qmin2, #0xff
    vmov.i8     qmax2, #0

    .align 5
1:
    vld1.8      {q8, q9}, [pSrc]!
    vld1.8      {q10, q11}, [pSrc]!
    vld1.8      {q12, q13}, [pSrc]!
    vld1.8      {q14, q15}, [pSrc]!
    subs    size, size, #128
    pld     [pSrc, #64*3]
    pld     [pSrc, #64*4]
    vmin.u8     qmin1, q8
    vmax.u8     qmax1, q8
    vmin.u8     qmin2, q9
    vmax.u8     qmax2, q9
    vmin.u8     qmin1, q10
    vmax.u8     qmax1, q10
    vmin.u8     qmin2, q11
    vmax.u8     qmax2, q11
    vmin.u8     qmin1, q12
    vmax.u8     qmax1, q12
    vmin.u8     qmin2, q13
    vmax.u8     qmax2, q13
    vmin.u8     qmin1, q14
    vmax.u8     qmax1, q14
    vmin.u8     qmin2, q15
    vmax.u8     qmax2, q15
    bpl     1b

// deal width residuals (size % 128)
    cmp     size, #-128
    addgt   pSrc, pSrc, size
    bgt     1b

// shrink to sixteen
    vmin.u8     qmin1, qmin2
    vmax.u8     qmax1, qmax2
// shrink to eight
    vpmin.u8    dmina, dmina, dminb
    vpmax.u8    dmaxa, dmaxa, dmaxb
// shrink to four
    vpmin.u8    dmina, dmina, dminb
    vpmax.u8    dmaxa, dmaxa, dmaxb
// shrink to two
    vpmin.u8    dmina, dmina, dminb
    vpmax.u8    dmaxa, dmaxa, dmaxb
// shrink to one
    vpmin.u8    dmina, dmina, dminb
    vpmax.u8    dmaxa, dmaxa, dmaxb

    vmov    r0, dmina[0]
    vmov    r1, dmaxa[0]

    and     r0, r0, #0xff
    and     r1, r1, #0xff
    orr     r0, r0, r1, lsl #16
    bx      lr
    .endfunc
    .end

返回值是unsigned int。低16位包含最小值和高值max:

result = minmax(pSrc, size);
min = result & 0xff;
max = result >> 16;

答案 1 :(得分:1)

GCC将自动对其进行矢量化,只需稍加修改。

unsigned char someVector[256] = { 1, 2, 4, 1, 2, 0, 8, 100 };
unsigned char maxVal = 0, minVal = 255;

void f(void)
{
    unsigned char mn = 255, mx = 0;
    for (int i = 0; i < sizeof(someVector); i++) {
        if (someVector[i] < mn) {
            mn = someVector[i];
        }
        if (someVector[i] > mx) {
            mx = someVector[i];
        }
    }
    maxVal = mx;
    minVal = mn;
}

编译
$ arm-unknown-linux-gnueabihf-gcc -O3 -std=c11 -mfpu=neon -c test.c

$ arm-unknown-linux-gnueabihf-gcc -O2 -ftree-vectorize -std=c11 -mfpu=neon -c test.c

如果您编写NEON内在函数或汇编程序,则可以比GCC做得更好。