mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-16 23:31:05 +08:00
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:
parent
c460314601
commit
4df8acd3c8
@ -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
|
||||
|
161
gcc/combine.c
161
gcc/combine.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user