OSDN Git Service

Revert my previous commit.
[pf3gnuchains/gcc-fork.git] / gcc / convert.c
index ae7b2c3..f82604e 100644 (file)
@@ -1,12 +1,13 @@
-/* Utility routines for data type conversion for GNU C.
-   Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1997,
-   1998 Free Software Foundation, Inc.
+/* Utility routines for data type conversion for GCC.
+   Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1997, 1998,
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 
 /* These routines are somewhat language-independent utility function
 
 
 /* These routines are somewhat language-independent utility function
@@ -33,39 +33,37 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "toplev.h"
 #include "langhooks.h"
 #include "real.h"
 #include "toplev.h"
 #include "langhooks.h"
 #include "real.h"
-/* Convert EXPR to some pointer or reference type TYPE.
+#include "fixed-value.h"
 
 
+/* Convert EXPR to some pointer or reference type TYPE.
    EXPR must be pointer, reference, integer, enumeral, or literal zero;
    in other cases error is called.  */
 
 tree
    EXPR must be pointer, reference, integer, enumeral, or literal zero;
    in other cases error is called.  */
 
 tree
-convert_to_pointer (type, expr)
-     tree type, expr;
+convert_to_pointer (tree type, tree expr)
 {
 {
+  if (TREE_TYPE (expr) == type)
+    return expr;
+
+  /* Propagate overflow to the NULL pointer.  */
   if (integer_zerop (expr))
   if (integer_zerop (expr))
-    {
-      expr = build_int_2 (0, 0);
-      TREE_TYPE (expr) = type;
-      return expr;
-    }
+    return force_fit_type_double (type, 0, 0, 0, TREE_OVERFLOW (expr));
 
   switch (TREE_CODE (TREE_TYPE (expr)))
     {
     case POINTER_TYPE:
     case REFERENCE_TYPE:
 
   switch (TREE_CODE (TREE_TYPE (expr)))
     {
     case POINTER_TYPE:
     case REFERENCE_TYPE:
-      return build1 (NOP_EXPR, type, expr);
+      return fold_build1 (NOP_EXPR, type, expr);
 
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
 
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
-    case CHAR_TYPE:
-      if (TYPE_PRECISION (TREE_TYPE (expr)) == POINTER_SIZE)
-       return build1 (CONVERT_EXPR, type, expr);
+      if (TYPE_PRECISION (TREE_TYPE (expr)) != POINTER_SIZE)
+       expr = fold_build1 (NOP_EXPR,
+                            lang_hooks.types.type_for_size (POINTER_SIZE, 0),
+                           expr);
+      return fold_build1 (CONVERT_EXPR, type, expr);
 
 
-      return
-       convert_to_pointer (type,
-                           convert ((*lang_hooks.types.type_for_size)
-                                    (POINTER_SIZE, 0), expr));
 
     default:
       error ("cannot convert to a pointer type");
 
     default:
       error ("cannot convert to a pointer type");
@@ -75,8 +73,7 @@ convert_to_pointer (type, expr)
 
 /* Avoid any floating point extensions from EXP.  */
 tree
 
 /* Avoid any floating point extensions from EXP.  */
 tree
-strip_float_extensions (exp)
-     tree exp;
+strip_float_extensions (tree exp)
 {
   tree sub, expt, subt;
 
 {
   tree sub, expt, subt;
 
@@ -101,7 +98,8 @@ strip_float_extensions (exp)
        return build_real (type, real_value_truncate (TYPE_MODE (type), orig));
     }
 
        return build_real (type, real_value_truncate (TYPE_MODE (type), orig));
     }
 
-  if (TREE_CODE (exp) != NOP_EXPR)
+  if (TREE_CODE (exp) != NOP_EXPR
+      && TREE_CODE (exp) != CONVERT_EXPR)
     return exp;
 
   sub = TREE_OPERAND (exp, 0);
     return exp;
 
   sub = TREE_OPERAND (exp, 0);
@@ -120,121 +118,138 @@ strip_float_extensions (exp)
 
 /* Convert EXPR to some floating-point type TYPE.
 
 
 /* Convert EXPR to some floating-point type TYPE.
 
-   EXPR must be float, integer, or enumeral;
+   EXPR must be float, fixed-point, integer, or enumeral;
    in other cases error is called.  */
 
 tree
    in other cases error is called.  */
 
 tree
-convert_to_real (type, expr)
-     tree type, expr;
+convert_to_real (tree type, tree expr)
 {
 {
+  enum built_in_function fcode = builtin_mathfn_code (expr);
   tree itype = TREE_TYPE (expr);
 
   /* Disable until we figure out how to decide whether the functions are
      present in runtime.  */
   tree itype = TREE_TYPE (expr);
 
   /* Disable until we figure out how to decide whether the functions are
      present in runtime.  */
-#if 0
-  enum built_in_function fcode = builtin_mathfn_code (expr);
-
   /* Convert (float)sqrt((double)x) where x is float into sqrtf(x) */
   /* Convert (float)sqrt((double)x) where x is float into sqrtf(x) */
-  if ((fcode == BUILT_IN_SQRT
-       || fcode == BUILT_IN_SQRTL
-       || fcode == BUILT_IN_SIN
-       || fcode == BUILT_IN_SINL
-       || fcode == BUILT_IN_COS
-       || fcode == BUILT_IN_COSL
-       || fcode == BUILT_IN_EXP
-       || fcode == BUILT_IN_EXPL)
-      && optimize
+  if (optimize
       && (TYPE_MODE (type) == TYPE_MODE (double_type_node)
           || TYPE_MODE (type) == TYPE_MODE (float_type_node)))
     {
       && (TYPE_MODE (type) == TYPE_MODE (double_type_node)
           || TYPE_MODE (type) == TYPE_MODE (float_type_node)))
     {
-      tree arg0 = strip_float_extensions (TREE_VALUE (TREE_OPERAND (expr, 1)));
-      tree newtype = type;
-
-      /* We have (outertype)sqrt((innertype)x).  Choose the wider mode from
-        the both as the safe type for operation.  */
-      if (TYPE_PRECISION (TREE_TYPE (arg0)) > TYPE_PRECISION (type))
-       newtype = TREE_TYPE (arg0);
-
-      /* Be careful about integer to fp conversions.
-        These may overflow still.  */
-      if (FLOAT_TYPE_P (TREE_TYPE (arg0))
-         && TYPE_PRECISION (newtype) <= TYPE_PRECISION (itype)
-         && (TYPE_MODE (newtype) == TYPE_MODE (double_type_node)
-             || TYPE_MODE (newtype) == TYPE_MODE (float_type_node)))
-       {
-         tree arglist;
-         if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
-           switch (fcode)
-             {
-             case BUILT_IN_SQRT:
-             case BUILT_IN_SQRTL:
-               fcode = BUILT_IN_SQRTF;
-               break;
-             case BUILT_IN_SIN:
-             case BUILT_IN_SINL:
-               fcode = BUILT_IN_SINF;
-               break;
-             case BUILT_IN_COS:
-             case BUILT_IN_COSL:
-               fcode = BUILT_IN_COSF;
-               break;
-             case BUILT_IN_EXP:
-             case BUILT_IN_EXPL:
-               fcode = BUILT_IN_EXPF;
-               break;
-             default:
-               abort ();
-             }
-         else
-           switch (fcode)
-             {
-             case BUILT_IN_SQRT:
-             case BUILT_IN_SQRTL:
-               fcode = BUILT_IN_SQRT;
-               break;
-             case BUILT_IN_SIN:
-             case BUILT_IN_SINL:
-               fcode = BUILT_IN_SIN;
-               break;
-             case BUILT_IN_COS:
-             case BUILT_IN_COSL:
-               fcode = BUILT_IN_COS;
-               break;
-             case BUILT_IN_EXP:
-             case BUILT_IN_EXPL:
-               fcode = BUILT_IN_EXP;
-               break;
-             default:
-               abort ();
-             }
-
-         /* ??? Fortran frontend does not initialize built_in_decls.
-            For some reason creating the decl using builtin_function does not
-            work as it should.  */
-         if (built_in_decls [fcode])
+      switch (fcode)
+        {
+#define CASE_MATHFN(FN) case BUILT_IN_##FN: case BUILT_IN_##FN##L:
+         CASE_MATHFN (ACOS)
+         CASE_MATHFN (ACOSH)
+         CASE_MATHFN (ASIN)
+         CASE_MATHFN (ASINH)
+         CASE_MATHFN (ATAN)
+         CASE_MATHFN (ATANH)
+         CASE_MATHFN (CBRT)
+         CASE_MATHFN (COS)
+         CASE_MATHFN (COSH)
+         CASE_MATHFN (ERF)
+         CASE_MATHFN (ERFC)
+         CASE_MATHFN (EXP)
+         CASE_MATHFN (EXP10)
+         CASE_MATHFN (EXP2)
+         CASE_MATHFN (EXPM1)
+         CASE_MATHFN (FABS)
+         CASE_MATHFN (GAMMA)
+         CASE_MATHFN (J0)
+         CASE_MATHFN (J1)
+         CASE_MATHFN (LGAMMA)
+         CASE_MATHFN (LOG)
+         CASE_MATHFN (LOG10)
+         CASE_MATHFN (LOG1P)
+         CASE_MATHFN (LOG2)
+         CASE_MATHFN (LOGB)
+         CASE_MATHFN (POW10)
+         CASE_MATHFN (SIN)
+         CASE_MATHFN (SINH)
+         CASE_MATHFN (SQRT)
+         CASE_MATHFN (TAN)
+         CASE_MATHFN (TANH)
+         CASE_MATHFN (TGAMMA)
+         CASE_MATHFN (Y0)
+         CASE_MATHFN (Y1)
+#undef CASE_MATHFN
            {
            {
-             arglist = build_tree_list (NULL_TREE, fold (convert_to_real (newtype, arg0)));
-             expr = build_function_call_expr (built_in_decls [fcode], arglist);
-             if (newtype == type)
-               return expr;
+             tree arg0 = strip_float_extensions (CALL_EXPR_ARG (expr, 0));
+             tree newtype = type;
+
+             /* We have (outertype)sqrt((innertype)x).  Choose the wider mode from
+                the both as the safe type for operation.  */
+             if (TYPE_PRECISION (TREE_TYPE (arg0)) > TYPE_PRECISION (type))
+               newtype = TREE_TYPE (arg0);
+
+             /* Be careful about integer to fp conversions.
+                These may overflow still.  */
+             if (FLOAT_TYPE_P (TREE_TYPE (arg0))
+                 && TYPE_PRECISION (newtype) < TYPE_PRECISION (itype)
+                 && (TYPE_MODE (newtype) == TYPE_MODE (double_type_node)
+                     || TYPE_MODE (newtype) == TYPE_MODE (float_type_node)))
+               {
+                 tree fn = mathfn_built_in (newtype, fcode);
+
+                 if (fn)
+                 {
+                   tree arg = fold (convert_to_real (newtype, arg0));
+                   expr = build_call_expr (fn, 1, arg);
+                   if (newtype == type)
+                     return expr;
+                 }
+               }
            }
            }
+       default:
+         break;
+       }
+    }
+  if (optimize
+      && (((fcode == BUILT_IN_FLOORL
+          || fcode == BUILT_IN_CEILL
+          || fcode == BUILT_IN_ROUNDL
+          || fcode == BUILT_IN_RINTL
+          || fcode == BUILT_IN_TRUNCL
+          || fcode == BUILT_IN_NEARBYINTL)
+         && (TYPE_MODE (type) == TYPE_MODE (double_type_node)
+             || TYPE_MODE (type) == TYPE_MODE (float_type_node)))
+         || ((fcode == BUILT_IN_FLOOR
+              || fcode == BUILT_IN_CEIL
+              || fcode == BUILT_IN_ROUND
+              || fcode == BUILT_IN_RINT
+              || fcode == BUILT_IN_TRUNC
+              || fcode == BUILT_IN_NEARBYINT)
+             && (TYPE_MODE (type) == TYPE_MODE (float_type_node)))))
+    {
+      tree fn = mathfn_built_in (type, fcode);
+
+      if (fn)
+       {
+         tree arg = strip_float_extensions (CALL_EXPR_ARG (expr, 0));
+
+         /* Make sure (type)arg0 is an extension, otherwise we could end up
+            changing (float)floor(double d) into floorf((float)d), which is
+            incorrect because (float)d uses round-to-nearest and can round
+            up to the next integer.  */
+         if (TYPE_PRECISION (type) >= TYPE_PRECISION (TREE_TYPE (arg)))
+           return build_call_expr (fn, 1, fold (convert_to_real (type, arg)));
        }
     }
        }
     }
-#endif
 
   /* Propagate the cast into the operation.  */
   if (itype != type && FLOAT_TYPE_P (type))
     switch (TREE_CODE (expr))
       {
 
   /* Propagate the cast into the operation.  */
   if (itype != type && FLOAT_TYPE_P (type))
     switch (TREE_CODE (expr))
       {
-       /* convert (float)-x into -(float)x.  This is always safe.  */
+       /* Convert (float)-x into -(float)x.  This is safe for
+          round-to-nearest rounding mode.  */
        case ABS_EXPR:
        case NEGATE_EXPR:
        case ABS_EXPR:
        case NEGATE_EXPR:
-         if (TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (expr)))
+         if (!flag_rounding_math
+             && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (expr)))
            return build1 (TREE_CODE (expr), type,
                           fold (convert_to_real (type,
                                                  TREE_OPERAND (expr, 0))));
          break;
            return build1 (TREE_CODE (expr), type,
                           fold (convert_to_real (type,
                                                  TREE_OPERAND (expr, 0))));
          break;
-       /* convert (outertype)((innertype0)a+(innertype1)b)
+       /* Convert (outertype)((innertype0)a+(innertype1)b)
           into ((newtype)a+(newtype)b) where newtype
           is the widest mode from all of these.  */
        case PLUS_EXPR:
           into ((newtype)a+(newtype)b) where newtype
           is the widest mode from all of these.  */
        case PLUS_EXPR:
@@ -249,15 +264,37 @@ convert_to_real (type, expr)
                 && FLOAT_TYPE_P (TREE_TYPE (arg1)))
               {
                  tree newtype = type;
                 && FLOAT_TYPE_P (TREE_TYPE (arg1)))
               {
                  tree newtype = type;
+
+                 if (TYPE_MODE (TREE_TYPE (arg0)) == SDmode
+                     || TYPE_MODE (TREE_TYPE (arg1)) == SDmode)
+                   newtype = dfloat32_type_node;
+                 if (TYPE_MODE (TREE_TYPE (arg0)) == DDmode
+                     || TYPE_MODE (TREE_TYPE (arg1)) == DDmode)
+                   newtype = dfloat64_type_node;
+                 if (TYPE_MODE (TREE_TYPE (arg0)) == TDmode
+                     || TYPE_MODE (TREE_TYPE (arg1)) == TDmode)
+                    newtype = dfloat128_type_node;
+                 if (newtype == dfloat32_type_node
+                     || newtype == dfloat64_type_node
+                     || newtype == dfloat128_type_node)
+                   {
+                     expr = build2 (TREE_CODE (expr), newtype,
+                                    fold (convert_to_real (newtype, arg0)),
+                                    fold (convert_to_real (newtype, arg1)));
+                     if (newtype == type)
+                       return expr;
+                     break;
+                   }
+
                  if (TYPE_PRECISION (TREE_TYPE (arg0)) > TYPE_PRECISION (newtype))
                    newtype = TREE_TYPE (arg0);
                  if (TYPE_PRECISION (TREE_TYPE (arg1)) > TYPE_PRECISION (newtype))
                    newtype = TREE_TYPE (arg1);
                  if (TYPE_PRECISION (newtype) < TYPE_PRECISION (itype))
                    {
                  if (TYPE_PRECISION (TREE_TYPE (arg0)) > TYPE_PRECISION (newtype))
                    newtype = TREE_TYPE (arg0);
                  if (TYPE_PRECISION (TREE_TYPE (arg1)) > TYPE_PRECISION (newtype))
                    newtype = TREE_TYPE (arg1);
                  if (TYPE_PRECISION (newtype) < TYPE_PRECISION (itype))
                    {
-                     expr = build (TREE_CODE (expr), newtype,
-                                   fold (convert_to_real (newtype, arg0)),
-                                   fold (convert_to_real (newtype, arg1)));
+                     expr = build2 (TREE_CODE (expr), newtype,
+                                    fold (convert_to_real (newtype, arg0)),
+                                    fold (convert_to_real (newtype, arg1)));
                      if (newtype == type)
                        return expr;
                    }
                      if (newtype == type)
                        return expr;
                    }
@@ -271,19 +308,25 @@ convert_to_real (type, expr)
   switch (TREE_CODE (TREE_TYPE (expr)))
     {
     case REAL_TYPE:
   switch (TREE_CODE (TREE_TYPE (expr)))
     {
     case REAL_TYPE:
-      return build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
-                    type, expr);
+      /* Ignore the conversion if we don't need to store intermediate
+        results and neither type is a decimal float.  */
+      return build1 ((flag_float_store
+                    || DECIMAL_FLOAT_TYPE_P (type)
+                    || DECIMAL_FLOAT_TYPE_P (itype))
+                    ? CONVERT_EXPR : NOP_EXPR, type, expr);
 
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
 
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
-    case CHAR_TYPE:
       return build1 (FLOAT_EXPR, type, expr);
 
       return build1 (FLOAT_EXPR, type, expr);
 
+    case FIXED_POINT_TYPE:
+      return build1 (FIXED_CONVERT_EXPR, type, expr);
+
     case COMPLEX_TYPE:
       return convert (type,
     case COMPLEX_TYPE:
       return convert (type,
-                     fold (build1 (REALPART_EXPR,
-                                   TREE_TYPE (TREE_TYPE (expr)), expr)));
+                     fold_build1 (REALPART_EXPR,
+                                  TREE_TYPE (TREE_TYPE (expr)), expr));
 
     case POINTER_TYPE:
     case REFERENCE_TYPE:
 
     case POINTER_TYPE:
     case REFERENCE_TYPE:
@@ -298,15 +341,14 @@ convert_to_real (type, expr)
 
 /* Convert EXPR to some integer (or enum) type TYPE.
 
 
 /* Convert EXPR to some integer (or enum) type TYPE.
 
-   EXPR must be pointer, integer, discrete (enum, char, or bool), float, or
-   vector; in other cases error is called.
+   EXPR must be pointer, integer, discrete (enum, char, or bool), float,
+   fixed-point or vector; in other cases error is called.
 
    The result of this is always supposed to be a newly created tree node
    not in use in any existing structure.  */
 
 tree
 
    The result of this is always supposed to be a newly created tree node
    not in use in any existing structure.  */
 
 tree
-convert_to_integer (type, expr)
-     tree type, expr;
+convert_to_integer (tree type, tree expr)
 {
   enum tree_code ex_form = TREE_CODE (expr);
   tree intype = TREE_TYPE (expr);
 {
   enum tree_code ex_form = TREE_CODE (expr);
   tree intype = TREE_TYPE (expr);
@@ -321,46 +363,111 @@ convert_to_integer (type, expr)
       return error_mark_node;
     }
 
       return error_mark_node;
     }
 
+  /* Convert e.g. (long)round(d) -> lround(d).  */
+  /* If we're converting to char, we may encounter differing behavior
+     between converting from double->char vs double->long->char.
+     We're in "undefined" territory but we prefer to be conservative,
+     so only proceed in "unsafe" math mode.  */
+  if (optimize
+      && (flag_unsafe_math_optimizations
+         || (long_integer_type_node
+             && outprec >= TYPE_PRECISION (long_integer_type_node))))
+    {
+      tree s_expr = strip_float_extensions (expr);
+      tree s_intype = TREE_TYPE (s_expr);
+      const enum built_in_function fcode = builtin_mathfn_code (s_expr);
+      tree fn = 0;
+      
+      switch (fcode)
+        {
+       CASE_FLT_FN (BUILT_IN_CEIL):
+         /* Only convert in ISO C99 mode.  */
+         if (!TARGET_C99_FUNCTIONS)
+           break;
+         if (outprec < TYPE_PRECISION (long_integer_type_node)
+             || (outprec == TYPE_PRECISION (long_integer_type_node)
+                 && !TYPE_UNSIGNED (type)))
+           fn = mathfn_built_in (s_intype, BUILT_IN_LCEIL);
+         else if (outprec == TYPE_PRECISION (long_long_integer_type_node)
+                  && !TYPE_UNSIGNED (type))
+           fn = mathfn_built_in (s_intype, BUILT_IN_LLCEIL);
+         break;
+
+       CASE_FLT_FN (BUILT_IN_FLOOR):
+         /* Only convert in ISO C99 mode.  */
+         if (!TARGET_C99_FUNCTIONS)
+           break;
+         if (outprec < TYPE_PRECISION (long_integer_type_node)
+             || (outprec == TYPE_PRECISION (long_integer_type_node)
+                 && !TYPE_UNSIGNED (type)))
+           fn = mathfn_built_in (s_intype, BUILT_IN_LFLOOR);
+         else if (outprec == TYPE_PRECISION (long_long_integer_type_node)
+                  && !TYPE_UNSIGNED (type))
+           fn = mathfn_built_in (s_intype, BUILT_IN_LLFLOOR);
+         break;
+
+       CASE_FLT_FN (BUILT_IN_ROUND):
+         if (outprec < TYPE_PRECISION (long_integer_type_node)
+             || (outprec == TYPE_PRECISION (long_integer_type_node)
+                 && !TYPE_UNSIGNED (type)))
+           fn = mathfn_built_in (s_intype, BUILT_IN_LROUND);
+         else if (outprec == TYPE_PRECISION (long_long_integer_type_node)
+                  && !TYPE_UNSIGNED (type))
+           fn = mathfn_built_in (s_intype, BUILT_IN_LLROUND);
+         break;
+
+       CASE_FLT_FN (BUILT_IN_NEARBYINT):
+         /* Only convert nearbyint* if we can ignore math exceptions.  */
+         if (flag_trapping_math)
+           break;
+         /* ... Fall through ...  */
+       CASE_FLT_FN (BUILT_IN_RINT):
+         if (outprec < TYPE_PRECISION (long_integer_type_node)
+             || (outprec == TYPE_PRECISION (long_integer_type_node)
+                 && !TYPE_UNSIGNED (type)))
+           fn = mathfn_built_in (s_intype, BUILT_IN_LRINT);
+         else if (outprec == TYPE_PRECISION (long_long_integer_type_node)
+                  && !TYPE_UNSIGNED (type))
+           fn = mathfn_built_in (s_intype, BUILT_IN_LLRINT);
+         break;
+
+       CASE_FLT_FN (BUILT_IN_TRUNC):
+         return convert_to_integer (type, CALL_EXPR_ARG (s_expr, 0));
+
+       default:
+         break;
+       }
+      
+      if (fn)
+        {
+         tree newexpr = build_call_expr (fn, 1, CALL_EXPR_ARG (s_expr, 0));
+         return convert_to_integer (type, newexpr);
+       }
+    }
+
   switch (TREE_CODE (intype))
     {
     case POINTER_TYPE:
     case REFERENCE_TYPE:
       if (integer_zerop (expr))
   switch (TREE_CODE (intype))
     {
     case POINTER_TYPE:
     case REFERENCE_TYPE:
       if (integer_zerop (expr))
-       expr = integer_zero_node;
-      else
-       expr = fold (build1 (CONVERT_EXPR, (*lang_hooks.types.type_for_size)
-                            (POINTER_SIZE, 0), expr));
+       return build_int_cst (type, 0);
 
 
-      return convert_to_integer (type, expr);
+      /* Convert to an unsigned integer of the correct width first,
+        and from there widen/truncate to the required type.  */
+      expr = fold_build1 (CONVERT_EXPR,
+                         lang_hooks.types.type_for_size (POINTER_SIZE, 0),
+                         expr);
+      return fold_convert (type, expr);
 
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
 
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
-    case CHAR_TYPE:
       /* If this is a logical operation, which just returns 0 or 1, we can
       /* If this is a logical operation, which just returns 0 or 1, we can
-        change the type of the expression.  For some logical operations,
-        we must also change the types of the operands to maintain type
-        correctness.  */
+        change the type of the expression.  */
 
 
-      if (TREE_CODE_CLASS (ex_form) == '<')
+      if (TREE_CODE_CLASS (ex_form) == tcc_comparison)
        {
        {
-         TREE_TYPE (expr) = type;
-         return expr;
-       }
-
-      else if (ex_form == TRUTH_AND_EXPR || ex_form == TRUTH_ANDIF_EXPR
-              || ex_form == TRUTH_OR_EXPR || ex_form == TRUTH_ORIF_EXPR
-              || ex_form == TRUTH_XOR_EXPR)
-       {
-         TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0));
-         TREE_OPERAND (expr, 1) = convert (type, TREE_OPERAND (expr, 1));
-         TREE_TYPE (expr) = type;
-         return expr;
-       }
-
-      else if (ex_form == TRUTH_NOT_EXPR)
-       {
-         TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0));
+         expr = copy_node (expr);
          TREE_TYPE (expr) = type;
          return expr;
        }
          TREE_TYPE (expr) = type;
          return expr;
        }
@@ -370,7 +477,34 @@ convert_to_integer (type, expr)
         we are truncating EXPR.  */
 
       else if (outprec >= inprec)
         we are truncating EXPR.  */
 
       else if (outprec >= inprec)
-       return build1 (NOP_EXPR, type, expr);
+       {
+         enum tree_code code;
+         tree tem;
+
+         /* If the precision of the EXPR's type is K bits and the
+            destination mode has more bits, and the sign is changing,
+            it is not safe to use a NOP_EXPR.  For example, suppose
+            that EXPR's type is a 3-bit unsigned integer type, the
+            TYPE is a 3-bit signed integer type, and the machine mode
+            for the types is 8-bit QImode.  In that case, the
+            conversion necessitates an explicit sign-extension.  In
+            the signed-to-unsigned case the high-order bits have to
+            be cleared.  */
+         if (TYPE_UNSIGNED (type) != TYPE_UNSIGNED (TREE_TYPE (expr))
+             && (TYPE_PRECISION (TREE_TYPE (expr))
+                 != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (expr)))))
+           code = CONVERT_EXPR;
+         else
+           code = NOP_EXPR;
+
+         tem = fold_unary (code, type, expr);
+         if (tem)
+           return tem;
+
+         tem = build1 (code, type, expr);
+         TREE_NO_WARNING (tem) = 1;
+         return tem;
+       }
 
       /* If TYPE is an enumeral type or a type with a precision less
         than the number of bits in its mode, do the conversion to the
 
       /* If TYPE is an enumeral type or a type with a precision less
         than the number of bits in its mode, do the conversion to the
@@ -379,8 +513,8 @@ convert_to_integer (type, expr)
       else if (TREE_CODE (type) == ENUMERAL_TYPE
               || outprec != GET_MODE_BITSIZE (TYPE_MODE (type)))
        return build1 (NOP_EXPR, type,
       else if (TREE_CODE (type) == ENUMERAL_TYPE
               || outprec != GET_MODE_BITSIZE (TYPE_MODE (type)))
        return build1 (NOP_EXPR, type,
-                      convert ((*lang_hooks.types.type_for_mode)
-                               (TYPE_MODE (type), TREE_UNSIGNED (type)),
+                      convert (lang_hooks.types.type_for_mode
+                               (TYPE_MODE (type), TYPE_UNSIGNED (type)),
                                expr));
 
       /* Here detect when we can distribute the truncation down past some
                                expr));
 
       /* Here detect when we can distribute the truncation down past some
@@ -409,9 +543,7 @@ convert_to_integer (type, expr)
          /* We can pass truncation down through right shifting
             when the shift count is a nonpositive constant.  */
          if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
          /* We can pass truncation down through right shifting
             when the shift count is a nonpositive constant.  */
          if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
-             && tree_int_cst_lt (TREE_OPERAND (expr, 1),
-                                 convert (TREE_TYPE (TREE_OPERAND (expr, 1)),
-                                          integer_one_node)))
+             && tree_int_cst_sgn (TREE_OPERAND (expr, 1)) <= 0)
            goto trunc1;
          break;
 
            goto trunc1;
          break;
 
@@ -421,7 +553,7 @@ convert_to_integer (type, expr)
             the target type is unsigned.  */
          if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
              && tree_int_cst_sgn (TREE_OPERAND (expr, 1)) >= 0
             the target type is unsigned.  */
          if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
              && tree_int_cst_sgn (TREE_OPERAND (expr, 1)) >= 0
-             && TREE_UNSIGNED (type)
+             && TYPE_UNSIGNED (type)
              && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
            {
              /* If shift count is less than the width of the truncated type,
              && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
            {
              /* If shift count is less than the width of the truncated type,
@@ -437,12 +569,12 @@ convert_to_integer (type, expr)
                     but (int) a << 32 is undefined and would get a
                     warning.  */
 
                     but (int) a << 32 is undefined and would get a
                     warning.  */
 
-                 tree t = convert_to_integer (type, integer_zero_node);
+                 tree t = build_int_cst (type, 0);
 
                  /* If the original expression had side-effects, we must
                     preserve it.  */
                  if (TREE_SIDE_EFFECTS (expr))
 
                  /* If the original expression had side-effects, we must
                     preserve it.  */
                  if (TREE_SIDE_EFFECTS (expr))
-                   return build (COMPOUND_EXPR, type, expr, t);
+                   return build2 (COMPOUND_EXPR, type, expr, t);
                  else
                    return t;
                }
                  else
                    return t;
                }
@@ -463,8 +595,8 @@ convert_to_integer (type, expr)
                && outprec >= TYPE_PRECISION (TREE_TYPE (arg1))
                /* If signedness of arg0 and arg1 don't match,
                   we can't necessarily find a type to compare them in.  */
                && outprec >= TYPE_PRECISION (TREE_TYPE (arg1))
                /* If signedness of arg0 and arg1 don't match,
                   we can't necessarily find a type to compare them in.  */
-               && (TREE_UNSIGNED (TREE_TYPE (arg0))
-                   == TREE_UNSIGNED (TREE_TYPE (arg1))))
+               && (TYPE_UNSIGNED (TREE_TYPE (arg0))
+                   == TYPE_UNSIGNED (TREE_TYPE (arg1))))
              goto trunc1;
            break;
          }
              goto trunc1;
            break;
          }
@@ -474,7 +606,6 @@ convert_to_integer (type, expr)
        case BIT_AND_EXPR:
        case BIT_IOR_EXPR:
        case BIT_XOR_EXPR:
        case BIT_AND_EXPR:
        case BIT_IOR_EXPR:
        case BIT_XOR_EXPR:
-       case BIT_ANDTC_EXPR:
        trunc1:
          {
            tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type);
        trunc1:
          {
            tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type);
@@ -492,8 +623,8 @@ convert_to_integer (type, expr)
                /* Can't do arithmetic in enumeral types
                   so use an integer type that will hold the values.  */
                if (TREE_CODE (typex) == ENUMERAL_TYPE)
                /* Can't do arithmetic in enumeral types
                   so use an integer type that will hold the values.  */
                if (TREE_CODE (typex) == ENUMERAL_TYPE)
-                 typex = (*lang_hooks.types.type_for_size)
-                   (TYPE_PRECISION (typex), TREE_UNSIGNED (typex));
+                 typex = lang_hooks.types.type_for_size
+                   (TYPE_PRECISION (typex), TYPE_UNSIGNED (typex));
 
                /* But now perhaps TYPEX is as wide as INPREC.
                   In that case, do nothing special here.
 
                /* But now perhaps TYPEX is as wide as INPREC.
                   In that case, do nothing special here.
@@ -503,7 +634,7 @@ convert_to_integer (type, expr)
                    /* Don't do unsigned arithmetic where signed was wanted,
                       or vice versa.
                       Exception: if both of the original operands were
                    /* Don't do unsigned arithmetic where signed was wanted,
                       or vice versa.
                       Exception: if both of the original operands were
-                      unsigned then we can safely do the work as unsigned.
+                      unsigned then we can safely do the work as unsigned.
                       Exception: shift operations take their type solely
                       from the first argument.
                       Exception: the LSHIFT_EXPR case above requires that
                       Exception: shift operations take their type solely
                       from the first argument.
                       Exception: the LSHIFT_EXPR case above requires that
@@ -511,22 +642,30 @@ convert_to_integer (type, expr)
                       signed-overflow undefinedness.
                       And we may need to do it as unsigned
                       if we truncate to the original size.  */
                       signed-overflow undefinedness.
                       And we may need to do it as unsigned
                       if we truncate to the original size.  */
-                   if (TREE_UNSIGNED (TREE_TYPE (expr))
-                       || (TREE_UNSIGNED (TREE_TYPE (arg0))
-                           && (TREE_UNSIGNED (TREE_TYPE (arg1))
+                   if (TYPE_UNSIGNED (TREE_TYPE (expr))
+                       || (TYPE_UNSIGNED (TREE_TYPE (arg0))
+                           && (TYPE_UNSIGNED (TREE_TYPE (arg1))
                                || ex_form == LSHIFT_EXPR
                                || ex_form == RSHIFT_EXPR
                                || ex_form == LROTATE_EXPR
                                || ex_form == RROTATE_EXPR))
                                || ex_form == LSHIFT_EXPR
                                || ex_form == RSHIFT_EXPR
                                || ex_form == LROTATE_EXPR
                                || ex_form == RROTATE_EXPR))
-                       || ex_form == LSHIFT_EXPR)
-                     typex = (*lang_hooks.types.unsigned_type) (typex);
+                       || ex_form == LSHIFT_EXPR
+                       /* If we have !flag_wrapv, and either ARG0 or
+                          ARG1 is of a signed type, we have to do
+                          PLUS_EXPR or MINUS_EXPR in an unsigned
+                          type.  Otherwise, we would introduce
+                          signed-overflow undefinedness.  */
+                       || ((!TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0))
+                            || !TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1)))
+                           && (ex_form == PLUS_EXPR
+                               || ex_form == MINUS_EXPR)))
+                     typex = unsigned_type_for (typex);
                    else
                    else
-                     typex = (*lang_hooks.types.signed_type) (typex);
+                     typex = signed_type_for (typex);
                    return convert (type,
                    return convert (type,
-                                   fold (build (ex_form, typex,
+                                   fold_build2 (ex_form, typex,
                                                 convert (typex, arg0),
                                                 convert (typex, arg0),
-                                                convert (typex, arg1),
-                                                0)));
+                                                convert (typex, arg1)));
                  }
              }
          }
                  }
              }
          }
@@ -537,30 +676,18 @@ convert_to_integer (type, expr)
          /* This is not correct for ABS_EXPR,
             since we must test the sign before truncation.  */
          {
          /* This is not correct for ABS_EXPR,
             since we must test the sign before truncation.  */
          {
-           tree typex = type;
-
-           /* Can't do arithmetic in enumeral types
-              so use an integer type that will hold the values.  */
-           if (TREE_CODE (typex) == ENUMERAL_TYPE)
-             typex = (*lang_hooks.types.type_for_size)
-               (TYPE_PRECISION (typex), TREE_UNSIGNED (typex));
-
-           /* But now perhaps TYPEX is as wide as INPREC.
-              In that case, do nothing special here.
-              (Otherwise would recurse infinitely in convert.  */
-           if (TYPE_PRECISION (typex) != inprec)
-             {
-               /* Don't do unsigned arithmetic where signed was wanted,
-                  or vice versa.  */
-               if (TREE_UNSIGNED (TREE_TYPE (expr)))
-                 typex = (*lang_hooks.types.unsigned_type) (typex);
-               else
-                 typex = (*lang_hooks.types.signed_type) (typex);
-               return convert (type,
-                               fold (build1 (ex_form, typex,
-                                             convert (typex,
-                                                      TREE_OPERAND (expr, 0)))));
-             }
+           tree typex;
+
+           /* Don't do unsigned arithmetic where signed was wanted,
+              or vice versa.  */
+           if (TYPE_UNSIGNED (TREE_TYPE (expr)))
+             typex = unsigned_type_for (type);
+           else
+             typex = signed_type_for (type);
+           return convert (type,
+                           fold_build1 (ex_form, typex,
+                                        convert (typex,
+                                                 TREE_OPERAND (expr, 0))));
          }
 
        case NOP_EXPR:
          }
 
        case NOP_EXPR:
@@ -577,32 +704,34 @@ convert_to_integer (type, expr)
        case COND_EXPR:
          /* It is sometimes worthwhile to push the narrowing down through
             the conditional and never loses.  */
        case COND_EXPR:
          /* It is sometimes worthwhile to push the narrowing down through
             the conditional and never loses.  */
-         return fold (build (COND_EXPR, type, TREE_OPERAND (expr, 0),
-                             convert (type, TREE_OPERAND (expr, 1)), 
-                             convert (type, TREE_OPERAND (expr, 2))));
+         return fold_build3 (COND_EXPR, type, TREE_OPERAND (expr, 0),
+                             convert (type, TREE_OPERAND (expr, 1)),
+                             convert (type, TREE_OPERAND (expr, 2)));
 
        default:
          break;
        }
 
 
        default:
          break;
        }
 
-      return build1 (NOP_EXPR, type, expr);
+      return build1 (CONVERT_EXPR, type, expr);
 
     case REAL_TYPE:
       return build1 (FIX_TRUNC_EXPR, type, expr);
 
 
     case REAL_TYPE:
       return build1 (FIX_TRUNC_EXPR, type, expr);
 
+    case FIXED_POINT_TYPE:
+      return build1 (FIXED_CONVERT_EXPR, type, expr);
+
     case COMPLEX_TYPE:
       return convert (type,
     case COMPLEX_TYPE:
       return convert (type,
-                     fold (build1 (REALPART_EXPR,
-                                   TREE_TYPE (TREE_TYPE (expr)), expr)));
+                     fold_build1 (REALPART_EXPR,
+                                  TREE_TYPE (TREE_TYPE (expr)), expr));
 
     case VECTOR_TYPE:
 
     case VECTOR_TYPE:
-      if (GET_MODE_SIZE (TYPE_MODE (type))
-         != GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))))
+      if (!tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (TREE_TYPE (expr))))
        {
          error ("can't convert between vector values of different size");
          return error_mark_node;
        }
        {
          error ("can't convert between vector values of different size");
          return error_mark_node;
        }
-      return build1 (NOP_EXPR, type, expr);
+      return build1 (VIEW_CONVERT_EXPR, type, expr);
 
     default:
       error ("aggregate value used where an integer was expected");
 
     default:
       error ("aggregate value used where an integer was expected");
@@ -613,20 +742,19 @@ convert_to_integer (type, expr)
 /* Convert EXPR to the complex type TYPE in the usual ways.  */
 
 tree
 /* Convert EXPR to the complex type TYPE in the usual ways.  */
 
 tree
-convert_to_complex (type, expr)
-     tree type, expr;
+convert_to_complex (tree type, tree expr)
 {
   tree subtype = TREE_TYPE (type);
 {
   tree subtype = TREE_TYPE (type);
-  
+
   switch (TREE_CODE (TREE_TYPE (expr)))
     {
     case REAL_TYPE:
   switch (TREE_CODE (TREE_TYPE (expr)))
     {
     case REAL_TYPE:
+    case FIXED_POINT_TYPE:
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
-    case CHAR_TYPE:
-      return build (COMPLEX_EXPR, type, convert (subtype, expr),
-                   convert (subtype, integer_zero_node));
+      return build2 (COMPLEX_EXPR, type, convert (subtype, expr),
+                    convert (subtype, integer_zero_node));
 
     case COMPLEX_TYPE:
       {
 
     case COMPLEX_TYPE:
       {
@@ -635,23 +763,22 @@ convert_to_complex (type, expr)
        if (TYPE_MAIN_VARIANT (elt_type) == TYPE_MAIN_VARIANT (subtype))
          return expr;
        else if (TREE_CODE (expr) == COMPLEX_EXPR)
        if (TYPE_MAIN_VARIANT (elt_type) == TYPE_MAIN_VARIANT (subtype))
          return expr;
        else if (TREE_CODE (expr) == COMPLEX_EXPR)
-         return fold (build (COMPLEX_EXPR,
-                             type,
+         return fold_build2 (COMPLEX_EXPR, type,
                              convert (subtype, TREE_OPERAND (expr, 0)),
                              convert (subtype, TREE_OPERAND (expr, 0)),
-                             convert (subtype, TREE_OPERAND (expr, 1))));
+                             convert (subtype, TREE_OPERAND (expr, 1)));
        else
          {
            expr = save_expr (expr);
            return
        else
          {
            expr = save_expr (expr);
            return
-             fold (build (COMPLEX_EXPR,
-                          type, convert (subtype,
-                                         fold (build1 (REALPART_EXPR,
-                                                       TREE_TYPE (TREE_TYPE (expr)),
-                                                       expr))),
+             fold_build2 (COMPLEX_EXPR, type,
+                          convert (subtype,
+                                   fold_build1 (REALPART_EXPR,
+                                                TREE_TYPE (TREE_TYPE (expr)),
+                                                expr)),
                           convert (subtype,
                           convert (subtype,
-                                   fold (build1 (IMAGPART_EXPR,
-                                                 TREE_TYPE (TREE_TYPE (expr)),
-                                                 expr)))));
+                                   fold_build1 (IMAGPART_EXPR,
+                                                TREE_TYPE (TREE_TYPE (expr)),
+                                                expr)));
          }
       }
 
          }
       }
 
@@ -669,23 +796,60 @@ convert_to_complex (type, expr)
 /* Convert EXPR to the vector type TYPE in the usual ways.  */
 
 tree
 /* Convert EXPR to the vector type TYPE in the usual ways.  */
 
 tree
-convert_to_vector (type, expr)
-     tree type, expr;
+convert_to_vector (tree type, tree expr)
 {
   switch (TREE_CODE (TREE_TYPE (expr)))
     {
     case INTEGER_TYPE:
     case VECTOR_TYPE:
 {
   switch (TREE_CODE (TREE_TYPE (expr)))
     {
     case INTEGER_TYPE:
     case VECTOR_TYPE:
-      if (GET_MODE_SIZE (TYPE_MODE (type))
-         != GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))))
+      if (!tree_int_cst_equal (TYPE_SIZE (type), TYPE_SIZE (TREE_TYPE (expr))))
        {
          error ("can't convert between vector values of different size");
          return error_mark_node;
        }
        {
          error ("can't convert between vector values of different size");
          return error_mark_node;
        }
-      return build1 (NOP_EXPR, type, expr);
+      return build1 (VIEW_CONVERT_EXPR, type, expr);
 
     default:
       error ("can't convert value to a vector");
 
     default:
       error ("can't convert value to a vector");
-      return convert_to_vector (type, integer_zero_node);
+      return error_mark_node;
+    }
+}
+
+/* Convert EXPR to some fixed-point type TYPE.
+
+   EXPR must be fixed-point, float, integer, or enumeral;
+   in other cases error is called.  */
+
+tree
+convert_to_fixed (tree type, tree expr)
+{
+  if (integer_zerop (expr))
+    {
+      tree fixed_zero_node = build_fixed (type, FCONST0 (TYPE_MODE (type)));
+      return fixed_zero_node;
+    }
+  else if (integer_onep (expr) && ALL_SCALAR_ACCUM_MODE_P (TYPE_MODE (type)))
+    {
+      tree fixed_one_node = build_fixed (type, FCONST1 (TYPE_MODE (type)));
+      return fixed_one_node;
+    }
+
+  switch (TREE_CODE (TREE_TYPE (expr)))
+    {
+    case FIXED_POINT_TYPE:
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+    case REAL_TYPE:
+      return build1 (FIXED_CONVERT_EXPR, type, expr);
+
+    case COMPLEX_TYPE:
+      return convert (type,
+                     fold_build1 (REALPART_EXPR,
+                                  TREE_TYPE (TREE_TYPE (expr)), expr));
+
+    default:
+      error ("aggregate value used where a fixed-point was expected");
+      return error_mark_node;
     }
 }
     }
 }