]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/expmed.c
Merge from trunk.
[thirdparty/gcc.git] / gcc / expmed.c
index c5123cbbe81c21136ddd38737dd3c659369d80c4..cca7a0df9fbf893069a7cc9f4c549bd4d9cf46e2 100644 (file)
@@ -56,7 +56,6 @@ static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
 static rtx extract_fixed_bit_field (enum machine_mode, rtx,
                                    unsigned HOST_WIDE_INT,
                                    unsigned HOST_WIDE_INT, rtx, int);
-static rtx mask_rtx (enum machine_mode, int, int, int);
 static rtx lshift_value (enum machine_mode, unsigned HOST_WIDE_INT, int);
 static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
                                    unsigned HOST_WIDE_INT, int);
@@ -64,6 +63,19 @@ 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);
 
+/* Return a constant integer mask value of mode MODE with BITSIZE ones
+   followed by BITPOS zeros, or the complement of that if COMPLEMENT.
+   The mask is truncated if necessary to the width of mode MODE.  The
+   mask is zero-extended if BITSIZE+BITPOS is too small for MODE.  */
+
+static inline rtx 
+mask_rtx (enum machine_mode mode, int bitpos, int bitsize, bool complement)
+{
+  return immed_wide_int_const 
+    (wi::shifted_mask (bitpos, bitsize, complement,
+                      GET_MODE_PRECISION (mode)), mode);
+}
+
 /* Test whether a value is zero of a power of two.  */
 #define EXACT_POWER_OF_2_OR_ZERO_P(x) \
   (((x) & ((x) - (unsigned HOST_WIDE_INT) 1)) == 0)
@@ -1817,26 +1829,6 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
   return expand_shift (RSHIFT_EXPR, mode, op0,
                       GET_MODE_BITSIZE (mode) - bitsize, target, 0);
 }
-\f
-/* Return a constant integer (CONST_INT or CONST_DOUBLE) mask value
-   of mode MODE with BITSIZE ones followed by BITPOS zeros, or the
-   complement of that if COMPLEMENT.  The mask is truncated if
-   necessary to the width of mode MODE.  The mask is zero-extended if
-   BITSIZE+BITPOS is too small for MODE.  */
-
-static rtx
-mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
-{
-  double_int mask;
-
-  mask = double_int::mask (bitsize);
-  mask = mask.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
-  if (complement)
-    mask = ~mask;
-
-  return immed_double_int_const (mask, mode);
-}
 
 /* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
    VALUE << BITPOS.  */
@@ -1845,12 +1837,7 @@ static rtx
 lshift_value (enum machine_mode mode, unsigned HOST_WIDE_INT value,
              int bitpos)
 {
-  double_int val;
-  
-  val = double_int::from_uhwi (value);
-  val = val.llshift (bitpos, HOST_BITS_PER_DOUBLE_INT);
-
-  return immed_double_int_const (val, mode);
+  return immed_wide_int_const (wi::lshift (value, bitpos), mode);
 }
 \f
 /* Extract a bit field that is split across two words
@@ -3078,38 +3065,22 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
         only if the constant value exactly fits in an `unsigned int' without
         any truncation.  This means that multiplying by negative values does
         not work; results are off by 2^32 on a 32 bit machine.  */
-
       if (CONST_INT_P (scalar_op1))
        {
          coeff = INTVAL (scalar_op1);
          is_neg = coeff < 0;
        }
+#if TARGET_SUPPORTS_WIDE_INT
+      else if (CONST_WIDE_INT_P (scalar_op1))
+#else
       else if (CONST_DOUBLE_AS_INT_P (scalar_op1))
+#endif
        {
-         /* If we are multiplying in DImode, it may still be a win
-            to try to work with shifts and adds.  */
-         if (CONST_DOUBLE_HIGH (scalar_op1) == 0
-             && (CONST_DOUBLE_LOW (scalar_op1) > 0
-                 || (CONST_DOUBLE_LOW (scalar_op1) < 0
-                     && EXACT_POWER_OF_2_OR_ZERO_P
-                          (CONST_DOUBLE_LOW (scalar_op1)))))
-           {
-             coeff = CONST_DOUBLE_LOW (scalar_op1);
-             is_neg = false;
-           }
-         else if (CONST_DOUBLE_LOW (scalar_op1) == 0)
-           {
-             coeff = CONST_DOUBLE_HIGH (scalar_op1);
-             if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
-               {
-                 int shift = floor_log2 (coeff) + HOST_BITS_PER_WIDE_INT;
-                 if (shift < HOST_BITS_PER_DOUBLE_INT - 1
-                     || mode_bitsize <= HOST_BITS_PER_DOUBLE_INT)
-                   return expand_shift (LSHIFT_EXPR, mode, op0,
-                                        shift, target, unsignedp);
-               }
-             goto skip_synth;
-           }
+         int shift = wi::exact_log2 (std::make_pair (scalar_op1, mode));
+         /* Perfect power of 2 (other than 1, which is handled above).  */
+         if (shift > 0)
+           return expand_shift (LSHIFT_EXPR, mode, op0,
+                                shift, target, unsignedp);
          else
            goto skip_synth;
        }
@@ -3286,7 +3257,6 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
                   unsigned HOST_WIDE_INT *multiplier_ptr,
                   int *post_shift_ptr, int *lgup_ptr)
 {
-  double_int mhigh, mlow;
   int lgup, post_shift;
   int pow, pow2;
 
@@ -3298,23 +3268,13 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
   pow = n + lgup;
   pow2 = n + lgup - precision;
 
-  /* We could handle this with some effort, but this case is much
-     better handled directly with a scc insn, so rely on caller using
-     that.  */
-  gcc_assert (pow != HOST_BITS_PER_DOUBLE_INT);
-
   /* mlow = 2^(N + lgup)/d */
-  double_int val = double_int_zero.set_bit (pow);
-  mlow = val.div (double_int::from_uhwi (d), true, TRUNC_DIV_EXPR); 
+  wide_int val = wi::set_bit_in_zero (pow, HOST_BITS_PER_DOUBLE_INT);
+  wide_int mlow = wi::udiv_trunc (val, d);
 
   /* mhigh = (2^(N + lgup) + 2^(N + lgup - precision))/d */
-  val |= double_int_zero.set_bit (pow2);
-  mhigh = val.div (double_int::from_uhwi (d), true, TRUNC_DIV_EXPR);
-
-  gcc_assert (!mhigh.high || val.high - d < d);
-  gcc_assert (mhigh.high <= 1 && mlow.high <= 1);
-  /* Assert that mlow < mhigh.  */
-  gcc_assert (mlow.ult (mhigh));
+  val |= wi::set_bit_in_zero (pow2, HOST_BITS_PER_DOUBLE_INT);
+  wide_int mhigh = wi::udiv_trunc (val, d);
 
   /* If precision == N, then mlow, mhigh exceed 2^N
      (but they do not exceed 2^(N+1)).  */
@@ -3322,14 +3282,15 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
   /* Reduce to lowest terms.  */
   for (post_shift = lgup; post_shift > 0; post_shift--)
     {
-      int shft = HOST_BITS_PER_WIDE_INT - 1;
-      unsigned HOST_WIDE_INT ml_lo = (mlow.high << shft) | (mlow.low >> 1);
-      unsigned HOST_WIDE_INT mh_lo = (mhigh.high << shft) | (mhigh.low >> 1);
+      unsigned HOST_WIDE_INT ml_lo = wi::extract_uhwi (mlow, 1,
+                                                      HOST_BITS_PER_WIDE_INT);
+      unsigned HOST_WIDE_INT mh_lo = wi::extract_uhwi (mhigh, 1,
+                                                      HOST_BITS_PER_WIDE_INT);
       if (ml_lo >= mh_lo)
        break;
 
-      mlow = double_int::from_uhwi (ml_lo);
-      mhigh = double_int::from_uhwi (mh_lo);
+      mlow = wi::uhwi (ml_lo, HOST_BITS_PER_DOUBLE_INT);
+      mhigh = wi::uhwi (mh_lo, HOST_BITS_PER_DOUBLE_INT);
     }
 
   *post_shift_ptr = post_shift;
@@ -3337,13 +3298,13 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
   if (n < HOST_BITS_PER_WIDE_INT)
     {
       unsigned HOST_WIDE_INT mask = ((unsigned HOST_WIDE_INT) 1 << n) - 1;
-      *multiplier_ptr = mhigh.low & mask;
-      return mhigh.low >= mask;
+      *multiplier_ptr = mhigh.to_uhwi () & mask;
+      return mhigh.to_uhwi () >= mask;
     }
   else
     {
-      *multiplier_ptr = mhigh.low;
-      return mhigh.high;
+      *multiplier_ptr = mhigh.to_uhwi ();
+      return wi::extract_uhwi (mhigh, HOST_BITS_PER_WIDE_INT, 1);
     }
 }
 
@@ -3610,9 +3571,9 @@ expmed_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
 static rtx
 expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 {
-  unsigned HOST_WIDE_INT masklow, maskhigh;
   rtx result, temp, shift, label;
   int logd;
+  int prec = GET_MODE_PRECISION (mode);
 
   logd = floor_log2 (d);
   result = gen_reg_rtx (mode);
@@ -3625,8 +3586,8 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
                                      mode, 0, -1);
       if (signmask)
        {
+         HOST_WIDE_INT masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
          signmask = force_reg (mode, signmask);
-         masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
          shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
 
          /* Use the rtx_cost of a LSHIFTRT instruction to determine
@@ -3673,19 +3634,11 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
      modulus.  By including the signbit in the operation, many targets
      can avoid an explicit compare operation in the following comparison
      against zero.  */
-
-  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
-  if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
-    {
-      masklow |= HOST_WIDE_INT_M1U << (GET_MODE_BITSIZE (mode) - 1);
-      maskhigh = -1;
-    }
-  else
-    maskhigh = HOST_WIDE_INT_M1U
-                << (GET_MODE_BITSIZE (mode) - HOST_BITS_PER_WIDE_INT - 1);
+  wide_int mask = wi::mask (logd, false, prec);
+  mask = wi::set_bit (mask, prec - 1);
 
   temp = expand_binop (mode, and_optab, op0,
-                      immed_double_const (masklow, maskhigh, mode),
+                      immed_wide_int_const (mask, mode),
                       result, 1, OPTAB_LIB_WIDEN);
   if (temp != result)
     emit_move_insn (result, temp);
@@ -3695,10 +3648,10 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 
   temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
                       0, OPTAB_LIB_WIDEN);
-  masklow = HOST_WIDE_INT_M1U << logd;
-  maskhigh = -1;
+
+  mask = wi::mask (logd, true, prec);
   temp = expand_binop (mode, ior_optab, temp,
-                      immed_double_const (masklow, maskhigh, mode),
+                      immed_wide_int_const (mask, mode),
                       result, 1, OPTAB_LIB_WIDEN);
   temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
                       0, OPTAB_LIB_WIDEN);
@@ -4942,24 +4895,15 @@ make_tree (tree type, rtx x)
   switch (GET_CODE (x))
     {
     case CONST_INT:
-      {
-       HOST_WIDE_INT hi = 0;
-
-       if (INTVAL (x) < 0
-           && !(TYPE_UNSIGNED (type)
-                && (GET_MODE_BITSIZE (TYPE_MODE (type))
-                    < HOST_BITS_PER_WIDE_INT)))
-         hi = -1;
-
-       t = build_int_cst_wide (type, INTVAL (x), hi);
-
-       return t;
-      }
+    case CONST_WIDE_INT:
+      t = wide_int_to_tree (type, std::make_pair (x, TYPE_MODE (type)));
+      return t;
 
     case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
-       t = build_int_cst_wide (type,
-                               CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
+      if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
+       t = wide_int_to_tree (type,
+                             wide_int::from_array (&CONST_DOUBLE_LOW (x), 2,
+                                                   HOST_BITS_PER_WIDE_INT * 2));
       else
        {
          REAL_VALUE_TYPE d;