diff options
-rw-r--r-- | gcc/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/config/i386/i386-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 52 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 2 |
4 files changed, 63 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 39f2df0..5c50794cb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2012-08-16 Yuri Rumyantsev <ysrumyan@gmail.com> + + * config/i386/i386-protos.h (ix86_split_lea_for_addr) : Add + additional argument. + * config/i386/i386.md (ix86_split_lea_for_addr) : Add + additional argument curr_insn. + * config/i386/i386.c (ix86_split_lea_for_addr): Load base or index + register first, depending on their defintion distances. + (ix86_lea_outperforms): Prefer LEA only if split cost exceeds + AGU stall. + (find_nearest_reg-def): New function. Find register with + nearest definition. + 2012-08-16 Walter Lee <walt@tilera.com> * config.gcc (tilegx-*-linux*): Add feedback.h. @@ -74,7 +87,7 @@ * config/avr/t-avr: Replace occurrences of $(CC) with $(COMPILER). * config/avr/avr.c (avr_legitimize_reload_address): Add casts for reload_type enums. - (DEF_BUILTIN): Cast the icode to enum insn_code. + (DEF_BUILTIN): Cast the icode to enum insn_code. 2012-08-15 Segher Boessenkool <segher@kernel.crashing.org> diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index a1daeda..29bd69a 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -95,7 +95,7 @@ extern bool ix86_binary_operator_ok (enum rtx_code, enum machine_mode, rtx[]); extern bool ix86_avoid_lea_for_add (rtx, rtx[]); extern bool ix86_use_lea_for_mov (rtx, rtx[]); extern bool ix86_avoid_lea_for_addr (rtx, rtx[]); -extern void ix86_split_lea_for_addr (rtx[], enum machine_mode); +extern void ix86_split_lea_for_addr (rtx, rtx[], enum machine_mode); extern bool ix86_lea_for_add_ok (rtx, rtx[]); extern bool ix86_vec_interleave_v2df_operator_ok (rtx operands[3], bool high); extern bool ix86_dep_by_shift_count (const_rtx set_insn, const_rtx use_insn); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 624dab1..976bbb4 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -16942,9 +16942,9 @@ ix86_lea_outperforms (rtx insn, unsigned int regno0, unsigned int regno1, dist_define += split_cost + IX86_LEA_PRIORITY; /* If there is no use in memory addess then we just check - that split cost does not exceed AGU stall. */ + that split cost exceeds AGU stall. */ if (dist_use < 0) - return dist_define >= LEA_MAX_STALL; + return dist_define > LEA_MAX_STALL; /* If this insn has both backward non-agu dependence and forward agu dependence, the one with short distance takes effect. */ @@ -17127,13 +17127,41 @@ ix86_emit_binop (enum rtx_code code, enum machine_mode mode, emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob))); } +/* Return true if regno1 def is nearest to the insn. */ + +static bool +find_nearest_reg_def (rtx insn, int regno1, int regno2) +{ + rtx prev = insn; + rtx start = BB_HEAD (BLOCK_FOR_INSN (insn)); + + if (insn == start) + return false; + while (prev && prev != start) + { + if (!INSN_P (prev) || !NONDEBUG_INSN_P (prev)) + { + prev = PREV_INSN (prev); + continue; + } + if (insn_defines_reg (regno1, INVALID_REGNUM, prev)) + return true; + else if (insn_defines_reg (regno2, INVALID_REGNUM, prev)) + return false; + prev = PREV_INSN (prev); + } + + /* None of the regs is defined in the bb. */ + return false; +} + /* Split lea instructions into a sequence of instructions which are executed on ALU to avoid AGU stalls. It is assumed that it is allowed to clobber flags register at lea position. */ void -ix86_split_lea_for_addr (rtx operands[], enum machine_mode mode) +ix86_split_lea_for_addr (rtx insn, rtx operands[], enum machine_mode mode) { unsigned int regno0, regno1, regno2; struct ix86_address parts; @@ -17220,8 +17248,22 @@ ix86_split_lea_for_addr (rtx operands[], enum machine_mode mode) tmp = parts.base; else { - emit_insn (gen_rtx_SET (VOIDmode, target, parts.base)); - tmp = parts.index; + rtx tmp1; + + /* Find better operand for SET instruction, depending + on which definition is farther from the insn. */ + if (find_nearest_reg_def (insn, regno1, regno2)) + tmp = parts.index, tmp1 = parts.base; + else + tmp = parts.base, tmp1 = parts.index; + + emit_insn (gen_rtx_SET (VOIDmode, target, tmp)); + + if (parts.disp && parts.disp != const0_rtx) + ix86_emit_binop (PLUS, mode, target, parts.disp); + + ix86_emit_binop (PLUS, mode, target, tmp1); + return; } ix86_emit_binop (PLUS, mode, target, tmp); diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 16a5c13..7756832 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -5520,7 +5520,7 @@ || GET_CODE (operands[1]) == AND) mode = SImode; - ix86_split_lea_for_addr (operands, mode); + ix86_split_lea_for_addr (curr_insn, operands, mode); DONE; } [(set_attr "type" "lea") |