#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "tm_p.h"
#include "insn-config.h"
an INSN, CALL_INSN, or JUMP_INSN, the insn will be re-recognized with
the change in place.
- IN_GROUP is non-zero if this is part of a group of changes that must be
+ IN_GROUP is nonzero if this is part of a group of changes that must be
performed as a group. In that case, the changes will be stored. The
function `apply_change_group' will validate and apply the changes.
return 0;
}
+/* Return number of changes made and not validated yet. */
+int
+num_changes_pending ()
+{
+ return num_changes;
+}
+
/* Apply a group of changes previously issued with `validate_change'.
Return 1 if all changes are valid, zero otherwise. */
for (i = 0; i < num_changes; i++)
if (changes[i].object
&& INSN_P (changes[i].object)
- && basic_block_for_insn
- && ((unsigned int)INSN_UID (changes[i].object)
- < basic_block_for_insn->num_elements)
&& (bb = BLOCK_FOR_INSN (changes[i].object)))
bb->flags |= BB_DIRTY;
{
case PLUS:
/* If we have a PLUS whose second operand is now a CONST_INT, use
- plus_constant to try to simplify it.
+ simplify_gen_binary to try to simplify it.
??? We may want later to remove this, once simplification is
separated from this function. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to)
validate_change (object, loc,
simplify_gen_binary
(PLUS, GET_MODE (x), XEXP (x, 0), XEXP (x, 1)), 1);
}
/* Try replacing every occurrence of FROM in INSN with TO, avoiding
- SET_DESTs. After all changes have been made, validate by seeing if
- INSN is still valid. */
+ SET_DESTs. */
-int
-validate_replace_src (from, to, insn)
+void
+validate_replace_src_group (from, to, insn)
rtx from, to, insn;
{
struct validate_replace_src_data d;
d.to = to;
d.insn = insn;
note_uses (&PATTERN (insn), validate_replace_src_1, &d);
+}
+
+/* Same as validate_repalace_src_group, but validate by seeing if
+ INSN is still valid. */
+int
+validate_replace_src (from, to, insn)
+ rtx from, to, insn;
+{
+ validate_replace_src_group (from, to, insn);
return apply_change_group ();
}
\f
sequel. If so, return a pointer to the innermost rtx expression in which
it is used.
- If PLOC is non-zero, *PLOC is set to the insn containing the single use.
+ If PLOC is nonzero, *PLOC is set to the insn containing the single use.
This routine will return usually zero either before flow is called (because
there will be no LOG_LINKS notes) or after reload (because the REG_DEAD
return 0;
if (GET_CODE (op) == CONST_INT
+ && mode != VOIDmode
&& trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
return 0;
if (code == SUBREG)
{
+ rtx sub = SUBREG_REG (op);
+
#ifdef INSN_SCHEDULING
/* On machines that have insn scheduling, we want all memory
reference to be explicit, so outlaw paradoxical SUBREGs. */
- if (GET_CODE (SUBREG_REG (op)) == MEM
- && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
+ if (GET_CODE (sub) == MEM
+ && GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (sub)))
return 0;
#endif
/* Avoid memories with nonzero SUBREG_BYTE, as offsetting the memory
??? This is a kludge. */
if (!reload_completed && SUBREG_BYTE (op) != 0
- && GET_CODE (SUBREG_REG (op)) == MEM)
+ && GET_CODE (sub) == MEM)
return 0;
- op = SUBREG_REG (op);
+ /* FLOAT_MODE subregs can't be paradoxical. Combine will occasionally
+ create such rtl, and we must reject it. */
+ if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
+ && GET_MODE_SIZE (GET_MODE (op)) > GET_MODE_SIZE (GET_MODE (sub)))
+ return 0;
+
+ op = sub;
code = GET_CODE (op);
}
if (GET_CODE (op) == SUBREG)
{
+ rtx sub = SUBREG_REG (op);
+
/* Before reload, we can allow (SUBREG (MEM...)) as a register operand
because it is guaranteed to be reloaded into one.
Just make sure the MEM is valid in itself.
(Ideally, (SUBREG (MEM)...) should not exist after reload,
but currently it does result from (SUBREG (REG)...) where the
reg went on the stack.) */
- if (! reload_completed && GET_CODE (SUBREG_REG (op)) == MEM)
+ if (! reload_completed && GET_CODE (sub) == MEM)
return general_operand (op, mode);
-#ifdef CLASS_CANNOT_CHANGE_MODE
- if (GET_CODE (SUBREG_REG (op)) == REG
- && REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER
- && (TEST_HARD_REG_BIT
- (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
- REGNO (SUBREG_REG (op))))
- && CLASS_CANNOT_CHANGE_MODE_P (mode, GET_MODE (SUBREG_REG (op)))
- && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) != MODE_COMPLEX_INT
- && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) != MODE_COMPLEX_FLOAT)
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ if (GET_CODE (sub) == REG
+ && REGNO (sub) < FIRST_PSEUDO_REGISTER
+ && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), mode, GET_MODE (sub))
+ && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT
+ && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_FLOAT)
return 0;
#endif
- op = SUBREG_REG (op);
+ /* FLOAT_MODE subregs can't be paradoxical. Combine will occasionally
+ create such rtl, and we must reject it. */
+ if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
+ && GET_MODE_SIZE (GET_MODE (op)) > GET_MODE_SIZE (GET_MODE (sub)))
+ return 0;
+
+ op = sub;
}
/* If we have an ADDRESSOF, consider it valid since it will be
return 0;
if (GET_CODE (op) == CONST_INT
+ && mode != VOIDmode
&& trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
return 0;
return 0;
if (GET_CODE (op) == CONST_INT
+ && mode != VOIDmode
&& trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
return 0;
case 'E':
case 'F':
- if (GET_CODE (op) == CONST_DOUBLE)
+ if (GET_CODE (op) == CONST_DOUBLE
+ || (GET_CODE (op) == CONST_VECTOR
+ && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
return 1;
break;
#ifdef EXTRA_CONSTRAINT
if (EXTRA_CONSTRAINT (op, c))
return 1;
+ if (EXTRA_MEMORY_CONSTRAINT (c))
+ {
+ /* Every memory operand can be reloaded to fit. */
+ if (memory_operand (op, VOIDmode))
+ return 1;
+ }
+ if (EXTRA_ADDRESS_CONSTRAINT (c))
+ {
+ /* Every address operand can be reloaded to fit. */
+ if (address_operand (op, VOIDmode))
+ return 1;
+ }
#endif
break;
}
break;
default:
+ if (EXTRA_MEMORY_CONSTRAINT (c))
+ {
+ op_alt[j].memory_ok = 1;
+ break;
+ }
+ if (EXTRA_ADDRESS_CONSTRAINT (c))
+ {
+ op_alt[j].is_address = 1;
+ op_alt[j].class = reg_class_subunion[(int) op_alt[j].class]
+ [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+ break;
+ }
+
op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) REG_CLASS_FROM_LETTER ((unsigned char) c)];
break;
}
This is used in final, just before printing the assembler code and by
the routines that determine an insn's attribute.
- If STRICT is a positive non-zero value, it means that we have been
+ If STRICT is a positive nonzero value, it means that we have been
called after reload has been completed. In that case, we must
do all checks strictly. If it is zero, it means that we have been called
before reload has completed. In that case, we first try to see if we can
case 'E':
case 'F':
- if (GET_CODE (op) == CONST_DOUBLE)
+ if (GET_CODE (op) == CONST_DOUBLE
+ || (GET_CODE (op) == CONST_VECTOR
+ && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
win = 1;
break;
#ifdef EXTRA_CONSTRAINT
else if (EXTRA_CONSTRAINT (op, c))
win = 1;
+
+ if (EXTRA_MEMORY_CONSTRAINT (c))
+ {
+ /* Every memory operand can be reloaded to fit. */
+ if (strict < 0 && GET_CODE (op) == MEM)
+ win = 1;
+
+ /* Before reload, accept what reload can turn into mem. */
+ if (strict < 0 && CONSTANT_P (op))
+ win = 1;
+
+ /* During reload, accept a pseudo */
+ if (reload_in_progress && GET_CODE (op) == REG
+ && REGNO (op) >= FIRST_PSEUDO_REGISTER)
+ win = 1;
+ }
+ if (EXTRA_ADDRESS_CONSTRAINT (c))
+ {
+ /* Every address operand can be reloaded to fit. */
+ if (strict < 0)
+ win = 1;
+ }
#endif
break;
}
cfg-related call notes. */
for (i = 0; i <= match_len; ++i)
{
- int j, k;
+ int j;
rtx old_insn, new_insn, note;
j = i + peep2_current;
continue;
was_call = true;
- new_insn = NULL_RTX;
- if (GET_CODE (try) == SEQUENCE)
- for (k = XVECLEN (try, 0) - 1; k >= 0; k--)
- {
- rtx x = XVECEXP (try, 0, k);
- if (GET_CODE (x) == CALL_INSN)
- {
- new_insn = x;
- break;
- }
- }
- else if (GET_CODE (try) == CALL_INSN)
- new_insn = try;
- if (! new_insn)
+ new_insn = try;
+ while (new_insn != NULL_RTX)
+ {
+ if (GET_CODE (new_insn) == CALL_INSN)
+ break;
+ new_insn = NEXT_INSN (new_insn);
+ }
+
+ if (new_insn == NULL_RTX)
abort ();
CALL_INSN_FUNCTION_USAGE (new_insn)
REG_EH_REGION, NULL_RTX);
/* Replace the old sequence with the new. */
- try = emit_insn_after (try, peep2_insn_data[i].insn);
+ try = emit_insn_after_scope (try, peep2_insn_data[i].insn,
+ INSN_SCOPE (peep2_insn_data[i].insn));
before_try = PREV_INSN (insn);
delete_insn_chain (insn, peep2_insn_data[i].insn);