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
This commit is contained in:
Adam Nemet 2006-01-13 23:24:42 +00:00 committed by Adam Nemet
parent c460314601
commit 4df8acd3c8
2 changed files with 148 additions and 27 deletions

View File

@ -1,3 +1,17 @@
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>
* tree-ssa-alias.c (add_type_alias): Fix typo. Test whether

View File

@ -220,7 +220,7 @@ struct reg_stat {
unsigned HOST_WIDE_INT last_set_nonzero_bits;
char last_set_sign_bit_copies;
ENUM_BITFIELD(machine_mode) last_set_mode : 8;
ENUM_BITFIELD(machine_mode) last_set_mode : 8;
/* Set nonzero if references to register n in expressions should not be
used. last_set_invalid is set nonzero when this register is being
@ -243,6 +243,19 @@ struct reg_stat {
unsigned char sign_bit_copies;
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;
@ -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 void update_table_tick (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 (rtx);
static int get_last_value_validate (rtx *, rtx, int, int);
@ -424,6 +437,9 @@ static int insn_cuid (rtx);
static void record_promoted_value (rtx, rtx);
static int unmentioned_reg_p_1 (rtx *, void *);
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.
@ -790,7 +806,7 @@ combine_instructions (rtx f, unsigned int nregs)
{
/* See if we know about function return values before this
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. */
@ -5989,6 +6005,11 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
&& ! (spans_byte && inner_mode != tmode)
&& ((pos_rtx == 0 && (pos % BITS_PER_WORD) == 0
&& !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
|| (REG_P (inner)
&& have_insn_for (STRICT_LOW_PART, tmode))))
@ -6758,6 +6779,22 @@ canon_reg_for_combine (rtx x, rtx reg)
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
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
@ -7023,11 +7060,11 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
/* For most binary operations, just propagate into the operation and
change the mode if we have an operation of that mode. */
op0 = gen_lowpart (op_mode,
force_to_mode (XEXP (x, 0), mode, mask,
next_select));
op1 = gen_lowpart (op_mode,
force_to_mode (XEXP (x, 1), mode, mask,
op0 = gen_lowpart_or_truncate (op_mode,
force_to_mode (XEXP (x, 0), mode, mask,
next_select));
op1 = gen_lowpart_or_truncate (op_mode,
force_to_mode (XEXP (x, 1), mode, mask,
next_select));
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
@ -7060,9 +7097,9 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
else
mask = fuller_mask;
op0 = gen_lowpart (op_mode,
force_to_mode (XEXP (x, 0), op_mode,
mask, next_select));
op0 = gen_lowpart_or_truncate (op_mode,
force_to_mode (XEXP (x, 0), op_mode,
mask, next_select));
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
x = simplify_gen_binary (code, op_mode, op0, XEXP (x, 1));
@ -7266,9 +7303,9 @@ force_to_mode (rtx x, enum machine_mode mode, unsigned HOST_WIDE_INT mask,
mask = fuller_mask;
unop:
op0 = gen_lowpart (op_mode,
force_to_mode (XEXP (x, 0), mode, mask,
next_select));
op0 = gen_lowpart_or_truncate (op_mode,
force_to_mode (XEXP (x, 0), mode, mask,
next_select));
if (op_mode != GET_MODE (x) || op0 != XEXP (x, 0))
x = simplify_gen_unary (code, op_mode, op0, op_mode);
break;
@ -7291,11 +7328,13 @@ 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. */
SUBST (XEXP (x, 1),
gen_lowpart (GET_MODE (x), force_to_mode (XEXP (x, 1), mode,
mask, next_select)));
gen_lowpart_or_truncate (GET_MODE (x),
force_to_mode (XEXP (x, 1), mode,
mask, next_select)));
SUBST (XEXP (x, 2),
gen_lowpart (GET_MODE (x), force_to_mode (XEXP (x, 2), mode,
mask, next_select)));
gen_lowpart_or_truncate (GET_MODE (x),
force_to_mode (XEXP (x, 2), mode,
mask, next_select)));
break;
default:
@ -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. */
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
@ -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_sign_bit_copies = 0;
reg_stat[i].last_death = 0;
reg_stat[i].truncated_to_mode = 0;
}
/* Mark registers that are being referenced in this value. */
@ -11004,6 +11044,7 @@ record_dead_and_set_regs (rtx insn)
reg_stat[i].last_set_nonzero_bits = 0;
reg_stat[i].last_set_sign_bit_copies = 0;
reg_stat[i].last_death = 0;
reg_stat[i].truncated_to_mode = 0;
}
last_call_cuid = mem_last_set = INSN_CUID (insn);
@ -11067,15 +11108,81 @@ record_promoted_value (rtx insn, rtx subreg)
}
}
/* Scan X for promoted SUBREGs. For each one found,
note what it implies to the registers used in it. */
/* Check if X, a register, is known to contain a value already
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
check_promoted_subreg (rtx insn, rtx x)
record_truncated_value (rtx x)
{
if (GET_CODE (x) == SUBREG && SUBREG_PROMOTED_VAR_P (x)
&& REG_P (SUBREG_REG (x)))
record_promoted_value (insn, 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
check_conversions (rtx insn, rtx x)
{
if (GET_CODE (x) == SUBREG || REG_P (x))
{
if (GET_CODE (x) == SUBREG
&& SUBREG_PROMOTED_VAR_P (x)
&& REG_P (SUBREG_REG (x)))
record_promoted_value (insn, x);
record_truncated_value (x);
}
else
{
const char *format = GET_RTX_FORMAT (GET_CODE (x));
@ -11085,13 +11192,13 @@ check_promoted_subreg (rtx insn, rtx x)
switch (format[i])
{
case 'e':
check_promoted_subreg (insn, XEXP (x, i));
check_conversions (insn, XEXP (x, i));
break;
case 'V':
case 'E':
if (XVEC (x, i) != 0)
for (j = 0; j < XVECLEN (x, i); j++)
check_promoted_subreg (insn, XVECEXP (x, i, j));
check_conversions (insn, XVECEXP (x, i, j));
break;
}
}