Commit 7894bc6b by Joern Rennecke Committed by Joern Rennecke

re PR rtl-optimization/56833 (Valid register is over written by postreload pass)

        PR rtl-optimization/56833
        * postreload.c (move2add_record_mode): New function.
        (move2add_record_sym_value, move2add_valid_value_p): Likewise.
        (move2add_use_add2_insn): Use move2add_record_sym_value.
        (move2add_use_add3_insn): Likewise.
        (reload_cse_move2add): Use move2add_valid_value_p and
        move2add_record_mode.  Invalidate call-clobbered and REG_INC
        affected regs by setting reg_mode to VOIDmode.
        (move2add_note_store): Don't pretend the inside of a SUBREG is
        the actual destination.  Invalidate single/leading registers by
        setting reg_mode to VOIDmode.
        Use move2add_record_sym_value, move2add_valid_value_p and
        move2add_record_mode.

From-SVN: r199353
parent 4fed6b25
2013-05-27 Joern Rennecke <joern.rennecke@embecosm.com>
PR rtl-optimization/56833
* postreload.c (move2add_record_mode): New function.
(move2add_record_sym_value, move2add_valid_value_p): Likewise.
(move2add_use_add2_insn): Use move2add_record_sym_value.
(move2add_use_add3_insn): Likewise.
(reload_cse_move2add): Use move2add_valid_value_p and
move2add_record_mode. Invalidate call-clobbered and REG_INC
affected regs by setting reg_mode to VOIDmode.
(move2add_note_store): Don't pretend the inside of a SUBREG is
the actual destination. Invalidate single/leading registers by
setting reg_mode to VOIDmode.
Use move2add_record_sym_value, move2add_valid_value_p and
move2add_record_mode.
2013-05-27 Richard Biener <rguenther@suse.de> 2013-05-27 Richard Biener <rguenther@suse.de>
PR tree-optimization/57396 PR tree-optimization/57396
......
...@@ -1645,14 +1645,22 @@ reload_combine_note_use (rtx *xp, rtx insn, int ruid, rtx containing_mem) ...@@ -1645,14 +1645,22 @@ reload_combine_note_use (rtx *xp, rtx insn, int ruid, rtx containing_mem)
later disable any optimization that would cross it. later disable any optimization that would cross it.
reg_offset[n] / reg_base_reg[n] / reg_symbol_ref[n] / reg_mode[n] reg_offset[n] / reg_base_reg[n] / reg_symbol_ref[n] / reg_mode[n]
are only valid if reg_set_luid[n] is greater than are only valid if reg_set_luid[n] is greater than
move2add_last_label_luid. */ move2add_last_label_luid.
For a set that established a new (potential) base register with
non-constant value, we use move2add_luid from the place where the
setting insn is encountered; registers based off that base then
get the same reg_set_luid. Constants all get
move2add_last_label_luid + 1 as their reg_set_luid. */
static int reg_set_luid[FIRST_PSEUDO_REGISTER]; static int reg_set_luid[FIRST_PSEUDO_REGISTER];
/* If reg_base_reg[n] is negative, register n has been set to /* If reg_base_reg[n] is negative, register n has been set to
reg_offset[n] or reg_symbol_ref[n] + reg_offset[n] in mode reg_mode[n]. reg_offset[n] or reg_symbol_ref[n] + reg_offset[n] in mode reg_mode[n].
If reg_base_reg[n] is non-negative, register n has been set to the If reg_base_reg[n] is non-negative, register n has been set to the
sum of reg_offset[n] and the value of register reg_base_reg[n] sum of reg_offset[n] and the value of register reg_base_reg[n]
before reg_set_luid[n], calculated in mode reg_mode[n] . */ before reg_set_luid[n], calculated in mode reg_mode[n] .
For multi-hard-register registers, all but the first one are
recorded as BLKmode in reg_mode. Setting reg_mode to VOIDmode
marks it as invalid. */
static HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER]; static HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER];
static int reg_base_reg[FIRST_PSEUDO_REGISTER]; static int reg_base_reg[FIRST_PSEUDO_REGISTER];
static rtx reg_symbol_ref[FIRST_PSEUDO_REGISTER]; static rtx reg_symbol_ref[FIRST_PSEUDO_REGISTER];
...@@ -1674,6 +1682,60 @@ static int move2add_last_label_luid; ...@@ -1674,6 +1682,60 @@ static int move2add_last_label_luid;
|| (GET_MODE_SIZE (OUTMODE) <= GET_MODE_SIZE (INMODE) \ || (GET_MODE_SIZE (OUTMODE) <= GET_MODE_SIZE (INMODE) \
&& TRULY_NOOP_TRUNCATION_MODES_P (OUTMODE, INMODE))) && TRULY_NOOP_TRUNCATION_MODES_P (OUTMODE, INMODE)))
/* Record that REG is being set to a value with the mode of REG. */
static void
move2add_record_mode (rtx reg)
{
int regno, nregs;
enum machine_mode mode = GET_MODE (reg);
if (GET_CODE (reg) == SUBREG)
{
regno = subreg_regno (reg);
nregs = subreg_nregs (reg);
}
else if (REG_P (reg))
{
regno = REGNO (reg);
nregs = hard_regno_nregs[regno][mode];
}
else
gcc_unreachable ();
for (int i = nregs - 1; i > 0; i--)
reg_mode[regno + i] = BLKmode;
reg_mode[regno] = mode;
}
/* Record that REG is being set to the sum of SYM and OFF. */
static void
move2add_record_sym_value (rtx reg, rtx sym, rtx off)
{
int regno = REGNO (reg);
move2add_record_mode (reg);
reg_set_luid[regno] = move2add_luid;
reg_base_reg[regno] = -1;
reg_symbol_ref[regno] = sym;
reg_offset[regno] = INTVAL (off);
}
/* Check if REGNO contains a valid value in MODE. */
static bool
move2add_valid_value_p (int regno, enum machine_mode mode)
{
if (reg_set_luid[regno] <= move2add_last_label_luid
|| !MODES_OK_FOR_MOVE2ADD (mode, reg_mode[regno]))
return false;
for (int i = hard_regno_nregs[regno][mode] - 1; i > 0; i--)
if (reg_mode[regno + i] != BLKmode)
return false;
return true;
}
/* This function is called with INSN that sets REG to (SYM + OFF), /* This function is called with INSN that sets REG to (SYM + OFF),
while REG is known to already have value (SYM + offset). while REG is known to already have value (SYM + offset).
This function tries to change INSN into an add instruction This function tries to change INSN into an add instruction
...@@ -1749,11 +1811,7 @@ move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx insn) ...@@ -1749,11 +1811,7 @@ move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx insn)
} }
} }
} }
reg_set_luid[regno] = move2add_luid; move2add_record_sym_value (reg, sym, off);
reg_base_reg[regno] = -1;
reg_mode[regno] = GET_MODE (reg);
reg_symbol_ref[regno] = sym;
reg_offset[regno] = INTVAL (off);
return changed; return changed;
} }
...@@ -1787,8 +1845,7 @@ move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn) ...@@ -1787,8 +1845,7 @@ move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn)
SET_SRC (pat) = plus_expr; SET_SRC (pat) = plus_expr;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (reg_set_luid[i] > move2add_last_label_luid if (move2add_valid_value_p (i, GET_MODE (reg))
&& reg_mode[i] == GET_MODE (reg)
&& reg_base_reg[i] < 0 && reg_base_reg[i] < 0
&& reg_symbol_ref[i] != NULL_RTX && reg_symbol_ref[i] != NULL_RTX
&& rtx_equal_p (sym, reg_symbol_ref[i])) && rtx_equal_p (sym, reg_symbol_ref[i]))
...@@ -1836,10 +1893,7 @@ move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn) ...@@ -1836,10 +1893,7 @@ move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn)
changed = true; changed = true;
} }
reg_set_luid[regno] = move2add_luid; reg_set_luid[regno] = move2add_luid;
reg_base_reg[regno] = -1; move2add_record_sym_value (reg, sym, off);
reg_mode[regno] = GET_MODE (reg);
reg_symbol_ref[regno] = sym;
reg_offset[regno] = INTVAL (off);
return changed; return changed;
} }
...@@ -1890,8 +1944,7 @@ reload_cse_move2add (rtx first) ...@@ -1890,8 +1944,7 @@ reload_cse_move2add (rtx first)
/* Check if we have valid information on the contents of this /* Check if we have valid information on the contents of this
register in the mode of REG. */ register in the mode of REG. */
if (reg_set_luid[regno] > move2add_last_label_luid if (move2add_valid_value_p (regno, GET_MODE (reg))
&& MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno])
&& dbg_cnt (cse2_move2add)) && dbg_cnt (cse2_move2add))
{ {
/* Try to transform (set (REGX) (CONST_INT A)) /* Try to transform (set (REGX) (CONST_INT A))
...@@ -1928,8 +1981,7 @@ reload_cse_move2add (rtx first) ...@@ -1928,8 +1981,7 @@ reload_cse_move2add (rtx first)
else if (REG_P (src) else if (REG_P (src)
&& reg_set_luid[regno] == reg_set_luid[REGNO (src)] && reg_set_luid[regno] == reg_set_luid[REGNO (src)]
&& reg_base_reg[regno] == reg_base_reg[REGNO (src)] && reg_base_reg[regno] == reg_base_reg[REGNO (src)]
&& MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), && move2add_valid_value_p (REGNO (src), GET_MODE (reg)))
reg_mode[REGNO (src)]))
{ {
rtx next = next_nonnote_nondebug_insn (insn); rtx next = next_nonnote_nondebug_insn (insn);
rtx set = NULL_RTX; rtx set = NULL_RTX;
...@@ -1982,10 +2034,10 @@ reload_cse_move2add (rtx first) ...@@ -1982,10 +2034,10 @@ reload_cse_move2add (rtx first)
delete_insn (insn); delete_insn (insn);
changed |= success; changed |= success;
insn = next; insn = next;
reg_mode[regno] = GET_MODE (reg); move2add_record_mode (reg);
reg_offset[regno] = reg_offset[regno]
trunc_int_for_mode (added_offset + base_offset, = trunc_int_for_mode (added_offset + base_offset,
GET_MODE (reg)); GET_MODE (reg));
continue; continue;
} }
} }
...@@ -2021,8 +2073,7 @@ reload_cse_move2add (rtx first) ...@@ -2021,8 +2073,7 @@ reload_cse_move2add (rtx first)
/* If the reg already contains the value which is sum of /* If the reg already contains the value which is sum of
sym and some constant value, we can use an add2 insn. */ sym and some constant value, we can use an add2 insn. */
if (reg_set_luid[regno] > move2add_last_label_luid if (move2add_valid_value_p (regno, GET_MODE (reg))
&& MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno])
&& reg_base_reg[regno] < 0 && reg_base_reg[regno] < 0
&& reg_symbol_ref[regno] != NULL_RTX && reg_symbol_ref[regno] != NULL_RTX
&& rtx_equal_p (sym, reg_symbol_ref[regno])) && rtx_equal_p (sym, reg_symbol_ref[regno]))
...@@ -2045,7 +2096,10 @@ reload_cse_move2add (rtx first) ...@@ -2045,7 +2096,10 @@ reload_cse_move2add (rtx first)
/* Reset the information about this register. */ /* Reset the information about this register. */
int regno = REGNO (XEXP (note, 0)); int regno = REGNO (XEXP (note, 0));
if (regno < FIRST_PSEUDO_REGISTER) if (regno < FIRST_PSEUDO_REGISTER)
reg_set_luid[regno] = 0; {
move2add_record_mode (XEXP (note, 0));
reg_mode[regno] = VOIDmode;
}
} }
} }
note_stores (PATTERN (insn), move2add_note_store, insn); note_stores (PATTERN (insn), move2add_note_store, insn);
...@@ -2082,7 +2136,7 @@ reload_cse_move2add (rtx first) ...@@ -2082,7 +2136,7 @@ reload_cse_move2add (rtx first)
{ {
if (call_used_regs[i]) if (call_used_regs[i])
/* Reset the information about this register. */ /* Reset the information about this register. */
reg_set_luid[i] = 0; reg_mode[i] = VOIDmode;
} }
} }
} }
...@@ -2099,20 +2153,8 @@ move2add_note_store (rtx dst, const_rtx set, void *data) ...@@ -2099,20 +2153,8 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
{ {
rtx insn = (rtx) data; rtx insn = (rtx) data;
unsigned int regno = 0; unsigned int regno = 0;
unsigned int nregs = 0;
unsigned int i;
enum machine_mode mode = GET_MODE (dst); enum machine_mode mode = GET_MODE (dst);
if (GET_CODE (dst) == SUBREG)
{
regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)),
GET_MODE (SUBREG_REG (dst)),
SUBREG_BYTE (dst),
GET_MODE (dst));
nregs = subreg_nregs (dst);
dst = SUBREG_REG (dst);
}
/* Some targets do argument pushes without adding REG_INC notes. */ /* Some targets do argument pushes without adding REG_INC notes. */
if (MEM_P (dst)) if (MEM_P (dst))
...@@ -2120,27 +2162,28 @@ move2add_note_store (rtx dst, const_rtx set, void *data) ...@@ -2120,27 +2162,28 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
dst = XEXP (dst, 0); dst = XEXP (dst, 0);
if (GET_CODE (dst) == PRE_INC || GET_CODE (dst) == POST_INC if (GET_CODE (dst) == PRE_INC || GET_CODE (dst) == POST_INC
|| GET_CODE (dst) == PRE_DEC || GET_CODE (dst) == POST_DEC) || GET_CODE (dst) == PRE_DEC || GET_CODE (dst) == POST_DEC)
reg_set_luid[REGNO (XEXP (dst, 0))] = 0; reg_mode[REGNO (XEXP (dst, 0))] = VOIDmode;
return; return;
} }
if (!REG_P (dst))
return;
regno += REGNO (dst); if (GET_CODE (dst) == SUBREG)
if (!nregs) regno = subreg_regno (dst);
nregs = hard_regno_nregs[regno][mode]; else if (REG_P (dst))
regno = REGNO (dst);
else
return;
if (SCALAR_INT_MODE_P (GET_MODE (dst)) if (SCALAR_INT_MODE_P (mode)
&& nregs == 1 && GET_CODE (set) == SET) && GET_CODE (set) == SET)
{ {
rtx note, sym = NULL_RTX; rtx note, sym = NULL_RTX;
HOST_WIDE_INT off; rtx off;
note = find_reg_equal_equiv_note (insn); note = find_reg_equal_equiv_note (insn);
if (note && GET_CODE (XEXP (note, 0)) == SYMBOL_REF) if (note && GET_CODE (XEXP (note, 0)) == SYMBOL_REF)
{ {
sym = XEXP (note, 0); sym = XEXP (note, 0);
off = 0; off = const0_rtx;
} }
else if (note && GET_CODE (XEXP (note, 0)) == CONST else if (note && GET_CODE (XEXP (note, 0)) == CONST
&& GET_CODE (XEXP (XEXP (note, 0), 0)) == PLUS && GET_CODE (XEXP (XEXP (note, 0), 0)) == PLUS
...@@ -2148,22 +2191,18 @@ move2add_note_store (rtx dst, const_rtx set, void *data) ...@@ -2148,22 +2191,18 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
&& CONST_INT_P (XEXP (XEXP (XEXP (note, 0), 0), 1))) && CONST_INT_P (XEXP (XEXP (XEXP (note, 0), 0), 1)))
{ {
sym = XEXP (XEXP (XEXP (note, 0), 0), 0); sym = XEXP (XEXP (XEXP (note, 0), 0), 0);
off = INTVAL (XEXP (XEXP (XEXP (note, 0), 0), 1)); off = XEXP (XEXP (XEXP (note, 0), 0), 1);
} }
if (sym != NULL_RTX) if (sym != NULL_RTX)
{ {
reg_base_reg[regno] = -1; move2add_record_sym_value (dst, sym, off);
reg_symbol_ref[regno] = sym;
reg_offset[regno] = off;
reg_mode[regno] = mode;
reg_set_luid[regno] = move2add_luid;
return; return;
} }
} }
if (SCALAR_INT_MODE_P (GET_MODE (dst)) if (SCALAR_INT_MODE_P (mode)
&& nregs == 1 && GET_CODE (set) == SET && GET_CODE (set) == SET
&& GET_CODE (SET_DEST (set)) != ZERO_EXTRACT && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT
&& GET_CODE (SET_DEST (set)) != STRICT_LOW_PART) && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
{ {
...@@ -2171,9 +2210,6 @@ move2add_note_store (rtx dst, const_rtx set, void *data) ...@@ -2171,9 +2210,6 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
rtx base_reg; rtx base_reg;
HOST_WIDE_INT offset; HOST_WIDE_INT offset;
int base_regno; int base_regno;
/* This may be different from mode, if SET_DEST (set) is a
SUBREG. */
enum machine_mode dst_mode = GET_MODE (dst);
switch (GET_CODE (src)) switch (GET_CODE (src))
{ {
...@@ -2185,20 +2221,14 @@ move2add_note_store (rtx dst, const_rtx set, void *data) ...@@ -2185,20 +2221,14 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
if (CONST_INT_P (XEXP (src, 1))) if (CONST_INT_P (XEXP (src, 1)))
offset = INTVAL (XEXP (src, 1)); offset = INTVAL (XEXP (src, 1));
else if (REG_P (XEXP (src, 1)) else if (REG_P (XEXP (src, 1))
&& (reg_set_luid[REGNO (XEXP (src, 1))] && move2add_valid_value_p (REGNO (XEXP (src, 1)), mode))
> move2add_last_label_luid)
&& (MODES_OK_FOR_MOVE2ADD
(dst_mode, reg_mode[REGNO (XEXP (src, 1))])))
{ {
if (reg_base_reg[REGNO (XEXP (src, 1))] < 0 if (reg_base_reg[REGNO (XEXP (src, 1))] < 0
&& reg_symbol_ref[REGNO (XEXP (src, 1))] == NULL_RTX) && reg_symbol_ref[REGNO (XEXP (src, 1))] == NULL_RTX)
offset = reg_offset[REGNO (XEXP (src, 1))]; offset = reg_offset[REGNO (XEXP (src, 1))];
/* Maybe the first register is known to be a /* Maybe the first register is known to be a
constant. */ constant. */
else if (reg_set_luid[REGNO (base_reg)] else if (move2add_valid_value_p (REGNO (base_reg), mode)
> move2add_last_label_luid
&& (MODES_OK_FOR_MOVE2ADD
(dst_mode, reg_mode[REGNO (base_reg)]))
&& reg_base_reg[REGNO (base_reg)] < 0 && reg_base_reg[REGNO (base_reg)] < 0
&& reg_symbol_ref[REGNO (base_reg)] == NULL_RTX) && reg_symbol_ref[REGNO (base_reg)] == NULL_RTX)
{ {
...@@ -2228,33 +2258,26 @@ move2add_note_store (rtx dst, const_rtx set, void *data) ...@@ -2228,33 +2258,26 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
reg_offset[regno] = INTVAL (SET_SRC (set)); reg_offset[regno] = INTVAL (SET_SRC (set));
/* We assign the same luid to all registers set to constants. */ /* We assign the same luid to all registers set to constants. */
reg_set_luid[regno] = move2add_last_label_luid + 1; reg_set_luid[regno] = move2add_last_label_luid + 1;
reg_mode[regno] = mode; move2add_record_mode (dst);
return; return;
default: default:
invalidate: goto invalidate;
/* Invalidate the contents of the register. */
reg_set_luid[regno] = 0;
return;
} }
base_regno = REGNO (base_reg); base_regno = REGNO (base_reg);
/* If information about the base register is not valid, set it /* If information about the base register is not valid, set it
up as a new base register, pretending its value is known up as a new base register, pretending its value is known
starting from the current insn. */ starting from the current insn. */
if (reg_set_luid[base_regno] <= move2add_last_label_luid) if (!move2add_valid_value_p (base_regno, mode))
{ {
reg_base_reg[base_regno] = base_regno; reg_base_reg[base_regno] = base_regno;
reg_symbol_ref[base_regno] = NULL_RTX; reg_symbol_ref[base_regno] = NULL_RTX;
reg_offset[base_regno] = 0; reg_offset[base_regno] = 0;
reg_set_luid[base_regno] = move2add_luid; reg_set_luid[base_regno] = move2add_luid;
reg_mode[base_regno] = mode; gcc_assert (GET_MODE (base_reg) == mode);
move2add_record_mode (base_reg);
} }
else if (! MODES_OK_FOR_MOVE2ADD (dst_mode,
reg_mode[base_regno]))
goto invalidate;
reg_mode[regno] = mode;
/* Copy base information from our base register. */ /* Copy base information from our base register. */
reg_set_luid[regno] = reg_set_luid[base_regno]; reg_set_luid[regno] = reg_set_luid[base_regno];
...@@ -2262,17 +2285,17 @@ move2add_note_store (rtx dst, const_rtx set, void *data) ...@@ -2262,17 +2285,17 @@ move2add_note_store (rtx dst, const_rtx set, void *data)
reg_symbol_ref[regno] = reg_symbol_ref[base_regno]; reg_symbol_ref[regno] = reg_symbol_ref[base_regno];
/* Compute the sum of the offsets or constants. */ /* Compute the sum of the offsets or constants. */
reg_offset[regno] = trunc_int_for_mode (offset reg_offset[regno]
+ reg_offset[base_regno], = trunc_int_for_mode (offset + reg_offset[base_regno], mode);
dst_mode);
move2add_record_mode (dst);
} }
else else
{ {
unsigned int endregno = regno + nregs; invalidate:
/* Invalidate the contents of the register. */
for (i = regno; i < endregno; i++) move2add_record_mode (dst);
/* Reset the information about this register. */ reg_mode[regno] = VOIDmode;
reg_set_luid[i] = 0;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment