===================================================================
@@ -10507,6 +10507,7 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pn
int i;
rtx notes = 0;
rtx old_notes, old_pat;
+ int old_icode;
/* If PAT is a PARALLEL, check to see if it contains the CLOBBER
we use to indicate that something didn't match. If we find such a
@@ -10566,6 +10567,7 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pn
print_rtl_single (dump_file, pat);
}
}
+
PATTERN (insn) = old_pat;
REG_NOTES (insn) = old_notes;
@@ -10607,6 +10609,86 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pn
pat = newpat;
}
+ old_pat = PATTERN (insn);
+ old_notes = REG_NOTES (insn);
+ old_icode = INSN_CODE (insn);
+ PATTERN (insn) = pat;
+ REG_NOTES (insn) = notes;
+
+ /* Check operand constraints in case hard registers were propagated
+ into insn pattern. This check prevents combine pass from
+ generating insn patterns with invalid hard register operands.
+ These invalid insns can eventually confuse reload to error out
+ with a spill failure. See also PR 46829. */
+ if (insn_code_number >= 0
+ && insn_code_number != NOOP_MOVE_INSN_CODE
+ && (INSN_CODE (insn) = recog (PATTERN (insn), insn, 0)) >= 0)
+ {
+ extract_insn (insn);
+ preprocess_constraints ();
+
+ for (i = 0; i < recog_data.n_operands; i++)
+ {
+ rtx op = recog_data.operand[i];
+ enum machine_mode mode = GET_MODE (op);
+ struct operand_alternative *op_alt;
+ int offset = 0;
+ bool win;
+ int j;
+
+ /* A unary operator may be accepted by the predicate, but it
+ is irrelevant for matching constraints. */
+ if (UNARY_P (op))
+ op = XEXP (op, 0);
+
+ if (GET_CODE (op) == SUBREG)
+ {
+ if (REG_P (SUBREG_REG (op))
+ && REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
+ offset = subreg_regno_offset (REGNO (SUBREG_REG (op)),
+ GET_MODE (SUBREG_REG (op)),
+ SUBREG_BYTE (op),
+ GET_MODE (op));
+ op = SUBREG_REG (op);
+ }
+
+ if (!(REG_P (op) && HARD_REGISTER_P (op)))
+ continue;
+
+ op_alt = recog_op_alt[i];
+
+ win = false;
+ for (j = 0; j < recog_data.n_alternatives; j++)
+ {
+ if (op_alt[j].anything_ok
+ || (op_alt[j].matches != -1
+ && rtx_equal_p (recog_data.operand[j],
+ recog_data.operand[op_alt[j].matches]))
+ || (reg_fits_class_p (op, op_alt[j].cl, offset, mode)))
+ {
+ win = true;
+ break;
+ }
+ }
+
+ if (!win)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fputs ("Operand failed to match constraints:\n",
+ dump_file);
+ print_rtl_single (dump_file, op);
+ }
+ insn_code_number = -1;
+ break;
+ }
+ }
+ }
+
+ PATTERN (insn) = old_pat;
+ REG_NOTES (insn) = old_notes;
+ INSN_CODE (insn) = old_icode;
+
*pnewpat = pat;
*pnotes = notes;
===================================================================
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fschedule-insns" } */
+
+struct S
+{
+ int i, j;
+};
+
+extern struct S s[];
+
+extern void bar (int, ...);
+
+void
+foo (int n)
+{
+ while (s[n].i)
+ bar (0, n, s[n].j, s, s[n].i / s[n].j);
+}