使用ARM指令查找数组的最小值和最大值
我有下面的代码,我想使用ARM NEON指令对其进行优化。我如何实现它? 谢谢你的回答使用ARM指令查找数组的最小值和最大值,arm,neon,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 = s
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];
}
}
unsigned char someVector[]={1,2,4,1,2,0,8,100};
无符号字符maxVal=0,minVal=255;
对于(int i=0;imaxVal)
{
maxVal=someVector[i];
}
}
下面是一个高度优化的示例,介绍如何在大型数组中查找最小值和最大值。如果大小小于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
返回值为无符号整数。低16位包含最小值,高16位包含最大值:
result = minmax(pSrc, size);
min = result & 0xff;
max = result >> 16;
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;
}
或
如果您编写NEON Intrinsic或assembler,您可以比GCC做得更好。您可以在infocenter.arm.com下载组装手册。然后您可以查看说明“vmin”和“vmax”,谢谢您的评论。我知道vmin和vmax,但它们在两个寄存器中比较每个通道。然后我将有8个值的最小值和最大值成对,但不是所有的值,剩下的将是三个连续的vpmin和vpmax。但是,最好使用ARM integer core执行此操作,因为指令延迟将严重削弱性能。NEON一开始并不打算处理这么小的数据。谢谢Jake。实际上我的数组是图像,someVector只是一个例子,很抱歉混淆了。因此,阵列要长得多。对于一个图像,你会在8像素的基础上调用vmin和vmax,最后调用三次vpmin和vpmax吗?我的代码一次调用16字节。(q寄存器),每次迭代执行128字节。看起来您正试图让它与intrinsic一起工作,但速度甚至不及上述汇编版本的一半。@Jake'Alquimista'LEE为什么您的PLD+64*3和+64*4?“pSrc”不是下一个要加载的地址吗?为什么不预加载pSrc本身呢?我可以连续使用两个不同寄存器的pld来提高速度吗?这里没有任何有用的文档。谢谢查尔斯,不幸的是我和WinCE工作,而不是GCC。@ Zoli认为自己是幸运的:MS的ARM编译器比GCC更好。
$ 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