#include "rtl.h"
#include "flags.h"
#include "regs.h"
+#include "hard-reg-set.h"
#include "expr.h"
#include "basic-block.h"
#include "insn-config.h"
If an entry is zero, it means that we don't know anything special. */
-static HOST_WIDE_INT *reg_nonzero_bits;
+static unsigned HOST_WIDE_INT *reg_nonzero_bits;
/* Mode used to compute significance in reg_nonzero_bits. It is the largest
integer mode that can fit in HOST_BITS_PER_WIDE_INT. */
which can be incorrect if a variable is modified in a loop. */
static int nonzero_sign_valid;
+
+/* These arrays are maintained in parallel with reg_last_set_value
+ and are used to store the mode in which the register was last set,
+ the bits that were known to be zero when it was last set, and the
+ number of sign bits copies it was known to have when it was last set. */
+
+static enum machine_mode *reg_last_set_mode;
+static unsigned HOST_WIDE_INT *reg_last_set_nonzero_bits;
+static char *reg_last_set_sign_bit_copies;
\f
/* Record one modification to rtl structure
to be undone by storing old_contents into *where.
reg_last_set_table_tick = (short *) alloca (nregs * sizeof (short));
reg_last_set_label = (short *) alloca (nregs * sizeof (short));
reg_last_set_invalid = (char *) alloca (nregs * sizeof (char));
- reg_nonzero_bits = (HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT));
+ reg_last_set_mode
+ = (enum machine_mode *) alloca (nregs * sizeof (enum machine_mode));
+ reg_last_set_nonzero_bits
+ = (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT));
+ reg_last_set_sign_bit_copies
+ = (char *) alloca (nregs * sizeof (char));
+
+ reg_nonzero_bits
+ = (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT));
reg_sign_bit_copies = (char *) alloca (nregs * sizeof (char));
bzero (reg_last_death, nregs * sizeof (rtx));
bzero (reg_last_set_table_tick, nregs * sizeof (short));
bzero (reg_last_set_label, nregs * sizeof (short));
bzero (reg_last_set_invalid, nregs * sizeof (char));
+ bzero (reg_last_set_mode, nregs * sizeof (enum machine_mode));
+ bzero (reg_last_set_nonzero_bits, nregs * sizeof (HOST_WIDE_INT));
+ bzero (reg_last_set_sign_bit_copies, nregs * sizeof (char));
bzero (reg_nonzero_bits, nregs * sizeof (HOST_WIDE_INT));
bzero (reg_sign_bit_copies, nregs * sizeof (char));
}
#endif
- /* If X is a register whose value we can find, use that value.
- Otherwise, use the previously-computed nonzero bits for this
- register. */
+ /* If X is a register whose nonzero bits value is current, use it.
+ Otherwise, if X is a register whose value we can find, use that
+ value. Otherwise, use the previously-computed global nonzero bits
+ for this register. */
+
+ if (reg_last_set_value[REGNO (x)] != 0
+ && reg_last_set_mode[REGNO (x)] == mode
+ && (reg_n_sets[REGNO (x)] == 1
+ || reg_last_set_label[REGNO (x)] == label_tick)
+ && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
+ return reg_last_set_nonzero_bits[REGNO (x)];
tem = get_last_value (x);
if (tem)
switch (code)
{
case REG:
- if (nonzero_sign_valid && reg_sign_bit_copies[REGNO (x)] != 0)
- return reg_sign_bit_copies[REGNO (x)];
+
+ if (reg_last_set_value[REGNO (x)] != 0
+ && reg_last_set_mode[REGNO (x)] == mode
+ && (reg_n_sets[REGNO (x)] == 1
+ || reg_last_set_label[REGNO (x)] == label_tick)
+ && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
+ return reg_last_set_sign_bit_copies[REGNO (x)];
tem = get_last_value (x);
if (tem != 0)
return num_sign_bit_copies (tem, mode);
+
+ if (nonzero_sign_valid && reg_sign_bit_copies[REGNO (x)] != 0)
+ return reg_sign_bit_copies[REGNO (x)];
break;
#ifdef BYTE_LOADS_SIGN_EXTEND
value = 0;
}
- /* For the main register being modified, update the value. */
+ /* For the main register being modified, update the value, the mode, the
+ nonzero bits, and the number of sign bit copies. */
+
reg_last_set_value[regno] = value;
+ if (value)
+ {
+ reg_last_set_mode[regno] = GET_MODE (reg);
+ reg_last_set_nonzero_bits[regno] = nonzero_bits (value, GET_MODE (reg));
+ reg_last_set_sign_bit_copies[regno]
+ = num_sign_bit_copies (value, GET_MODE (reg));
+ }
}
/* Used for communication between the following two routines. */
rtx insn;
{
register rtx link;
+ int i;
+
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
{
if (REG_NOTE_KIND (link) == REG_DEAD
= regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (link, 0)))
: 1);
- int i;
for (i = regno; i < endregno; i++)
reg_last_death[i] = insn;
}
if (GET_CODE (insn) == CALL_INSN)
- last_call_cuid = mem_last_set = INSN_CUID (insn);
+ {
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (call_used_regs[i])
+ {
+ reg_last_set_value[i] = 0;
+ reg_last_death[i] = 0;
+ }
+
+ last_call_cuid = mem_last_set = INSN_CUID (insn);
+ }
record_dead_insn = insn;
note_stores (PATTERN (insn), record_dead_and_set_regs_1);
if (value == 0
|| (reg_n_sets[regno] != 1
- && (reg_last_set_label[regno] != label_tick)))
+ && reg_last_set_label[regno] != label_tick))
return 0;
/* If the value was set in a later insn that the ones we are processing,