+/* Try to split PATTERN found in INSN. This returns NULL_RTX if
+ PATTERN can not be split. Otherwise, it returns an insn sequence.
+ This is a wrapper around split_insns which ensures that the
+ reg_stat vector is made larger if the splitter creates a new
+ register. */
+
+static rtx
+combine_split_insns (rtx pattern, rtx insn)
+{
+ rtx ret;
+ unsigned int nregs;
+
+ ret = split_insns (pattern, insn);
+ nregs = max_reg_num ();
+ if (nregs > VEC_length (reg_stat_type, reg_stat))
+ VEC_safe_grow_cleared (reg_stat_type, heap, reg_stat, nregs);
+ return ret;
+}
+
+/* This is used by find_single_use to locate an rtx in LOC that
+ contains exactly one use of DEST, which is typically either a REG
+ or CC0. It returns a pointer to the innermost rtx expression
+ containing DEST. Appearances of DEST that are being used to
+ totally replace it are not counted. */
+
+static rtx *
+find_single_use_1 (rtx dest, rtx *loc)
+{
+ rtx x = *loc;
+ enum rtx_code code = GET_CODE (x);
+ rtx *result = NULL;
+ rtx *this_result;
+ int i;
+ const char *fmt;
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ case CONST_DOUBLE:
+ case CONST_VECTOR:
+ case CLOBBER:
+ return 0;
+
+ case SET:
+ /* If the destination is anything other than CC0, PC, a REG or a SUBREG
+ of a REG that occupies all of the REG, the insn uses DEST if
+ it is mentioned in the destination or the source. Otherwise, we
+ need just check the source. */
+ if (GET_CODE (SET_DEST (x)) != CC0
+ && GET_CODE (SET_DEST (x)) != PC
+ && !REG_P (SET_DEST (x))
+ && ! (GET_CODE (SET_DEST (x)) == SUBREG
+ && REG_P (SUBREG_REG (SET_DEST (x)))
+ && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
+ + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
+ == ((GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
+ + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))))
+ break;
+
+ return find_single_use_1 (dest, &SET_SRC (x));
+
+ case MEM:
+ case SUBREG:
+ return find_single_use_1 (dest, &XEXP (x, 0));
+
+ default:
+ break;
+ }
+
+ /* If it wasn't one of the common cases above, check each expression and
+ vector of this code. Look for a unique usage of DEST. */
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ if (dest == XEXP (x, i)
+ || (REG_P (dest) && REG_P (XEXP (x, i))
+ && REGNO (dest) == REGNO (XEXP (x, i))))
+ this_result = loc;
+ else
+ this_result = find_single_use_1 (dest, &XEXP (x, i));
+
+ if (result == NULL)
+ result = this_result;
+ else if (this_result)
+ /* Duplicate usage. */
+ return NULL;
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ {
+ if (XVECEXP (x, i, j) == dest
+ || (REG_P (dest)
+ && REG_P (XVECEXP (x, i, j))
+ && REGNO (XVECEXP (x, i, j)) == REGNO (dest)))
+ this_result = loc;
+ else
+ this_result = find_single_use_1 (dest, &XVECEXP (x, i, j));
+
+ if (result == NULL)
+ result = this_result;
+ else if (this_result)
+ return NULL;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+/* See if DEST, produced in INSN, is used only a single time in the
+ sequel. If so, return a pointer to the innermost rtx expression in which
+ it is used.
+
+ If PLOC is nonzero, *PLOC is set to the insn containing the single use.
+
+ If DEST is cc0_rtx, we look only at the next insn. In that case, we don't
+ care about REG_DEAD notes or LOG_LINKS.
+
+ Otherwise, we find the single use by finding an insn that has a
+ LOG_LINKS pointing at INSN and has a REG_DEAD note for DEST. If DEST is
+ only referenced once in that insn, we know that it must be the first
+ and last insn referencing DEST. */
+
+static rtx *
+find_single_use (rtx dest, rtx insn, rtx *ploc)
+{
+ rtx next;
+ rtx *result;
+ rtx link;
+
+#ifdef HAVE_cc0
+ if (dest == cc0_rtx)
+ {
+ next = NEXT_INSN (insn);
+ if (next == 0
+ || (!NONJUMP_INSN_P (next) && !JUMP_P (next)))
+ return 0;
+
+ result = find_single_use_1 (dest, &PATTERN (next));
+ if (result && ploc)
+ *ploc = next;
+ return result;
+ }
+#endif
+
+ if (!REG_P (dest))
+ return 0;
+
+ for (next = next_nonnote_insn (insn);
+ next != 0 && !LABEL_P (next);
+ next = next_nonnote_insn (next))
+ if (INSN_P (next) && dead_or_set_p (next, dest))
+ {
+ for (link = LOG_LINKS (next); link; link = XEXP (link, 1))
+ if (XEXP (link, 0) == insn)
+ break;
+
+ if (link)
+ {
+ result = find_single_use_1 (dest, &PATTERN (next));
+ if (ploc)
+ *ploc = next;
+ return result;
+ }
+ }
+
+ return 0;
+}
+\f