Commit 7beb0596 by Jie Zhang Committed by Jie Zhang

postreload.c (reg_symbol_ref[]): New.

	* postreload.c (reg_symbol_ref[]): New.
	(move2add_use_add2_insn): New.
	(move2add_use_add3_insn): New.
	(reload_cse_move2add): Handle SYMBOL + OFFSET case.
	(move2add_note_store): Likewise.

From-SVN: r162085
parent 2bc7b00c
2010-07-12 Jie Zhang <jie@codesourcery.com>
* postreload.c (reg_symbol_ref[]): New.
(move2add_use_add2_insn): New.
(move2add_use_add3_insn): New.
(reload_cse_move2add): Handle SYMBOL + OFFSET case.
(move2add_note_store): Likewise.
2010-07-12 Joern Rennecke <joern.rennecke@embecosm.com> 2010-07-12 Joern Rennecke <joern.rennecke@embecosm.com>
PR rtl-optimization/44752 PR rtl-optimization/44752
......
...@@ -1160,17 +1160,19 @@ reload_combine_note_use (rtx *xp, rtx insn) ...@@ -1160,17 +1160,19 @@ reload_combine_note_use (rtx *xp, rtx insn)
information about register contents we have would be costly, so we information about register contents we have would be costly, so we
use move2add_last_label_luid to note where the label is and then use move2add_last_label_luid to note where the label is and then
later disable any optimization that would cross it. later disable any optimization that would cross it.
reg_offset[n] / reg_base_reg[n] / reg_mode[n] are only valid if reg_offset[n] / reg_base_reg[n] / reg_symbol_ref[n] / reg_mode[n]
reg_set_luid[n] is greater than move2add_last_label_luid. */ are only valid if reg_set_luid[n] is greater than
move2add_last_label_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] 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] . */
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 enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER]; static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
/* move2add_luid is linearly increased while scanning the instructions /* move2add_luid is linearly increased while scanning the instructions
...@@ -1190,6 +1192,151 @@ static int move2add_last_label_luid; ...@@ -1190,6 +1192,151 @@ static int move2add_last_label_luid;
&& TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (OUTMODE), \ && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (OUTMODE), \
GET_MODE_BITSIZE (INMODE)))) GET_MODE_BITSIZE (INMODE))))
/* This function is called with INSN that sets REG to (SYM + OFF),
while REG is known to already have value (SYM + offset).
This function tries to change INSN into an add instruction
(set (REG) (plus (REG) (OFF - offset))) using the known value.
It also updates the information about REG's known value. */
static void
move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx insn)
{
rtx pat = PATTERN (insn);
rtx src = SET_SRC (pat);
int regno = REGNO (reg);
rtx new_src = gen_int_mode (INTVAL (off) - reg_offset[regno],
GET_MODE (reg));
bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
/* (set (reg) (plus (reg) (const_int 0))) is not canonical;
use (set (reg) (reg)) instead.
We don't delete this insn, nor do we convert it into a
note, to avoid losing register notes or the return
value flag. jump2 already knows how to get rid of
no-op moves. */
if (new_src == const0_rtx)
{
/* If the constants are different, this is a
truncation, that, if turned into (set (reg)
(reg)), would be discarded. Maybe we should
try a truncMN pattern? */
if (INTVAL (off) == reg_offset [regno])
validate_change (insn, &SET_SRC (pat), reg, 0);
}
else if (rtx_cost (new_src, PLUS, speed) < rtx_cost (src, SET, speed)
&& have_add2_insn (reg, new_src))
{
rtx tem = gen_rtx_PLUS (GET_MODE (reg), reg, new_src);
validate_change (insn, &SET_SRC (pat), tem, 0);
}
else if (sym == NULL_RTX && GET_MODE (reg) != BImode)
{
enum machine_mode narrow_mode;
for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
narrow_mode != VOIDmode
&& narrow_mode != GET_MODE (reg);
narrow_mode = GET_MODE_WIDER_MODE (narrow_mode))
{
if (have_insn_for (STRICT_LOW_PART, narrow_mode)
&& ((reg_offset[regno]
& ~GET_MODE_MASK (narrow_mode))
== (INTVAL (off)
& ~GET_MODE_MASK (narrow_mode))))
{
rtx narrow_reg = gen_rtx_REG (narrow_mode,
REGNO (reg));
rtx narrow_src = gen_int_mode (INTVAL (off),
narrow_mode);
rtx new_set =
gen_rtx_SET (VOIDmode,
gen_rtx_STRICT_LOW_PART (VOIDmode,
narrow_reg),
narrow_src);
if (validate_change (insn, &PATTERN (insn),
new_set, 0))
break;
}
}
}
reg_set_luid[regno] = move2add_luid;
reg_base_reg[regno] = -1;
reg_mode[regno] = GET_MODE (reg);
reg_symbol_ref[regno] = sym;
reg_offset[regno] = INTVAL (off);
}
/* This function is called with INSN that sets REG to (SYM + OFF),
but REG doesn't have known value (SYM + offset). This function
tries to find another register which is known to already have
value (SYM + offset) and change INSN into an add instruction
(set (REG) (plus (the found register) (OFF - offset))) if such
a register is found. It also updates the information about
REG's known value. */
static void
move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn)
{
rtx pat = PATTERN (insn);
rtx src = SET_SRC (pat);
int regno = REGNO (reg);
int min_cost = INT_MAX;
int min_regno;
bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
int i;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (reg_set_luid[i] > move2add_last_label_luid
&& reg_mode[i] == GET_MODE (reg)
&& reg_base_reg[i] < 0
&& reg_symbol_ref[i] != NULL_RTX
&& rtx_equal_p (sym, reg_symbol_ref[i]))
{
rtx new_src = gen_int_mode (INTVAL (off) - reg_offset[i],
GET_MODE (reg));
/* (set (reg) (plus (reg) (const_int 0))) is not canonical;
use (set (reg) (reg)) instead.
We don't delete this insn, nor do we convert it into a
note, to avoid losing register notes or the return
value flag. jump2 already knows how to get rid of
no-op moves. */
if (new_src == const0_rtx)
{
min_cost = 0;
min_regno = i;
break;
}
else
{
int cost = rtx_cost (new_src, PLUS, speed);
if (cost < min_cost)
{
min_cost = cost;
min_regno = i;
}
}
}
if (min_cost < rtx_cost (src, SET, speed))
{
rtx tem;
tem = gen_rtx_REG (GET_MODE (reg), min_regno);
if (i != min_regno)
{
rtx new_src = gen_int_mode (INTVAL (off) - reg_offset[min_regno],
GET_MODE (reg));
tem = gen_rtx_PLUS (GET_MODE (reg), tem, new_src);
}
validate_change (insn, &SET_SRC (pat), tem, 0);
}
reg_set_luid[regno] = move2add_luid;
reg_base_reg[regno] = -1;
reg_mode[regno] = GET_MODE (reg);
reg_symbol_ref[regno] = sym;
reg_offset[regno] = INTVAL (off);
}
static void static void
reload_cse_move2add (rtx first) reload_cse_move2add (rtx first)
{ {
...@@ -1197,7 +1344,13 @@ reload_cse_move2add (rtx first) ...@@ -1197,7 +1344,13 @@ reload_cse_move2add (rtx first)
rtx insn; rtx insn;
for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
reg_set_luid[i] = 0; {
reg_set_luid[i] = 0;
reg_offset[i] = 0;
reg_base_reg[i] = 0;
reg_symbol_ref[i] = NULL_RTX;
reg_mode[i] = VOIDmode;
}
move2add_last_label_luid = 0; move2add_last_label_luid = 0;
move2add_luid = 2; move2add_luid = 2;
...@@ -1245,65 +1398,11 @@ reload_cse_move2add (rtx first) ...@@ -1245,65 +1398,11 @@ reload_cse_move2add (rtx first)
(set (STRICT_LOW_PART (REGX)) (CONST_INT B)) (set (STRICT_LOW_PART (REGX)) (CONST_INT B))
*/ */
if (CONST_INT_P (src) && reg_base_reg[regno] < 0) if (CONST_INT_P (src)
&& reg_base_reg[regno] < 0
&& reg_symbol_ref[regno] == NULL_RTX)
{ {
rtx new_src = gen_int_mode (INTVAL (src) - reg_offset[regno], move2add_use_add2_insn (reg, NULL_RTX, src, insn);
GET_MODE (reg));
bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
/* (set (reg) (plus (reg) (const_int 0))) is not canonical;
use (set (reg) (reg)) instead.
We don't delete this insn, nor do we convert it into a
note, to avoid losing register notes or the return
value flag. jump2 already knows how to get rid of
no-op moves. */
if (new_src == const0_rtx)
{
/* If the constants are different, this is a
truncation, that, if turned into (set (reg)
(reg)), would be discarded. Maybe we should
try a truncMN pattern? */
if (INTVAL (src) == reg_offset [regno])
validate_change (insn, &SET_SRC (pat), reg, 0);
}
else if (rtx_cost (new_src, PLUS, speed) < rtx_cost (src, SET, speed)
&& have_add2_insn (reg, new_src))
{
rtx tem = gen_rtx_PLUS (GET_MODE (reg), reg, new_src);
validate_change (insn, &SET_SRC (pat), tem, 0);
}
else if (GET_MODE (reg) != BImode)
{
enum machine_mode narrow_mode;
for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
narrow_mode != VOIDmode
&& narrow_mode != GET_MODE (reg);
narrow_mode = GET_MODE_WIDER_MODE (narrow_mode))
{
if (have_insn_for (STRICT_LOW_PART, narrow_mode)
&& ((reg_offset[regno]
& ~GET_MODE_MASK (narrow_mode))
== (INTVAL (src)
& ~GET_MODE_MASK (narrow_mode))))
{
rtx narrow_reg = gen_rtx_REG (narrow_mode,
REGNO (reg));
rtx narrow_src = gen_int_mode (INTVAL (src),
narrow_mode);
rtx new_set =
gen_rtx_SET (VOIDmode,
gen_rtx_STRICT_LOW_PART (VOIDmode,
narrow_reg),
narrow_src);
if (validate_change (insn, &PATTERN (insn),
new_set, 0))
break;
}
}
}
reg_set_luid[regno] = move2add_luid;
reg_mode[regno] = GET_MODE (reg);
reg_offset[regno] = INTVAL (src);
continue; continue;
} }
...@@ -1373,6 +1472,51 @@ reload_cse_move2add (rtx first) ...@@ -1373,6 +1472,51 @@ reload_cse_move2add (rtx first)
} }
} }
} }
/* Try to transform
(set (REGX) (CONST (PLUS (SYMBOL_REF) (CONST_INT A))))
...
(set (REGY) (CONST (PLUS (SYMBOL_REF) (CONST_INT B))))
to
(set (REGX) (CONST (PLUS (SYMBOL_REF) (CONST_INT A))))
...
(set (REGY) (CONST (PLUS (REGX) (CONST_INT B-A)))) */
if ((GET_CODE (src) == SYMBOL_REF
|| (GET_CODE (src) == CONST
&& GET_CODE (XEXP (src, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (src, 0), 0)) == SYMBOL_REF
&& CONST_INT_P (XEXP (XEXP (src, 0), 1))))
&& dbg_cnt (cse2_move2add))
{
rtx sym, off;
if (GET_CODE (src) == SYMBOL_REF)
{
sym = src;
off = const0_rtx;
}
else
{
sym = XEXP (XEXP (src, 0), 0);
off = XEXP (XEXP (src, 0), 1);
}
/* If the reg already contains the value which is sum of
sym and some constant value, we can use an add2 insn. */
if (reg_set_luid[regno] > move2add_last_label_luid
&& MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno])
&& reg_base_reg[regno] < 0
&& reg_symbol_ref[regno] != NULL_RTX
&& rtx_equal_p (sym, reg_symbol_ref[regno]))
move2add_use_add2_insn (reg, sym, off, insn);
/* Otherwise, we have to find a register whose value is sum
of sym and some constant value. */
else
move2add_use_add3_insn (reg, sym, off, insn);
continue;
}
} }
for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
...@@ -1386,7 +1530,7 @@ reload_cse_move2add (rtx first) ...@@ -1386,7 +1530,7 @@ reload_cse_move2add (rtx first)
reg_set_luid[regno] = 0; reg_set_luid[regno] = 0;
} }
} }
note_stores (PATTERN (insn), move2add_note_store, NULL); note_stores (PATTERN (insn), move2add_note_store, insn);
/* If INSN is a conditional branch, we try to extract an /* If INSN is a conditional branch, we try to extract an
implicit set out of it. */ implicit set out of it. */
...@@ -1408,7 +1552,7 @@ reload_cse_move2add (rtx first) ...@@ -1408,7 +1552,7 @@ reload_cse_move2add (rtx first)
{ {
rtx implicit_set = rtx implicit_set =
gen_rtx_SET (VOIDmode, XEXP (cnd, 0), XEXP (cnd, 1)); gen_rtx_SET (VOIDmode, XEXP (cnd, 0), XEXP (cnd, 1));
move2add_note_store (SET_DEST (implicit_set), implicit_set, 0); move2add_note_store (SET_DEST (implicit_set), implicit_set, insn);
} }
} }
...@@ -1426,13 +1570,15 @@ reload_cse_move2add (rtx first) ...@@ -1426,13 +1570,15 @@ reload_cse_move2add (rtx first)
} }
} }
/* SET is a SET or CLOBBER that sets DST. /* SET is a SET or CLOBBER that sets DST. DATA is the insn which
contains SET.
Update reg_set_luid, reg_offset and reg_base_reg accordingly. Update reg_set_luid, reg_offset and reg_base_reg accordingly.
Called from reload_cse_move2add via note_stores. */ Called from reload_cse_move2add via note_stores. */
static void static void
move2add_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED) move2add_note_store (rtx dst, const_rtx set, void *data)
{ {
rtx insn = (rtx) data;
unsigned int regno = 0; unsigned int regno = 0;
unsigned int nregs = 0; unsigned int nregs = 0;
unsigned int i; unsigned int i;
...@@ -1466,6 +1612,38 @@ move2add_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED) ...@@ -1466,6 +1612,38 @@ move2add_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
nregs = hard_regno_nregs[regno][mode]; nregs = hard_regno_nregs[regno][mode];
if (SCALAR_INT_MODE_P (GET_MODE (dst)) if (SCALAR_INT_MODE_P (GET_MODE (dst))
&& nregs == 1 && GET_CODE (set) == SET)
{
rtx note, sym = NULL_RTX;
HOST_WIDE_INT off;
note = find_reg_equal_equiv_note (insn);
if (note && GET_CODE (XEXP (note, 0)) == SYMBOL_REF)
{
sym = XEXP (note, 0);
off = 0;
}
else if (note && GET_CODE (XEXP (note, 0)) == CONST
&& GET_CODE (XEXP (XEXP (note, 0), 0)) == PLUS
&& GET_CODE (XEXP (XEXP (XEXP (note, 0), 0), 0)) == SYMBOL_REF
&& CONST_INT_P (XEXP (XEXP (XEXP (note, 0), 0), 1)))
{
sym = XEXP (XEXP (XEXP (note, 0), 0), 0);
off = INTVAL (XEXP (XEXP (XEXP (note, 0), 0), 1));
}
if (sym != NULL_RTX)
{
reg_base_reg[regno] = -1;
reg_symbol_ref[regno] = sym;
reg_offset[regno] = off;
reg_mode[regno] = mode;
reg_set_luid[regno] = move2add_luid;
return;
}
}
if (SCALAR_INT_MODE_P (GET_MODE (dst))
&& nregs == 1 && GET_CODE (set) == SET && nregs == 1 && 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)
...@@ -1525,6 +1703,7 @@ move2add_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED) ...@@ -1525,6 +1703,7 @@ move2add_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
case CONST_INT: case CONST_INT:
/* Start tracking the register as a constant. */ /* Start tracking the register as a constant. */
reg_base_reg[regno] = -1; reg_base_reg[regno] = -1;
reg_symbol_ref[regno] = NULL_RTX;
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;
...@@ -1545,6 +1724,7 @@ move2add_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED) ...@@ -1545,6 +1724,7 @@ move2add_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
if (reg_set_luid[base_regno] <= move2add_last_label_luid) if (reg_set_luid[base_regno] <= move2add_last_label_luid)
{ {
reg_base_reg[base_regno] = base_regno; reg_base_reg[base_regno] = base_regno;
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; reg_mode[base_regno] = mode;
...@@ -1558,6 +1738,7 @@ move2add_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED) ...@@ -1558,6 +1738,7 @@ move2add_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
/* 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];
reg_base_reg[regno] = reg_base_reg[base_regno]; reg_base_reg[regno] = reg_base_reg[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] = trunc_int_for_mode (offset
......
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