OSDN Git Service

2005-07-06 Daniel Berlin <dberlin@dberlin.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-structalias.c
index 61137aa..efa2238 100644 (file)
@@ -34,7 +34,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 #include "basic-block.h"
 #include "output.h"
 #include "errors.h"
-#include "expr.h"
 #include "diagnostic.h"
 #include "tree.h"
 #include "c-common.h"
@@ -1850,13 +1849,14 @@ get_constraint_exp_from_ssa_var (tree t)
 
   cexpr.type = SCALAR;
   
-  if (TREE_READONLY (t))
+  cexpr.var = get_id_for_tree (t);
+  /* If we determine the result is "anything", and we know this is readonly,
+     say it points to readonly memory instead.  */
+  if (cexpr.var == anything_id && TREE_READONLY (t))
     {
       cexpr.type = ADDRESSOF;
       cexpr.var = readonly_id;
     }
-  else
-    cexpr.var = get_id_for_tree (t);    
     
   cexpr.offset = 0;
   return cexpr;
@@ -1940,6 +1940,25 @@ bitpos_of_field (const tree fdecl)
 }
 
 
+/* Return true if an access to [ACCESSPOS, ACCESSSIZE]
+   overlaps with a field at [FIELDPOS, FIELDSIZE] */
+
+static bool
+offset_overlaps_with_access (const unsigned HOST_WIDE_INT fieldpos,
+                            const unsigned HOST_WIDE_INT fieldsize,
+                            const unsigned HOST_WIDE_INT accesspos,
+                            const unsigned HOST_WIDE_INT accesssize)
+{
+  if (fieldpos == accesspos && fieldsize == accesssize)
+    return true;
+  if (accesspos >= fieldpos && accesspos < (fieldpos + fieldsize))
+    return true;
+  if (accesspos < fieldpos && (accesspos + accesssize > fieldpos))
+    return true;
+  
+  return false;
+}
+
 /* Given a COMPONENT_REF T, return the constraint_expr for it.  */
 
 static struct constraint_expr
@@ -2000,8 +2019,27 @@ get_constraint_for_component_ref (tree t)
         we may have to do something cute here.  */
       
       if (result.offset < get_varinfo (result.var)->fullsize)  
-       result.var = first_vi_for_offset (get_varinfo (result.var), 
-                                         result.offset)->id;
+       {
+         /* It's also not true that the constraint will actually start at the
+            right offset, it may start in some padding.  We only care about
+            setting the constraint to the first actual field it touches, so
+            walk to find it.  */ 
+         varinfo_t curr;
+         for (curr = get_varinfo (result.var); curr; curr = curr->next)
+           {
+             if (offset_overlaps_with_access (curr->offset, curr->size,
+                                              result.offset, bitsize))
+               {
+                 result.var = curr->id;
+                 break;
+
+               }
+           }
+         /* assert that we found *some* field there. The user couldn't be
+            accessing *only* padding.  */
+            
+         gcc_assert (curr);
+       }
       else
        if (dump_file && (dump_flags & TDF_DETAILS))
          fprintf (dump_file, "Access to past the end of variable, ignoring\n");
@@ -2358,18 +2396,39 @@ do_structure_copy (tree lhsop, tree rhsop)
     }
   else
     {
+      tree rhstype = TREE_TYPE (rhsop);
+      tree lhstype = TREE_TYPE (lhsop);
+      tree rhstypesize = TYPE_SIZE (rhstype);
+      tree lhstypesize = TYPE_SIZE (lhstype);
+
+      /* If we have a variably sized types on the rhs or lhs, and a deref
+        constraint, add the constraint, lhsconstraint = &ANYTHING.
+        This is conservatively correct because either the lhs is an unknown
+        sized var (if the constraint is SCALAR), or the lhs is a DEREF
+        constraint, and every variable it can point to must be unknown sized
+        anyway, so we don't need to worry about fields at all.  */
+      if ((rhs.type == DEREF && TREE_CODE (rhstypesize) != INTEGER_CST)
+         || (lhs.type == DEREF && TREE_CODE (lhstypesize) != INTEGER_CST))
+       {
+         rhs.var = anything_id;
+         rhs.type = ADDRESSOF;
+         rhs.offset = 0;
+         process_constraint (new_constraint (lhs, rhs));
+         return;
+       }
+
       /* The size only really matters insofar as we don't set more or less of
         the variable.  If we hit an unknown size var, the size should be the
         whole darn thing.  */
       if (get_varinfo (rhs.var)->is_unknown_size_var)
        rhssize = ~0;
       else
-       rhssize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (rhsop)));
+       rhssize = TREE_INT_CST_LOW (rhstypesize);
 
       if (get_varinfo (lhs.var)->is_unknown_size_var)
        lhssize = ~0;
       else
-       lhssize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (lhsop)));
+       lhssize = TREE_INT_CST_LOW (lhstypesize);
 
   
       if (rhs.type == SCALAR && lhs.type == SCALAR)  
@@ -2380,9 +2439,7 @@ do_structure_copy (tree lhsop, tree rhsop)
        do_lhs_deref_structure_copy (lhs, rhs, MIN (lhssize, rhssize));
       else
        {
-         tree rhsdecl = get_varinfo (rhs.var)->decl;
-         tree pointertype = TREE_TYPE (rhsdecl);
-         tree pointedtotype = TREE_TYPE (pointertype);
+         tree pointedtotype = lhstype;
          tree tmpvar;  
 
          gcc_assert (rhs.type == DEREF && lhs.type == DEREF);