diff options
Diffstat (limited to 'gcc/recog.c')
-rw-r--r-- | gcc/recog.c | 199 |
1 files changed, 119 insertions, 80 deletions
diff --git a/gcc/recog.c b/gcc/recog.c index 8da4e205f7d..7ab6a1de4e0 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -69,7 +69,7 @@ get_attr_enabled (rtx insn ATTRIBUTE_UNUSED) } #endif -static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx); +static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx, bool); static void validate_replace_src_1 (rtx *, void *); static rtx split_insn (rtx); @@ -513,88 +513,17 @@ cancel_changes (int num) num_changes = num; } -/* Replace every occurrence of FROM in X with TO. Mark each change with - validate_change passing OBJECT. */ +/* A subroutine of validate_replace_rtx_1 that tries to simplify the resulting + rtx. */ static void -validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) +simplify_while_replacing (rtx *loc, rtx to, rtx object, + enum machine_mode op0_mode) { - int i, j; - const char *fmt; rtx x = *loc; - enum rtx_code code; - enum machine_mode op0_mode = VOIDmode; - int prev_changes = num_changes; + enum rtx_code code = GET_CODE (x); rtx new_rtx; - if (!x) - return; - - code = GET_CODE (x); - fmt = GET_RTX_FORMAT (code); - if (fmt[0] == 'e') - op0_mode = GET_MODE (XEXP (x, 0)); - - /* X matches FROM if it is the same rtx or they are both referring to the - same register in the same mode. Avoid calling rtx_equal_p unless the - operands look similar. */ - - if (x == from - || (REG_P (x) && REG_P (from) - && GET_MODE (x) == GET_MODE (from) - && REGNO (x) == REGNO (from)) - || (GET_CODE (x) == GET_CODE (from) && GET_MODE (x) == GET_MODE (from) - && rtx_equal_p (x, from))) - { - validate_unshare_change (object, loc, to, 1); - return; - } - - /* Call ourself recursively to perform the replacements. - We must not replace inside already replaced expression, otherwise we - get infinite recursion for replacements like (reg X)->(subreg (reg X)) - done by regmove, so we must special case shared ASM_OPERANDS. */ - - if (GET_CODE (x) == PARALLEL) - { - for (j = XVECLEN (x, 0) - 1; j >= 0; j--) - { - if (j && GET_CODE (XVECEXP (x, 0, j)) == SET - && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == ASM_OPERANDS) - { - /* Verify that operands are really shared. */ - gcc_assert (ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, 0))) - == ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP - (x, 0, j)))); - validate_replace_rtx_1 (&SET_DEST (XVECEXP (x, 0, j)), - from, to, object); - } - else - validate_replace_rtx_1 (&XVECEXP (x, 0, j), from, to, object); - } - } - else - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - validate_replace_rtx_1 (&XEXP (x, i), from, to, object); - else if (fmt[i] == 'E') - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object); - } - - /* If we didn't substitute, there is nothing more to do. */ - if (num_changes == prev_changes) - return; - - /* Allow substituted expression to have different mode. This is used by - regmove to change mode of pseudo register. */ - if (fmt[0] == 'e' && GET_MODE (XEXP (x, 0)) != VOIDmode) - op0_mode = GET_MODE (XEXP (x, 0)); - - /* Do changes needed to keep rtx consistent. Don't do any other - simplifications, as it is not our job. */ - if (SWAPPABLE_OPERANDS_P (x) && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1))) { @@ -715,22 +644,132 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object) } } +/* Replace every occurrence of FROM in X with TO. Mark each change with + validate_change passing OBJECT. */ + +static void +validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object, + bool simplify) +{ + int i, j; + const char *fmt; + rtx x = *loc; + enum rtx_code code; + enum machine_mode op0_mode = VOIDmode; + int prev_changes = num_changes; + + if (!x) + return; + + code = GET_CODE (x); + fmt = GET_RTX_FORMAT (code); + if (fmt[0] == 'e') + op0_mode = GET_MODE (XEXP (x, 0)); + + /* X matches FROM if it is the same rtx or they are both referring to the + same register in the same mode. Avoid calling rtx_equal_p unless the + operands look similar. */ + + if (x == from + || (REG_P (x) && REG_P (from) + && GET_MODE (x) == GET_MODE (from) + && REGNO (x) == REGNO (from)) + || (GET_CODE (x) == GET_CODE (from) && GET_MODE (x) == GET_MODE (from) + && rtx_equal_p (x, from))) + { + validate_unshare_change (object, loc, to, 1); + return; + } + + /* Call ourself recursively to perform the replacements. + We must not replace inside already replaced expression, otherwise we + get infinite recursion for replacements like (reg X)->(subreg (reg X)) + done by regmove, so we must special case shared ASM_OPERANDS. */ + + if (GET_CODE (x) == PARALLEL) + { + for (j = XVECLEN (x, 0) - 1; j >= 0; j--) + { + if (j && GET_CODE (XVECEXP (x, 0, j)) == SET + && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == ASM_OPERANDS) + { + /* Verify that operands are really shared. */ + gcc_assert (ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, 0))) + == ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP + (x, 0, j)))); + validate_replace_rtx_1 (&SET_DEST (XVECEXP (x, 0, j)), + from, to, object, simplify); + } + else + validate_replace_rtx_1 (&XVECEXP (x, 0, j), from, to, object, + simplify); + } + } + else + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + validate_replace_rtx_1 (&XEXP (x, i), from, to, object, simplify); + else if (fmt[i] == 'E') + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object, + simplify); + } + + /* If we didn't substitute, there is nothing more to do. */ + if (num_changes == prev_changes) + return; + + /* Allow substituted expression to have different mode. This is used by + regmove to change mode of pseudo register. */ + if (fmt[0] == 'e' && GET_MODE (XEXP (x, 0)) != VOIDmode) + op0_mode = GET_MODE (XEXP (x, 0)); + + /* Do changes needed to keep rtx consistent. Don't do any other + simplifications, as it is not our job. */ + if (simplify) + simplify_while_replacing (loc, to, object, op0_mode); +} + /* Try replacing every occurrence of FROM in INSN with TO. After all changes have been made, validate by seeing if INSN is still valid. */ int validate_replace_rtx (rtx from, rtx to, rtx insn) { - validate_replace_rtx_1 (&PATTERN (insn), from, to, insn); + validate_replace_rtx_1 (&PATTERN (insn), from, to, insn, true); return apply_change_group (); } +/* Try replacing every occurrence of FROM in WHERE with TO. Assume that WHERE + is a part of INSN. After all changes have been made, validate by seeing if + INSN is still valid. + validate_replace_rtx (from, to, insn) is equivalent to + validate_replace_rtx_part (from, to, &PATTERN (insn), insn). */ + +int +validate_replace_rtx_part (rtx from, rtx to, rtx *where, rtx insn) +{ + validate_replace_rtx_1 (where, from, to, insn, true); + return apply_change_group (); +} + +/* Same as above, but do not simplify rtx afterwards. */ +int +validate_replace_rtx_part_nosimplify (rtx from, rtx to, rtx *where, + rtx insn) +{ + validate_replace_rtx_1 (where, from, to, insn, false); + return apply_change_group (); + +} + /* Try replacing every occurrence of FROM in INSN with TO. */ void validate_replace_rtx_group (rtx from, rtx to, rtx insn) { - validate_replace_rtx_1 (&PATTERN (insn), from, to, insn); + validate_replace_rtx_1 (&PATTERN (insn), from, to, insn, true); } /* Function called by note_uses to replace used subexpressions. */ @@ -747,7 +786,7 @@ validate_replace_src_1 (rtx *x, void *data) struct validate_replace_src_data *d = (struct validate_replace_src_data *) data; - validate_replace_rtx_1 (x, d->from, d->to, d->insn); + validate_replace_rtx_1 (x, d->from, d->to, d->insn, true); } /* Try replacing every occurrence of FROM in INSN with TO, avoiding |