From c6fb08ad284af074092aa4fb9edd1a9a44014b49 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 29 Apr 2004 07:50:55 +0000 Subject: [PATCH] combine.c (combine_simplify_rtx): Adjust call to use simplify_relational_operation. 2004-04-29 Paolo Bonzini * combine.c (combine_simplify_rtx): Adjust call to use simplify_relational_operation. Do not use SELECT_CC_MODE when a comparison already has a MODE_CC mode. (simplify_set): simplify_relational_operation may now return another relational expression. * cse.c (fold_rtx): simplify_relational_operation now takes of computing the comparison mode. * dojump.c (compare_from_rtx): Use simplify_relational_operation, remove dead code. (do_compare_rtx_and_jump): Likewise. * integrate.c (subst_constants): simplify_relational_operation may now return another relational expression. * simplify-rtx.c (simplify_gen_relational): Move most code to the new simplify_relational_operation and simplify_relational_operation_1 functions. (simplify_relational_operation): Rewritten. (simplify_relational_operation_1): New function. (simplify_ternary_operation): simplify_relational_operation may now return another relational expression. (simplify_rtx): Remove unnecessary temp variable. From-SVN: r81282 --- gcc/ChangeLog | 23 +++ gcc/combine.c | 451 +++++++++++++++++++++------------------------ gcc/cse.c | 20 +- gcc/dojump.c | 88 +++------ gcc/integrate.c | 20 +- gcc/simplify-rtx.c | 226 +++++++++++++---------- 6 files changed, 407 insertions(+), 421 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3916f83518c..01c77f04dbf 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +2004-04-29 Paolo Bonzini + + * combine.c (combine_simplify_rtx): Adjust call to use + simplify_relational_operation. Do not use SELECT_CC_MODE + when a comparison already has a MODE_CC mode. + (simplify_set): simplify_relational_operation may now + return another relational expression. + * cse.c (fold_rtx): simplify_relational_operation now + takes of computing the comparison mode. + * dojump.c (compare_from_rtx): Use simplify_relational_operation, + remove dead code. + (do_compare_rtx_and_jump): Likewise. + * integrate.c (subst_constants): simplify_relational_operation + may now return another relational expression. + * simplify-rtx.c (simplify_gen_relational): Move most code to + the new simplify_relational_operation and + simplify_relational_operation_1 functions. + (simplify_relational_operation): Rewritten. + (simplify_relational_operation_1): New function. + (simplify_ternary_operation): simplify_relational_operation + may now return another relational expression. + (simplify_rtx): Remove unnecessary temp variable. + 2004-04-29 Uros Bizjak * reg-stack.c (swap_to_top): New function. diff --git a/gcc/combine.c b/gcc/combine.c index 568862d6b0a..1d6093a516d 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -143,13 +143,103 @@ static int max_uid_cuid; static unsigned int combine_max_regno; -/* Record last point of death of (hard or pseudo) register n. */ +struct reg_stat { + /* Record last point of death of (hard or pseudo) register n. */ + rtx last_death; -static rtx *reg_last_death; + /* Record last point of modification of (hard or pseudo) register n. */ + rtx last_set; -/* Record last point of modification of (hard or pseudo) register n. */ + /* The next group of fields allows the recording of the last value assigned + to (hard or pseudo) register n. We use this information to see if an + operation being processed is redundant given a prior operation performed + on the register. For example, an `and' with a constant is redundant if + all the zero bits are already known to be turned off. -static rtx *reg_last_set; + We use an approach similar to that used by cse, but change it in the + following ways: + + (1) We do not want to reinitialize at each label. + (2) It is useful, but not critical, to know the actual value assigned + to a register. Often just its form is helpful. + + Therefore, we maintain the following fields: + + last_set_value the last value assigned + last_set_label records the value of label_tick when the + register was assigned + last_set_table_tick records the value of label_tick when a + value using the register is assigned + last_set_invalid set to nonzero when it is not valid + to use the value of this register in some + register's value + + To understand the usage of these tables, it is important to understand + the distinction between the value in last_set_value being valid and + the register being validly contained in some other expression in the + table. + + (The next two parameters are out of date). + + reg_stat[i].last_set_value is valid if it is nonzero, and either + reg_n_sets[i] is 1 or reg_stat[i].last_set_label == label_tick. + + Register I may validly appear in any expression returned for the value + of another register if reg_n_sets[i] is 1. It may also appear in the + value for register J if reg_stat[j].last_set_invalid is zero, or + reg_stat[i].last_set_label < reg_stat[j].last_set_label. + + If an expression is found in the table containing a register which may + not validly appear in an expression, the register is replaced by + something that won't match, (clobber (const_int 0)). */ + + /* Record last value assigned to (hard or pseudo) register n. */ + + rtx last_set_value; + + /* Record the value of label_tick when an expression involving register n + is placed in last_set_value. */ + + int last_set_table_tick; + + /* Record the value of label_tick when the value for register n is placed in + last_set_value. */ + + int last_set_label; + + /* These fields are maintained in parallel with last_set_value and are + used to store the mode in which the register was last set, te bits + that were known to be zero when it was last set, and the number of + sign bits copies it was known to have when it was last set. */ + + unsigned HOST_WIDE_INT last_set_nonzero_bits; + char last_set_sign_bit_copies; + 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 + assigned to and last_set_table_tick == label_tick. */ + + char last_set_invalid; + + /* Some registers that are set more than once and used in more than one + basic block are nevertheless always set in similar ways. For example, + a QImode register may be loaded from memory in two places on a machine + where byte loads zero extend. + + We record in the following fields if a register has some leading bits + that are always equal to the sign bit, and what we know about the + nonzero bits of a register, specifically which bits are known to be + zero. + + If an entry is zero, it means that we don't know anything special. */ + + unsigned char sign_bit_copies; + + unsigned HOST_WIDE_INT nonzero_bits; +}; + +static struct reg_stat *reg_stat; /* Record the cuid of the last insn that invalidated memory (anything that writes memory, and subroutine calls, but not pushes). */ @@ -197,110 +287,23 @@ static basic_block this_basic_block; those blocks as starting points. */ static sbitmap refresh_blocks; -/* The next group of arrays allows the recording of the last value assigned - to (hard or pseudo) register n. We use this information to see if an - operation being processed is redundant given a prior operation performed - on the register. For example, an `and' with a constant is redundant if - all the zero bits are already known to be turned off. - - We use an approach similar to that used by cse, but change it in the - following ways: - - (1) We do not want to reinitialize at each label. - (2) It is useful, but not critical, to know the actual value assigned - to a register. Often just its form is helpful. - - Therefore, we maintain the following arrays: - - reg_last_set_value the last value assigned - reg_last_set_label records the value of label_tick when the - register was assigned - reg_last_set_table_tick records the value of label_tick when a - value using the register is assigned - reg_last_set_invalid set to nonzero when it is not valid - to use the value of this register in some - register's value - - To understand the usage of these tables, it is important to understand - the distinction between the value in reg_last_set_value being valid - and the register being validly contained in some other expression in the - table. - - Entry I in reg_last_set_value is valid if it is nonzero, and either - reg_n_sets[i] is 1 or reg_last_set_label[i] == label_tick. - - Register I may validly appear in any expression returned for the value - of another register if reg_n_sets[i] is 1. It may also appear in the - value for register J if reg_last_set_label[i] < reg_last_set_label[j] or - reg_last_set_invalid[j] is zero. - - If an expression is found in the table containing a register which may - not validly appear in an expression, the register is replaced by - something that won't match, (clobber (const_int 0)). - - reg_last_set_invalid[i] is set nonzero when register I is being assigned - to and reg_last_set_table_tick[i] == label_tick. */ - -/* Record last value assigned to (hard or pseudo) register n. */ - -static rtx *reg_last_set_value; - -/* Record the value of label_tick when the value for register n is placed in - reg_last_set_value[n]. */ - -static int *reg_last_set_label; - -/* Record the value of label_tick when an expression involving register n - is placed in reg_last_set_value. */ - -static int *reg_last_set_table_tick; - -/* Set nonzero if references to register n in expressions should not be - used. */ - -static char *reg_last_set_invalid; - /* Incremented for each label. */ static int label_tick; -/* Some registers that are set more than once and used in more than one - basic block are nevertheless always set in similar ways. For example, - a QImode register may be loaded from memory in two places on a machine - where byte loads zero extend. - - We record in the following array what we know about the nonzero - bits of a register, specifically which bits are known to be zero. - - If an entry is zero, it means that we don't know anything special. */ - -static unsigned HOST_WIDE_INT *reg_nonzero_bits; - -/* Mode used to compute significance in reg_nonzero_bits. It is the largest - integer mode that can fit in HOST_BITS_PER_WIDE_INT. */ +/* Mode used to compute significance in reg_stat[].nonzero_bits. It is the + largest integer mode that can fit in HOST_BITS_PER_WIDE_INT. */ static enum machine_mode nonzero_bits_mode; -/* Nonzero if we know that a register has some leading bits that are always - equal to the sign bit. */ - -static unsigned char *reg_sign_bit_copies; - -/* Nonzero when reg_nonzero_bits and reg_sign_bit_copies can be safely used. - It is zero while computing them and after combine has completed. This - former test prevents propagating values based on previously set values, - which can be incorrect if a variable is modified in a loop. */ +/* Nonzero when reg_stat[].nonzero_bits and reg_stat[].sign_bit_copies can + be safely used. It is zero while computing them and after combine has + completed. This former test prevents propagating values based on + previously set values, which can be incorrect if a variable is modified + in a loop. */ static int nonzero_sign_valid; -/* These arrays are maintained in parallel with reg_last_set_value - and are used to store the mode in which the register was last set, - the bits that were known to be zero when it was last set, and the - number of sign bits copies it was known to have when it was last set. */ - -static enum machine_mode *reg_last_set_mode; -static unsigned HOST_WIDE_INT *reg_last_set_nonzero_bits; -static char *reg_last_set_sign_bit_copies; /* Record one modification to rtl structure to be undone by storing old_contents into *where. @@ -336,7 +339,7 @@ static int n_occurrences; static void do_SUBST (rtx *, rtx); static void do_SUBST_INT (int *, int); -static void init_reg_last_arrays (void); +static void init_reg_last (void); static void setup_incoming_promotions (void); static void set_nonzero_bits_and_sign_copies (rtx, rtx, void *); static int cant_combine_insn_p (rtx); @@ -523,20 +526,7 @@ combine_instructions (rtx f, unsigned int nregs) See comments in gen_lowpart_for_combine. */ gen_lowpart = gen_lowpart_for_combine; - reg_nonzero_bits = xcalloc (nregs, sizeof (unsigned HOST_WIDE_INT)); - reg_sign_bit_copies = xcalloc (nregs, sizeof (unsigned char)); - - reg_last_death = xmalloc (nregs * sizeof (rtx)); - reg_last_set = xmalloc (nregs * sizeof (rtx)); - reg_last_set_value = xmalloc (nregs * sizeof (rtx)); - reg_last_set_table_tick = xmalloc (nregs * sizeof (int)); - reg_last_set_label = xmalloc (nregs * sizeof (int)); - reg_last_set_invalid = xmalloc (nregs * sizeof (char)); - reg_last_set_mode = xmalloc (nregs * sizeof (enum machine_mode)); - reg_last_set_nonzero_bits = xmalloc (nregs * sizeof (HOST_WIDE_INT)); - reg_last_set_sign_bit_copies = xmalloc (nregs * sizeof (char)); - - init_reg_last_arrays (); + reg_stat = xcalloc (nregs, sizeof (struct reg_stat)); init_recog_no_volatile (); @@ -551,8 +541,8 @@ combine_instructions (rtx f, unsigned int nregs) nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0); - /* Don't use reg_nonzero_bits when computing it. This can cause problems - when, for example, we have j <<= 1 in a loop. */ + /* Don't use reg_stat[].nonzero_bits when computing it. This can cause + problems when, for example, we have j <<= 1 in a loop. */ nonzero_sign_valid = 0; @@ -605,7 +595,7 @@ combine_instructions (rtx f, unsigned int nregs) label_tick = 1; last_call_cuid = 0; mem_last_set = 0; - init_reg_last_arrays (); + init_reg_last (); setup_incoming_promotions (); FOR_EACH_BB (this_basic_block) @@ -768,17 +758,7 @@ combine_instructions (rtx f, unsigned int nregs) /* Clean up. */ sbitmap_free (refresh_blocks); - free (reg_nonzero_bits); - free (reg_sign_bit_copies); - free (reg_last_death); - free (reg_last_set); - free (reg_last_set_value); - free (reg_last_set_table_tick); - free (reg_last_set_label); - free (reg_last_set_invalid); - free (reg_last_set_mode); - free (reg_last_set_nonzero_bits); - free (reg_last_set_sign_bit_copies); + free (reg_stat); free (uid_cuid); { @@ -805,22 +785,14 @@ combine_instructions (rtx f, unsigned int nregs) return new_direct_jump_p; } -/* Wipe the reg_last_xxx arrays in preparation for another pass. */ +/* Wipe the last_xxx fields of reg_stat in preparation for another pass. */ static void -init_reg_last_arrays (void) +init_reg_last (void) { - unsigned int nregs = combine_max_regno; - - memset (reg_last_death, 0, nregs * sizeof (rtx)); - memset (reg_last_set, 0, nregs * sizeof (rtx)); - memset (reg_last_set_value, 0, nregs * sizeof (rtx)); - memset (reg_last_set_table_tick, 0, nregs * sizeof (int)); - memset (reg_last_set_label, 0, nregs * sizeof (int)); - memset (reg_last_set_invalid, 0, nregs * sizeof (char)); - memset (reg_last_set_mode, 0, nregs * sizeof (enum machine_mode)); - memset (reg_last_set_nonzero_bits, 0, nregs * sizeof (HOST_WIDE_INT)); - memset (reg_last_set_sign_bit_copies, 0, nregs * sizeof (char)); + unsigned int i; + for (i = 0; i < combine_max_regno; i++) + memset (reg_stat + i, 0, offsetof (struct reg_stat, sign_bit_copies)); } /* Set up any promoted values for incoming argument registers. */ @@ -878,8 +850,8 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set, { if (set == 0 || GET_CODE (set) == CLOBBER) { - reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x)); - reg_sign_bit_copies[REGNO (x)] = 1; + reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x)); + reg_stat[REGNO (x)].sign_bit_copies = 1; return; } @@ -901,7 +873,7 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set, #ifdef SHORT_IMMEDIATES_SIGN_EXTEND /* If X is narrower than a word and SRC is a non-negative constant that would appear negative in the mode of X, - sign-extend it for use in reg_nonzero_bits because some + sign-extend it for use in reg_stat[].nonzero_bits because some machines (maybe most) will actually do the sign-extension and this is the conservative approach. @@ -920,18 +892,18 @@ set_nonzero_bits_and_sign_copies (rtx x, rtx set, #endif /* Don't call nonzero_bits if it cannot change anything. */ - if (reg_nonzero_bits[REGNO (x)] != ~(unsigned HOST_WIDE_INT) 0) - reg_nonzero_bits[REGNO (x)] + if (reg_stat[REGNO (x)].nonzero_bits != ~(unsigned HOST_WIDE_INT) 0) + reg_stat[REGNO (x)].nonzero_bits |= nonzero_bits (src, nonzero_bits_mode); num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x)); - if (reg_sign_bit_copies[REGNO (x)] == 0 - || reg_sign_bit_copies[REGNO (x)] > num) - reg_sign_bit_copies[REGNO (x)] = num; + if (reg_stat[REGNO (x)].sign_bit_copies == 0 + || reg_stat[REGNO (x)].sign_bit_copies > num) + reg_stat[REGNO (x)].sign_bit_copies = num; } else { - reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x)); - reg_sign_bit_copies[REGNO (x)] = 1; + reg_stat[REGNO (x)].nonzero_bits = GET_MODE_MASK (GET_MODE (x)); + reg_stat[REGNO (x)].sign_bit_copies = 1; } } } @@ -1101,7 +1073,7 @@ can_combine_p (rtx insn, rtx i3, rtx pred ATTRIBUTE_UNUSED, rtx succ, does not use any registers whose values alter in between. However, If the insns are adjacent, a use can't cross a set even though we think it might (this can happen for a sequence of insns each setting - the same destination; reg_last_set of that register might point to + the same destination; last_set of that register might point to a NOTE). If INSN has a REG_EQUIV note, the register is always equivalent to the memory so the substitution is valid even if there are intervening stores. Also, don't move a volatile asm or @@ -2331,18 +2303,18 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p) && GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) != STRICT_LOW_PART && ! (temp = SET_DEST (XVECEXP (newpat, 0, 1)), (GET_CODE (temp) == REG - && reg_nonzero_bits[REGNO (temp)] != 0 + && reg_stat[REGNO (temp)].nonzero_bits != 0 && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT - && (reg_nonzero_bits[REGNO (temp)] + && (reg_stat[REGNO (temp)].nonzero_bits != GET_MODE_MASK (word_mode)))) && ! (GET_CODE (SET_DEST (XVECEXP (newpat, 0, 1))) == SUBREG && (temp = SUBREG_REG (SET_DEST (XVECEXP (newpat, 0, 1))), (GET_CODE (temp) == REG - && reg_nonzero_bits[REGNO (temp)] != 0 + && reg_stat[REGNO (temp)].nonzero_bits != 0 && GET_MODE_BITSIZE (GET_MODE (temp)) < BITS_PER_WORD && GET_MODE_BITSIZE (GET_MODE (temp)) < HOST_BITS_PER_INT - && (reg_nonzero_bits[REGNO (temp)] + && (reg_stat[REGNO (temp)].nonzero_bits != GET_MODE_MASK (word_mode))))) && ! reg_overlap_mentioned_p (SET_DEST (XVECEXP (newpat, 0, 1)), SET_SRC (XVECEXP (newpat, 0, 1))) @@ -2783,9 +2755,10 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p) REG_N_SETS (regno)--; } - /* Update reg_nonzero_bits et al for any changes that may have been made - to this insn. The order of set_nonzero_bits_and_sign_copies() is - important. Because newi2pat can affect nonzero_bits of newpat */ + /* Update reg_stat[].nonzero_bits et al for any changes that may have + been made to this insn. The order of + set_nonzero_bits_and_sign_copies() is important. Because newi2pat + can affect nonzero_bits of newpat */ if (newi2pat) note_stores (newi2pat, set_nonzero_bits_and_sign_copies, NULL); note_stores (newpat, set_nonzero_bits_and_sign_copies, NULL); @@ -4994,23 +4967,23 @@ simplify_set (rtx x) rtx op0, op1, tmp; int other_changed = 0; enum machine_mode compare_mode = GET_MODE (dest); - enum machine_mode tmp_mode; if (GET_CODE (src) == COMPARE) op0 = XEXP (src, 0), op1 = XEXP (src, 1); else op0 = src, op1 = const0_rtx; - /* Check whether the comparison is known at compile time. */ - if (GET_MODE (op0) != VOIDmode) - tmp_mode = GET_MODE (op0); - else if (GET_MODE (op1) != VOIDmode) - tmp_mode = GET_MODE (op1); + tmp = simplify_relational_operation (old_code, compare_mode, VOIDmode, + op0, op1); + if (!tmp) + new_code = old_code; + else if (!CONSTANT_P (tmp)) + { + new_code = GET_CODE (tmp); + op0 = XEXP (tmp, 0); + op1 = XEXP (tmp, 1); + } else - tmp_mode = compare_mode; - tmp = simplify_const_relational_operation (old_code, tmp_mode, - op0, op1); - if (tmp != NULL_RTX) { rtx pat = PATTERN (other_insn); undobuf.other_insn = other_insn; @@ -5031,12 +5004,15 @@ simplify_set (rtx x) } /* Simplify our comparison, if possible. */ - new_code = simplify_comparison (old_code, &op0, &op1); + new_code = simplify_comparison (new_code, &op0, &op1); #ifdef SELECT_CC_MODE /* If this machine has CC modes other than CCmode, check to see if we need to use a different CC mode here. */ - compare_mode = SELECT_CC_MODE (new_code, op0, op1); + if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC) + compare_mode = GET_MODE (op0); + else + compare_mode = SELECT_CC_MODE (new_code, op0, op1); #ifndef HAVE_cc0 /* If the mode changed, we have to change SET_DEST, the mode in the @@ -8168,17 +8144,17 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x, value. Otherwise, use the previously-computed global nonzero bits for this register. */ - if (reg_last_set_value[REGNO (x)] != 0 - && (reg_last_set_mode[REGNO (x)] == mode - || (GET_MODE_CLASS (reg_last_set_mode[REGNO (x)]) == MODE_INT + if (reg_stat[REGNO (x)].last_set_value != 0 + && (reg_stat[REGNO (x)].last_set_mode == mode + || (GET_MODE_CLASS (reg_stat[REGNO (x)].last_set_mode) == MODE_INT && GET_MODE_CLASS (mode) == MODE_INT)) - && (reg_last_set_label[REGNO (x)] == label_tick + && (reg_stat[REGNO (x)].last_set_label == label_tick || (REGNO (x) >= FIRST_PSEUDO_REGISTER && REG_N_SETS (REGNO (x)) == 1 && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, REGNO (x)))) - && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid) - return reg_last_set_nonzero_bits[REGNO (x)] & nonzero; + && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid) + return reg_stat[REGNO (x)].last_set_nonzero_bits & nonzero; tem = get_last_value (x); @@ -8187,8 +8163,8 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x, #ifdef SHORT_IMMEDIATES_SIGN_EXTEND /* If X is narrower than MODE and TEM is a non-negative constant that would appear negative in the mode of X, - sign-extend it for use in reg_nonzero_bits because some - machines (maybe most) will actually do the sign-extension + sign-extend it for use in reg_stat[].nonzero_bits because + some machines (maybe most) will actually do the sign-extension and this is the conservative approach. ??? For 2.5, try to tighten up the MD files in this regard @@ -8206,9 +8182,9 @@ nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x, #endif return nonzero_bits_with_known (tem, mode) & nonzero; } - else if (nonzero_sign_valid && reg_nonzero_bits[REGNO (x)]) + else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits) { - unsigned HOST_WIDE_INT mask = reg_nonzero_bits[REGNO (x)]; + unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits; if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width) /* We don't know anything about the upper bits. */ @@ -8664,23 +8640,23 @@ num_sign_bit_copies1 (rtx x, enum machine_mode mode, rtx known_x, return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1; #endif - if (reg_last_set_value[REGNO (x)] != 0 - && reg_last_set_mode[REGNO (x)] == mode - && (reg_last_set_label[REGNO (x)] == label_tick + if (reg_stat[REGNO (x)].last_set_value != 0 + && reg_stat[REGNO (x)].last_set_mode == mode + && (reg_stat[REGNO (x)].last_set_label == label_tick || (REGNO (x) >= FIRST_PSEUDO_REGISTER && REG_N_SETS (REGNO (x)) == 1 && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, REGNO (x)))) - && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid) - return reg_last_set_sign_bit_copies[REGNO (x)]; + && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid) + return reg_stat[REGNO (x)].last_set_sign_bit_copies; tem = get_last_value (x); if (tem != 0) return num_sign_bit_copies_with_known (tem, mode); - if (nonzero_sign_valid && reg_sign_bit_copies[REGNO (x)] != 0 + if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0 && GET_MODE_BITSIZE (GET_MODE (x)) == bitwidth) - return reg_sign_bit_copies[REGNO (x)]; + return reg_stat[REGNO (x)].sign_bit_copies; break; case MEM: @@ -11364,7 +11340,7 @@ reversed_comparison (rtx exp, enum machine_mode mode, rtx op0, rtx op1) } /* Utility function for following routine. Called when X is part of a value - being stored into reg_last_set_value. Sets reg_last_set_table_tick + being stored into last_set_value. Sets last_set_table_tick for each register mentioned. Similar to mention_regs in cse.c */ static void @@ -11383,7 +11359,7 @@ update_table_tick (rtx x) unsigned int r; for (r = regno; r < endregno; r++) - reg_last_set_table_tick[r] = label_tick; + reg_stat[r].last_set_table_tick = label_tick; return; } @@ -11431,8 +11407,9 @@ update_table_tick (rtx x) /* Record that REG is set to VALUE in insn INSN. If VALUE is zero, we are saying that the register is clobbered and we no longer know its - value. If INSN is zero, don't update reg_last_set; this is only permitted - with VALUE also zero and is used to invalidate the register. */ + value. If INSN is zero, don't update reg_stat[].last_set; this is + only permitted with VALUE also zero and is used to invalidate the + register. */ static void record_value_for_reg (rtx reg, rtx insn, rtx value) @@ -11476,13 +11453,13 @@ record_value_for_reg (rtx reg, rtx insn, rtx value) for (i = regno; i < endregno; i++) { if (insn) - reg_last_set[i] = insn; + reg_stat[i].last_set = insn; - reg_last_set_value[i] = 0; - reg_last_set_mode[i] = 0; - reg_last_set_nonzero_bits[i] = 0; - reg_last_set_sign_bit_copies[i] = 0; - reg_last_death[i] = 0; + reg_stat[i].last_set_value = 0; + reg_stat[i].last_set_mode = 0; + reg_stat[i].last_set_nonzero_bits = 0; + reg_stat[i].last_set_sign_bit_copies = 0; + reg_stat[i].last_death = 0; } /* Mark registers that are being referenced in this value. */ @@ -11498,40 +11475,40 @@ record_value_for_reg (rtx reg, rtx insn, rtx value) for (i = regno; i < endregno; i++) { - reg_last_set_label[i] = label_tick; - if (value && reg_last_set_table_tick[i] == label_tick) - reg_last_set_invalid[i] = 1; + reg_stat[i].last_set_label = label_tick; + if (value && reg_stat[i].last_set_table_tick == label_tick) + reg_stat[i].last_set_invalid = 1; else - reg_last_set_invalid[i] = 0; + reg_stat[i].last_set_invalid = 0; } /* The value being assigned might refer to X (like in "x++;"). In that case, we must replace it with (clobber (const_int 0)) to prevent infinite loops. */ if (value && ! get_last_value_validate (&value, insn, - reg_last_set_label[regno], 0)) + reg_stat[regno].last_set_label, 0)) { value = copy_rtx (value); if (! get_last_value_validate (&value, insn, - reg_last_set_label[regno], 1)) + reg_stat[regno].last_set_label, 1)) value = 0; } /* For the main register being modified, update the value, the mode, the nonzero bits, and the number of sign bit copies. */ - reg_last_set_value[regno] = value; + reg_stat[regno].last_set_value = value; if (value) { enum machine_mode mode = GET_MODE (reg); subst_low_cuid = INSN_CUID (insn); - reg_last_set_mode[regno] = mode; + reg_stat[regno].last_set_mode = mode; if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) mode = nonzero_bits_mode; - reg_last_set_nonzero_bits[regno] = nonzero_bits (value, mode); - reg_last_set_sign_bit_copies[regno] + reg_stat[regno].last_set_nonzero_bits = nonzero_bits (value, mode); + reg_stat[regno].last_set_sign_bit_copies = num_sign_bit_copies (value, GET_MODE (reg)); } } @@ -11576,11 +11553,11 @@ record_dead_and_set_regs_1 (rtx dest, rtx setter, void *data) for the things done by INSN. This is the last thing done in processing INSN in the combiner loop. - We update reg_last_set, reg_last_set_value, reg_last_set_mode, - reg_last_set_nonzero_bits, reg_last_set_sign_bit_copies, reg_last_death, - and also the similar information mem_last_set (which insn most recently - modified memory) and last_call_cuid (which insn was the most recent - subroutine call). */ + We update reg_stat[], in particular fields last_set, last_set_value, + last_set_mode, last_set_nonzero_bits, last_set_sign_bit_copies, + last_death, and also the similar information mem_last_set (which insn + most recently modified memory) and last_call_cuid (which insn was the + most recent subroutine call). */ static void record_dead_and_set_regs (rtx insn) @@ -11600,7 +11577,7 @@ record_dead_and_set_regs (rtx insn) : 1); for (i = regno; i < endregno; i++) - reg_last_death[i] = insn; + reg_stat[i].last_death = insn; } else if (REG_NOTE_KIND (link) == REG_INC) record_value_for_reg (XEXP (link, 0), insn, NULL_RTX); @@ -11611,11 +11588,11 @@ record_dead_and_set_regs (rtx insn) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)) { - reg_last_set_value[i] = 0; - reg_last_set_mode[i] = 0; - reg_last_set_nonzero_bits[i] = 0; - reg_last_set_sign_bit_copies[i] = 0; - reg_last_death[i] = 0; + reg_stat[i].last_set_value = 0; + reg_stat[i].last_set_mode = 0; + reg_stat[i].last_set_nonzero_bits = 0; + reg_stat[i].last_set_sign_bit_copies = 0; + reg_stat[i].last_death = 0; } last_call_cuid = mem_last_set = INSN_CUID (insn); @@ -11663,10 +11640,10 @@ record_promoted_value (rtx insn, rtx subreg) continue; } - if (reg_last_set[regno] == insn) + if (reg_stat[regno].last_set == insn) { if (SUBREG_PROMOTED_UNSIGNED_P (subreg) > 0) - reg_last_set_nonzero_bits[regno] &= GET_MODE_MASK (mode); + reg_stat[regno].last_set_nonzero_bits &= GET_MODE_MASK (mode); } if (GET_CODE (SET_SRC (set)) == REG) @@ -11736,14 +11713,14 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace) unsigned int j; for (j = regno; j < endregno; j++) - if (reg_last_set_invalid[j] + if (reg_stat[j].last_set_invalid /* If this is a pseudo-register that was only set once and not live at the beginning of the function, it is always valid. */ || (! (regno >= FIRST_PSEUDO_REGISTER && REG_N_SETS (regno) == 1 && (! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno))) - && reg_last_set_label[j] > tick)) + && reg_stat[j].last_set_label > tick)) { if (replace) *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); @@ -11835,7 +11812,7 @@ get_last_value (rtx x) return 0; regno = REGNO (x); - value = reg_last_set_value[regno]; + value = reg_stat[regno].last_set_value; /* If we don't have a value, or if it isn't for this basic block and it's either a hard register, set more than once, or it's a live @@ -11848,7 +11825,7 @@ get_last_value (rtx x) block. */ if (value == 0 - || (reg_last_set_label[regno] != label_tick + || (reg_stat[regno].last_set_label != label_tick && (regno < FIRST_PSEUDO_REGISTER || REG_N_SETS (regno) != 1 || (REGNO_REG_SET_P @@ -11857,20 +11834,20 @@ get_last_value (rtx x) /* If the value was set in a later insn than the ones we are processing, we can't use it even if the register was only set once. */ - if (INSN_CUID (reg_last_set[regno]) >= subst_low_cuid) + if (INSN_CUID (reg_stat[regno].last_set) >= subst_low_cuid) return 0; /* If the value has all its registers valid, return it. */ - if (get_last_value_validate (&value, reg_last_set[regno], - reg_last_set_label[regno], 0)) + if (get_last_value_validate (&value, reg_stat[regno].last_set, + reg_stat[regno].last_set_label, 0)) return value; /* Otherwise, make a copy and replace any invalid register with (clobber (const_int 0)). If that fails for some reason, return 0. */ value = copy_rtx (value); - if (get_last_value_validate (&value, reg_last_set[regno], - reg_last_set_label[regno], 1)) + if (get_last_value_validate (&value, reg_stat[regno].last_set, + reg_stat[regno].last_set_label, 1)) return value; return 0; @@ -11899,8 +11876,8 @@ use_crosses_set_p (rtx x, int from_cuid) return 1; #endif for (; regno < endreg; regno++) - if (reg_last_set[regno] - && INSN_CUID (reg_last_set[regno]) > from_cuid) + if (reg_stat[regno].last_set + && INSN_CUID (reg_stat[regno].last_set) > from_cuid) return 1; return 0; } @@ -12160,7 +12137,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn, if (code == REG) { unsigned int regno = REGNO (x); - rtx where_dead = reg_last_death[regno]; + rtx where_dead = reg_stat[regno].last_death; rtx before_dead, after_dead; /* Don't move the register if it gets killed in between from and to. */ @@ -12187,7 +12164,7 @@ move_deaths (rtx x, rtx maybe_kill_insn, int from_cuid, rtx to_insn, rtx note = remove_death (regno, where_dead); /* It is possible for the call above to return 0. This can occur - when reg_last_death points to I2 or I1 that we combined with. + when last_death points to I2 or I1 that we combined with. In that case make a new note. We must also check for the case where X is a hard register @@ -12794,14 +12771,14 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2) || reg_bitfield_target_p (XEXP (note, 0), PATTERN (place))) { /* Unless the register previously died in PLACE, clear - reg_last_death. [I no longer understand why this is + last_death. [I no longer understand why this is being done.] */ - if (reg_last_death[regno] != place) - reg_last_death[regno] = 0; + if (reg_stat[regno].last_death != place) + reg_stat[regno].last_death = 0; place = 0; } else - reg_last_death[regno] = place; + reg_stat[regno].last_death = place; /* If this is a death note for a hard reg that is occupying multiple registers, ensure that we are still using all diff --git a/gcc/cse.c b/gcc/cse.c index 0a7281ecc42..e155db98fea 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -3924,21 +3924,11 @@ fold_rtx (rtx x, rtx insn) } } - new = simplify_relational_operation (code, mode, - (mode_arg0 != VOIDmode - ? mode_arg0 - : (GET_MODE (const_arg0 - ? const_arg0 - : folded_arg0) - != VOIDmode) - ? GET_MODE (const_arg0 - ? const_arg0 - : folded_arg0) - : GET_MODE (const_arg1 - ? const_arg1 - : folded_arg1)), - const_arg0 ? const_arg0 : folded_arg0, - const_arg1 ? const_arg1 : folded_arg1); + { + rtx op0 = const_arg0 ? const_arg0 : folded_arg0; + rtx op1 = const_arg1 ? const_arg1 : folded_arg1; + new = simplify_relational_operation (code, mode, mode_arg0, op0, op1); + } break; case RTX_BIN_ARITH: diff --git a/gcc/dojump.c b/gcc/dojump.c index eb98e76e4a8..7f76c5e752f 100644 --- a/gcc/dojump.c +++ b/gcc/dojump.c @@ -820,7 +820,6 @@ rtx compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp, enum machine_mode mode, rtx size) { - enum rtx_code ucode; rtx tem; /* If one operand is constant, make it the second one. Only do this @@ -842,32 +841,19 @@ compare_from_rtx (rtx op0, rtx op1, enum rtx_code code, int unsignedp, do_pending_stack_adjust (); - ucode = unsignedp ? unsigned_condition (code) : code; - tem = simplify_const_relational_operation (ucode, mode, op0, op1); - if (tem != 0) - return tem; - -#if 0 - /* There's no need to do this now that combine.c can eliminate lots of - sign extensions. This can be less efficient in certain cases on other - machines. */ - - /* If this is a signed equality comparison, we can do it as an - unsigned comparison since zero-extension is cheaper than sign - extension and comparisons with zero are done as unsigned. This is - the case even on machines that can do fast sign extension, since - zero-extension is easier to combine with other operations than - sign-extension is. If we are comparing against a constant, we must - convert it to what it would look like unsigned. */ - if ((code == EQ || code == NE) && ! unsignedp - && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT) + code = unsignedp ? unsigned_condition (code) : code; + if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode, + op0, op1))) { - if (GET_CODE (op1) == CONST_INT - && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1)) - op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))); - unsignedp = 1; + if (CONSTANT_P (tem)) + return tem; + + code = GET_CODE (tem); + mode = GET_MODE (tem); + op0 = XEXP (tem, 0); + op1 = XEXP (tem, 1); + unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU); } -#endif emit_cmp_insn (op0, op1, code, size, mode, unsignedp); @@ -889,7 +875,6 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp, enum machine_mode mode, rtx size, rtx if_false_label, rtx if_true_label) { - enum rtx_code ucode; rtx tem; int dummy_true_label = 0; @@ -921,44 +906,25 @@ do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp, do_pending_stack_adjust (); - ucode = unsignedp ? unsigned_condition (code) : code; - tem = simplify_const_relational_operation (ucode, mode, op0, op1); - if (tem != 0) + code = unsignedp ? unsigned_condition (code) : code; + if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode, + op0, op1))) { - if (tem == const_true_rtx) - { - if (if_true_label) - emit_jump (if_true_label); - } - else - { - if (if_false_label) - emit_jump (if_false_label); - } - return; - } + if (CONSTANT_P (tem)) + { + rtx label = (tem == const0_rtx || tem == CONST0_RTX (mode)) + ? if_false_label : if_true_label; + if (label) + emit_jump (label); + return; + } -#if 0 - /* There's no need to do this now that combine.c can eliminate lots of - sign extensions. This can be less efficient in certain cases on other - machines. */ - - /* If this is a signed equality comparison, we can do it as an - unsigned comparison since zero-extension is cheaper than sign - extension and comparisons with zero are done as unsigned. This is - the case even on machines that can do fast sign extension, since - zero-extension is easier to combine with other operations than - sign-extension is. If we are comparing against a constant, we must - convert it to what it would look like unsigned. */ - if ((code == EQ || code == NE) && ! unsignedp - && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT) - { - if (GET_CODE (op1) == CONST_INT - && (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))) != INTVAL (op1)) - op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (GET_MODE (op0))); - unsignedp = 1; + code = GET_CODE (tem); + mode = GET_MODE (tem); + op0 = XEXP (tem, 0); + op1 = XEXP (tem, 1); + unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU); } -#endif if (! if_true_label) { diff --git a/gcc/integrate.c b/gcc/integrate.c index 567cd9317ca..3a58f2cda04 100644 --- a/gcc/integrate.c +++ b/gcc/integrate.c @@ -2738,6 +2738,7 @@ subst_constants (rtx *loc, rtx insn, struct inline_remap *map, int memonly) if (op_mode == VOIDmode) op_mode = GET_MODE (XEXP (x, 1)); + new = simplify_relational_operation (code, GET_MODE (x), op_mode, XEXP (x, 0), XEXP (x, 1)); break; @@ -2766,15 +2767,18 @@ subst_constants (rtx *loc, rtx insn, struct inline_remap *map, int memonly) { /* We have compare of two VOIDmode constants for which we recorded the comparison mode. */ - rtx temp = - simplify_const_relational_operation (GET_CODE (op0), - map->compare_mode, - XEXP (op0, 0), - XEXP (op0, 1)); - - if (temp == const0_rtx) + rtx tem = + simplify_gen_relational (GET_CODE (op0), GET_MODE (op0), + map->compare_mode, XEXP (op0, 0), + XEXP (op0, 1)); + + if (GET_CODE (tem) != CONST_INT) + new = simplify_ternary_operation (code, GET_MODE (x), + op0_mode, tem, XEXP (x, 1), + XEXP (x, 2)); + else if (tem == const0_rtx) new = XEXP (x, 2); - else if (temp == const1_rtx) + else new = XEXP (x, 1); } } diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index b6340e54c8b..5895bb90686 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -58,6 +58,8 @@ static rtx simplify_immed_subreg (enum machine_mode, rtx, enum machine_mode, unsigned int); static rtx simplify_associative_operation (enum rtx_code, enum machine_mode, rtx, rtx); +static rtx simplify_relational_operation_1 (enum rtx_code, enum machine_mode, + enum machine_mode, rtx, rtx); /* Negate a CONST_INT rtx, truncating (because a conversion from a maximally negative number can overflow). */ @@ -221,10 +223,9 @@ simplify_gen_ternary (enum rtx_code code, enum machine_mode mode, return gen_rtx_fmt_eee (code, mode, op0, op1, op2); } - + /* Likewise, for relational operations. - CMP_MODE specifies mode comparison is done in. - */ + CMP_MODE specifies mode comparison is done in. */ rtx simplify_gen_relational (enum rtx_code code, enum machine_mode mode, @@ -232,46 +233,9 @@ simplify_gen_relational (enum rtx_code code, enum machine_mode mode, { rtx tem; - if (cmp_mode == VOIDmode) - cmp_mode = GET_MODE (op0); - if (cmp_mode == VOIDmode) - cmp_mode = GET_MODE (op1); - - if (cmp_mode != VOIDmode) - { - tem = simplify_relational_operation (code, mode, cmp_mode, op0, op1); - if (tem) - return tem; - } - - /* For the following tests, ensure const0_rtx is op1. */ - if (swap_commutative_operands_p (op0, op1) - || (op0 == const0_rtx && op1 != const0_rtx)) - tem = op0, op0 = op1, op1 = tem, code = swap_condition (code); - - /* If op0 is a compare, extract the comparison arguments from it. */ - if (GET_CODE (op0) == COMPARE && op1 == const0_rtx) - return simplify_gen_relational (code, mode, VOIDmode, - XEXP (op0, 0), XEXP (op0, 1)); - - /* If op0 is a comparison, extract the comparison arguments form it. */ - if (COMPARISON_P (op0) && op1 == const0_rtx) - { - if (code == NE) - { - if (GET_MODE (op0) == mode) - return op0; - return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode, - XEXP (op0, 0), XEXP (op0, 1)); - } - else if (code == EQ) - { - enum rtx_code new = reversed_comparison_code (op0, NULL_RTX); - if (new != UNKNOWN) - return simplify_gen_relational (new, mode, VOIDmode, - XEXP (op0, 0), XEXP (op0, 1)); - } - } + if (0 != (tem = simplify_relational_operation (code, mode, cmp_mode, + op0, op1))) + return tem; return gen_rtx_fmt_ee (code, mode, op0, op1); } @@ -1201,7 +1165,6 @@ simplify_associative_operation (enum rtx_code code, enum machine_mode mode, Don't use this for relational operations such as EQ or LT. Use simplify_relational_operation instead. */ - rtx simplify_binary_operation (enum rtx_code code, enum machine_mode mode, rtx op0, rtx op1) @@ -2662,10 +2625,102 @@ simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0, } /* Like simplify_binary_operation except used for relational operators. - MODE is the mode of the operands, not that of the result. If MODE - is VOIDmode, both operands must also be VOIDmode and we compare the - operands in "infinite precision". + MODE is the mode of the result. If MODE is VOIDmode, both operands must + also be VOIDmode. + + CMP_MODE specifies in which mode the comparison is done in, so it is + the mode of the operands. If CMP_MODE is VOIDmode, it is taken from + the operands or, if both are VOIDmode, the operands are compared in + "infinite precision". */ +rtx +simplify_relational_operation (enum rtx_code code, enum machine_mode mode, + enum machine_mode cmp_mode, rtx op0, rtx op1) +{ + rtx tem, trueop0, trueop1; + + if (cmp_mode == VOIDmode) + cmp_mode = GET_MODE (op0); + if (cmp_mode == VOIDmode) + cmp_mode = GET_MODE (op1); + + tem = simplify_const_relational_operation (code, cmp_mode, op0, op1); + if (tem) + { +#ifdef FLOAT_STORE_FLAG_VALUE + if (GET_MODE_CLASS (mode) == MODE_FLOAT) + { + if (tem == const0_rtx) + return CONST0_RTX (mode); + else if (GET_MODE_CLASS (mode) == MODE_FLOAT) + { + REAL_VALUE_TYPE val; + val = FLOAT_STORE_FLAG_VALUE (mode); + return CONST_DOUBLE_FROM_REAL_VALUE (val, mode); + } + } +#endif + + return tem; + } + + /* For the following tests, ensure const0_rtx is op1. */ + if (swap_commutative_operands_p (op0, op1) + || (op0 == const0_rtx && op1 != const0_rtx)) + tem = op0, op0 = op1, op1 = tem, code = swap_condition (code); + + /* If op0 is a compare, extract the comparison arguments from it. */ + if (GET_CODE (op0) == COMPARE && op1 == const0_rtx) + return simplify_relational_operation (code, mode, VOIDmode, + XEXP (op0, 0), XEXP (op0, 1)); + + if (mode == VOIDmode + || GET_MODE_CLASS (cmp_mode) == MODE_CC + || CC0_P (op0)) + return NULL_RTX; + + trueop0 = avoid_constant_pool_reference (op0); + trueop1 = avoid_constant_pool_reference (op1); + return simplify_relational_operation_1 (code, mode, cmp_mode, + trueop0, trueop1); +} + +/* This part of simplify_relational_operation is only used when CMP_MODE + is not in class MODE_CC (i.e. it is a real comparison). + + MODE is the mode of the result, while CMP_MODE specifies in which + mode the comparison is done in, so it is the mode of the operands. */ +rtx +simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode, + enum machine_mode cmp_mode, rtx op0, rtx op1) +{ + if (GET_CODE (op1) == CONST_INT) + { + if (INTVAL (op1) == 0 && COMPARISON_P (op0)) + { + /* If op0 is a comparison, extract the comparison arguments form it. */ + if (code == NE) + { + if (GET_MODE (op0) == cmp_mode) + return simplify_rtx (op0); + else + return simplify_gen_relational (GET_CODE (op0), mode, VOIDmode, + XEXP (op0, 0), XEXP (op0, 1)); + } + else if (code == EQ) + { + enum rtx_code new = reversed_comparison_code (op0, NULL_RTX); + if (new != UNKNOWN) + return simplify_gen_relational (new, mode, VOIDmode, + XEXP (op0, 0), XEXP (op0, 1)); + } + } + } + return NULL_RTX; +} + +/* Check if the given comparison (done in the given MODE) is actually a + tautology or a contradiction. If no simplification is possible, this function returns zero. Otherwise, it returns either const_true_rtx or const0_rtx. */ @@ -2954,36 +3009,6 @@ simplify_const_relational_operation (enum rtx_code code, abort (); } } - -/* Like simplify_binary_operation except used for relational operators. - MODE is the mode of the result, and CMP_MODE is the mode of the operands. - If CMP_MODE is VOIDmode, both operands must also be VOIDmode and we - compare the operands in "infinite precision". */ - -rtx -simplify_relational_operation (enum rtx_code code, - enum machine_mode mode ATTRIBUTE_UNUSED, - enum machine_mode cmp_mode, rtx op0, rtx op1) -{ - rtx tmp; - - tmp = simplify_const_relational_operation (code, cmp_mode, op0, op1); - if (tmp) - { -#ifdef FLOAT_STORE_FLAG_VALUE - if (GET_MODE_CLASS (mode) == MODE_FLOAT) - { - if (tmp == const0_rtx) - return CONST0_RTX (mode); - return CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE (mode), - mode); - } -#endif - return tmp; - } - - return NULL_RTX; -} /* Simplify CODE, an operation with result mode MODE and three operands, OP0, OP1, and OP2. OP0_MODE was the mode of OP0 before it became @@ -3078,20 +3103,6 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode, ? GET_MODE (XEXP (op0, 1)) : GET_MODE (XEXP (op0, 0))); rtx temp; - if (cmp_mode == VOIDmode) - cmp_mode = op0_mode; - temp = simplify_const_relational_operation (GET_CODE (op0), - cmp_mode, - XEXP (op0, 0), - XEXP (op0, 1)); - - /* See if any simplifications were possible. */ - if (temp == const0_rtx) - return op2; - else if (temp == const_true_rtx) - return op1; - else if (temp) - abort (); /* Look for happy constants in op1 and op2. */ if (GET_CODE (op1) == CONST_INT && GET_CODE (op2) == CONST_INT) @@ -3112,7 +3123,23 @@ simplify_ternary_operation (enum rtx_code code, enum machine_mode mode, else break; - return gen_rtx_fmt_ee (code, mode, XEXP (op0, 0), XEXP (op0, 1)); + return simplify_gen_relational (code, op0_mode, cmp_mode, + XEXP (op0, 0), XEXP (op0, 1)); + } + + if (cmp_mode == VOIDmode) + cmp_mode = op0_mode; + temp = simplify_relational_operation (GET_CODE (op0), op0_mode, + cmp_mode, XEXP (op0, 0), + XEXP (op0, 1)); + + /* See if any simplifications were possible. */ + if (temp) + { + if (GET_CODE (temp) == CONST_INT) + return temp == const0_rtx ? op2 : op1; + else if (temp) + return gen_rtx_IF_THEN_ELSE (mode, temp, op1, op2); } } break; @@ -3721,7 +3748,6 @@ simplify_rtx (rtx x) { enum rtx_code code = GET_CODE (x); enum machine_mode mode = GET_MODE (x); - rtx temp; switch (GET_RTX_CLASS (code)) { @@ -3745,13 +3771,13 @@ simplify_rtx (rtx x) case RTX_COMPARE: case RTX_COMM_COMPARE: - temp = simplify_relational_operation (code, mode, - ((GET_MODE (XEXP (x, 0)) - != VOIDmode) - ? GET_MODE (XEXP (x, 0)) - : GET_MODE (XEXP (x, 1))), - XEXP (x, 0), XEXP (x, 1)); - return temp; + return simplify_relational_operation (code, mode, + ((GET_MODE (XEXP (x, 0)) + != VOIDmode) + ? GET_MODE (XEXP (x, 0)) + : GET_MODE (XEXP (x, 1))), + XEXP (x, 0), + XEXP (x, 1)); case RTX_EXTRA: if (code == SUBREG) -- 2.30.2