OSDN Git Service

Correct test results for avoid-bool-define fix
[pf3gnuchains/gcc-fork.git] / gcc / expmed.c
index 79ea3c9..b08d535 100644 (file)
@@ -1,7 +1,7 @@
 /* Medium-level subroutines: convert bit-field store and extract
    and shifts, multiplies and divides to rtl instructions.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -28,8 +28,6 @@ Boston, MA 02111-1307, USA.  */
 #include "tree.h"
 #include "tm_p.h"
 #include "flags.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
 #include "insn-config.h"
 #include "expr.h"
 #include "real.h"
@@ -90,7 +88,6 @@ static int mul_highpart_cost[NUM_MACHINE_MODES];
 void
 init_expmed ()
 {
-  char *free_point;
   /* This is "some random pseudo register" for purposes of calling recog
      to see what insns exist.  */
   rtx reg = gen_rtx_REG (word_mode, 10000);
@@ -101,11 +98,6 @@ init_expmed ()
 
   start_sequence ();
 
-  /* Since we are on the permanent obstack, we must be sure we save this
-     spot AFTER we call start_sequence, since it will reuse the rtl it
-     makes.  */
-  free_point = (char *) oballoc (0);
-
   reg = gen_rtx_REG (word_mode, 10000);
 
   zero_cost = rtx_cost (const0_rtx, 0);
@@ -191,9 +183,7 @@ init_expmed ()
        }
     }
 
-  /* Free the objects we just allocated.  */
   end_sequence ();
-  obfree (free_point);
 }
 
 /* Return an rtx representing minus the value of X.
@@ -217,7 +207,7 @@ negate_rtx (mode, x)
    into a bit-field within structure STR_RTX
    containing BITSIZE bits starting at bit BITNUM.
    FIELDMODE is the machine-mode of the FIELD_DECL node for this field.
-   ALIGN is the alignment that STR_RTX is known to have, measured in bytes.
+   ALIGN is the alignment that STR_RTX is known to have.
    TOTAL_SIZE is the size of the structure in bytes, or -1 if varying.  */
 
 /* ??? Note that there are two different ideas here for how
@@ -253,7 +243,9 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
   insv_bitsize = GET_MODE_BITSIZE (op_mode);
 #endif
 
-  if (GET_CODE (str_rtx) == MEM && ! MEM_IN_STRUCT_P (str_rtx))
+  /* It is wrong to have align==0, since every object is aligned at
+     least at a bit boundary.  This usually means a bug elsewhere.  */
+  if (align == 0)
     abort ();
 
   /* Discount the part of the structure before the desired byte.
@@ -269,27 +261,12 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
         meaningful at a much higher level; when structures are copied
         between memory and regs, the higher-numbered regs
         always get higher addresses.  */
-      offset += SUBREG_WORD (op0);
+      offset += (SUBREG_BYTE (op0) / UNITS_PER_WORD);
       /* We used to adjust BITPOS here, but now we do the whole adjustment
         right after the loop.  */
       op0 = SUBREG_REG (op0);
     }
 
-  /* Make sure we are playing with integral modes.  Pun with subregs
-     if we aren't.  */
-  {
-    enum machine_mode imode = int_mode_for_mode (GET_MODE (op0));
-    if (imode != GET_MODE (op0))
-      {
-       if (GET_CODE (op0) == MEM)
-         op0 = change_address (op0, imode, NULL_RTX);
-       else if (imode != BLKmode)
-         op0 = gen_lowpart (imode, op0);
-       else
-         abort ();
-      }
-  }
-
   /* If OP0 is a register, BITPOS must count within a word.
      But as we have it, it counts within whatever size OP0 now has.
      On a bigendian machine, these are not the same, so convert.  */
@@ -303,19 +280,22 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
   if (flag_force_mem)
     value = force_not_mem (value);
 
-  if ((GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
-       || (GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode)
-          && GET_MODE_SIZE (fieldmode) != 0))
+  /* If the target is a register, overwriting the entire object, or storing
+     a full-word or multi-word field can be done with just a SUBREG.
+
+     If the target is memory, storing any naturally aligned field can be
+     done with a simple store.  For targets that support fast unaligned
+     memory, any naturally sized, unit aligned field can be done directly.  */
+     
+  if (bitsize == GET_MODE_BITSIZE (fieldmode)
       && (GET_CODE (op0) != MEM
-         || ! SLOW_UNALIGNED_ACCESS (fieldmode, align)
-         || (offset * BITS_PER_UNIT % bitsize == 0
-             && align % GET_MODE_SIZE (fieldmode) == 0))
-      && (BYTES_BIG_ENDIAN ? bitpos + bitsize == unit : bitpos == 0)
-      && bitsize == GET_MODE_BITSIZE (fieldmode))
+         ? (GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
+            || GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode))
+         : (! SLOW_UNALIGNED_ACCESS (fieldmode, align)
+            || (offset * BITS_PER_UNIT % bitsize == 0
+                && align % GET_MODE_BITSIZE (fieldmode) == 0)))
+      && (BYTES_BIG_ENDIAN ? bitpos + bitsize == unit : bitpos == 0))
     {
-      /* Storing in a full-word or multi-word field in a register
-        can be done with just SUBREG.  Also, storing in the entire object
-        can be done with just SUBREG.  */
       if (GET_MODE (op0) != fieldmode)
        {
          if (GET_CODE (op0) == SUBREG)
@@ -331,7 +311,9 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
                abort ();
            }
          if (GET_CODE (op0) == REG)
-           op0 = gen_rtx_SUBREG (fieldmode, op0, offset);
+           op0 = gen_rtx_SUBREG (fieldmode, op0,
+                                 (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+                                 + (offset * UNITS_PER_WORD));
          else
            op0 = change_address (op0, fieldmode,
                                  plus_constant (XEXP (op0, 0), offset));
@@ -340,6 +322,23 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
       return value;
     }
 
+  /* Make sure we are playing with integral modes.  Pun with subregs
+     if we aren't.  This must come after the entire register case above,
+     since that case is valid for any mode.  The following cases are only
+     valid for integral modes.  */
+  {
+    enum machine_mode imode = int_mode_for_mode (GET_MODE (op0));
+    if (imode != GET_MODE (op0))
+      {
+       if (GET_CODE (op0) == MEM)
+         op0 = change_address (op0, imode, NULL_RTX);
+       else if (imode != BLKmode)
+         op0 = gen_lowpart (imode, op0);
+       else
+         abort ();
+      }
+  }
+
   /* Storing an lsb-aligned field in a register
      can be done with a movestrict instruction.  */
 
@@ -376,7 +375,10 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
        }
 
       emit_insn (GEN_FCN (icode)
-                (gen_rtx_SUBREG (fieldmode, op0, offset), value));
+                (gen_rtx_SUBREG (fieldmode, op0,
+                                 (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+                                 + (offset * UNITS_PER_WORD)),
+                                 value));
 
       return value;
     }
@@ -400,7 +402,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
         VOIDmode, because that is what store_field uses to indicate that this
         is a bit field, but passing VOIDmode to operand_subword_force will
         result in an abort.  */
-      fieldmode = mode_for_size (nwords * BITS_PER_WORD, MODE_INT, 0);
+      fieldmode = smallest_mode_for_size (nwords * BITS_PER_WORD, MODE_INT);
 
       for (i = 0; i < nwords; i++)
        {
@@ -450,7 +452,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
                abort ();
            }
          op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
-                               op0, offset);
+                               op0, (offset * UNITS_PER_WORD));
        }
       offset = 0;
     }
@@ -515,14 +517,14 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
          if (GET_MODE (op0) == BLKmode
              || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (maxmode))
            bestmode
-             = get_best_mode (bitsize, bitnum, align * BITS_PER_UNIT, maxmode,
+             = get_best_mode (bitsize, bitnum, align, maxmode,
                               MEM_VOLATILE_P (op0));
          else
            bestmode = GET_MODE (op0);
 
          if (bestmode == VOIDmode
              || (SLOW_UNALIGNED_ACCESS (bestmode, align)
-                 && GET_MODE_SIZE (bestmode) > align))
+                 && GET_MODE_BITSIZE (bestmode) > align))
            goto insv_loses;
 
          /* Adjust address to point to the containing unit of that mode.  */
@@ -533,7 +535,8 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
          op0 = change_address (op0, bestmode, 
                                plus_constant (XEXP (op0, 0), offset));
 
-         /* Fetch that unit, store the bitfield in it, then store the unit.  */
+         /* Fetch that unit, store the bitfield in it, then store
+            the unit.  */
          tempreg = copy_to_reg (op0);
          store_bit_field (tempreg, bitsize, bitpos, fieldmode, value,
                           align, total_size);
@@ -552,7 +555,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
       if (GET_CODE (xop0) == SUBREG)
        /* We can't just change the mode, because this might clobber op0,
           and we will need the original value of op0 if insv fails.  */
-       xop0 = gen_rtx_SUBREG (maxmode, SUBREG_REG (xop0), SUBREG_WORD (xop0));
+       xop0 = gen_rtx_SUBREG (maxmode, SUBREG_REG (xop0), SUBREG_BYTE (xop0));
       if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
        xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
 
@@ -589,6 +592,8 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
              else
                value1 = gen_lowpart (maxmode, value1);
            }
+         else if (GET_CODE (value) == CONST_INT)
+           value1 = GEN_INT (trunc_int_for_mode (INTVAL (value), maxmode));
          else if (!CONSTANT_P (value))
            /* Parse phase is supposed to make VALUE's data type
               match that of the component reference, which is a type
@@ -628,7 +633,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
     (If OP0 is a register, it may be a full word or a narrower mode,
      but BITPOS still counts within a full word,
      which is significant on bigendian machines.)
-   STRUCT_ALIGN is the alignment the structure is known to have (in bytes).
+   STRUCT_ALIGN is the alignment the structure is known to have.
 
    Note that protect_from_queue has already been done on OP0 and VALUE.  */
 
@@ -798,7 +803,7 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align)
    BITSIZE is the field width; BITPOS the position of its first bit
    (within the word).
    VALUE is the value to store.
-   ALIGN is the known alignment of OP0, measured in bytes.
+   ALIGN is the known alignment of OP0.
    This is also the size of the memory objects to be used.
 
    This does not yet handle fields wider than BITS_PER_WORD.  */
@@ -818,7 +823,7 @@ store_split_bit_field (op0, bitsize, bitpos, value, align)
   if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
     unit = BITS_PER_WORD;
   else
-    unit = MIN (align * BITS_PER_UNIT, BITS_PER_WORD);
+    unit = MIN (align, BITS_PER_WORD);
 
   /* If VALUE is a constant other than a CONST_INT, get it into a register in
      WORD_MODE.  If we can do this using gen_lowpart_common, do so.  Note
@@ -885,8 +890,7 @@ store_split_bit_field (op0, bitsize, bitpos, value, align)
                 GET_MODE (value) == VOIDmode
                 ? UNITS_PER_WORD
                 : (GET_MODE (value) == BLKmode
-                   ? 1
-                   : GET_MODE_ALIGNMENT (GET_MODE (value)) / BITS_PER_UNIT));
+                   ? 1 : GET_MODE_ALIGNMENT (GET_MODE (value))));
        }
       else
        {
@@ -902,8 +906,7 @@ store_split_bit_field (op0, bitsize, bitpos, value, align)
                 GET_MODE (value) == VOIDmode
                 ? UNITS_PER_WORD
                 : (GET_MODE (value) == BLKmode
-                   ? 1
-                   : GET_MODE_ALIGNMENT (GET_MODE (value)) / BITS_PER_UNIT));
+                   ? 1 : GET_MODE_ALIGNMENT (GET_MODE (value))));
        }
 
       /* If OP0 is a register, then handle OFFSET here.
@@ -914,8 +917,8 @@ store_split_bit_field (op0, bitsize, bitpos, value, align)
         the current word starting from the base register.  */
       if (GET_CODE (op0) == SUBREG)
        {
-         word = operand_subword_force (SUBREG_REG (op0),
-                                       SUBREG_WORD (op0) + offset,
+         int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset;
+         word = operand_subword_force (SUBREG_REG (op0), word_offset,
                                        GET_MODE (SUBREG_REG (op0)));
          offset = 0;
        }
@@ -1012,7 +1015,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
       int outer_size = GET_MODE_BITSIZE (GET_MODE (op0));
       int inner_size = GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)));
 
-      offset += SUBREG_WORD (op0);
+      offset += SUBREG_BYTE (op0) / UNITS_PER_WORD;
 
       inner_size = MIN (inner_size, BITS_PER_WORD);
 
@@ -1029,6 +1032,15 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
       op0 = SUBREG_REG (op0);
     }
 
+  if (GET_CODE (op0) == REG
+      && mode == GET_MODE (op0)
+      && bitnum == 0
+      && bitsize == GET_MODE_BITSIZE (GET_MODE (op0)))
+    {
+      /* We're trying to extract a full register from itself.  */
+      return op0;
+    }
+
   /* Make sure we are playing with integral modes.  Pun with subregs
      if we aren't.  */
   {
@@ -1081,7 +1093,8 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
                  : bitpos == 0))))
     {
       enum machine_mode mode1
-       = mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0);
+       = (VECTOR_MODE_P (tmode) ? mode
+          : mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0));
 
       if (mode1 != GET_MODE (op0))
        {
@@ -1098,7 +1111,9 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
                abort ();
            }
          if (GET_CODE (op0) == REG)
-           op0 = gen_rtx_SUBREG (mode1, op0, offset);
+           op0 = gen_rtx_SUBREG (mode1, op0,
+                                 (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+                                 + (offset * UNITS_PER_WORD));
          else
            op0 = change_address (op0, mode1,
                                  plus_constant (XEXP (op0, 0), offset));
@@ -1207,7 +1222,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
          if (GET_CODE (op0) != REG)
            op0 = copy_to_reg (op0);
          op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
-                               op0, offset);
+                               op0, (offset * UNITS_PER_WORD));
        }
       offset = 0;
     }
@@ -1802,8 +1817,8 @@ extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align)
         the current word starting from the base register.  */
       if (GET_CODE (op0) == SUBREG)
        {
-         word = operand_subword_force (SUBREG_REG (op0),
-                                       SUBREG_WORD (op0) + offset,
+         int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset;
+         word = operand_subword_force (SUBREG_REG (op0), word_offset,
                                        GET_MODE (SUBREG_REG (op0)));
          offset = 0;
        }
@@ -1922,7 +1937,7 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
         op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
                       % GET_MODE_BITSIZE (mode));
       else if (GET_CODE (op1) == SUBREG
-              && SUBREG_WORD (op1) == 0)
+              && SUBREG_BYTE (op1) == 0)
        op1 = SUBREG_REG (op1);
     }
 #endif
@@ -2138,18 +2153,21 @@ synth_mult (alg_out, t, cost_limit)
   if ((t & 1) == 0)
     {
       m = floor_log2 (t & -t); /* m = number of low zero bits */
-      q = t >> m;
-      cost = shift_cost[m];
-      synth_mult (alg_in, q, cost_limit - cost);
-
-      cost += alg_in->cost;
-      if (cost < cost_limit)
+      if (m < BITS_PER_WORD)
        {
-         struct algorithm *x;
-         x = alg_in, alg_in = best_alg, best_alg = x;
-         best_alg->log[best_alg->ops] = m;
-         best_alg->op[best_alg->ops] = alg_shift;
-         cost_limit = cost;
+         q = t >> m;
+         cost = shift_cost[m];
+         synth_mult (alg_in, q, cost_limit - cost);
+
+         cost += alg_in->cost;
+         if (cost < cost_limit)
+           {
+             struct algorithm *x;
+             x = alg_in, alg_in = best_alg, best_alg = x;
+             best_alg->log[best_alg->ops] = m;
+             best_alg->op[best_alg->ops] = alg_shift;
+             cost_limit = cost;
+           }
        }
     }
 
@@ -2220,7 +2238,7 @@ synth_mult (alg_out, t, cost_limit)
       unsigned HOST_WIDE_INT d;
 
       d = ((unsigned HOST_WIDE_INT) 1 << m) + 1;
-      if (t % d == 0 && t > d)
+      if (t % d == 0 && t > d && m < BITS_PER_WORD)
        {
          cost = MIN (shiftadd_cost[m], add_cost + shift_cost[m]);
          synth_mult (alg_in, t / d, cost_limit - cost);
@@ -2239,7 +2257,7 @@ synth_mult (alg_out, t, cost_limit)
        }
 
       d = ((unsigned HOST_WIDE_INT) 1 << m) - 1;
-      if (t % d == 0 && t > d)
+      if (t % d == 0 && t > d && m < BITS_PER_WORD)
        {
          cost = MIN (shiftsub_cost[m], add_cost + shift_cost[m]);
          synth_mult (alg_in, t / d, cost_limit - cost);
@@ -2264,7 +2282,7 @@ synth_mult (alg_out, t, cost_limit)
       q = t - 1;
       q = q & -q;
       m = exact_log2 (q);
-      if (m >= 0)
+      if (m >= 0 && m < BITS_PER_WORD)
        {
          cost = shiftadd_cost[m];
          synth_mult (alg_in, (t - 1) >> m, cost_limit - cost);
@@ -2283,7 +2301,7 @@ synth_mult (alg_out, t, cost_limit)
       q = t + 1;
       q = q & -q;
       m = exact_log2 (q);
-      if (m >= 0)
+      if (m >= 0 && m < BITS_PER_WORD)
        {
          cost = shiftsub_cost[m];
          synth_mult (alg_in, (t + 1) >> m, cost_limit - cost);
@@ -2315,10 +2333,10 @@ synth_mult (alg_out, t, cost_limit)
      best_alg is normally undefined, and this is a critical function.  */
   alg_out->ops = best_alg->ops + 1;
   alg_out->cost = cost_limit;
-  bcopy ((char *) best_alg->op, (char *) alg_out->op,
-        alg_out->ops * sizeof *alg_out->op);
-  bcopy ((char *) best_alg->log, (char *) alg_out->log,
-        alg_out->ops * sizeof *alg_out->log);
+  memcpy (alg_out->op, best_alg->op,
+         alg_out->ops * sizeof *alg_out->op);
+  memcpy (alg_out->log, best_alg->log,
+         alg_out->ops * sizeof *alg_out->log);
 }
 \f
 /* Perform a multiplication and return an rtx for the result.
@@ -2361,7 +2379,8 @@ expand_mult (mode, op0, op1, target, unsignedp)
      But this causes such a terrible slowdown sometimes
      that it seems better to use synth_mult always.  */
 
-  if (const_op1 && GET_CODE (const_op1) == CONST_INT)
+  if (const_op1 && GET_CODE (const_op1) == CONST_INT
+      && (unsignedp || ! flag_trapv))
     {
       struct algorithm alg;
       struct algorithm alg2;
@@ -2401,6 +2420,7 @@ expand_mult (mode, op0, op1, target, unsignedp)
          /* We found something cheaper than a multiply insn.  */
          int opno;
          rtx accum, tem;
+         enum machine_mode nmode;
 
          op0 = protect_from_queue (op0, 0);
 
@@ -2505,12 +2525,21 @@ expand_mult (mode, op0, op1, target, unsignedp)
                }
 
              /* Write a REG_EQUAL note on the last insn so that we can cse
-                multiplication sequences.  */
+                multiplication sequences.  Note that if ACCUM is a SUBREG,
+                we've set the inner register and must properly indicate
+                that.  */
+
+             tem = op0, nmode = mode;
+             if (GET_CODE (accum) == SUBREG)
+               {
+                 nmode = GET_MODE (SUBREG_REG (accum));
+                 tem = gen_lowpart (nmode, op0);
+               }
 
              insn = get_last_insn ();
              set_unique_reg_note (insn, 
                                   REG_EQUAL,
-                                  gen_rtx_MULT (mode, op0, 
+                                  gen_rtx_MULT (nmode, tem,
                                                 GEN_INT (val_so_far)));
            }
 
@@ -2534,7 +2563,10 @@ expand_mult (mode, op0, op1, target, unsignedp)
 
   /* This used to use umul_optab if unsigned, but for non-widening multiply
      there is no difference between signed and unsigned.  */
-  op0 = expand_binop (mode, smul_optab,
+  op0 = expand_binop (mode, 
+                     ! unsignedp
+                       && flag_trapv && (GET_MODE_CLASS(mode) == MODE_INT)
+                       ? smulv_optab : smul_optab,
                      op0, op1, target, unsignedp, OPTAB_LIB_WIDEN);
   if (op0 == 0)
     abort ();
@@ -2576,11 +2608,12 @@ choose_multiplier (d, n, precision, multiplier_ptr, post_shift_ptr, lgup_ptr)
      int *post_shift_ptr;
      int *lgup_ptr;
 {
-  unsigned HOST_WIDE_INT mhigh_hi, mhigh_lo;
-  unsigned HOST_WIDE_INT mlow_hi, mlow_lo;
+  HOST_WIDE_INT mhigh_hi, mlow_hi;
+  unsigned HOST_WIDE_INT mhigh_lo, mlow_lo;
   int lgup, post_shift;
   int pow, pow2;
-  unsigned HOST_WIDE_INT nh, nl, dummy1, dummy2;
+  unsigned HOST_WIDE_INT nl, dummy1;
+  HOST_WIDE_INT nh, dummy2;
 
   /* lgup = ceil(log2(divisor)); */
   lgup = ceil_log2 (d);
@@ -2601,7 +2634,7 @@ choose_multiplier (d, n, precision, multiplier_ptr, post_shift_ptr, lgup_ptr)
   /* mlow = 2^(N + lgup)/d */
  if (pow >= HOST_BITS_PER_WIDE_INT)
     {
-      nh = (unsigned HOST_WIDE_INT) 1 << (pow - HOST_BITS_PER_WIDE_INT);
+      nh = (HOST_WIDE_INT) 1 << (pow - HOST_BITS_PER_WIDE_INT);
       nl = 0;
     }
   else
@@ -2614,7 +2647,7 @@ choose_multiplier (d, n, precision, multiplier_ptr, post_shift_ptr, lgup_ptr)
 
   /* mhigh = (2^(N + lgup) + 2^N + lgup - precision)/d */
   if (pow2 >= HOST_BITS_PER_WIDE_INT)
-    nh |= (unsigned HOST_WIDE_INT) 1 << (pow2 - HOST_BITS_PER_WIDE_INT);
+    nh |= (HOST_WIDE_INT) 1 << (pow2 - HOST_BITS_PER_WIDE_INT);
   else
     nl |= (unsigned HOST_WIDE_INT) 1 << pow2;
   div_and_round_double (TRUNC_DIV_EXPR, 1, nl, nh, d, (HOST_WIDE_INT) 0,
@@ -2756,7 +2789,7 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
   if (size > HOST_BITS_PER_WIDE_INT)
     abort ();
 
-  op1 = GEN_INT (cnst1);
+  op1 = GEN_INT (trunc_int_for_mode (cnst1, mode));
 
   if (GET_MODE_BITSIZE (wider_mode) <= HOST_BITS_PER_INT)
     wide_op1 = op1;
@@ -2777,7 +2810,9 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
         multiply.  Maybe change expand_binop to handle widening multiply?  */
       op0 = convert_to_mode (wider_mode, op0, unsignedp);
 
-      tem = expand_mult (wider_mode, op0, wide_op1, NULL_RTX, unsignedp);
+      /* We know that this can't have signed overflow, so pretend this is
+         an unsigned multiply.  */
+      tem = expand_mult (wider_mode, op0, wide_op1, NULL_RTX, 0);
       tem = expand_shift (RSHIFT_EXPR, wider_mode, tem,
                          build_int_2 (size, 0), NULL_RTX, 1);
       return convert_modes (mode, wider_mode, tem, unsignedp);
@@ -2792,18 +2827,20 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
     {
       mul_highpart_optab = unsignedp ? umul_highpart_optab : smul_highpart_optab;
       target = expand_binop (mode, mul_highpart_optab,
-                            op0, wide_op1, target, unsignedp, OPTAB_DIRECT);
+                            op0, op1, target, unsignedp, OPTAB_DIRECT);
       if (target)
        return target;
     }
 
   /* Secondly, same as above, but use sign flavor opposite of unsignedp.
      Need to adjust the result after the multiplication.  */
-  if (mul_highpart_cost[(int) mode] + 2 * shift_cost[size-1] + 4 * add_cost < max_cost)
+  if (size - 1 < BITS_PER_WORD
+      && (mul_highpart_cost[(int) mode] + 2 * shift_cost[size-1] + 4 * add_cost
+         < max_cost))
     {
       mul_highpart_optab = unsignedp ? smul_highpart_optab : umul_highpart_optab;
       target = expand_binop (mode, mul_highpart_optab,
-                            op0, wide_op1, target, unsignedp, OPTAB_DIRECT);
+                            op0, op1, target, unsignedp, OPTAB_DIRECT);
       if (target)
        /* We used the wrong signedness.  Adjust the result.  */
        return expand_mult_highpart_adjust (mode, target, op0,
@@ -2822,6 +2859,7 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
   /* Try widening the mode and perform a non-widening multiplication.  */
   moptab = smul_optab;
   if (smul_optab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
+      && size - 1 < BITS_PER_WORD
       && mul_cost[(int) wider_mode] + shift_cost[size-1] < max_cost)
     {
       op1 = wide_op1;
@@ -2831,6 +2869,7 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
   /* Try widening multiplication of opposite signedness, and adjust.  */
   moptab = unsignedp ? smul_widen_optab : umul_widen_optab;
   if (moptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
+      && size - 1 < BITS_PER_WORD
       && (mul_widen_cost[(int) wider_mode]
          + 2 * shift_cost[size-1] + 4 * add_cost < max_cost))
     {
@@ -2970,6 +3009,16 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
   if (op1 == const1_rtx)
     return rem_flag ? const0_rtx : op0;
 
+    /* When dividing by -1, we could get an overflow.
+     negv_optab can handle overflows.  */
+  if (! unsignedp && op1 == constm1_rtx)
+    {
+      if (rem_flag)
+        return const0_rtx;
+      return expand_unop (mode, flag_trapv && GET_MODE_CLASS(mode) == MODE_INT
+                        ? negv_optab : neg_optab, op0, target, 0);
+    }
+
   if (target
       /* Don't use the function value register as a target
         since we have to read it as well as write it,
@@ -3157,6 +3206,9 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
                          {
                            rtx t1, t2, t3, t4;
 
+                           if (post_shift - 1 >= BITS_PER_WORD)
+                             goto fail1;
+
                            extra_cost = (shift_cost[post_shift - 1]
                                          + shift_cost[1] + 2 * add_cost);
                            t1 = expand_mult_highpart (compute_mode, op0, ml,
@@ -3181,6 +3233,10 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
                          {
                            rtx t1, t2;
 
+                           if (pre_shift >= BITS_PER_WORD
+                               || post_shift >= BITS_PER_WORD)
+                             goto fail1;
+
                            t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
                                               build_int_2 (pre_shift, 0),
                                               NULL_RTX, 1);
@@ -3220,7 +3276,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
                if (rem_flag && d < 0)
                  {
                    d = abs_d;
-                   op1 = GEN_INT (abs_d);
+                   op1 = GEN_INT (trunc_int_for_mode (abs_d, compute_mode));
                  }
 
                if (d == 1)
@@ -3242,7 +3298,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
                else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d))
                  {
                    lgup = floor_log2 (abs_d);
-                   if (abs_d != 2 && BRANCH_COST < 3)
+                   if (BRANCH_COST < 1 || (abs_d != 2 && BRANCH_COST < 3))
                      {
                        rtx label = gen_label_rtx ();
                        rtx t1;
@@ -3250,7 +3306,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
                        t1 = copy_to_mode_reg (compute_mode, op0);
                        do_cmp_and_jump (t1, const0_rtx, GE,
                                         compute_mode, label);
-                       expand_inc (t1, GEN_INT (abs_d - 1));
+                       expand_inc (t1, GEN_INT (trunc_int_for_mode
+                                                (abs_d - 1, compute_mode)));
                        emit_label (label);
                        quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1,
                                                 build_int_2 (lgup, 0),
@@ -3287,7 +3344,10 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
                                               REG_EQUAL,
                                               gen_rtx_DIV (compute_mode,
                                                            op0,
-                                                           GEN_INT (abs_d)));
+                                                           GEN_INT
+                                                           (trunc_int_for_mode
+                                                            (abs_d,
+                                                             compute_mode))));
 
                        quotient = expand_unop (compute_mode, neg_optab,
                                                quotient, quotient, 0);
@@ -3301,6 +3361,10 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
                      {
                        rtx t1, t2, t3;
 
+                       if (post_shift >= BITS_PER_WORD
+                           || size - 1 >= BITS_PER_WORD)
+                         goto fail1;
+
                        extra_cost = (shift_cost[post_shift]
                                      + shift_cost[size - 1] + add_cost);
                        t1 = expand_mult_highpart (compute_mode, op0, ml,
@@ -3327,6 +3391,10 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
                      {
                        rtx t1, t2, t3, t4;
 
+                       if (post_shift >= BITS_PER_WORD
+                           || size - 1 >= BITS_PER_WORD)
+                         goto fail1;
+
                        ml |= (~(unsigned HOST_WIDE_INT) 0) << (size - 1);
                        extra_cost = (shift_cost[post_shift]
                                      + shift_cost[size - 1] + 2 * add_cost);
@@ -3410,23 +3478,28 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
                    if (mh)
                      abort ();
 
-                   t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
-                                      build_int_2 (size - 1, 0), NULL_RTX, 0);
-                   t2 = expand_binop (compute_mode, xor_optab, op0, t1,
-                                      NULL_RTX, 0, OPTAB_WIDEN);
-                   extra_cost = (shift_cost[post_shift]
-                                 + shift_cost[size - 1] + 2 * add_cost);
-                   t3 = expand_mult_highpart (compute_mode, t2, ml,
-                                              NULL_RTX, 1,
-                                              max_cost - extra_cost);
-                   if (t3 != 0)
+                   if (post_shift < BITS_PER_WORD
+                       && size - 1 < BITS_PER_WORD)
                      {
-                       t4 = expand_shift (RSHIFT_EXPR, compute_mode, t3,
-                                          build_int_2 (post_shift, 0),
-                                          NULL_RTX, 1);
-                       quotient = expand_binop (compute_mode, xor_optab,
-                                                t4, t1, tquotient, 0,
-                                                OPTAB_WIDEN);
+                       t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
+                                          build_int_2 (size - 1, 0),
+                                          NULL_RTX, 0);
+                       t2 = expand_binop (compute_mode, xor_optab, op0, t1,
+                                          NULL_RTX, 0, OPTAB_WIDEN);
+                       extra_cost = (shift_cost[post_shift]
+                                     + shift_cost[size - 1] + 2 * add_cost);
+                       t3 = expand_mult_highpart (compute_mode, t2, ml,
+                                                  NULL_RTX, 1,
+                                                  max_cost - extra_cost);
+                       if (t3 != 0)
+                         {
+                           t4 = expand_shift (RSHIFT_EXPR, compute_mode, t3,
+                                              build_int_2 (post_shift, 0),
+                                              NULL_RTX, 1);
+                           quotient = expand_binop (compute_mode, xor_optab,
+                                                    t4, t1, tquotient, 0,
+                                                    OPTAB_WIDEN);
+                         }
                      }
                  }
              }
@@ -3766,16 +3839,17 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
          {
            HOST_WIDE_INT d = INTVAL (op1);
            unsigned HOST_WIDE_INT ml;
-           int post_shift;
+           int pre_shift;
            rtx t1;
 
-           post_shift = floor_log2 (d & -d);
-           ml = invert_mod2n (d >> post_shift, size);
-           t1 = expand_mult (compute_mode, op0, GEN_INT (ml), NULL_RTX,
-                             unsignedp);
-           quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1,
-                                    build_int_2 (post_shift, 0),
-                                    NULL_RTX, unsignedp);
+           pre_shift = floor_log2 (d & -d);
+           ml = invert_mod2n (d >> pre_shift, size);
+           t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
+                              build_int_2 (pre_shift, 0), NULL_RTX, unsignedp);
+           quotient = expand_mult (compute_mode, t1,
+                                   GEN_INT (trunc_int_for_mode
+                                            (ml, compute_mode)),
+                                   NULL_RTX, 0);
 
            insn = get_last_insn ();
            set_unique_reg_note (insn,
@@ -3828,8 +3902,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
                remainder = expand_binop (compute_mode, sub_optab, op0, tem,
                                          remainder, 0, OPTAB_LIB_WIDEN);
              }
-           abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 0);
-           abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 0);
+           abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 1, 0);
+           abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 1, 0);
            tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
                                build_int_2 (1, 0), NULL_RTX, 1);
            do_cmp_and_jump (tem, abs_op1, LTU, compute_mode, label);
@@ -4041,6 +4115,14 @@ make_tree (type, x)
    default:
       t = make_node (RTL_EXPR);
       TREE_TYPE (t) = type;
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+      /* If TYPE is a POINTER_TYPE, X might be Pmode with TYPE_MODE being
+        ptr_mode.  So convert.  */
+      if (POINTER_TYPE_P (type) && GET_MODE (x) != TYPE_MODE (type))
+       x = convert_memory_address (TYPE_MODE (type), x);
+#endif
+
       RTL_EXPR_RTL (t) = x;
       /* There are no insns to be output
         when this rtl_expr is used.  */
@@ -4144,8 +4226,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
   /* If one operand is constant, make it the second one.  Only do this
      if the other operand is not constant as well.  */
 
-  if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
-      || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
+  if (swap_commutative_operands_p (op0, op1))
     {
       tem = op0;
       op0 = op1;
@@ -4190,6 +4271,29 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
       break;
     }
 
+  /* If we are comparing a double-word integer with zero, we can convert
+     the comparison into one involving a single word.  */
+  if (GET_MODE_BITSIZE (mode) == BITS_PER_WORD * 2
+      && GET_MODE_CLASS (mode) == MODE_INT
+      && op1 == const0_rtx)
+    {
+      if (code == EQ || code == NE)
+       {
+         /* Do a logical OR of the two words and compare the result.  */
+         rtx op0h = gen_highpart (word_mode, op0);
+         rtx op0l = gen_lowpart (word_mode, op0);
+         rtx op0both = expand_binop (word_mode, ior_optab, op0h, op0l,
+                                     NULL_RTX, unsignedp, OPTAB_DIRECT);
+         if (op0both != 0)
+           return emit_store_flag (target, code, op0both, op1, word_mode,
+                                   unsignedp, normalizep);
+       }
+      else if (code == LT || code == GE)
+       /* If testing the sign bit, can just test on high word.  */
+       return emit_store_flag (target, code, gen_highpart (word_mode, op0),
+                               op1, word_mode, unsignedp, normalizep);
+    }
+
   /* From now on, we won't change CODE, so set ICODE now.  */
   icode = setcc_gen_code[(int) code];
 
@@ -4456,6 +4560,10 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
         we can use zero-extension to the wider mode (an unsigned conversion)
         as the operation.  */
 
+      /* Note that ABS doesn't yield a positive number for INT_MIN, but 
+        that is compensated by the subsequent overflow when subtracting 
+        one / negating. */
+
       if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
        tem = expand_unop (mode, abs_optab, op0, subtarget, 1);
       else if (ffs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)