aboutsummaryrefslogtreecommitdiff
path: root/gcc/ira.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2017-02-17 09:26:51 +1030
committerJeff Law <law@gcc.gnu.org>2017-02-16 15:56:51 -0700
commita72b242eacf3bc43375daff829e04bcce634ad22 (patch)
tree8292f5e8b39f99c7703446eee1a6e3e17e09c454 /gcc/ira.c
parent9b9ad3606debd14bd1e57306358f4fcab2c2b1db (diff)
downloadgcc-a72b242eacf3bc43375daff829e04bcce634ad22.zip
gcc-a72b242eacf3bc43375daff829e04bcce634ad22.tar.gz
gcc-a72b242eacf3bc43375daff829e04bcce634ad22.tar.bz2
re PR rtl-optimization/79286 (ira and lra wrong code at -O2 and -Os on i686-linux)
2017-02-16 Alan Modra <amodra@gmail.com> PR rtl-optimization/79286 * ira.c (def_dominates_uses): New function. (update_equiv_regs): Don't create an equivalence for insns that may trap where the register def does not dominate the use. * gcc.c-torture/execute/pr79286.c: New. From-SVN: r245521
Diffstat (limited to 'gcc/ira.c')
-rw-r--r--gcc/ira.c56
1 files changed, 54 insertions, 2 deletions
diff --git a/gcc/ira.c b/gcc/ira.c
index 96b4b62..6fb8aaf 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -3300,6 +3300,49 @@ adjust_cleared_regs (rtx loc, const_rtx old_rtx ATTRIBUTE_UNUSED, void *data)
return NULL_RTX;
}
+/* Given register REGNO is set only once, return true if the defining
+ insn dominates all uses. */
+
+static bool
+def_dominates_uses (int regno)
+{
+ df_ref def = DF_REG_DEF_CHAIN (regno);
+
+ struct df_insn_info *def_info = DF_REF_INSN_INFO (def);
+ /* If this is an artificial def (eh handler regs, hard frame pointer
+ for non-local goto, regs defined on function entry) then def_info
+ is NULL and the reg is always live before any use. We might
+ reasonably return true in that case, but since the only call
+ of this function is currently here in ira.c when we are looking
+ at a defining insn we can't have an artificial def as that would
+ bump DF_REG_DEF_COUNT. */
+ gcc_assert (DF_REG_DEF_COUNT (regno) == 1 && def_info != NULL);
+
+ rtx_insn *def_insn = DF_REF_INSN (def);
+ basic_block def_bb = BLOCK_FOR_INSN (def_insn);
+
+ for (df_ref use = DF_REG_USE_CHAIN (regno);
+ use;
+ use = DF_REF_NEXT_REG (use))
+ {
+ struct df_insn_info *use_info = DF_REF_INSN_INFO (use);
+ /* Only check real uses, not artificial ones. */
+ if (use_info)
+ {
+ rtx_insn *use_insn = DF_REF_INSN (use);
+ if (!DEBUG_INSN_P (use_insn))
+ {
+ basic_block use_bb = BLOCK_FOR_INSN (use_insn);
+ if (use_bb != def_bb
+ ? !dominated_by_p (CDI_DOMINATORS, use_bb, def_bb)
+ : DF_INSN_INFO_LUID (use_info) < DF_INSN_INFO_LUID (def_info))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
/* Find registers that are equivalent to a single value throughout the
compilation (either because they can be referenced in memory or are
set once from a single constant). Lower their priority for a
@@ -3498,9 +3541,18 @@ update_equiv_regs (void)
= gen_rtx_INSN_LIST (VOIDmode, insn, reg_equiv[regno].init_insns);
/* If this register is known to be equal to a constant, record that
- it is always equivalent to the constant. */
+ it is always equivalent to the constant.
+ Note that it is possible to have a register use before
+ the def in loops (see gcc.c-torture/execute/pr79286.c)
+ where the reg is undefined on first use. If the def insn
+ won't trap we can use it as an equivalence, effectively
+ choosing the "undefined" value for the reg to be the
+ same as the value set by the def. */
if (DF_REG_DEF_COUNT (regno) == 1
- && note && ! rtx_varies_p (XEXP (note, 0), 0))
+ && note
+ && !rtx_varies_p (XEXP (note, 0), 0)
+ && (!may_trap_p (XEXP (note, 0))
+ || def_dominates_uses (regno)))
{
rtx note_value = XEXP (note, 0);
remove_note (insn, note);