OSDN Git Service

* config/sparc/sparc.md (save_register_windowdi): Add missing mode.
[pf3gnuchains/gcc-fork.git] / gcc / expmed.c
index 23ae551..231a33e 100644 (file)
@@ -54,6 +54,9 @@ static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
 static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 
+/* Test whether a value is zero of a power of two.  */
+#define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
+
 /* Nonzero means divides or modulus operations are relatively cheap for
    powers of two, so don't use branches; emit the operation instead.
    Usually, this will mean that the MD file will emit non-branch
@@ -431,21 +434,11 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     {
       if (GET_MODE (op0) != fieldmode)
        {
-         if (GET_CODE (op0) == SUBREG)
-           {
-             /* Else we've got some float mode source being extracted
-                into a different float mode destination -- this
-                combination of subregs results in Severe Tire
-                Damage.  */
-             gcc_assert (GET_MODE (SUBREG_REG (op0)) == fieldmode
-                         || GET_MODE_CLASS (fieldmode) == MODE_INT
-                         || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT);
-             op0 = SUBREG_REG (op0);
-           }
-         if (REG_P (op0))
-           op0 = gen_rtx_SUBREG (fieldmode, op0, byte_offset);
-         else
+         if (MEM_P (op0))
            op0 = adjust_address (op0, fieldmode, offset);
+         else
+           op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
+                                      byte_offset);
        }
       emit_move_insn (op0, value);
       return value;
@@ -598,16 +591,18 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       offset = 0;
     }
 
-  /* If VALUE is a floating-point mode, access it as an integer of the
-     corresponding size.  This can occur on a machine with 64 bit registers
-     that uses SFmode for float.  This can also occur for unaligned float
-     structure fields.  */
+  /* If VALUE has a floating-point or complex mode, access it as an
+     integer of the corresponding size.  This can occur on a machine
+     with 64 bit registers that uses SFmode for float.  It can also
+     occur for unaligned float or complex fields.  */
   orig_value = value;
-  if (GET_MODE_CLASS (GET_MODE (value)) != MODE_INT
+  if (GET_MODE (value) != VOIDmode
+      && GET_MODE_CLASS (GET_MODE (value)) != MODE_INT
       && GET_MODE_CLASS (GET_MODE (value)) != MODE_PARTIAL_INT)
-    value = gen_lowpart ((GET_MODE (value) == VOIDmode
-                         ? word_mode : int_mode_for_mode (GET_MODE (value))),
-                        value);
+    {
+      value = gen_reg_rtx (int_mode_for_mode (GET_MODE (value)));
+      emit_move_insn (gen_lowpart (GET_MODE (orig_value), value), orig_value);
+    }
 
   /* Now OFFSET is nonzero only if OP0 is memory
      and is therefore always measured in bytes.  */
@@ -1163,13 +1158,12 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     enum machine_mode imode = int_mode_for_mode (GET_MODE (op0));
     if (imode != GET_MODE (op0))
       {
-       if (MEM_P (op0))
-         op0 = adjust_address (op0, imode, 0);
-       else
-         {
-           gcc_assert (imode != BLKmode);
-           op0 = gen_lowpart (imode, op0);
-         }
+       op0 = gen_lowpart (imode, op0);
+
+       /* If we got a SUBREG, force it into a register since we aren't going
+          to be able to do another SUBREG on it.  */
+       if (GET_CODE (op0) == SUBREG)
+         op0 = force_reg (imode, op0);
       }
   }
 
@@ -1233,22 +1227,16 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     {
       if (mode1 != GET_MODE (op0))
        {
-         if (GET_CODE (op0) == SUBREG)
+         if (MEM_P (op0))
+           op0 = adjust_address (op0, mode1, offset);
+         else
            {
-             if (GET_MODE (SUBREG_REG (op0)) == mode1
-                 || GET_MODE_CLASS (mode1) == MODE_INT
-                 || GET_MODE_CLASS (mode1) == MODE_PARTIAL_INT)
-               op0 = SUBREG_REG (op0);
-             else
-               /* Else we've got some float mode source being extracted into
-                  a different float mode destination -- this combination of
-                  subregs results in Severe Tire Damage.  */
+             rtx sub = simplify_gen_subreg (mode1, op0, GET_MODE (op0),
+                                            byte_offset);
+             if (sub == NULL)
                goto no_subreg_mode_swap;
+             op0 = sub;
            }
-         if (REG_P (op0))
-           op0 = gen_rtx_SUBREG (mode1, op0, byte_offset);
-         else
-           op0 = adjust_address (op0, mode1, offset);
        }
       if (mode1 != mode)
        return convert_to_mode (tmode, op0, unsignedp);
@@ -1628,19 +1616,19 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     return spec_target;
   if (GET_MODE (target) != tmode && GET_MODE (target) != mode)
     {
-      /* If the target mode is floating-point, first convert to the
+      /* If the target mode is not a scalar integral, first convert to the
         integer mode of that size and then access it as a floating-point
         value via a SUBREG.  */
-      if (GET_MODE_CLASS (tmode) != MODE_INT
-         && GET_MODE_CLASS (tmode) != MODE_PARTIAL_INT)
+      if (!SCALAR_INT_MODE_P (tmode))
        {
-         target = convert_to_mode (mode_for_size (GET_MODE_BITSIZE (tmode),
-                                                  MODE_INT, 0),
-                                   target, unsignedp);
+         enum machine_mode smode
+           = mode_for_size (GET_MODE_BITSIZE (tmode), MODE_INT, 0);
+         target = convert_to_mode (smode, target, unsignedp);
+         target = force_reg (smode, target);
          return gen_lowpart (tmode, target);
        }
-      else
-       return convert_to_mode (tmode, target, unsignedp);
+
+      return convert_to_mode (tmode, target, unsignedp);
     }
   return target;
 }
@@ -2672,7 +2660,7 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
            op_latency = add_cost[mode];
 
          new_limit.cost = best_cost.cost - op_cost;
-         new_limit.cost = best_cost.cost - op_latency;
+         new_limit.latency = best_cost.latency - op_latency;
          synth_mult (alg_in, t / d, &new_limit, mode);
 
          alg_in->cost.cost += op_cost;
@@ -3041,11 +3029,25 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
   if (const_op1 && GET_CODE (const_op1) == CONST_INT
       && (unsignedp || !flag_trapv))
     {
-      int mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
+      HOST_WIDE_INT coeff = INTVAL (const_op1);
+      int mult_cost;
 
-      if (choose_mult_variant (mode, INTVAL (const_op1), &algorithm, &variant,
+      /* Special case powers of two.  */
+      if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
+       {
+         if (coeff == 0)
+           return const0_rtx;
+         if (coeff == 1)
+           return op0;
+         return expand_shift (LSHIFT_EXPR, mode, op0,
+                              build_int_cst (NULL_TREE, floor_log2 (coeff)),
+                              target, unsignedp);
+       }
+
+      mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
+      if (choose_mult_variant (mode, coeff, &algorithm, &variant,
                               mult_cost))
-       return expand_mult_const (mode, op0, INTVAL (const_op1), target,
+       return expand_mult_const (mode, op0, coeff, target,
                                  &algorithm, variant);
     }
 
@@ -3644,8 +3646,6 @@ expand_sdiv_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
    (x mod 12) == (((x & 1023) + ((x >> 8) & ~3)) * 0x15555558 >> 2 * 3) >> 28
    */
 
-#define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
-
 rtx
 expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
               rtx op0, rtx op1, rtx target, int unsignedp)