OSDN Git Service

2004-06-28 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / expmed.c
index da0a9fe..c862503 100644 (file)
@@ -57,7 +57,8 @@ static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
    Usually, this will mean that the MD file will emit non-branch
    sequences.  */
 
-static int sdiv_pow2_cheap, smod_pow2_cheap;
+static int sdiv_pow2_cheap[NUM_MACHINE_MODES];
+static int smod_pow2_cheap[NUM_MACHINE_MODES];
 
 #ifndef SLOW_UNALIGNED_ACCESS
 #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
@@ -90,10 +91,12 @@ static int sdiv_pow2_cheap, smod_pow2_cheap;
 
 /* Cost of various pieces of RTL.  Note that some of these are indexed by
    shift count and some by mode.  */
-static int add_cost, negate_cost, zero_cost;
-static int shift_cost[MAX_BITS_PER_WORD];
-static int shiftadd_cost[MAX_BITS_PER_WORD];
-static int shiftsub_cost[MAX_BITS_PER_WORD];
+static int zero_cost;
+static int add_cost[NUM_MACHINE_MODES];
+static int neg_cost[NUM_MACHINE_MODES];
+static int shift_cost[NUM_MACHINE_MODES][MAX_BITS_PER_WORD];
+static int shiftadd_cost[NUM_MACHINE_MODES][MAX_BITS_PER_WORD];
+static int shiftsub_cost[NUM_MACHINE_MODES][MAX_BITS_PER_WORD];
 static int mul_cost[NUM_MACHINE_MODES];
 static int div_cost[NUM_MACHINE_MODES];
 static int mul_widen_cost[NUM_MACHINE_MODES];
@@ -103,85 +106,51 @@ void
 init_expmed (void)
 {
   rtx reg, shift_insn, shiftadd_insn, shiftsub_insn;
+  rtx shift_pat, shiftadd_pat, shiftsub_pat;
+  rtx pow2[MAX_BITS_PER_WORD];
+  rtx cint[MAX_BITS_PER_WORD];
   int dummy;
-  int m;
+  int m, n;
   enum machine_mode mode, wider_mode;
 
   start_sequence ();
 
-  /* This is "some random pseudo register" for purposes of calling recog
-     to see what insns exist.  */
-  reg = gen_rtx_REG (word_mode, 10000);
-
   zero_cost = rtx_cost (const0_rtx, 0);
-  add_cost = rtx_cost (gen_rtx_PLUS (word_mode, reg, reg), SET);
-
-  shift_insn = emit_insn (gen_rtx_SET (VOIDmode, reg,
-                                      gen_rtx_ASHIFT (word_mode, reg,
-                                                      const0_rtx)));
-
-  shiftadd_insn
-    = emit_insn (gen_rtx_SET (VOIDmode, reg,
-                             gen_rtx_PLUS (word_mode,
-                                           gen_rtx_MULT (word_mode,
-                                                         reg, const0_rtx),
-                                           reg)));
-
-  shiftsub_insn
-    = emit_insn (gen_rtx_SET (VOIDmode, reg,
-                             gen_rtx_MINUS (word_mode,
-                                            gen_rtx_MULT (word_mode,
-                                                          reg, const0_rtx),
-                                            reg)));
 
   init_recog ();
 
-  shift_cost[0] = 0;
-  shiftadd_cost[0] = shiftsub_cost[0] = add_cost;
-
   for (m = 1; m < MAX_BITS_PER_WORD; m++)
     {
-      rtx c_int = GEN_INT ((HOST_WIDE_INT) 1 << m);
-      shift_cost[m] = shiftadd_cost[m] = shiftsub_cost[m] = 32000;
-
-      XEXP (SET_SRC (PATTERN (shift_insn)), 1) = GEN_INT (m);
-      if (recog (PATTERN (shift_insn), shift_insn, &dummy) >= 0)
-       shift_cost[m] = rtx_cost (SET_SRC (PATTERN (shift_insn)), SET);
-
-      XEXP (XEXP (SET_SRC (PATTERN (shiftadd_insn)), 0), 1) = c_int;
-      if (recog (PATTERN (shiftadd_insn), shiftadd_insn, &dummy) >= 0)
-       shiftadd_cost[m] = rtx_cost (SET_SRC (PATTERN (shiftadd_insn)), SET);
-
-      XEXP (XEXP (SET_SRC (PATTERN (shiftsub_insn)), 0), 1) = c_int;
-      if (recog (PATTERN (shiftsub_insn), shiftsub_insn, &dummy) >= 0)
-       shiftsub_cost[m] = rtx_cost (SET_SRC (PATTERN (shiftsub_insn)), SET);
+      pow2[m] = GEN_INT ((HOST_WIDE_INT) 1 << m);
+      cint[m] = GEN_INT (m);
     }
 
-  negate_cost = rtx_cost (gen_rtx_NEG (word_mode, reg), SET);
-
-  sdiv_pow2_cheap
-    = (rtx_cost (gen_rtx_DIV (word_mode, reg, GEN_INT (32)), SET)
-       <= 2 * add_cost);
-  smod_pow2_cheap
-    = (rtx_cost (gen_rtx_MOD (word_mode, reg, GEN_INT (32)), SET)
-       <= 2 * add_cost);
-
   for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
        mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
     {
       reg = gen_rtx_REG (mode, 10000);
-      div_cost[(int) mode] = rtx_cost (gen_rtx_UDIV (mode, reg, reg), SET);
-      mul_cost[(int) mode] = rtx_cost (gen_rtx_MULT (mode, reg, reg), SET);
+      add_cost[mode] = rtx_cost (gen_rtx_PLUS (mode, reg, reg), SET);
+      neg_cost[mode] = rtx_cost (gen_rtx_NEG (mode, reg), SET);
+      div_cost[mode] = rtx_cost (gen_rtx_UDIV (mode, reg, reg), SET);
+      mul_cost[mode] = rtx_cost (gen_rtx_MULT (mode, reg, reg), SET);
+
+      sdiv_pow2_cheap[mode]
+       = (rtx_cost (gen_rtx_DIV (mode, reg, GEN_INT (32)), SET)
+          <= 2 * add_cost[mode]);
+      smod_pow2_cheap[mode]
+       = (rtx_cost (gen_rtx_MOD (mode, reg, GEN_INT (32)), SET)
+          <= 2 * add_cost[mode]);
+
       wider_mode = GET_MODE_WIDER_MODE (mode);
       if (wider_mode != VOIDmode)
        {
-         mul_widen_cost[(int) wider_mode]
+         mul_widen_cost[wider_mode]
            = rtx_cost (gen_rtx_MULT (wider_mode,
                                      gen_rtx_ZERO_EXTEND (wider_mode, reg),
                                      gen_rtx_ZERO_EXTEND (wider_mode, reg)),
                        SET);
-         mul_highpart_cost[(int) mode]
+         mul_highpart_cost[mode]
            = rtx_cost (gen_rtx_TRUNCATE
                        (mode,
                         gen_rtx_LSHIFTRT (wider_mode,
@@ -193,6 +162,52 @@ init_expmed (void)
                                           GEN_INT (GET_MODE_BITSIZE (mode)))),
                        SET);
        }
+
+       shift_insn = emit_insn (gen_rtx_SET (VOIDmode, reg,
+                                            gen_rtx_ASHIFT (mode, reg,
+                                                            const0_rtx)));
+
+       shiftadd_insn
+         = emit_insn (gen_rtx_SET (VOIDmode, reg,
+                                   gen_rtx_PLUS (mode,
+                                                 gen_rtx_MULT (mode,
+                                                               reg,
+                                                               const0_rtx),
+                                                 reg)));
+
+       shiftsub_insn
+         = emit_insn (gen_rtx_SET (VOIDmode, reg,
+                                   gen_rtx_MINUS (mode,
+                                                  gen_rtx_MULT (mode,
+                                                                reg,
+                                                                const0_rtx),
+                                                  reg)));
+
+       shift_pat = PATTERN (shift_insn);
+       shiftadd_pat = PATTERN (shiftadd_insn);
+       shiftsub_pat = PATTERN (shiftsub_insn);
+
+       shift_cost[mode][0] = 0;
+       shiftadd_cost[mode][0] = shiftsub_cost[mode][0] = add_cost[mode];
+
+       n = MIN (MAX_BITS_PER_WORD, GET_MODE_BITSIZE (mode));
+       for (m = 1; m < n; m++)
+         {
+           shift_cost[mode][m] = 32000;
+           XEXP (SET_SRC (shift_pat), 1) = cint[m];
+           if (recog (shift_pat, shift_insn, &dummy) >= 0)
+             shift_cost[mode][m] = rtx_cost (SET_SRC (shift_pat), SET);
+
+           shiftadd_cost[mode][m] = 32000;
+           XEXP (XEXP (SET_SRC (shiftadd_pat), 0), 1) = pow2[m];
+           if (recog (shiftadd_pat, shiftadd_insn, &dummy) >= 0)
+             shiftadd_cost[mode][m] = rtx_cost (SET_SRC (shiftadd_pat), SET);
+
+           shiftsub_cost[mode][m] = 32000;
+           XEXP (XEXP (SET_SRC (shiftsub_pat), 0), 1) = pow2[m];
+           if (recog (shiftsub_pat, shiftsub_insn, &dummy) >= 0)
+             shiftsub_cost[mode][m] = rtx_cost (SET_SRC (shiftsub_pat), SET);
+         }
     }
 
   end_sequence ();
@@ -317,7 +332,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
      available.  */
   if (VECTOR_MODE_P (GET_MODE (op0))
       && GET_CODE (op0) != MEM
-      && (vec_set_optab->handlers[(int)GET_MODE (op0)].insn_code
+      && (vec_set_optab->handlers[GET_MODE (op0)].insn_code
          != CODE_FOR_nothing)
       && fieldmode == GET_MODE_INNER (GET_MODE (op0))
       && bitsize == GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))
@@ -325,7 +340,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     {
       enum machine_mode outermode = GET_MODE (op0);
       enum machine_mode innermode = GET_MODE_INNER (outermode);
-      int icode = (int) vec_set_optab->handlers[(int) outermode].insn_code;
+      int icode = (int) vec_set_optab->handlers[outermode].insn_code;
       int pos = bitnum / GET_MODE_BITSIZE (innermode);
       rtx rtxpos = GEN_INT (pos);
       rtx src = value;
@@ -402,7 +417,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
                   subregs results in Severe Tire Damage.  */
                abort ();
            }
-         if (GET_CODE (op0) == REG)
+         if (REG_P (op0))
            op0 = gen_rtx_SUBREG (fieldmode, op0, byte_offset);
          else
            op0 = adjust_address (op0, fieldmode, offset);
@@ -451,13 +466,13 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   if (GET_CODE (op0) != MEM
       && (BYTES_BIG_ENDIAN ? bitpos + bitsize == unit : bitpos == 0)
       && bitsize == GET_MODE_BITSIZE (fieldmode)
-      && (movstrict_optab->handlers[(int) fieldmode].insn_code
+      && (movstrict_optab->handlers[fieldmode].insn_code
          != CODE_FOR_nothing))
     {
-      int icode = movstrict_optab->handlers[(int) fieldmode].insn_code;
+      int icode = movstrict_optab->handlers[fieldmode].insn_code;
 
       /* Get appropriate low part of the value being stored.  */
-      if (GET_CODE (value) == CONST_INT || GET_CODE (value) == REG)
+      if (GET_CODE (value) == CONST_INT || REG_P (value))
        value = gen_lowpart (fieldmode, value);
       else if (!(GET_CODE (value) == SYMBOL_REF
                 || GET_CODE (value) == LABEL_REF
@@ -543,7 +558,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       if (offset != 0
          || GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)
        {
-         if (GET_CODE (op0) != REG)
+         if (!REG_P (op0))
            {
              /* Since this is a destination (lvalue), we can't copy it to a
                 pseudo.  We can trivially remove a SUBREG that does not
@@ -582,7 +597,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       && !(bitsize == 1 && GET_CODE (value) == CONST_INT)
       /* Ensure insv's size is wide enough for this field.  */
       && (GET_MODE_BITSIZE (op_mode) >= bitsize)
-      && ! ((GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
+      && ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
            && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode))))
     {
       int xbitpos = bitpos;
@@ -651,7 +666,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
        /* 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_BYTE (xop0));
-      if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
+      if (REG_P (xop0) && GET_MODE (xop0) != maxmode)
        xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
 
       /* On big-endian machines, we count bits from the most significant.
@@ -753,7 +768,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
      and a field split across two bytes.
      Such cases are not supposed to be able to occur.  */
 
-  if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
+  if (REG_P (op0) || GET_CODE (op0) == SUBREG)
     {
       if (offset != 0)
        abort ();
@@ -851,7 +866,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
 
       if (GET_MODE (value) != mode)
        {
-         if ((GET_CODE (value) == REG || GET_CODE (value) == SUBREG)
+         if ((REG_P (value) || GET_CODE (value) == SUBREG)
              && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (value)))
            value = gen_lowpart (mode, value);
          else
@@ -870,7 +885,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
   /* Now clear the chosen bits in OP0,
      except that if VALUE is -1 we need not bother.  */
 
-  subtarget = (GET_CODE (op0) == REG || ! flag_force_mem) ? op0 : 0;
+  subtarget = (REG_P (op0) || ! flag_force_mem) ? op0 : 0;
 
   if (! all_one)
     {
@@ -909,7 +924,7 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
 
   /* Make sure UNIT isn't larger than BITS_PER_WORD, we can only handle that
      much at a time.  */
-  if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
+  if (REG_P (op0) || GET_CODE (op0) == SUBREG)
     unit = BITS_PER_WORD;
   else
     unit = MIN (MEM_ALIGN (op0), BITS_PER_WORD);
@@ -998,7 +1013,7 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
                                        GET_MODE (SUBREG_REG (op0)));
          offset = 0;
        }
-      else if (GET_CODE (op0) == REG)
+      else if (REG_P (op0))
        {
          word = operand_subword_force (op0, offset, GET_MODE (op0));
          offset = 0;
@@ -1073,7 +1088,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       op0 = SUBREG_REG (op0);
     }
 
-  if (GET_CODE (op0) == REG
+  if (REG_P (op0)
       && mode == GET_MODE (op0)
       && bitnum == 0
       && bitsize == GET_MODE_BITSIZE (GET_MODE (op0)))
@@ -1086,14 +1101,14 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
      available.  */
   if (VECTOR_MODE_P (GET_MODE (op0))
       && GET_CODE (op0) != MEM
-      && (vec_extract_optab->handlers[(int)GET_MODE (op0)].insn_code
+      && (vec_extract_optab->handlers[GET_MODE (op0)].insn_code
          != CODE_FOR_nothing)
       && ((bitsize + bitnum) / GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))
          == bitsize / GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))))
     {
       enum machine_mode outermode = GET_MODE (op0);
       enum machine_mode innermode = GET_MODE_INNER (outermode);
-      int icode = (int) vec_extract_optab->handlers[(int) outermode].insn_code;
+      int icode = (int) vec_extract_optab->handlers[outermode].insn_code;
       int pos = bitnum / GET_MODE_BITSIZE (innermode);
       rtx rtxpos = GEN_INT (pos);
       rtx src = op0;
@@ -1125,6 +1140,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
          || ! (*insn_data[icode].operand[1].predicate) (src, mode1)
          || ! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2))
        abort ();
+
       pat = GEN_FCN (icode) (dest, src, rtxpos);
       seq = get_insns ();
       end_sequence ();
@@ -1132,9 +1148,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
        {
          emit_insn (seq);
          emit_insn (pat);
-         return extract_bit_field (dest, bitsize,
-                                   bitnum - pos * GET_MODE_BITSIZE (innermode),
-                                   unsignedp, target, mode, tmode, total_size);
+         return dest;
        }
     }
 
@@ -1225,7 +1239,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
                   subregs results in Severe Tire Damage.  */
                goto no_subreg_mode_swap;
            }
-         if (GET_CODE (op0) == REG)
+         if (REG_P (op0))
            op0 = gen_rtx_SUBREG (mode1, op0, byte_offset);
          else
            op0 = adjust_address (op0, mode1, offset);
@@ -1248,7 +1262,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
       unsigned int i;
 
-      if (target == 0 || GET_CODE (target) != REG)
+      if (target == 0 || !REG_P (target))
        target = gen_reg_rtx (mode);
 
       /* Indicate for flow that the entire target reg is being set.  */
@@ -1332,7 +1346,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       if (offset != 0
          || GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)
        {
-         if (GET_CODE (op0) != REG)
+         if (!REG_P (op0))
            op0 = copy_to_reg (op0);
          op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
                                op0, (offset * UNITS_PER_WORD));
@@ -1348,7 +1362,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     {
       if (HAVE_extzv
          && (GET_MODE_BITSIZE (extzv_mode) >= bitsize)
-         && ! ((GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
+         && ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
                && (bitsize + bitpos > GET_MODE_BITSIZE (extzv_mode))))
        {
          unsigned HOST_WIDE_INT xbitpos = bitpos, xoffset = offset;
@@ -1416,7 +1430,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
             SImode). to make it acceptable to the format of extzv.  */
          if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != maxmode)
            goto extzv_loses;
-         if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
+         if (REG_P (xop0) && GET_MODE (xop0) != maxmode)
            xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
 
          /* On big-endian machines, we count bits from the most significant.
@@ -1436,7 +1450,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
          if (GET_MODE (xtarget) != maxmode)
            {
-             if (GET_CODE (xtarget) == REG)
+             if (REG_P (xtarget))
                {
                  int wider = (GET_MODE_SIZE (maxmode)
                               > GET_MODE_SIZE (GET_MODE (xtarget)));
@@ -1482,7 +1496,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     {
       if (HAVE_extv
          && (GET_MODE_BITSIZE (extv_mode) >= bitsize)
-         && ! ((GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
+         && ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
                && (bitsize + bitpos > GET_MODE_BITSIZE (extv_mode))))
        {
          int xbitpos = bitpos, xoffset = offset;
@@ -1544,7 +1558,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
             SImode) to make it acceptable to the format of extv.  */
          if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != maxmode)
            goto extv_loses;
-         if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
+         if (REG_P (xop0) && GET_MODE (xop0) != maxmode)
            xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
 
          /* On big-endian machines, we count bits from the most significant.
@@ -1565,7 +1579,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
          if (GET_MODE (xtarget) != maxmode)
            {
-             if (GET_CODE (xtarget) == REG)
+             if (REG_P (xtarget))
                {
                  int wider = (GET_MODE_SIZE (maxmode)
                               > GET_MODE_SIZE (GET_MODE (xtarget)));
@@ -1656,7 +1670,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
   unsigned int total_bits = BITS_PER_WORD;
   enum machine_mode mode;
 
-  if (GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG)
+  if (GET_CODE (op0) == SUBREG || REG_P (op0))
     {
       /* Special treatment for a bit field split across two registers.  */
       if (bitsize + bitpos > BITS_PER_WORD)
@@ -1718,9 +1732,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
          tree amount = build_int_2 (bitpos, 0);
          /* Maybe propagate the target for the shift.  */
          /* But not if we will return it--could confuse integrate.c.  */
-         rtx subtarget = (target != 0 && GET_CODE (target) == REG
-                          && !REG_FUNCTION_VALUE_P (target)
-                          ? target : 0);
+         rtx subtarget = (target != 0 && REG_P (target) ? target : 0);
          if (tmode != mode) subtarget = 0;
          op0 = expand_shift (RSHIFT_EXPR, mode, op0, amount, subtarget, 1);
        }
@@ -1759,10 +1771,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
       tree amount
        = build_int_2 (GET_MODE_BITSIZE (mode) - (bitsize + bitpos), 0);
       /* Maybe propagate the target for the shift.  */
-      /* But not if we will return the result--could confuse integrate.c.  */
-      rtx subtarget = (target != 0 && GET_CODE (target) == REG
-                      && ! REG_FUNCTION_VALUE_P (target)
-                      ? target : 0);
+      rtx subtarget = (target != 0 && REG_P (target) ? target : 0);
       op0 = expand_shift (LSHIFT_EXPR, mode, op0, amount, subtarget, 1);
     }
 
@@ -1859,7 +1868,7 @@ extract_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
 
   /* Make sure UNIT isn't larger than BITS_PER_WORD, we can only handle that
      much at a time.  */
-  if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG)
+  if (REG_P (op0) || GET_CODE (op0) == SUBREG)
     unit = BITS_PER_WORD;
   else
     unit = MIN (MEM_ALIGN (op0), BITS_PER_WORD);
@@ -1893,7 +1902,7 @@ extract_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
                                        GET_MODE (SUBREG_REG (op0)));
          offset = 0;
        }
-      else if (GET_CODE (op0) == REG)
+      else if (REG_P (op0))
        {
          word = operand_subword_force (op0, offset, GET_MODE (op0));
          offset = 0;
@@ -2155,9 +2164,10 @@ struct algorithm
    multiplicand should be added to the result.  */
 enum mult_variant {basic_variant, negate_variant, add_variant};
 
-static void synth_mult (struct algorithm *, unsigned HOST_WIDE_INT, int);
+static void synth_mult (struct algorithm *, unsigned HOST_WIDE_INT,
+                       int, enum machine_mode mode);
 static bool choose_mult_variant (enum machine_mode, HOST_WIDE_INT,
-                                struct algorithm *, enum mult_variant *);
+                                struct algorithm *, enum mult_variant *, int);
 static rtx expand_mult_const (enum machine_mode, rtx, HOST_WIDE_INT, rtx,
                              const struct algorithm *, enum mult_variant);
 static unsigned HOST_WIDE_INT choose_multiplier (unsigned HOST_WIDE_INT, int,
@@ -2170,16 +2180,18 @@ static rtx expand_mult_highpart_optab (enum machine_mode, rtx, rtx, rtx,
 /* Compute and return the best algorithm for multiplying by T.
    The algorithm must cost less than cost_limit
    If retval.cost >= COST_LIMIT, no algorithm was found and all
-   other field of the returned struct are undefined.  */
+   other field of the returned struct are undefined.
+   MODE is the machine mode of the multiplication.  */
 
 static void
 synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
-           int cost_limit)
+           int cost_limit, enum machine_mode mode)
 {
   int m;
   struct algorithm *alg_in, *best_alg;
   int cost;
   unsigned HOST_WIDE_INT q;
+  int maxm = MIN (BITS_PER_WORD, GET_MODE_BITSIZE (mode));
 
   /* Indicate that no algorithm is yet found.  If no algorithm
      is found, this value will be returned and indicate failure.  */
@@ -2188,6 +2200,9 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
   if (cost_limit <= 0)
     return;
 
+  /* Restrict the bits of "t" to the multiplication's mode.  */
+  t &= GET_MODE_MASK (mode);
+
   /* t == 1 can be done in zero cost.  */
   if (t == 1)
     {
@@ -2223,11 +2238,11 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
   if ((t & 1) == 0)
     {
       m = floor_log2 (t & -t); /* m = number of low zero bits */
-      if (m < BITS_PER_WORD)
+      if (m < maxm)
        {
          q = t >> m;
-         cost = shift_cost[m];
-         synth_mult (alg_in, q, cost_limit - cost);
+         cost = shift_cost[mode][m];
+         synth_mult (alg_in, q, cost_limit - cost, mode);
 
          cost += alg_in->cost;
          if (cost < cost_limit)
@@ -2261,8 +2276,8 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
        {
          /* T ends with ...111.  Multiply by (T + 1) and subtract 1.  */
 
-         cost = add_cost;
-         synth_mult (alg_in, t + 1, cost_limit - cost);
+         cost = add_cost[mode];
+         synth_mult (alg_in, t + 1, cost_limit - cost, mode);
 
          cost += alg_in->cost;
          if (cost < cost_limit)
@@ -2278,8 +2293,8 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
        {
          /* T ends with ...01 or ...011.  Multiply by (T - 1) and add 1.  */
 
-         cost = add_cost;
-         synth_mult (alg_in, t - 1, cost_limit - cost);
+         cost = add_cost[mode];
+         synth_mult (alg_in, t - 1, cost_limit - cost, mode);
 
          cost += alg_in->cost;
          if (cost < cost_limit)
@@ -2308,10 +2323,12 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
       unsigned HOST_WIDE_INT d;
 
       d = ((unsigned HOST_WIDE_INT) 1 << m) + 1;
-      if (t % d == 0 && t > d && m < BITS_PER_WORD)
+      if (t % d == 0 && t > d && m < maxm)
        {
-         cost = MIN (shiftadd_cost[m], add_cost + shift_cost[m]);
-         synth_mult (alg_in, t / d, cost_limit - cost);
+         cost = add_cost[mode] + shift_cost[mode][m];
+         if (shiftadd_cost[mode][m] < cost)
+           cost = shiftadd_cost[mode][m];
+         synth_mult (alg_in, t / d, cost_limit - cost, mode);
 
          cost += alg_in->cost;
          if (cost < cost_limit)
@@ -2327,10 +2344,12 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
        }
 
       d = ((unsigned HOST_WIDE_INT) 1 << m) - 1;
-      if (t % d == 0 && t > d && m < BITS_PER_WORD)
+      if (t % d == 0 && t > d && m < maxm)
        {
-         cost = MIN (shiftsub_cost[m], add_cost + shift_cost[m]);
-         synth_mult (alg_in, t / d, cost_limit - cost);
+         cost = add_cost[mode] + shift_cost[mode][m];
+         if (shiftsub_cost[mode][m] < cost)
+           cost = shiftsub_cost[mode][m];
+         synth_mult (alg_in, t / d, cost_limit - cost, mode);
 
          cost += alg_in->cost;
          if (cost < cost_limit)
@@ -2352,10 +2371,10 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
       q = t - 1;
       q = q & -q;
       m = exact_log2 (q);
-      if (m >= 0 && m < BITS_PER_WORD)
+      if (m >= 0 && m < maxm)
        {
-         cost = shiftadd_cost[m];
-         synth_mult (alg_in, (t - 1) >> m, cost_limit - cost);
+         cost = shiftadd_cost[mode][m];
+         synth_mult (alg_in, (t - 1) >> m, cost_limit - cost, mode);
 
          cost += alg_in->cost;
          if (cost < cost_limit)
@@ -2371,10 +2390,10 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
       q = t + 1;
       q = q & -q;
       m = exact_log2 (q);
-      if (m >= 0 && m < BITS_PER_WORD)
+      if (m >= 0 && m < maxm)
        {
-         cost = shiftsub_cost[m];
-         synth_mult (alg_in, (t + 1) >> m, cost_limit - cost);
+         cost = shiftsub_cost[mode][m];
+         synth_mult (alg_in, (t + 1) >> m, cost_limit - cost, mode);
 
          cost += alg_in->cost;
          if (cost < cost_limit)
@@ -2409,45 +2428,41 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
          alg_out->ops * sizeof *alg_out->log);
 }
 \f
-/* Find the cheapeast way of multiplying a value of mode MODE by VAL.
+/* Find the cheapest way of multiplying a value of mode MODE by VAL.
    Try three variations:
 
        - a shift/add sequence based on VAL itself
        - a shift/add sequence based on -VAL, followed by a negation
        - a shift/add sequence based on VAL - 1, followed by an addition.
 
-   Return true if the cheapest of these is better than register
-   multiplication, describing the algorithm in *ALG and final
-   fixup in *VARIANT.  */
+   Return true if the cheapest of these cost less than MULT_COST,
+   describing the algorithm in *ALG and final fixup in *VARIANT.  */
 
 static bool
 choose_mult_variant (enum machine_mode mode, HOST_WIDE_INT val,
-                    struct algorithm *alg, enum mult_variant *variant)
+                    struct algorithm *alg, enum mult_variant *variant,
+                    int mult_cost)
 {
-  int mult_cost;
   struct algorithm alg2;
-  rtx reg;
-
-  reg = gen_rtx_REG (mode, FIRST_PSEUDO_REGISTER);
-  mult_cost = rtx_cost (gen_rtx_MULT (mode, reg, GEN_INT (val)), SET);
-  mult_cost = MIN (12 * add_cost, mult_cost);
 
   *variant = basic_variant;
-  synth_mult (alg, val, mult_cost);
+  synth_mult (alg, val, mult_cost, mode);
 
   /* This works only if the inverted value actually fits in an
      `unsigned int' */
   if (HOST_BITS_PER_INT >= GET_MODE_BITSIZE (mode))
     {
-      synth_mult (&alg2, -val, MIN (alg->cost, mult_cost) - negate_cost);
-      alg2.cost += negate_cost;
+      synth_mult (&alg2, -val, MIN (alg->cost, mult_cost) - neg_cost[mode],
+                 mode);
+      alg2.cost += neg_cost[mode];
       if (alg2.cost < alg->cost)
        *alg = alg2, *variant = negate_variant;
     }
 
   /* This proves very useful for division-by-constant.  */
-  synth_mult (&alg2, val - 1, MIN (alg->cost, mult_cost) - add_cost);
-  alg2.cost += add_cost;
+  synth_mult (&alg2, val - 1, MIN (alg->cost, mult_cost) - add_cost[mode],
+             mode);
+  alg2.cost += add_cost[mode];
   if (alg2.cost < alg->cost)
     *alg = alg2, *variant = add_variant;
 
@@ -2595,6 +2610,10 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
       accum = force_operand (gen_rtx_PLUS (mode, accum, op0), target);
     }
 
+  /* Compare only the bits of val and val_so_far that are significant
+     in the result mode, to avoid sign-/zero-extension confusion.  */
+  val &= GET_MODE_MASK (mode);
+  val_so_far &= GET_MODE_MASK (mode);
   if (val != val_so_far)
     abort ();
 
@@ -2642,10 +2661,15 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
      that it seems better to use synth_mult always.  */
 
   if (const_op1 && GET_CODE (const_op1) == CONST_INT
-      && (unsignedp || !flag_trapv)
-      && choose_mult_variant (mode, INTVAL (const_op1), &algorithm, &variant))
-    return expand_mult_const (mode, op0, INTVAL (const_op1), target,
-                             &algorithm, variant);
+      && (unsignedp || !flag_trapv))
+    {
+      int mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
+
+      if (choose_mult_variant (mode, INTVAL (const_op1), &algorithm, &variant,
+                              mult_cost))
+       return expand_mult_const (mode, op0, INTVAL (const_op1), target,
+                                 &algorithm, variant);
+    }
 
   if (GET_CODE (op0) == CONST_DOUBLE)
     {
@@ -2882,6 +2906,7 @@ static rtx
 expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
                            rtx target, int unsignedp, int max_cost)
 {
+  rtx narrow_op1 = gen_int_mode (INTVAL (op1), mode);
   enum machine_mode wider_mode;
   optab moptab;
   rtx tem;
@@ -2892,10 +2917,10 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
 
   /* Firstly, try using a multiplication insn that only generates the needed
      high part of the product, and in the sign flavor of unsignedp.  */
-  if (mul_highpart_cost[(int) mode] < max_cost)
+  if (mul_highpart_cost[mode] < max_cost)
     {
       moptab = unsignedp ? umul_highpart_optab : smul_highpart_optab;
-      tem = expand_binop (mode, moptab, op0, op1, target,
+      tem = expand_binop (mode, moptab, op0, narrow_op1, target,
                          unsignedp, OPTAB_DIRECT);
       if (tem)
        return tem;
@@ -2904,24 +2929,24 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
   /* Secondly, same as above, but use sign flavor opposite of unsignedp.
      Need to adjust the result after the multiplication.  */
   if (size - 1 < BITS_PER_WORD
-      && (mul_highpart_cost[(int) mode] + 2 * shift_cost[size-1] + 4 * add_cost
-         < max_cost))
+      && (mul_highpart_cost[mode] + 2 * shift_cost[mode][size-1]
+         + 4 * add_cost[mode] < max_cost))
     {
       moptab = unsignedp ? smul_highpart_optab : umul_highpart_optab;
-      tem = expand_binop (mode, moptab, op0, op1, target,
+      tem = expand_binop (mode, moptab, op0, narrow_op1, target,
                          unsignedp, OPTAB_DIRECT);
       if (tem)
        /* We used the wrong signedness.  Adjust the result.  */
-       return expand_mult_highpart_adjust (mode, tem, op0, op1,
+       return expand_mult_highpart_adjust (mode, tem, op0, narrow_op1,
                                            tem, unsignedp);
     }
 
   /* Try widening multiplication.  */
   moptab = unsignedp ? umul_widen_optab : smul_widen_optab;
-  if (moptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
-      && mul_widen_cost[(int) wider_mode] < max_cost)
+  if (moptab->handlers[wider_mode].insn_code != CODE_FOR_nothing
+      && mul_widen_cost[wider_mode] < max_cost)
     {
-      tem = expand_binop (wider_mode, moptab, op0, op1, 0,
+      tem = expand_binop (wider_mode, moptab, op0, narrow_op1, 0,
                          unsignedp, OPTAB_WIDEN);
       if (tem)
        return extract_high_half (mode, tem);
@@ -2929,9 +2954,9 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
 
   /* 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
+  if (smul_optab->handlers[wider_mode].insn_code != CODE_FOR_nothing
       && size - 1 < BITS_PER_WORD
-      && mul_cost[(int) wider_mode] + shift_cost[size-1] < max_cost)
+      && mul_cost[wider_mode] + shift_cost[mode][size-1] < max_cost)
     {
       tem = expand_binop (wider_mode, moptab, op0, op1, 0,
                          unsignedp, OPTAB_WIDEN);
@@ -2941,19 +2966,18 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
 
   /* 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
+  if (moptab->handlers[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))
+      && (mul_widen_cost[wider_mode] + 2 * shift_cost[mode][size-1]
+         + 4 * add_cost[mode] < max_cost))
     {
-      rtx regop1 = force_reg (mode, op1);
-      tem = expand_binop (wider_mode, moptab, op0, regop1,
+      tem = expand_binop (wider_mode, moptab, op0, narrow_op1,
                          NULL_RTX, ! unsignedp, OPTAB_WIDEN);
       if (tem != 0)
        {
          tem = extract_high_half (mode, tem);
          /* We used the wrong signedness.  Adjust the result.  */
-         return expand_mult_highpart_adjust (mode, tem, op0, op1,
+         return expand_mult_highpart_adjust (mode, tem, op0, narrow_op1,
                                              target, unsignedp);
        }
     }
@@ -2976,7 +3000,9 @@ expand_mult_highpart (enum machine_mode mode, rtx op0,
                      unsigned HOST_WIDE_INT cnst1, rtx target,
                      int unsignedp, int max_cost)
 {
-  enum machine_mode wider_mode;
+  enum machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
+  int extra_cost;
+  bool sign_adjust = false;
   enum mult_variant variant;
   struct algorithm alg;
   rtx op1, tem;
@@ -2985,23 +3011,46 @@ expand_mult_highpart (enum machine_mode mode, rtx op0,
   if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
     abort ();
 
-  op1 = gen_int_mode (cnst1, mode);
+  op1 = gen_int_mode (cnst1, wider_mode);
+  cnst1 &= GET_MODE_MASK (mode);
+
+  /* We can't optimize modes wider than BITS_PER_WORD. 
+     ??? We might be able to perform double-word arithmetic if 
+     mode == word_mode, however all the cost calculations in
+     synth_mult etc. assume single-word operations.  */
+  if (GET_MODE_BITSIZE (wider_mode) > BITS_PER_WORD)
+    return expand_mult_highpart_optab (mode, op0, op1, target,
+                                      unsignedp, max_cost);
+
+  extra_cost = shift_cost[mode][GET_MODE_BITSIZE (mode) - 1];
+
+  /* Check whether we try to multiply by a negative constant.  */
+  if (!unsignedp && ((cnst1 >> (GET_MODE_BITSIZE (mode) - 1)) & 1))
+    {
+      sign_adjust = true;
+      extra_cost += add_cost[mode];
+    }
 
   /* See whether shift/add multiplication is cheap enough.  */
-  if (choose_mult_variant (mode, cnst1, &alg, &variant)
-      && (alg.cost += shift_cost[GET_MODE_BITSIZE (mode) - 1]) < max_cost)
+  if (choose_mult_variant (wider_mode, cnst1, &alg, &variant,
+                          max_cost - extra_cost))
     {
       /* See whether the specialized multiplication optabs are
         cheaper than the shift/add version.  */
       tem = expand_mult_highpart_optab (mode, op0, op1, target,
-                                       unsignedp, alg.cost);
+                                       unsignedp, alg.cost + extra_cost);
       if (tem)
        return tem;
 
-      wider_mode = GET_MODE_WIDER_MODE (mode);
-      op0 = convert_to_mode (wider_mode, op0, unsignedp);
-      tem = expand_mult_const (wider_mode, op0, cnst1, 0, &alg, variant);
-      return extract_high_half (mode, tem);
+      tem = convert_to_mode (wider_mode, op0, unsignedp);
+      tem = expand_mult_const (wider_mode, tem, cnst1, 0, &alg, variant);
+      tem = extract_high_half (mode, tem);
+
+      /* Adjust result for signedness.  */
+      if (sign_adjust)
+       tem = force_operand (gen_rtx_MINUS (mode, tem, op0), tem);
+
+      return tem;
     }
   return expand_mult_highpart_optab (mode, op0, op1, target,
                                     unsignedp, max_cost);
@@ -3160,15 +3209,15 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 
   for (compute_mode = mode; compute_mode != VOIDmode;
        compute_mode = GET_MODE_WIDER_MODE (compute_mode))
-    if (optab1->handlers[(int) compute_mode].insn_code != CODE_FOR_nothing
-       || optab2->handlers[(int) compute_mode].insn_code != CODE_FOR_nothing)
+    if (optab1->handlers[compute_mode].insn_code != CODE_FOR_nothing
+       || optab2->handlers[compute_mode].insn_code != CODE_FOR_nothing)
       break;
 
   if (compute_mode == VOIDmode)
     for (compute_mode = mode; compute_mode != VOIDmode;
         compute_mode = GET_MODE_WIDER_MODE (compute_mode))
-      if (optab1->handlers[(int) compute_mode].libfunc
-         || optab2->handlers[(int) compute_mode].libfunc)
+      if (optab1->handlers[compute_mode].libfunc
+         || optab2->handlers[compute_mode].libfunc)
        break;
 
   /* If we still couldn't find a mode, use MODE, but we'll probably abort
@@ -3192,10 +3241,11 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
   /* Only deduct something for a REM if the last divide done was
      for a different constant.   Then set the constant of the last
      divide.  */
-  max_cost = div_cost[(int) compute_mode]
+  max_cost = div_cost[compute_mode]
     - (rem_flag && ! (last_div_const != 0 && op1_is_constant
                      && INTVAL (op1) == last_div_const)
-       ? mul_cost[(int) compute_mode] + add_cost : 0);
+       ? mul_cost[compute_mode] + add_cost[compute_mode]
+       : 0);
 
   last_div_const = ! rem_flag && op1_is_constant ? INTVAL (op1) : 0;
 
@@ -3312,8 +3362,10 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                            if (post_shift - 1 >= BITS_PER_WORD)
                              goto fail1;
 
-                           extra_cost = (shift_cost[post_shift - 1]
-                                         + shift_cost[1] + 2 * add_cost);
+                           extra_cost
+                             = (shift_cost[compute_mode][post_shift - 1]
+                                + shift_cost[compute_mode][1]
+                                + 2 * add_cost[compute_mode]);
                            t1 = expand_mult_highpart (compute_mode, op0, ml,
                                                       NULL_RTX, 1,
                                                       max_cost - extra_cost);
@@ -3343,8 +3395,9 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                            t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
                                               build_int_2 (pre_shift, 0),
                                               NULL_RTX, 1);
-                           extra_cost = (shift_cost[pre_shift]
-                                         + shift_cost[post_shift]);
+                           extra_cost
+                             = (shift_cost[compute_mode][pre_shift]
+                                + shift_cost[compute_mode][post_shift]);
                            t2 = expand_mult_highpart (compute_mode, t1, ml,
                                                       NULL_RTX, 1,
                                                       max_cost - extra_cost);
@@ -3396,15 +3449,16 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                      goto fail1;
                  }
                else if (EXACT_POWER_OF_2_OR_ZERO_P (d)
-                        && (rem_flag ? smod_pow2_cheap : sdiv_pow2_cheap)
+                        && (rem_flag ? smod_pow2_cheap[compute_mode]
+                                     : sdiv_pow2_cheap[compute_mode])
                         /* ??? The cheap metric is computed only for
                            word_mode.  If this operation is wider, this may
                            not be so.  Assume true if the optab has an
                            expander for this mode.  */
                         && (((rem_flag ? smod_optab : sdiv_optab)
-                             ->handlers[(int) compute_mode].insn_code
+                             ->handlers[compute_mode].insn_code
                              != CODE_FOR_nothing)
-                            || (sdivmod_optab->handlers[(int) compute_mode]
+                            || (sdivmod_optab->handlers[compute_mode]
                                 .insn_code != CODE_FOR_nothing)))
                  ;
                else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d))
@@ -3477,8 +3531,9 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                            || size - 1 >= BITS_PER_WORD)
                          goto fail1;
 
-                       extra_cost = (shift_cost[post_shift]
-                                     + shift_cost[size - 1] + add_cost);
+                       extra_cost = (shift_cost[compute_mode][post_shift]
+                                     + shift_cost[compute_mode][size - 1]
+                                     + add_cost[compute_mode]);
                        t1 = expand_mult_highpart (compute_mode, op0, ml,
                                                   NULL_RTX, 0,
                                                   max_cost - extra_cost);
@@ -3508,8 +3563,9 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                          goto fail1;
 
                        ml |= (~(unsigned HOST_WIDE_INT) 0) << (size - 1);
-                       extra_cost = (shift_cost[post_shift]
-                                     + shift_cost[size - 1] + 2 * add_cost);
+                       extra_cost = (shift_cost[compute_mode][post_shift]
+                                     + shift_cost[compute_mode][size - 1]
+                                     + 2 * add_cost[compute_mode]);
                        t1 = expand_mult_highpart (compute_mode, op0, ml,
                                                   NULL_RTX, 0,
                                                   max_cost - extra_cost);
@@ -3598,8 +3654,9 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                                           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);
+                       extra_cost = (shift_cost[compute_mode][post_shift]
+                                     + shift_cost[compute_mode][size - 1]
+                                     + 2 * add_cost[compute_mode]);
                        t3 = expand_mult_highpart (compute_mode, t2, ml,
                                                   NULL_RTX, 1,
                                                   max_cost - extra_cost);
@@ -3655,13 +3712,13 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
        if (rem_flag)
          {
            remainder
-             = GET_CODE (target) == REG ? target : gen_reg_rtx (compute_mode);
+             = REG_P (target) ? target : gen_reg_rtx (compute_mode);
            quotient = gen_reg_rtx (compute_mode);
          }
        else
          {
            quotient
-             = GET_CODE (target) == REG ? target : gen_reg_rtx (compute_mode);
+             = REG_P (target) ? target : gen_reg_rtx (compute_mode);
            remainder = gen_reg_rtx (compute_mode);
          }
 
@@ -3771,13 +3828,13 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 
            if (rem_flag)
              {
-               remainder = (GET_CODE (target) == REG
+               remainder = (REG_P (target)
                             ? target : gen_reg_rtx (compute_mode));
                quotient = gen_reg_rtx (compute_mode);
              }
            else
              {
-               quotient = (GET_CODE (target) == REG
+               quotient = (REG_P (target)
                            ? target : gen_reg_rtx (compute_mode));
                remainder = gen_reg_rtx (compute_mode);
              }
@@ -3868,13 +3925,13 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
              target = gen_reg_rtx (compute_mode);
            if (rem_flag)
              {
-               remainder= (GET_CODE (target) == REG
+               remainder= (REG_P (target)
                            ? target : gen_reg_rtx (compute_mode));
                quotient = gen_reg_rtx (compute_mode);
              }
            else
              {
-               quotient = (GET_CODE (target) == REG
+               quotient = (REG_P (target)
                            ? target : gen_reg_rtx (compute_mode));
                remainder = gen_reg_rtx (compute_mode);
              }
@@ -4060,7 +4117,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
            = sign_expand_binop (compute_mode, umod_optab, smod_optab,
                                 op0, op1, target,
                                 unsignedp,
-                                ((optab2->handlers[(int) compute_mode].insn_code
+                                ((optab2->handlers[compute_mode].insn_code
                                   != CODE_FOR_nothing)
                                  ? OPTAB_DIRECT : OPTAB_WIDEN));
          if (remainder == 0)
@@ -4088,7 +4145,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
        = sign_expand_binop (compute_mode, udiv_optab, sdiv_optab,
                             op0, op1, rem_flag ? NULL_RTX : target,
                             unsignedp,
-                            ((optab2->handlers[(int) compute_mode].insn_code
+                            ((optab2->handlers[compute_mode].insn_code
                               != CODE_FOR_nothing)
                              ? OPTAB_DIRECT : OPTAB_WIDEN));
 
@@ -4151,8 +4208,9 @@ make_tree (tree type, rtx x)
     {
     case CONST_INT:
       t = build_int_2 (INTVAL (x),
-                      (TREE_UNSIGNED (type)
-                       && (GET_MODE_BITSIZE (TYPE_MODE (type)) < HOST_BITS_PER_WIDE_INT))
+                      (TYPE_UNSIGNED (type)
+                       && (GET_MODE_BITSIZE (TYPE_MODE (type))
+                           < HOST_BITS_PER_WIDE_INT))
                       || INTVAL (x) >= 0 ? 0 : -1);
       TREE_TYPE (t) = type;
       return t;
@@ -4523,11 +4581,28 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
 
       comparison
        = compare_from_rtx (op0, op1, code, unsignedp, mode, NULL_RTX);
-      if (GET_CODE (comparison) == CONST_INT)
-       return (comparison == const0_rtx ? const0_rtx
-               : normalizep == 1 ? const1_rtx
-               : normalizep == -1 ? constm1_rtx
-               : const_true_rtx);
+      if (CONSTANT_P (comparison))
+       {
+         if (GET_CODE (comparison) == CONST_INT)
+           {
+             if (comparison == const0_rtx)
+               return const0_rtx;
+           }
+#ifdef FLOAT_STORE_FLAG_VALUE
+         else if (GET_CODE (comparison) == CONST_DOUBLE)
+           {
+             if (comparison == CONST0_RTX (GET_MODE (comparison)))
+               return const0_rtx;
+           }
+#endif
+         else
+           abort ();
+         if (normalizep == 1)
+           return const1_rtx;
+         if (normalizep == -1)
+           return constm1_rtx;
+         return const_true_rtx;
+       }
 
       /* The code of COMPARISON may not match CODE if compare_from_rtx
         decided to swap its operands and reverse the original code.
@@ -4731,9 +4806,9 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
         that is compensated by the subsequent overflow when subtracting
         one / negating.  */
 
-      if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+      if (abs_optab->handlers[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)
+      else if (ffs_optab->handlers[mode].insn_code != CODE_FOR_nothing)
        tem = expand_unop (mode, ffs_optab, op0, subtarget, 1);
       else if (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
        {
@@ -4812,7 +4887,7 @@ emit_store_flag_force (rtx target, enum rtx_code code, rtx op0, rtx op1,
 
   /* If this failed, we have to do this with set/compare/jump/set code.  */
 
-  if (GET_CODE (target) != REG
+  if (!REG_P (target)
       || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
     target = gen_reg_rtx (GET_MODE (target));