Compile following function with options -march=armv5te -mthumb -Os int mulx(int x) { return x*42; }
Gcc generates: mulx: mov r2, #42 mov r3, r2 //A mul r3, r0 @ sp needed for prologue mov r0, r3 //B bx lr There are two redundant mov instructions marked as A and B. The ideal code should be: mov r2, #42 mul r0, r2 bx lr The root causes of the two movs are different. A. In arm.md there is an insn pattern which can support 3-register multiplication. (define_insn "*thumb_mulsi3" [(set (match_operand:SI 0 "register_operand" "=&l,&l,&l") (mult:SI (match_operand:SI 1 "register_operand" "%l,*h,0") (match_operand:SI 2 "register_operand" "l,l,l")))] "TARGET_THUMB1 && !arm_arch6" "* if (which_alternative < 2) return \"mov\\t%0, %1\;mul\\t%0, %2\"; else return \"mul\\t%0, %2\"; " [(set_attr "length" "4,4,2") (set_attr "insn" "mul")] ) So after expand we got the following rtx insn: (insn 7 6 8 3 testD.i:2 (set (reg:SI 136) (mult:SI (reg:SI 137) (reg/v:SI 135 [ x ]))) -1 (nil)) For register allocator there is no difference between (set r3 mult(r0, r2)) and (set r2 mult(r0, r2)) if the original r2 is dead after this instruction. Unfortunately the first form is chosen, so an extra mov is generated. B. After rtl expansion I got: (insn 2 4 3 2 testD.i:2 (set (reg/v:SI 135 [ x ]) (reg:SI 0 r0 [ x ])) -1 (nil)) (note 3 2 5 2 NOTE_INSN_FUNCTION_BEG) (note 5 3 6 3 [bb 3] NOTE_INSN_BASIC_BLOCK) (insn 6 5 7 3 testD.i:2 (set (reg:SI 137) (const_int 42 [0x2a])) -1 (nil)) (insn 7 6 8 3 testD.i:2 (set (reg:SI 136) (mult:SI (reg:SI 137) (reg/v:SI 135 [ x ]))) -1 (nil)) (insn 8 7 9 3 testD.i:2 (set (reg:SI 134 [ <retval> ]) (reg:SI 136)) -1 (nil)) (jump_insn 9 8 10 3 testD.i:2 (set (pc) (label_ref 11)) -1 (nil) -> 11) (barrier 10 9 16) (note 16 10 13 4 [bb 4] NOTE_INSN_BASIC_BLOCK) (insn 13 16 14 4 testD.i:4 (clobber (reg/i:SI 0 r0)) -1 (nil)) (insn 14 13 11 4 testD.i:4 (clobber (reg:SI 134 [ <retval> ])) -1 (nil)) (code_label 11 14 17 5 1 "" [1 uses]) (note 17 11 12 5 [bb 5] NOTE_INSN_BASIC_BLOCK) (insn 12 17 15 5 testD.i:4 (set (reg/i:SI 0 r0) (reg:SI 134 [ <retval> ])) -1 (nil)) (insn 15 12 0 5 testD.i:4 (use (reg/i:SI 0 r0)) -1 (nil)) The extra mov comes from insn 12 and no later pass can eliminate it. Should we propagate expression into return register? -- Summary: redundant register move around mul instruction 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=42258