diff options
author | Vladimir Makarov <vmakarov@redhat.com> | 2008-04-10 19:29:12 +0000 |
---|---|---|
committer | Vladimir Makarov <vmakarov@redhat.com> | 2008-04-10 19:29:12 +0000 |
commit | d8122bef792de9617da2828cae8174cca4eba927 (patch) | |
tree | 9734e0b10e916b63fd5fbf2e5a1724c600375f79 /gcc | |
parent | 9ed6dfc63fc0f01b19888e534afeea7a11021a7e (diff) |
2008-04-10 Vladimir Makarov <vmakarov@redhat.com>
* reload1.c (substitute, gen_reload_chain_without_interm_reg_p):
New functions.
(reloads_conflict): Use gen_reload_chain_without_interm_reg_p.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/ira@134173 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/reload1.c | 124 |
2 files changed, 129 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2d2d2692e6f..5115ef747e0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2008-04-10 Vladimir Makarov <vmakarov@redhat.com> + + * reload1.c (substitute, gen_reload_chain_without_interm_reg_p): + New functions. + (reloads_conflict): Use gen_reload_chain_without_interm_reg_p. + 2008-04-09 Vladimir Makarov <vmakarov@redhat.com> * ira.c (ira): Move allocate_initial_values after initializing reg diff --git a/gcc/reload1.c b/gcc/reload1.c index 5288a5ca387..4ed8a10b5a7 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -444,6 +444,8 @@ static rtx inc_for_reload (rtx, rtx, rtx, int); static void add_auto_inc_notes (rtx, rtx); #endif static void copy_eh_notes (rtx, rtx); +static void substitute (rtx *, const_rtx, rtx); +static bool gen_reload_chain_without_interm_reg_p (int, int); static int reloads_conflict (int, int); static rtx gen_reload (rtx, rtx, int, enum reload_type); static rtx emit_insn_if_valid_for_reload (rtx); @@ -5129,6 +5131,125 @@ reloads_unique_chain_p (int r1, int r2) return true; } +/* The recursive function change all occurrences of WHAT in *WHERE + onto REPL. */ +static void +substitute (rtx *where, const_rtx what, rtx repl) +{ + const char *fmt; + int i; + enum rtx_code code; + + if (*where == 0) + return; + + if (*where == what || rtx_equal_p (*where, what)) + { + *where = repl; + return; + } + + code = GET_CODE (*where); + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + int j; + + for (j = XVECLEN (*where, i) - 1; j >= 0; j--) + substitute (&XVECEXP (*where, i, j), what, repl); + } + else if (fmt[i] == 'e') + substitute (&XEXP (*where, i), what, repl); + } +} + +/* The function returns TRUE if chain of reload R1 and R2 (in any + order) can be evaluated without usage of intermediate register for + the reload containing another reload. It is important to see + gen_reload to understand what the function is trying to do. As an + example, let us have reload chain + + r2: const + r1: <something> + const + + and reload R2 got reload reg HR. The function returns true if + there is a correct insn HR = HR + <something>. Otherwise, + gen_reload will use intermediate register (and this is the reload + reg for R1) to reload <something>. + + We need this function to find a conflict for chain reloads. In our + example, if HR = HR + <something> is incorrect insn, then we cannot + use HR as a reload register for R2. If we do use it then we get a + wrong code: + + HR = const + HR = <something> + HR = HR + HR + +*/ +static bool +gen_reload_chain_without_interm_reg_p (int r1, int r2) +{ + bool result; + int regno, n, code; + rtx out, in, tem, insn; + rtx last = get_last_insn (); + + /* Make r2 a component of r1. */ + if (reg_mentioned_p (rld[r1].in, rld[r2].in)) + { + n = r1; + r1 = r2; + r2 = n; + } + gcc_assert (reg_mentioned_p (rld[r2].in, rld[r1].in)); + regno = rld[r1].regno >= 0 ? rld[r1].regno : rld[r2].regno; + gcc_assert (regno >= 0); + out = gen_rtx_REG (rld[r1].mode, regno); + in = copy_rtx (rld[r1].in); + substitute (&in, rld[r2].in, gen_rtx_REG (rld[r2].mode, regno)); + + /* If IN is a paradoxical SUBREG, remove it and try to put the + opposite SUBREG on OUT. Likewise for a paradoxical SUBREG on OUT. */ + if (GET_CODE (in) == SUBREG + && (GET_MODE_SIZE (GET_MODE (in)) + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))) + && (tem = gen_lowpart_common (GET_MODE (SUBREG_REG (in)), out)) != 0) + in = SUBREG_REG (in), out = tem; + + if (GET_CODE (in) == PLUS + && (REG_P (XEXP (in, 0)) + || GET_CODE (XEXP (in, 0)) == SUBREG + || MEM_P (XEXP (in, 0))) + && (REG_P (XEXP (in, 1)) + || GET_CODE (XEXP (in, 1)) == SUBREG + || CONSTANT_P (XEXP (in, 1)) + || MEM_P (XEXP (in, 1)))) + { + insn = emit_insn (gen_rtx_SET (VOIDmode, out, in)); + code = recog_memoized (insn); + result = false; + + if (code >= 0) + { + extract_insn (insn); + /* We want constrain operands to treat this insn strictly in + its validity determination, i.e., the way it would after + reload has completed. */ + result = constrain_operands (1); + } + + delete_insns_since (last); + return result; + } + + /* It looks like other cases in gen_reload are not possible for + chain reloads or do need an intermediate hard registers. */ + return true; +} + /* Return 1 if the reloads denoted by R1 and R2 cannot share a register. Return 0 otherwise. @@ -5178,7 +5299,8 @@ reloads_conflict (int r1, int r2) case RELOAD_FOR_OPERAND_ADDRESS: return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN || (r2_type == RELOAD_FOR_OPERAND_ADDRESS - && !reloads_unique_chain_p (r1, r2))); + && (!reloads_unique_chain_p (r1, r2) + || !gen_reload_chain_without_interm_reg_p (r1, r2)))); case RELOAD_FOR_OPADDR_ADDR: return (r2_type == RELOAD_FOR_INPUT |