tree.h (maybe_fold_offset_to_component_ref): Remove.
authorJan Hubicka <jh@suse.cz>
Tue, 1 May 2007 11:18:01 +0000 (13:18 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Tue, 1 May 2007 11:18:01 +0000 (11:18 +0000)
* tree.h (maybe_fold_offset_to_component_ref): Remove.
(maybe_fold_offset_to_reference): Declare.
* fold-const.c (fold_unary): Do not fold
(type *)&A into &A->field_of_type_and_offset_0
* tree-ssa-ccp.c (maybe_fold_offset_to_array_ref): When base type
size is unknown, give up.
(maybe_fold_offset_to_component_ref): Ignore firelds with unknown
offsets.
(maybe_fold_offset_to_reference): New.
(maybe_fold_stmt_indirect): Use it.
(fold_stmt_r): Fold (type *)&A+offset into A->field_if_type_and_offset.
* gimplify.c (gimplify_conversion): Canonicalize conversions to
field references.
(gimplify_expr): Likewise for plus_expr.

From-SVN: r124323

gcc/ChangeLog
gcc/fold-const.c
gcc/gimplify.c
gcc/tree-ssa-ccp.c
gcc/tree.h

index 2230102974d838567003aff951dea9372d3e8e96..88d090a6ec8ab33f3fb045aba7e7ee1eeb71821b 100644 (file)
@@ -1,3 +1,20 @@
+2007-05-01  Jan Hubicka  <jh@suse.cz>
+
+       * tree.h (maybe_fold_offset_to_component_ref): Remove.
+       (maybe_fold_offset_to_reference): Declare.
+       * fold-const.c (fold_unary): Do not fold
+       (type *)&A into &A->field_of_type_and_offset_0
+       * tree-ssa-ccp.c (maybe_fold_offset_to_array_ref): When base type
+       size is unknown, give up.
+       (maybe_fold_offset_to_component_ref): Ignore firelds with unknown
+       offsets.
+       (maybe_fold_offset_to_reference): New.
+       (maybe_fold_stmt_indirect): Use it.
+       (fold_stmt_r): Fold (type *)&A+offset into A->field_if_type_and_offset.
+       * gimplify.c (gimplify_conversion): Canonicalize conversions to
+       field references.
+       (gimplify_expr): Likewise for plus_expr.
+
 2007-05-01  Zdenek Dvorak  <dvorakz@suse.cz>
 
        * tree-ssa-loop-ivopts.c (rewrite_use_nonlinear_expr): Use
index 7a8afcdbe878417ece1555569b4cc5adae4357bf..6311be7e0848e72fcd6e1a440ff5d8cbf5889271 100644 (file)
@@ -7748,13 +7748,6 @@ fold_unary (enum tree_code code, tree type, tree op0)
            return fold_convert (type, build_fold_addr_expr (base));
         }
 
-      /* Convert (type *)&A into &A->field_of_type_and_offset_0.  */
-      if (TREE_CODE (op0) == ADDR_EXPR && POINTER_TYPE_P (type)
-         && (tem = maybe_fold_offset_to_component_ref
-                     (TREE_TYPE (TREE_OPERAND (op0, 0)), TREE_OPERAND (op0, 0),
-                      integer_zero_node, TREE_TYPE (type), false)))
-        return build_fold_addr_expr_with_type (tem, type);
-
       if ((TREE_CODE (op0) == MODIFY_EXPR
           || TREE_CODE (op0) == GIMPLE_MODIFY_STMT)
          && TREE_CONSTANT (GENERIC_TREE_OPERAND (op0, 1))
index 0b6ec34d97471dc946aba2fc54bff697b7f2fa28..805c3020272323babd0b1086afb6b1553fef28e2 100644 (file)
@@ -1617,6 +1617,7 @@ canonicalize_addr_expr (tree *expr_p)
 static enum gimplify_status
 gimplify_conversion (tree *expr_p)
 {
+  tree tem;
   gcc_assert (TREE_CODE (*expr_p) == NOP_EXPR
              || TREE_CODE (*expr_p) == CONVERT_EXPR);
   
@@ -1627,6 +1628,17 @@ gimplify_conversion (tree *expr_p)
   if (tree_ssa_useless_type_conversion (*expr_p))
     *expr_p = TREE_OPERAND (*expr_p, 0);
 
+  /* Attempt to avoid NOP_EXPR by producing reference to a subtype.
+     For example this fold (subclass *)&A into &A->subclass avoiding
+     a need for statement.  */
+  if (TREE_CODE (*expr_p) == NOP_EXPR
+      && POINTER_TYPE_P (TREE_TYPE (*expr_p))
+      && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 0)))
+      && (tem = maybe_fold_offset_to_reference
+                 (TREE_OPERAND (*expr_p, 0),
+                  integer_zero_node, TREE_TYPE (TREE_TYPE (*expr_p)))))
+    *expr_p = build_fold_addr_expr_with_type (tem, TREE_TYPE (*expr_p));
+
   /* If we still have a conversion at the toplevel,
      then canonicalize some constructs.  */
   if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
@@ -5857,6 +5869,21 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          ret = GS_ALL_DONE;
          break;
 
+       case PLUS_EXPR:
+          /* Convert ((type *)A)+offset into &A->field_of_type_and_offset.
+            The second is gimple immediate saving a need for extra statement.
+          */
+         if (POINTER_TYPE_P (TREE_TYPE (*expr_p))
+             && TREE_CODE (TREE_OPERAND (*expr_p, 1)) == INTEGER_CST
+             && (tmp = maybe_fold_offset_to_reference
+                        (TREE_OPERAND (*expr_p, 0), TREE_OPERAND (*expr_p, 1),
+                         TREE_TYPE (TREE_TYPE (*expr_p)))))
+            {
+               *expr_p = build_fold_addr_expr_with_type (tmp,
+                                                        TREE_TYPE (*expr_p));
+               break;
+            }
+          /* FALLTHRU */
        default:
          switch (TREE_CODE_CLASS (TREE_CODE (*expr_p)))
            {
index 9c9d847eed6f1b79c4675f54ecf092eaf9d22be8..6c9475540fefd6f27aa1e342e26121710a204cef 100644 (file)
@@ -1587,6 +1587,8 @@ maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
      Otherwise, compute the offset as an index by using a division.  If the
      division isn't exact, then don't do anything.  */
   elt_size = TYPE_SIZE_UNIT (elt_type);
+  if (!elt_size)
+    return NULL;
   if (integer_zerop (offset))
     {
       if (TREE_CODE (elt_size) != INTEGER_CST)
@@ -1647,12 +1649,11 @@ maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
 }
 
 
-/* A subroutine of fold_stmt_r.  Attempts to fold *(S+O) to S.X.
+/* Attempt to fold *(S+O) to S.X.
    BASE is a record type.  OFFSET is a byte displacement.  ORIG_TYPE
    is the desired result type.  */
-/* ??? This doesn't handle class inheritance.  */
 
-tree
+static tree
 maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
                                    tree orig_type, bool base_is_ptr)
 {
@@ -1679,6 +1680,8 @@ maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
       if (DECL_BIT_FIELD (f))
        continue;
 
+      if (!DECL_FIELD_OFFSET (f))
+       continue;
       field_offset = byte_position (f);
       if (TREE_CODE (field_offset) != INTEGER_CST)
        continue;
@@ -1766,6 +1769,69 @@ maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
                                             orig_type, false);
 }
 
+/* Attempt to express (ORIG_TYPE)BASE+OFFSET as BASE->field_of_orig_type
+   or BASE[index] or by combination of those. 
+
+   Before attempting the conversion strip off existing ADDR_EXPRs and
+   handled component refs.  */
+
+tree
+maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type)
+{
+  tree ret;
+  tree type;
+  bool base_is_ptr = true;
+
+  STRIP_NOPS (base);
+  if (TREE_CODE (base) == ADDR_EXPR)
+    {
+      base_is_ptr = false;
+
+      base = TREE_OPERAND (base, 0);
+
+      /* Handle case where existing COMPONENT_REF pick e.g. wrong field of union,
+        so it needs to be removed and new COMPONENT_REF constructed.
+        The wrong COMPONENT_REF are often constructed by folding the
+        (type *)&object within the expression (type *)&object+offset  */
+      if (handled_component_p (base) && 0)
+       {
+          HOST_WIDE_INT sub_offset, size, maxsize;
+         tree newbase;
+         newbase = get_ref_base_and_extent (base, &sub_offset,
+                                            &size, &maxsize);
+         gcc_assert (newbase);
+         gcc_assert (!(sub_offset & (BITS_PER_UNIT - 1)));
+         if (size == maxsize)
+           {
+             base = newbase;
+             if (sub_offset)
+               offset = int_const_binop (PLUS_EXPR, offset,
+                                         build_int_cst (TREE_TYPE (offset),
+                                         sub_offset / BITS_PER_UNIT), 1);
+           }
+       }
+      if (lang_hooks.types_compatible_p (orig_type, TREE_TYPE (base))
+         && integer_zerop (offset))
+       return base;
+      type = TREE_TYPE (base);
+    }
+  else
+    {
+      base_is_ptr = true;
+      if (!POINTER_TYPE_P (TREE_TYPE (base)))
+       return NULL_TREE;
+      type = TREE_TYPE (TREE_TYPE (base));
+    }
+  ret = maybe_fold_offset_to_component_ref (type, base, offset,
+                                           orig_type, base_is_ptr);
+  if (!ret)
+    {
+      if (base_is_ptr)
+       base = build1 (INDIRECT_REF, type, base);
+      ret = maybe_fold_offset_to_array_ref (base, offset, orig_type);
+    }
+  return ret;
+}
 
 /* A subroutine of fold_stmt_r.  Attempt to simplify *(BASE+OFFSET).
    Return the simplified expression, or NULL if nothing could be done.  */
@@ -1802,6 +1868,8 @@ maybe_fold_stmt_indirect (tree expr, tree base, tree offset)
 
   if (TREE_CODE (base) == ADDR_EXPR)
     {
+      tree base_addr = base;
+
       /* Strip the ADDR_EXPR.  */
       base = TREE_OPERAND (base, 0);
 
@@ -1810,24 +1878,11 @@ maybe_fold_stmt_indirect (tree expr, tree base, tree offset)
          && ccp_decl_initial_min_invariant (DECL_INITIAL (base)))
        return DECL_INITIAL (base);
 
-      /* Try folding *(&B+O) to B[X].  */
-      t = maybe_fold_offset_to_array_ref (base, offset, TREE_TYPE (expr));
-      if (t)
-       return t;
-
       /* Try folding *(&B+O) to B.X.  */
-      t = maybe_fold_offset_to_component_ref (TREE_TYPE (base), base, offset,
-                                             TREE_TYPE (expr), false);
+      t = maybe_fold_offset_to_reference (base_addr, offset,
+                                         TREE_TYPE (expr));
       if (t)
        return t;
-
-      /* Fold *&B to B.  We can only do this if EXPR is the same type
-        as BASE.  We can't do this if EXPR is the element type of an array
-        and BASE is the array.  */
-      if (integer_zerop (offset)
-         && lang_hooks.types_compatible_p (TREE_TYPE (base),
-                                           TREE_TYPE (expr)))
-       return base;
     }
   else
     {
@@ -1856,9 +1911,8 @@ maybe_fold_stmt_indirect (tree expr, tree base, tree offset)
       /* Try folding *(B+O) to B->X.  Still an improvement.  */
       if (POINTER_TYPE_P (TREE_TYPE (base)))
        {
-          t = maybe_fold_offset_to_component_ref (TREE_TYPE (TREE_TYPE (base)),
-                                                 base, offset,
-                                                 TREE_TYPE (expr), true);
+          t = maybe_fold_offset_to_reference (base, offset,
+                                             TREE_TYPE (expr));
          if (t)
            return t;
        }
@@ -2020,6 +2074,21 @@ fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
                                    integer_zero_node);
       break;
 
+    case NOP_EXPR:
+      t = walk_tree (&TREE_OPERAND (expr, 0), fold_stmt_r, data, NULL);
+      if (t)
+       return t;
+      *walk_subtrees = 0;
+
+      if (POINTER_TYPE_P (TREE_TYPE (expr))
+         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)))
+         && (t = maybe_fold_offset_to_reference
+                     (TREE_OPERAND (expr, 0),
+                      integer_zero_node,
+                      TREE_TYPE (TREE_TYPE (expr)))))
+        t = build_fold_addr_expr_with_type (t, TREE_TYPE (expr));
+      break;
+
       /* ??? Could handle more ARRAY_REFs here, as a variant of INDIRECT_REF.
         We'd only want to bother decomposing an existing ARRAY_REF if
         the base array is found to have another offset contained within.
index c076fc1aa7a65bb84d2c24ebb16b46e8ec4f87a4..3059d40280436924a7472a244753c44f2877e3cf 100644 (file)
@@ -4422,8 +4422,7 @@ extern void fold_defer_overflow_warnings (void);
 extern void fold_undefer_overflow_warnings (bool, tree, int);
 extern void fold_undefer_and_ignore_overflow_warnings (void);
 extern bool fold_deferring_overflow_warnings_p (void);
-extern tree maybe_fold_offset_to_component_ref (tree, tree, tree,
-                                               tree, bool);
+extern tree maybe_fold_offset_to_reference (tree, tree, tree);
 
 extern tree force_fit_type_double (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT,
                                   int, bool);