and set by `-m...' switches. Must be defined in rtlanal.c. */
int target_flags;
+
+/* Truncation narrows the mode from SOURCE mode to DESTINATION mode.
+ If TARGET_MODE_REP_EXTENDED (DESTINATION, DESTINATION_REP) is
+ SIGN_EXTEND then while narrowing we also have to enforce the
+ representation and sign-extend the value to mode DESTINATION_REP.
+
+ If the value is already sign-extended to DESTINATION_REP mode we
+ can just switch to DESTINATION mode on it. For each pair of
+ integral modes SOURCE and DESTINATION, when truncating from SOURCE
+ to DESTINATION, NUM_SIGN_BIT_COPIES_IN_REP[SOURCE][DESTINATION]
+ contains the number of high-order bits in SOURCE that have to be
+ copies of the sign-bit so that we can do this mode-switch to
+ DESTINATION. */
+
+static unsigned int
+num_sign_bit_copies_in_rep[MAX_MODE_INT + 1][MAX_MODE_INT + 1];
\f
/* Return 1 if the value of X is unstable
(would be different at a different point in the program).
case PLUS:
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
- {
- /* Pointers aren't allowed to wrap. If we've got a register
- that is known to be a pointer, and a positive offset, then
- the composite can't be zero. */
- if (INTVAL (XEXP (x, 1)) > 0
- && REG_P (XEXP (x, 0))
- && REG_POINTER (XEXP (x, 0)))
- return true;
-
- return nonzero_address_p (XEXP (x, 0));
- }
+ return nonzero_address_p (XEXP (x, 0));
/* Handle PIC references. */
else if (XEXP (x, 0) == pic_offset_table_rtx
&& CONSTANT_P (XEXP (x, 1)))
return x;
}
\f
-/* Throughout the rtx X, replace many registers according to REG_MAP.
- Return the replacement for X (which may be X with altered contents).
- REG_MAP[R] is the replacement for register R, or 0 for don't replace.
- NREGS is the length of REG_MAP; regs >= NREGS are not mapped.
-
- We only support REG_MAP entries of REG or SUBREG. Also, hard registers
- should not be mapped to pseudos or vice versa since validate_change
- is not called.
-
- If REPLACE_DEST is 1, replacements are also done in destinations;
- otherwise, only sources are replaced. */
-
-rtx
-replace_regs (rtx x, rtx *reg_map, unsigned int nregs, int replace_dest)
-{
- enum rtx_code code;
- int i;
- const char *fmt;
-
- if (x == 0)
- return x;
-
- code = GET_CODE (x);
- switch (code)
- {
- case SCRATCH:
- case PC:
- case CC0:
- case CONST_INT:
- case CONST_DOUBLE:
- case CONST_VECTOR:
- case CONST:
- case SYMBOL_REF:
- case LABEL_REF:
- return x;
-
- case REG:
- /* Verify that the register has an entry before trying to access it. */
- if (REGNO (x) < nregs && reg_map[REGNO (x)] != 0)
- {
- /* SUBREGs can't be shared. Always return a copy to ensure that if
- this replacement occurs more than once then each instance will
- get distinct rtx. */
- if (GET_CODE (reg_map[REGNO (x)]) == SUBREG)
- return copy_rtx (reg_map[REGNO (x)]);
- return reg_map[REGNO (x)];
- }
- return x;
-
- case SUBREG:
- /* Prevent making nested SUBREGs. */
- if (REG_P (SUBREG_REG (x)) && REGNO (SUBREG_REG (x)) < nregs
- && reg_map[REGNO (SUBREG_REG (x))] != 0
- && GET_CODE (reg_map[REGNO (SUBREG_REG (x))]) == SUBREG)
- {
- rtx map_val = reg_map[REGNO (SUBREG_REG (x))];
- return simplify_gen_subreg (GET_MODE (x), map_val,
- GET_MODE (SUBREG_REG (x)),
- SUBREG_BYTE (x));
- }
- break;
-
- case SET:
- if (replace_dest)
- SET_DEST (x) = replace_regs (SET_DEST (x), reg_map, nregs, 0);
-
- else if (MEM_P (SET_DEST (x))
- || GET_CODE (SET_DEST (x)) == STRICT_LOW_PART)
- /* Even if we are not to replace destinations, replace register if it
- is CONTAINED in destination (destination is memory or
- STRICT_LOW_PART). */
- XEXP (SET_DEST (x), 0) = replace_regs (XEXP (SET_DEST (x), 0),
- reg_map, nregs, 0);
- else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
- /* Similarly, for ZERO_EXTRACT we replace all operands. */
- break;
-
- SET_SRC (x) = replace_regs (SET_SRC (x), reg_map, nregs, 0);
- return x;
-
- default:
- break;
- }
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- XEXP (x, i) = replace_regs (XEXP (x, i), reg_map, nregs, replace_dest);
- else if (fmt[i] == 'E')
- {
- int j;
- for (j = 0; j < XVECLEN (x, i); j++)
- XVECEXP (x, i, j) = replace_regs (XVECEXP (x, i, j), reg_map,
- nregs, replace_dest);
- }
- }
- return x;
-}
-
/* Replace occurrences of the old label in *X with the new one.
DATA is a REPLACE_LABEL_DATA containing the old and new labels. */
int
loc_mentioned_in_p (rtx *loc, rtx in)
{
- enum rtx_code code = GET_CODE (in);
- const char *fmt = GET_RTX_FORMAT (code);
+ enum rtx_code code;
+ const char *fmt;
int i, j;
+ if (!in)
+ return 0;
+
+ code = GET_CODE (in);
+ fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (loc == &in->u.fld[i].rt_rtx)
total = COSTS_N_INSNS (7);
break;
case USE:
- /* Used in loop.c and combine.c as a marker. */
+ /* Used in combine.c as a marker. */
total = 0;
break;
default:
allow_cc_mode, valid_at_insn_p);
}
+/* Initialize the table NUM_SIGN_BIT_COPIES_IN_REP based on
+ TARGET_MODE_REP_EXTENDED.
+
+ Note that we assume that the property of
+ TARGET_MODE_REP_EXTENDED(B, C) is sticky to the integral modes
+ narrower than mode B. I.e., if A is a mode narrower than B then in
+ order to be able to operate on it in mode B, mode A needs to
+ satisfy the requirements set by the representation of mode B. */
+
+static void
+init_num_sign_bit_copies_in_rep (void)
+{
+ enum machine_mode mode, in_mode;
+
+ for (in_mode = GET_CLASS_NARROWEST_MODE (MODE_INT); in_mode != VOIDmode;
+ in_mode = GET_MODE_WIDER_MODE (mode))
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != in_mode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ enum machine_mode i;
+
+ /* Currently, it is assumed that TARGET_MODE_REP_EXTENDED
+ extends to the next widest mode. */
+ gcc_assert (targetm.mode_rep_extended (mode, in_mode) == UNKNOWN
+ || GET_MODE_WIDER_MODE (mode) == in_mode);
+
+ /* We are in in_mode. Count how many bits outside of mode
+ have to be copies of the sign-bit. */
+ for (i = mode; i != in_mode; i = GET_MODE_WIDER_MODE (i))
+ {
+ enum machine_mode wider = GET_MODE_WIDER_MODE (i);
+
+ if (targetm.mode_rep_extended (i, wider) == SIGN_EXTEND
+ /* We can only check sign-bit copies starting from the
+ top-bit. In order to be able to check the bits we
+ have already seen we pretend that subsequent bits
+ have to be sign-bit copies too. */
+ || num_sign_bit_copies_in_rep [in_mode][mode])
+ num_sign_bit_copies_in_rep [in_mode][mode]
+ += GET_MODE_BITSIZE (wider) - GET_MODE_BITSIZE (i);
+ }
+ }
+}
+
/* Suppose that truncation from the machine mode of X to MODE is not a
no-op. See if there is anything special about X so that we can
assume it already contains a truncated value of MODE. */
bool
truncated_to_mode (enum machine_mode mode, rtx x)
{
- return REG_P (x) && rtl_hooks.reg_truncated_to_mode (mode, x);
-}
+ /* This register has already been used in MODE without explicit
+ truncation. */
+ if (REG_P (x) && rtl_hooks.reg_truncated_to_mode (mode, x))
+ return true;
+ /* See if we already satisfy the requirements of MODE. If yes we
+ can just switch to MODE. */
+ if (num_sign_bit_copies_in_rep[GET_MODE (x)][mode]
+ && (num_sign_bit_copies (x, GET_MODE (x))
+ >= num_sign_bit_copies_in_rep[GET_MODE (x)][mode] + 1))
+ return true;
+
+ return false;
+}
\f
/* Initialize non_rtx_starting_operands, which is used to speed up
for_each_rtx. */
const char *first = strpbrk (format, "eEV");
non_rtx_starting_operands[i] = first ? first - format : -1;
}
+
+ init_num_sign_bit_copies_in_rep ();
}
\f
/* Check whether this is a constant pool constant. */