/* Optimize by combining instructions for GNU compiler.
- Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1992, 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
combine anyway. */
#include "config.h"
+/* Must precede rtl.h for FFS. */
+#include <stdio.h>
+
#include "gvarargs.h"
#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"
#include "insn-attr.h"
#include "recog.h"
#include "real.h"
-#include <stdio.h>
/* It is not safe to use ordinary gen_lowpart in combine.
Use gen_lowpart_for_combine instead. See comments there. */
#define LOAD_EXTEND ZERO_EXTEND
#endif
-#ifdef BYTE_LOAD_SIGN_EXTEND
+#ifdef BYTE_LOADS_SIGN_EXTEND
#define BYTE_LOADS_EXTEND
#define LOAD_EXTEND SIGN_EXTEND
#endif
/* Record the value of label_tick when the value for register n is placed in
reg_last_set_value[n]. */
-static short *reg_last_set_label;
+static int *reg_last_set_label;
/* Record the value of label_tick when an expression involving register n
is placed in reg_last_set_value. */
-static short *reg_last_set_table_tick;
+static int *reg_last_set_table_tick;
/* Set non-zero if references to register n in expressions should not be
used. */
/* Incremented for each label. */
-static short label_tick;
+static int label_tick;
/* Some registers that are set more than once and used in more than one
basic block are nevertheless always set in similar ways. For example,
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.
static int n_occurrences;
static void set_nonzero_bits_and_sign_copies ();
+static void setup_incoming_promotions ();
static void move_deaths ();
rtx remove_death ();
static void record_value_for_reg ();
combine_merges = 0;
combine_extras = 0;
combine_successes = 0;
+ undobuf.num_undo = previous_num_undos = 0;
combine_max_regno = nregs;
reg_last_death = (rtx *) alloca (nregs * sizeof (rtx));
reg_last_set = (rtx *) alloca (nregs * sizeof (rtx));
reg_last_set_value = (rtx *) alloca (nregs * sizeof (rtx));
- reg_last_set_table_tick = (short *) alloca (nregs * sizeof (short));
- reg_last_set_label = (short *) alloca (nregs * sizeof (short));
+ reg_last_set_table_tick = (int *) alloca (nregs * sizeof (int));
+ reg_last_set_label = (int *) alloca (nregs * sizeof (int));
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, nregs * sizeof (rtx));
bzero (reg_last_set_value, nregs * sizeof (rtx));
- bzero (reg_last_set_table_tick, nregs * sizeof (short));
- bzero (reg_last_set_label, nregs * sizeof (short));
+ bzero (reg_last_set_table_tick, nregs * sizeof (int));
+ bzero (reg_last_set_label, nregs * sizeof (int));
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));
Scan all SETs and see if we can deduce anything about what
bits are known to be zero for some registers and how many copies
- of the sign bit are known to exist for those registers. */
+ of the sign bit are known to exist for those registers.
+
+ Also set any known values so that we can use it while searching
+ for what bits are known to be set. */
+
+ label_tick = 1;
+
+ setup_incoming_promotions ();
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
{
INSN_CUID (insn) = ++i;
+ subst_low_cuid = i;
+ subst_insn = insn;
+
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
- note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies);
+ {
+ note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies);
+ record_dead_and_set_regs (insn);
+ }
+
+ if (GET_CODE (insn) == CODE_LABEL)
+ label_tick++;
}
nonzero_sign_valid = 1;
label_tick = 1;
last_call_cuid = 0;
mem_last_set = 0;
+ bzero (reg_last_death, nregs * sizeof (rtx));
+ bzero (reg_last_set, nregs * sizeof (rtx));
+ bzero (reg_last_set_value, nregs * sizeof (rtx));
+ bzero (reg_last_set_table_tick, nregs * sizeof (int));
+ bzero (reg_last_set_label, nregs * sizeof (int));
+ bzero (reg_last_set_invalid, nregs * sizeof (char));
+
+ setup_incoming_promotions ();
for (insn = f; insn; insn = next ? next : NEXT_INSN (insn))
{
nonzero_sign_valid = 0;
}
\f
+/* Set up any promoted values for incoming argument registers. */
+
+static void
+setup_incoming_promotions ()
+{
+#ifdef PROMOTE_FUNCTION_ARGS
+ int regno;
+ rtx reg;
+ enum machine_mode mode;
+ int unsignedp;
+ rtx first = get_insns ();
+
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (FUNCTION_ARG_REGNO_P (regno)
+ && (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0)
+ record_value_for_reg (reg, first,
+ gen_rtx (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
+ GET_MODE (reg),
+ gen_rtx (CLOBBER, mode, const0_rtx)));
+#endif
+}
+\f
/* Called via note_stores. If X is a pseudo that is used in more than
one basic block, is narrower that HOST_BITS_PER_WIDE_INT, and is being
set, record what bits are known zero. If we are clobbering X,
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
&& reg_n_sets[REGNO (x)] > 1
&& reg_basic_block[REGNO (x)] < 0
+ /* If this register is undefined at the start of the file, we can't
+ say what its contents were. */
+ && ! (basic_block_live_at_start[0][REGNO (x) / REGSET_ELT_BITS]
+ & ((REGSET_ELT_TYPE) 1 << (REGNO (x) % REGSET_ELT_BITS)))
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
{
if (GET_CODE (set) == CLOBBER)
- return;
+ {
+ reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
+ reg_sign_bit_copies[REGNO (x)] = 0;
+ return;
+ }
/* If this is a complex assignment, see if we can convert it into a
simple assignment. */
set = expand_field_assignment (set);
- if (SET_DEST (set) == x)
+
+ /* If this is a simple assignment, or we have a paradoxical SUBREG,
+ set what we know about X. */
+
+ if (SET_DEST (set) == x
+ || (GET_CODE (SET_DEST (set)) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (SET_DEST (set)))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (set)))))
+ && SUBREG_REG (SET_DEST (set)) == x))
{
+ rtx src = SET_SRC (set);
+
+#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
+ /* If X is narrower than a word and SRC is a non-negative
+ constant that would appear negative in the mode of X,
+ sign-extend it for use in reg_nonzero_bits because some
+ machines (maybe most) will actually do the sign-extension
+ and this is the conservative approach.
+
+ ??? For 2.5, try to tighten up the MD files in this regard
+ instead of this kludge. */
+
+ if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD
+ && GET_CODE (src) == CONST_INT
+ && INTVAL (src) > 0
+ && 0 != (INTVAL (src)
+ & ((HOST_WIDE_INT) 1
+ << GET_MODE_BITSIZE (GET_MODE (x)))))
+ src = GEN_INT (INTVAL (src)
+ | ((HOST_WIDE_INT) (-1)
+ << GET_MODE_BITSIZE (GET_MODE (x))));
+#endif
+
reg_nonzero_bits[REGNO (x)]
- |= nonzero_bits (SET_SRC (set), nonzero_bits_mode);
+ |= nonzero_bits (src, nonzero_bits_mode);
num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
if (reg_sign_bit_copies[REGNO (x)] == 0
|| reg_sign_bit_copies[REGNO (x)] > num)
If the insns are adjacent, a use can't cross a set even though we
think it might (this can happen for a sequence of insns each setting
the same destination; reg_last_set of that register might point to
- a NOTE). Also, don't move a volatile asm across any other insns. */
+ a NOTE). Also, don't move a volatile asm or UNSPEC_VOLATILE across
+ any other insns. */
|| (! all_adjacent
&& (use_crosses_set_p (src, INSN_CUID (insn))
- || (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))))
+ || (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))
+ || GET_CODE (src) == UNSPEC_VOLATILE))
/* If there is a REG_NO_CONFLICT note for DEST in I3 or SUCC, we get
better register allocation by not doing the combine. */
|| find_reg_note (i3, REG_NO_CONFLICT, dest)
return 0;
/* If DEST is used in I3, it is being killed in this insn,
- so record that for later. */
+ so record that for later.
+ Never add REG_DEAD notes for the FRAME_POINTER_REGNUM or the
+ STACK_POINTER_REGNUM, since these are always considered to be
+ live. Similarly for ARG_POINTER_REGNUM if it is fixed. */
if (pi3dest_killed && GET_CODE (dest) == REG
- && reg_referenced_p (dest, PATTERN (i3)))
+ && reg_referenced_p (dest, PATTERN (i3))
+ && REGNO (dest) != FRAME_POINTER_REGNUM
+#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
+ && (REGNO (dest) != ARG_POINTER_REGNUM
+ || ! fixed_regs [REGNO (dest)])
+#endif
+ && REGNO (dest) != STACK_POINTER_REGNUM)
{
if (*pi3dest_killed)
return 0;
x = temp, code = GET_CODE (temp);
/* First see if we can apply the inverse distributive law. */
- if (code == PLUS || code == MINUS || code == IOR || code == XOR)
+ if (code == PLUS || code == MINUS
+ || code == AND || code == IOR || code == XOR)
{
x = apply_distributive_law (x);
code = GET_CODE (x);
|| code == MULT || code == AND || code == IOR || code == XOR
|| code == DIV || code == UDIV
|| code == SMAX || code == SMIN || code == UMAX || code == UMIN)
- && GET_MODE_CLASS (mode) == MODE_INT)
+ && INTEGRAL_MODE_P (mode))
{
if (GET_CODE (XEXP (x, 0)) == code)
{
return temp;
}
+ /* If we want a subreg of a constant, at offset 0,
+ take the low bits. On a little-endian machine, that's
+ always valid. On a big-endian machine, it's valid
+ only if the constant's mode fits in one word. */
if (CONSTANT_P (SUBREG_REG (x)) && subreg_lowpart_p (x)
- && GET_MODE_SIZE (mode) < GET_MODE_SIZE (op0_mode))
+ && GET_MODE_SIZE (mode) < GET_MODE_SIZE (op0_mode)
+#if WORDS_BIG_ENDIAN
+ && GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD
+#endif
+ )
return gen_lowpart_for_combine (mode, SUBREG_REG (x));
/* If we are narrowing the object, we need to see if we can simplify
return gen_rtx_combine (reverse_condition (GET_CODE (XEXP (x, 0))),
mode, XEXP (XEXP (x, 0), 0),
XEXP (XEXP (x, 0), 1));
+
+ /* (ashiftrt foo C) where C is the number of bits in FOO minus 1
+ is (lt foo (const_int 0)), so we can perform the above
+ simplification. */
+
+ if (XEXP (x, 1) == const1_rtx
+ && GET_CODE (XEXP (x, 0)) == ASHIFTRT
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1)
+ return gen_rtx_combine (GE, mode, XEXP (XEXP (x, 0), 0), const0_rtx);
#endif
/* Apply De Morgan's laws to reduce number of patterns for machines
/* (neg (minus X Y)) can become (minus Y X). */
if (GET_CODE (XEXP (x, 0)) == MINUS
- && (GET_MODE_CLASS (mode) != MODE_FLOAT
+ && (! FLOAT_MODE_P (mode)
/* x-y != -(y-x) with IEEE floating point. */
|| TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT))
{
/* In IEEE floating point, x-0 is not the same as x. */
if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- || GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) == MODE_INT)
+ || ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0))))
&& XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
return XEXP (x, 0);
break;
goto restart;
}
- /* If only the low-order bit of X is possible nonzero, (plus x -1)
+ /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if
+ C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE
+ is 1. This produces better code than the alternative immediately
+ below. */
+ if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+ && reversible_comparison_p (XEXP (x, 0))
+ && ((STORE_FLAG_VALUE == -1 && XEXP (x, 1) == const1_rtx)
+ || (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx)))
+ {
+ x = gen_binary (reverse_condition (GET_CODE (XEXP (x, 0))),
+ mode, XEXP (XEXP (x, 0), 0), XEXP (XEXP (x, 0), 1));
+ x = gen_unary (NEG, mode, x);
+ goto restart;
+ }
+
+ /* If only the low-order bit of X is possibly nonzero, (plus x -1)
can become (ashiftrt (ashift (xor x 1) C) C) where C is
the bitsize of the mode - 1. This allows simplification of
"a = (b & 8) == 0;" */
/* Look for MIN or MAX. */
- if (GET_MODE_CLASS (mode) == MODE_INT
+ if (! FLOAT_MODE_P (mode)
&& GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
&& rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1))
&& rtx_equal_p (XEXP (XEXP (x, 0), 1), XEXP (x, 2))
return temp;
}
}
+
+ /* If we have (if_then_else (ne A 0) C1 0) and either A is known to
+ be 0 or 1 and C1 is a single bit or A is known to be 0 or -1 and
+ C1 is the negation of a single bit, we can convert this operation
+ to a shift. We can actually do this in more general cases, but it
+ doesn't seem worth it. */
+
+ if (GET_CODE (XEXP (x, 0)) == NE && XEXP (XEXP (x, 0), 1) == const0_rtx
+ && XEXP (x, 2) == const0_rtx && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && ((1 == nonzero_bits (XEXP (XEXP (x, 0), 0), mode)
+ && (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0)
+ || ((num_sign_bit_copies (XEXP (XEXP (x, 0), 0), mode)
+ == GET_MODE_BITSIZE (mode))
+ && (i = exact_log2 (- INTVAL (XEXP (x, 1)))) >= 0)))
+ return
+ simplify_shift_const (NULL_RTX, ASHIFT, mode,
+ gen_lowpart_for_combine (mode,
+ XEXP (XEXP (x, 0), 0)),
+ i);
break;
case ZERO_EXTRACT:
/* Simplify our comparison, if possible. */
new_code = simplify_comparison (old_code, &op0, &op1);
-#if !defined (HAVE_cc0) && defined (EXTRA_CC_MODES)
+#ifdef EXTRA_CC_MODES
/* If this machine has CC modes other than CCmode, check to see
if we need to use a different CC mode here. */
compare_mode = SELECT_CC_MODE (new_code, op0, op1);
+#endif /* EXTRA_CC_MODES */
+#if !defined (HAVE_cc0) && defined (EXTRA_CC_MODES)
/* If the mode changed, we have to change SET_DEST, the mode
in the compare, and the mode in the place SET_DEST is used.
If SET_DEST is a hard register, just build new versions with
means that we only care about the low bits of the result.
However, on most machines (those with neither BYTE_LOADS_ZERO_EXTEND
- nor BYTES_LOADS_SIGN_EXTEND defined), we cannot perform a
+ nor BYTE_LOADS_SIGN_EXTEND defined), we cannot perform a
narrower operation that requested since the high-order bits will
be undefined. On machine where BYTE_LOADS_*_EXTEND is defined,
however, this transformation is safe as long as M1 and M2 have
return gen_rtx_combine (reverse_condition (GET_CODE (XEXP (x, 0))),
mode, XEXP (XEXP (x, 0), 0),
XEXP (XEXP (x, 0), 1));
+
+ /* (lshiftrt foo C) where C is the number of bits in FOO minus 1
+ is (lt foo (const_int 0)), so we can perform the above
+ simplification. */
+
+ if (XEXP (x, 1) == const1_rtx
+ && GET_CODE (XEXP (x, 0)) == LSHIFTRT
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1)
+ return gen_rtx_combine (GE, mode, XEXP (XEXP (x, 0), 0), const0_rtx);
#endif
/* (xor (comparison foo bar) (const_int sign-bit))
endian in both bits and bytes or little endian in bits and bytes.
If it is mixed, we must adjust. */
-#if BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
- if (! spans_byte && is_mode != wanted_mem_mode)
- offset = (GET_MODE_SIZE (is_mode)
- - GET_MODE_SIZE (wanted_mem_mode) - offset);
-#endif
-
/* If bytes are big endian and we had a paradoxical SUBREG, we must
adjust OFFSET to compensate. */
#if BYTES_BIG_ENDIAN
pos %= GET_MODE_BITSIZE (wanted_mem_mode);
}
+#if BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
+ if (! spans_byte && is_mode != wanted_mem_mode)
+ offset = (GET_MODE_SIZE (is_mode)
+ - GET_MODE_SIZE (wanted_mem_mode) - offset);
+#endif
+
if (offset != 0 || inner_mode != wanted_mem_mode)
{
rtx newmem = gen_rtx (MEM, wanted_mem_mode,
enum rtx_code next_code;
int i, count;
rtx new = 0;
+ rtx tem;
char *fmt;
/* Select the code to be used in recursive calls. Once we are inside an
if (in_code == MEM && GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
&& INTVAL (XEXP (x, 1)) >= 0)
- new = gen_rtx_combine (MULT, mode, XEXP (x, 0),
- GEN_INT ((HOST_WIDE_INT) 1
- << INTVAL (XEXP (x, 1))));
+ {
+ new = make_compound_operation (XEXP (x, 0), next_code);
+ new = gen_rtx_combine (MULT, mode, new,
+ GEN_INT ((HOST_WIDE_INT) 1
+ << INTVAL (XEXP (x, 1))));
+ }
break;
case AND:
is a logical right shift, make an extraction. */
if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
&& (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
- new = make_extraction (mode, XEXP (XEXP (x, 0), 0), 0,
- XEXP (XEXP (x, 0), 1), i, 1,
- 0, in_code == COMPARE);
+ {
+ new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+ new = make_extraction (mode, new, 0, XEXP (XEXP (x, 0), 1), i, 1,
+ 0, in_code == COMPARE);
+ }
/* Same as previous, but for (subreg (lshiftrt ...)) in first op. */
else if (GET_CODE (XEXP (x, 0)) == SUBREG
&& subreg_lowpart_p (XEXP (x, 0))
&& GET_CODE (SUBREG_REG (XEXP (x, 0))) == LSHIFTRT
&& (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
- new = make_extraction (GET_MODE (SUBREG_REG (XEXP (x, 0))),
- XEXP (SUBREG_REG (XEXP (x, 0)), 0), 0,
- XEXP (SUBREG_REG (XEXP (x, 0)), 1), i, 1,
- 0, in_code == COMPARE);
-
+ {
+ new = make_compound_operation (XEXP (SUBREG_REG (XEXP (x, 0)), 0),
+ next_code);
+ new = make_extraction (GET_MODE (SUBREG_REG (XEXP (x, 0))), new, 0,
+ XEXP (SUBREG_REG (XEXP (x, 0)), 1), i, 1,
+ 0, in_code == COMPARE);
+ }
/* If we are have (and (rotate X C) M) and C is larger than the number
of bits in M, this is an extraction. */
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0
&& i <= INTVAL (XEXP (XEXP (x, 0), 1)))
- new = make_extraction (mode, XEXP (XEXP (x, 0), 0),
- (GET_MODE_BITSIZE (mode)
- - INTVAL (XEXP (XEXP (x, 0), 1))),
- NULL_RTX, i, 1, 0, in_code == COMPARE);
+ {
+ new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+ new = make_extraction (mode, new,
+ (GET_MODE_BITSIZE (mode)
+ - INTVAL (XEXP (XEXP (x, 0), 1))),
+ NULL_RTX, i, 1, 0, in_code == COMPARE);
+ }
/* On machines without logical shifts, if the operand of the AND is
a logical shift and our mask turns off all the propagated sign
mask >>= INTVAL (XEXP (XEXP (x, 0), 1));
if ((INTVAL (XEXP (x, 1)) & ~mask) == 0)
SUBST (XEXP (x, 0),
- gen_rtx_combine (ASHIFTRT, mode, XEXP (XEXP (x, 0), 0),
+ gen_rtx_combine (ASHIFTRT, mode,
+ make_compound_operation (XEXP (XEXP (x, 0), 0),
+ next_code),
XEXP (XEXP (x, 0), 1)));
}
If it doesn't end up being a ZERO_EXTEND, we will ignore it unless
we are in a COMPARE. */
else if ((i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
- new = make_extraction (mode, XEXP (x, 0), 0, NULL_RTX, i, 1,
- 0, in_code == COMPARE);
+ new = make_extraction (mode,
+ make_compound_operation (XEXP (x, 0),
+ next_code),
+ 0, NULL_RTX, i, 1, 0, in_code == COMPARE);
/* If we are in a comparison and this is an AND with a power of two,
convert this into the appropriate bit extract. */
else if (in_code == COMPARE
&& (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0)
- new = make_extraction (mode, XEXP (x, 0), i, NULL_RTX, 1, 1, 0, 1);
+ new = make_extraction (mode,
+ make_compound_operation (XEXP (x, 0),
+ next_code),
+ i, NULL_RTX, 1, 1, 0, 1);
break;
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (XEXP (x, 0), mode) & (1 << (mode_width - 1))) == 0)
{
- new = gen_rtx_combine (ASHIFTRT, mode, XEXP (x, 0), XEXP (x, 1));
+ new = gen_rtx_combine (ASHIFTRT, mode,
+ make_compound_operation (XEXP (x, 0),
+ next_code),
+ XEXP (x, 1));
break;
}
&& GET_CODE (XEXP (x, 0)) == ASHIFT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= INTVAL (XEXP (XEXP (x, 0), 1)))
- new = make_extraction (mode, XEXP (XEXP (x, 0), 0),
- (INTVAL (XEXP (x, 1))
- - INTVAL (XEXP (XEXP (x, 0), 1))),
- NULL_RTX, mode_width - INTVAL (XEXP (x, 1)),
- code == LSHIFTRT, 0, in_code == COMPARE);
+ {
+ new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+ new = make_extraction (mode, new,
+ (INTVAL (XEXP (x, 1))
+ - INTVAL (XEXP (XEXP (x, 0), 1))),
+ NULL_RTX, mode_width - INTVAL (XEXP (x, 1)),
+ code == LSHIFTRT, 0, in_code == COMPARE);
+ }
/* Similarly if we have (ashifrt (OP (ashift foo C1) C3) C2). In these
cases, we are better off returning a SIGN_EXTEND of the operation. */
|| GET_CODE (XEXP (x, 0)) == PLUS)
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == ASHIFT
&& GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
- && INTVAL (XEXP (x, 1)) >= INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))
&& INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)) < HOST_BITS_PER_WIDE_INT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
- && (INTVAL (XEXP (XEXP (x, 0), 1))
- & (((HOST_WIDE_INT) 1
- << INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))) - 1)) == 0)
+ && 0 == (INTVAL (XEXP (XEXP (x, 0), 1))
+ & (((HOST_WIDE_INT) 1
+ << (MIN (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)),
+ INTVAL (XEXP (x, 1)))
+ - 1)))))
{
- HOST_WIDE_INT newop1
- = (INTVAL (XEXP (XEXP (x, 0), 1))
- >> INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)));
+ rtx c1 = XEXP (XEXP (XEXP (x, 0), 0), 1);
+ rtx c2 = XEXP (x, 1);
+ rtx c3 = XEXP (XEXP (x, 0), 1);
+ HOST_WIDE_INT newop1;
+ rtx inner = XEXP (XEXP (XEXP (x, 0), 0), 0);
+
+ /* If C1 > C2, INNER needs to have the shift performed on it
+ for C1-C2 bits. */
+ if (INTVAL (c1) > INTVAL (c2))
+ {
+ inner = gen_binary (ASHIFT, mode, inner,
+ GEN_INT (INTVAL (c1) - INTVAL (c2)));
+ c1 = c2;
+ }
+ newop1 = INTVAL (c3) >> INTVAL (c1);
+ new = make_compound_operation (inner,
+ GET_CODE (XEXP (x, 0)) == PLUS
+ ? MEM : GET_CODE (XEXP (x, 0)));
new = make_extraction (mode,
- gen_binary (GET_CODE (XEXP (x, 0)), mode,
- XEXP (XEXP (XEXP (x, 0), 0), 0),
+ gen_binary (GET_CODE (XEXP (x, 0)), mode, new,
GEN_INT (newop1)),
- (INTVAL (XEXP (x, 1))
- - INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))),
- NULL_RTX, mode_width - INTVAL (XEXP (x, 1)),
+ INTVAL (c2) - INTVAL (c1),
+ NULL_RTX, mode_width - INTVAL (c2),
code == LSHIFTRT, 0, in_code == COMPARE);
}
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == ASHIFT
&& GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) >= INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)))
- new = make_extraction (mode,
- gen_unary (GET_CODE (XEXP (x, 0)), mode,
- XEXP (XEXP (XEXP (x, 0), 0), 0)),
- (INTVAL (XEXP (x, 1))
- - INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))),
- NULL_RTX, mode_width - INTVAL (XEXP (x, 1)),
- code == LSHIFTRT, 0, in_code == COMPARE);
+ {
+ new = make_compound_operation (XEXP (XEXP (XEXP (x, 0), 0), 0),
+ next_code);
+ new = make_extraction (mode,
+ gen_unary (GET_CODE (XEXP (x, 0)), mode,
+ new, 0),
+ (INTVAL (XEXP (x, 1))
+ - INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))),
+ NULL_RTX, mode_width - INTVAL (XEXP (x, 1)),
+ code == LSHIFTRT, 0, in_code == COMPARE);
+ }
break;
+
+ case SUBREG:
+ /* Call ourselves recursively on the inner expression. If we are
+ narrowing the object and it has a different RTL code from
+ what it originally did, do this SUBREG as a force_to_mode. */
+
+ tem = make_compound_operation (SUBREG_REG (x), in_code);
+ if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x))
+ && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (tem))
+ && subreg_lowpart_p (x))
+ {
+ rtx newer = force_to_mode (tem, mode,
+ GET_MODE_BITSIZE (mode), NULL_RTX);
+
+ /* If we have something other than a SUBREG, we might have
+ done an expansion, so rerun outselves. */
+ if (GET_CODE (newer) != SUBREG)
+ newer = make_compound_operation (newer, in_code);
+
+ return newer;
+ }
}
if (new)
case ASHIFT:
case LSHIFT:
/* For left shifts, do the same, but just for the first operand.
- If the shift count is a constant, we need even fewer bits of the
- first operand. */
-
+ However, we cannot do anything with shifts where we cannot
+ guarantee that the counts are smaller than the size of the mode
+ because such a count will have a different meaning in a
+ wider mode.
+
+ If we can narrow the shift and know the count, we need even fewer
+ bits of the first operand. */
+
+ if (! (GET_CODE (XEXP (x, 1)) == CONST_INT
+ && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (mode))
+ && ! (GET_MODE (XEXP (x, 1)) != VOIDmode
+ && (nonzero_bits (XEXP (x, 1), GET_MODE (XEXP (x, 1)))
+ < (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode))))
+ break;
+
if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) < bits)
bits -= INTVAL (XEXP (x, 1));
case LSHIFTRT:
/* Here we can only do something if the shift count is a constant and
- the count plus BITS is no larger than the width of MODE, we can do
- the shift in MODE. */
+ the count plus BITS is no larger than the width of MODE. In that
+ case, we can do the shift in MODE. */
if (GET_CODE (XEXP (x, 1)) == CONST_INT
&& INTVAL (XEXP (x, 1)) + bits <= GET_MODE_BITSIZE (mode))
rtx tem;
enum rtx_code inner_code;
+ /* Distributivity is not true for floating point.
+ It can change the value. So don't do it.
+ -- rms and moshier@world.std.com. */
+ if (FLOAT_MODE_P (GET_MODE (x)))
+ return x;
+
/* The outer operation can only be one of the following: */
if (code != IOR && code != AND && code != XOR
&& code != PLUS && code != MINUS)
case XOR:
/* If VAROP is (ior (lshiftrt FOO C1) C2), try to commute the IOR and
LSHIFT so we end up with an (and (lshiftrt (ior ...) ...) ...)
- operation which may be a bitfield extraction. */
+ operation which may be a bitfield extraction. Ensure
+ that the constant we form is not wider than the mode of
+ VAROP. */
if (GET_CODE (XEXP (varop, 0)) == LSHIFTRT
&& GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (varop, 0), 1)) >= 0
&& INTVAL (XEXP (XEXP (varop, 0), 1)) < HOST_BITS_PER_WIDE_INT
&& GET_CODE (XEXP (varop, 1)) == CONST_INT
+ && ((INTVAL (XEXP (XEXP (varop, 0), 1))
+ + floor_log2 (INTVAL (XEXP (varop, 1))))
+ < GET_MODE_BITSIZE (GET_MODE (varop)))
&& (INTVAL (XEXP (varop, 1))
& ~ nonzero_bits (XEXP (varop, 0), GET_MODE (varop)) == 0))
{
XEXP (varop, 1), constop))));
case NOT:
- /* (and (not FOO)) is (and (xor FOO CONST_OP)) so if FOO is an
- LSHIFTRT we can do the same as above. */
+ /* (and (not FOO)) is (and (xor FOO CONST)), so if FOO is an
+ LSHIFTRT, we can do the same as above. Ensure that the constant
+ we form is not wider than the mode of VAROP. */
if (GET_CODE (XEXP (varop, 0)) == LSHIFTRT
&& GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (varop, 0), 1)) >= 0
+ && (INTVAL (XEXP (XEXP (varop, 0), 1)) + floor_log2 (constop)
+ < GET_MODE_BITSIZE (GET_MODE (varop)))
&& INTVAL (XEXP (XEXP (varop, 0), 1)) < HOST_BITS_PER_WIDE_INT)
{
temp = GEN_INT (constop << INTVAL (XEXP (XEXP (varop, 0), 1)));
XEXP (varop, 0), XEXP (varop, 1));
break;
+ case LSHIFTRT:
+ /* If we have (and (lshiftrt FOO C1) C2) where the combination of the
+ shift and AND produces only copies of the sign bit (C2 is one less
+ than a power of two), we can do this with just a shift. */
+
+ if (GET_CODE (XEXP (varop, 1)) == CONST_INT
+ && ((INTVAL (XEXP (varop, 1))
+ + num_sign_bit_copies (XEXP (varop, 0),
+ GET_MODE (XEXP (varop, 0))))
+ >= GET_MODE_BITSIZE (GET_MODE (varop)))
+ && exact_log2 (constop + 1) >= 0
+ && (num_sign_bit_copies (XEXP (varop, 0),
+ GET_MODE (XEXP (varop, 0)))
+ >= exact_log2 (constop + 1)))
+ varop
+ = gen_rtx_combine (LSHIFTRT, GET_MODE (varop), XEXP (varop, 0),
+ GEN_INT (GET_MODE_BITSIZE (GET_MODE (varop))
+ - exact_log2 (constop + 1)));
+ break;
+
case NE:
/* (and (ne FOO 0) CONST) can be (and FOO CONST) if CONST is
included in STORE_FLAG_VALUE and FOO has no bits that might be
if (GET_CODE (varop) == CONST_INT)
return GEN_INT (constop & INTVAL (varop));
- /* See what bits may be nonzero in VAROP. */
- nonzero = nonzero_bits (varop, mode);
+ /* See what bits may be nonzero in VAROP. Unlike the general case of
+ a call to nonzero_bits, here we don't care about bits outside
+ MODE. */
+
+ nonzero = nonzero_bits (varop, mode) & GET_MODE_MASK (mode);
/* Turn off all bits in the constant that are known to already be zero.
Thus, if the AND isn't needed at all, we will have CONSTOP == NONZERO_BITS
}
#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)
- return nonzero_bits (tem, mode);
+ {
+#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
+ /* If X is narrower than MODE and TEM is a non-negative
+ constant that would appear negative in the mode of X,
+ sign-extend it for use in reg_nonzero_bits because some
+ machines (maybe most) will actually do the sign-extension
+ and this is the conservative approach.
+
+ ??? For 2.5, try to tighten up the MD files in this regard
+ instead of this kludge. */
+
+ if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width
+ && GET_CODE (tem) == CONST_INT
+ && INTVAL (tem) > 0
+ && 0 != (INTVAL (tem)
+ & ((HOST_WIDE_INT) 1
+ << GET_MODE_BITSIZE (GET_MODE (x)))))
+ tem = GEN_INT (INTVAL (tem)
+ | ((HOST_WIDE_INT) (-1)
+ << GET_MODE_BITSIZE (GET_MODE (x))));
+#endif
+ return nonzero_bits (tem, mode);
+ }
else if (nonzero_sign_valid && reg_nonzero_bits[REGNO (x)])
return reg_nonzero_bits[REGNO (x)] & nonzero;
else
return nonzero;
case CONST_INT:
+#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
+ /* If X is negative in MODE, sign-extend the value. */
+ if (INTVAL (x) > 0
+ && 0 != (INTVAL (x)
+ & ((HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (GET_MODE (x)))))
+ return (INTVAL (x)
+ | ((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (GET_MODE (x))));
+#endif
+
return INTVAL (x);
#ifdef BYTE_LOADS_ZERO_EXTEND
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
high-order bits are known to be sign bit copies. */
if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x))
- return (GET_MODE_BITSIZE (mode) - GET_MODE_BITSIZE (GET_MODE (x))
- + num_sign_bit_copies (SUBREG_REG (x), GET_MODE (x)));
+ return MAX (bitwidth - GET_MODE_BITSIZE (GET_MODE (x)) + 1,
+ num_sign_bit_copies (SUBREG_REG (x), mode));
/* For a smaller object, just ignore the high bits. */
if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))
be 0 or 1, we know the result is either -1 or 0. */
if (code == PLUS && XEXP (x, 1) == constm1_rtx
- && bitwidth <= HOST_BITS_PER_INT)
+ && bitwidth <= HOST_BITS_PER_WIDE_INT)
{
nonzero = nonzero_bits (XEXP (x, 0), mode);
if ((((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero) == 0)
result = bitwidth - (bitwidth - num0) - (bitwidth - num1);
if (result > 0
- && bitwidth <= HOST_BITS_PER_INT
+ && bitwidth <= HOST_BITS_PER_WIDE_INT
&& ((nonzero_bits (XEXP (x, 0), mode)
& ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
&& (nonzero_bits (XEXP (x, 1), mode)
return 1;
nonzero = nonzero_bits (x, mode);
- return (nonzero == GET_MODE_MASK (mode)
+ return (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))
? 1 : bitwidth - floor_log2 (nonzero) - 1);
}
\f
break;
}
+ /* If we are doing an arithmetic right shift and discarding all but
+ the sign bit copies, this is equivalent to doing a shift by the
+ bitsize minus one. Convert it into that shift because it will often
+ allow other simplifications. */
+
+ if (code == ASHIFTRT
+ && (count + num_sign_bit_copies (varop, shift_mode)
+ >= GET_MODE_BITSIZE (shift_mode)))
+ count = GET_MODE_BITSIZE (shift_mode) - 1;
+
/* We simplify the tests below and elsewhere by converting
ASHIFTRT to LSHIFTRT if we know the sign bit is clear.
`make_compound_operation' will convert it to a ASHIFTRT for
SUBST (XEXP (x, 1), const_rtx);
}
+ /* If we have an outer operation and we just made a shift, it is
+ possible that we could have simplified the shift were it not
+ for the outer operation. So try to do the simplification
+ recursively. */
+
+ if (outer_op != NIL && GET_CODE (x) == code
+ && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ x = simplify_shift_const (x, code, shift_mode, XEXP (x, 0),
+ INTVAL (XEXP (x, 1)));
+
/* If we were doing a LSHIFTRT in a wider mode than it was originally,
turn off all the bits that the shift would have turned off. */
if (orig_code == LSHIFTRT && result_mode != shift_mode)
&& INTVAL (XEXP (SUBREG_REG (op0), 1)) < 0
&& (- INTVAL (XEXP (SUBREG_REG (op0), 1))
< GET_MODE_MASK (mode) / 2)
- && (unsigned) const_op < GET_MODE_MASK (mode) / 2
+ && (unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode) / 2
&& (0 == (nonzero_bits (XEXP (SUBREG_REG (op0), 0),
GET_MODE (SUBREG_REG (op0)))
& ~ GET_MODE_MASK (mode))
break;
case PLUS:
- /* (eq (plus X C1) C2) -> (eq X (minus C2 C1)). We can only do
+ /* (eq (plus X A) B) -> (eq X (minus B A)). We can only do
this for equality comparisons due to pathological cases involving
overflows. */
- if (equality_comparison_p && GET_CODE (XEXP (op0, 1)) == CONST_INT
- && (tem = simplify_binary_operation (MINUS, mode, op1,
- XEXP (op0, 1))) != 0)
+ if (equality_comparison_p
+ && 0 != (tem = simplify_binary_operation (MINUS, mode,
+ op1, XEXP (op0, 1))))
{
op0 = XEXP (op0, 0);
op1 = tem;
break;
case MINUS:
+ /* (eq (minus A B) C) -> (eq A (plus B C)) or
+ (eq B (minus A C)), whichever simplifies. We can only do
+ this for equality comparisons due to pathological cases involving
+ overflows. */
+ if (equality_comparison_p
+ && 0 != (tem = simplify_binary_operation (PLUS, mode,
+ XEXP (op0, 1), op1)))
+ {
+ op0 = XEXP (op0, 0);
+ op1 = tem;
+ continue;
+ }
+
+ if (equality_comparison_p
+ && 0 != (tem = simplify_binary_operation (MINUS, mode,
+ XEXP (op0, 0), op1)))
+ {
+ op0 = XEXP (op0, 1);
+ op1 = tem;
+ continue;
+ }
+
/* The sign bit of (minus (ashiftrt X C) X), where C is the number
of bits in X minus 1, is one iff X > 0. */
if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == ASHIFTRT
&& ((INTVAL (XEXP (op0, 1)) + ! equality_comparison_p)
< HOST_BITS_PER_WIDE_INT)
&& ((const_op
- & ((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1) == 0)
+ & (((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1)) == 0)
&& mode_width <= HOST_BITS_PER_WIDE_INT
&& (nonzero_bits (XEXP (op0, 0), mode)
& ~ (mask >> (INTVAL (XEXP (op0, 1))
switch (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))))
{
case MODE_INT:
+ case MODE_PARTIAL_INT:
+ case MODE_COMPLEX_INT:
return 1;
case MODE_CC:
x = get_last_value (XEXP (x, 0));
return (x && GET_CODE (x) == COMPARE
- && GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) == MODE_INT);
+ && ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0))));
}
return 0;
/* Record that REG is set to VALUE in insn INSN. If VALUE is zero, we
are saying that the register is clobbered and we no longer know its
- value. If INSN is zero, don't update reg_last_set; this call is normally
- done with VALUE also zero to invalidate the register. */
+ value. If INSN is zero, don't update reg_last_set; this is only permitted
+ with VALUE also zero and is used to invalidate the register. */
static void
record_value_for_reg (reg, insn, value)
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)
+ {
+ subst_low_cuid = INSN_CUID (insn);
+ 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)
- reg_last_death[REGNO (XEXP (link, 0))] = insn;
+ if (REG_NOTE_KIND (link) == REG_DEAD
+ && GET_CODE (XEXP (link, 0)) == REG)
+ {
+ int regno = REGNO (XEXP (link, 0));
+ int endregno
+ = regno + (regno < FIRST_PSEUDO_REGISTER
+ ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (link, 0)))
+ : 1);
+
+ for (i = regno; i < endregno; i++)
+ reg_last_death[i] = insn;
+ }
else if (REG_NOTE_KIND (link) == REG_INC)
record_value_for_reg (XEXP (link, 0), insn, NULL_RTX);
}
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,
if (where_dead && INSN_CUID (where_dead) >= from_cuid
&& INSN_CUID (where_dead) < INSN_CUID (to_insn))
{
- rtx note = remove_death (regno, reg_last_death[regno]);
+ rtx note = remove_death (regno, where_dead);
/* It is possible for the call above to return 0. This can occur
when reg_last_death points to I2 or I1 that we combined with.
- In that case make a new note. */
+ In that case make a new note.
+
+ We must also check for the case where X is a hard register
+ and NOTE is a death note for a range of hard registers
+ including X. In that case, we must put REG_DEAD notes for
+ the remaining registers in place of NOTE. */
- if (note)
+ if (note != 0 && regno < FIRST_PSEUDO_REGISTER
+ && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
+ != GET_MODE_SIZE (GET_MODE (x))))
+ {
+ int deadregno = REGNO (XEXP (note, 0));
+ int deadend
+ = (deadregno + HARD_REGNO_NREGS (deadregno,
+ GET_MODE (XEXP (note, 0))));
+ int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+ int i;
+
+ for (i = deadregno; i < deadend; i++)
+ if (i < regno || i >= ourend)
+ REG_NOTES (where_dead)
+ = gen_rtx (EXPR_LIST, REG_DEAD,
+ gen_rtx (REG, word_mode, i),
+ REG_NOTES (where_dead));
+ }
+
+ if (note != 0 && GET_MODE (XEXP (note, 0)) == GET_MODE (x))
{
XEXP (note, 1) = *pnotes;
*pnotes = note;
all_used = 0;
}
+ /* Check for the case where the register dying partially
+ overlaps the register set by this insn. */
+ if (all_used)
+ for (i = regno; i < endregno; i++)
+ if (dead_or_set_regno_p (place, i))
+ {
+ all_used = 0;
+ break;
+ }
+
if (! all_used)
{
/* Put only REG_DEAD notes for pieces that are