OSDN Git Service

2008-03-13 Jerry DeLisle <jvdelisle@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-sra.c
index df6c6dc..45142e8 100644 (file)
@@ -1,7 +1,7 @@
 /* Scalar Replacement of Aggregates (SRA) converts some structure
    references into scalar references, exposing them to the scalar
    optimizers.
-   Copyright (C) 2003, 2004, 2005, 2006, 2007
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
      Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
@@ -1280,9 +1280,6 @@ instantiate_element (struct sra_elt *elt)
                                               TYPE_SIZE (elt->type),
                                               DECL_SIZE (var))
                                 : bitsize_int (0));
-      if (!INTEGRAL_TYPE_P (elt->type)
-         || TYPE_UNSIGNED (elt->type))
-       BIT_FIELD_REF_UNSIGNED (elt->replacement) = 1;
     }
 
   /* For vectors, if used on the left hand side with BIT_FIELD_REF,
@@ -1677,12 +1674,17 @@ try_instantiate_multiple_fields (struct sra_elt *elt, tree f)
 
   /* Create the field group as a single variable.  */
 
-  type = lang_hooks.types.type_for_mode (mode, 1);
+  /* We used to create a type for the mode above, but size turns
+     to be out not of mode-size.  As we need a matching type
+     to build a BIT_FIELD_REF, use a nonstandard integer type as
+     fallback.  */
+  type = lang_hooks.types.type_for_size (size, 1);
+  if (!type || TYPE_PRECISION (type) != size)
+    type = build_nonstandard_integer_type (size, 1);
   gcc_assert (type);
   var = build3 (BIT_FIELD_REF, type, NULL_TREE,
                bitsize_int (size),
                bitsize_int (bit));
-  BIT_FIELD_REF_UNSIGNED (var) = 1;
 
   block = instantiate_missing_elements_1 (elt, var, type);
   gcc_assert (block && block->is_scalar);
@@ -1696,7 +1698,6 @@ try_instantiate_multiple_fields (struct sra_elt *elt, tree f)
                                   TREE_TYPE (block->element), var,
                                   bitsize_int (size),
                                   bitsize_int (bit & ~alchk));
-      BIT_FIELD_REF_UNSIGNED (block->replacement) = 1;
     }
 
   block->in_bitfld_block = 2;
@@ -1719,7 +1720,6 @@ try_instantiate_multiple_fields (struct sra_elt *elt, tree f)
                                   + (TREE_INT_CST_LOW
                                      (DECL_FIELD_BIT_OFFSET (f))))
                                  & ~alchk));
-      BIT_FIELD_REF_UNSIGNED (fld->replacement) = TYPE_UNSIGNED (field_type);
       fld->in_bitfld_block = 1;
     }
 
@@ -2139,9 +2139,10 @@ sra_build_assignment (tree dst, tree src)
   if (scalar_bitfield_p (src))
     {
       tree var, shift, width;
-      tree utype, stype, stmp, utmp;
+      tree utype, stype, stmp, utmp, dtmp;
       tree list, stmt;
-      bool unsignedp = BIT_FIELD_REF_UNSIGNED (src);
+      bool unsignedp = (INTEGRAL_TYPE_P (TREE_TYPE (src))
+                       ? TYPE_UNSIGNED (TREE_TYPE (src)) : true);
 
       var = TREE_OPERAND (src, 0);
       width = TREE_OPERAND (src, 1);
@@ -2256,6 +2257,16 @@ sra_build_assignment (tree dst, tree src)
            var = fold_convert (TREE_TYPE (dst), var);
          else
            var = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (dst), var);
+
+         /* If the destination is not a register the conversion needs
+            to be a separate statement.  */
+         if (!is_gimple_reg (dst))
+           {
+             dtmp = make_rename_temp (TREE_TYPE (dst), "SR");
+             stmt = build_gimple_modify_stmt (dtmp, var);
+             append_to_statement_list (stmt, &list);
+             var = dtmp;
+           }
        }
       stmt = build_gimple_modify_stmt (dst, var);
       append_to_statement_list (stmt, &list);
@@ -2270,7 +2281,13 @@ sra_build_assignment (tree dst, tree src)
      Since such accesses under different types require compatibility
      anyway, there's little point in making tests and/or adding
      conversions to ensure the types of src and dst are the same.
-     So we just assume type differences at this point are ok.  */
+     So we just assume type differences at this point are ok.
+     The only exception we make here are pointer types, which can be different
+     in e.g. structurally equal, but non-identical RECORD_TYPEs.  */
+  if (POINTER_TYPE_P (TREE_TYPE (dst))
+      && !useless_type_conversion_p (TREE_TYPE (dst), TREE_TYPE (src)))
+    src = fold_convert (TREE_TYPE (dst), src);
+
   return build_gimple_modify_stmt (dst, src);
 }
 
@@ -2475,6 +2492,7 @@ sra_build_elt_assignment (struct sra_elt *elt, tree src)
   if (elt->in_bitfld_block == 2
       && TREE_CODE (src) == BIT_FIELD_REF)
     {
+      tmp = src;
       cst = TYPE_SIZE (TREE_TYPE (var));
       cst2 = size_binop (MINUS_EXPR, TREE_OPERAND (src, 2),
                         TREE_OPERAND (dst, 2));
@@ -2520,8 +2538,7 @@ sra_build_elt_assignment (struct sra_elt *elt, tree src)
        }
       else
        {
-         src = fold_build3 (BIT_FIELD_REF, TREE_TYPE (var), src, cst, cst2);
-         BIT_FIELD_REF_UNSIGNED (src) = 1;
+         src = fold_convert (TREE_TYPE (var), tmp);
        }
 
       return sra_build_assignment (var, src);
@@ -2600,7 +2617,33 @@ generate_element_copy (struct sra_elt *dst, struct sra_elt *src, tree *list_p)
 
          continue;
        }
-      gcc_assert (sc);
+
+      /* If DST and SRC are structs with the same elements, but do not have
+        the same TYPE_MAIN_VARIANT, then lookup of DST FIELD_DECL in SRC
+        will fail.  Try harder by finding the corresponding FIELD_DECL
+        in SRC.  */
+      if (!sc)
+       {
+         tree f;
+
+         gcc_assert (useless_type_conversion_p (dst->type, src->type));
+         gcc_assert (TREE_CODE (dc->element) == FIELD_DECL);
+         for (f = TYPE_FIELDS (src->type); f ; f = TREE_CHAIN (f))
+           if (simple_cst_equal (DECL_FIELD_OFFSET (f),
+                                 DECL_FIELD_OFFSET (dc->element)) > 0
+               && simple_cst_equal (DECL_FIELD_BIT_OFFSET (f),
+                                    DECL_FIELD_BIT_OFFSET (dc->element)) > 0
+               && simple_cst_equal (DECL_SIZE (f),
+                                    DECL_SIZE (dc->element)) > 0
+               && (useless_type_conversion_p (TREE_TYPE (dc->element),
+                                              TREE_TYPE (f))
+                   || (POINTER_TYPE_P (TREE_TYPE (dc->element))
+                       && POINTER_TYPE_P (TREE_TYPE (f)))))
+             break;
+         gcc_assert (f != NULL_TREE);
+         sc = lookup_element (src, f, NULL, NO_INSERT);
+       }
+
       generate_element_copy (dc, sc, list_p);
     }
 
@@ -2972,6 +3015,8 @@ sra_explode_bitfield_assignment (tree var, tree vpos, bool to_var,
          type = TREE_TYPE (infld);
          if (TYPE_PRECISION (type) != TREE_INT_CST_LOW (flen))
            type = lang_hooks.types.type_for_size (TREE_INT_CST_LOW (flen), 1);
+         else
+           type = unsigned_type_for (type);
 
          if (TREE_CODE (infld) == BIT_FIELD_REF)
            {
@@ -2989,7 +3034,6 @@ sra_explode_bitfield_assignment (tree var, tree vpos, bool to_var,
            }
 
          infld = fold_build3 (BIT_FIELD_REF, type, infld, flen, fpos);
-         BIT_FIELD_REF_UNSIGNED (infld) = 1;
 
          invar = size_binop (MINUS_EXPR, flp.field_pos, bpos);
          if (flp.overlap_pos)
@@ -2997,7 +3041,6 @@ sra_explode_bitfield_assignment (tree var, tree vpos, bool to_var,
          invar = size_binop (PLUS_EXPR, invar, vpos);
 
          invar = fold_build3 (BIT_FIELD_REF, type, var, flen, invar);
-         BIT_FIELD_REF_UNSIGNED (invar) = 1;
 
          if (to_var)
            st = sra_build_bf_assignment (invar, infld);