OSDN Git Service

* cfgexpand.c (expand_debug_expr): Check for mismatched modes in
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 129cd4d..2e81efc 100644 (file)
@@ -1,6 +1,6 @@
 /* Optimize by combining instructions for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -92,7 +92,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "expr.h"
 #include "insn-attr.h"
 #include "recog.h"
-#include "real.h"
 #include "toplev.h"
 #include "target.h"
 #include "optabs.h"
@@ -391,7 +390,7 @@ static int contains_muldiv (rtx);
 static rtx try_combine (rtx, rtx, rtx, int *);
 static void undo_all (void);
 static void undo_commit (void);
-static rtx *find_split_point (rtx *, rtx);
+static rtx *find_split_point (rtx *, rtx, bool);
 static rtx subst (rtx, rtx, rtx, int, int);
 static rtx combine_simplify_rtx (rtx, enum machine_mode, int);
 static rtx simplify_if_then_else (rtx);
@@ -767,7 +766,7 @@ do_SUBST_MODE (rtx *into, enum machine_mode newval)
 /* Subroutine of try_combine.  Determine whether the combine replacement
    patterns NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to
    insn_rtx_cost that the original instruction sequence I1, I2, I3 and
-   undobuf.other_insn.  Note that I1 and/or NEWI2PAT may be NULL_RTX. 
+   undobuf.other_insn.  Note that I1 and/or NEWI2PAT may be NULL_RTX.
    NEWOTHERPAT and undobuf.other_insn may also both be NULL_RTX.  This
    function returns false, if the costs of all instructions can be
    estimated, and the replacements are more expensive than the original
@@ -912,7 +911,7 @@ create_log_links (void)
      register and establishing log links when def is encountered.
      Note that we do not clear next_use array in order to save time,
      so we have to test whether the use is in the same basic block as def.
-              
+
      There are a few cases below when we do not consider the definition or
      usage -- these are taken from original flow.c did. Don't ask me why it is
      done this way; I don't know and if it works, I don't want to know.  */
@@ -1343,7 +1342,7 @@ setup_incoming_promotions (rtx first)
   for (arg = DECL_ARGUMENTS (current_function_decl); arg;
        arg = TREE_CHAIN (arg))
     {
-      rtx reg = DECL_INCOMING_RTL (arg);
+      rtx x, reg = DECL_INCOMING_RTL (arg);
       int uns1, uns3;
       enum machine_mode mode1, mode2, mode3, mode4;
 
@@ -1367,7 +1366,7 @@ setup_incoming_promotions (rtx first)
       mode2 = TYPE_MODE (DECL_ARG_TYPE (arg));
       uns3 = TYPE_UNSIGNED (DECL_ARG_TYPE (arg));
 
-      /* The mode and signedness of the argument as it is actually passed, 
+      /* The mode and signedness of the argument as it is actually passed,
          after any TARGET_PROMOTE_FUNCTION_ARGS-driven ABI promotions.  */
       mode3 = promote_function_mode (DECL_ARG_TYPE (arg), mode2, &uns3,
                                     TREE_TYPE (cfun->decl), 0);
@@ -1375,30 +1374,38 @@ setup_incoming_promotions (rtx first)
       /* The mode of the register in which the argument is being passed.  */
       mode4 = GET_MODE (reg);
 
-      /* Eliminate sign extensions in the callee when possible.  Only
-         do this when:
-        (a) a mode promotion has occurred;
-        (b) the mode of the register is the same as the mode of
-            the argument as it is passed; and
-        (c) the signedness does not change across any of the promotions; and
-        (d) when no language-level promotions (which we cannot guarantee
-            will have been done by an external caller) are necessary,
-            unless we know that this function is only ever called from
-            the current compilation unit -- all of whose call sites will
-            do the mode1 --> mode2 promotion.  */
-      if (mode1 != mode3
-          && mode3 == mode4
-          && uns1 == uns3
-         && (mode1 == mode2 || strictly_local))
-        {
-         /* Record that the value was promoted from mode1 to mode3,
-            so that any sign extension at the head of the current
-            function may be eliminated.  */
-         rtx x;
-         x = gen_rtx_CLOBBER (mode1, const0_rtx);
-         x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
-         record_value_for_reg (reg, first, x);
-       }
+      /* Eliminate sign extensions in the callee when:
+        (a) A mode promotion has occurred;  */
+      if (mode1 == mode3)
+       continue;
+      /* (b) The mode of the register is the same as the mode of
+            the argument as it is passed; */
+      if (mode3 != mode4)
+       continue;
+      /* (c) There's no language level extension;  */
+      if (mode1 == mode2)
+       ;
+      /* (c.1) All callers are from the current compilation unit.  If that's
+        the case we don't have to rely on an ABI, we only have to know
+        what we're generating right now, and we know that we will do the
+        mode1 to mode2 promotion with the given sign.  */
+      else if (!strictly_local)
+       continue;
+      /* (c.2) The combination of the two promotions is useful.  This is
+        true when the signs match, or if the first promotion is unsigned.
+        In the later case, (sign_extend (zero_extend x)) is the same as
+        (zero_extend (zero_extend x)), so make sure to force UNS3 true.  */
+      else if (uns1)
+       uns3 = true;
+      else if (uns3)
+       continue;
+
+      /* Record that the value was promoted from mode1 to mode3,
+        so that any sign extension at the head of the current
+        function may be eliminated.  */
+      x = gen_rtx_CLOBBER (mode1, const0_rtx);
+      x = gen_rtx_fmt_e ((uns3 ? ZERO_EXTEND : SIGN_EXTEND), mode3, x);
+      record_value_for_reg (reg, first, x);
     }
 }
 
@@ -2068,14 +2075,14 @@ likely_spilled_retval_p (rtx insn)
   unsigned regno, nregs;
   /* We assume here that no machine mode needs more than
      32 hard registers when the value overlaps with a register
-     for which FUNCTION_VALUE_REGNO_P is true.  */
+     for which TARGET_FUNCTION_VALUE_REGNO_P is true.  */
   unsigned mask;
   struct likely_spilled_retval_info info;
 
   if (!NONJUMP_INSN_P (use) || GET_CODE (PATTERN (use)) != USE || insn == use)
     return 0;
   reg = XEXP (PATTERN (use), 0);
-  if (!REG_P (reg) || !FUNCTION_VALUE_REGNO_P (REGNO (reg)))
+  if (!REG_P (reg) || !targetm.calls.function_value_regno_p (REGNO (reg)))
     return 0;
   regno = REGNO (reg);
   nregs = hard_regno_nregs[regno][GET_MODE (reg)];
@@ -2278,10 +2285,12 @@ struct rtx_subst_pair
    substituted.  */
 
 static rtx
-propagate_for_debug_subst (rtx from ATTRIBUTE_UNUSED, void *data)
+propagate_for_debug_subst (rtx from, const_rtx old_rtx, void *data)
 {
   struct rtx_subst_pair *pair = (struct rtx_subst_pair *)data;
 
+  if (!rtx_equal_p (from, old_rtx))
+    return NULL_RTX;
   if (!pair->adjusted)
     {
       pair->adjusted = true;
@@ -2300,6 +2309,7 @@ static void
 propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src, bool move)
 {
   rtx next, move_pos = move ? last : NULL_RTX, loc;
+  bool first_p;
 
 #ifdef AUTO_INC_DEC
   struct rtx_subst_pair p;
@@ -2308,6 +2318,7 @@ propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src, bool move)
   p.after = move;
 #endif
 
+  first_p = true;
   next = NEXT_INSN (insn);
   while (next != last)
     {
@@ -2315,6 +2326,11 @@ propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src, bool move)
       next = NEXT_INSN (insn);
       if (DEBUG_INSN_P (insn))
        {
+         if (first_p)
+           {
+             src = make_compound_operation (src, SET);
+             first_p = false;
+           }
 #ifdef AUTO_INC_DEC
          loc = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
                                         dest, propagate_for_debug_subst, &p);
@@ -2655,10 +2671,16 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
          i2dest = SET_DEST (temp);
          i2dest_killed = dead_or_set_p (i2, i2dest);
 
+         /* Replace the source in I2 with the new constant and make the
+            resulting insn the new pattern for I3.  Then skip to where we
+            validate the pattern.  Everything was set up above.  */
          SUBST (SET_SRC (temp),
                 immed_double_const (olo, ohi, GET_MODE (SET_DEST (temp))));
 
          newpat = PATTERN (i2);
+
+          /* The dest of I3 has been replaced with the dest of I2.  */
+          changed_i3_dest = 1;
          goto validate_replacement;
        }
     }
@@ -3030,8 +3052,6 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        }
     }
 
-  /* We come here when we are replacing a destination in I2 with the
-     destination of I3.  */
  validate_replacement:
 
   /* Note which hard regs this insn has as inputs.  */
@@ -3253,7 +3273,8 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
       /* If we can split it and use I2DEST, go ahead and see if that
         helps things be recognized.  Verify that none of the registers
         are set between I2 and I3.  */
-      if (insn_code_number < 0 && (split = find_split_point (&newpat, i3)) != 0
+      if (insn_code_number < 0
+          && (split = find_split_point (&newpat, i3, false)) != 0
 #ifdef HAVE_cc0
          && REG_P (i2dest)
 #endif
@@ -3279,6 +3300,14 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
          i2scratch = true;
 
+         /* *SPLIT may be part of I2SRC, so make sure we have the
+            original expression around for later debug processing.
+            We should not need I2SRC any more in other cases.  */
+         if (MAY_HAVE_DEBUG_INSNS)
+           i2src = copy_rtx (i2src);
+         else
+           i2src = NULL;
+
          /* Get NEWDEST as a register in the proper mode.  We have already
             validated that we can do this.  */
          if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode)
@@ -3775,7 +3804,13 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        call_usage = copy_rtx (call_usage);
 
        if (substed_i2)
-         replace_rtx (call_usage, i2dest, i2src);
+         {
+           /* I2SRC must still be meaningful at this point.  Some splitting
+              operations can invalidate I2SRC, but those operations do not
+              apply to calls.  */
+           gcc_assert (i2src);
+           replace_rtx (call_usage, i2dest, i2src);
+         }
 
        if (substed_i1)
          replace_rtx (call_usage, i1dest, i1src);
@@ -3887,7 +3922,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
 
     if (newi2pat && new_i2_notes)
       distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
-    
+
     if (new_i3_notes)
       distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
 
@@ -4033,7 +4068,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
        }
       df_insn_rescan (i3);
     }
-  
+
   /* Set new_direct_jump_p if a new return or simple jump instruction
      has been created.  Adjust the CFG accordingly.  */
 
@@ -4061,7 +4096,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p)
       *new_direct_jump_p = 1;
       update_cfg_for_uncondjump (i3);
     }
-  
+
   combine_successes++;
   undo_commit ();
 
@@ -4130,7 +4165,7 @@ undo_commit (void)
    two insns.  */
 
 static rtx *
-find_split_point (rtx *loc, rtx insn)
+find_split_point (rtx *loc, rtx insn, bool set_src)
 {
   rtx x = *loc;
   enum rtx_code code = GET_CODE (x);
@@ -4150,7 +4185,7 @@ find_split_point (rtx *loc, rtx insn)
       if (MEM_P (SUBREG_REG (x)))
        return loc;
 #endif
-      return find_split_point (&SUBREG_REG (x), insn);
+      return find_split_point (&SUBREG_REG (x), insn, false);
 
     case MEM:
 #ifdef HAVE_lo_sum
@@ -4159,9 +4194,12 @@ find_split_point (rtx *loc, rtx insn)
       if (GET_CODE (XEXP (x, 0)) == CONST
          || GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
        {
+         enum machine_mode address_mode
+           = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x));
+
          SUBST (XEXP (x, 0),
-                gen_rtx_LO_SUM (Pmode,
-                                gen_rtx_HIGH (Pmode, XEXP (x, 0)),
+                gen_rtx_LO_SUM (address_mode,
+                                gen_rtx_HIGH (address_mode, XEXP (x, 0)),
                                 XEXP (x, 0)));
          return &XEXP (XEXP (x, 0), 0);
        }
@@ -4174,7 +4212,8 @@ find_split_point (rtx *loc, rtx insn)
         it will not remain in the result.  */
       if (GET_CODE (XEXP (x, 0)) == PLUS
          && CONST_INT_P (XEXP (XEXP (x, 0), 1))
-         && ! memory_address_p (GET_MODE (x), XEXP (x, 0)))
+         && ! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+                                           MEM_ADDR_SPACE (x)))
        {
          rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER];
          rtx seq = combine_split_insns (gen_rtx_SET (VOIDmode, reg,
@@ -4197,8 +4236,9 @@ find_split_point (rtx *loc, rtx insn)
              && NONJUMP_INSN_P (NEXT_INSN (seq))
              && GET_CODE (PATTERN (NEXT_INSN (seq))) == SET
              && SET_DEST (PATTERN (NEXT_INSN (seq))) == reg
-             && memory_address_p (GET_MODE (x),
-                                  SET_SRC (PATTERN (NEXT_INSN (seq)))))
+             && memory_address_addr_space_p
+                  (GET_MODE (x), SET_SRC (PATTERN (NEXT_INSN (seq))),
+                   MEM_ADDR_SPACE (x)))
            {
              rtx src1 = SET_SRC (PATTERN (seq));
              rtx src2 = SET_SRC (PATTERN (NEXT_INSN (seq)));
@@ -4237,7 +4277,8 @@ find_split_point (rtx *loc, rtx insn)
       /* If we have a PLUS whose first operand is complex, try computing it
          separately by making a split there.  */
       if (GET_CODE (XEXP (x, 0)) == PLUS
-          && ! memory_address_p (GET_MODE (x), XEXP (x, 0))
+          && ! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0),
+                                           MEM_ADDR_SPACE (x))
           && ! OBJECT_P (XEXP (XEXP (x, 0), 0))
           && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG
                 && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0)))))
@@ -4261,12 +4302,12 @@ find_split_point (rtx *loc, rtx insn)
 #endif
 
       /* See if we can split SET_SRC as it stands.  */
-      split = find_split_point (&SET_SRC (x), insn);
+      split = find_split_point (&SET_SRC (x), insn, true);
       if (split && split != &SET_SRC (x))
        return split;
 
       /* See if we can split SET_DEST as it stands.  */
-      split = find_split_point (&SET_DEST (x), insn);
+      split = find_split_point (&SET_DEST (x), insn, false);
       if (split && split != &SET_DEST (x))
        return split;
 
@@ -4310,7 +4351,7 @@ find_split_point (rtx *loc, rtx insn)
 
          SUBST (SET_DEST (x), dest);
 
-         split = find_split_point (&SET_SRC (x), insn);
+         split = find_split_point (&SET_SRC (x), insn, true);
          if (split && split != &SET_SRC (x))
            return split;
        }
@@ -4346,7 +4387,7 @@ find_split_point (rtx *loc, rtx insn)
              if (extraction != 0)
                {
                  SUBST (SET_SRC (x), extraction);
-                 return find_split_point (loc, insn);
+                 return find_split_point (loc, insn, false);
                }
            }
          break;
@@ -4368,7 +4409,7 @@ find_split_point (rtx *loc, rtx insn)
                                                    XEXP (SET_SRC (x), 0),
                                                    GEN_INT (pos))));
 
-             split = find_split_point (&SET_SRC (x), insn);
+             split = find_split_point (&SET_SRC (x), insn, true);
              if (split && split != &SET_SRC (x))
                return split;
            }
@@ -4427,7 +4468,7 @@ find_split_point (rtx *loc, rtx insn)
                                   GEN_INT (pos)),
                                  GEN_INT (((HOST_WIDE_INT) 1 << len) - 1)));
 
-             split = find_split_point (&SET_SRC (x), insn);
+             split = find_split_point (&SET_SRC (x), insn, true);
              if (split && split != &SET_SRC (x))
                return split;
            }
@@ -4442,7 +4483,7 @@ find_split_point (rtx *loc, rtx insn)
                                               - len - pos)),
                      GEN_INT (GET_MODE_BITSIZE (mode) - len)));
 
-             split = find_split_point (&SET_SRC (x), insn);
+             split = find_split_point (&SET_SRC (x), insn, true);
              if (split && split != &SET_SRC (x))
                return split;
            }
@@ -4482,7 +4523,7 @@ find_split_point (rtx *loc, rtx insn)
                                              GET_MODE (x),
                                              XEXP (XEXP (x, 0), 0),
                                              XEXP (XEXP (x, 1), 0))));
-         return find_split_point (loc, insn);
+         return find_split_point (loc, insn, set_src);
        }
 
       /* Many RISC machines have a large set of logical insns.  If the
@@ -4496,6 +4537,14 @@ find_split_point (rtx *loc, rtx insn)
        }
       break;
 
+    case PLUS:
+    case MINUS:
+      /* Split at a multiply-accumulate instruction.  However if this is
+         the SET_SRC, we likely do not have such an instruction and it's
+         worthless to try this split.  */
+      if (!set_src && GET_CODE (XEXP (x, 0)) == MULT)
+        return loc;
+
     default:
       break;
     }
@@ -4505,7 +4554,7 @@ find_split_point (rtx *loc, rtx insn)
     {
     case RTX_BITFIELD_OPS:             /* This is ZERO_EXTRACT and SIGN_EXTRACT.  */
     case RTX_TERNARY:
-      split = find_split_point (&XEXP (x, 2), insn);
+      split = find_split_point (&XEXP (x, 2), insn, false);
       if (split)
        return split;
       /* ... fall through ...  */
@@ -4513,7 +4562,7 @@ find_split_point (rtx *loc, rtx insn)
     case RTX_COMM_ARITH:
     case RTX_COMPARE:
     case RTX_COMM_COMPARE:
-      split = find_split_point (&XEXP (x, 1), insn);
+      split = find_split_point (&XEXP (x, 1), insn, false);
       if (split)
        return split;
       /* ... fall through ...  */
@@ -4523,7 +4572,7 @@ find_split_point (rtx *loc, rtx insn)
       if (GET_CODE (x) != AND && GET_CODE (XEXP (x, 0)) == AND)
        return &XEXP (x, 0);
 
-      split = find_split_point (&XEXP (x, 0), insn);
+      split = find_split_point (&XEXP (x, 0), insn, false);
       if (split)
        return split;
       return loc;
@@ -5150,6 +5199,10 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
               force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
                              GET_MODE_MASK (mode), 0));
 
+      /* We can truncate a constant value and return it.  */
+      if (CONST_INT_P (XEXP (x, 0)))
+       return gen_int_mode (INTVAL (XEXP (x, 0)), mode);
+
       /* Similarly to what we do in simplify-rtx.c, a truncate of a register
         whose value is a comparison can be replaced with a subreg if
         STORE_FLAG_VALUE permits.  */
@@ -5266,7 +5319,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int in_dest)
        }
 
       /* Try simplify a*(b/c) as (a*b)/c.  */
-      if (FLOAT_MODE_P (mode) && flag_associative_math 
+      if (FLOAT_MODE_P (mode) && flag_associative_math
          && GET_CODE (XEXP (x, 0)) == DIV)
        {
          rtx tem = simplify_binary_operation (MULT, mode,
@@ -6769,8 +6822,10 @@ make_extraction (enum machine_mode mode, rtx inner, HOST_WIDE_INT pos,
       if (mode == tmode)
        return new_rtx;
 
-      if (CONST_INT_P (new_rtx))
-       return gen_int_mode (INTVAL (new_rtx), mode);
+      if (CONST_INT_P (new_rtx)
+         || GET_CODE (new_rtx) == CONST_DOUBLE)
+       return simplify_unary_operation (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
+                                        mode, new_rtx, tmode);
 
       /* If we know that no extraneous bits are set, and that the high
         bit is not set, convert the extraction to the cheaper of
@@ -7288,15 +7343,14 @@ make_compound_operation (rtx x, enum rtx_code in_code)
       tem = make_compound_operation (SUBREG_REG (x), in_code);
 
       {
-       rtx simplified;
-       simplified = simplify_subreg (GET_MODE (x), tem, GET_MODE (tem),
-                                     SUBREG_BYTE (x));
+       rtx simplified = simplify_subreg (mode, tem, GET_MODE (SUBREG_REG (x)),
+                                         SUBREG_BYTE (x));
 
        if (simplified)
          tem = simplified;
 
        if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x))
-           && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (tem))
+           && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
            && subreg_lowpart_p (x))
          {
            rtx newer = force_to_mode (tem, mode, ~(HOST_WIDE_INT) 0,
@@ -10169,7 +10223,7 @@ recog_for_combine (rtx *pnewpat, rtx insn, rtx *pnotes)
          if (REG_P (XEXP (XVECEXP (newpat, 0, i), 0))
              && ! reg_dead_at_p (XEXP (XVECEXP (newpat, 0, i), 0), insn))
            return -1;
-         if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) != SCRATCH) 
+         if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) != SCRATCH)
            {
              gcc_assert (REG_P (XEXP (XVECEXP (newpat, 0, i), 0)));
              notes = alloc_reg_note (REG_UNUSED,
@@ -11461,6 +11515,22 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
        {
          int zero_extended;
 
+         /* If this is a test for negative, we can make an explicit
+            test of the sign bit.  Test this first so we can use
+            a paradoxical subreg to extend OP0.  */
+
+         if (op1 == const0_rtx && (code == LT || code == GE)
+             && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+           {
+             op0 = simplify_gen_binary (AND, tmode,
+                                        gen_lowpart (tmode, op0),
+                                        GEN_INT ((HOST_WIDE_INT) 1
+                                                 << (GET_MODE_BITSIZE (mode)
+                                                     - 1)));
+             code = (code == LT) ? NE : EQ;
+             break;
+           }
+
          /* If the only nonzero bits in OP0 and OP1 are those in the
             narrower mode and this is an equality or unsigned comparison,
             we can use the wider mode.  Similarly for sign-extended
@@ -11491,27 +11561,20 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
                                                        XEXP (op0, 0)),
                                           gen_lowpart (tmode,
                                                        XEXP (op0, 1)));
-
-             op0 = gen_lowpart (tmode, op0);
-             if (zero_extended && CONST_INT_P (op1))
-               op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (mode));
-             op1 = gen_lowpart (tmode, op1);
-             break;
-           }
-
-         /* If this is a test for negative, we can make an explicit
-            test of the sign bit.  */
-
-         if (op1 == const0_rtx && (code == LT || code == GE)
-             && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
-           {
-             op0 = simplify_gen_binary (AND, tmode,
-                                        gen_lowpart (tmode, op0),
-                                        GEN_INT ((HOST_WIDE_INT) 1
-                                                 << (GET_MODE_BITSIZE (mode)
-                                                     - 1)));
-             code = (code == LT) ? NE : EQ;
-             break;
+             else
+               {
+                 if (zero_extended)
+                   {
+                     op0 = simplify_gen_unary (ZERO_EXTEND, tmode, op0, mode);
+                     op1 = simplify_gen_unary (ZERO_EXTEND, tmode, op1, mode);
+                   }
+                 else
+                   {
+                     op0 = simplify_gen_unary (SIGN_EXTEND, tmode, op0, mode);
+                     op1 = simplify_gen_unary (SIGN_EXTEND, tmode, op1, mode);
+                   }
+                 break;
+               }
            }
        }