Compile following function with options -Os -mthumb -march=armv5te void bar(char*, char*, int); void foo(char* left, char* rite, int element) { while (left <= rite) { rite -= element; bar(left, rite, element); left += element; } }
Gcc generates: push {r3, r4, r5, r6, r7, lr} mov r5, r0 mov r6, r1 mov r7, r2 neg r4, r2 // A b .L2 .L3: add r6, r6, r4 // B mov r0, r5 mov r1, r6 mov r2, r7 bl bar add r5, r5, r7 .L2: cmp r5, r6 bls .L3 @ sp needed for prologue pop {r3, r4, r5, r6, r7, pc} Note that instruction A computes (r4 = -r2), and r4 is only used by instruction B (r6 = r6 + r4), this can be simplified to (r6 = r6 - r7, r7 contains the original r2). Thus we can reduce one instruction. Expression rite -= element was transformed to the following by the gimplify pass element.0 = (unsigned int) element; D.2003 = -element.0; rite = rite + D.2003; This form was kept until pass neg.c.156r.loop2_invariant. Then the expression -element was identified as loop invariant and hoisted out of the loop. So caused the current result. Is the transform of gimplify intended? Do we have any chance to merge the previous expressions back to (rite = rite - element) before loop invariant pass? -- Summary: redundant neg instruction caused by loop-invariant Product: gcc Version: 4.5.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: carrot at google dot com GCC build triplet: i686-linux GCC host triplet: i686-linux GCC target triplet: arm-eabi http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40815