Compile following code with options -march=armv7-a -mthumb -Os int foo(); long long bar22() { int result = foo(); return result; }
GCC generates: bar22: push {r3, lr} bl foo asrs r3, r0, #31 // A mov r1, r3 // B pop {r3, pc} Instruction A,B can be simplified to "asrs r1, r0, #31". In rtl expand, result was first extended to a DI register and then the DI register was moved to return register. In later passs the low half of the return value and variable result were recognized as in the same register, so the low part move was removed. After register allocation I get: (call_insn 5 2 7 2 src/t5.c:5 (parallel [ (set (reg:SI 0 r0) (call (mem:SI (symbol_ref:SI ("foo") [flags 0x41] <function_decl 0x7f6e60fe0600 foo>) [0 S4 A32]) (const_int 0 [0x0]))) (use (const_int 0 [0x0])) (clobber (reg:SI 14 lr)) ]) 255 {*call_value_insn} (nil) (nil)) (insn 7 5 22 2 src/t5.c:5 (set (reg:DI 2 r2 [orig:136 result ] [136]) (sign_extend:DI (reg/v:SI 0 r0 [orig:133 result ] [133]))) 691 {*thumb2_extendsidi2} (nil)) (insn 22 7 15 2 src/t5.c:7 (set (reg:SI 1 r1 [+4 ]) (reg:SI 3 r3 [ result+4 ])) 658 {*thumb2_movsi_insn} (nil)) The high part register move didn't get any chance to be removed until the end of compilation. -- Summary: redundant register move for sign extending 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=43137