tree.c (init_ttree): Add STRUCT_FIELD_TAG handling.
authorDaniel Berlin <dberlin@dberlin.org>
Wed, 15 Feb 2006 22:09:45 +0000 (22:09 +0000)
committerDaniel Berlin <dberlin@gcc.gnu.org>
Wed, 15 Feb 2006 22:09:45 +0000 (22:09 +0000)
2006-02-15 Daniel Berlin  <dberlin@dberlin.org>

* tree.c (init_ttree): Add STRUCT_FIELD_TAG handling.
(tree_code_size): Ditto.
* tree.h (struct tree_memory_tag): Remove parent_var.
(struct tree_struct_field_tag): New.
(SFT_OFFSET): New.
(SFT_SIZE): New.
(union tree_node): Add sft member.
* tree-ssa-alias.c (get_tmt_for): Don't handle TYPE_READONLY
specially here.
(create_sft): Add size and offset argument, set SFT_OFFSET and
SFT_SIZE.
(create_overlap_variables_for): Update for SFT_OFFSET/SFT_SIZE.
* treestruct.def: Add TS_STRUCT_FIELD_TAG.
* tree-flow-inline.h (get_subvar_at): Update for
SFT_OFFSET/SFT_SIZE.
(var_can_have_subvars): Ditto.
(overlap_subvar): Ditto.
* print-tree.c (print_node): Print out interesting things for
SFT's.
* tree-flow.h (struct subvar): Remove offset and size members.
* tree-ssa-operands.c (get_expr_operands): Update for
get_indirect_ref_operands changes.
(get_indirect_ref_operands): Call add_virtual_operand instead of
add_stmt_operand.  Only recurse on base var if requested.
(access_can_touch_variable): New function.
(add_stmt_operand): Split virtual operand handling into ...
(add_virtual_operand): Here.  Add offset, size, and for_clobber
arguments.  Prune alias sets.
(add_call_clobber_ops): Call add_virtual_operand.

From-SVN: r111120

gcc/ChangeLog
gcc/print-tree.c
gcc/tree-flow-inline.h
gcc/tree-flow.h
gcc/tree-ssa-alias.c
gcc/tree-ssa-operands.c
gcc/tree.c
gcc/tree.h
gcc/treestruct.def

index 9b388d6..50477ba 100644 (file)
@@ -1,3 +1,35 @@
+2006-02-15 Daniel Berlin  <dberlin@dberlin.org>
+
+       * tree.c (init_ttree): Add STRUCT_FIELD_TAG handling.
+       (tree_code_size): Ditto.
+       * tree.h (struct tree_memory_tag): Remove parent_var.
+       (struct tree_struct_field_tag): New.
+       (SFT_OFFSET): New.
+       (SFT_SIZE): New.
+       (union tree_node): Add sft member.
+       * tree-ssa-alias.c (get_tmt_for): Don't handle TYPE_READONLY
+       specially here.
+       (create_sft): Add size and offset argument, set SFT_OFFSET and
+       SFT_SIZE.
+       (create_overlap_variables_for): Update for SFT_OFFSET/SFT_SIZE.
+       * treestruct.def: Add TS_STRUCT_FIELD_TAG.
+       * tree-flow-inline.h (get_subvar_at): Update for
+       SFT_OFFSET/SFT_SIZE.
+       (var_can_have_subvars): Ditto.
+       (overlap_subvar): Ditto.
+       * print-tree.c (print_node): Print out interesting things for
+       SFT's.
+       * tree-flow.h (struct subvar): Remove offset and size members.
+       * tree-ssa-operands.c (get_expr_operands): Update for
+       get_indirect_ref_operands changes.
+       (get_indirect_ref_operands): Call add_virtual_operand instead of
+       add_stmt_operand.  Only recurse on base var if requested.
+       (access_can_touch_variable): New function.
+       (add_stmt_operand): Split virtual operand handling into ...
+       (add_virtual_operand): Here.  Add offset, size, and for_clobber
+       arguments.  Prune alias sets.
+       (add_call_clobber_ops): Call add_virtual_operand.
+       
 2006-02-15  Jakub Jelinek  <jakub@redhat.com>
 
        PR middle-end/26300
index dad7e59..02e5c7b 100644 (file)
@@ -510,6 +510,15 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
          && DECL_HAS_VALUE_EXPR_P (node))
        print_node (file, "value-expr", DECL_VALUE_EXPR (node), indent + 4);
 
+      if (TREE_CODE (node) == STRUCT_FIELD_TAG)
+       {
+         fprintf (file, " sft size " HOST_WIDE_INT_PRINT_DEC, 
+                  SFT_SIZE (node));
+         fprintf (file, " sft offset " HOST_WIDE_INT_PRINT_DEC,
+                  SFT_OFFSET (node));
+         print_node_brief (file, "parent var", SFT_PARENT_VAR (node), 
+                           indent + 4);
+       }
       /* Print the decl chain only if decl is at second level.  */
       if (indent == 4)
        print_node (file, "chain", TREE_CHAIN (node), indent + 4);
index 1abf556..6a37b86 100644 (file)
@@ -1450,7 +1450,7 @@ get_subvar_at (tree var, unsigned HOST_WIDE_INT offset)
   subvar_t sv;
 
   for (sv = get_subvars_for_var (var); sv; sv = sv->next)
-    if (sv->offset == offset)
+    if (SFT_OFFSET (sv->var) == offset)
       return sv->var;
 
   return NULL_TREE;
@@ -1491,7 +1491,7 @@ var_can_have_subvars (tree v)
 
 static inline bool
 overlap_subvar (unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT size,
-               subvar_t sv,  bool *exact)
+               tree sv,  bool *exact)
 {
   /* There are three possible cases of overlap.
      1. We can have an exact overlap, like so:   
@@ -1511,17 +1511,19 @@ overlap_subvar (unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT size,
 
   if (exact)
     *exact = false;
-  if (offset == sv->offset && size == sv->size)
+  if (offset == SFT_OFFSET (sv) && size == SFT_SIZE (sv))
     {
       if (exact)
        *exact = true;
       return true;
     }
-  else if (offset >= sv->offset && offset < (sv->offset + sv->size))
+  else if (offset >= SFT_OFFSET (sv) 
+          && offset < (SFT_OFFSET (sv) + SFT_SIZE (sv)))
     {
       return true;
     }
-  else if (offset < sv->offset && (size > sv->offset - offset))
+  else if (offset < SFT_OFFSET (sv) 
+          && (size > SFT_OFFSET (sv) - offset))
     {
       return true;
     }
index 7774c3b..864835b 100644 (file)
@@ -149,12 +149,6 @@ struct subvar GTY(())
   /* Fake variable.  */
   tree var;
 
-  /* Offset inside structure.  */
-  unsigned HOST_WIDE_INT offset;
-
-  /* Size of the field.  */
-  unsigned HOST_WIDE_INT size;
-
   /* Next subvar for this structure.  */
   subvar_t next;
 };
@@ -610,7 +604,7 @@ extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *,
 static inline bool var_can_have_subvars (tree);
 static inline bool overlap_subvar (unsigned HOST_WIDE_INT,
                                   unsigned HOST_WIDE_INT,
-                                  subvar_t, bool *);
+                                  tree, bool *);
 
 /* Call-back function for walk_use_def_chains().  At each reaching
    definition, a function with this prototype is called.  */
index 75a5ae5..b262fd0 100644 (file)
@@ -2061,8 +2061,7 @@ get_tmt_for (tree ptr, struct alias_info *ai)
     {
       struct alias_map_d *curr = ai->pointers[i];
       tree curr_tag = var_ann (curr->var)->type_mem_tag;
-      if (tag_set == curr->set
-         && TYPE_READONLY (tag_type) == TYPE_READONLY (TREE_TYPE (curr_tag)))
+      if (tag_set == curr->set)
        {
          tag = curr_tag;
          break;
@@ -2099,10 +2098,6 @@ get_tmt_for (tree ptr, struct alias_info *ai)
      pointed-to type.  */
   gcc_assert (tag_set == get_alias_set (tag));
 
-  /* If PTR's pointed-to type is read-only, then TAG's type must also
-     be read-only.  */
-  gcc_assert (TYPE_READONLY (tag_type) == TYPE_READONLY (TREE_TYPE (tag)));
-
   return tag;
 }
 
@@ -2749,11 +2744,12 @@ get_or_create_used_part_for (size_t uid)
 }
 
 
-/* Create and return a structure sub-variable for field type FIELD of
-   variable VAR.  */
+/* Create and return a structure sub-variable for field type FIELD at
+   offset OFFSET, with size SIZE, of variable VAR.  */
 
 static tree
-create_sft (tree var, tree field)
+create_sft (tree var, tree field, unsigned HOST_WIDE_INT offset,
+           unsigned HOST_WIDE_INT size)
 {
   var_ann_t ann;
   tree subvar = create_tag_raw (STRUCT_FIELD_TAG, field, "SFT");
@@ -2771,7 +2767,8 @@ create_sft (tree var, tree field)
   ann->type_mem_tag = NULL;    
   add_referenced_tmp_var (subvar);
   SFT_PARENT_VAR (subvar) = var;
-
+  SFT_OFFSET (subvar) = offset;
+  SFT_SIZE (subvar) = size;
   return subvar;
 }
 
@@ -2882,19 +2879,17 @@ create_overlap_variables_for (tree var)
                  && currfotype == lastfotype))
            continue;
          sv = GGC_NEW (struct subvar);
-         sv->offset = fo->offset;
-         sv->size = fosize;
          sv->next = *subvars;
-         sv->var = create_sft (var, fo->type);
+         sv->var = create_sft (var, fo->type, fo->offset, fosize);
 
          if (dump_file)
            {
              fprintf (dump_file, "structure field tag %s created for var %s",
                       get_name (sv->var), get_name (var));
              fprintf (dump_file, " offset " HOST_WIDE_INT_PRINT_DEC,
-                      sv->offset);
+                      SFT_OFFSET (sv->var));
              fprintf (dump_file, " size " HOST_WIDE_INT_PRINT_DEC,
-                      sv->size);
+                      SFT_SIZE (sv->var));
              fprintf (dump_file, "\n");
            }
          
index fbee0b9..2d0e71c 100644 (file)
@@ -128,7 +128,8 @@ static unsigned operand_memory_index;
 
 static void get_expr_operands (tree, tree *, int);
 static void get_asm_expr_operands (tree);
-static void get_indirect_ref_operands (tree, tree, int);
+static void get_indirect_ref_operands (tree, tree, int, tree, HOST_WIDE_INT,
+                                      HOST_WIDE_INT, bool);
 static void get_tmr_operands (tree, tree, int);
 static void get_call_expr_operands (tree, tree);
 static inline void append_def (tree *);
@@ -138,6 +139,9 @@ static void append_v_must_def (tree);
 static void add_call_clobber_ops (tree, tree);
 static void add_call_read_ops (tree, tree);
 static void add_stmt_operand (tree *, stmt_ann_t, int);
+static void add_virtual_operand (tree, stmt_ann_t, int, tree,
+                                HOST_WIDE_INT, HOST_WIDE_INT, 
+                                bool);
 static void build_ssa_operands (tree stmt);
                                                                                 
 static def_optype_p free_defs = NULL;
@@ -1123,7 +1127,8 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
 
     case ALIGN_INDIRECT_REF:
     case INDIRECT_REF:
-      get_indirect_ref_operands (stmt, expr, flags);
+      get_indirect_ref_operands (stmt, expr, flags, NULL_TREE,
+                                0, -1, true);
       return;
 
     case TARGET_MEM_REF:
@@ -1165,7 +1170,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
            for (sv = svars; sv; sv = sv->next)
              {
                bool exact;             
-               if (overlap_subvar (offset, maxsize, sv, &exact))
+               if (overlap_subvar (offset, maxsize, sv->var, &exact))
                  {
                    int subvar_flags = flags;
                    none = false;
@@ -1178,6 +1183,12 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
            if (!none)
              flags |= opf_no_vops;
          }
+       else if (TREE_CODE (ref) == INDIRECT_REF)
+         {
+           get_indirect_ref_operands (stmt, ref, flags, expr, 
+                                      offset, maxsize, false);
+           flags |= opf_no_vops;
+         }
 
        /* Even if we found subvars above we need to ensure to see
           immediate uses for d in s.a[d].  In case of s.a having
@@ -1416,10 +1427,24 @@ get_asm_expr_operands (tree stmt)
 }
 
 /* A subroutine of get_expr_operands to handle INDIRECT_REF,
-   ALIGN_INDIRECT_REF and MISALIGNED_INDIRECT_REF.  */
+   ALIGN_INDIRECT_REF and MISALIGNED_INDIRECT_REF.  
+   STMT is the statement being processed, EXPR is the INDIRECT_REF
+   that got us here.  FLAGS is as in get_expr_operands.
+   FULL_REF contains the full pointer dereference expression, if we
+   have it, or NULL otherwise.
+   OFFSET and SIZE are the location of the access inside the
+   dereferenced pointer, if known.
+   RECURSE_ON_BASE should be set to true if we want to continue
+   calling get_expr_operands on the base pointer, and false if
+   something else will do it for us.
+
+*/
 
 static void
-get_indirect_ref_operands (tree stmt, tree expr, int flags)
+get_indirect_ref_operands (tree stmt, tree expr, int flags,
+                          tree full_ref,
+                          HOST_WIDE_INT offset, HOST_WIDE_INT size,
+                          bool recurse_on_base)
 {
   tree *pptr = &TREE_OPERAND (expr, 0);
   tree ptr = *pptr;
@@ -1438,7 +1463,8 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags)
          && pi->name_mem_tag)
        {
          /* PTR has its own memory tag.  Use it.  */
-         add_stmt_operand (&pi->name_mem_tag, s_ann, flags);
+         add_virtual_operand (pi->name_mem_tag, s_ann, flags,
+                              full_ref, offset, size, false);
        }
       else
        {
@@ -1464,8 +1490,10 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags)
          if (TREE_CODE (ptr) == SSA_NAME)
            ptr = SSA_NAME_VAR (ptr);
          v_ann = var_ann (ptr);
+
          if (v_ann->type_mem_tag)
-           add_stmt_operand (&v_ann->type_mem_tag, s_ann, flags);
+           add_virtual_operand (v_ann->type_mem_tag, s_ann, flags,
+                                full_ref, offset, size, false);
        }
     }
 
@@ -1483,7 +1511,8 @@ get_indirect_ref_operands (tree stmt, tree expr, int flags)
     gcc_unreachable ();
 
   /* Add a USE operand for the base pointer.  */
-  get_expr_operands (stmt, pptr, opf_none);
+  if (recurse_on_base)
+    get_expr_operands (stmt, pptr, opf_none);
 }
 
 /* A subroutine of get_expr_operands to handle TARGET_MEM_REF.  */
@@ -1528,7 +1557,7 @@ get_tmr_operands (tree stmt, tree expr, int flags)
   for (sv = svars; sv; sv = sv->next)
     {
       bool exact;              
-      if (overlap_subvar (offset, maxsize, sv, &exact))
+      if (overlap_subvar (offset, maxsize, sv->var, &exact))
        {
          int subvar_flags = flags;
          if (!exact || size != maxsize)
@@ -1580,30 +1609,151 @@ get_call_expr_operands (tree stmt, tree expr)
 
 }
 
+/* REF is a tree that contains the entire pointer dereference
+   expression, if available, or NULL otherwise.  ALIAS is the variable
+   we are asking if REF can access.  OFFSET and SIZE come from the
+   memory access expression that generated this virtual operand.
+   FOR_CLOBBER is true is this is adding a virtual operand for a call
+   clobber.  */
+
+static bool
+access_can_touch_variable (tree ref, tree alias, HOST_WIDE_INT offset,
+                          HOST_WIDE_INT size)
+{  
+  bool offsetgtz = offset > 0;
+  unsigned HOST_WIDE_INT uoffset = (unsigned HOST_WIDE_INT) offset;
+  tree base = ref ? get_base_address (ref) : NULL;
+
+  /* If ALIAS is an SFT, it can't be touched if the offset     
+     and size of the access is not overlapping with the SFT offset and
+     size.    This is only true if we are accessing through a pointer
+     to a type that is the same as SFT_PARENT_VAR.  Otherwise, we may
+     be accessing through a pointer to some substruct of the
+     structure, and if we try to prune there, we will have the wrong
+     offset, and get the wrong answer.
+     i.e., we can't prune without more work if we have something like
+     struct gcc_target
+     {
+       struct asm_out
+       {
+         const char *byte_op;
+        struct asm_int_op
+        {    
+          const char *hi;
+        } aligned_op;
+       } asm_out;
+     } targetm;
+     
+     foo = &targetm.asm_out.aligned_op;
+     return foo->hi;
+
+     SFT.1, which represents hi, will have SFT_OFFSET=32 because in
+     terms of SFT_PARENT_VAR, that is where it is.
+     However, the access through the foo pointer will be at offset 0.
+  */
+  if (size != -1
+      && TREE_CODE (alias) == STRUCT_FIELD_TAG
+      && base
+      && TREE_TYPE (base) == TREE_TYPE (SFT_PARENT_VAR (alias))
+      && !overlap_subvar (offset, size, alias, NULL))
+    {
+#ifdef ACCESS_DEBUGGING
+      fprintf (stderr, "Access to ");
+      print_generic_expr (stderr, ref, 0);
+      fprintf (stderr, " may not touch ");
+      print_generic_expr (stderr, alias, 0);
+      fprintf (stderr, " in function %s\n", get_name (current_function_decl));
+#endif
+      return false;
+    }
+  /* Without strict aliasing, it is impossible for a component access
+     through a pointer to touch a random variable, unless that
+     variable *is* a structure or a pointer.
 
-/* Add *VAR_P to the appropriate operand array for INFO.  FLAGS is as in
-   get_expr_operands.  If *VAR_P is a GIMPLE register, it will be added to
-   the statement's real operands, otherwise it is added to virtual
-   operands.  */
+     
+     IE given p->c, and some random global variable b,
+     there is no legal way that p->c could be an access to b.
+     
+     Without strict aliasing on, we consider it legal to do something
+     like:
+     struct foos { int l; };
+     int foo;
+     static struct foos *getfoo(void);
+     int main (void)
+     {
+       struct foos *f = getfoo();
+       f->l = 1;
+       foo = 2;
+       if (f->l == 1)
+         abort();
+       exit(0);
+     }
+     static struct foos *getfoo(void)     
+     { return (struct foos *)&foo; }
+     
+     (taken from 20000623-1.c)
+  */
+  else if (ref 
+          && flag_strict_aliasing
+          && TREE_CODE (ref) != INDIRECT_REF
+          && !MTAG_P (alias)
+          && !AGGREGATE_TYPE_P (TREE_TYPE (alias))
+          && !TREE_CODE (TREE_TYPE (alias)) == COMPLEX_TYPE
+          && !POINTER_TYPE_P (TREE_TYPE (alias)))
+    {
+#ifdef ACCESS_DEBUGGING
+      fprintf (stderr, "Access to ");
+      print_generic_expr (stderr, ref, 0);
+      fprintf (stderr, " may not touch ");
+      print_generic_expr (stderr, alias, 0);
+      fprintf (stderr, " in function %s\n", get_name (current_function_decl));
+#endif
+      return false;
+    }
+  /* If the offset of the access is greater than the size of one of
+     the possible aliases, it can't be touching that alias, because it
+     would be past the end of the structure.  */
+  else if (ref
+          && flag_strict_aliasing
+          && TREE_CODE (ref) != INDIRECT_REF
+          && !MTAG_P (alias)
+          && !POINTER_TYPE_P (TREE_TYPE (alias))
+          && offsetgtz
+          && DECL_SIZE (alias)
+          && TREE_CODE (DECL_SIZE (alias)) == INTEGER_CST
+          && uoffset > TREE_INT_CST_LOW (DECL_SIZE (alias)))
+    {
+#ifdef ACCESS_DEBUGGING
+      fprintf (stderr, "Access to ");
+      print_generic_expr (stderr, ref, 0);
+      fprintf (stderr, " may not touch ");
+      print_generic_expr (stderr, alias, 0);
+      fprintf (stderr, " in function %s\n", get_name (current_function_decl));
+#endif
+      return false;
+    }     
+  return true;
+}
 
-static void
-add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
+/* Add VAR to the virtual operands array. FLAGS is as in
+   get_expr_operands.  FULL_REF is a tree that contains the entire
+   pointer dereference expression, if available, or NULL otherwise.
+   OFFSET and SIZE come from the memory access expression that
+   generated this virtual operand.  FOR_CLOBBER is true is this is
+   adding a virtual operand for a call clobber.  */
+
+static void 
+add_virtual_operand (tree var, stmt_ann_t s_ann, int flags,
+                    tree full_ref, HOST_WIDE_INT offset,
+                    HOST_WIDE_INT size, bool for_clobber)
 {
-  bool is_real_op;
-  tree var, sym;
+  VEC(tree,gc) *aliases;
+  tree sym;
   var_ann_t v_ann;
-
-  var = *var_p;
-  gcc_assert (SSA_VAR_P (var));
-
-  is_real_op = is_gimple_reg (var);
-  /* If this is a real operand, the operand is either ssa name or decl.
-     Virtual operands may only be decls.  */
-  gcc_assert (is_real_op || DECL_P (var));
-
+  
   sym = (TREE_CODE (var) == SSA_NAME ? SSA_NAME_VAR (var) : var);
   v_ann = var_ann (sym);
-
+  
   /* Mark statements with volatile operands.  Optimizers should back
      off from statements having volatile operands.  */
   if (TREE_THIS_VOLATILE (sym) && s_ann)
@@ -1623,93 +1773,146 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
      at runtime, then the program is ill formed.  If the statement is
      not executed then all is well.  At the very least, we cannot ICE.  */
   if ((flags & opf_non_specific) && unmodifiable_var_p (var))
-    {
-      gcc_assert (!is_real_op);
-      flags &= ~(opf_is_def | opf_kill_def);
-    }
+    flags &= ~(opf_is_def | opf_kill_def);
+  
 
-  if (is_real_op)
+  /* The variable is not a GIMPLE register.  Add it (or its aliases) to
+     virtual operands, unless the caller has specifically requested
+     not to add virtual operands (used when adding operands inside an
+     ADDR_EXPR expression).  */
+  if (flags & opf_no_vops)
+    return;
+  
+  aliases = v_ann->may_aliases;
+  if (aliases == NULL)
     {
-      /* The variable is a GIMPLE register.  Add it to real operands.  */
+      /* The variable is not aliased or it is an alias tag.  */
       if (flags & opf_is_def)
-       append_def (var_p);
+       {
+         if (flags & opf_kill_def)
+           {
+             /* Only regular variables or struct fields may get a
+                V_MUST_DEF operand.  */
+             gcc_assert (!MTAG_P (var)
+                         || TREE_CODE (var) == STRUCT_FIELD_TAG);
+             /* V_MUST_DEF for non-aliased, non-GIMPLE register 
+                variable definitions.  */
+             append_v_must_def (var);
+           }
+         else
+           {
+             /* Add a V_MAY_DEF for call-clobbered variables and
+                memory tags.  */
+             append_v_may_def (var);
+           }
+       }
       else
-       append_use (var_p);
+       append_vuse (var);
     }
   else
     {
-      VEC(tree,gc) *aliases;
-
-      /* The variable is not a GIMPLE register.  Add it (or its aliases) to
-        virtual operands, unless the caller has specifically requested
-        not to add virtual operands (used when adding operands inside an
-        ADDR_EXPR expression).  */
-      if (flags & opf_no_vops)
-       return;
+      unsigned i;
+      tree al;
+      
+      /* The variable is aliased.  Add its aliases to the virtual
+        operands.  */
+      gcc_assert (VEC_length (tree, aliases) != 0);
+      
+      if (flags & opf_is_def)
+       {
+         
+         bool none_added = true;
 
-      aliases = v_ann->may_aliases;
+         for (i = 0; VEC_iterate (tree, aliases, i, al); i++)
+           {
+             if (!access_can_touch_variable (full_ref, al, offset, size))
+               continue;
+             
+             none_added = false;
+             append_v_may_def (al);
+           }
 
-      if (aliases == NULL)
-       {
-         /* The variable is not aliased or it is an alias tag.  */
-         if (flags & opf_is_def)
+         /* If the variable is also an alias tag, add a virtual
+            operand for it, otherwise we will miss representing
+            references to the members of the variable's alias set.          
+            This fixes the bug in gcc.c-torture/execute/20020503-1.c.
+            
+            It is also necessary to add bare defs on clobbers for
+            TMT's, so that bare TMT uses caused by pruning all the
+            aliases will link up properly with calls.   */
+         if (v_ann->is_alias_tag || none_added
+             || (TREE_CODE (var) == TYPE_MEMORY_TAG && for_clobber))
            {
-             if (flags & opf_kill_def)
-               {
-                 /* Only regular variables or struct fields may get a
-                    V_MUST_DEF operand.  */
-                 gcc_assert (!MTAG_P (var)
-                             || TREE_CODE (var) == STRUCT_FIELD_TAG);
-                 /* V_MUST_DEF for non-aliased, non-GIMPLE register 
-                   variable definitions.  */
-                 append_v_must_def (var);
-               }
-             else
-               {
-                 /* Add a V_MAY_DEF for call-clobbered variables and
-                    memory tags.  */
-                 append_v_may_def (var);
-               }
+             /* We should never end up with adding no aliases of an
+                NMT, as that would imply we got the set wrong.  */
+             gcc_assert (!(none_added && TREE_CODE (var) == NAME_MEMORY_TAG));
+             
+             append_v_may_def (var);
            }
-         else
-           append_vuse (var);
        }
       else
        {
-         unsigned i;
-         tree al;
-
-         /* The variable is aliased.  Add its aliases to the virtual
-            operands.  */
-         gcc_assert (VEC_length (tree, aliases) != 0);
-
-         if (flags & opf_is_def)
+         bool none_added = true;
+         for (i = 0; VEC_iterate (tree, aliases, i, al); i++)
            {
-             /* If the variable is also an alias tag, add a virtual
-                operand for it, otherwise we will miss representing
-                references to the members of the variable's alias set.
-                This fixes the bug in gcc.c-torture/execute/20020503-1.c.  */
-             if (v_ann->is_alias_tag)
-               append_v_may_def (var);
-
-             for (i = 0; VEC_iterate (tree, aliases, i, al); i++)
-               append_v_may_def (al);
+             if (!access_can_touch_variable (full_ref, al, offset, size))
+               continue;
+             none_added = false;
+             append_vuse (al);
            }
-         else
+
+         /* Similarly, append a virtual uses for VAR itself, when
+            it is an alias tag.  */
+         if (v_ann->is_alias_tag || none_added)
            {
-             /* Similarly, append a virtual uses for VAR itself, when
-                it is an alias tag.  */
-             if (v_ann->is_alias_tag)
-               append_vuse (var);
+             gcc_assert (!(none_added && TREE_CODE (var) == NAME_MEMORY_TAG));
 
-             for (i = 0; VEC_iterate (tree, aliases, i, al); i++)
-               append_vuse (al);
+             append_vuse (var);
            }
        }
     }
 }
 
-  
+/* Add *VAR_P to the appropriate operand array for INFO.  FLAGS is as in
+   get_expr_operands.  If *VAR_P is a GIMPLE register, it will be added to
+   the statement's real operands, otherwise it is added to virtual
+   operands.  */
+
+static void
+add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
+{
+  bool is_real_op;
+  tree var, sym;
+  var_ann_t v_ann;
+
+  var = *var_p;
+  gcc_assert (SSA_VAR_P (var));
+
+  is_real_op = is_gimple_reg (var);
+  /* If this is a real operand, the operand is either ssa name or decl.
+     Virtual operands may only be decls.  */
+  gcc_assert (is_real_op || DECL_P (var));
+
+  sym = (TREE_CODE (var) == SSA_NAME ? SSA_NAME_VAR (var) : var);
+  v_ann = var_ann (sym);
+
+  /* Mark statements with volatile operands.  Optimizers should back
+     off from statements having volatile operands.  */
+  if (TREE_THIS_VOLATILE (sym) && s_ann)
+    s_ann->has_volatile_ops = true;
+
+  if (is_real_op)
+    {
+      /* The variable is a GIMPLE register.  Add it to real operands.  */
+      if (flags & opf_is_def)
+       append_def (var_p);
+      else
+       append_use (var_p);
+    }
+  else
+    add_virtual_operand (var, s_ann, flags, NULL_TREE, 0, -1, false);
+}
+
 /* Add the base address of REF to the set *ADDRESSES_TAKEN.  If
    *ADDRESSES_TAKEN is NULL, a new set is created.  REF may be
    a single variable whose address has been taken or any other valid
@@ -1836,7 +2039,8 @@ add_call_clobber_ops (tree stmt, tree callee)
            clobber_stats.static_read_clobbers_avoided++;
        }
       else
-       add_stmt_operand (&var, s_ann, opf_is_def);
+       add_virtual_operand (var, s_ann, opf_is_def, 
+                            NULL, 0, -1, true);
     }
   
 }
index d66e0c6..0a3d606 100644 (file)
@@ -276,6 +276,8 @@ init_ttree (void)
   tree_contains_struct[NAME_MEMORY_TAG][TS_MEMORY_TAG] = 1;
   tree_contains_struct[TYPE_MEMORY_TAG][TS_MEMORY_TAG] = 1;
 
+  tree_contains_struct[STRUCT_FIELD_TAG][TS_STRUCT_FIELD_TAG] = 1;
+
   tree_contains_struct[VAR_DECL][TS_DECL_WITH_VIS] = 1;
   tree_contains_struct[FUNCTION_DECL][TS_DECL_WITH_VIS] = 1;
   tree_contains_struct[TYPE_DECL][TS_DECL_WITH_VIS] = 1;
@@ -335,8 +337,9 @@ tree_code_size (enum tree_code code)
            return sizeof (struct tree_function_decl);
          case NAME_MEMORY_TAG:
          case TYPE_MEMORY_TAG:
-         case STRUCT_FIELD_TAG:
            return sizeof (struct tree_memory_tag);
+         case STRUCT_FIELD_TAG:
+           return sizeof (struct tree_struct_field_tag);
          default:
            return sizeof (struct tree_decl_non_common);
          }
index e89389d..f0cb29d 100644 (file)
@@ -2309,12 +2309,28 @@ struct tree_decl_minimal GTY(())
 struct tree_memory_tag GTY(())
 {
   struct tree_decl_minimal common;
-  tree parent_var;
   unsigned int is_global:1;
 };
 
 #define MTAG_GLOBAL(NODE) (TREE_MEMORY_TAG_CHECK (NODE)->mtag.is_global)
-#define SFT_PARENT_VAR(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->mtag.parent_var)
+
+struct tree_struct_field_tag GTY(())
+{
+  struct tree_memory_tag common;
+  
+  /* Parent variable.  */
+  tree parent_var;
+  /* Offset inside structure.  */
+  unsigned HOST_WIDE_INT offset;
+
+  /* Size of the field.  */
+  unsigned HOST_WIDE_INT size;
+
+};
+#define SFT_PARENT_VAR(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.parent_var)
+#define SFT_OFFSET(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.offset)
+#define SFT_SIZE(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.size)
 
 /* For any sort of a ..._DECL node, this points to the original (abstract)
    decl node which this decl is an instance of, or else it is NULL indicating
@@ -3124,6 +3140,7 @@ union tree_node GTY ((ptr_alias (union lang_tree_node),
   struct tree_value_handle GTY ((tag ("TS_VALUE_HANDLE"))) value_handle;
   struct tree_constructor GTY ((tag ("TS_CONSTRUCTOR"))) constructor;
   struct tree_memory_tag GTY ((tag ("TS_MEMORY_TAG"))) mtag;
+  struct tree_struct_field_tag GTY ((tag ("TS_STRUCT_FIELD_TAG"))) sft; 
   struct tree_omp_clause GTY ((tag ("TS_OMP_CLAUSE"))) omp_clause;
 };
 \f
index 3131d4b..b826be6 100644 (file)
@@ -60,4 +60,5 @@ DEFTREESTRUCT(TS_STATEMENT_LIST, "statement list")
 DEFTREESTRUCT(TS_VALUE_HANDLE, "value handle")
 DEFTREESTRUCT(TS_CONSTRUCTOR, "constructor")
 DEFTREESTRUCT(TS_MEMORY_TAG, "memory tag")
+DEFTREESTRUCT(TS_STRUCT_FIELD_TAG, "struct field tag")
 DEFTREESTRUCT(TS_OMP_CLAUSE, "omp clause")