OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-structalias.c
index 7de22aa..0d4258d 100644 (file)
@@ -261,9 +261,6 @@ struct variable_info
   /* True if this is a heap variable.  */
   unsigned int is_heap_var : 1;
 
-  /* True if this is a variable tracking a restrict pointer source.  */
-  unsigned int is_restrict_var : 1;
-
   /* True if this field may contain pointers.  */
   unsigned int may_have_pointers : 1;
 
@@ -306,6 +303,7 @@ static varinfo_t first_vi_for_offset (varinfo_t, unsigned HOST_WIDE_INT);
 static varinfo_t first_or_preceding_vi_for_offset (varinfo_t,
                                                   unsigned HOST_WIDE_INT);
 static varinfo_t lookup_vi_for_tree (tree);
+static inline bool type_can_have_subvars (const_tree);
 
 /* Pool of variable info structures.  */
 static alloc_pool variable_info_pool;
@@ -350,7 +348,6 @@ new_var_info (tree t, const char *name)
   ret->is_unknown_size_var = false;
   ret->is_full_var = (t == NULL_TREE);
   ret->is_heap_var = false;
-  ret->is_restrict_var = false;
   ret->may_have_pointers = true;
   ret->only_restrict_pointers = false;
   ret->is_global_var = (t == NULL_TREE);
@@ -1919,10 +1916,10 @@ equiv_class_label_eq (const void *p1, const void *p2)
 }
 
 /* Lookup a equivalence class in TABLE by the bitmap of LABELS it
-   contains.  */
+   contains.  Sets *REF_LABELS to the bitmap LABELS is equivalent to.  */
 
 static unsigned int
-equiv_class_lookup (htab_t table, bitmap labels)
+equiv_class_lookup (htab_t table, bitmap labels, bitmap *ref_labels)
 {
   void **slot;
   struct equiv_class_label ecl;
@@ -1933,9 +1930,18 @@ equiv_class_lookup (htab_t table, bitmap labels)
   slot = htab_find_slot_with_hash (table, &ecl,
                                   ecl.hashcode, NO_INSERT);
   if (!slot)
-    return 0;
+    {
+      if (ref_labels)
+       *ref_labels = NULL;
+      return 0;
+    }
   else
-    return ((equiv_class_label_t) *slot)->equivalence_class;
+    {
+      equiv_class_label_t ec = (equiv_class_label_t) *slot;
+      if (ref_labels)
+       *ref_labels = ec->labels;
+      return ec->equivalence_class;
+    }
 }
 
 
@@ -2135,14 +2141,21 @@ label_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
 
   if (!bitmap_empty_p (graph->points_to[n]))
     {
+      bitmap ref_points_to;
       unsigned int label = equiv_class_lookup (pointer_equiv_class_table,
-                                              graph->points_to[n]);
+                                              graph->points_to[n],
+                                              &ref_points_to);
       if (!label)
        {
          label = pointer_equiv_class++;
          equiv_class_add (pointer_equiv_class_table,
                           label, graph->points_to[n]);
        }
+      else
+       {
+         BITMAP_FREE (graph->points_to[n]);
+         graph->points_to[n] = ref_points_to;
+       }
       graph->pointer_label[n] = label;
     }
 }
@@ -2202,7 +2215,7 @@ perform_var_substitution (constraint_graph_t graph)
       /* Look up the location equivalence label if one exists, or make
         one otherwise.  */
       label = equiv_class_lookup (location_equiv_class_table,
-                                 pointed_by);
+                                 pointed_by, NULL);
       if (label == 0)
        {
          label = location_equiv_class++;
@@ -3279,7 +3292,8 @@ get_constraint_for_1 (tree t, VEC (ce_s, heap) **results, bool address_p,
                return;
 
              cs = *VEC_last (ce_s, *results);
-             if (cs.type == DEREF)
+             if (cs.type == DEREF
+                 && type_can_have_subvars (TREE_TYPE (t)))
                {
                  /* For dereferences this means we have to defer it
                     to solving time.  */
@@ -3643,30 +3657,30 @@ make_heapvar (const char *name)
 }
 
 /* Create a new artificial heap variable with NAME and make a
-   constraint from it to LHS.  Return the created variable.  */
+   constraint from it to LHS.  Set flags according to a tag used
+   for tracking restrict pointers.  */
 
 static varinfo_t
-make_constraint_from_heapvar (varinfo_t lhs, const char *name)
+make_constraint_from_restrict (varinfo_t lhs, const char *name)
 {
   varinfo_t vi = make_heapvar (name);
+  vi->is_global_var = 1;
+  vi->may_have_pointers = 1;
   make_constraint_from (lhs, vi->id);
-
   return vi;
 }
 
 /* Create a new artificial heap variable with NAME and make a
    constraint from it to LHS.  Set flags according to a tag used
-   for tracking restrict pointers.  */
+   for tracking restrict pointers and make the artificial heap
+   point to global memory.  */
 
-static void
-make_constraint_from_restrict (varinfo_t lhs, const char *name)
+static varinfo_t
+make_constraint_from_global_restrict (varinfo_t lhs, const char *name)
 {
-  varinfo_t vi;
-  vi = make_constraint_from_heapvar (lhs, name);
-  vi->is_restrict_var = 1;
-  vi->is_global_var = 0;
-  vi->is_special_var = 1;
-  vi->may_have_pointers = 0;
+  varinfo_t vi = make_constraint_from_restrict (lhs, name);
+  make_copy_constraint (vi, nonlocal_id);
+  return vi;
 }
 
 /* In IPA mode there are varinfos for different aspects of reach
@@ -3737,29 +3751,43 @@ handle_rhs_call (gimple stmt, VEC(ce_s, heap) **results)
       /* As we compute ESCAPED context-insensitive we do not gain
          any precision with just EAF_NOCLOBBER but not EAF_NOESCAPE
         set.  The argument would still get clobbered through the
-        escape solution.
-        ???  We might get away with less (and more precise) constraints
-        if using a temporary for transitively closing things.  */
+        escape solution.  */
       if ((flags & EAF_NOCLOBBER)
           && (flags & EAF_NOESCAPE))
        {
          varinfo_t uses = get_call_use_vi (stmt);
          if (!(flags & EAF_DIRECT))
-           make_transitive_closure_constraints (uses);
-         make_constraint_to (uses->id, arg);
+           {
+             varinfo_t tem = new_var_info (NULL_TREE, "callarg");
+             make_constraint_to (tem->id, arg);
+             make_transitive_closure_constraints (tem);
+             make_copy_constraint (uses, tem->id);
+           }
+         else
+           make_constraint_to (uses->id, arg);
          returns_uses = true;
        }
       else if (flags & EAF_NOESCAPE)
        {
+         struct constraint_expr lhs, rhs;
          varinfo_t uses = get_call_use_vi (stmt);
          varinfo_t clobbers = get_call_clobber_vi (stmt);
+         varinfo_t tem = new_var_info (NULL_TREE, "callarg");
+         make_constraint_to (tem->id, arg);
          if (!(flags & EAF_DIRECT))
-           {
-             make_transitive_closure_constraints (uses);
-             make_transitive_closure_constraints (clobbers);
-           }
-         make_constraint_to (uses->id, arg);
-         make_constraint_to (clobbers->id, arg);
+           make_transitive_closure_constraints (tem);
+         make_copy_constraint (uses, tem->id);
+         make_copy_constraint (clobbers, tem->id);
+         /* Add *tem = nonlocal, do not add *tem = callused as
+            EAF_NOESCAPE parameters do not escape to other parameters
+            and all other uses appear in NONLOCAL as well.  */
+         lhs.type = DEREF;
+         lhs.var = tem->id;
+         lhs.offset = 0;
+         rhs.type = SCALAR;
+         rhs.var = nonlocal_id;
+         rhs.offset = 0;
+         process_constraint (new_constraint (lhs, rhs));
          returns_uses = true;
        }
       else
@@ -3861,9 +3889,11 @@ handle_lhs_call (gimple stmt, tree lhs, int flags, VEC(ce_s, heap) *rhsc,
       tmpc.offset = 0;
       tmpc.type = ADDRESSOF;
       VEC_safe_push (ce_s, heap, rhsc, &tmpc);
+      process_all_all_constraints (lhsc, rhsc);
+      VEC_free (ce_s, heap, rhsc);
     }
-
-  process_all_all_constraints (lhsc, rhsc);
+  else
+    process_all_all_constraints (lhsc, rhsc);
 
   VEC_free (ce_s, heap, lhsc);
 }
@@ -3999,8 +4029,7 @@ find_func_aliases_for_builtin_call (gimple t)
   VEC(ce_s, heap) *rhsc = NULL;
   varinfo_t fi;
 
-  if (fndecl != NULL_TREE
-      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+  if (gimple_call_builtin_class_p (t, BUILT_IN_NORMAL))
     /* ???  All builtins that are handled here need to be handled
        in the alias-oracle query functions explicitly!  */
     switch (DECL_FUNCTION_CODE (fndecl))
@@ -4026,8 +4055,11 @@ find_func_aliases_for_builtin_call (gimple t)
       case BUILT_IN_MEMMOVE_CHK:
       case BUILT_IN_MEMPCPY_CHK:
       case BUILT_IN_STPCPY_CHK:
+      case BUILT_IN_STPNCPY_CHK:
       case BUILT_IN_STRCAT_CHK:
       case BUILT_IN_STRNCAT_CHK:
+      case BUILT_IN_TM_MEMCPY:
+      case BUILT_IN_TM_MEMMOVE:
        {
          tree res = gimple_call_lhs (t);
          tree dest = gimple_call_arg (t, (DECL_FUNCTION_CODE (fndecl)
@@ -4041,7 +4073,8 @@ find_func_aliases_for_builtin_call (gimple t)
                  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY
                  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPNCPY
                  || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY_CHK
-                 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY_CHK)
+                 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY_CHK
+                 || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPNCPY_CHK)
                get_constraint_for_ptr_offset (dest, NULL_TREE, &rhsc);
              else
                get_constraint_for (dest, &rhsc);
@@ -4060,6 +4093,7 @@ find_func_aliases_for_builtin_call (gimple t)
        }
       case BUILT_IN_MEMSET:
       case BUILT_IN_MEMSET_CHK:
+      case BUILT_IN_TM_MEMSET:
        {
          tree res = gimple_call_lhs (t);
          tree dest = gimple_call_arg (t, 0);
@@ -4201,6 +4235,50 @@ find_func_aliases_for_builtin_call (gimple t)
            }
          return true;
        }
+      CASE_BUILT_IN_TM_STORE (1):
+      CASE_BUILT_IN_TM_STORE (2):
+      CASE_BUILT_IN_TM_STORE (4):
+      CASE_BUILT_IN_TM_STORE (8):
+      CASE_BUILT_IN_TM_STORE (FLOAT):
+      CASE_BUILT_IN_TM_STORE (DOUBLE):
+      CASE_BUILT_IN_TM_STORE (LDOUBLE):
+      CASE_BUILT_IN_TM_STORE (M64):
+      CASE_BUILT_IN_TM_STORE (M128):
+      CASE_BUILT_IN_TM_STORE (M256):
+       {
+         tree addr = gimple_call_arg (t, 0);
+         tree src = gimple_call_arg (t, 1);
+
+         get_constraint_for (addr, &lhsc);
+         do_deref (&lhsc);
+         get_constraint_for (src, &rhsc);
+         process_all_all_constraints (lhsc, rhsc);
+         VEC_free (ce_s, heap, lhsc);
+         VEC_free (ce_s, heap, rhsc);
+         return true;
+       }
+      CASE_BUILT_IN_TM_LOAD (1):
+      CASE_BUILT_IN_TM_LOAD (2):
+      CASE_BUILT_IN_TM_LOAD (4):
+      CASE_BUILT_IN_TM_LOAD (8):
+      CASE_BUILT_IN_TM_LOAD (FLOAT):
+      CASE_BUILT_IN_TM_LOAD (DOUBLE):
+      CASE_BUILT_IN_TM_LOAD (LDOUBLE):
+      CASE_BUILT_IN_TM_LOAD (M64):
+      CASE_BUILT_IN_TM_LOAD (M128):
+      CASE_BUILT_IN_TM_LOAD (M256):
+       {
+         tree dest = gimple_call_lhs (t);
+         tree addr = gimple_call_arg (t, 0);
+
+         get_constraint_for (dest, &lhsc);
+         get_constraint_for (addr, &rhsc);
+         do_deref (&rhsc);
+         process_all_all_constraints (lhsc, rhsc);
+         VEC_free (ce_s, heap, lhsc);
+         VEC_free (ce_s, heap, rhsc);
+         return true;
+       }
       /* Variadic argument handling needs to be handled in IPA
         mode as well.  */
       case BUILT_IN_VA_START:
@@ -4441,7 +4519,11 @@ find_func_aliases (gimple origt)
       tree lhsop = gimple_assign_lhs (t);
       tree rhsop = (gimple_num_ops (t) == 2) ? gimple_assign_rhs1 (t) : NULL;
 
-      if (rhsop && AGGREGATE_TYPE_P (TREE_TYPE (lhsop)))
+      if (rhsop && TREE_CLOBBER_P (rhsop))
+       /* Ignore clobbers, they don't actually store anything into
+          the LHS.  */
+       ;
+      else if (rhsop && AGGREGATE_TYPE_P (TREE_TYPE (lhsop)))
        do_structure_copy (lhsop, rhsop);
       else
        {
@@ -4688,8 +4770,7 @@ find_func_clobbers (gimple origt)
 
       /* For builtins we do not have separate function info.  For those
         we do not generate escapes for we have to generate clobbers/uses.  */
-      if (decl
-         && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+      if (gimple_call_builtin_class_p (t, BUILT_IN_NORMAL))
        switch (DECL_FUNCTION_CODE (decl))
          {
          /* The following functions use and clobber memory pointed to
@@ -4710,6 +4791,7 @@ find_func_clobbers (gimple origt)
          case BUILT_IN_MEMMOVE_CHK:
          case BUILT_IN_MEMPCPY_CHK:
          case BUILT_IN_STPCPY_CHK:
+         case BUILT_IN_STPNCPY_CHK:
          case BUILT_IN_STRCAT_CHK:
          case BUILT_IN_STRNCAT_CHK:
            {
@@ -4993,6 +5075,15 @@ sort_fieldstack (VEC(fieldoff_s,heap) *fieldstack)
   VEC_qsort (fieldoff_s, fieldstack, fieldoff_compare);
 }
 
+/* Return true if T is a type that can have subvars.  */
+
+static inline bool
+type_can_have_subvars (const_tree t)
+{
+  /* Aggregates without overlapping fields can have subvars.  */
+  return TREE_CODE (t) == RECORD_TYPE;
+}
+
 /* Return true if V is a tree that we can have subvars for.
    Normally, this is any aggregate type.  Also complex
    types which are not gimple registers can have subvars.  */
@@ -5008,11 +5099,7 @@ var_can_have_subvars (const_tree v)
   if (!DECL_P (v))
     return false;
 
-  /* Aggregates without overlapping fields can have subvars.  */
-  if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE)
-    return true;
-
-  return false;
+  return type_can_have_subvars (TREE_TYPE (v));
 }
 
 /* Return true if T is a type that does contain pointers.  */
@@ -5504,13 +5591,18 @@ create_variable_info_for (tree decl, const char *name)
       if ((POINTER_TYPE_P (TREE_TYPE (decl))
           && TYPE_RESTRICT (TREE_TYPE (decl)))
          || vi->only_restrict_pointers)
-       make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
+       {
+         make_constraint_from_global_restrict (vi, "GLOBAL_RESTRICT");
+         continue;
+       }
 
       /* In non-IPA mode the initializer from nonlocal is all we need.  */
       if (!in_ipa_mode
          || DECL_HARD_REGISTER (decl))
        make_copy_constraint (vi, nonlocal_id);
 
+      /* In IPA mode parse the initializer and generate proper constraints
+        for it.  */
       else
        {
          struct varpool_node *vnode = varpool_get_node (decl);
@@ -5595,14 +5687,15 @@ intra_create_variable_infos (void)
      passed-by-reference argument.  */
   for (t = DECL_ARGUMENTS (current_function_decl); t; t = DECL_CHAIN (t))
     {
-      varinfo_t p;
+      varinfo_t p = get_vi_for_tree (t);
 
       /* For restrict qualified pointers to objects passed by
          reference build a real representative for the pointed-to object.
         Treat restrict qualified references the same.  */
       if (TYPE_RESTRICT (TREE_TYPE (t))
          && ((DECL_BY_REFERENCE (t) && POINTER_TYPE_P (TREE_TYPE (t)))
-             || TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE))
+             || TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+         && !type_contains_placeholder_p (TREE_TYPE (TREE_TYPE (t))))
        {
          struct constraint_expr lhsc, rhsc;
          varinfo_t vi;
@@ -5610,34 +5703,37 @@ intra_create_variable_infos (void)
          DECL_EXTERNAL (heapvar) = 1;
          vi = create_variable_info_for_1 (heapvar, "PARM_NOALIAS");
          insert_vi_for_tree (heapvar, vi);
-         lhsc.var = get_vi_for_tree (t)->id;
+         lhsc.var = p->id;
          lhsc.type = SCALAR;
          lhsc.offset = 0;
          rhsc.var = vi->id;
          rhsc.type = ADDRESSOF;
          rhsc.offset = 0;
          process_constraint (new_constraint (lhsc, rhsc));
-         vi->is_restrict_var = 1;
          for (; vi; vi = vi->next)
            if (vi->may_have_pointers)
              {
                if (vi->only_restrict_pointers)
-                 make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
-               make_copy_constraint (vi, nonlocal_id);
+                 make_constraint_from_global_restrict (vi, "GLOBAL_RESTRICT");
+               else
+                 make_copy_constraint (vi, nonlocal_id);
              }
          continue;
        }
 
-      for (p = get_vi_for_tree (t); p; p = p->next)
-       {
-         if (p->may_have_pointers)
-           make_constraint_from (p, nonlocal_id);
-         if (p->only_restrict_pointers)
-           make_constraint_from_restrict (p, "PARM_RESTRICT");
-       }
       if (POINTER_TYPE_P (TREE_TYPE (t))
          && TYPE_RESTRICT (TREE_TYPE (t)))
-       make_constraint_from_restrict (get_vi_for_tree (t), "PARM_RESTRICT");
+       make_constraint_from_global_restrict (p, "PARM_RESTRICT");
+      else
+       {
+         for (; p; p = p->next)
+           {
+             if (p->only_restrict_pointers)
+               make_constraint_from_global_restrict (p, "PARM_RESTRICT");
+             else if (p->may_have_pointers)
+               make_constraint_from (p, nonlocal_id);
+           }
+       }
     }
 
   /* Add a constraint for a result decl that is passed by reference.  */
@@ -5813,15 +5909,11 @@ find_what_var_points_to (varinfo_t orig_vi, struct pt_solution *pt)
                   || vi->id == integer_id)
            pt->anything = 1;
        }
-      if (vi->is_restrict_var)
-       pt->vars_contains_restrict = true;
     }
 
   /* Instead of doing extra work, simply do not create
      elaborate points-to information for pt_anything pointers.  */
-  if (pt->anything
-      && (orig_vi->is_artificial_var
-         || !pt->vars_contains_restrict))
+  if (pt->anything)
     return;
 
   /* Share the final set of variables when possible.  */
@@ -5912,13 +6004,11 @@ pt_solution_reset (struct pt_solution *pt)
    it contains restrict tag variables.  */
 
 void
-pt_solution_set (struct pt_solution *pt, bitmap vars,
-                bool vars_contains_global, bool vars_contains_restrict)
+pt_solution_set (struct pt_solution *pt, bitmap vars, bool vars_contains_global)
 {
   memset (pt, 0, sizeof (struct pt_solution));
   pt->vars = vars;
   pt->vars_contains_global = vars_contains_global;
-  pt->vars_contains_restrict = vars_contains_restrict;
 }
 
 /* Set the points-to solution *PT to point only to the variable VAR.  */
@@ -5953,7 +6043,6 @@ pt_solution_ior_into (struct pt_solution *dest, struct pt_solution *src)
   dest->ipa_escaped |= src->ipa_escaped;
   dest->null |= src->null;
   dest->vars_contains_global |= src->vars_contains_global;
-  dest->vars_contains_restrict |= src->vars_contains_restrict;
   if (!src->vars)
     return;
 
@@ -6141,27 +6230,6 @@ pt_solutions_intersect (struct pt_solution *pt1, struct pt_solution *pt2)
   return res;
 }
 
-/* Return true if both points-to solutions PT1 and PT2 for two restrict
-   qualified pointers are possibly based on the same pointer.  */
-
-bool
-pt_solutions_same_restrict_base (struct pt_solution *pt1,
-                                struct pt_solution *pt2)
-{
-  /* If we deal with points-to solutions of two restrict qualified
-     pointers solely rely on the pointed-to variable bitmap intersection.
-     For two pointers that are based on each other the bitmaps will
-     intersect.  */
-  if (pt1->vars_contains_restrict
-      && pt2->vars_contains_restrict)
-    {
-      gcc_assert (pt1->vars && pt2->vars);
-      return bitmap_intersect_p (pt1->vars, pt2->vars);
-    }
-
-  return true;
-}
-
 
 /* Dump points-to information to OUTFILE.  */
 
@@ -6574,7 +6642,6 @@ compute_points_to_sets (void)
   /* Mark escaped HEAP variables as global.  */
   FOR_EACH_VEC_ELT (varinfo_t, varmap, i, vi)
     if (vi->is_heap_var
-       && !vi->is_restrict_var
        && !vi->is_global_var)
       DECL_EXTERNAL (vi->decl) = vi->is_global_var
        = pt_solution_includes (&cfun->gimple_df->escaped, vi->decl);
@@ -6794,7 +6861,7 @@ gate_ipa_pta (void)
 
 /* IPA PTA solutions for ESCAPED.  */
 struct pt_solution ipa_escaped_pt
-  = { true, false, false, false, false, false, false, NULL };
+  = { true, false, false, false, false, false, NULL };
 
 /* Associate node with varinfo DATA. Worker for
    cgraph_for_node_and_aliases.  */