OSDN Git Service

(output_toc): Align DF constants if STRICT_ALIGNMENT.
[pf3gnuchains/gcc-fork.git] / gcc / convert.c
index a063a6e..17e7552 100644 (file)
@@ -1,5 +1,5 @@
 /* Utility routines for data type conversion for GNU C.
-   Copyright (C) 1987, 1988, 1991, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 91, 92, 94, 1995 Free Software Foundation, Inc.
 
 This file is part of GNU C.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* These routines are somewhat language-independent utility function
@@ -26,9 +27,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "flags.h"
 #include "convert.h"
 
-/* Convert EXPR to some pointer type TYPE.
+/* Convert EXPR to some pointer or reference type TYPE.
 
-   EXPR must be pointer, integer, enumeral, or literal zero;
+   EXPR must be pointer, reference, integer, enumeral, or literal zero;
    in other cases error is called. */
 
 tree
@@ -40,14 +41,12 @@ convert_to_pointer (type, expr)
   
   if (integer_zerop (expr))
     {
-      if (type == TREE_TYPE (null_pointer_node))
-       return null_pointer_node;
       expr = build_int_2 (0, 0);
       TREE_TYPE (expr) = type;
       return expr;
     }
 
-  if (form == POINTER_TYPE)
+  if (form == POINTER_TYPE || form == REFERENCE_TYPE)
     return build1 (NOP_EXPR, type, expr);
 
 
@@ -67,7 +66,9 @@ convert_to_pointer (type, expr)
 
   error ("cannot convert to a pointer type");
 
-  return null_pointer_node;
+  expr = build_int_2 (0, 0);
+  TREE_TYPE (expr) = type;
+  return expr;
 }
 
 /* Convert EXPR to some floating-point type TYPE.
@@ -85,14 +86,14 @@ convert_to_real (type, expr)
     return build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
                   type, expr);
 
-  if (form == INTEGER_TYPE || form == ENUMERAL_TYPE)
+  if (INTEGRAL_TYPE_P (TREE_TYPE (expr)))
     return build1 (FLOAT_EXPR, type, expr);
 
   if (form == COMPLEX_TYPE)
     return convert (type, fold (build1 (REALPART_EXPR,
                                        TREE_TYPE (TREE_TYPE (expr)), expr)));
 
-  if (form == POINTER_TYPE)
+  if (form == POINTER_TYPE || form == REFERENCE_TYPE)
     error ("pointer value used where a floating point value was expected");
   else
     error ("aggregate value used where a float was expected");
@@ -100,7 +101,7 @@ convert_to_real (type, expr)
   {
     register tree tem = make_node (REAL_CST);
     TREE_TYPE (tem) = type;
-    TREE_REAL_CST (tem) = REAL_VALUE_ATOF ("0.0");
+    TREE_REAL_CST (tem) = REAL_VALUE_ATOF ("0.0", TYPE_MODE (type));
     return tem;
   }
 }
@@ -120,7 +121,7 @@ convert_to_integer (type, expr)
   register tree intype = TREE_TYPE (expr);
   register enum tree_code form = TREE_CODE (intype);
 
-  if (form == POINTER_TYPE)
+  if (form == POINTER_TYPE || form == REFERENCE_TYPE)
     {
       if (integer_zerop (expr))
        expr = integer_zero_node;
@@ -143,38 +144,63 @@ convert_to_integer (type, expr)
       /* If we are widening the type, put in an explicit conversion.
         Similarly if we are not changing the width.  However, if this is
         a logical operation that just returns 0 or 1, we can change the
-        type of the expression (see below).  */
+        type of the expression.  For logical operations, we must
+        also change the types of the operands to maintain type
+        correctness.  */
 
-      if (TREE_CODE_CLASS (ex_form) == '<'
-         || 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 || ex_form == TRUTH_NOT_EXPR)
+      if (TREE_CODE_CLASS (ex_form) == '<')
+       {
+         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));
          TREE_TYPE (expr) = type;
          return expr;
        }
       else if (outprec >= inprec)
        return build1 (NOP_EXPR, type, expr);
 
-/* Here detect when we can distribute the truncation down past some arithmetic.
-   For example, if adding two longs and converting to an int,
-   we can equally well convert both to ints and then add.
-   For the operations handled here, such truncation distribution
-   is always safe.
-   It is desirable in these cases:
-   1) when truncating down to full-word from a larger size
-   2) when truncating takes no work.
-   3) when at least one operand of the arithmetic has been extended
-   (as by C's default conversions).  In this case we need two conversions
-   if we do the arithmetic as already requested, so we might as well
-   truncate both and then combine.  Perhaps that way we need only one.
-
-   Note that in general we cannot do the arithmetic in a type
-   shorter than the desired result of conversion, even if the operands
-   are both extended from a shorter type, because they might overflow
-   if combined in that type.  The exceptions to this--the times when
-   two narrow values can be combined in their narrow type even to
-   make a wider result--are handled by "shorten" in build_binary_op.  */
+      /* 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
+        type corresponding to its mode, then do a nop conversion
+        to TYPE.  */
+      else if (TREE_CODE (type) == ENUMERAL_TYPE
+              || outprec != GET_MODE_BITSIZE (TYPE_MODE (type)))
+       return build1 (NOP_EXPR, type,
+                      convert (type_for_mode (TYPE_MODE (type),
+                                              TREE_UNSIGNED (type)),
+                               expr));
+
+      /* Here detect when we can distribute the truncation down past some
+        arithmetic.  For example, if adding two longs and converting to an
+        int, we can equally well convert both to ints and then add.
+        For the operations handled here, such truncation distribution
+        is always safe.
+        It is desirable in these cases:
+        1) when truncating down to full-word from a larger size
+        2) when truncating takes no work.
+        3) when at least one operand of the arithmetic has been extended
+        (as by C's default conversions).  In this case we need two conversions
+        if we do the arithmetic as already requested, so we might as well
+        truncate both and then combine.  Perhaps that way we need only one.
+
+        Note that in general we cannot do the arithmetic in a type
+        shorter than the desired result of conversion, even if the operands
+        are both extended from a shorter type, because they might overflow
+        if combined in that type.  The exceptions to this--the times when
+        two narrow values can be combined in their narrow type even to
+        make a wider result--are handled by "shorten" in build_binary_op.  */
 
       switch (ex_form)
        {
@@ -182,7 +208,9 @@ 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
-             && tree_int_cst_lt (TREE_OPERAND (expr, 1), integer_one_node))
+             && tree_int_cst_lt (TREE_OPERAND (expr, 1),
+                                 convert (TREE_TYPE (TREE_OPERAND (expr, 1)),
+                                          integer_one_node)))
            goto trunc1;
          break;
 
@@ -190,7 +218,7 @@ convert_to_integer (type, expr)
          /* We can pass truncation down through left shifting
             when the shift count is a nonnegative constant.  */
          if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
-             && ! tree_int_cst_lt (TREE_OPERAND (expr, 1), integer_zero_node)
+             && tree_int_cst_sgn (TREE_OPERAND (expr, 1)) >= 0
              && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
            {
              /* If shift count is less than the width of the truncated type,
@@ -199,11 +227,22 @@ convert_to_integer (type, expr)
                /* In this case, shifting is like multiplication.  */
                goto trunc1;
              else
-               /* If it is >= that width, result is zero.
-                  Handling this with trunc1 would give the wrong result:
-                  (int) ((long long) a << 32) is well defined (as 0)
-                  but (int) a << 32 is undefined and would get a warning.  */
-               return convert_to_integer (type, integer_zero_node);
+               {
+                 /* If it is >= that width, result is zero.
+                    Handling this with trunc1 would give the wrong result:
+                    (int) ((long long) a << 32) is well defined (as 0)
+                    but (int) a << 32 is undefined and would get a
+                    warning.  */
+
+                 tree t = convert_to_integer (type, integer_zero_node);
+
+                 /* If the original expression had side-effects, we must
+                    preserve it.  */
+                 if (TREE_SIDE_EFFECTS (expr))
+                   return build (COMPOUND_EXPR, type, expr, t);
+                 else
+                   return t;
+               }
            }
          break;
 
@@ -269,10 +308,10 @@ convert_to_integer (type, expr)
                              || TREE_UNSIGNED (TREE_TYPE (arg1)))
                             ? unsigned_type (typex) : signed_type (typex));
                    return convert (type,
-                                   build_binary_op (ex_form,
-                                                    convert (typex, arg0),
-                                                    convert (typex, arg1),
-                                                    0));
+                                   fold (build (ex_form, typex,
+                                                convert (typex, arg0),
+                                                convert (typex, arg1),
+                                                0)));
                  }
              }
          }
@@ -280,7 +319,8 @@ convert_to_integer (type, expr)
 
        case NEGATE_EXPR:
        case BIT_NOT_EXPR:
-       case ABS_EXPR:
+         /* This is not correct for ABS_EXPR,
+            since we must test the sign before truncation.  */
          {
            register tree typex = type;
 
@@ -300,9 +340,9 @@ convert_to_integer (type, expr)
                typex = (TREE_UNSIGNED (TREE_TYPE (expr))
                         ? unsigned_type (typex) : signed_type (typex));
                return convert (type,
-                               build_unary_op (ex_form,
-                                               convert (typex, TREE_OPERAND (expr, 0)),
-                                               1));
+                               fold (build1 (ex_form, typex,
+                                             convert (typex,
+                                                      TREE_OPERAND (expr, 0)))));
              }
          }
 
@@ -411,13 +451,17 @@ convert_to_complex (type, expr)
          return fold (build (COMPLEX_EXPR,
                              type,
                              convert (subtype,
-                                      build_unary_op (REALPART_EXPR, expr, 1)),
+                                      fold (build1 (REALPART_EXPR,
+                                                    TREE_TYPE (TREE_TYPE (expr)),
+                                                    expr))),
                              convert (subtype,
-                                      build_unary_op (IMAGPART_EXPR, expr, 1))));
+                                      fold (build1 (IMAGPART_EXPR,
+                                                    TREE_TYPE (TREE_TYPE (expr)),
+                                                    expr)))));
        }
     }
 
-  if (form == POINTER_TYPE)
+  if (form == POINTER_TYPE || form == REFERENCE_TYPE)
     error ("pointer value used where a complex was expected");
   else
     error ("aggregate value used where a complex was expected");