OSDN Git Service

(fold_convert): Add new arg to REAL_VALUE_FROM_INT.
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 796f742..d494f64 100644 (file)
@@ -1,5 +1,5 @@
 /* Fold a constant sub-tree into a single node for C-compiler
-   Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -71,12 +71,12 @@ static tree optimize_bit_field_compare PROTO((enum tree_code, tree,
                                              tree, tree));
 static tree decode_field_reference PROTO((tree, int *, int *,
                                          enum machine_mode *, int *,
-                                         int *, tree *));
+                                         int *, tree *, tree *));
 static int all_ones_mask_p PROTO((tree, int));
 static int simple_operand_p PROTO((tree));
 static tree range_test PROTO((enum tree_code, tree, enum tree_code,
                               enum tree_code, tree, tree, tree));
-static tree unextend   PROTO((tree, int, int));
+static tree unextend   PROTO((tree, int, int, tree));
 static tree fold_truthop PROTO((enum tree_code, tree, tree, tree));
 static tree strip_compound_expr PROTO((tree, tree));
 
@@ -84,9 +84,6 @@ static tree strip_compound_expr PROTO((tree, tree));
 #define BRANCH_COST 1
 #endif
 
-/* Yield nonzero if a signed left shift of A by B bits overflows.  */
-#define left_shift_overflows(a, b)  ((a)  !=  ((a) << (b)) >> (b))
-
 /* Suppose A1 + B1 = SUM1, using 2's complement arithmetic ignoring overflow.
    Suppose A, B and SUM have the same respective signs as A1, B1, and SUM1.
    Then this yields nonzero if overflow occurred during the addition.
@@ -462,7 +459,7 @@ div_and_round_double (code, uns,
   HOST_WIDE_INT den[4], quo[4];
   register int i, j;
   unsigned HOST_WIDE_INT work;
-  register int carry = 0;
+  register unsigned HOST_WIDE_INT carry = 0;
   HOST_WIDE_INT lnum = lnum_orig;
   HOST_WIDE_INT hnum = hnum_orig;
   HOST_WIDE_INT lden = lden_orig;
@@ -529,7 +526,8 @@ div_and_round_double (code, uns,
     {
       /* Full double precision division,
         with thanks to Don Knuth's "Seminumerical Algorithms".  */
-    int quo_est, scale, num_hi_sig, den_hi_sig;
+    int num_hi_sig, den_hi_sig;
+    unsigned HOST_WIDE_INT quo_est, scale;
 
     /* Find the highest non-zero divisor digit.  */
     for (i = 4 - 1; ; i--)
@@ -965,6 +963,8 @@ const_binop (code, arg1, arg2, notrunc)
      register tree arg1, arg2;
      int notrunc;
 {
+  STRIP_NOPS (arg1); STRIP_NOPS (arg2);
+
   if (TREE_CODE (arg1) == INTEGER_CST)
     {
       register HOST_WIDE_INT int1l = TREE_INT_CST_LOW (arg1);
@@ -1357,7 +1357,7 @@ size_binop (code, arg0, arg1)
          && TREE_INT_CST_HIGH (arg0) == 0)
        return arg1;
       /* Handle general case of two integer constants.  */
-      return const_binop (code, arg0, arg1, 1);
+      return const_binop (code, arg0, arg1, 0);
     }
 
   if (arg0 == error_mark_node || arg1 == error_mark_node)
@@ -1412,10 +1412,11 @@ fold_convert (t, arg1)
          REAL_VALUE_TYPE x;
          REAL_VALUE_TYPE l;
          REAL_VALUE_TYPE u;
+         tree type1 = TREE_TYPE (arg1);
 
          x = TREE_REAL_CST (arg1);
-         l = real_value_from_int_cst (TYPE_MIN_VALUE (type));
-         u = real_value_from_int_cst (TYPE_MAX_VALUE (type));
+         l = real_value_from_int_cst (type1, TYPE_MIN_VALUE (type));
+         u = real_value_from_int_cst (type1, TYPE_MAX_VALUE (type));
          /* See if X will be in range after truncation towards 0.
             To compensate for truncation, move the bounds away from 0,
             but reject if X exactly equals the adjusted bounds.  */
@@ -1480,7 +1481,11 @@ fold_convert (t, arg1)
       if (TREE_CODE (arg1) == REAL_CST)
        {
          if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg1)))
-           return arg1;
+           {
+             t = arg1;
+             TREE_TYPE (arg1) = type;
+             return t;
+           }
          else if (setjmp (float_error))
            {
              overflow = 1;
@@ -2382,17 +2387,20 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
    *PMASK is set to the mask used.  This is either contained in a
    BIT_AND_EXPR or derived from the width of the field.
 
+   *PAND_MASK is set the the mask found in a BIT_AND_EXPR, if any.
+
    Return 0 if this is not a component reference or is one that we can't
    do anything with.  */
 
 static tree
 decode_field_reference (exp, pbitsize, pbitpos, pmode, punsignedp,
-                       pvolatilep, pmask)
+                       pvolatilep, pmask, pand_mask)
      tree exp;
      int *pbitsize, *pbitpos;
      enum machine_mode *pmode;
      int *punsignedp, *pvolatilep;
      tree *pmask;
+     tree *pand_mask;
 {
   tree and_mask = 0;
   tree mask, inner, offset;
@@ -2439,6 +2447,7 @@ decode_field_reference (exp, pbitsize, pbitpos, pmode, punsignedp,
                        convert (unsigned_type, and_mask), mask));
 
   *pmask = mask;
+  *pand_mask = and_mask;
   return inner;
 }
 
@@ -2621,13 +2630,15 @@ range_test (jcode, type, lo_code, hi_code, var, lo_cst, hi_cst)
 \f
 /* Subroutine for fold_truthop: C is an INTEGER_CST interpreted as a P
    bit value.  Arrange things so the extra bits will be set to zero if and
-   only if C is signed-extended to its full width.  */
+   only if C is signed-extended to its full width.  If MASK is nonzero,
+   it is an INTEGER_CST that should be AND'ed with the extra bits.  */
 
 static tree
-unextend (c, p, unsignedp)
+unextend (c, p, unsignedp, mask)
      tree c;
      int p;
      int unsignedp;
+     tree mask;
 {
   tree type = TREE_TYPE (c);
   int modesize = GET_MODE_BITSIZE (TYPE_MODE (type));
@@ -2646,6 +2657,9 @@ unextend (c, p, unsignedp)
   temp = const_binop (BIT_AND_EXPR, temp, size_int (1), 0);
   temp = const_binop (LSHIFT_EXPR, temp, size_int (modesize - 1), 0);
   temp = const_binop (RSHIFT_EXPR, temp, size_int (modesize - p - 1), 0);
+  if (mask != 0)
+    temp = const_binop (BIT_AND_EXPR, temp, convert (TREE_TYPE (c), mask), 0);
+
   return convert (type, const_binop (BIT_XOR_EXPR, c, temp, 0));
 }
 \f
@@ -2699,6 +2713,7 @@ fold_truthop (code, truth_type, lhs, rhs)
   enum machine_mode ll_mode, lr_mode, rl_mode, rr_mode;
   enum machine_mode lnmode, rnmode;
   tree ll_mask, lr_mask, rl_mask, rr_mask;
+  tree ll_and_mask, lr_and_mask, rl_and_mask, rr_and_mask;
   tree l_const, r_const;
   tree type, result;
   int first_bit, end_bit;
@@ -2788,16 +2803,20 @@ fold_truthop (code, truth_type, lhs, rhs)
   volatilep = 0;
   ll_inner = decode_field_reference (ll_arg,
                                     &ll_bitsize, &ll_bitpos, &ll_mode,
-                                    &ll_unsignedp, &volatilep, &ll_mask);
+                                    &ll_unsignedp, &volatilep, &ll_mask,
+                                    &ll_and_mask);
   lr_inner = decode_field_reference (lr_arg,
                                     &lr_bitsize, &lr_bitpos, &lr_mode,
-                                    &lr_unsignedp, &volatilep, &lr_mask);
+                                    &lr_unsignedp, &volatilep, &lr_mask,
+                                    &lr_and_mask);
   rl_inner = decode_field_reference (rl_arg,
                                     &rl_bitsize, &rl_bitpos, &rl_mode,
-                                    &rl_unsignedp, &volatilep, &rl_mask);
+                                    &rl_unsignedp, &volatilep, &rl_mask,
+                                    &rl_and_mask);
   rr_inner = decode_field_reference (rr_arg,
                                     &rr_bitsize, &rr_bitpos, &rr_mode,
-                                    &rr_unsignedp, &volatilep, &rr_mask);
+                                    &rr_unsignedp, &volatilep, &rr_mask,
+                                    &rr_and_mask);
 
   /* It must be true that the inner operation on the lhs of each
      comparison must be the same if we are to be able to do anything.
@@ -2866,7 +2885,8 @@ fold_truthop (code, truth_type, lhs, rhs)
 
   if (l_const)
     {
-      l_const = unextend (convert (type, l_const), ll_bitsize, ll_unsignedp);
+      l_const = convert (type, l_const);
+      l_const = unextend (l_const,  ll_bitsize, ll_unsignedp, ll_and_mask);
       l_const = const_binop (LSHIFT_EXPR, l_const, size_int (xll_bitpos), 0);
       if (! integer_zerop (const_binop (BIT_AND_EXPR, l_const,
                                        fold (build1 (BIT_NOT_EXPR,
@@ -2883,7 +2903,8 @@ fold_truthop (code, truth_type, lhs, rhs)
     }
   if (r_const)
     {
-      r_const = unextend (convert (type, r_const), rl_bitsize, rl_unsignedp);
+      r_const = convert (type, r_const);
+      r_const = unextend (r_const, rl_bitsize, rl_unsignedp, rl_and_mask);
       r_const = const_binop (LSHIFT_EXPR, r_const, size_int (xrl_bitpos), 0);
       if (! integer_zerop (const_binop (BIT_AND_EXPR, r_const,
                                        fold (build1 (BIT_NOT_EXPR,
@@ -3429,11 +3450,14 @@ fold (expr)
             float or both integer, we don't need the middle conversion if
             it is wider than the final type and doesn't change the signedness
             (for integers).  Avoid this if the final type is a pointer
-            since then we sometimes need the inner conversion.  */
+            since then we sometimes need the inner conversion.  Likewise if
+            the outer has a precision not equal to the size of its mode.  */
          if ((((inter_int || inter_ptr) && (inside_int || inside_ptr))
               || (inter_float && inside_float))
              && inter_prec >= inside_prec
              && (inter_float || inter_unsignedp == inside_unsignedp)
+             && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (final_type))
+                   && TYPE_MODE (final_type) == TYPE_MODE (inter_type))
              && ! final_ptr)
            return convert (final_type, TREE_OPERAND (TREE_OPERAND (t, 0), 0));
 
@@ -3455,7 +3479,10 @@ fold (expr)
              && ((inter_unsignedp && inter_prec > inside_prec)
                  == (final_unsignedp && final_prec > inter_prec))
              && ! (inside_ptr && inter_prec != final_prec)
-             && ! (final_ptr && inside_prec != inter_prec))
+             && ! (final_ptr && inside_prec != inter_prec)
+             && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (final_type))
+                   && TYPE_MODE (final_type) == TYPE_MODE (inter_type))
+             && ! final_ptr)
            return convert (final_type, TREE_OPERAND (TREE_OPERAND (t, 0), 0));
        }
 
@@ -3526,7 +3553,7 @@ fold (expr)
              TREE_TYPE (t) = type;
              TREE_OVERFLOW (t)
                = (TREE_OVERFLOW (arg0)
-                  | force_fit_type (t, overflow));
+                  | force_fit_type (t, overflow && !TREE_UNSIGNED (type)));
              TREE_CONSTANT_OVERFLOW (t)
                = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0);
            }
@@ -3875,6 +3902,9 @@ fold (expr)
 
     case BIT_IOR_EXPR:
     bit_ior:
+      {
+      register enum tree_code code0, code1;
+
       if (integer_all_onesp (arg1))
        return omit_one_operand (type, arg1, arg0);
       if (integer_zerop (arg1))
@@ -3883,28 +3913,53 @@ fold (expr)
       if (t1 != NULL_TREE)
        return t1;
 
-      /* (a << C1) | (a >> C2) if A is unsigned and C1+C2 is the size of A
+      /* (A << C1) | (A >> C2) if A is unsigned and C1+C2 is the size of A
         is a rotate of A by C1 bits.  */
+      /* (A << B) | (A >> (Z - B)) if A is unsigned and Z is the size of A
+        is a rotate of A by B bits.  */
 
-      if ((TREE_CODE (arg0) == RSHIFT_EXPR
-          || TREE_CODE (arg0) == LSHIFT_EXPR)
-         && (TREE_CODE (arg1) == RSHIFT_EXPR
-             || TREE_CODE (arg1) == LSHIFT_EXPR)
-         && TREE_CODE (arg0) != TREE_CODE (arg1)
+      code0 = TREE_CODE (arg0);
+      code1 = TREE_CODE (arg1);
+      if (((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR)
+         || (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR))
          && operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1,0), 0)
-         && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0)))
-         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
-         && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
-         && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == 0
-         && TREE_INT_CST_HIGH (TREE_OPERAND (arg1, 1)) == 0
-         && ((TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1))
-              + TREE_INT_CST_LOW (TREE_OPERAND (arg1, 1)))
+         && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+       {
+         register tree tree01, tree11;
+         register enum tree_code code01, code11;
+
+         tree01 = TREE_OPERAND (arg0, 1);
+         tree11 = TREE_OPERAND (arg1, 1);
+         code01 = TREE_CODE (tree01);
+         code11 = TREE_CODE (tree11);
+         if (code01 == INTEGER_CST
+           && code11 == INTEGER_CST
+           && TREE_INT_CST_HIGH (tree01) == 0
+           && TREE_INT_CST_HIGH (tree11) == 0
+           && ((TREE_INT_CST_LOW (tree01) + TREE_INT_CST_LOW (tree11))
              == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
-       return build (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0),
-                     TREE_CODE (arg0) == LSHIFT_EXPR
-                     ? TREE_OPERAND (arg0, 1) : TREE_OPERAND (arg1, 1));
+           return build (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0),
+                     code0 == LSHIFT_EXPR ? tree01 : tree11);
+         else if (code11 == MINUS_EXPR
+               && TREE_CODE (TREE_OPERAND (tree11, 0)) == INTEGER_CST
+               && TREE_INT_CST_HIGH (TREE_OPERAND (tree11, 0)) == 0
+               && TREE_INT_CST_LOW (TREE_OPERAND (tree11, 0))
+                 == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))
+               && operand_equal_p (tree01, TREE_OPERAND (tree11, 1), 0))
+           return build (code0 == LSHIFT_EXPR ? LROTATE_EXPR : RROTATE_EXPR,
+                       type, TREE_OPERAND (arg0, 0), tree01);
+         else if (code01 == MINUS_EXPR
+               && TREE_CODE (TREE_OPERAND (tree01, 0)) == INTEGER_CST
+               && TREE_INT_CST_HIGH (TREE_OPERAND (tree01, 0)) == 0
+               && TREE_INT_CST_LOW (TREE_OPERAND (tree01, 0))
+                 == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))
+               && operand_equal_p (tree11, TREE_OPERAND (tree01, 1), 0))
+           return build (code0 != LSHIFT_EXPR ? LROTATE_EXPR : RROTATE_EXPR,
+                       type, TREE_OPERAND (arg0, 0), tree11);
+       }
 
       goto associate;
+      }
 
     case BIT_XOR_EXPR:
       if (integer_zerop (arg1))
@@ -4025,7 +4080,7 @@ fold (expr)
          tree c2 = integer_zero_node;
          tree xarg0 = arg0;
 
-         if (TREE_CODE (xarg0) == SAVE_EXPR)
+         if (TREE_CODE (xarg0) == SAVE_EXPR && SAVE_EXPR_RTL (xarg0) == 0)
            have_save_expr = 1, xarg0 = TREE_OPERAND (xarg0, 0);
 
          STRIP_NOPS (xarg0);
@@ -4043,7 +4098,7 @@ fold (expr)
              xarg0 = TREE_OPERAND (xarg0, 0);
            }
 
-         if (TREE_CODE (xarg0) == SAVE_EXPR)
+         if (TREE_CODE (xarg0) == SAVE_EXPR && SAVE_EXPR_RTL (xarg0) == 0)
            have_save_expr = 1, xarg0 = TREE_OPERAND (xarg0, 0);
 
          STRIP_NOPS (xarg0);