From 4df8acd3c82998c4f18ec1fd3ee97b6d81c61135 Mon Sep 17 00:00:00 2001 From: Adam Nemet Date: Fri, 13 Jan 2006 23:24:42 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 14 +++++ gcc/combine.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 148 insertions(+), 27 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4211f8c..e12842e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2006-01-13 Adam Nemet + + * 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 * tree-ssa-alias.c (add_type_alias): Fix typo. Test whether diff --git a/gcc/combine.c b/gcc/combine.c index e2e7258..3b1fd77 100644 --- a/gcc/combine.c +++ b/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; } } -- 2.7.4