]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Makefile.in (OBJS): Add rtlhooks.o.
authorPaolo Bonzini <bonzini@gnu.org>
Tue, 25 May 2004 12:04:17 +0000 (12:04 +0000)
committerPaolo Bonzini <bonzini@gcc.gnu.org>
Tue, 25 May 2004 12:04:17 +0000 (12:04 +0000)
2004-05-25  Paolo Bonzini  <bonzini@gnu.org>

* Makefile.in (OBJS): Add rtlhooks.o.
(rtlanal.o): Depend on function.h.
(cse.o): Depend on rtlhooks-def.h.
(combine.o): Depend on rtlhooks-def.h.
(rtlhooks.o): New rule.
* combine.c: Include rtlhooks-def.h.
(nonzero_bits, cached_nonzero_bits, nonzero_bits1,
num_sign_bit_copies, cached_num_sign_bit_copies,
num_sign_bit_copies1): Move most of the code to rtlanal.c.
(reg_nonzero_bits_for_combine,
reg_num_sign_bit_copies_for_combine): New functions holding
the remnants of the above.
(combine_rtl_hooks): New.
(combine_instructions): Set rtl_hooks instead of gen_lowpart.
* cse.c: Include rtlhooks-def.h.
(cse_rtl_hooks): New.
(cse_main): Set rtl_hooks instead of gen_lowpart.
* emit-rtl.c (gen_lowpart): Remove.
(gen_lowpart_general): Move to rtlhooks.c.
* rtl.h (nonzero_bits, num_sign_bit_copies,
struct rtl_hooks, rtl_hooks, general_rtl_hooks): New.
(gen_lowpart_general): Remove.
(gen_lowpart): Temporarily redefine as a macro.
* rtlanal.c: Include function.h.
(nonzero_bits, cached_nonzero_bits, nonzero_bits1,
num_sign_bit_copies, cached_num_sign_bit_copies,
num_sign_bit_copies1): New, from combine.c.
* rtlhooks.c: New file.

From-SVN: r82234

gcc/ChangeLog
gcc/Makefile.in
gcc/combine.c
gcc/cse.c
gcc/emit-rtl.c
gcc/rtl.h
gcc/rtlanal.c
gcc/rtlhooks-def.h [new file with mode: 0644]
gcc/rtlhooks.c [new file with mode: 0644]

index c5419232d7b24dafd0232c5ac55463f453d02b2b..5248ce15104b3ef2209ee13dc0b5ac00c000e881 100644 (file)
@@ -1,3 +1,34 @@
+2004-05-25  Paolo Bonzini  <bonzini@gnu.org>
+
+       * Makefile.in (OBJS): Add rtlhooks.o.
+       (rtlanal.o): Depend on function.h.
+       (cse.o): Depend on rtlhooks-def.h.
+       (combine.o): Depend on rtlhooks-def.h.
+       (rtlhooks.o): New rule.
+       * combine.c: Include rtlhooks-def.h.
+       (nonzero_bits, cached_nonzero_bits, nonzero_bits1,
+       num_sign_bit_copies, cached_num_sign_bit_copies,
+       num_sign_bit_copies1): Move most of the code to rtlanal.c.
+       (reg_nonzero_bits_for_combine,
+       reg_num_sign_bit_copies_for_combine): New functions holding
+       the remnants of the above.
+       (combine_rtl_hooks): New.
+       (combine_instructions): Set rtl_hooks instead of gen_lowpart.
+       * cse.c: Include rtlhooks-def.h.
+       (cse_rtl_hooks): New.
+       (cse_main): Set rtl_hooks instead of gen_lowpart.
+       * emit-rtl.c (gen_lowpart): Remove.
+       (gen_lowpart_general): Move to rtlhooks.c.
+       * rtl.h (nonzero_bits, num_sign_bit_copies,
+       struct rtl_hooks, rtl_hooks, general_rtl_hooks): New.
+       (gen_lowpart_general): Remove.
+       (gen_lowpart): Temporarily redefine as a macro.
+       * rtlanal.c: Include function.h.
+       (nonzero_bits, cached_nonzero_bits, nonzero_bits1,
+       num_sign_bit_copies, cached_num_sign_bit_copies,
+       num_sign_bit_copies1): New, from combine.c.
+       * rtlhooks.c: New file. 
+
 2004-05-25  Svein E. Seldal  <Svein.Seldal@solidas.com>
 
        * config/avr/avr.h (LONG_LONG_TYPE_SIZE): Changed long long type
index 63552c5ff8c9b11de268e75bec1856dd4c51b560..568b263a1917f33b5b3a5ed89fe781a839e017d7 100644 (file)
@@ -901,7 +901,7 @@ OBJS-common = \
  targhooks.o timevar.o toplev.o tracer.o tree.o tree-dump.o unroll.o      \
  varasm.o varray.o version.o vmsdbgout.o xcoffout.o alloc-pool.o          \
  et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o    \
- rtl-profile.o tree-profile.o
+ rtl-profile.o tree-profile.o rtlhooks.o
 
 OBJS-md = $(out_object_file)
 OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) tree-inline.o               \
@@ -1735,7 +1735,7 @@ print-rtl.o : print-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
     $(RTL_H) $(TREE_H) hard-reg-set.h $(BASIC_BLOCK_H) real.h $(TM_P_H)
 rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h \
    $(RTL_H) hard-reg-set.h $(TM_P_H) insn-config.h $(RECOG_H) real.h flags.h \
-   $(BASIC_BLOCK_H) $(REGS_H) output.h target.h
+   $(BASIC_BLOCK_H) $(REGS_H) output.h target.h function.h
 
 errors.o : errors.c $(CONFIG_H) $(SYSTEM_H) errors.h
        $(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
@@ -1837,7 +1837,7 @@ cselib.o : cselib.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_
 cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
    hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \
    output.h function.h $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H) \
-   except.h $(TARGET_H) $(PARAMS_H)
+   except.h $(TARGET_H) $(PARAMS_H) rtlhooks-def.h
 web.o : web.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
    hard-reg-set.h flags.h $(BASIC_BLOCK_H) function.h output.h toplev.h df.h
 gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
@@ -1938,7 +1938,7 @@ dominance.o : dominance.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    hard-reg-set.h $(BASIC_BLOCK_H) et-forest.h
 et-forest.o : et-forest.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) et-forest.h alloc-pool.h
 combine.o : combine.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) flags.h \
-   function.h insn-config.h $(INSN_ATTR_H) $(REGS_H) $(EXPR_H) \
+   function.h insn-config.h $(INSN_ATTR_H) $(REGS_H) $(EXPR_H) rtlhooks-def.h \
    $(BASIC_BLOCK_H) $(RECOG_H) real.h hard-reg-set.h toplev.h $(TM_P_H) $(TREE_H) $(TARGET_H)
 regclass.o : regclass.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    hard-reg-set.h flags.h $(BASIC_BLOCK_H) $(REGS_H) insn-config.h $(RECOG_H) reload.h \
@@ -1975,6 +1975,8 @@ reload1.o : reload1.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) real.
    $(EXPR_H) $(OPTABS_H) reload.h $(REGS_H) hard-reg-set.h insn-config.h \
    $(BASIC_BLOCK_H) $(RECOG_H) output.h function.h toplev.h $(TM_P_H) \
    except.h $(TREE_H)
+rtlhooks.o :  rtlhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
+   rtlhooks-def.h $(EXPR_H)
 postreload.o : postreload.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) real.h flags.h \
    $(EXPR_H) $(OPTABS_H) reload.h $(REGS_H) hard-reg-set.h insn-config.h \
    $(BASIC_BLOCK_H) $(RECOG_H) output.h function.h toplev.h cselib.h $(TM_P_H) \
index 5a1f89bd83da7b53d3d62ab503a4582073032555..64af27c779bd3e3ecc84f4e62ad8e0084b08c475 100644 (file)
@@ -90,6 +90,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "real.h"
 #include "toplev.h"
 #include "target.h"
+#include "rtlhooks-def.h"
 
 /* Number of attempts to combine instructions in this function.  */
 
@@ -133,12 +134,6 @@ static int max_uid_cuid;
 #define UWIDE_SHIFT_LEFT_BY_BITS_PER_WORD(val) \
   (((unsigned HOST_WIDE_INT) (val) << (BITS_PER_WORD - 1)) << 1)
 
-#define nonzero_bits(X, M) \
-  cached_nonzero_bits (X, M, NULL_RTX, VOIDmode, 0)
-
-#define num_sign_bit_copies(X, M) \
-  cached_num_sign_bit_copies (X, M, NULL_RTX, VOIDmode, 0)
-
 /* Maximum register number, which is the size of the tables below.  */
 
 static unsigned int combine_max_regno;
@@ -337,6 +332,13 @@ static struct undobuf undobuf;
 
 static int n_occurrences;
 
+static rtx reg_nonzero_bits_for_combine (rtx, enum machine_mode, rtx,
+                                        enum machine_mode,
+                                        unsigned HOST_WIDE_INT,
+                                        unsigned HOST_WIDE_INT *);
+static rtx reg_num_sign_bit_copies_for_combine (rtx, enum machine_mode, rtx,
+                                               enum machine_mode,
+                                               unsigned int, unsigned int *);
 static void do_SUBST (rtx *, rtx);
 static void do_SUBST_INT (int *, int);
 static void init_reg_last (void);
@@ -372,17 +374,6 @@ static rtx make_field_assignment (rtx);
 static rtx apply_distributive_law (rtx);
 static rtx simplify_and_const_int (rtx, enum machine_mode, rtx,
                                   unsigned HOST_WIDE_INT);
-static unsigned HOST_WIDE_INT cached_nonzero_bits (rtx, enum machine_mode,
-                                                  rtx, enum machine_mode,
-                                                  unsigned HOST_WIDE_INT);
-static unsigned HOST_WIDE_INT nonzero_bits1 (rtx, enum machine_mode, rtx,
-                                            enum machine_mode,
-                                            unsigned HOST_WIDE_INT);
-static unsigned int cached_num_sign_bit_copies (rtx, enum machine_mode, rtx,
-                                               enum machine_mode,
-                                               unsigned int);
-static unsigned int num_sign_bit_copies1 (rtx, enum machine_mode, rtx,
-                                         enum machine_mode, unsigned int);
 static int merge_outer_ops (enum rtx_code *, HOST_WIDE_INT *, enum rtx_code,
                            HOST_WIDE_INT, enum machine_mode, int *);
 static rtx simplify_shift_const        (rtx, enum rtx_code, enum machine_mode, rtx,
@@ -412,6 +403,21 @@ static rtx reversed_comparison (rtx, enum machine_mode, rtx, rtx);
 static enum rtx_code combine_reversed_comparison_code (rtx);
 static int unmentioned_reg_p_1 (rtx *, void *);
 static bool unmentioned_reg_p (rtx, rtx);
+\f
+
+/* It is not safe to use ordinary gen_lowpart in combine.
+   See comments in gen_lowpart_for_combine.  */
+#undef RTL_HOOKS_GEN_LOWPART
+#define RTL_HOOKS_GEN_LOWPART              gen_lowpart_for_combine
+
+#undef RTL_HOOKS_REG_NONZERO_REG_BITS
+#define RTL_HOOKS_REG_NONZERO_REG_BITS     reg_nonzero_bits_for_combine
+
+#undef RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES
+#define RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES  reg_num_sign_bit_copies_for_combine
+
+static const struct rtl_hooks combine_rtl_hooks = RTL_HOOKS_INITIALIZER;
+
 \f
 /* Substitute NEWVAL, an rtx expression, into INTO, a place in some
    insn.  The substitution can be undone by undo_all.  If INTO is already
@@ -522,9 +528,7 @@ combine_instructions (rtx f, unsigned int nregs)
 
   combine_max_regno = nregs;
 
-  /* It is not safe to use ordinary gen_lowpart in combine.
-     See comments in gen_lowpart_for_combine.  */
-  gen_lowpart = gen_lowpart_for_combine;
+  rtl_hooks = combine_rtl_hooks;
 
   reg_stat = xcalloc (nregs, sizeof (struct reg_stat));
 
@@ -777,7 +781,7 @@ combine_instructions (rtx f, unsigned int nregs)
   total_successes += combine_successes;
 
   nonzero_sign_valid = 0;
-  gen_lowpart = gen_lowpart_general;
+  rtl_hooks = general_rtl_hooks;
 
   /* Make recognizer allow volatile MEMs again.  */
   init_recog ();
@@ -7997,577 +8001,78 @@ simplify_and_const_int (rtx x, enum machine_mode mode, rtx varop,
   return x;
 }
 \f
-#define nonzero_bits_with_known(X, MODE) \
-  cached_nonzero_bits (X, MODE, known_x, known_mode, known_ret)
-
-/* The function cached_nonzero_bits is a wrapper around nonzero_bits1.
-   It avoids exponential behavior in nonzero_bits1 when X has
-   identical subexpressions on the first or the second level.  */
-
-static unsigned HOST_WIDE_INT
-cached_nonzero_bits (rtx x, enum machine_mode mode, rtx known_x,
-                    enum machine_mode known_mode,
-                    unsigned HOST_WIDE_INT known_ret)
-{
-  if (x == known_x && mode == known_mode)
-    return known_ret;
-
-  /* Try to find identical subexpressions.  If found call
-     nonzero_bits1 on X with the subexpressions as KNOWN_X and the
-     precomputed value for the subexpression as KNOWN_RET.  */
-
-  if (ARITHMETIC_P (x))
-    {
-      rtx x0 = XEXP (x, 0);
-      rtx x1 = XEXP (x, 1);
-
-      /* Check the first level.  */
-      if (x0 == x1)
-       return nonzero_bits1 (x, mode, x0, mode,
-                             nonzero_bits_with_known (x0, mode));
-
-      /* Check the second level.  */
-      if (ARITHMETIC_P (x0)
-         && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
-       return nonzero_bits1 (x, mode, x1, mode,
-                             nonzero_bits_with_known (x1, mode));
-
-      if (ARITHMETIC_P (x1)
-         && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
-       return nonzero_bits1 (x, mode, x0, mode,
-                        nonzero_bits_with_known (x0, mode));
-    }
-
-  return nonzero_bits1 (x, mode, known_x, known_mode, known_ret);
-}
-
-/* We let num_sign_bit_copies recur into nonzero_bits as that is useful.
-   We don't let nonzero_bits recur into num_sign_bit_copies, because that
-   is less useful.  We can't allow both, because that results in exponential
-   run time recursion.  There is a nullstone testcase that triggered
-   this.  This macro avoids accidental uses of num_sign_bit_copies.  */
-#define cached_num_sign_bit_copies()
-
-/* Given an expression, X, compute which bits in X can be nonzero.
+/* Given a REG, X, compute which bits in X can be nonzero.
    We don't care about bits outside of those defined in MODE.
 
    For most X this is simply GET_MODE_MASK (GET_MODE (MODE)), but if X is
    a shift, AND, or zero_extract, we can do better.  */
 
-static unsigned HOST_WIDE_INT
-nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x,
-              enum machine_mode known_mode,
-              unsigned HOST_WIDE_INT known_ret)
+static rtx
+reg_nonzero_bits_for_combine (rtx x, enum machine_mode mode,
+                             rtx known_x ATTRIBUTE_UNUSED,
+                             enum machine_mode known_mode ATTRIBUTE_UNUSED,
+                             unsigned HOST_WIDE_INT known_ret ATTRIBUTE_UNUSED,
+                             unsigned HOST_WIDE_INT *nonzero)
 {
-  unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
-  unsigned HOST_WIDE_INT inner_nz;
-  enum rtx_code code;
-  unsigned int mode_width = GET_MODE_BITSIZE (mode);
   rtx tem;
 
-  /* For floating-point values, assume all bits are needed.  */
-  if (FLOAT_MODE_P (GET_MODE (x)) || FLOAT_MODE_P (mode))
-    return nonzero;
+  /* 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 X is wider than MODE, use its mode instead.  */
-  if (GET_MODE_BITSIZE (GET_MODE (x)) > mode_width)
+  if (reg_stat[REGNO (x)].last_set_value != 0
+      && (reg_stat[REGNO (x)].last_set_mode == mode
+          || (GET_MODE_CLASS (reg_stat[REGNO (x)].last_set_mode) == MODE_INT
+             && GET_MODE_CLASS (mode) == MODE_INT))
+      && (reg_stat[REGNO (x)].last_set_label == label_tick
+         || (REGNO (x) >= FIRST_PSEUDO_REGISTER
+             && REG_N_SETS (REGNO (x)) == 1
+             && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
+                                   REGNO (x))))
+      && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
     {
-      mode = GET_MODE (x);
-      nonzero = GET_MODE_MASK (mode);
-      mode_width = GET_MODE_BITSIZE (mode);
+      *nonzero &= reg_stat[REGNO (x)].last_set_nonzero_bits;
+      return NULL;
     }
 
-  if (mode_width > HOST_BITS_PER_WIDE_INT)
-    /* Our only callers in this case look for single bit values.  So
-       just return the mode mask.  Those tests will then be false.  */
-    return nonzero;
-
-#ifndef WORD_REGISTER_OPERATIONS
-  /* If MODE is wider than X, but both are a single word for both the host
-     and target machines, we can compute this from which bits of the
-     object might be nonzero in its own mode, taking into account the fact
-     that on many CISC machines, accessing an object in a wider mode
-     causes the high-order bits to become undefined.  So they are
-     not known to be zero.  */
-
-  if (GET_MODE (x) != VOIDmode && GET_MODE (x) != mode
-      && GET_MODE_BITSIZE (GET_MODE (x)) <= BITS_PER_WORD
-      && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
-      && GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (GET_MODE (x)))
-    {
-      nonzero &= nonzero_bits_with_known (x, GET_MODE (x));
-      nonzero |= GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x));
-      return nonzero;
-    }
-#endif
+  tem = get_last_value (x);
 
-  code = GET_CODE (x);
-  switch (code)
+  if (tem)
     {
-    case REG:
-#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
-      /* If pointers extend unsigned and this is a pointer in Pmode, say that
-        all the bits above ptr_mode are known to be zero.  */
-      if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
-         && REG_POINTER (x))
-       nonzero &= GET_MODE_MASK (ptr_mode);
-#endif
-
-      /* Include declared information about alignment of pointers.  */
-      /* ??? We don't properly preserve REG_POINTER changes across
-        pointer-to-integer casts, so we can't trust it except for
-        things that we know must be pointers.  See execute/960116-1.c.  */
-      if ((x == stack_pointer_rtx
-          || x == frame_pointer_rtx
-          || x == arg_pointer_rtx)
-         && REGNO_POINTER_ALIGN (REGNO (x)))
-       {
-         unsigned HOST_WIDE_INT alignment
-           = REGNO_POINTER_ALIGN (REGNO (x)) / BITS_PER_UNIT;
-
-#ifdef PUSH_ROUNDING
-         /* If PUSH_ROUNDING is defined, it is possible for the
-            stack to be momentarily aligned only to that amount,
-            so we pick the least alignment.  */
-         if (x == stack_pointer_rtx && PUSH_ARGS)
-           alignment = MIN ((unsigned HOST_WIDE_INT) PUSH_ROUNDING (1),
-                            alignment);
-#endif
-
-         nonzero &= ~(alignment - 1);
-       }
-
-      /* 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_stat[REGNO (x)].last_set_value != 0
-         && (reg_stat[REGNO (x)].last_set_mode == mode
-             || (GET_MODE_CLASS (reg_stat[REGNO (x)].last_set_mode) == MODE_INT
-                 && GET_MODE_CLASS (mode) == MODE_INT))
-         && (reg_stat[REGNO (x)].last_set_label == label_tick
-             || (REGNO (x) >= FIRST_PSEUDO_REGISTER
-                 && REG_N_SETS (REGNO (x)) == 1
-                 && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
-                                       REGNO (x))))
-         && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
-       return reg_stat[REGNO (x)].last_set_nonzero_bits & nonzero;
-
-      tem = get_last_value (x);
-
-      if (tem)
-       {
-#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_stat[].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)) - 1))))
-           tem = GEN_INT (INTVAL (tem)
-                          | ((HOST_WIDE_INT) (-1)
-                             << GET_MODE_BITSIZE (GET_MODE (x))));
-#endif
-         return nonzero_bits_with_known (tem, mode) & nonzero;
-       }
-      else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits)
-       {
-         unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits;
-
-         if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width)
-           /* We don't know anything about the upper bits.  */
-           mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (GET_MODE (x));
-         return nonzero & mask;
-       }
-      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 && mode_width < BITS_PER_WORD
-         && 0 != (INTVAL (x) & ((HOST_WIDE_INT) 1 << (mode_width - 1))))
-       return (INTVAL (x) | ((HOST_WIDE_INT) (-1) << mode_width));
-#endif
-
-      return INTVAL (x);
-
-    case MEM:
-#ifdef LOAD_EXTEND_OP
-      /* In many, if not most, RISC machines, reading a byte from memory
-        zeros the rest of the register.  Noticing that fact saves a lot
-        of extra zero-extends.  */
-      if (LOAD_EXTEND_OP (GET_MODE (x)) == ZERO_EXTEND)
-       nonzero &= GET_MODE_MASK (GET_MODE (x));
-#endif
-      break;
-
-    case EQ:  case NE:
-    case UNEQ:  case LTGT:
-    case GT:  case GTU:  case UNGT:
-    case LT:  case LTU:  case UNLT:
-    case GE:  case GEU:  case UNGE:
-    case LE:  case LEU:  case UNLE:
-    case UNORDERED: case ORDERED:
-
-      /* If this produces an integer result, we know which bits are set.
-        Code here used to clear bits outside the mode of X, but that is
-        now done above.  */
-
-      if (GET_MODE_CLASS (mode) == MODE_INT
-         && mode_width <= HOST_BITS_PER_WIDE_INT)
-       nonzero = STORE_FLAG_VALUE;
-      break;
-
-    case NEG:
-#if 0
-      /* Disabled to avoid exponential mutual recursion between nonzero_bits
-        and num_sign_bit_copies.  */
-      if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
-         == GET_MODE_BITSIZE (GET_MODE (x)))
-       nonzero = 1;
-#endif
-
-      if (GET_MODE_SIZE (GET_MODE (x)) < mode_width)
-       nonzero |= (GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x)));
-      break;
-
-    case ABS:
-#if 0
-      /* Disabled to avoid exponential mutual recursion between nonzero_bits
-        and num_sign_bit_copies.  */
-      if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
-         == GET_MODE_BITSIZE (GET_MODE (x)))
-       nonzero = 1;
-#endif
-      break;
-
-    case TRUNCATE:
-      nonzero &= (nonzero_bits_with_known (XEXP (x, 0), mode)
-                 & GET_MODE_MASK (mode));
-      break;
-
-    case ZERO_EXTEND:
-      nonzero &= nonzero_bits_with_known (XEXP (x, 0), mode);
-      if (GET_MODE (XEXP (x, 0)) != VOIDmode)
-       nonzero &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
-      break;
-
-    case SIGN_EXTEND:
-      /* If the sign bit is known clear, this is the same as ZERO_EXTEND.
-        Otherwise, show all the bits in the outer mode but not the inner
-        may be nonzero.  */
-      inner_nz = nonzero_bits_with_known (XEXP (x, 0), mode);
-      if (GET_MODE (XEXP (x, 0)) != VOIDmode)
-       {
-         inner_nz &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
-         if (inner_nz
-             & (((HOST_WIDE_INT) 1
-                 << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1))))
-           inner_nz |= (GET_MODE_MASK (mode)
-                        & ~GET_MODE_MASK (GET_MODE (XEXP (x, 0))));
-       }
-
-      nonzero &= inner_nz;
-      break;
-
-    case AND:
-      nonzero &= (nonzero_bits_with_known (XEXP (x, 0), mode)
-                 & nonzero_bits_with_known (XEXP (x, 1), mode));
-      break;
-
-    case XOR:   case IOR:
-    case UMIN:  case UMAX:  case SMIN:  case SMAX:
-      {
-       unsigned HOST_WIDE_INT nonzero0 =
-         nonzero_bits_with_known (XEXP (x, 0), mode);
-
-       /* Don't call nonzero_bits for the second time if it cannot change
-          anything.  */
-       if ((nonzero & nonzero0) != nonzero)
-         nonzero &= (nonzero0
-                     | nonzero_bits_with_known (XEXP (x, 1), mode));
-      }
-      break;
-
-    case PLUS:  case MINUS:
-    case MULT:
-    case DIV:   case UDIV:
-    case MOD:   case UMOD:
-      /* We can apply the rules of arithmetic to compute the number of
-        high- and low-order zero bits of these operations.  We start by
-        computing the width (position of the highest-order nonzero bit)
-        and the number of low-order zero bits for each value.  */
-      {
-       unsigned HOST_WIDE_INT nz0 =
-         nonzero_bits_with_known (XEXP (x, 0), mode);
-       unsigned HOST_WIDE_INT nz1 =
-         nonzero_bits_with_known (XEXP (x, 1), mode);
-       int sign_index = GET_MODE_BITSIZE (GET_MODE (x)) - 1;
-       int width0 = floor_log2 (nz0) + 1;
-       int width1 = floor_log2 (nz1) + 1;
-       int low0 = floor_log2 (nz0 & -nz0);
-       int low1 = floor_log2 (nz1 & -nz1);
-       HOST_WIDE_INT op0_maybe_minusp
-         = (nz0 & ((HOST_WIDE_INT) 1 << sign_index));
-       HOST_WIDE_INT op1_maybe_minusp
-         = (nz1 & ((HOST_WIDE_INT) 1 << sign_index));
-       unsigned int result_width = mode_width;
-       int result_low = 0;
-
-       switch (code)
-         {
-         case PLUS:
-           result_width = MAX (width0, width1) + 1;
-           result_low = MIN (low0, low1);
-           break;
-         case MINUS:
-           result_low = MIN (low0, low1);
-           break;
-         case MULT:
-           result_width = width0 + width1;
-           result_low = low0 + low1;
-           break;
-         case DIV:
-           if (width1 == 0)
-             break;
-           if (! op0_maybe_minusp && ! op1_maybe_minusp)
-             result_width = width0;
-           break;
-         case UDIV:
-           if (width1 == 0)
-             break;
-           result_width = width0;
-           break;
-         case MOD:
-           if (width1 == 0)
-             break;
-           if (! op0_maybe_minusp && ! op1_maybe_minusp)
-             result_width = MIN (width0, width1);
-           result_low = MIN (low0, low1);
-           break;
-         case UMOD:
-           if (width1 == 0)
-             break;
-           result_width = MIN (width0, width1);
-           result_low = MIN (low0, low1);
-           break;
-         default:
-           abort ();
-         }
-
-       if (result_width < mode_width)
-         nonzero &= ((HOST_WIDE_INT) 1 << result_width) - 1;
-
-       if (result_low > 0)
-         nonzero &= ~(((HOST_WIDE_INT) 1 << result_low) - 1);
-
-#ifdef POINTERS_EXTEND_UNSIGNED
-       /* If pointers extend unsigned and this is an addition or subtraction
-          to a pointer in Pmode, all the bits above ptr_mode are known to be
-          zero.  */
-       if (POINTERS_EXTEND_UNSIGNED > 0 && GET_MODE (x) == Pmode
-           && (code == PLUS || code == MINUS)
-           && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0)))
-         nonzero &= GET_MODE_MASK (ptr_mode);
-#endif
-      }
-      break;
-
-    case ZERO_EXTRACT:
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
-       nonzero &= ((HOST_WIDE_INT) 1 << INTVAL (XEXP (x, 1))) - 1;
-      break;
-
-    case SUBREG:
-      /* If this is a SUBREG formed for a promoted variable that has
-        been zero-extended, we know that at least the high-order bits
-        are zero, though others might be too.  */
-
-      if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x) > 0)
-       nonzero = (GET_MODE_MASK (GET_MODE (x))
-                  & nonzero_bits_with_known (SUBREG_REG (x), GET_MODE (x)));
-
-      /* If the inner mode is a single word for both the host and target
-        machines, we can compute this from which bits of the inner
-        object might be nonzero.  */
-      if (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) <= BITS_PER_WORD
-         && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
-             <= HOST_BITS_PER_WIDE_INT))
-       {
-         nonzero &= nonzero_bits_with_known (SUBREG_REG (x), mode);
-
-#if defined (WORD_REGISTER_OPERATIONS) && defined (LOAD_EXTEND_OP)
-         /* If this is a typical RISC machine, we only have to worry
-            about the way loads are extended.  */
-         if ((LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
-              ? (((nonzero
-                   & (((unsigned HOST_WIDE_INT) 1
-                       << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1))))
-                  != 0))
-              : LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND)
-             || GET_CODE (SUBREG_REG (x)) != MEM)
+      /* 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)) < GET_MODE_BITSIZE (mode)
+         && GET_CODE (tem) == CONST_INT
+         && INTVAL (tem) > 0
+         && 0 != (INTVAL (tem)
+                  & ((HOST_WIDE_INT) 1
+                     << (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
+       tem = GEN_INT (INTVAL (tem)
+                      | ((HOST_WIDE_INT) (-1)
+                         << GET_MODE_BITSIZE (GET_MODE (x))));
 #endif
-           {
-             /* On many CISC machines, accessing an object in a wider mode
-                causes the high-order bits to become undefined.  So they are
-                not known to be zero.  */
-             if (GET_MODE_SIZE (GET_MODE (x))
-                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-               nonzero |= (GET_MODE_MASK (GET_MODE (x))
-                           & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x))));
-           }
-       }
-      break;
-
-    case ASHIFTRT:
-    case LSHIFTRT:
-    case ASHIFT:
-    case ROTATE:
-      /* The nonzero bits are in two classes: any bits within MODE
-        that aren't in GET_MODE (x) are always significant.  The rest of the
-        nonzero bits are those that are significant in the operand of
-        the shift when shifted the appropriate number of bits.  This
-        shows that high-order bits are cleared by the right shift and
-        low-order bits by left shifts.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) >= 0
-         && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
-       {
-         enum machine_mode inner_mode = GET_MODE (x);
-         unsigned int width = GET_MODE_BITSIZE (inner_mode);
-         int count = INTVAL (XEXP (x, 1));
-         unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (inner_mode);
-         unsigned HOST_WIDE_INT op_nonzero =
-           nonzero_bits_with_known (XEXP (x, 0), mode);
-         unsigned HOST_WIDE_INT inner = op_nonzero & mode_mask;
-         unsigned HOST_WIDE_INT outer = 0;
-
-         if (mode_width > width)
-           outer = (op_nonzero & nonzero & ~mode_mask);
-
-         if (code == LSHIFTRT)
-           inner >>= count;
-         else if (code == ASHIFTRT)
-           {
-             inner >>= count;
-
-             /* If the sign bit may have been nonzero before the shift, we
-                need to mark all the places it could have been copied to
-                by the shift as possibly nonzero.  */
-             if (inner & ((HOST_WIDE_INT) 1 << (width - 1 - count)))
-               inner |= (((HOST_WIDE_INT) 1 << count) - 1) << (width - count);
-           }
-         else if (code == ASHIFT)
-           inner <<= count;
-         else
-           inner = ((inner << (count % width)
-                     | (inner >> (width - (count % width)))) & mode_mask);
-
-         nonzero &= (outer | inner);
-       }
-      break;
-
-    case FFS:
-    case POPCOUNT:
-      /* This is at most the number of bits in the mode.  */
-      nonzero = ((HOST_WIDE_INT) 2 << (floor_log2 (mode_width))) - 1;
-      break;
-
-    case CLZ:
-      /* If CLZ has a known value at zero, then the nonzero bits are
-        that value, plus the number of bits in the mode minus one.  */
-      if (CLZ_DEFINED_VALUE_AT_ZERO (mode, nonzero))
-       nonzero |= ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1;
-      else
-       nonzero = -1;
-      break;
-
-    case CTZ:
-      /* If CTZ has a known value at zero, then the nonzero bits are
-        that value, plus the number of bits in the mode minus one.  */
-      if (CTZ_DEFINED_VALUE_AT_ZERO (mode, nonzero))
-       nonzero |= ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1;
-      else
-       nonzero = -1;
-      break;
-
-    case PARITY:
-      nonzero = 1;
-      break;
-
-    case IF_THEN_ELSE:
-      nonzero &= (nonzero_bits_with_known (XEXP (x, 1), mode)
-                 | nonzero_bits_with_known (XEXP (x, 2), mode));
-      break;
-
-    default:
-      break;
+      return tem;
     }
-
-  return nonzero;
-}
-
-/* See the macro definition above.  */
-#undef cached_num_sign_bit_copies
-\f
-#define num_sign_bit_copies_with_known(X, M) \
-  cached_num_sign_bit_copies (X, M, known_x, known_mode, known_ret)
-
-/* The function cached_num_sign_bit_copies is a wrapper around
-   num_sign_bit_copies1.  It avoids exponential behavior in
-   num_sign_bit_copies1 when X has identical subexpressions on the
-   first or the second level.  */
-
-static unsigned int
-cached_num_sign_bit_copies (rtx x, enum machine_mode mode, rtx known_x,
-                           enum machine_mode known_mode,
-                           unsigned int known_ret)
-{
-  if (x == known_x && mode == known_mode)
-    return known_ret;
-
-  /* Try to find identical subexpressions.  If found call
-     num_sign_bit_copies1 on X with the subexpressions as KNOWN_X and
-     the precomputed value for the subexpression as KNOWN_RET.  */
-
-  if (ARITHMETIC_P (x))
+  else if (nonzero_sign_valid && reg_stat[REGNO (x)].nonzero_bits)
     {
-      rtx x0 = XEXP (x, 0);
-      rtx x1 = XEXP (x, 1);
-
-      /* Check the first level.  */
-      if (x0 == x1)
-       return
-         num_sign_bit_copies1 (x, mode, x0, mode,
-                               num_sign_bit_copies_with_known (x0, mode));
-
-      /* Check the second level.  */
-      if (ARITHMETIC_P (x0)
-         && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
-       return
-         num_sign_bit_copies1 (x, mode, x1, mode,
-                               num_sign_bit_copies_with_known (x1, mode));
+      unsigned HOST_WIDE_INT mask = reg_stat[REGNO (x)].nonzero_bits;
 
-      if (ARITHMETIC_P (x1)
-         && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
-       return
-         num_sign_bit_copies1 (x, mode, x0, mode,
-                               num_sign_bit_copies_with_known (x0, mode));
+      if (GET_MODE_BITSIZE (GET_MODE (x)) < GET_MODE_BITSIZE (mode))
+        /* We don't know anything about the upper bits.  */
+        mask |= GET_MODE_MASK (mode) ^ GET_MODE_MASK (GET_MODE (x));
+      *nonzero &= mask;
     }
 
-  return num_sign_bit_copies1 (x, mode, known_x, known_mode, known_ret);
+  return NULL;
 }
 
 /* Return the number of bits at the high-order end of X that are known to
@@ -8575,354 +8080,38 @@ cached_num_sign_bit_copies (rtx x, enum machine_mode mode, rtx known_x,
    VOIDmode, X will be used in its own mode.  The returned value  will always
    be between 1 and the number of bits in MODE.  */
 
-static unsigned int
-num_sign_bit_copies1 (rtx x, enum machine_mode mode, rtx known_x,
-                     enum machine_mode known_mode,
-                     unsigned int known_ret)
+static rtx
+reg_num_sign_bit_copies_for_combine (rtx x, enum machine_mode mode,
+                                    rtx known_x ATTRIBUTE_UNUSED,
+                                    enum machine_mode known_mode
+                                    ATTRIBUTE_UNUSED,
+                                    unsigned int known_ret ATTRIBUTE_UNUSED,
+                                    unsigned int *result)
 {
-  enum rtx_code code = GET_CODE (x);
-  unsigned int bitwidth;
-  int num0, num1, result;
-  unsigned HOST_WIDE_INT nonzero;
   rtx tem;
 
-  /* If we weren't given a mode, use the mode of X.  If the mode is still
-     VOIDmode, we don't know anything.  Likewise if one of the modes is
-     floating-point.  */
-
-  if (mode == VOIDmode)
-    mode = GET_MODE (x);
-
-  if (mode == VOIDmode || FLOAT_MODE_P (mode) || FLOAT_MODE_P (GET_MODE (x)))
-    return 1;
-
-  bitwidth = GET_MODE_BITSIZE (mode);
-
-  /* For a smaller object, just ignore the high bits.  */
-  if (bitwidth < GET_MODE_BITSIZE (GET_MODE (x)))
+  if (reg_stat[REGNO (x)].last_set_value != 0
+      && reg_stat[REGNO (x)].last_set_mode == mode
+      && (reg_stat[REGNO (x)].last_set_label == label_tick
+          || (REGNO (x) >= FIRST_PSEUDO_REGISTER
+             && REG_N_SETS (REGNO (x)) == 1
+             && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
+                                   REGNO (x))))
+      && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
     {
-      num0 = num_sign_bit_copies_with_known (x, GET_MODE (x));
-      return MAX (1,
-                 num0 - (int) (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth));
-    }
-
-  if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_BITSIZE (GET_MODE (x)))
-    {
-#ifndef WORD_REGISTER_OPERATIONS
-  /* If this machine does not do all register operations on the entire
-     register and MODE is wider than the mode of X, we can say nothing
-     at all about the high-order bits.  */
-      return 1;
-#else
-      /* Likewise on machines that do, if the mode of the object is smaller
-        than a word and loads of that size don't sign extend, we can say
-        nothing about the high order bits.  */
-      if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD
-#ifdef LOAD_EXTEND_OP
-         && LOAD_EXTEND_OP (GET_MODE (x)) != SIGN_EXTEND
-#endif
-         )
-       return 1;
-#endif
+      *result = reg_stat[REGNO (x)].last_set_sign_bit_copies;
+      return NULL;
     }
 
-  switch (code)
-    {
-    case REG:
+  tem = get_last_value (x);
+  if (tem != 0)
+    return tem;
 
-#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
-      /* If pointers extend signed and this is a pointer in Pmode, say that
-        all the bits above ptr_mode are known to be sign bit copies.  */
-      if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && mode == Pmode
-         && REG_POINTER (x))
-       return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1;
-#endif
-
-      if (reg_stat[REGNO (x)].last_set_value != 0
-         && reg_stat[REGNO (x)].last_set_mode == mode
-         && (reg_stat[REGNO (x)].last_set_label == label_tick
-             || (REGNO (x) >= FIRST_PSEUDO_REGISTER
-                 && REG_N_SETS (REGNO (x)) == 1
-                 && ! REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start,
-                                       REGNO (x))))
-         && INSN_CUID (reg_stat[REGNO (x)].last_set) < subst_low_cuid)
-       return reg_stat[REGNO (x)].last_set_sign_bit_copies;
-
-      tem = get_last_value (x);
-      if (tem != 0)
-       return num_sign_bit_copies_with_known (tem, mode);
-
-      if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0
-         && GET_MODE_BITSIZE (GET_MODE (x)) == bitwidth)
-       return reg_stat[REGNO (x)].sign_bit_copies;
-      break;
-
-    case MEM:
-#ifdef LOAD_EXTEND_OP
-      /* Some RISC machines sign-extend all loads of smaller than a word.  */
-      if (LOAD_EXTEND_OP (GET_MODE (x)) == SIGN_EXTEND)
-       return MAX (1, ((int) bitwidth
-                       - (int) GET_MODE_BITSIZE (GET_MODE (x)) + 1));
-#endif
-      break;
-
-    case CONST_INT:
-      /* If the constant is negative, take its 1's complement and remask.
-        Then see how many zero bits we have.  */
-      nonzero = INTVAL (x) & GET_MODE_MASK (mode);
-      if (bitwidth <= HOST_BITS_PER_WIDE_INT
-         && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
-       nonzero = (~nonzero) & GET_MODE_MASK (mode);
-
-      return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1);
-
-    case SUBREG:
-      /* If this is a SUBREG for a promoted object that is sign-extended
-        and we are looking at it in a wider mode, we know that at least the
-        high-order bits are known to be sign bit copies.  */
-
-      if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x))
-       {
-         num0 = num_sign_bit_copies_with_known (SUBREG_REG (x), mode);
-         return MAX ((int) bitwidth
-                     - (int) GET_MODE_BITSIZE (GET_MODE (x)) + 1,
-                     num0);
-       }
-
-      /* For a smaller object, just ignore the high bits.  */
-      if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))
-       {
-         num0 = num_sign_bit_copies_with_known (SUBREG_REG (x), VOIDmode);
-         return MAX (1, (num0
-                         - (int) (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
-                                  - bitwidth)));
-       }
-
-#ifdef WORD_REGISTER_OPERATIONS
-#ifdef LOAD_EXTEND_OP
-      /* For paradoxical SUBREGs on machines where all register operations
-        affect the entire register, just look inside.  Note that we are
-        passing MODE to the recursive call, so the number of sign bit copies
-        will remain relative to that mode, not the inner mode.  */
-
-      /* This works only if loads sign extend.  Otherwise, if we get a
-        reload for the inner part, it may be loaded from the stack, and
-        then we lose all sign bit copies that existed before the store
-        to the stack.  */
-
-      if ((GET_MODE_SIZE (GET_MODE (x))
-          > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-         && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
-         && GET_CODE (SUBREG_REG (x)) == MEM)
-       return num_sign_bit_copies_with_known (SUBREG_REG (x), mode);
-#endif
-#endif
-      break;
-
-    case SIGN_EXTRACT:
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
-       return MAX (1, (int) bitwidth - INTVAL (XEXP (x, 1)));
-      break;
-
-    case SIGN_EXTEND:
-      return (bitwidth - GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
-             + num_sign_bit_copies_with_known (XEXP (x, 0), VOIDmode));
-
-    case TRUNCATE:
-      /* For a smaller object, just ignore the high bits.  */
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), VOIDmode);
-      return MAX (1, (num0 - (int) (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
-                                   - bitwidth)));
-
-    case NOT:
-      return num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-
-    case ROTATE:       case ROTATERT:
-      /* If we are rotating left by a number of bits less than the number
-        of sign bit copies, we can just subtract that amount from the
-        number.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) >= 0
-         && INTVAL (XEXP (x, 1)) < (int) bitwidth)
-       {
-         num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-         return MAX (1, num0 - (code == ROTATE ? INTVAL (XEXP (x, 1))
-                                : (int) bitwidth - INTVAL (XEXP (x, 1))));
-       }
-      break;
-
-    case NEG:
-      /* In general, this subtracts one sign bit copy.  But if the value
-        is known to be positive, the number of sign bit copies is the
-        same as that of the input.  Finally, if the input has just one bit
-        that might be nonzero, all the bits are copies of the sign bit.  */
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      if (bitwidth > HOST_BITS_PER_WIDE_INT)
-       return num0 > 1 ? num0 - 1 : 1;
-
-      nonzero = nonzero_bits (XEXP (x, 0), mode);
-      if (nonzero == 1)
-       return bitwidth;
-
-      if (num0 > 1
-         && (((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero))
-       num0--;
-
-      return num0;
-
-    case IOR:   case AND:   case XOR:
-    case SMIN:  case SMAX:  case UMIN:  case UMAX:
-      /* Logical operations will preserve the number of sign-bit copies.
-        MIN and MAX operations always return one of the operands.  */
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      num1 = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
-      return MIN (num0, num1);
-
-    case PLUS:  case MINUS:
-      /* For addition and subtraction, we can have a 1-bit carry.  However,
-        if we are subtracting 1 from a positive number, there will not
-        be such a carry.  Furthermore, if the positive number is known to
-        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_WIDE_INT)
-       {
-         nonzero = nonzero_bits (XEXP (x, 0), mode);
-         if ((((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero) == 0)
-           return (nonzero == 1 || nonzero == 0 ? bitwidth
-                   : bitwidth - floor_log2 (nonzero) - 1);
-       }
-
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      num1 = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
-      result = MAX (1, MIN (num0, num1) - 1);
-
-#ifdef POINTERS_EXTEND_UNSIGNED
-      /* If pointers extend signed and this is an addition or subtraction
-        to a pointer in Pmode, all the bits above ptr_mode are known to be
-        sign bit copies.  */
-      if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
-         && (code == PLUS || code == MINUS)
-         && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0)))
-       result = MAX ((int) (GET_MODE_BITSIZE (Pmode)
-                            - GET_MODE_BITSIZE (ptr_mode) + 1),
-                     result);
-#endif
-      return result;
-
-    case MULT:
-      /* The number of bits of the product is the sum of the number of
-        bits of both terms.  However, unless one of the terms if known
-        to be positive, we must allow for an additional bit since negating
-        a negative number can remove one sign bit copy.  */
-
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      num1 = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
-
-      result = bitwidth - (bitwidth - num0) - (bitwidth - num1);
-      if (result > 0
-         && (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)
-                      & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))))
-       result--;
-
-      return MAX (1, result);
-
-    case UDIV:
-      /* The result must be <= the first operand.  If the first operand
-         has the high bit set, we know nothing about the number of sign
-         bit copies.  */
-      if (bitwidth > HOST_BITS_PER_WIDE_INT)
-       return 1;
-      else if ((nonzero_bits (XEXP (x, 0), mode)
-               & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
-       return 1;
-      else
-       return num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-
-    case UMOD:
-      /* The result must be <= the second operand.  */
-      return num_sign_bit_copies_with_known (XEXP (x, 1), mode);
-
-    case DIV:
-      /* Similar to unsigned division, except that we have to worry about
-        the case where the divisor is negative, in which case we have
-        to add 1.  */
-      result = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      if (result > 1
-         && (bitwidth > HOST_BITS_PER_WIDE_INT
-             || (nonzero_bits (XEXP (x, 1), mode)
-                 & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))
-       result--;
-
-      return result;
-
-    case MOD:
-      result = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
-      if (result > 1
-         && (bitwidth > HOST_BITS_PER_WIDE_INT
-             || (nonzero_bits (XEXP (x, 1), mode)
-                 & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))
-       result--;
-
-      return result;
-
-    case ASHIFTRT:
-      /* Shifts by a constant add to the number of bits equal to the
-        sign bit.  */
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) > 0)
-       num0 = MIN ((int) bitwidth, num0 + INTVAL (XEXP (x, 1)));
-
-      return num0;
-
-    case ASHIFT:
-      /* Left shifts destroy copies.  */
-      if (GET_CODE (XEXP (x, 1)) != CONST_INT
-         || INTVAL (XEXP (x, 1)) < 0
-         || INTVAL (XEXP (x, 1)) >= (int) bitwidth)
-       return 1;
-
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 0), mode);
-      return MAX (1, num0 - INTVAL (XEXP (x, 1)));
-
-    case IF_THEN_ELSE:
-      num0 = num_sign_bit_copies_with_known (XEXP (x, 1), mode);
-      num1 = num_sign_bit_copies_with_known (XEXP (x, 2), mode);
-      return MIN (num0, num1);
-
-    case EQ:  case NE:  case GE:  case GT:  case LE:  case LT:
-    case UNEQ:  case LTGT:  case UNGE:  case UNGT:  case UNLE:  case UNLT:
-    case GEU: case GTU: case LEU: case LTU:
-    case UNORDERED: case ORDERED:
-      /* If the constant is negative, take its 1's complement and remask.
-        Then see how many zero bits we have.  */
-      nonzero = STORE_FLAG_VALUE;
-      if (bitwidth <= HOST_BITS_PER_WIDE_INT
-         && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
-       nonzero = (~nonzero) & GET_MODE_MASK (mode);
-
-      return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1);
-      break;
-
-    default:
-      break;
-    }
-
-  /* If we haven't been able to figure it out by one of the above rules,
-     see if some of the high-order bits are known to be zero.  If so,
-     count those bits and return one less than that amount.  If we can't
-     safely compute the mask for this mode, always return BITWIDTH.  */
-
-  if (bitwidth > HOST_BITS_PER_WIDE_INT)
-    return 1;
-
-  nonzero = nonzero_bits (x, mode);
-  return (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))
-         ? 1 : bitwidth - floor_log2 (nonzero) - 1);
+  if (nonzero_sign_valid && reg_stat[REGNO (x)].sign_bit_copies != 0
+      && GET_MODE_BITSIZE (GET_MODE (x)) == GET_MODE_BITSIZE (mode))
+    *result = reg_stat[REGNO (x)].sign_bit_copies;
+      
+  return NULL;
 }
 \f
 /* Return the number of "extended" bits there are in X, when interpreted
index 6d3c53f7635b8e5a4cefbb4a5611619c4b0e0f54..5f1107c3e2259b9dda3c91eb991ea19b18a6cb3d 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -43,6 +43,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "except.h"
 #include "target.h"
 #include "params.h"
+#include "rtlhooks-def.h"
 
 /* The basic idea of common subexpression elimination is to go
    through the code, keeping a record of expressions that would
@@ -664,6 +665,12 @@ static int cse_change_cc_mode (rtx *, void *);
 static void cse_change_cc_mode_insns (rtx, rtx, rtx);
 static enum machine_mode cse_cc_succs (basic_block, rtx, rtx, bool);
 \f
+
+#undef RTL_HOOKS_GEN_LOWPART
+#define RTL_HOOKS_GEN_LOWPART          gen_lowpart_if_possible
+
+static const struct rtl_hooks cse_rtl_hooks = RTL_HOOKS_INITIALIZER;
+\f
 /* Nonzero if X has the form (PLUS frame-pointer integer).  We check for
    virtual regs here because the simplify_*_operation routines are called
    by integrate.c, which is called before virtual register instantiation.  */
@@ -6881,7 +6888,7 @@ cse_main (rtx f, int nregs, int after_loop, FILE *file)
   constant_pool_entries_cost = 0;
   constant_pool_entries_regcost = 0;
   val.path_size = 0;
-  gen_lowpart = gen_lowpart_if_possible;
+  rtl_hooks = cse_rtl_hooks;
 
   init_recog ();
   init_alias_analysis ();
@@ -7001,7 +7008,7 @@ cse_main (rtx f, int nregs, int after_loop, FILE *file)
   free (uid_cuid);
   free (reg_eqv_table);
   free (val.path);
-  gen_lowpart = gen_lowpart_general;
+  rtl_hooks = general_rtl_hooks;
 
   return cse_jumps_altered || recorded_label_ref;
 }
index ba8a3d6cf2410447e68d80b09484a3101302089f..9211c0875370f05f3e1bb015e01b1c3b946c45e5 100644 (file)
@@ -97,8 +97,6 @@ rtx global_rtl[GR_MAX];
    at the beginning of each function.  */
 static GTY(()) rtx static_regno_reg_rtx[FIRST_PSEUDO_REGISTER];
 
-rtx (*gen_lowpart) (enum machine_mode mode, rtx x) = gen_lowpart_general;
-
 /* We record floating-point CONST_DOUBLEs in each floating-point mode for
    the values of 0, 1, and 2.  For the integer entries and VOIDmode, we
    record a copy of const[012]_rtx.  */
@@ -1124,62 +1122,6 @@ gen_imagpart (enum machine_mode mode, rtx x)
     return gen_highpart (mode, x);
 }
 \f
-/* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a value,
-   return an rtx (MEM, SUBREG, or CONST_INT) that refers to the
-   least-significant part of X.
-   MODE specifies how big a part of X to return;
-   it usually should not be larger than a word.
-   If X is a MEM whose address is a QUEUED, the value may be so also.  */
-
-rtx
-gen_lowpart_general (enum machine_mode mode, rtx x)
-{
-  rtx result = gen_lowpart_common (mode, x);
-
-  if (result)
-    return result;
-  else if (GET_CODE (x) == REG)
-    {
-      /* Must be a hard reg that's not valid in MODE.  */
-      result = gen_lowpart_common (mode, copy_to_reg (x));
-      if (result == 0)
-       abort ();
-      return result;
-    }
-  else if (GET_CODE (x) == MEM)
-    {
-      /* The only additional case we can do is MEM.  */
-      int offset = 0;
-
-      /* The following exposes the use of "x" to CSE.  */
-      if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
-         && SCALAR_INT_MODE_P (GET_MODE (x))
-         && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
-                                   GET_MODE_BITSIZE (GET_MODE (x)))
-         && ! no_new_pseudos)
-       return gen_lowpart (mode, force_reg (GET_MODE (x), x));
-
-      if (WORDS_BIG_ENDIAN)
-       offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
-                 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
-
-      if (BYTES_BIG_ENDIAN)
-       /* Adjust the address so that the address-after-the-data
-          is unchanged.  */
-       offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
-                  - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
-
-      return adjust_address (x, mode, offset);
-    }
-  else if (GET_CODE (x) == ADDRESSOF)
-    return gen_lowpart (mode, force_reg (GET_MODE (x), x));
-  else
-    abort ();
-}
-
-/* Like `gen_lowpart', but refer to the most significant part.
-   This is used to access the imaginary part of a complex number.  */
-
 rtx
 gen_highpart (enum machine_mode mode, rtx x)
 {
index cb6850a9927067bf2db65f32fe4f67277988ab65..65f68d81b59bb54d7741829fb2fdbf961925ec57 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1195,6 +1195,9 @@ extern unsigned int subreg_regno_offset   (unsigned int, enum machine_mode,
 extern bool subreg_offset_representable_p (unsigned int, enum machine_mode,
                                           unsigned int, enum machine_mode);
 extern unsigned int subreg_regno (rtx);
+extern unsigned HOST_WIDE_INT nonzero_bits (rtx, enum machine_mode);
+extern unsigned int num_sign_bit_copies (rtx, enum machine_mode);
+
 
 /* 1 if RTX is a subreg containing a reg that is already known to be
    sign- or zero-extended from the mode of the subreg to the mode of
@@ -1598,9 +1601,6 @@ extern rtx gen_rtx_REG_offset (rtx, enum machine_mode, unsigned int, int);
 extern rtx gen_label_rtx (void);
 extern int subreg_hard_regno (rtx, int);
 extern rtx gen_lowpart_common (enum machine_mode, rtx);
-extern rtx gen_lowpart_general (enum machine_mode, rtx);
-extern rtx (*gen_lowpart) (enum machine_mode mode, rtx x);
-
 
 /* In cse.c */
 extern rtx gen_lowpart_if_possible (enum machine_mode, rtx);
@@ -2461,4 +2461,25 @@ extern void simplify_using_condition (rtx, rtx *, struct bitmap_head_def *);
 /* In ra.c.  */
 extern void reg_alloc (void);
 
+\f
+struct rtl_hooks
+{
+  rtx (*gen_lowpart) (enum machine_mode, rtx);
+  rtx (*reg_nonzero_bits) (rtx, enum machine_mode, rtx, enum machine_mode,
+                          unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT *);
+  rtx (*reg_num_sign_bit_copies) (rtx, enum machine_mode, rtx, enum machine_mode,
+                                 unsigned int, unsigned int *);
+
+  /* Whenever you add entries here, make sure you adjust hosthooks-def.h.  */
+};
+
+/* Each pass can provide its own.  */
+extern struct rtl_hooks rtl_hooks;
+
+/* ... but then it has to restore these.  */
+extern const struct rtl_hooks general_rtl_hooks;
+
+/* Keep this for the nonce.  */
+#define gen_lowpart rtl_hooks.gen_lowpart
+
 #endif /* ! GCC_RTL_H */
index a52f614b8785a7f14a9010538ec2cdc19e389f99..8da8b80ddb3323f538ed8a30c780196dec94f243 100644 (file)
@@ -36,6 +36,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "basic-block.h"
 #include "real.h"
 #include "regs.h"
+#include "function.h"
 
 /* Forward declarations */
 static int global_reg_mentioned_p_1 (rtx *, void *);
@@ -47,6 +48,18 @@ static void parms_set (rtx, rtx, void *);
 static bool hoist_test_store (rtx, rtx, regset);
 static void hoist_update_store (rtx, rtx *, rtx, rtx);
 
+static unsigned HOST_WIDE_INT cached_nonzero_bits (rtx, enum machine_mode,
+                                                   rtx, enum machine_mode,
+                                                   unsigned HOST_WIDE_INT);
+static unsigned HOST_WIDE_INT nonzero_bits1 (rtx, enum machine_mode, rtx,
+                                             enum machine_mode,
+                                             unsigned HOST_WIDE_INT);
+static unsigned int cached_num_sign_bit_copies (rtx, enum machine_mode, rtx,
+                                                enum machine_mode,
+                                                unsigned int);
+static unsigned int num_sign_bit_copies1 (rtx, enum machine_mode, rtx,
+                                          enum machine_mode, unsigned int);
+
 /* Bit flags that specify the machine subtype we are compiling for.
    Bits are tested using macros TARGET_... defined in the tm.h file
    and set by `-m...' switches.  Must be defined in rtlanal.c.  */
@@ -3849,3 +3862,946 @@ default_address_cost (rtx x)
 {
   return rtx_cost (x, MEM);
 }
+\f
+
+unsigned HOST_WIDE_INT
+nonzero_bits (rtx x, enum machine_mode mode)
+{
+  return cached_nonzero_bits (x, mode, NULL_RTX, VOIDmode, 0);
+}
+
+unsigned int
+num_sign_bit_copies (rtx x, enum machine_mode mode)
+{
+  return cached_num_sign_bit_copies (x, mode, NULL_RTX, VOIDmode, 0);
+}
+
+/* The function cached_nonzero_bits is a wrapper around nonzero_bits1.
+   It avoids exponential behavior in nonzero_bits1 when X has
+   identical subexpressions on the first or the second level.  */
+
+static unsigned HOST_WIDE_INT
+cached_nonzero_bits (rtx x, enum machine_mode mode, rtx known_x,
+                    enum machine_mode known_mode,
+                    unsigned HOST_WIDE_INT known_ret)
+{
+  if (x == known_x && mode == known_mode)
+    return known_ret;
+
+  /* Try to find identical subexpressions.  If found call
+     nonzero_bits1 on X with the subexpressions as KNOWN_X and the
+     precomputed value for the subexpression as KNOWN_RET.  */
+
+  if (ARITHMETIC_P (x))
+    {
+      rtx x0 = XEXP (x, 0);
+      rtx x1 = XEXP (x, 1);
+
+      /* Check the first level.  */
+      if (x0 == x1)
+       return nonzero_bits1 (x, mode, x0, mode,
+                             cached_nonzero_bits (x0, mode, known_x,
+                                                  known_mode, known_ret));
+
+      /* Check the second level.  */
+      if (ARITHMETIC_P (x0)
+         && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
+       return nonzero_bits1 (x, mode, x1, mode,
+                             cached_nonzero_bits (x1, mode, known_x,
+                                                  known_mode, known_ret));
+
+      if (ARITHMETIC_P (x1)
+         && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
+       return nonzero_bits1 (x, mode, x0, mode,
+                             cached_nonzero_bits (x0, mode, known_x,
+                                                  known_mode, known_ret));
+    }
+
+  return nonzero_bits1 (x, mode, known_x, known_mode, known_ret);
+}
+
+/* We let num_sign_bit_copies recur into nonzero_bits as that is useful.
+   We don't let nonzero_bits recur into num_sign_bit_copies, because that
+   is less useful.  We can't allow both, because that results in exponential
+   run time recursion.  There is a nullstone testcase that triggered
+   this.  This macro avoids accidental uses of num_sign_bit_copies.  */
+#define cached_num_sign_bit_copies sorry_i_am_preventing_exponential_behavior
+
+/* Given an expression, X, compute which bits in X can be nonzero.
+   We don't care about bits outside of those defined in MODE.
+
+   For most X this is simply GET_MODE_MASK (GET_MODE (MODE)), but if X is
+   an arithmetic operation, we can do better.  */
+
+static unsigned HOST_WIDE_INT
+nonzero_bits1 (rtx x, enum machine_mode mode, rtx known_x,
+              enum machine_mode known_mode,
+              unsigned HOST_WIDE_INT known_ret)
+{
+  unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
+  unsigned HOST_WIDE_INT inner_nz;
+  enum rtx_code code;
+  unsigned int mode_width = GET_MODE_BITSIZE (mode);
+
+  /* For floating-point values, assume all bits are needed.  */
+  if (FLOAT_MODE_P (GET_MODE (x)) || FLOAT_MODE_P (mode))
+    return nonzero;
+
+  /* If X is wider than MODE, use its mode instead.  */
+  if (GET_MODE_BITSIZE (GET_MODE (x)) > mode_width)
+    {
+      mode = GET_MODE (x);
+      nonzero = GET_MODE_MASK (mode);
+      mode_width = GET_MODE_BITSIZE (mode);
+    }
+
+  if (mode_width > HOST_BITS_PER_WIDE_INT)
+    /* Our only callers in this case look for single bit values.  So
+       just return the mode mask.  Those tests will then be false.  */
+    return nonzero;
+
+#ifndef WORD_REGISTER_OPERATIONS
+  /* If MODE is wider than X, but both are a single word for both the host
+     and target machines, we can compute this from which bits of the
+     object might be nonzero in its own mode, taking into account the fact
+     that on many CISC machines, accessing an object in a wider mode
+     causes the high-order bits to become undefined.  So they are
+     not known to be zero.  */
+
+  if (GET_MODE (x) != VOIDmode && GET_MODE (x) != mode
+      && GET_MODE_BITSIZE (GET_MODE (x)) <= BITS_PER_WORD
+      && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
+      && GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (GET_MODE (x)))
+    {
+      nonzero &= cached_nonzero_bits (x, GET_MODE (x),
+                                     known_x, known_mode, known_ret);
+      nonzero |= GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x));
+      return nonzero;
+    }
+#endif
+
+  code = GET_CODE (x);
+  switch (code)
+    {
+    case REG:
+#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
+      /* If pointers extend unsigned and this is a pointer in Pmode, say that
+        all the bits above ptr_mode are known to be zero.  */
+      if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
+         && REG_POINTER (x))
+       nonzero &= GET_MODE_MASK (ptr_mode);
+#endif
+
+      /* Include declared information about alignment of pointers.  */
+      /* ??? We don't properly preserve REG_POINTER changes across
+        pointer-to-integer casts, so we can't trust it except for
+        things that we know must be pointers.  See execute/960116-1.c.  */
+      if ((x == stack_pointer_rtx
+          || x == frame_pointer_rtx
+          || x == arg_pointer_rtx)
+         && REGNO_POINTER_ALIGN (REGNO (x)))
+       {
+         unsigned HOST_WIDE_INT alignment
+           = REGNO_POINTER_ALIGN (REGNO (x)) / BITS_PER_UNIT;
+
+#ifdef PUSH_ROUNDING
+         /* If PUSH_ROUNDING is defined, it is possible for the
+            stack to be momentarily aligned only to that amount,
+            so we pick the least alignment.  */
+         if (x == stack_pointer_rtx && PUSH_ARGS)
+           alignment = MIN ((unsigned HOST_WIDE_INT) PUSH_ROUNDING (1),
+                            alignment);
+#endif
+
+         nonzero &= ~(alignment - 1);
+       }
+
+      {
+       unsigned HOST_WIDE_INT nonzero_for_hook = nonzero;
+       rtx new = rtl_hooks.reg_nonzero_bits (x, mode, known_x,
+                                             known_mode, known_ret,
+                                             &nonzero_for_hook);
+
+       if (new)
+         nonzero_for_hook &= cached_nonzero_bits (new, mode, known_x,
+                                                  known_mode, known_ret);
+
+       return nonzero_for_hook;
+      }
+
+    case CONST_INT:
+#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
+      /* If X is negative in MODE, sign-extend the value.  */
+      if (INTVAL (x) > 0 && mode_width < BITS_PER_WORD
+         && 0 != (INTVAL (x) & ((HOST_WIDE_INT) 1 << (mode_width - 1))))
+       return (INTVAL (x) | ((HOST_WIDE_INT) (-1) << mode_width));
+#endif
+
+      return INTVAL (x);
+
+    case MEM:
+#ifdef LOAD_EXTEND_OP
+      /* In many, if not most, RISC machines, reading a byte from memory
+        zeros the rest of the register.  Noticing that fact saves a lot
+        of extra zero-extends.  */
+      if (LOAD_EXTEND_OP (GET_MODE (x)) == ZERO_EXTEND)
+       nonzero &= GET_MODE_MASK (GET_MODE (x));
+#endif
+      break;
+
+    case EQ:  case NE:
+    case UNEQ:  case LTGT:
+    case GT:  case GTU:  case UNGT:
+    case LT:  case LTU:  case UNLT:
+    case GE:  case GEU:  case UNGE:
+    case LE:  case LEU:  case UNLE:
+    case UNORDERED: case ORDERED:
+
+      /* If this produces an integer result, we know which bits are set.
+        Code here used to clear bits outside the mode of X, but that is
+        now done above.  */
+
+      if (GET_MODE_CLASS (mode) == MODE_INT
+         && mode_width <= HOST_BITS_PER_WIDE_INT)
+       nonzero = STORE_FLAG_VALUE;
+      break;
+
+    case NEG:
+#if 0
+      /* Disabled to avoid exponential mutual recursion between nonzero_bits
+        and num_sign_bit_copies.  */
+      if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
+         == GET_MODE_BITSIZE (GET_MODE (x)))
+       nonzero = 1;
+#endif
+
+      if (GET_MODE_SIZE (GET_MODE (x)) < mode_width)
+       nonzero |= (GET_MODE_MASK (mode) & ~GET_MODE_MASK (GET_MODE (x)));
+      break;
+
+    case ABS:
+#if 0
+      /* Disabled to avoid exponential mutual recursion between nonzero_bits
+        and num_sign_bit_copies.  */
+      if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
+         == GET_MODE_BITSIZE (GET_MODE (x)))
+       nonzero = 1;
+#endif
+      break;
+
+    case TRUNCATE:
+      nonzero &= (cached_nonzero_bits (XEXP (x, 0), mode,
+                                      known_x, known_mode, known_ret)
+                 & GET_MODE_MASK (mode));
+      break;
+
+    case ZERO_EXTEND:
+      nonzero &= cached_nonzero_bits (XEXP (x, 0), mode,
+                                     known_x, known_mode, known_ret);
+      if (GET_MODE (XEXP (x, 0)) != VOIDmode)
+       nonzero &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
+      break;
+
+    case SIGN_EXTEND:
+      /* If the sign bit is known clear, this is the same as ZERO_EXTEND.
+        Otherwise, show all the bits in the outer mode but not the inner
+        may be nonzero.  */
+      inner_nz = cached_nonzero_bits (XEXP (x, 0), mode,
+                                     known_x, known_mode, known_ret);
+      if (GET_MODE (XEXP (x, 0)) != VOIDmode)
+       {
+         inner_nz &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
+         if (inner_nz
+             & (((HOST_WIDE_INT) 1
+                 << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1))))
+           inner_nz |= (GET_MODE_MASK (mode)
+                        & ~GET_MODE_MASK (GET_MODE (XEXP (x, 0))));
+       }
+
+      nonzero &= inner_nz;
+      break;
+
+    case AND:
+      nonzero &= cached_nonzero_bits (XEXP (x, 0), mode,
+                                      known_x, known_mode, known_ret)
+                & cached_nonzero_bits (XEXP (x, 1), mode,
+                                       known_x, known_mode, known_ret);
+      break;
+
+    case XOR:   case IOR:
+    case UMIN:  case UMAX:  case SMIN:  case SMAX:
+      {
+       unsigned HOST_WIDE_INT nonzero0 =
+         cached_nonzero_bits (XEXP (x, 0), mode,
+                              known_x, known_mode, known_ret);
+
+       /* Don't call nonzero_bits for the second time if it cannot change
+          anything.  */
+       if ((nonzero & nonzero0) != nonzero)
+         nonzero &= nonzero0
+                    | cached_nonzero_bits (XEXP (x, 1), mode,
+                                           known_x, known_mode, known_ret);
+      }
+      break;
+
+    case PLUS:  case MINUS:
+    case MULT:
+    case DIV:   case UDIV:
+    case MOD:   case UMOD:
+      /* We can apply the rules of arithmetic to compute the number of
+        high- and low-order zero bits of these operations.  We start by
+        computing the width (position of the highest-order nonzero bit)
+        and the number of low-order zero bits for each value.  */
+      {
+       unsigned HOST_WIDE_INT nz0 =
+         cached_nonzero_bits (XEXP (x, 0), mode,
+                              known_x, known_mode, known_ret);
+       unsigned HOST_WIDE_INT nz1 =
+         cached_nonzero_bits (XEXP (x, 1), mode,
+                              known_x, known_mode, known_ret);
+       int sign_index = GET_MODE_BITSIZE (GET_MODE (x)) - 1;
+       int width0 = floor_log2 (nz0) + 1;
+       int width1 = floor_log2 (nz1) + 1;
+       int low0 = floor_log2 (nz0 & -nz0);
+       int low1 = floor_log2 (nz1 & -nz1);
+       HOST_WIDE_INT op0_maybe_minusp
+         = (nz0 & ((HOST_WIDE_INT) 1 << sign_index));
+       HOST_WIDE_INT op1_maybe_minusp
+         = (nz1 & ((HOST_WIDE_INT) 1 << sign_index));
+       unsigned int result_width = mode_width;
+       int result_low = 0;
+
+       switch (code)
+         {
+         case PLUS:
+           result_width = MAX (width0, width1) + 1;
+           result_low = MIN (low0, low1);
+           break;
+         case MINUS:
+           result_low = MIN (low0, low1);
+           break;
+         case MULT:
+           result_width = width0 + width1;
+           result_low = low0 + low1;
+           break;
+         case DIV:
+           if (width1 == 0)
+             break;
+           if (! op0_maybe_minusp && ! op1_maybe_minusp)
+             result_width = width0;
+           break;
+         case UDIV:
+           if (width1 == 0)
+             break;
+           result_width = width0;
+           break;
+         case MOD:
+           if (width1 == 0)
+             break;
+           if (! op0_maybe_minusp && ! op1_maybe_minusp)
+             result_width = MIN (width0, width1);
+           result_low = MIN (low0, low1);
+           break;
+         case UMOD:
+           if (width1 == 0)
+             break;
+           result_width = MIN (width0, width1);
+           result_low = MIN (low0, low1);
+           break;
+         default:
+           abort ();
+         }
+
+       if (result_width < mode_width)
+         nonzero &= ((HOST_WIDE_INT) 1 << result_width) - 1;
+
+       if (result_low > 0)
+         nonzero &= ~(((HOST_WIDE_INT) 1 << result_low) - 1);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+       /* If pointers extend unsigned and this is an addition or subtraction
+          to a pointer in Pmode, all the bits above ptr_mode are known to be
+          zero.  */
+       if (POINTERS_EXTEND_UNSIGNED > 0 && GET_MODE (x) == Pmode
+           && (code == PLUS || code == MINUS)
+           && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0)))
+         nonzero &= GET_MODE_MASK (ptr_mode);
+#endif
+      }
+      break;
+
+    case ZERO_EXTRACT:
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
+       nonzero &= ((HOST_WIDE_INT) 1 << INTVAL (XEXP (x, 1))) - 1;
+      break;
+
+    case SUBREG:
+      /* If this is a SUBREG formed for a promoted variable that has
+        been zero-extended, we know that at least the high-order bits
+        are zero, though others might be too.  */
+
+      if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x) > 0)
+       nonzero = GET_MODE_MASK (GET_MODE (x))
+                 & cached_nonzero_bits (SUBREG_REG (x), GET_MODE (x),
+                                        known_x, known_mode, known_ret);
+
+      /* If the inner mode is a single word for both the host and target
+        machines, we can compute this from which bits of the inner
+        object might be nonzero.  */
+      if (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) <= BITS_PER_WORD
+         && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
+             <= HOST_BITS_PER_WIDE_INT))
+       {
+         nonzero &= cached_nonzero_bits (SUBREG_REG (x), mode,
+                                         known_x, known_mode, known_ret);
+
+#if defined (WORD_REGISTER_OPERATIONS) && defined (LOAD_EXTEND_OP)
+         /* If this is a typical RISC machine, we only have to worry
+            about the way loads are extended.  */
+         if ((LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
+              ? (((nonzero
+                   & (((unsigned HOST_WIDE_INT) 1
+                       << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1))))
+                  != 0))
+              : LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND)
+             || GET_CODE (SUBREG_REG (x)) != MEM)
+#endif
+           {
+             /* On many CISC machines, accessing an object in a wider mode
+                causes the high-order bits to become undefined.  So they are
+                not known to be zero.  */
+             if (GET_MODE_SIZE (GET_MODE (x))
+                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+               nonzero |= (GET_MODE_MASK (GET_MODE (x))
+                           & ~GET_MODE_MASK (GET_MODE (SUBREG_REG (x))));
+           }
+       }
+      break;
+
+    case ASHIFTRT:
+    case LSHIFTRT:
+    case ASHIFT:
+    case ROTATE:
+      /* The nonzero bits are in two classes: any bits within MODE
+        that aren't in GET_MODE (x) are always significant.  The rest of the
+        nonzero bits are those that are significant in the operand of
+        the shift when shifted the appropriate number of bits.  This
+        shows that high-order bits are cleared by the right shift and
+        low-order bits by left shifts.  */
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) >= 0
+         && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
+       {
+         enum machine_mode inner_mode = GET_MODE (x);
+         unsigned int width = GET_MODE_BITSIZE (inner_mode);
+         int count = INTVAL (XEXP (x, 1));
+         unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (inner_mode);
+         unsigned HOST_WIDE_INT op_nonzero =
+           cached_nonzero_bits (XEXP (x, 0), mode,
+                                known_x, known_mode, known_ret);
+         unsigned HOST_WIDE_INT inner = op_nonzero & mode_mask;
+         unsigned HOST_WIDE_INT outer = 0;
+
+         if (mode_width > width)
+           outer = (op_nonzero & nonzero & ~mode_mask);
+
+         if (code == LSHIFTRT)
+           inner >>= count;
+         else if (code == ASHIFTRT)
+           {
+             inner >>= count;
+
+             /* If the sign bit may have been nonzero before the shift, we
+                need to mark all the places it could have been copied to
+                by the shift as possibly nonzero.  */
+             if (inner & ((HOST_WIDE_INT) 1 << (width - 1 - count)))
+               inner |= (((HOST_WIDE_INT) 1 << count) - 1) << (width - count);
+           }
+         else if (code == ASHIFT)
+           inner <<= count;
+         else
+           inner = ((inner << (count % width)
+                     | (inner >> (width - (count % width)))) & mode_mask);
+
+         nonzero &= (outer | inner);
+       }
+      break;
+
+    case FFS:
+    case POPCOUNT:
+      /* This is at most the number of bits in the mode.  */
+      nonzero = ((HOST_WIDE_INT) 2 << (floor_log2 (mode_width))) - 1;
+      break;
+
+    case CLZ:
+      /* If CLZ has a known value at zero, then the nonzero bits are
+        that value, plus the number of bits in the mode minus one.  */
+      if (CLZ_DEFINED_VALUE_AT_ZERO (mode, nonzero))
+       nonzero |= ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1;
+      else
+       nonzero = -1;
+      break;
+
+    case CTZ:
+      /* If CTZ has a known value at zero, then the nonzero bits are
+        that value, plus the number of bits in the mode minus one.  */
+      if (CTZ_DEFINED_VALUE_AT_ZERO (mode, nonzero))
+       nonzero |= ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width))) - 1;
+      else
+       nonzero = -1;
+      break;
+
+    case PARITY:
+      nonzero = 1;
+      break;
+
+    case IF_THEN_ELSE:
+      {
+       unsigned HOST_WIDE_INT nonzero_true =
+         cached_nonzero_bits (XEXP (x, 1), mode,
+                              known_x, known_mode, known_ret);
+
+       /* Don't call nonzero_bits for the second time if it cannot change
+          anything.  */
+       if ((nonzero & nonzero_true) != nonzero)
+         nonzero &= nonzero_true
+                    | cached_nonzero_bits (XEXP (x, 2), mode,
+                                           known_x, known_mode, known_ret);
+      }
+      break;
+
+    default:
+      break;
+    }
+
+  return nonzero;
+}
+
+/* See the macro definition above.  */
+#undef cached_num_sign_bit_copies
+
+\f
+/* The function cached_num_sign_bit_copies is a wrapper around
+   num_sign_bit_copies1.  It avoids exponential behavior in
+   num_sign_bit_copies1 when X has identical subexpressions on the
+   first or the second level.  */
+
+static unsigned int
+cached_num_sign_bit_copies (rtx x, enum machine_mode mode, rtx known_x,
+                           enum machine_mode known_mode,
+                           unsigned int known_ret)
+{
+  if (x == known_x && mode == known_mode)
+    return known_ret;
+
+  /* Try to find identical subexpressions.  If found call
+     num_sign_bit_copies1 on X with the subexpressions as KNOWN_X and
+     the precomputed value for the subexpression as KNOWN_RET.  */
+
+  if (ARITHMETIC_P (x))
+    {
+      rtx x0 = XEXP (x, 0);
+      rtx x1 = XEXP (x, 1);
+
+      /* Check the first level.  */
+      if (x0 == x1)
+       return
+         num_sign_bit_copies1 (x, mode, x0, mode,
+                               cached_num_sign_bit_copies (x0, mode, known_x,
+                                                           known_mode,
+                                                           known_ret));
+
+      /* Check the second level.  */
+      if (ARITHMETIC_P (x0)
+         && (x1 == XEXP (x0, 0) || x1 == XEXP (x0, 1)))
+       return
+         num_sign_bit_copies1 (x, mode, x1, mode,
+                               cached_num_sign_bit_copies (x1, mode, known_x,
+                                                           known_mode,
+                                                           known_ret));
+
+      if (ARITHMETIC_P (x1)
+         && (x0 == XEXP (x1, 0) || x0 == XEXP (x1, 1)))
+       return
+         num_sign_bit_copies1 (x, mode, x0, mode,
+                               cached_num_sign_bit_copies (x0, mode, known_x,
+                                                           known_mode,
+                                                           known_ret));
+    }
+
+  return num_sign_bit_copies1 (x, mode, known_x, known_mode, known_ret);
+}
+
+/* Return the number of bits at the high-order end of X that are known to
+   be equal to the sign bit.  X will be used in mode MODE; if MODE is
+   VOIDmode, X will be used in its own mode.  The returned value  will always
+   be between 1 and the number of bits in MODE.  */
+
+static unsigned int
+num_sign_bit_copies1 (rtx x, enum machine_mode mode, rtx known_x,
+                     enum machine_mode known_mode,
+                     unsigned int known_ret)
+{
+  enum rtx_code code = GET_CODE (x);
+  unsigned int bitwidth = GET_MODE_BITSIZE (mode);
+  int num0, num1, result;
+  unsigned HOST_WIDE_INT nonzero;
+
+  /* If we weren't given a mode, use the mode of X.  If the mode is still
+     VOIDmode, we don't know anything.  Likewise if one of the modes is
+     floating-point.  */
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (x);
+
+  if (mode == VOIDmode || FLOAT_MODE_P (mode) || FLOAT_MODE_P (GET_MODE (x)))
+    return 1;
+
+  /* For a smaller object, just ignore the high bits.  */
+  if (bitwidth < GET_MODE_BITSIZE (GET_MODE (x)))
+    {
+      num0 = cached_num_sign_bit_copies (x, GET_MODE (x),
+                                        known_x, known_mode, known_ret);
+      return MAX (1,
+                 num0 - (int) (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth));
+    }
+
+  if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_BITSIZE (GET_MODE (x)))
+    {
+#ifndef WORD_REGISTER_OPERATIONS
+  /* If this machine does not do all register operations on the entire
+     register and MODE is wider than the mode of X, we can say nothing
+     at all about the high-order bits.  */
+      return 1;
+#else
+      /* Likewise on machines that do, if the mode of the object is smaller
+        than a word and loads of that size don't sign extend, we can say
+        nothing about the high order bits.  */
+      if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD
+#ifdef LOAD_EXTEND_OP
+         && LOAD_EXTEND_OP (GET_MODE (x)) != SIGN_EXTEND
+#endif
+         )
+       return 1;
+#endif
+    }
+
+  switch (code)
+    {
+    case REG:
+
+#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
+      /* If pointers extend signed and this is a pointer in Pmode, say that
+        all the bits above ptr_mode are known to be sign bit copies.  */
+      if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && mode == Pmode
+         && REG_POINTER (x))
+       return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1;
+#endif
+
+      {
+       unsigned int copies_for_hook = 1, copies = 1;
+       rtx new = rtl_hooks.reg_num_sign_bit_copies (x, mode, known_x,
+                                                    known_mode, known_ret,
+                                                    &copies_for_hook);
+
+       if (new)
+         copies = cached_num_sign_bit_copies (new, mode, known_x,
+                                              known_mode, known_ret);
+
+       if (copies > 1 || copies_for_hook > 1)
+         return MAX (copies, copies_for_hook);
+
+       /* Else, use nonzero_bits to guess num_sign_bit_copies (see below).  */
+      }
+      break;
+
+    case MEM:
+#ifdef LOAD_EXTEND_OP
+      /* Some RISC machines sign-extend all loads of smaller than a word.  */
+      if (LOAD_EXTEND_OP (GET_MODE (x)) == SIGN_EXTEND)
+       return MAX (1, ((int) bitwidth
+                       - (int) GET_MODE_BITSIZE (GET_MODE (x)) + 1));
+#endif
+      break;
+
+    case CONST_INT:
+      /* If the constant is negative, take its 1's complement and remask.
+        Then see how many zero bits we have.  */
+      nonzero = INTVAL (x) & GET_MODE_MASK (mode);
+      if (bitwidth <= HOST_BITS_PER_WIDE_INT
+         && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
+       nonzero = (~nonzero) & GET_MODE_MASK (mode);
+
+      return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1);
+
+    case SUBREG:
+      /* If this is a SUBREG for a promoted object that is sign-extended
+        and we are looking at it in a wider mode, we know that at least the
+        high-order bits are known to be sign bit copies.  */
+
+      if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x))
+       {
+         num0 = cached_num_sign_bit_copies (SUBREG_REG (x), mode,
+                                            known_x, known_mode, known_ret);
+         return MAX ((int) bitwidth
+                     - (int) GET_MODE_BITSIZE (GET_MODE (x)) + 1,
+                     num0);
+       }
+
+      /* For a smaller object, just ignore the high bits.  */
+      if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))
+       {
+         num0 = cached_num_sign_bit_copies (SUBREG_REG (x), VOIDmode,
+                                            known_x, known_mode, known_ret);
+         return MAX (1, (num0
+                         - (int) (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
+                                  - bitwidth)));
+       }
+
+#ifdef WORD_REGISTER_OPERATIONS
+#ifdef LOAD_EXTEND_OP
+      /* For paradoxical SUBREGs on machines where all register operations
+        affect the entire register, just look inside.  Note that we are
+        passing MODE to the recursive call, so the number of sign bit copies
+        will remain relative to that mode, not the inner mode.  */
+
+      /* This works only if loads sign extend.  Otherwise, if we get a
+        reload for the inner part, it may be loaded from the stack, and
+        then we lose all sign bit copies that existed before the store
+        to the stack.  */
+
+      if ((GET_MODE_SIZE (GET_MODE (x))
+          > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+         && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
+         && GET_CODE (SUBREG_REG (x)) == MEM)
+       return cached_num_sign_bit_copies (SUBREG_REG (x), mode,
+                                          known_x, known_mode, known_ret);
+#endif
+#endif
+      break;
+
+    case SIGN_EXTRACT:
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+       return MAX (1, (int) bitwidth - INTVAL (XEXP (x, 1)));
+      break;
+
+    case SIGN_EXTEND:
+      return (bitwidth - GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+             + cached_num_sign_bit_copies (XEXP (x, 0), VOIDmode,
+                                           known_x, known_mode, known_ret));
+
+    case TRUNCATE:
+      /* For a smaller object, just ignore the high bits.  */
+      num0 = cached_num_sign_bit_copies (XEXP (x, 0), VOIDmode,
+                                        known_x, known_mode, known_ret);
+      return MAX (1, (num0 - (int) (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+                                   - bitwidth)));
+
+    case NOT:
+      return cached_num_sign_bit_copies (XEXP (x, 0), mode,
+                                        known_x, known_mode, known_ret);
+
+    case ROTATE:       case ROTATERT:
+      /* If we are rotating left by a number of bits less than the number
+        of sign bit copies, we can just subtract that amount from the
+        number.  */
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) >= 0
+         && INTVAL (XEXP (x, 1)) < (int) bitwidth)
+       {
+         num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode,
+                                            known_x, known_mode, known_ret);
+         return MAX (1, num0 - (code == ROTATE ? INTVAL (XEXP (x, 1))
+                                : (int) bitwidth - INTVAL (XEXP (x, 1))));
+       }
+      break;
+
+    case NEG:
+      /* In general, this subtracts one sign bit copy.  But if the value
+        is known to be positive, the number of sign bit copies is the
+        same as that of the input.  Finally, if the input has just one bit
+        that might be nonzero, all the bits are copies of the sign bit.  */
+      num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode,
+                                        known_x, known_mode, known_ret);
+      if (bitwidth > HOST_BITS_PER_WIDE_INT)
+       return num0 > 1 ? num0 - 1 : 1;
+
+      nonzero = nonzero_bits (XEXP (x, 0), mode);
+      if (nonzero == 1)
+       return bitwidth;
+
+      if (num0 > 1
+         && (((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero))
+       num0--;
+
+      return num0;
+
+    case IOR:   case AND:   case XOR:
+    case SMIN:  case SMAX:  case UMIN:  case UMAX:
+      /* Logical operations will preserve the number of sign-bit copies.
+        MIN and MAX operations always return one of the operands.  */
+      num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode,
+                                        known_x, known_mode, known_ret);
+      num1 = cached_num_sign_bit_copies (XEXP (x, 1), mode,
+                                        known_x, known_mode, known_ret);
+      return MIN (num0, num1);
+
+    case PLUS:  case MINUS:
+      /* For addition and subtraction, we can have a 1-bit carry.  However,
+        if we are subtracting 1 from a positive number, there will not
+        be such a carry.  Furthermore, if the positive number is known to
+        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_WIDE_INT)
+       {
+         nonzero = nonzero_bits (XEXP (x, 0), mode);
+         if ((((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero) == 0)
+           return (nonzero == 1 || nonzero == 0 ? bitwidth
+                   : bitwidth - floor_log2 (nonzero) - 1);
+       }
+
+      num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode,
+                                        known_x, known_mode, known_ret);
+      num1 = cached_num_sign_bit_copies (XEXP (x, 1), mode,
+                                        known_x, known_mode, known_ret);
+      result = MAX (1, MIN (num0, num1) - 1);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+      /* If pointers extend signed and this is an addition or subtraction
+        to a pointer in Pmode, all the bits above ptr_mode are known to be
+        sign bit copies.  */
+      if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
+         && (code == PLUS || code == MINUS)
+         && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0)))
+       result = MAX ((int) (GET_MODE_BITSIZE (Pmode)
+                            - GET_MODE_BITSIZE (ptr_mode) + 1),
+                     result);
+#endif
+      return result;
+
+    case MULT:
+      /* The number of bits of the product is the sum of the number of
+        bits of both terms.  However, unless one of the terms if known
+        to be positive, we must allow for an additional bit since negating
+        a negative number can remove one sign bit copy.  */
+
+      num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode,
+                                        known_x, known_mode, known_ret);
+      num1 = cached_num_sign_bit_copies (XEXP (x, 1), mode,
+                                        known_x, known_mode, known_ret);
+
+      result = bitwidth - (bitwidth - num0) - (bitwidth - num1);
+      if (result > 0
+         && (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)
+                      & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))))
+       result--;
+
+      return MAX (1, result);
+
+    case UDIV:
+      /* The result must be <= the first operand.  If the first operand
+        has the high bit set, we know nothing about the number of sign
+        bit copies.  */
+      if (bitwidth > HOST_BITS_PER_WIDE_INT)
+       return 1;
+      else if ((nonzero_bits (XEXP (x, 0), mode)
+               & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
+       return 1;
+      else
+       return cached_num_sign_bit_copies (XEXP (x, 0), mode,
+                                          known_x, known_mode, known_ret);
+
+    case UMOD:
+      /* The result must be <= the second operand.  */
+      return cached_num_sign_bit_copies (XEXP (x, 1), mode,
+                                          known_x, known_mode, known_ret);
+
+    case DIV:
+      /* Similar to unsigned division, except that we have to worry about
+        the case where the divisor is negative, in which case we have
+        to add 1.  */
+      result = cached_num_sign_bit_copies (XEXP (x, 0), mode,
+                                          known_x, known_mode, known_ret);
+      if (result > 1
+         && (bitwidth > HOST_BITS_PER_WIDE_INT
+             || (nonzero_bits (XEXP (x, 1), mode)
+                 & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))
+       result--;
+
+      return result;
+
+    case MOD:
+      result = cached_num_sign_bit_copies (XEXP (x, 1), mode,
+                                          known_x, known_mode, known_ret);
+      if (result > 1
+         && (bitwidth > HOST_BITS_PER_WIDE_INT
+             || (nonzero_bits (XEXP (x, 1), mode)
+                 & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))
+       result--;
+
+      return result;
+
+    case ASHIFTRT:
+      /* Shifts by a constant add to the number of bits equal to the
+        sign bit.  */
+      num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode,
+                                        known_x, known_mode, known_ret);
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) > 0)
+       num0 = MIN ((int) bitwidth, num0 + INTVAL (XEXP (x, 1)));
+
+      return num0;
+
+    case ASHIFT:
+      /* Left shifts destroy copies.  */
+      if (GET_CODE (XEXP (x, 1)) != CONST_INT
+         || INTVAL (XEXP (x, 1)) < 0
+         || INTVAL (XEXP (x, 1)) >= (int) bitwidth)
+       return 1;
+
+      num0 = cached_num_sign_bit_copies (XEXP (x, 0), mode,
+                                        known_x, known_mode, known_ret);
+      return MAX (1, num0 - INTVAL (XEXP (x, 1)));
+
+    case IF_THEN_ELSE:
+      num0 = cached_num_sign_bit_copies (XEXP (x, 1), mode,
+                                        known_x, known_mode, known_ret);
+      num1 = cached_num_sign_bit_copies (XEXP (x, 2), mode,
+                                        known_x, known_mode, known_ret);
+      return MIN (num0, num1);
+
+    case EQ:  case NE:  case GE:  case GT:  case LE:  case LT:
+    case UNEQ:  case LTGT:  case UNGE:  case UNGT:  case UNLE:  case UNLT:
+    case GEU: case GTU: case LEU: case LTU:
+    case UNORDERED: case ORDERED:
+      /* If the constant is negative, take its 1's complement and remask.
+        Then see how many zero bits we have.  */
+      nonzero = STORE_FLAG_VALUE;
+      if (bitwidth <= HOST_BITS_PER_WIDE_INT
+         && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
+       nonzero = (~nonzero) & GET_MODE_MASK (mode);
+
+      return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1);
+
+    default:
+      break;
+    }
+
+  /* If we haven't been able to figure it out by one of the above rules,
+     see if some of the high-order bits are known to be zero.  If so,
+     count those bits and return one less than that amount.  If we can't
+     safely compute the mask for this mode, always return BITWIDTH.  */
+
+  bitwidth = GET_MODE_BITSIZE (mode);
+  if (bitwidth > HOST_BITS_PER_WIDE_INT)
+    return 1;
+
+  nonzero = nonzero_bits (x, mode);
+  return nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))
+        ? 1 : bitwidth - floor_log2 (nonzero) - 1;
+}
diff --git a/gcc/rtlhooks-def.h b/gcc/rtlhooks-def.h
new file mode 100644 (file)
index 0000000..aaae80c
--- /dev/null
@@ -0,0 +1,46 @@
+/* Default macros to initialize an rtl_hooks data structure.
+   Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#ifndef GCC_RTL_HOOKS_DEF_H
+#define GCC_RTL_HOOKS_DEF_H
+
+#include "rtl.h"
+
+#define RTL_HOOKS_GEN_LOWPART gen_lowpart_general
+#define RTL_HOOKS_REG_NONZERO_REG_BITS reg_nonzero_bits_general
+#define RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES reg_num_sign_bit_copies_general
+
+/* The structure is defined in rtl.h.  */
+#define RTL_HOOKS_INITIALIZER {                        \
+  RTL_HOOKS_GEN_LOWPART,                       \
+  RTL_HOOKS_REG_NONZERO_REG_BITS,              \
+  RTL_HOOKS_REG_NUM_SIGN_BIT_COPIES,           \
+}
+
+extern rtx gen_lowpart_general (enum machine_mode, rtx);
+extern rtx reg_nonzero_bits_general (rtx, enum machine_mode, rtx,
+                                    enum machine_mode,
+                                    unsigned HOST_WIDE_INT,
+                                    unsigned HOST_WIDE_INT *);
+extern rtx reg_num_sign_bit_copies_general (rtx, enum machine_mode, rtx,
+                                           enum machine_mode,
+                                           unsigned int, unsigned int *);
+
+#endif /* GCC_RTL_HOOKS_DEF_H */
diff --git a/gcc/rtlhooks.c b/gcc/rtlhooks.c
new file mode 100644 (file)
index 0000000..b27cece
--- /dev/null
@@ -0,0 +1,105 @@
+/* Generic hooks for the RTL middle-end.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "rtlhooks-def.h"
+#include "expr.h"
+\f
+
+/* For speed, we will copy the RTX hooks struct member-by-member
+   instead of doing indirect calls.  For these reason, we initialize
+   *two* struct rtl_hooks globals: rtl_hooks is the one that is used
+   to actually call the hooks, while general_rtl_hooks is used
+   to restore the hooks by passes that modify them.  */
+
+const struct rtl_hooks general_rtl_hooks = RTL_HOOKS_INITIALIZER;
+struct rtl_hooks rtl_hooks = RTL_HOOKS_INITIALIZER;
+
+rtx
+gen_lowpart_general (enum machine_mode mode, rtx x)
+{
+  rtx result = gen_lowpart_common (mode, x);
+
+  if (result)
+    return result;
+  else if (GET_CODE (x) == REG)
+    {
+      /* Must be a hard reg that's not valid in MODE.  */
+      result = gen_lowpart_common (mode, copy_to_reg (x));
+      if (result == 0)
+       abort ();
+      return result;
+    }
+  else if (GET_CODE (x) == MEM)
+    {
+      /* The only additional case we can do is MEM.  */
+      int offset = 0;
+
+      /* The following exposes the use of "x" to CSE.  */
+      if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
+         && SCALAR_INT_MODE_P (GET_MODE (x))
+         && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+                                   GET_MODE_BITSIZE (GET_MODE (x)))
+         && ! no_new_pseudos)
+       return gen_lowpart_general (mode, force_reg (GET_MODE (x), x));
+
+      if (WORDS_BIG_ENDIAN)
+       offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
+                 - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
+
+      if (BYTES_BIG_ENDIAN)
+       /* Adjust the address so that the address-after-the-data
+          is unchanged.  */
+       offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
+                  - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
+
+      return adjust_address (x, mode, offset);
+    }
+  else if (GET_CODE (x) == ADDRESSOF)
+    return gen_lowpart_general (mode, force_reg (GET_MODE (x), x));
+  else
+    abort ();
+}
+
+rtx
+reg_num_sign_bit_copies_general (rtx x ATTRIBUTE_UNUSED,
+                                enum machine_mode mode ATTRIBUTE_UNUSED,
+                                 rtx known_x ATTRIBUTE_UNUSED,
+                                enum machine_mode known_mode ATTRIBUTE_UNUSED,
+                                 unsigned int known_ret ATTRIBUTE_UNUSED,
+                                 unsigned int *result ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}
+
+rtx
+reg_nonzero_bits_general (rtx x ATTRIBUTE_UNUSED,
+                         enum machine_mode mode ATTRIBUTE_UNUSED,
+                         rtx known_x ATTRIBUTE_UNUSED,
+                          enum machine_mode known_mode ATTRIBUTE_UNUSED,
+                          unsigned HOST_WIDE_INT known_ret ATTRIBUTE_UNUSED,
+                          unsigned HOST_WIDE_INT *nonzero ATTRIBUTE_UNUSED)
+{
+  return NULL;
+}