Embedded 对于霓虹灯优化,gcc或armcc哪个更好?
这里参考@auselen的答案:,看起来armcc编译器在NEON优化方面比gcc编译器要好得多。这是真的吗?我还没有真正尝试过armcc编译器。但是我使用带有-O3优化标志的gcc编译器得到了非常优化的代码。但现在我想知道armcc是否真的那么好?那么,考虑到所有因素,这两个编译器中哪一个更好呢?如果您使用NEON Intrinsic,编译器应该没有那么重要。大多数(如果不是全部的话)NEON内部函数都转换为一条NEON指令,因此编译器只剩下寄存器分配和指令调度。根据我的经验,GCC4.2和Clang3.1在这些任务上都做得相当好 然而,请注意,霓虹灯指令比霓虹灯指令更具表现力。例如,NEON加载/存储指令具有增量前和增量后寻址模式,该模式将加载或存储与地址寄存器的增量相结合,从而为您节省一条指令。NEON intrinsic没有提供一种明确的方法来实现这一点,而是依赖于编译器将reguler NEON加载/存储内部函数和地址增量结合到加载/存储指令和post增量中。类似地,某些加载/存储指令允许您指定内存地址的对齐方式,如果指定更严格的对齐保证,则执行速度更快。NEON内部函数同样不允许显式指定对齐方式,而是依赖编译器推断正确的对齐说明符。理论上,您可以在指针上使用“align”属性为编译器提供合适的提示,但至少Clang似乎忽略了这些 根据我的经验,当涉及到这些类型的优化时,无论是Clang还是GCC都不是很聪明。幸运的是,这类优化带来的额外性能好处通常并不是那么高——它更像是10%而不是100% 这两个编译器不是特别聪明的另一个领域是避免堆栈溢出。如果你的代码使用的向量值变量比NEON寄存器多,我觉得这两个编译器产生的代码都很糟糕。基本上,他们似乎是基于有足够可用寄存器的假设来调度指令。寄存器分配似乎是在之后进行的,并且似乎只是在堆栈运行寄存器后将值溢出到堆栈中。因此,请确保您的代码在任何时候都具有小于16 128位向量或32 64位向量的工作集 总的来说,我已经从GCC和Clang中获得了相当好的结果,但是我经常不得不重新组织代码以避免编译器的特性。我的建议是坚持使用GCC或Clang,但是定期与您选择的disassembler一起检查Embedded 对于霓虹灯优化,gcc或armcc哪个更好?,embedded,arm,simd,neon,cortex-a8,Embedded,Arm,Simd,Neon,Cortex A8,这里参考@auselen的答案:,看起来armcc编译器在NEON优化方面比gcc编译器要好得多。这是真的吗?我还没有真正尝试过armcc编译器。但是我使用带有-O3优化标志的gcc编译器得到了非常优化的代码。但现在我想知道armcc是否真的那么好?那么,考虑到所有因素,这两个编译器中哪一个更好呢?如果您使用NEON Intrinsic,编译器应该没有那么重要。大多数(如果不是全部的话)NEON内部函数都转换为一条NEON指令,因此编译器只剩下寄存器分配和指令调度。根据我的经验,GCC4.2和C
所以,总的来说,我认为坚持GCC是好的。不过,您可能需要查看性能关键部件的组装情况,并检查其是否合理。编译器也是软件,它们往往会随着时间的推移而改进。任何像armcc这样的通用声明都比霓虹灯上的GCC好(或者更好地说是矢量化)不可能永远成立,因为一个开发小组可以通过足够的关注来缩小差距。然而,一开始,期望硬件公司开发的编译器更优秀是合乎逻辑的,因为他们需要展示/推广这些功能 我最近看到的一个例子是关于堆栈溢出的。引用更新部分最后一行的话“这表明,即使是成熟的现代编译器,在优化代码的能力上也可能存在很大差异……” 我是GCC的忠实粉丝,但我不会拿GCC产生的代码质量与英特尔或ARM的编译器打赌。我希望任何主流的商业编译器产生的代码至少和GCC一样好 对这个问题的一个实证答案可能是使用不同的编译器,看看它们是如何优化的
void neon_convert (uint8_t * __restrict dest, uint8_t * __restrict src, int n)
{
int i;
uint8x8_t rfac = vdup_n_u8 (77);
uint8x8_t gfac = vdup_n_u8 (151);
uint8x8_t bfac = vdup_n_u8 (28);
n/=8;
for (i=0; i<n; i++)
{
uint16x8_t temp;
uint8x8x3_t rgb = vld3_u8 (src);
uint8x8_t result;
temp = vmull_u8 (rgb.val[0], rfac);
temp = vmlal_u8 (temp,rgb.val[1], gfac);
temp = vmlal_u8 (temp,rgb.val[2], bfac);
result = vshrn_n_u16 (temp, 8);
vst1_u8 (dest, result);
src += 8*3;
dest += 8;
}
}
void neon\u convert(uint8\u t*\u restrict dest,uint8\u t*\u restrict src,int n)
{
int i;
uint8x8_t rfac=vdup_n_u8(77);
uint8x8_t gfac=vdup_n_u8(151);
uint8x8\u t bfac=vdup\u u8(28);
n/=8;
对于(i=0;与标量整数/fp支持相比,gcc中的NEON支持还不够成熟。然而,auselen的比较是基于2.5年前发布的gcc 4.4.3。从那时起,NEON改进方面做了相当多的工作。同时,armcc 5.01只有一年的历史。虽然我仍然希望armcc 5.02领先,但更相关的comparison将介于它和4.7 gcc之间。@unixsmurf+1中的一个是我:)尝试在gcc中使用“-marm”标志,thumb代码在gcc中还不太成熟,对于Cortex-A9.Hmm中的thumb2单元更是如此,正如预期的那样,寄存器溢出在gcc中非常广泛。
20: f421140d vld3.8 {d1-d3}, [r1]!
24: e2822001 add r2, r2, #1
28: f3810c04 vmull.u8 q0, d1, d4
2c: f3820805 vmlal.u8 q0, d2, d5
30: f3830806 vmlal.u8 q0, d3, d6
34: f2880810 vshrn.i16 d0, q0, #8
38: f400070d vst1.8 {d0}, [r0]!
3c: e1520003 cmp r2, r3
40: bafffff6 blt 20 <neon_convert+0x20>
1e: f961 040d vld3.8 {d16-d18}, [r1]!
22: 3301 adds r3, #1
24: 4293 cmp r3, r2
26: ffc0 4ca3 vmull.u8 q10, d16, d19
2a: ffc1 48a6 vmlal.u8 q10, d17, d22
2e: ffc2 48a7 vmlal.u8 q10, d18, d23
32: efc8 4834 vshrn.i16 d20, q10, #8
36: f940 470d vst1.8 {d20}, [r0]!
3a: d1f0 bne.n 1e <neon_convert+0x1e>
void neonPermuteRGBtoBGRA(unsigned char* src, unsigned char* dst, int numPix)
{
numPix /= 8; //process 8 pixels at a time
uint8x8_t alpha = vdup_n_u8 (0xff);
for (int i=0; i<numPix; i++)
{
uint8x8x3_t rgb = vld3_u8 (src);
uint8x8x4_t bgra;
bgra.val[0] = rgb.val[2]; //these lines are slow
bgra.val[1] = rgb.val[1]; //these lines are slow
bgra.val[2] = rgb.val[0]; //these lines are slow
bgra.val[3] = alpha;
vst4_u8(dst, bgra);
src += 8*3;
dst += 8*4;
}
}
$ arm-linux-gnueabihf-gcc --version
arm-linux-gnueabihf-gcc (crosstool-NG linaro-1.13.1-2012.05-20120523 - Linaro GCC 2012.05) 4.7.1 20120514 (prerelease)
$ arm-linux-gnueabihf-gcc -std=c99 -O3 -c ~/temp/permute.c -marm -mfpu=neon-vfpv4 -mcpu=cortex-a9 -o ~/temp/permute_gcc.o
00000000 <neonPermuteRGBtoBGRA>:
0: e3520000 cmp r2, #0
4: e2823007 add r3, r2, #7
8: b1a02003 movlt r2, r3
c: e92d01f0 push {r4, r5, r6, r7, r8}
10: e1a021c2 asr r2, r2, #3
14: e24dd01c sub sp, sp, #28
18: e3520000 cmp r2, #0
1c: da000019 ble 88 <neonPermuteRGBtoBGRA+0x88>
20: e3a03000 mov r3, #0
24: f460040d vld3.8 {d16-d18}, [r0]!
28: eccd0b06 vstmia sp, {d16-d18}
2c: e59dc014 ldr ip, [sp, #20]
30: e2833001 add r3, r3, #1
34: e59d6010 ldr r6, [sp, #16]
38: e1530002 cmp r3, r2
3c: e59d8008 ldr r8, [sp, #8]
40: e1a0500c mov r5, ip
44: e59dc00c ldr ip, [sp, #12]
48: e1a04006 mov r4, r6
4c: f3c73e1f vmov.i8 d19, #255 ; 0xff
50: e1a06008 mov r6, r8
54: e59d8000 ldr r8, [sp]
58: e1a0700c mov r7, ip
5c: e59dc004 ldr ip, [sp, #4]
60: ec454b34 vmov d20, r4, r5
64: e1a04008 mov r4, r8
68: f26401b4 vorr d16, d20, d20
6c: e1a0500c mov r5, ip
70: ec476b35 vmov d21, r6, r7
74: f26511b5 vorr d17, d21, d21
78: ec454b34 vmov d20, r4, r5
7c: f26421b4 vorr d18, d20, d20
80: f441000d vst4.8 {d16-d19}, [r1]!
84: 1affffe6 bne 24 <neonPermuteRGBtoBGRA+0x24>
88: e28dd01c add sp, sp, #28
8c: e8bd01f0 pop {r4, r5, r6, r7, r8}
90: e12fff1e bx lr
$ armcc
ARM C/C++ Compiler, 5.01 [Build 113]
$ armcc --C99 --cpu=Cortex-A9 -O3 -c permute.c -o permute_arm.o
00000000 <neonPermuteRGBtoBGRA>:
0: e1a03fc2 asr r3, r2, #31
4: f3870e1f vmov.i8 d0, #255 ; 0xff
8: e0822ea3 add r2, r2, r3, lsr #29
c: e1a031c2 asr r3, r2, #3
10: e3a02000 mov r2, #0
14: ea000006 b 34 <neonPermuteRGBtoBGRA+0x34>
18: f420440d vld3.8 {d4-d6}, [r0]!
1c: e2822001 add r2, r2, #1
20: eeb01b45 vmov.f64 d1, d5
24: eeb02b46 vmov.f64 d2, d6
28: eeb05b40 vmov.f64 d5, d0
2c: eeb03b41 vmov.f64 d3, d1
30: f401200d vst4.8 {d2-d5}, [r1]!
34: e1520003 cmp r2, r3
38: bafffff6 blt 18 <neonPermuteRGBtoBGRA+0x18>
3c: e12fff1e bx lr