diff options
author | Richard Kenner <kenner@gcc.gnu.org> | 1993-12-31 06:44:59 -0500 |
---|---|---|
committer | Richard Kenner <kenner@gcc.gnu.org> | 1993-12-31 06:44:59 -0500 |
commit | abe6e52f2327fb3eeb45e40eeeea83033485daa1 (patch) | |
tree | 704d7314fe48f3331d4c3c7ddf53fd07c81ee40f | |
parent | e3d616e3da1033aa9417bebf8005854cc4621d63 (diff) | |
download | gcc-abe6e52f2327fb3eeb45e40eeeea83033485daa1.zip gcc-abe6e52f2327fb3eeb45e40eeeea83033485daa1.tar.gz gcc-abe6e52f2327fb3eeb45e40eeeea83033485daa1.tar.bz2 |
(added_links_insn): New variable.
(distribute_links): Set it.
(if_then_else_cond): New function.
(try_combine): Return added_links_insn if it is earlier than what we would
otherwise return.
(subst): Generalize (OP X Y) to call if_then_else_cond instead of only
checking for an explicit IF_THEN_ELSE.
(subst, case IF_THEN_ELSE): When converting to a MULT, simplify the MULT
before putting it into OP.
(subst, case AND): Don't make IF_THEN_ELSE here; now made in generic case
earlier.
From-SVN: r6343
-rw-r--r-- | gcc/combine.c | 263 |
1 files changed, 186 insertions, 77 deletions
diff --git a/gcc/combine.c b/gcc/combine.c index e75010f..a71b201 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -173,6 +173,12 @@ static rtx subst_prev_insn; static int subst_low_cuid; +/* This is an insn to which a LOG_LINKS entry has been added. If this + insn is the earlier than I2 or I3, combine should rescan starting at + that location. */ + +static rtx added_links_insn; + /* This is the value of undobuf.num_undo when we started processing this substitution. This will prevent gen_rtx_combine from re-used a piece from the previous expression. Doing so can produce circular rtl @@ -377,6 +383,7 @@ static rtx make_compound_operation PROTO((rtx, enum rtx_code)); static int get_pos_from_mask PROTO((unsigned HOST_WIDE_INT, int *)); static rtx force_to_mode PROTO((rtx, enum machine_mode, unsigned HOST_WIDE_INT, rtx, int)); +static rtx if_then_else_cond PROTO((rtx, rtx *, rtx *)); static rtx known_cond PROTO((rtx, enum rtx_code, rtx, rtx)); static rtx make_field_assignment PROTO((rtx)); static rtx apply_distributive_law PROTO((rtx)); @@ -1136,8 +1143,9 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed) and I1 is pseudo-deleted by turning it into a NOTE. Otherwise, I1 and I2 are pseudo-deleted. - If we created two insns, return I2; otherwise return I3. - Return 0 if the combination does not work. Then nothing is changed. */ + Return 0 if the combination does not work. Then nothing is changed. + If we did the combination, return the insn at which combine should + resume scanning. */ static rtx try_combine (i3, i2, i1) @@ -1201,6 +1209,7 @@ try_combine (i3, i2, i1) temp = i1, i1 = i2, i2 = temp; subst_prev_insn = 0; + added_links_insn = 0; /* First check for one important special-case that the code below will not handle. Namely, the case where I1 is zero, I2 has multiple sets, @@ -2291,7 +2300,12 @@ try_combine (i3, i2, i1) combine_successes++; - return newi2pat ? i2 : i3; + if (added_links_insn + && (newi2pat == 0 || INSN_CUID (added_links_insn) < INSN_CUID (i2)) + && INSN_CUID (added_links_insn) < INSN_CUID (i3)) + return added_links_insn; + else + return newi2pat ? i2 : i3; } /* Undo all the modifications recorded in undobuf. */ @@ -2941,55 +2955,63 @@ subst (x, from, to, in_dest, unique_copy) /* If this is a simple operation applied to an IF_THEN_ELSE, try applying it to the arms of the IF_THEN_ELSE. This often simplifies - things. Don't deal with operations that change modes here. */ - - if ((GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c') - && GET_CODE (XEXP (x, 0)) == IF_THEN_ELSE) + things. Check for cases where both arms are testing the same + condition. + + Don't do anything if all operands are very simple. */ + + if (((GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c' + || GET_RTX_CLASS (code) == '<') + && ((GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o' + && ! (GET_CODE (XEXP (x, 0)) == SUBREG + && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) + == 'o'))) + || (GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o' + && ! (GET_CODE (XEXP (x, 1)) == SUBREG + && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 1)))) + == 'o'))))) + || (GET_RTX_CLASS (code) == '1' + && ((GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o' + && ! (GET_CODE (XEXP (x, 0)) == SUBREG + && (GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) + == 'o')))))) { - /* Don't do this by using SUBST inside X since we might be messing - up a shared expression. */ - rtx cond = XEXP (XEXP (x, 0), 0); - rtx t_arm = subst (gen_binary (code, mode, XEXP (XEXP (x, 0), 1), - XEXP (x, 1)), - pc_rtx, pc_rtx, 0, 0); - rtx f_arm = subst (gen_binary (code, mode, XEXP (XEXP (x, 0), 2), - XEXP (x, 1)), - pc_rtx, pc_rtx, 0, 0); - - - x = gen_rtx (IF_THEN_ELSE, mode, cond, t_arm, f_arm); - goto restart; - } - - else if ((GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c') - && GET_CODE (XEXP (x, 1)) == IF_THEN_ELSE) - { - /* Don't do this by using SUBST inside X since we might be messing - up a shared expression. */ - rtx cond = XEXP (XEXP (x, 1), 0); - rtx t_arm = subst (gen_binary (code, mode, XEXP (x, 0), - XEXP (XEXP (x, 1), 1)), - pc_rtx, pc_rtx, 0, 0); - rtx f_arm = subst (gen_binary (code, mode, XEXP (x, 0), - XEXP (XEXP (x, 1), 2)), - pc_rtx, pc_rtx, 0, 0); - - x = gen_rtx (IF_THEN_ELSE, mode, cond, t_arm, f_arm); - goto restart; - } + rtx cond, true, false; + + cond = if_then_else_cond (x, &true, &false); + if (cond != 0) + { + rtx cop1 = const0_rtx; + enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1); + + /* If the result values are STORE_FLAG_VALUE and zero, we can + just make the comparison operation. */ + if (true == const_true_rtx && false == const0_rtx) + x = gen_binary (cond_code, mode, cond, cop1); + else if (true == const0_rtx && false == const_true_rtx) + x = gen_binary (reverse_condition (cond_code), mode, cond, cop1); + + /* Likewise, we can make the negate of a comparison operation + if the result values are - STORE_FLAG_VALUE and zero. */ + else if (GET_CODE (true) == CONST_INT + && INTVAL (true) == - STORE_FLAG_VALUE + && false == const0_rtx) + x = gen_unary (NEG, mode, + gen_binary (cond_code, mode, cond, cop1)); + else if (GET_CODE (false) == CONST_INT + && INTVAL (false) == - STORE_FLAG_VALUE + && true == const0_rtx) + x = gen_unary (NEG, mode, + gen_binary (reverse_condition (cond_code), + mode, cond, cop1)); + else + x = gen_rtx (IF_THEN_ELSE, mode, + gen_binary (cond_code, VOIDmode, cond, cop1), + subst (true, pc_rtx, pc_rtx, 0, 0), + subst (false, pc_rtx, pc_rtx, 0, 0)); - else if (GET_RTX_CLASS (code) == '1' - && GET_CODE (XEXP (x, 0)) == IF_THEN_ELSE - && GET_MODE (XEXP (x, 0)) == mode) - { - rtx cond = XEXP (XEXP (x, 0), 0); - rtx t_arm = subst (gen_unary (code, mode, XEXP (XEXP (x, 0), 1)), - pc_rtx, pc_rtx, 0, 0); - rtx f_arm = subst (gen_unary (code, mode, XEXP (XEXP (x, 0), 2)), - pc_rtx, pc_rtx, 0, 0); - - x = gen_rtx_combine (IF_THEN_ELSE, mode, cond, t_arm, f_arm); - goto restart; + goto restart; + } } /* Try to fold this expression in case we have constants that weren't @@ -4042,6 +4064,8 @@ subst (x, from, to, in_dest, unique_copy) gen_binary (MULT, m, c1, GEN_INT (STORE_FLAG_VALUE))); + temp = subst (temp, pc_rtx, pc_rtx, 0, 0); + temp = gen_binary (op, m, gen_lowpart_for_combine (m, z), temp); if (extend_op != NIL) @@ -4405,33 +4429,6 @@ subst (x, from, to, in_dest, unique_copy) goto restart; } - /* If we have (and A B) with A not an object but that is known to - be -1 or 0, this is equivalent to the expression - (if_then_else (ne A (const_int 0)) B (const_int 0)) - We make this conversion because it may allow further - simplifications and then allow use of conditional move insns. - If the machine doesn't have condition moves, code in case SET - will convert the IF_THEN_ELSE back to the logical operation. - We build the IF_THEN_ELSE here in case further simplification - is possible (e.g., we can convert it to ABS). */ - - if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) != 'o' - && ! (GET_CODE (XEXP (x, 0)) == SUBREG - && GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == 'o') - && (num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0))) - == GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))) - { - rtx op0 = XEXP (x, 0); - rtx op1 = const0_rtx; - enum rtx_code comp_code - = simplify_comparison (NE, &op0, &op1); - - x = gen_rtx_combine (IF_THEN_ELSE, mode, - gen_binary (comp_code, VOIDmode, op0, op1), - XEXP (x, 1), const0_rtx); - goto restart; - } - /* In the following group of tests (and those in case IOR below), we start with some combination of logical operations and apply the distributive law followed by the inverse distributive law. @@ -6042,6 +6039,112 @@ force_to_mode (x, mode, mask, reg, just_select) return gen_lowpart_for_combine (mode, x); } +/* Return nonzero if X is an expression that has one of two values depending on + whether some other value is zero or nonzero. In that case, we return the + value that is being tested, *PTRUE is set to the value if the rtx being + returned has a nonzero value, and *PFALSE is set to the other alternative. + + If we return zero, we set *PTRUE and *PFALSE to X. */ + +static rtx +if_then_else_cond (x, ptrue, pfalse) + rtx x; + rtx *ptrue, *pfalse; +{ + enum machine_mode mode = GET_MODE (x); + enum rtx_code code = GET_CODE (x); + int size = GET_MODE_BITSIZE (mode); + rtx cond0, cond1, true0, true1, false0, false1; + unsigned HOST_WIDE_INT nz; + + /* If this is a unary operation whose operand has one of two values, apply + our opcode to compute those values. */ + if (GET_RTX_CLASS (code) == '1' + && (cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0)) != 0) + { + *ptrue = gen_unary (code, mode, true0); + *pfalse = gen_unary (code, mode, false0); + return cond0; + } + + /* If this is a binary operation, see if either side has only one of two + values. If either one does or if both do and they are conditional on + the same value, compute the new true and false values. */ + else if (GET_RTX_CLASS (code) == 'c' || GET_RTX_CLASS (code) == '2' + || GET_RTX_CLASS (code) == '<') + { + cond0 = if_then_else_cond (XEXP (x, 0), &true0, &false0); + cond1 = if_then_else_cond (XEXP (x, 1), &true1, &false1); + + if ((cond0 != 0 || cond1 != 0) + && ! (cond0 != 0 && cond1 != 0 && ! rtx_equal_p (cond0, cond1))) + { + *ptrue = gen_binary (code, mode, true0, true1); + *pfalse = gen_binary (code, mode, false0, false1); + return cond0 ? cond0 : cond1; + } + } + + else if (code == IF_THEN_ELSE) + { + /* If we have IF_THEN_ELSE already, extract the condition and + canonicalize it if it is NE or EQ. */ + cond0 = XEXP (x, 0); + *ptrue = XEXP (x, 1), *pfalse = XEXP (x, 2); + if (GET_CODE (cond0) == NE && XEXP (cond0, 1) == const0_rtx) + return XEXP (cond0, 0); + else if (GET_CODE (cond0) == EQ && XEXP (cond0, 1) == const0_rtx) + { + *ptrue = XEXP (x, 2), *pfalse = XEXP (x, 1); + return XEXP (cond0, 0); + } + else + return cond0; + } + + /* If X is a normal SUBREG with both inner and outer modes integral, + we can narrow both the true and false values of the inner expression, + if there is a condition. */ + else if (code == SUBREG && GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT + && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) + && 0 != (cond0 = if_then_else_cond (SUBREG_REG (x), + &true0, &false0))) + { + enum machine_mode inner_mode = GET_MODE (SUBREG_REG (x)); + unsigned HOST_WIDE_INT mask = GET_MODE_MASK (inner_mode); + + *ptrue = force_to_mode (true0, inner_mode, mask, NULL_RTX, 0); + *pfalse = force_to_mode (false0, inner_mode, mask, NULL_RTX, 0); + return cond0; + } + + /* If X is a constant, this isn't special and will cause confusions + if we treat it as such. Likewise if it is equivalent to a constant. */ + else if (CONSTANT_P (x) + || ((cond0 = get_last_value (x)) != 0 && CONSTANT_P (cond0))) + ; + + /* If X is known to be either 0 or -1, those are the true and + false values when testing X. */ + else if (num_sign_bit_copies (x, mode) == size) + { + *ptrue = constm1_rtx, *pfalse = const0_rtx; + return x; + } + + /* Likewise for 0 or a single bit. */ + else if (exact_log2 (nz = nonzero_bits (x, mode)) >= 0) + { + *ptrue = GEN_INT (nz), *pfalse = const0_rtx; + return x; + } + + /* Otherwise fail; show no condition with true and false values the same. */ + *ptrue = *pfalse = x; + return 0; +} + /* Return the value of expression X given the fact that condition COND is known to be true when applied to REG as its first operand and VAL as its second. X is known to not be shared and so can be modified in @@ -10363,6 +10466,12 @@ distribute_links (links) { XEXP (link, 1) = LOG_LINKS (place); LOG_LINKS (place) = link; + + /* Set added_links_insn to the earliest insn we added a + link to. */ + if (added_links_insn == 0 + || INSN_CUID (added_links_insn) > INSN_CUID (place)) + added_links_insn = place; } } } |