OSDN Git Service

2007-07-02 Richard Guenther <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 2 Jul 2007 12:13:39 +0000 (12:13 +0000)
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 2 Jul 2007 12:13:39 +0000 (12:13 +0000)
* tree-ssa.c (useless_type_conversion_p): Document
future intent as defining the middle-end type system.
Re-structure to call langhook last, group by type class,
mark questionable parts.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@126199 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/tree-ssa.c

index 66176e1..f9f4b24 100644 (file)
@@ -1,5 +1,12 @@
 2007-07-02  Richard Guenther  <rguenther@suse.de>
 
+       * tree-ssa.c (useless_type_conversion_p): Document
+       future intent as defining the middle-end type system.
+       Re-structure to call langhook last, group by type class,
+       mark questionable parts.
+
+2007-07-02  Richard Guenther  <rguenther@suse.de>
+
        * tree-flow.h (types_compatible_p): Declare.
        * tree-ssa.c (types_compatible_p): New function.
        * ipa-type-escape.c (discover_unique_type): Use
index 9e71606..8b2d852 100644 (file)
@@ -888,7 +888,29 @@ delete_tree_ssa (void)
 
 
 /* Return true if the conversion from INNER_TYPE to OUTER_TYPE is a
-   useless type conversion, otherwise return false.  */
+   useless type conversion, otherwise return false.
+
+   This function implicitly defines the middle-end type system.  With
+   the notion of 'a < b' meaning that useless_type_conversion_p (a, b)
+   holds and 'a > b' meaning that useless_type_conversion_p (b, a) holds,
+   the following invariants shall be fulfilled:
+
+     1) useless_type_conversion_p is transitive.
+       If a < b and b < c then a < c.
+
+     2) useless_type_conversion_p is not symmetric.
+       From a < b does not follow a > b.
+
+     3) Types define the available set of operations applicable to values.
+       A type conversion is useless if the operations for the target type
+       is a subset of the operations for the source type.  For example
+       casts to void* are useless, casts from void* are not (void* can't
+       be dereferenced or offsetted, but copied, hence its set of operations
+       is a strict subset of that of all other data pointer types).  Casts
+       to const T* are useless (can't be written to), casts from const T*
+       to T* are not.
+
+   ???  The above do not hold currently.  */
 
 bool
 useless_type_conversion_p (tree outer_type, tree inner_type)
@@ -900,75 +922,83 @@ useless_type_conversion_p (tree outer_type, tree inner_type)
   if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type))
     return false;
 
-  /* If the inner and outer types are effectively the same, then
-     strip the type conversion and enter the equivalence into
-     the table.  */
-  if (lang_hooks.types_compatible_p (inner_type, outer_type))
-    return true;
-
-  /* If both types are pointers and the outer type is a (void *), then
-     the conversion is not necessary.  The opposite is not true since
-     that conversion would result in a loss of information if the
-     equivalence was used.  Consider an indirect function call where
-     we need to know the exact type of the function to correctly
-     implement the ABI.  */
-  else if (POINTER_TYPE_P (inner_type)
-           && POINTER_TYPE_P (outer_type)
-          && TYPE_REF_CAN_ALIAS_ALL (inner_type)
-             == TYPE_REF_CAN_ALIAS_ALL (outer_type)
-          && TREE_CODE (TREE_TYPE (outer_type)) == VOID_TYPE)
-    return true;
+  /* If both the inner and outer types are integral types, then the
+     conversion is not necessary if they have the same mode and
+     signedness and precision, and both or neither are boolean.  */
+  if (INTEGRAL_TYPE_P (inner_type)
+      && INTEGRAL_TYPE_P (outer_type))
+    {
+      /* Preserve changes in signedness or precision.  */
+      if (TYPE_UNSIGNED (inner_type) != TYPE_UNSIGNED (outer_type)
+         || TYPE_PRECISION (inner_type) != TYPE_PRECISION (outer_type))
+       return false;
+
+      /* Preserve booleanness.  Some code assumes an invariant that boolean
+        types stay boolean and do not become 1-bit bit-field types.  */
+      if ((TREE_CODE (inner_type) == BOOLEAN_TYPE)
+         != (TREE_CODE (outer_type) == BOOLEAN_TYPE))
+       return false;
+
+      /* Preserve changes in the types minimum or maximum value.
+        ???  Due to the way we handle sizetype as signed we need
+        to jump through hoops here to make sizetype and size_type_node
+        compatible.  */
+      if (!tree_int_cst_equal (fold_convert (outer_type,
+                                            TYPE_MIN_VALUE (inner_type)),
+                              TYPE_MIN_VALUE (outer_type))
+         || !tree_int_cst_equal (fold_convert (outer_type,
+                                               TYPE_MAX_VALUE (inner_type)),
+                                 TYPE_MAX_VALUE (outer_type)))
+       return false;
+
+      /* ???  We might want to preserve base type changes because of
+        TBAA.  Or we need to be extra careful below.  */
 
-  /* Don't lose casts between pointers to volatile and non-volatile
-     qualified types.  Doing so would result in changing the semantics
-     of later accesses.  */
-  else if (POINTER_TYPE_P (inner_type)
-           && POINTER_TYPE_P (outer_type)
-          && TYPE_VOLATILE (TREE_TYPE (outer_type))
-             != TYPE_VOLATILE (TREE_TYPE (inner_type)))
-    return false;
+      return true;
+    }
 
-  /* Pointers/references are equivalent if their pointed to types
-     are effectively the same.  This allows to strip conversions between
-     pointer types with different type qualifiers.  */
+  /* We need to take special care recursing to pointed-to types.  */
   else if (POINTER_TYPE_P (inner_type)
-           && POINTER_TYPE_P (outer_type)
-          && TYPE_REF_CAN_ALIAS_ALL (inner_type)
-             == TYPE_REF_CAN_ALIAS_ALL (outer_type)
-           && lang_hooks.types_compatible_p (TREE_TYPE (inner_type),
-                                            TREE_TYPE (outer_type)))
-    return true;
-
-  /* If both the inner and outer types are integral types, then the
-     conversion is not necessary if they have the same mode and
-     signedness and precision, and both or neither are boolean.  Some
-     code assumes an invariant that boolean types stay boolean and do
-     not become 1-bit bit-field types.  Note that types with precision
-     not using all bits of the mode (such as bit-field types in C)
-     mean that testing of precision is necessary.  */
-  else if (INTEGRAL_TYPE_P (inner_type)
-           && INTEGRAL_TYPE_P (outer_type)
-          && TYPE_UNSIGNED (inner_type) == TYPE_UNSIGNED (outer_type)
-          && TYPE_PRECISION (inner_type) == TYPE_PRECISION (outer_type))
+          && POINTER_TYPE_P (outer_type))
     {
-      tree min_inner = fold_convert (outer_type, TYPE_MIN_VALUE (inner_type));
-      tree max_inner = fold_convert (outer_type, TYPE_MAX_VALUE (inner_type));
-      bool first_boolean = (TREE_CODE (inner_type) == BOOLEAN_TYPE);
-      bool second_boolean = (TREE_CODE (outer_type) == BOOLEAN_TYPE);
-      if (simple_cst_equal (max_inner, TYPE_MAX_VALUE (outer_type))
-         && simple_cst_equal (min_inner, TYPE_MIN_VALUE (outer_type))
-         && first_boolean == second_boolean)
+      /* Don't lose casts between pointers to volatile and non-volatile
+        qualified types.  Doing so would result in changing the semantics
+        of later accesses.  */
+      if (TYPE_VOLATILE (TREE_TYPE (outer_type))
+         != TYPE_VOLATILE (TREE_TYPE (inner_type)))
+       return false;
+
+      /* Do not lose casts between pointers with different
+        TYPE_REF_CAN_ALIAS_ALL setting.  */
+      if (TYPE_REF_CAN_ALIAS_ALL (inner_type)
+         != TYPE_REF_CAN_ALIAS_ALL (outer_type))
+       return false;
+
+      /* If the outer type is (void *), then the conversion is not
+        necessary.
+        ???  Together with calling the langhook below this makes
+        useless_type_conversion_p not transitive.  */
+      if (TREE_CODE (TREE_TYPE (outer_type)) == VOID_TYPE)
        return true;
+
+      /* Otherwise pointers/references are equivalent if their pointed
+        to types are effectively the same.  This allows to strip conversions
+        between pointer types with different type qualifiers.
+        ???  We should recurse here with
+        useless_type_conversion_p.  */
+      return lang_hooks.types_compatible_p (TREE_TYPE (inner_type),
+                                          TREE_TYPE (outer_type));
     }
 
   /* Recurse for complex types.  */
   else if (TREE_CODE (inner_type) == COMPLEX_TYPE
-          && TREE_CODE (outer_type) == COMPLEX_TYPE
-          && useless_type_conversion_p (TREE_TYPE (outer_type),
-                                                 TREE_TYPE (inner_type)))
-    return true;
+          && TREE_CODE (outer_type) == COMPLEX_TYPE)
+    return useless_type_conversion_p (TREE_TYPE (outer_type),
+                                     TREE_TYPE (inner_type));
 
-  return false;
+  /* Fall back to what the frontend thinks of type compatibility.
+     ???  This should eventually just return false.  */
+  return lang_hooks.types_compatible_p (inner_type, outer_type);
 }
 
 /* Return true if a conversion from either type of TYPE1 and TYPE2