In some cases before the function return GCC generates a redundant mov defining r0 just before another instruction defines r0 again. The first (dead) mov is unnecessary (see the example). --- c example --- int foo (int a, int x) { long long b,c; b = a << 16; c = x << 8; b += c; return (int)(b >> 32); } --- arm code --- foo: mov r1, r1, asl #8 mov r2, r1, asr #31 mov r0, r0, asl #16 stmfd sp!, {r4, lr} adds r3, r1, r0 adc r4, r2, r0, asr #31 mov r1, r4 mov r0, r3 <- OLD mov r0, r1 ldmfd sp!, {r4, pc} --- possible solution --- foo: mov r1, r1, asl #8 mov r2, r1, asr #31 mov r0, r0, asl #16 stmfd sp!, {r4, lr} adds r3, r1, r0 adc r4, r2, r0, asr #31 mov r1, r4 mov r0, r1 ldmfd sp!, {r4, pc}
A fix might to add to combine: (set b (ashiftrt:DI a (const_int 32)) (set c (subreg:SI b 4)) To (set c (subreg:SI a 8)) (Aka b = a >> 32; c = (int)b; To c = (upper part of long long)b; where b and a are long long's). This also happens on powerpc-*-*. I can confirm this on the mainline (20030806).
I looked at powerpc's rtl and it does not match arm's rtl. Arm's problem is that ashifrt is a libcall and that is where the problem is.
This bug is fixed on mainline. 3.4 branch however has it still. May be it can be closed for mainline.
Fixed on the mainline: stmfd sp!, {r4, lr} mov r1, r1, asl #8 mov r0, r0, asl #16 mov r2, r1, asr #31 adds r3, r1, r0 adc r4, r2, r0, asr #31 mov r0, r4 ldmfd sp!, {r4, pc}