return apply_change_group ();
}
+
+/* Function to be passed to for_each_rtx to test whether a piece of
+ RTL contains any mem/v. */
+static int
+volatile_mem_p (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+ return (MEM_P (*x) && MEM_VOLATILE_P (*x));
+}
+
+/* Same as validate_change, but doesn't support groups, and it accepts
+ volatile mems if they're already present in the original insn. */
+
+int
+validate_change_maybe_volatile (rtx object, rtx *loc, rtx new)
+{
+ int result;
+
+ if (validate_change (object, loc, new, 0))
+ return 1;
+
+ if (volatile_ok
+ /* If there isn't a volatile MEM, there's nothing we can do. */
+ || !for_each_rtx (&PATTERN (object), volatile_mem_p, 0)
+ /* Make sure we're not adding or removing volatile MEMs. */
+ || for_each_rtx (loc, volatile_mem_p, 0)
+ || for_each_rtx (&new, volatile_mem_p, 0)
+ || !insn_invalid_p (object))
+ return 0;
+
+ volatile_ok = 1;
+
+ gcc_assert (!insn_invalid_p (object));
+
+ result = validate_change (object, loc, new, 0);
+
+ volatile_ok = 0;
+
+ return result;
+}
+
/* This subroutine of apply_change_group verifies whether the changes to INSN
were valid; i.e. whether INSN can still be recognized. */
return num_changes;
}
-/* Apply a group of changes previously issued with `validate_change'.
+/* Tentatively apply the changes numbered NUM and up.
Return 1 if all changes are valid, zero otherwise. */
-int
-apply_change_group (void)
+static int
+verify_changes (int num)
{
int i;
rtx last_validated = NULL_RTX;
we also require that the operands meet the constraints for
the insn. */
- for (i = 0; i < num_changes; i++)
+ for (i = num; i < num_changes; i++)
{
rtx object = changes[i].object;
last_validated = object;
}
- if (i == num_changes)
- {
- basic_block bb;
+ return (i == num_changes);
+}
- for (i = 0; i < num_changes; i++)
- if (changes[i].object
- && INSN_P (changes[i].object)
- && (bb = BLOCK_FOR_INSN (changes[i].object)))
- bb->flags |= BB_DIRTY;
+/* A group of changes has previously been issued with validate_change and
+ verified with verify_changes. Update the BB_DIRTY flags of the affected
+ blocks, and clear num_changes. */
- num_changes = 0;
+void
+confirm_change_group (void)
+{
+ int i;
+ basic_block bb;
+
+ for (i = 0; i < num_changes; i++)
+ if (changes[i].object
+ && INSN_P (changes[i].object)
+ && (bb = BLOCK_FOR_INSN (changes[i].object)))
+ bb->flags |= BB_DIRTY;
+
+ num_changes = 0;
+}
+
+/* Apply a group of changes previously issued with `validate_change'.
+ If all changes are valid, call confirm_change_group and return 1,
+ otherwise, call cancel_changes and return 0. */
+
+int
+apply_change_group (void)
+{
+ if (verify_changes (0))
+ {
+ confirm_change_group ();
return 1;
}
else
}
}
+
/* Return the number of changes so far in the current group. */
int
do
{
+ int seen_earlyclobber_at = -1;
int opno;
int lose = 0;
funny_match_index = 0;
case '&':
earlyclobber[opno] = 1;
+ if (seen_earlyclobber_at < 0)
+ seen_earlyclobber_at = opno;
break;
case '0': case '1': case '2': case '3': case '4':
/* See if any earlyclobber operand conflicts with some other
operand. */
- if (strict > 0)
- for (eopno = 0; eopno < recog_data.n_operands; eopno++)
+ if (strict > 0 && seen_earlyclobber_at >= 0)
+ for (eopno = seen_earlyclobber_at;
+ eopno < recog_data.n_operands;
+ eopno++)
/* Ignore earlyclobber operands now in memory,
because we would often report failure when we have
two memory operands, one of which was formerly a REG. */
{
case REG_NORETURN:
case REG_SETJMP:
- case REG_ALWAYS_RETURN:
REG_NOTES (new_insn)
= gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
XEXP (note, 0),