+2004-07-11  Roger Sayle  <roger@eyesopen.com>
+
+       * builtins.c (fold_builtin_fputs): Don't bother converting the
+       return type to integer_type_node, as we've already checked that
+       the result will be ignored.
+
+       * tree-eh.c (tree_could_trap_p): Add support for -ftrapv such
+       that signed addition, subtraction, multiplication, division,
+       remainder, negation and absolute value may potentially trap.
+
+       * fold-const.c (fold_ignored_result): New function to strip
+       non-side-effecting tree nodes from an expression whose result
+       is ignored.
+       (fold_convert): Call fold_ignored_result when casting a value
+       to VOID_TYPE.
+       (omit_one_operand):  Call fold_ignored_result on the "omitted"
+       operand when building a COMPOUND_EXPR.
+       (pedantic_omit_one_operand): Likewise.
+       * tree.h (fold_ignored_result): Prototype here.
+       * tree-ssa-ccp.c (ccp_fold_builtin): Call fold_ignored_result
+       when we're going to ignore the result.
+
 2004-07-11  Richard Henderson  <rth@redhat.com>
 
        PR tree-opt/16383
 
       abort ();
     }
 
-  return fold_convert (integer_type_node,
-                      build_function_call_expr (fn, arglist));
+  /* These optimizations are only performed when the result is ignored,
+     hence there's no need to cast the result to integer_type_node.  */
+  return build_function_call_expr (fn, arglist);
 }
 
 static void
 
        return fold (build1 (NOP_EXPR, type, arg));
     }
   else if (VOID_TYPE_P (type))
-    return fold (build1 (CONVERT_EXPR, type, arg));
+    return fold (build1 (CONVERT_EXPR, type, fold_ignored_result (arg)));
   abort ();
 }
 \f
   tree t = fold_convert (type, result);
 
   if (TREE_SIDE_EFFECTS (omitted))
-    return build2 (COMPOUND_EXPR, type, omitted, t);
+    return build2 (COMPOUND_EXPR, type, fold_ignored_result (omitted), t);
 
   return non_lvalue (t);
 }
   tree t = fold_convert (type, result);
 
   if (TREE_SIDE_EFFECTS (omitted))
-    return build2 (COMPOUND_EXPR, type, omitted, t);
+    return build2 (COMPOUND_EXPR, type, fold_ignored_result (omitted), t);
 
   return pedantic_non_lvalue (t);
 }
   return build1 (INDIRECT_REF, type, t);
 }
 
+/* Strip non-trapping, non-side-effecting tree nodes from an expression
+   whose result is ignored.  The type of the returned tree need not be
+   the same as the original expression.  */
+
+tree
+fold_ignored_result (tree t)
+{
+  if (!TREE_SIDE_EFFECTS (t))
+    return integer_zero_node;
+
+  for (;;)
+    switch (TREE_CODE_CLASS (TREE_CODE (t)))
+      {
+      case '1':
+       t = TREE_OPERAND (t, 0);
+       break;
+
+      case '2':
+      case '<':
+       if (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)))
+         t = TREE_OPERAND (t, 0);
+       else if (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 0)))
+         t = TREE_OPERAND (t, 1);
+       else
+         return t;
+       break;
+
+      case 'e':
+       switch (TREE_CODE (t))
+         {
+         case COMPOUND_EXPR:
+           if (TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)))
+             return t;
+           t = TREE_OPERAND (t, 0);
+           break;
+
+         case COND_EXPR:
+           if (TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1))
+               || TREE_SIDE_EFFECTS (TREE_OPERAND (t, 2)))
+             return t;
+           t = TREE_OPERAND (t, 0);
+           break;
+
+         default:
+           return t;
+         }
+       break;
+
+      default:
+       return t;
+      }
+}
+
 #include "gt-fold-const.h"
 
   bool honor_nans = false;
   bool honor_snans = false;
   bool fp_operation = false;
+  bool honor_trapv = false;
   tree t, base, idx;
 
   if (TREE_CODE_CLASS (code) == '<'
          honor_nans = flag_trapping_math && !flag_finite_math_only;
          honor_snans = flag_signaling_nans != 0;
        }
+      else if (INTEGRAL_TYPE_P (t) && TYPE_TRAP_SIGNED (t))
+       honor_trapv = true;
     }
 
   switch (code)
     case ROUND_MOD_EXPR:
     case TRUNC_MOD_EXPR:
     case RDIV_EXPR:
-      if (honor_snans)
+      if (honor_snans || honor_trapv)
        return true;
       if (fp_operation && flag_trapping_math)
        return true;
     case NEGATE_EXPR:
     case ABS_EXPR:
     case CONJ_EXPR:
-      /* These operations don't trap even with floating point.  */
+      /* These operations don't trap with floating point.  */
+      if (honor_trapv)
+       return true;
+      return false;
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+      /* Any floating arithmetic may trap.  */
+      if (fp_operation && flag_trapping_math)
+       return true;
+      if (honor_trapv)
+       return true;
       return false;
 
     default:
 
     }
 
   if (result && ignore)
-    {
-      /* STRIP_NOPS isn't strong enough -- it'll stop when we change modes,
-        but given that we're ignoring the result, we don't care what type
-        is being returned by the transformed function.  */
-      while (TREE_CODE (result) == NOP_EXPR
-            || TREE_CODE (result) == CONVERT_EXPR
-            || TREE_CODE (result) == NON_LVALUE_EXPR)
-       result = TREE_OPERAND (result, 0);
-    }
-
+    result = fold_ignored_result (result);
   return result;
 }
 
 
 extern tree fold_initializer (tree);
 extern tree fold_convert (tree, tree);
 extern tree fold_single_bit_test (enum tree_code, tree, tree, tree);
+extern tree fold_ignored_result (tree);
 extern tree fold_abs_const (tree, tree);
 
 extern int force_fit_type (tree, int);