/* 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 "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. */
/* 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,
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_last_set_mode
= (enum machine_mode *) alloca (nregs * sizeof (enum machine_mode));
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_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));
setup_incoming_promotions ();
&& 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. */
> 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)
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
/* (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
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,
gen_binary (GET_CODE (XEXP (x, 0)), mode, new,
GEN_INT (newop1)),
INTVAL (c2) - INTVAL (c1),
- NULL_RTX, mode_width - INTVAL (c1),
+ NULL_RTX, mode_width - INTVAL (c2),
code == LSHIFTRT, 0, in_code == COMPARE);
}
&& 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) GET_MODE_BITSIZE (mode))))
+ < (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode))))
break;
if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) < bits)
/* Distributivity is not true for floating point.
It can change the value. So don't do it.
-- rms and moshier@world.std.com. */
- if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+ if (FLOAT_MODE_P (GET_MODE (x)))
return x;
/* The outer operation can only be one of the following: */
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)));
+ num_sign_bit_copies (XEXP (varop, 0),
GET_MODE (XEXP (varop, 0))))
>= GET_MODE_BITSIZE (GET_MODE (varop)))
- && exact_log2 (constop + 1) >= 0)
+ && 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))
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
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))))
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
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))
&& ((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;
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