Commit 4df8acd3 by Adam Nemet Committed by Adam Nemet

combine.c (struct reg_stat): Add new fields truncation_label and truncated_to_mode.

	* combine.c (struct reg_stat): Add new fields truncation_label and
	truncated_to_mode.
	(record_value_for_reg): Reset truncated_to_mode.
	(record_truncated_value): New function.
	(check_promoted_subreg): Call it.  Rename to check_conversions.
	(combine_instructions): Rename check_promoted_subreg to
	check_conversions.
	(reg_truncated_to_mode): New function.
	(make_extraction): Use it.  Check TRULY_NOOP_TRUNCATION.
	(gen_lowpart_or_truncate): New function.
	(force_to_mode): Use it instead of gen_lowpart.

From-SVN: r109679
parent c4603146
2006-01-13 Adam Nemet <anemet@caviumnetworks.com>
* combine.c (struct reg_stat): Add new fields truncation_label and
truncated_to_mode.
(record_value_for_reg): Reset truncated_to_mode.
(record_truncated_value): New function.
(check_promoted_subreg): Call it. Rename to check_conversions.
(combine_instructions): Rename check_promoted_subreg to
check_conversions.
(reg_truncated_to_mode): New function.
(make_extraction): Use it. Check TRULY_NOOP_TRUNCATION.
(gen_lowpart_or_truncate): New function.
(force_to_mode): Use it instead of gen_lowpart.
2006-01-13 Diego Novillo <dnovillo@redhat.com> 2006-01-13 Diego Novillo <dnovillo@redhat.com>
* tree-ssa-alias.c (add_type_alias): Fix typo. Test whether * tree-ssa-alias.c (add_type_alias): Fix typo. Test whether
......
...@@ -243,6 +243,19 @@ struct reg_stat { ...@@ -243,6 +243,19 @@ struct reg_stat {
unsigned char sign_bit_copies; unsigned char sign_bit_copies;
unsigned HOST_WIDE_INT nonzero_bits; unsigned HOST_WIDE_INT nonzero_bits;
/* Record the value of the label_tick when the last truncation
happened. The field truncated_to_mode is only valid if
truncation_label == label_tick. */
int truncation_label;
/* Record the last truncation seen for this register. If truncation
is not a nop to this mode we might be able to save an explicit
truncation if we know that value already contains a truncated
value. */
ENUM_BITFIELD(machine_mode) truncated_to_mode : 8;
}; };
static struct reg_stat *reg_stat; static struct reg_stat *reg_stat;
...@@ -407,7 +420,7 @@ static rtx gen_lowpart_for_combine (enum machine_mode, rtx); ...@@ -407,7 +420,7 @@ static rtx gen_lowpart_for_combine (enum machine_mode, rtx);
static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *); static enum rtx_code simplify_comparison (enum rtx_code, rtx *, rtx *);
static void update_table_tick (rtx); static void update_table_tick (rtx);
static void record_value_for_reg (rtx, rtx, rtx); static void record_value_for_reg (rtx, rtx, rtx);
static void check_promoted_subreg (rtx, rtx); static void check_conversions (rtx, rtx);
static void record_dead_and_set_regs_1 (rtx, rtx, void *); static void record_dead_and_set_regs_1 (rtx, rtx, void *);
static void record_dead_and_set_regs (rtx); static void record_dead_and_set_regs (rtx);
static int get_last_value_validate (rtx *, rtx, int, int); static int get_last_value_validate (rtx *, rtx, int, int);
...@@ -424,6 +437,9 @@ static int insn_cuid (rtx); ...@@ -424,6 +437,9 @@ static int insn_cuid (rtx);
static void record_promoted_value (rtx, rtx); static void record_promoted_value (rtx, rtx);
static int unmentioned_reg_p_1 (rtx *, void *); static int unmentioned_reg_p_1 (rtx *, void *);
static bool unmentioned_reg_p (rtx, rtx); static bool unmentioned_reg_p (rtx, rtx);
static void record_truncated_value (rtx);
static bool reg_truncated_to_mode (enum machine_mode, rtx);
static rtx gen_lowpart_or_truncate (enum machine_mode, rtx);
/* It is not safe to use ordinary gen_lowpart in combine. /* It is not safe to use ordinary gen_lowpart in combine.
...@@ -790,7 +806,7 @@ combine_instructions (rtx f, unsigned int nregs) ...@@ -790,7 +806,7 @@ combine_instructions (rtx f, unsigned int nregs)
{ {
/* See if we know about function return values before this /* See if we know about function return values before this
insn based upon SUBREG flags. */ insn based upon SUBREG flags. */
check_promoted_subreg (insn, PATTERN (insn)); check_conversions (insn, PATTERN (insn));
/* Try this insn with each insn it links back to. */ /* Try this insn with each insn it links back to. */
...@@ -5989,6 +6005,11 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos, ...@@ -5989,6 +6005,11 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
&& ! (spans_byte && inner_mode != tmode) && ! (spans_byte && inner_mode != tmode)
&& ((pos_rtx == 0 && (pos % BITS_PER_WORD) == 0 && ((pos_rtx == 0 && (pos % BITS_PER_WORD) == 0
&& !MEM_P (inner) && !MEM_P (inner)
&& (inner_mode == tmode
|| !REG_P (inner)
|| TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (tmode),
GET_MODE_BITSIZE (inner_mode))
|| reg_truncated_to_mode (tmode, inner))
&& (! in_dest && (! in_dest
|| (REG_P (inner) || (REG_P (inner)
&& have_insn_for (STRICT_LOW_PART, tmode)))) && have_insn_for (STRICT_LOW_PART, tmode))))
...@@ -6758,6 +6779,22 @@ canon_reg_for_combine (rtx x, rtx reg) ...@@ -6758,6 +6779,22 @@ canon_reg_for_combine (rtx x, rtx reg)
return x; return x;
} }
/* Return X converted to MODE. If the value is already truncated to
MODE we can just return a subreg even though in the general case we
would need an explicit truncation. */
static rtx
gen_lowpart_or_truncate (enum machine_mode mode, rtx x)
{
if (GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (mode)
|| TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
GET_MODE_BITSIZE (GET_MODE (x)))
|| (REG_P (x) && reg_truncated_to_mode (mode, x)))
return gen_lowpart (mode, x);
else
return gen_rtx_TRUNCATE (mode, x);
}
/* See if X can be simplified knowing that we will only refer to it in /* See if X can be simplified knowing that we will only refer to it in
MODE and will only refer to those bits that are nonzero in MASK. MODE and will only refer to those bits that are nonzero in MASK.
If other bits are being computed or if masking operations are done If other bits are being computed or if masking operations are done
...@@ -7023,10 +7060,10 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask, ...@@ -7023,10 +7060,10 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
/* For most binary operations, just propagate into the operation and /* For most binary operations, just propagate into the operation and
change the mode if we have an operation of that mode. */ change the mode if we have an operation of that mode. */
op0 = gen_lowpart (op_mode, op0 = gen_lowpart_or_truncate (op_mode,
force_to_mode (XEXP (x, 0), mode, mask, force_to_mode (XEXP (x, 0), mode, mask,
next_select)); next_select));
op1 = gen_lowpart (op_mode, op1 = gen_lowpart_or_truncate (op_mode,
force_to_mode (XEXP (x, 1), mode, mask, force_to_mode (XEXP (x, 1), mode, mask,
next_select)); next_select));
...@@ -7060,7 +7097,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask, ...@@ -7060,7 +7097,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
else else
mask = fuller_mask; mask = fuller_mask;
op0 = gen_lowpart (op_mode, op0 = gen_lowpart_or_truncate (op_mode,
force_to_mode (XEXP (x, 0), op_mode, force_to_mode (XEXP (x, 0), op_mode,
mask, next_select)); mask, next_select));
...@@ -7266,7 +7303,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask, ...@@ -7266,7 +7303,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
mask = fuller_mask; mask = fuller_mask;
unop: unop:
op0 = gen_lowpart (op_mode, op0 = gen_lowpart_or_truncate (op_mode,
force_to_mode (XEXP (x, 0), mode, mask, force_to_mode (XEXP (x, 0), mode, mask,
next_select)); next_select));
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0)) if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
...@@ -7291,10 +7328,12 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask, ...@@ -7291,10 +7328,12 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
written in a narrower mode. We play it safe and do not do so. */ written in a narrower mode. We play it safe and do not do so. */
SUBST (XEXP (x, 1), SUBST (XEXP (x, 1),
gen_lowpart (GET_MODE (x), force_to_mode (XEXP (x, 1), mode, gen_lowpart_or_truncate (GET_MODE (x),
force_to_mode (XEXP (x, 1), mode,
mask, next_select))); mask, next_select)));
SUBST (XEXP (x, 2), SUBST (XEXP (x, 2),
gen_lowpart (GET_MODE (x), force_to_mode (XEXP (x, 2), mode, gen_lowpart_or_truncate (GET_MODE (x),
force_to_mode (XEXP (x, 2), mode,
mask, next_select))); mask, next_select)));
break; break;
...@@ -7303,7 +7342,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask, ...@@ -7303,7 +7342,7 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
} }
/* Ensure we return a value of the proper mode. */ /* Ensure we return a value of the proper mode. */
return gen_lowpart (mode, x); return gen_lowpart_or_truncate (mode, x);
} }
/* Return nonzero if X is an expression that has one of two values depending on /* Return nonzero if X is an expression that has one of two values depending on
...@@ -10871,6 +10910,7 @@ record_value_for_reg (rtx reg, rtx insn, rtx value) ...@@ -10871,6 +10910,7 @@ record_value_for_reg (rtx reg, rtx insn, rtx value)
reg_stat[i].last_set_nonzero_bits = 0; reg_stat[i].last_set_nonzero_bits = 0;
reg_stat[i].last_set_sign_bit_copies = 0; reg_stat[i].last_set_sign_bit_copies = 0;
reg_stat[i].last_death = 0; reg_stat[i].last_death = 0;
reg_stat[i].truncated_to_mode = 0;
} }
/* Mark registers that are being referenced in this value. */ /* Mark registers that are being referenced in this value. */
...@@ -11004,6 +11044,7 @@ record_dead_and_set_regs (rtx insn) ...@@ -11004,6 +11044,7 @@ record_dead_and_set_regs (rtx insn)
reg_stat[i].last_set_nonzero_bits = 0; reg_stat[i].last_set_nonzero_bits = 0;
reg_stat[i].last_set_sign_bit_copies = 0; reg_stat[i].last_set_sign_bit_copies = 0;
reg_stat[i].last_death = 0; reg_stat[i].last_death = 0;
reg_stat[i].truncated_to_mode = 0;
} }
last_call_cuid = mem_last_set = INSN_CUID (insn); last_call_cuid = mem_last_set = INSN_CUID (insn);
...@@ -11067,15 +11108,81 @@ record_promoted_value (rtx insn, rtx subreg) ...@@ -11067,15 +11108,81 @@ record_promoted_value (rtx insn, rtx subreg)
} }
} }
/* Scan X for promoted SUBREGs. For each one found, /* Check if X, a register, is known to contain a value already
note what it implies to the registers used in it. */ truncated to MODE. In this case we can use a subreg to refer to
the truncated value even though in the generic case we would need
an explicit truncation. */
static bool
reg_truncated_to_mode (enum machine_mode mode, rtx x)
{
enum machine_mode truncated = reg_stat[REGNO (x)].truncated_to_mode;
if (truncated == 0 || reg_stat[REGNO (x)].truncation_label != label_tick)
return false;
if (GET_MODE_SIZE (truncated) <= GET_MODE_SIZE (mode))
return true;
if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
GET_MODE_BITSIZE (truncated)))
return true;
return false;
}
/* X is a REG or a SUBREG. If X is some sort of a truncation record
it. For non-TRULY_NOOP_TRUNCATION targets we might be able to turn
a truncate into a subreg using this information. */
static void
record_truncated_value (rtx x)
{
enum machine_mode truncated_mode;
if (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x)))
{
enum machine_mode original_mode = GET_MODE (SUBREG_REG (x));
truncated_mode = GET_MODE (x);
if (GET_MODE_SIZE (original_mode) <= GET_MODE_SIZE (truncated_mode))
return;
if (TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (truncated_mode),
GET_MODE_BITSIZE (original_mode)))
return;
x = SUBREG_REG (x);
}
/* ??? For hard-regs we now record everthing. We might be able to
optimize this using last_set_mode. */
else if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
truncated_mode = GET_MODE (x);
else
return;
if (reg_stat[REGNO (x)].truncated_to_mode == 0
|| reg_stat[REGNO (x)].truncation_label < label_tick
|| (GET_MODE_SIZE (truncated_mode)
< GET_MODE_SIZE (reg_stat[REGNO (x)].truncated_to_mode)))
{
reg_stat[REGNO (x)].truncated_to_mode = truncated_mode;
reg_stat[REGNO (x)].truncation_label = label_tick;
}
}
/* Scan X for promoted SUBREGs and truncated REGs. For each one
found, note what it implies to the registers used in it. */
static void static void
check_promoted_subreg (rtx insn, rtx x) check_conversions (rtx insn, rtx x)
{ {
if (GET_CODE (x) == SUBREG && SUBREG_PROMOTED_VAR_P (x) if (GET_CODE (x) == SUBREG || REG_P (x))
{
if (GET_CODE (x) == SUBREG
&& SUBREG_PROMOTED_VAR_P (x)
&& REG_P (SUBREG_REG (x))) && REG_P (SUBREG_REG (x)))
record_promoted_value (insn, x); record_promoted_value (insn, x);
record_truncated_value (x);
}
else else
{ {
const char *format = GET_RTX_FORMAT (GET_CODE (x)); const char *format = GET_RTX_FORMAT (GET_CODE (x));
...@@ -11085,13 +11192,13 @@ check_promoted_subreg (rtx insn, rtx x) ...@@ -11085,13 +11192,13 @@ check_promoted_subreg (rtx insn, rtx x)
switch (format[i]) switch (format[i])
{ {
case 'e': case 'e':
check_promoted_subreg (insn, XEXP (x, i)); check_conversions (insn, XEXP (x, i));
break; break;
case 'V': case 'V':
case 'E': case 'E':
if (XVEC (x, i) != 0) if (XVEC (x, i) != 0)
for (j = 0; j < XVECLEN (x, i); j++) for (j = 0; j < XVECLEN (x, i); j++)
check_promoted_subreg (insn, XVECEXP (x, i, j)); check_conversions (insn, XVECEXP (x, i, j));
break; break;
} }
} }
......
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