OSDN Git Service

2009-04-16 Ed Schonberg <schonberg@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index 820ca5a..bd5e97d 100644 (file)
@@ -1,6 +1,6 @@
 /* Fold a constant sub-tree into a single node for C-compiler
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -103,8 +103,6 @@ static tree associate_trees (tree, tree, enum tree_code, tree);
 static tree const_binop (enum tree_code, tree, tree, int);
 static enum comparison_code comparison_to_compcode (enum tree_code);
 static enum tree_code compcode_to_comparison (enum comparison_code);
-static tree combine_comparisons (enum tree_code, enum tree_code,
-                                enum tree_code, tree, tree, tree);
 static int operand_equal_for_comparison_p (tree, tree, tree);
 static int twoval_comparison_p (tree, tree *, tree *, int *);
 static tree eval_subst (tree, tree, tree, tree, tree);
@@ -143,6 +141,7 @@ static bool reorder_operands_p (const_tree, const_tree);
 static tree fold_negate_const (tree, tree);
 static tree fold_not_const (tree, tree);
 static tree fold_relational_const (enum tree_code, tree, tree, tree);
+static tree fold_convert_const (enum tree_code, tree, tree);
 
 
 /* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring
@@ -876,7 +875,7 @@ div_and_round_double (enum tree_code code, int uns,
    of type CODE and returns the quotient.
    Otherwise returns NULL_TREE.  */
 
-static tree
+tree
 div_if_zero_remainder (enum tree_code code, const_tree arg1, const_tree arg2)
 {
   unsigned HOST_WIDE_INT int1l, int2l;
@@ -1934,12 +1933,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
       t = build_fixed (type, result);
       /* Propagate overflow flags.  */
       if (overflow_p | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2))
-       {
-         TREE_OVERFLOW (t) = 1;
-         TREE_CONSTANT_OVERFLOW (t) = 1;
-       }
-      else if (TREE_CONSTANT_OVERFLOW (arg1) | TREE_CONSTANT_OVERFLOW (arg2))
-       TREE_CONSTANT_OVERFLOW (t) = 1;
+       TREE_OVERFLOW (t) = 1;
       return t;
     }
 
@@ -2005,6 +1999,50 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
        return build_complex (type, real, imag);
     }
 
+  if (TREE_CODE (arg1) == VECTOR_CST)
+    {
+      tree type = TREE_TYPE(arg1);
+      int count = TYPE_VECTOR_SUBPARTS (type), i;
+      tree elements1, elements2, list = NULL_TREE;
+      
+      if(TREE_CODE(arg2) != VECTOR_CST)
+        return NULL_TREE;
+        
+      elements1 = TREE_VECTOR_CST_ELTS (arg1);
+      elements2 = TREE_VECTOR_CST_ELTS (arg2);
+
+      for (i = 0; i < count; i++)
+       {
+          tree elem1, elem2, elem;
+          
+          /* The trailing elements can be empty and should be treated as 0 */
+          if(!elements1)
+            elem1 = fold_convert_const (NOP_EXPR, TREE_TYPE (type), integer_zero_node);
+          else
+            {
+              elem1 = TREE_VALUE(elements1);
+              elements1 = TREE_CHAIN (elements1);
+            }  
+            
+          if(!elements2)
+            elem2 = fold_convert_const (NOP_EXPR, TREE_TYPE (type), integer_zero_node);
+          else
+            {
+              elem2 = TREE_VALUE(elements2);
+              elements2 = TREE_CHAIN (elements2);
+            }
+              
+          elem = const_binop (code, elem1, elem2, notrunc);
+          
+          /* It is possible that const_binop cannot handle the given
+            code and return NULL_TREE */
+          if(elem == NULL_TREE)
+            return NULL_TREE;
+          
+          list = tree_cons (NULL_TREE, elem, list);
+       }
+      return build_vector(type, nreverse(list));  
+    }
   return NULL_TREE;
 }
 
@@ -2306,8 +2344,6 @@ fold_convert_const_real_from_fixed (tree type, const_tree arg1)
   t = build_real (type, value);
 
   TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1);
-  TREE_CONSTANT_OVERFLOW (t)
-    = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1);
   return t;
 }
 
@@ -2327,12 +2363,7 @@ fold_convert_const_fixed_from_fixed (tree type, const_tree arg1)
 
   /* Propagate overflow flags.  */
   if (overflow_p | TREE_OVERFLOW (arg1))
-    {
-      TREE_OVERFLOW (t) = 1;
-      TREE_CONSTANT_OVERFLOW (t) = 1;
-    }
-  else if (TREE_CONSTANT_OVERFLOW (arg1))
-    TREE_CONSTANT_OVERFLOW (t) = 1;
+    TREE_OVERFLOW (t) = 1;
   return t;
 }
 
@@ -2354,12 +2385,7 @@ fold_convert_const_fixed_from_int (tree type, const_tree arg1)
 
   /* Propagate overflow flags.  */
   if (overflow_p | TREE_OVERFLOW (arg1))
-    {
-      TREE_OVERFLOW (t) = 1;
-      TREE_CONSTANT_OVERFLOW (t) = 1;
-    }
-  else if (TREE_CONSTANT_OVERFLOW (arg1))
-    TREE_CONSTANT_OVERFLOW (t) = 1;
+    TREE_OVERFLOW (t) = 1;
   return t;
 }
 
@@ -2380,12 +2406,7 @@ fold_convert_const_fixed_from_real (tree type, const_tree arg1)
 
   /* Propagate overflow flags.  */
   if (overflow_p | TREE_OVERFLOW (arg1))
-    {
-      TREE_OVERFLOW (t) = 1;
-      TREE_CONSTANT_OVERFLOW (t) = 1;
-    }
-  else if (TREE_CONSTANT_OVERFLOW (arg1))
-    TREE_CONSTANT_OVERFLOW (t) = 1;
+    TREE_OVERFLOW (t) = 1;
   return t;
 }
 
@@ -4650,8 +4671,8 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh,
 static tree
 build_range_check (tree type, tree exp, int in_p, tree low, tree high)
 {
-  tree etype = TREE_TYPE (exp);
-  tree value;
+  tree etype = TREE_TYPE (exp), value;
+  enum tree_code code;
 
 #ifdef HAVE_canonicalize_funcptr_for_compare
   /* Disable this optimization for function pointer expressions
@@ -4735,20 +4756,25 @@ build_range_check (tree type, tree exp, int in_p, tree low, tree high)
 
   /* Optimize (c>=low) && (c<=high) into (c-low>=0) && (c-low<=high-low).
      This requires wrap-around arithmetics for the type of the expression.  */
-  switch (TREE_CODE (etype))
+  code = TREE_CODE (etype);
+  switch (code)
     {
     case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
       /* There is no requirement that LOW be within the range of ETYPE
         if the latter is a subtype.  It must, however, be within the base
         type of ETYPE.  So be sure we do the subtraction in that type.  */
-      if (TREE_TYPE (etype))
-       etype = TREE_TYPE (etype);
-      break;
+      if (code == INTEGER_TYPE && TREE_TYPE (etype))
+       {
+         etype = TREE_TYPE (etype);
+         /* But not in an enumeral or boolean type though.  */
+         code = TREE_CODE (etype);
+       }
 
-    case ENUMERAL_TYPE:
-    case BOOLEAN_TYPE:
-      etype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype),
-                                             TYPE_UNSIGNED (etype));
+      if (code != INTEGER_TYPE)
+       etype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype),
+                                               TYPE_UNSIGNED (etype));
       break;
 
     default:
@@ -7490,7 +7516,11 @@ fold_plusminus_mult_expr (enum tree_code code, tree type, tree arg0, tree arg1)
       else
        maybe_same = arg11;
 
-      if (exact_log2 (abs (int11)) > 0 && int01 % int11 == 0)
+      if (exact_log2 (abs (int11)) > 0 && int01 % int11 == 0
+         /* The remainder should not be a constant, otherwise we
+            end up folding i * 4 + 2 to (i * 2 + 1) * 2 which has
+            increased the number of multiplications necessary.  */
+         && TREE_CODE (arg10) != INTEGER_CST)
         {
          alt0 = fold_build2 (MULT_EXPR, TREE_TYPE (arg00), arg00,
                              build_int_cst (TREE_TYPE (arg00),
@@ -7937,11 +7967,10 @@ fold_view_convert_expr (tree type, tree expr)
 }
 
 /* Build an expression for the address of T.  Folds away INDIRECT_REF
-   to avoid confusing the gimplify process.  When IN_FOLD is true
-   avoid modifications of T.  */
+   to avoid confusing the gimplify process.  */
 
-static tree
-build_fold_addr_expr_with_type_1 (tree t, tree ptrtype, bool in_fold)
+tree
+build_fold_addr_expr_with_type (tree t, tree ptrtype)
 {
   /* The size of the object is not relevant when talking about its address.  */
   if (TREE_CODE (t) == WITH_SIZE_EXPR)
@@ -7956,56 +7985,20 @@ build_fold_addr_expr_with_type_1 (tree t, tree ptrtype, bool in_fold)
       if (TREE_TYPE (t) != ptrtype)
        t = build1 (NOP_EXPR, ptrtype, t);
     }
-  else if (!in_fold)
-    {
-      tree base = t;
-
-      while (handled_component_p (base))
-       base = TREE_OPERAND (base, 0);
-
-      if (DECL_P (base))
-       TREE_ADDRESSABLE (base) = 1;
-
-      t = build1 (ADDR_EXPR, ptrtype, t);
-    }
   else
     t = build1 (ADDR_EXPR, ptrtype, t);
 
   return t;
 }
 
-/* Build an expression for the address of T with type PTRTYPE.  This
-   function modifies the input parameter 'T' by sometimes setting the
-   TREE_ADDRESSABLE flag.  */
-
-tree
-build_fold_addr_expr_with_type (tree t, tree ptrtype)
-{
-  return build_fold_addr_expr_with_type_1 (t, ptrtype, false);
-}
-
-/* Build an expression for the address of T.  This function modifies
-   the input parameter 'T' by sometimes setting the TREE_ADDRESSABLE
-   flag.  When called from fold functions, use fold_addr_expr instead.  */
+/* Build an expression for the address of T.  */
 
 tree
 build_fold_addr_expr (tree t)
 {
-  return build_fold_addr_expr_with_type_1 (t, 
-                                          build_pointer_type (TREE_TYPE (t)),
-                                          false);
-}
-
-/* Same as build_fold_addr_expr, builds an expression for the address
-   of T, but avoids touching the input node 't'.  Fold functions
-   should use this version.  */
-
-static tree
-fold_addr_expr (tree t)
-{
   tree ptrtype = build_pointer_type (TREE_TYPE (t));
 
-  return build_fold_addr_expr_with_type_1 (t, ptrtype, true);
+  return build_fold_addr_expr_with_type (t, ptrtype);
 }
 
 /* Fold a unary expression of code CODE and type TYPE with operand
@@ -8174,12 +8167,12 @@ fold_unary (enum tree_code code, tree type, tree op0)
              && inter_prec >= final_prec)
            return fold_build1 (code, type, TREE_OPERAND (op0, 0));
 
-         /* Likewise, if the intermediate and final types are either both
-            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.  Likewise if
-            the outer has a precision not equal to the size of its mode.  */
+         /* Likewise, if the intermediate and initial types are either both
+            float or both integer, we don't need the middle conversion if the
+            former is wider than the latter and doesn't change the signedness
+            (for integers).  Avoid this if the final type is a pointer since
+            then we sometimes need the middle conversion.  Likewise if the
+            final type has a precision not equal to the size of its mode.  */
          if (((inter_int && inside_int)
               || (inter_float && inside_float)
               || (inter_vec && inside_vec))
@@ -8245,7 +8238,7 @@ fold_unary (enum tree_code code, tree type, tree op0)
          if (! offset && bitpos == 0
              && TYPE_MAIN_VARIANT (TREE_TYPE (type))
                  == TYPE_MAIN_VARIANT (TREE_TYPE (base)))
-           return fold_convert (type, fold_addr_expr (base));
+           return fold_convert (type, build_fold_addr_expr (base));
         }
 
       if (TREE_CODE (op0) == MODIFY_EXPR
@@ -8628,6 +8621,24 @@ fold_unary (enum tree_code code, tree type, tree op0)
     } /* switch (code) */
 }
 
+
+/* If the operation was a conversion do _not_ mark a resulting constant
+   with TREE_OVERFLOW if the original constant was not.  These conversions
+   have implementation defined behavior and retaining the TREE_OVERFLOW
+   flag here would confuse later passes such as VRP.  */
+tree
+fold_unary_ignore_overflow (enum tree_code code, tree type, tree op0)
+{
+  tree res = fold_unary (code, type, op0);
+  if (res
+      && TREE_CODE (res) == INTEGER_CST
+      && TREE_CODE (op0) == INTEGER_CST
+      && CONVERT_EXPR_CODE_P (code))
+    TREE_OVERFLOW (res) = TREE_OVERFLOW (op0);
+
+  return res;
+}
+
 /* Fold a binary expression of code CODE and type TYPE with operands
    OP0 and OP1, containing either a MIN-MAX or a MAX-MIN combination.
    Return the folded expression if folding is successful.  Otherwise,
@@ -9137,9 +9148,9 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
                       && operand_equal_p (offset0, offset1, 0))))
        {
          if (indirect_base0)
-           base0 = fold_addr_expr (base0);
+           base0 = build_fold_addr_expr (base0);
          if (indirect_base1)
-           base1 = fold_addr_expr (base1);
+           base1 = build_fold_addr_expr (base1);
          return fold_build2 (code, type, base0, base1);
        }
     }
@@ -9274,7 +9285,8 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
            }
 
          /* Fold comparisons against infinity.  */
-         if (REAL_VALUE_ISINF (cst))
+         if (REAL_VALUE_ISINF (cst)
+             && MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg1))))
            {
              tem = fold_inf_compare (code, type, arg0, arg1);
              if (tem != NULL_TREE)
@@ -9571,10 +9583,15 @@ fold_mult_zconjz (tree type, tree expr)
    0 <= N < M as is common.  In general, the precise value of P is unknown.
    M is chosen as large as possible such that constant N can be determined.
 
-   Returns M and sets *RESIDUE to N.  */
+   Returns M and sets *RESIDUE to N.
+
+   If ALLOW_FUNC_ALIGN is true, do take functions' DECL_ALIGN_UNIT into
+   account.  This is not always possible due to PR 35705.
+ */
 
 static unsigned HOST_WIDE_INT
-get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue)
+get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue,
+                                bool allow_func_align)
 {
   enum tree_code code;
 
@@ -9604,7 +9621,8 @@ get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue)
            }
        }
 
-      if (DECL_P (expr) && TREE_CODE (expr) != FUNCTION_DECL)
+      if (DECL_P (expr)
+         && (allow_func_align || TREE_CODE (expr) != FUNCTION_DECL))
        return DECL_ALIGN_UNIT (expr);
     }
   else if (code == POINTER_PLUS_EXPR)
@@ -9615,7 +9633,8 @@ get_pointer_modulus_and_residue (tree expr, unsigned HOST_WIDE_INT *residue)
       
       op0 = TREE_OPERAND (expr, 0);
       STRIP_NOPS (op0);
-      modulus = get_pointer_modulus_and_residue (op0, residue);
+      modulus = get_pointer_modulus_and_residue (op0, residue,
+                                                allow_func_align);
 
       op1 = TREE_OPERAND (expr, 1);
       STRIP_NOPS (op1);
@@ -9864,20 +9883,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       return NULL_TREE;
 
     case PLUS_EXPR:
-      /* PTR + INT -> (INT)(PTR p+ INT) */
-      if (POINTER_TYPE_P (TREE_TYPE (arg0))
-         && INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
-       return fold_convert (type, fold_build2 (POINTER_PLUS_EXPR,
-                                               TREE_TYPE (arg0),
-                                               arg0,
-                                               fold_convert (sizetype, arg1)));
-      /* INT + PTR -> (INT)(PTR p+ INT) */
-      if (POINTER_TYPE_P (TREE_TYPE (arg1))
-         && INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
-       return fold_convert (type, fold_build2 (POINTER_PLUS_EXPR,
-                                               TREE_TYPE (arg1),
-                                               arg1,
-                                               fold_convert (sizetype, arg0)));
       /* A + (-B) -> A - B */
       if (TREE_CODE (arg1) == NEGATE_EXPR)
        return fold_build2 (MINUS_EXPR, type,
@@ -11269,7 +11274,8 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          unsigned HOST_WIDE_INT modulus, residue;
          unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (arg1);
 
-         modulus = get_pointer_modulus_and_residue (arg0, &residue);
+         modulus = get_pointer_modulus_and_residue (arg0, &residue,
+                                                    integer_onep (arg1));
 
          /* This works because modulus is a power of 2.  If this weren't the
             case, we'd have to replace it by its greatest power-of-2
@@ -12239,22 +12245,33 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                         fold_convert (TREE_TYPE (arg0), arg1),
                                         TREE_OPERAND (arg0, 1)));
 
-      /* Transform comparisons of the form X +- C CMP X.  */
-      if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
+      /* Transform comparisons of the form X +- Y CMP X to Y CMP 0.  */
+      if ((TREE_CODE (arg0) == PLUS_EXPR
+          || TREE_CODE (arg0) == POINTER_PLUS_EXPR
+          || TREE_CODE (arg0) == MINUS_EXPR)
          && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
-         && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
          && (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
              || POINTER_TYPE_P (TREE_TYPE (arg0))))
        {
-         tree cst = TREE_OPERAND (arg0, 1);
+         tree val = TREE_OPERAND (arg0, 1);
+         return omit_two_operands (type,
+                                   fold_build2 (code, type,
+                                                val,
+                                                build_int_cst (TREE_TYPE (val),
+                                                               0)),
+                                   TREE_OPERAND (arg0, 0), arg1);
+       }
 
-         if (code == EQ_EXPR
-             && !integer_zerop (cst))
-           return omit_two_operands (type, boolean_false_node,
-                                     TREE_OPERAND (arg0, 0), arg1);
-         else
-           return omit_two_operands (type, boolean_true_node,
-                                     TREE_OPERAND (arg0, 0), arg1);
+      /* Transform comparisons of the form C - X CMP X if C % 2 == 1.  */
+      if (TREE_CODE (arg0) == MINUS_EXPR
+         && TREE_CODE (TREE_OPERAND (arg0, 0)) == INTEGER_CST
+         && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)
+         && (TREE_INT_CST_LOW (TREE_OPERAND (arg0, 0)) & 1) == 1)
+       {
+         return omit_two_operands (type,
+                                   code == NE_EXPR
+                                   ? boolean_true_node : boolean_false_node,
+                                   TREE_OPERAND (arg0, 1), arg1);
        }
 
       /* If we have X - Y == 0, we can convert that to X == Y and similarly
@@ -15005,9 +15022,13 @@ tree_single_nonzero_warnv_p (tree t, bool *strict_overflow_p)
        if (!base)
          return false;
 
-       /* Weak declarations may link to NULL.  */
-       if (VAR_OR_FUNCTION_DECL_P (base))
-         return !DECL_WEAK (base);
+       /* Weak declarations may link to NULL.  Other things may also be NULL
+          so protect with -fdelete-null-pointer-checks; but not variables
+          allocated on the stack.  */
+       if (DECL_P (base)
+           && (flag_delete_null_pointer_checks
+               || (TREE_CODE (base) == VAR_DECL && !TREE_STATIC (base))))
+         return !VAR_OR_FUNCTION_DECL_P (base) || !DECL_WEAK (base);
 
        /* Constants are never weak.  */
        if (CONSTANT_CLASS_P (base))
@@ -15254,12 +15275,7 @@ fold_negate_const (tree arg0, tree type)
        t = build_fixed (type, f);
        /* Propagate overflow flags.  */
        if (overflow_p | TREE_OVERFLOW (arg0))
-         {
-           TREE_OVERFLOW (t) = 1;
-           TREE_CONSTANT_OVERFLOW (t) = 1;
-         }
-       else if (TREE_CONSTANT_OVERFLOW (arg0))
-         TREE_CONSTANT_OVERFLOW (t) = 1;
+         TREE_OVERFLOW (t) = 1;
        break;
       }
 
@@ -15824,7 +15840,7 @@ split_address_to_core_and_offset (tree exp,
       core = get_inner_reference (TREE_OPERAND (exp, 0), &bitsize, pbitpos,
                                  poffset, &mode, &unsignedp, &volatilep,
                                  false);
-      core = fold_addr_expr (core);
+      core = build_fold_addr_expr (core);
     }
   else
     {