OSDN Git Service

PR testsuite/21010
[pf3gnuchains/gcc-fork.git] / gcc / fold-const.c
index d32172f..9487d3c 100644 (file)
@@ -2003,16 +2003,12 @@ fold_convert (tree type, tree arg)
     }
 }
 \f
-/* Return an expr equal to X but certainly not valid as an lvalue.  */
+/* Return false if expr can be assumed not to be an value, true
+   otherwise.  */
 
-tree
-non_lvalue (tree x)
+static bool
+maybe_lvalue_p (tree x)
 {
-  /* While we are in GIMPLE, NON_LVALUE_EXPR doesn't mean anything to
-     us.  */
-  if (in_gimple_form)
-    return x;
-
   /* We only need to wrap lvalue tree codes.  */
   switch (TREE_CODE (x))
   {
@@ -2052,8 +2048,24 @@ non_lvalue (tree x)
     /* Assume the worst for front-end tree codes.  */
     if ((int)TREE_CODE (x) >= NUM_TREE_CODES)
       break;
-    return x;
+    return false;
   }
+
+  return true;
+}
+
+/* Return an expr equal to X but certainly not valid as an lvalue.  */
+
+tree
+non_lvalue (tree x)
+{
+  /* While we are in GIMPLE, NON_LVALUE_EXPR doesn't mean anything to
+     us.  */
+  if (in_gimple_form)
+    return x;
+
+  if (! maybe_lvalue_p (x))
+    return x;
   return build1 (NON_LVALUE_EXPR, TREE_TYPE (x), x);
 }
 
@@ -4187,8 +4199,16 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
   if ((FLOAT_TYPE_P (TREE_TYPE (arg01))
        ? real_zerop (arg01)
        : integer_zerop (arg01))
-      && TREE_CODE (arg2) == NEGATE_EXPR
-      && operand_equal_p (TREE_OPERAND (arg2, 0), arg1, 0))
+      && ((TREE_CODE (arg2) == NEGATE_EXPR
+          && operand_equal_p (TREE_OPERAND (arg2, 0), arg1, 0))
+            /* In the case that A is of the form X-Y, '-A' (arg2) may
+               have already been folded to Y-X, check for that. */
+         || (TREE_CODE (arg1) == MINUS_EXPR
+             && TREE_CODE (arg2) == MINUS_EXPR
+             && operand_equal_p (TREE_OPERAND (arg1, 0),
+                                 TREE_OPERAND (arg2, 1), 0)
+             && operand_equal_p (TREE_OPERAND (arg1, 1),
+                                 TREE_OPERAND (arg2, 0), 0))))
     switch (comp_code)
       {
       case EQ_EXPR:
@@ -4265,7 +4285,13 @@ fold_cond_expr_with_comparison (tree type, tree arg0, tree arg1, tree arg2)
      a number and A is not.  The conditions in the original
      expressions will be false, so all four give B.  The min()
      and max() versions would give a NaN instead.  */
-  if (operand_equal_for_comparison_p (arg01, arg2, arg00))
+  if (operand_equal_for_comparison_p (arg01, arg2, arg00)
+      /* Avoid these transformations if the COND_EXPR may be used
+        as an lvalue in the C++ front-end.  PR c++/19199.  */
+      && (in_gimple_form
+         || strcmp (lang_hooks.name, "GNU C++") != 0
+         || ! maybe_lvalue_p (arg1)
+         || ! maybe_lvalue_p (arg2)))
     {
       tree comp_op0 = arg00;
       tree comp_op1 = arg01;
@@ -5493,14 +5519,18 @@ fold_binary_op_with_conditional_arg (enum tree_code code,
   if (lhs == 0)
     {
       true_value = fold_convert (cond_type, true_value);
-      lhs = fold (cond_first_p ? build2 (code, type, true_value, arg)
-                            : build2 (code, type, arg, true_value));
+      if (cond_first_p)
+       lhs = fold_build2 (code, type, true_value, arg);
+      else
+       lhs = fold_build2 (code, type, arg, true_value);
     }
   if (rhs == 0)
     {
       false_value = fold_convert (cond_type, false_value);
-      rhs = fold (cond_first_p ? build2 (code, type, false_value, arg)
-                            : build2 (code, type, arg, false_value));
+      if (cond_first_p)
+       rhs = fold_build2 (code, type, false_value, arg);
+      else
+       rhs = fold_build2 (code, type, arg, false_value);
     }
 
   test = fold_build3 (COND_EXPR, type, test, lhs, rhs);
@@ -6745,16 +6775,19 @@ fold_unary (enum tree_code code, tree type, tree op0)
          int inside_int = INTEGRAL_TYPE_P (inside_type);
          int inside_ptr = POINTER_TYPE_P (inside_type);
          int inside_float = FLOAT_TYPE_P (inside_type);
+         int inside_vec = TREE_CODE (inside_type) == VECTOR_TYPE;
          unsigned int inside_prec = TYPE_PRECISION (inside_type);
          int inside_unsignedp = TYPE_UNSIGNED (inside_type);
          int inter_int = INTEGRAL_TYPE_P (inter_type);
          int inter_ptr = POINTER_TYPE_P (inter_type);
          int inter_float = FLOAT_TYPE_P (inter_type);
+         int inter_vec = TREE_CODE (inter_type) == VECTOR_TYPE;
          unsigned int inter_prec = TYPE_PRECISION (inter_type);
          int inter_unsignedp = TYPE_UNSIGNED (inter_type);
          int final_int = INTEGRAL_TYPE_P (type);
          int final_ptr = POINTER_TYPE_P (type);
          int final_float = FLOAT_TYPE_P (type);
+         int final_vec = TREE_CODE (type) == VECTOR_TYPE;
          unsigned int final_prec = TYPE_PRECISION (type);
          int final_unsignedp = TYPE_UNSIGNED (type);
 
@@ -6774,12 +6807,15 @@ fold_unary (enum tree_code code, tree type, tree op0)
             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_float && inside_float)
+              || (inter_vec && inside_vec))
              && inter_prec >= inside_prec
-             && (inter_float || inter_unsignedp == inside_unsignedp)
+             && (inter_float || inter_vec
+                 || inter_unsignedp == inside_unsignedp)
              && ! (final_prec != GET_MODE_BITSIZE (TYPE_MODE (type))
                    && TYPE_MODE (type) == TYPE_MODE (inter_type))
-             && ! final_ptr)
+             && ! final_ptr
+             && (! final_vec || inter_prec == inside_prec))
            return fold_build1 (code, type, TREE_OPERAND (op0, 0));
 
          /* If we have a sign-extension of a zero-extended value, we can
@@ -6791,6 +6827,7 @@ fold_unary (enum tree_code code, tree type, tree op0)
 
          /* Two conversions in a row are not needed unless:
             - some conversion is floating-point (overstrict for now), or
+            - some conversion is a vector (overstrict for now), or
             - the intermediate type is narrower than both initial and
               final, or
             - the intermediate type and innermost type differ in signedness,
@@ -6800,6 +6837,7 @@ fold_unary (enum tree_code code, tree type, tree op0)
             - the final type is a pointer type and the precisions of the
               initial and intermediate types differ.  */
          if (! inside_float && ! inter_float && ! final_float
+             && ! inside_vec && ! inter_vec && ! final_vec
              && (inter_prec > inside_prec || inter_prec > final_prec)
              && ! (inside_int && inter_int
                    && inter_unsignedp != inside_unsignedp
@@ -6822,9 +6860,9 @@ fold_unary (enum tree_code code, tree type, tree op0)
        {
          /* Don't leave an assignment inside a conversion
             unless assigning a bitfield.  */
-         tem = build1 (code, type, TREE_OPERAND (op0, 1));
+         tem = fold_build1 (code, type, TREE_OPERAND (op0, 1));
          /* First do the assignment, then return converted constant.  */
-         tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), op0, fold (tem));
+         tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem), op0, tem);
          TREE_NO_WARNING (tem) = 1;
          TREE_USED (tem) = 1;
          return tem;
@@ -7915,10 +7953,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              if (fcode0 == fcode1 && BUILTIN_EXPONENT_P (fcode0))
                {
                  tree expfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
-                 tree arg = build2 (PLUS_EXPR, type,
-                                    TREE_VALUE (TREE_OPERAND (arg0, 1)),
-                                    TREE_VALUE (TREE_OPERAND (arg1, 1)));
-                 tree arglist = build_tree_list (NULL_TREE, fold (arg));
+                 tree arg = fold_build2 (PLUS_EXPR, type,
+                                         TREE_VALUE (TREE_OPERAND (arg0, 1)),
+                                         TREE_VALUE (TREE_OPERAND (arg1, 1)));
+                 tree arglist = build_tree_list (NULL_TREE, arg);
                  return build_function_call_expr (expfn, arglist);
                }
 
@@ -7938,8 +7976,8 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                  if (operand_equal_p (arg01, arg11, 0))
                    {
                      tree powfn = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
-                     tree arg = build2 (MULT_EXPR, type, arg00, arg10);
-                     tree arglist = tree_cons (NULL_TREE, fold (arg),
+                     tree arg = fold_build2 (MULT_EXPR, type, arg00, arg10);
+                     tree arglist = tree_cons (NULL_TREE, arg,
                                                build_tree_list (NULL_TREE,
                                                                 arg01));
                      return build_function_call_expr (powfn, arglist);
@@ -9509,11 +9547,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                      return omit_one_operand (type, integer_one_node, arg0);
                    }
 
-                 tem = build2 (code, type, cval1, cval2);
                  if (save_p)
-                   return save_expr (tem);
+                   return save_expr (build2 (code, type, cval1, cval2));
                  else
-                   return fold (tem);
+                   return fold_build2 (code, type, cval1, cval2);
                }
            }
        }
@@ -9971,6 +10008,21 @@ fold (tree expr)
     case CONST_DECL:
       return fold (DECL_INITIAL (t));
 
+    case ASSERT_EXPR:
+      {
+       /* Given ASSERT_EXPR <Y, COND>, return Y if COND can be folded
+          to boolean_true_node.  If COND folds to boolean_false_node,
+          return ASSERT_EXPR <Y, 0>.  Otherwise, return the original
+          expression.  */
+       tree c = fold (ASSERT_EXPR_COND (t));
+       if (c == boolean_true_node)
+         return ASSERT_EXPR_VAR (t);
+       else if (c == boolean_false_node)
+         return build (ASSERT_EXPR, TREE_TYPE (t), ASSERT_EXPR_VAR (t), c);
+       else
+         return t;
+      }
+
     default:
       return t;
     } /* switch (code) */
@@ -10169,7 +10221,7 @@ fold_checksum_tree (tree expr, struct md5_ctx *ctx, htab_t ht)
 #endif
 
 /* Fold a unary tree expression with code CODE of type TYPE with an
-   operand OP0.  Return a folded expresion if successful.  Otherwise,
+   operand OP0.  Return a folded expression if successful.  Otherwise,
    return a tree expression with code CODE of type TYPE with an
    operand OP0.  */
 
@@ -10184,7 +10236,7 @@ fold_build1 (enum tree_code code, tree type, tree op0)
 }
 
 /* Fold a binary tree expression with code CODE of type TYPE with
-   operands OP0 and OP1.  Return a folded expresion if successful.
+   operands OP0 and OP1.  Return a folded expression if successful.
    Otherwise, return a tree expression with code CODE of type TYPE
    with operands OP0 and OP1.  */
 
@@ -10199,7 +10251,7 @@ fold_build2 (enum tree_code code, tree type, tree op0, tree op1)
 }
 
 /* Fold a ternary tree expression with code CODE of type TYPE with
-   operands OP0, OP1, and OP2.  Return a folded expresion if
+   operands OP0, OP1, and OP2.  Return a folded expression if
    successful.  Otherwise, return a tree expression with code CODE of
    type TYPE with operands OP0, OP1, and OP2.  */
 
@@ -10569,7 +10621,11 @@ tree_expr_nonnegative_p (tree t)
            CASE_BUILTIN_F (BUILT_IN_EXPM1)
            CASE_BUILTIN_F (BUILT_IN_FLOOR)
            CASE_BUILTIN_F (BUILT_IN_FMOD)
+           CASE_BUILTIN_F (BUILT_IN_LCEIL)
            CASE_BUILTIN_F (BUILT_IN_LDEXP)
+           CASE_BUILTIN_F (BUILT_IN_LFLOOR)
+           CASE_BUILTIN_F (BUILT_IN_LLCEIL)
+           CASE_BUILTIN_F (BUILT_IN_LLFLOOR)
            CASE_BUILTIN_F (BUILT_IN_LLRINT)
            CASE_BUILTIN_F (BUILT_IN_LLROUND)
            CASE_BUILTIN_F (BUILT_IN_LRINT)