
Michael Marcin wrote:
Phil Endecott wrote:
Guillaume Melquiond wrote:
#include <algorithm>
std::pair<unsigned, bool> full_add(unsigned a, unsigned b) { return std::make_pair(a + b, a + b < a); }
bool no_overflow(unsigned a, unsigned b) { return !full_add(a, b).second; }
Here's what I get on ARM:
_Z8full_addjj: adds r2, r1, r2 movcc r1, #0 movcs r1, #1 str r2, [r0, #0] strb r1, [r0, #4] mov pc, lr
_Z11no_overflowjj: cmn r0, r1 movcs r0, #0 movcc r0, #1 mov pc, lr
RVCT 2.2 with --arm and -O2
Gives:
_Z8full_addjj PROC PUSH {r2,r3,lr} ADD r2,r1,r2 CMP r2,r1 MOVCS r1,#0 MOVCC r1,#1 STR r1,[sp,#0] STR r2,[sp,#4] STR r2,[r0,#0] LDRB r1,[sp,#0] STRB r1,[r0,#4] POP {r3,r12,pc} ENDP
_Z11no_overflowjj PROC PUSH {r0-r3,lr} MOV r2,r1 MOV r1,r0 ADD r0,sp,#8 BL _Z8full_addjj LDR r0,[sp,#8] LDR r1,[sp,#0xc] STM sp,{r0,r1} LDRB r0,[sp,#4] RSBS r0,r0,#1 MOVCC r0,#0 POP {r1-r3,r12,pc} ENDP
Seems just a tad worse than what you got :) What GCC did you use?
$ arm-linux-gnu-g++ --version arm-linux-gnu-g++ (GCC) 4.1.2 20061028 (prerelease) (Debian 4.1.1-19) It looks like your compiler is not inlining full_add inside no_overflow, and is doing a lot of spurious argument save/restore. There's also some strange store-as-word/load-as-byte going on for the bool. But the core is this
ADD r2,r1,r2 CMP r2,r1 MOVCS r1,#0 MOVCC r1,#1
which compares with
adds r2, r1, r2 movcc r1, #0 movcs r1, #1
So either it doesn't know that the add and compare can be merged into an adds (a peephole optimisation I would think) or it is confused by the inversion of the carry bit. Regards, Phil.