2009-06-29 Richard Guenther <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 29 Jun 2009 12:23:21 +0000 (12:23 +0000)
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 29 Jun 2009 12:23:21 +0000 (12:23 +0000)
PR middle-end/14187
* tree-ssa-alias.h (struct pt_solution): Add vars_contains_restrict
flag.
(pt_solutions_same_restrict_base): Declare.
* tree-ssa-structalias.c (struct variable_info): Add is_restrict_var
flag.
(new_var_info): Initialize is_global_var properly for SSA_NAMEs.
(make_constraint_from, make_copy_constraint): Move earlier.
(make_constraint_from_heapvar): New function.
(make_constraint_from_restrict): Likewise.
(handle_lhs_call): Use it.
(find_func_aliases): Use it to track conversions to restrict
qualified pointers.
(struct fieldoff): Add only_restrict_pointers flag.
(push_fields_onto_fieldstack): Initialize it.
(create_variable_info_for): Track global restrict qualified pointers.
(intra_create_variable_infos): Use make_constraint_from_heapvar.
Track restrict qualified pointer arguments.
(set_uids_in_ptset): Use varinfo is_global_var flag.
(find_what_var_points_to): Set the vars_contains_restrict flag.
Always create the points-to solution for sets including restrict tags.
(pt_solutions_same_restrict_base): New function.
* tree-ssa-alias.c (ptr_derefs_may_alias_p): For two restrict
qualified pointers use pt_solutions_same_restrict_base as
additional source for disambiguation.

* gcc.dg/tree-ssa/restrict-1.c: New testcase.
* gcc.dg/tree-ssa/restrict-2.c: Likewise.
* gcc.dg/tree-ssa/restrict-3.c: Likewise.
* gcc.c-torture/execute/20090623-1.c: Likewise.
* gcc.dg/tree-ssa/ldist-13.c: Likewise.
* gcc.dg/tree-ssa/ldist-14.c: Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@149048 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/20090623-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ldist-13.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/ldist-14.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/restrict-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/restrict-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/restrict-3.c [new file with mode: 0644]
gcc/tree-ssa-alias.c
gcc/tree-ssa-alias.h
gcc/tree-ssa-structalias.c

index 3066cbe..351175c 100644 (file)
@@ -1,5 +1,33 @@
 2009-06-29  Richard Guenther  <rguenther@suse.de>
 
+       PR middle-end/14187
+       * tree-ssa-alias.h (struct pt_solution): Add vars_contains_restrict
+       flag.
+       (pt_solutions_same_restrict_base): Declare.
+       * tree-ssa-structalias.c (struct variable_info): Add is_restrict_var
+       flag.
+       (new_var_info): Initialize is_global_var properly for SSA_NAMEs.
+       (make_constraint_from, make_copy_constraint): Move earlier.
+       (make_constraint_from_heapvar): New function.
+       (make_constraint_from_restrict): Likewise.
+       (handle_lhs_call): Use it.
+       (find_func_aliases): Use it to track conversions to restrict
+       qualified pointers.
+       (struct fieldoff): Add only_restrict_pointers flag.
+       (push_fields_onto_fieldstack): Initialize it.
+       (create_variable_info_for): Track global restrict qualified pointers.
+       (intra_create_variable_infos): Use make_constraint_from_heapvar.
+       Track restrict qualified pointer arguments.
+       (set_uids_in_ptset): Use varinfo is_global_var flag.
+       (find_what_var_points_to): Set the vars_contains_restrict flag.
+       Always create the points-to solution for sets including restrict tags.
+       (pt_solutions_same_restrict_base): New function.
+       * tree-ssa-alias.c (ptr_derefs_may_alias_p): For two restrict
+       qualified pointers use pt_solutions_same_restrict_base as
+       additional source for disambiguation.
+
+2009-06-29  Richard Guenther  <rguenther@suse.de>
+
        PR middle-end/38212
        * alias.c (find_base_decl): Remove.
        (get_deref_alias_set_1): Remove restrict handling.
index dbac55f..d325d4a 100644 (file)
@@ -1,5 +1,15 @@
 2009-06-29  Richard Guenther  <rguenther@suse.de>
 
+       PR middle-end/14187
+       * gcc.dg/tree-ssa/restrict-1.c: New testcase.
+       * gcc.dg/tree-ssa/restrict-2.c: Likewise.
+       * gcc.dg/tree-ssa/restrict-3.c: Likewise.
+       * gcc.c-torture/execute/20090623-1.c: Likewise.
+       * gcc.dg/tree-ssa/ldist-13.c: Likewise.
+       * gcc.dg/tree-ssa/ldist-14.c: Likewise.
+
+2009-06-29  Richard Guenther  <rguenther@suse.de>
+
        PR middle-end/38212
        * gcc.c-torture/execute/pr38212.c: New testcase.
 
diff --git a/gcc/testsuite/gcc.c-torture/execute/20090623-1.c b/gcc/testsuite/gcc.c-torture/execute/20090623-1.c
new file mode 100644 (file)
index 0000000..09a5672
--- /dev/null
@@ -0,0 +1,18 @@
+int * __restrict__ x;
+
+int foo (int y)
+{
+  *x = y;
+  return *x;
+}
+
+extern void abort (void);
+
+int main()
+{
+  int i = 0;
+  x = &i;
+  if (foo(1) != 1)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-13.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-13.c
new file mode 100644 (file)
index 0000000..9841569
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-loop-distribution -fdump-tree-ldist-details" } */
+
+float * __restrict__ x;
+float * __restrict__ y;
+
+float foo (int n)
+{
+  int i;
+  float tmp = 0.0;
+  for (i = 0; i < n; ++i)
+    {
+      x[i] = 0.0;
+      tmp += y[i];
+    }
+  return tmp;
+}
+
+/* We should apply loop distribution.  */
+
+/* { dg-final { scan-tree-dump "Loop 1 distributed: split to 2 loops" "ldist" } } */
+/* { dg-final { cleanup-tree-dump "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-14.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-14.c
new file mode 100644 (file)
index 0000000..700599f
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-strict-aliasing -ftree-loop-distribution -fdump-tree-ldist-details" } */
+
+struct desc {
+  int i;
+  void * __restrict__ data;
+  int j;
+} a, b;
+
+float foo (int n)
+{
+  int i;
+  float * __restrict__ x, * __restrict__ y, tmp = 0.0;
+  x = (float * __restrict__)a.data;
+  y = (float * __restrict__)b.data;
+  for (i = 0; i < n; ++i)
+    {
+      x[i] = 0.0;
+      tmp += y[i];
+    }
+  return tmp;
+}
+
+/* We should apply loop distribution.  */
+
+/* { dg-final { scan-tree-dump "Loop 1 distributed: split to 2 loops" "ldist" } } */
+/* { dg-final { cleanup-tree-dump "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/restrict-1.c b/gcc/testsuite/gcc.dg/tree-ssa/restrict-1.c
new file mode 100644 (file)
index 0000000..08fc10f
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do link } */
+/* { dg-options "-O -fno-strict-aliasing -fdump-tree-optimized" } */
+
+extern void link_error (void);
+
+void bar0 (int * __restrict__ arr1, int * __restrict__ arr2)
+{
+  arr1[0] = 1;
+  arr2[0] = 1;
+  if (arr1[0] != 1)
+    link_error ();
+}
+
+int main()
+{
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "link_error" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/restrict-2.c b/gcc/testsuite/gcc.dg/tree-ssa/restrict-2.c
new file mode 100644 (file)
index 0000000..b76ad98
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fno-strict-aliasing -fdump-tree-lim-details" } */
+
+void foo (float * __restrict__ a, float * __restrict__ b, int n, int j)
+{
+  int i;
+  for(i = 0; i < n; ++i)
+    a[i] = (b[j+50] + b[j-50]) * 0.5f;
+}
+
+/* We should move the RHS of the store out of the loop.  */
+
+/* { dg-final { scan-tree-dump-times "Moving statement" 11 "lim" } } */
+/* { dg-final { cleanup-tree-dump "lim" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/restrict-3.c b/gcc/testsuite/gcc.dg/tree-ssa/restrict-3.c
new file mode 100644 (file)
index 0000000..08faafa
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fno-strict-aliasing -fdump-tree-lim-details" } */
+
+void f(int * __restrict__ r,
+       int a[__restrict__ 16][16],
+       int b[__restrict__ 16][16],
+       int i, int j)
+{
+  int x;
+  *r = 0;
+  for (x = 1; x < 16; ++x)
+    *r = *r + a[i][x] * b[x][j];
+}
+
+/* We should apply store motion to the store to *r.  */
+
+/* { dg-final { scan-tree-dump "Executing store motion of \\\*r" "lim" } } */
+/* { dg-final { cleanup-tree-dump "lim" } } */
index 1473367..e8bca84 100644 (file)
@@ -273,6 +273,13 @@ ptr_derefs_may_alias_p (tree ptr1, tree ptr2)
   if (!pi1 || !pi2)
     return true;
 
+  /* If both pointers are restrict-qualified try to disambiguate
+     with restrict information.  */
+  if (TYPE_RESTRICT (TREE_TYPE (ptr1))
+      && TYPE_RESTRICT (TREE_TYPE (ptr2))
+      && !pt_solutions_same_restrict_base (&pi1->pt, &pi2->pt))
+    return false;
+
   /* ???  This does not use TBAA to prune decls from the intersection
      that not both pointers may access.  */
   return pt_solutions_intersect (&pi1->pt, &pi2->pt);
index 9115e61..b071e4b 100644 (file)
@@ -49,6 +49,9 @@ struct GTY(()) pt_solution
   /* Nonzero if the pt_vars bitmap includes a global variable.  */
   unsigned int vars_contains_global : 1;
 
+  /* Nonzero if the pt_vars bitmap includes a restrict tag variable.  */
+  unsigned int vars_contains_restrict : 1;
+
   /* Set of variables that this pointer may point to.  */
   bitmap vars;
 };
@@ -115,6 +118,8 @@ extern void delete_alias_heapvars (void);
 extern bool pt_solution_includes_global (struct pt_solution *);
 extern bool pt_solution_includes (struct pt_solution *, const_tree);
 extern bool pt_solutions_intersect (struct pt_solution *, struct pt_solution *);
+extern bool pt_solutions_same_restrict_base (struct pt_solution *,
+                                            struct pt_solution *);
 extern void pt_solution_reset (struct pt_solution *);
 extern void dump_pta_stats (FILE *);
 
index b175391..ad5482a 100644 (file)
@@ -211,20 +211,23 @@ struct variable_info
 
   /* True if this is a variable created by the constraint analysis, such as
      heap variables and constraints we had to break up.  */
-  unsigned int is_artificial_var:1;
+  unsigned int is_artificial_var : 1;
 
   /* True if this is a special variable whose solution set should not be
      changed.  */
-  unsigned int is_special_var:1;
+  unsigned int is_special_var : 1;
 
   /* True for variables whose size is not known or variable.  */
-  unsigned int is_unknown_size_var:1;
+  unsigned int is_unknown_size_var : 1;
 
   /* True for (sub-)fields that represent a whole variable.  */
   unsigned int is_full_var : 1;
 
   /* True if this is a heap variable.  */
-  unsigned int is_heap_var:1;
+  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;
@@ -339,7 +342,7 @@ new_var_info (tree t, const char *name)
   ret->is_special_var = false;
   ret->is_unknown_size_var = false;
   ret->may_have_pointers = true;
-  ret->is_global_var = true;
+  ret->is_global_var = (t == NULL_TREE);
   if (t && DECL_P (t))
     ret->is_global_var = is_global_var (t);
   ret->solution = BITMAP_ALLOC (&pta_obstack);
@@ -3312,6 +3315,40 @@ make_constraint_to (unsigned id, tree op)
   VEC_free (ce_s, heap, rhsc);
 }
 
+/* Create a constraint ID = &FROM.  */
+
+static void
+make_constraint_from (varinfo_t vi, int from)
+{
+  struct constraint_expr lhs, rhs;
+
+  lhs.var = vi->id;
+  lhs.offset = 0;
+  lhs.type = SCALAR;
+
+  rhs.var = from;
+  rhs.offset = 0;
+  rhs.type = ADDRESSOF;
+  process_constraint (new_constraint (lhs, rhs));
+}
+
+/* Create a constraint ID = FROM.  */
+
+static void
+make_copy_constraint (varinfo_t vi, int from)
+{
+  struct constraint_expr lhs, rhs;
+
+  lhs.var = vi->id;
+  lhs.offset = 0;
+  lhs.type = SCALAR;
+
+  rhs.var = from;
+  rhs.offset = 0;
+  rhs.type = SCALAR;
+  process_constraint (new_constraint (lhs, rhs));
+}
+
 /* Make constraints necessary to make OP escape.  */
 
 static void
@@ -3320,6 +3357,61 @@ make_escape_constraint (tree op)
   make_constraint_to (escaped_id, op);
 }
 
+/* Create a new artificial heap variable with NAME and make a
+   constraint from it to LHS.  Return the created variable.  */
+
+static varinfo_t
+make_constraint_from_heapvar (varinfo_t lhs, const char *name)
+{
+  varinfo_t vi;
+  tree heapvar = heapvar_lookup (lhs->decl);
+
+  if (heapvar == NULL_TREE)
+    {
+      var_ann_t ann;
+      heapvar = create_tmp_var_raw (ptr_type_node, name);
+      DECL_EXTERNAL (heapvar) = 1;
+
+      heapvar_insert (lhs->decl, heapvar);
+
+      ann = get_var_ann (heapvar);
+      ann->is_heapvar = 1;
+    }
+
+  /* For global vars we need to add a heapvar to the list of referenced
+     vars of a different function than it was created for originally.  */
+  if (gimple_referenced_vars (cfun))
+    add_referenced_var (heapvar);
+
+  vi = new_var_info (heapvar, name);
+  vi->is_artificial_var = true;
+  vi->is_heap_var = true;
+  vi->is_unknown_size_var = true;
+  vi->fullsize = ~0;
+  vi->size = ~0;
+  vi->is_full_var = true;
+  insert_vi_for_tree (heapvar, vi);
+
+  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.  */
+
+static void
+make_constraint_from_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;
+}
+
 /* For non-IPA mode, generate constraints necessary for a call on the
    RHS.  */
 
@@ -3374,39 +3466,14 @@ static void
 handle_lhs_call (tree lhs, int flags, VEC(ce_s, heap) *rhsc)
 {
   VEC(ce_s, heap) *lhsc = NULL;
-  unsigned int j;
-  struct constraint_expr *lhsp;
 
   get_constraint_for (lhs, &lhsc);
 
   if (flags & ECF_MALLOC)
     {
-      struct constraint_expr rhsc;
-      tree heapvar = heapvar_lookup (lhs);
       varinfo_t vi;
-
-      if (heapvar == NULL)
-       {
-         heapvar = create_tmp_var_raw (ptr_type_node, "HEAP");
-         DECL_EXTERNAL (heapvar) = 1;
-         get_var_ann (heapvar)->is_heapvar = 1;
-         if (gimple_referenced_vars (cfun))
-           add_referenced_var (heapvar);
-         heapvar_insert (lhs, heapvar);
-       }
-
-      rhsc.var = create_variable_info_for (heapvar,
-                                          alias_get_name (heapvar));
-      vi = get_varinfo (rhsc.var);
-      vi->is_artificial_var = 1;
-      vi->is_heap_var = 1;
-      vi->is_unknown_size_var = true;
-      vi->fullsize = ~0;
-      vi->size = ~0;
-      rhsc.type = ADDRESSOF;
-      rhsc.offset = 0;
-      for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
-       process_constraint (new_constraint (*lhsp, rhsc));
+      vi = make_constraint_from_heapvar (get_vi_for_tree (lhs), "HEAP");
+      make_copy_constraint (vi, nonlocal_id);
     }
   else if (VEC_length (ce_s, rhsc) > 0)
     {
@@ -3826,6 +3893,15 @@ find_func_aliases (gimple origt)
          && DECL_P (lhsop)
          && is_global_var (lhsop))
        make_escape_constraint (rhsop);
+      /* If this is a conversion of a non-restrict pointer to a
+        restrict pointer track it with a new heapvar.  */
+      else if (gimple_assign_cast_p (t)
+              && POINTER_TYPE_P (TREE_TYPE (rhsop))
+              && POINTER_TYPE_P (TREE_TYPE (lhsop))
+              && !TYPE_RESTRICT (TREE_TYPE (rhsop))
+              && TYPE_RESTRICT (TREE_TYPE (lhsop)))
+       make_constraint_from_restrict (get_vi_for_tree (lhsop),
+                                      "CAST_RESTRICT");
     }
   /* For conversions of pointers to non-pointers the pointer escapes.  */
   else if (gimple_assign_cast_p (t)
@@ -4017,6 +4093,8 @@ struct fieldoff
   unsigned has_unknown_size : 1;
 
   unsigned may_have_pointers : 1;
+
+  unsigned only_restrict_pointers : 1;
 };
 typedef struct fieldoff fieldoff_s;
 
@@ -4155,6 +4233,10 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
                else
                  pair->size = -1;
                pair->may_have_pointers = could_have_pointers (field);
+               pair->only_restrict_pointers
+                 = (!has_unknown_size
+                    && POINTER_TYPE_P (TREE_TYPE (field))
+                    && TYPE_RESTRICT (TREE_TYPE (field)));
                count++;
              }
          }
@@ -4165,40 +4247,6 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
   return count;
 }
 
-/* Create a constraint ID = &FROM.  */
-
-static void
-make_constraint_from (varinfo_t vi, int from)
-{
-  struct constraint_expr lhs, rhs;
-
-  lhs.var = vi->id;
-  lhs.offset = 0;
-  lhs.type = SCALAR;
-
-  rhs.var = from;
-  rhs.offset = 0;
-  rhs.type = ADDRESSOF;
-  process_constraint (new_constraint (lhs, rhs));
-}
-
-/* Create a constraint ID = FROM.  */
-
-static void
-make_copy_constraint (varinfo_t vi, int from)
-{
-  struct constraint_expr lhs, rhs;
-
-  lhs.var = vi->id;
-  lhs.offset = 0;
-  lhs.type = SCALAR;
-
-  rhs.var = from;
-  rhs.offset = 0;
-  rhs.type = SCALAR;
-  process_constraint (new_constraint (lhs, rhs));
-}
-
 /* Count the number of arguments DECL has, and set IS_VARARGS to true
    if it is a varargs function.  */
 
@@ -4346,17 +4394,12 @@ create_variable_info_for (tree decl, const char *name)
   varinfo_t vi;
   tree decl_type = TREE_TYPE (decl);
   tree declsize = DECL_P (decl) ? DECL_SIZE (decl) : TYPE_SIZE (decl_type);
-  bool is_global = DECL_P (decl) ? is_global_var (decl) : false;
   VEC (fieldoff_s,heap) *fieldstack = NULL;
 
   if (TREE_CODE (decl) == FUNCTION_DECL && in_ipa_mode)
     return create_function_info_for (decl, name);
 
-  if (var_can_have_subvars (decl) && use_field_sensitive
-      && (!var_ann (decl)
-         || var_ann (decl)->noalias_state == 0)
-      && (!var_ann (decl)
-         || !var_ann (decl)->is_heapvar))
+  if (var_can_have_subvars (decl) && use_field_sensitive)
     push_fields_onto_fieldstack (decl_type, &fieldstack, 0);
 
   /* If the variable doesn't have subvars, we may end up needing to
@@ -4379,14 +4422,14 @@ create_variable_info_for (tree decl, const char *name)
     }
 
   insert_vi_for_tree (vi->decl, vi);
-  if (is_global && (!flag_whole_program || !in_ipa_mode)
+  if (vi->is_global_var
+      && (!flag_whole_program || !in_ipa_mode)
       && vi->may_have_pointers)
     {
-      if (var_ann (decl)
-         && var_ann (decl)->noalias_state == NO_ALIAS_ANYTHING)
-       make_constraint_from (vi, vi->id);
-      else
-       make_copy_constraint (vi, nonlocal_id);
+      if (POINTER_TYPE_P (TREE_TYPE (decl))
+         && TYPE_RESTRICT (TREE_TYPE (decl)))
+       make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
+      make_copy_constraint (vi, nonlocal_id);
     }
 
   stats.total_vars++;
@@ -4463,9 +4506,14 @@ create_variable_info_for (tree decl, const char *name)
          newvi->fullsize = vi->fullsize;
          newvi->may_have_pointers = fo->may_have_pointers;
          insert_into_field_list (vi, newvi);
-         if (is_global && (!flag_whole_program || !in_ipa_mode)
+         if (newvi->is_global_var
+             && (!flag_whole_program || !in_ipa_mode)
              && newvi->may_have_pointers)
-           make_copy_constraint (newvi, nonlocal_id);
+           {
+              if (fo->only_restrict_pointers)
+                make_constraint_from_restrict (newvi, "GLOBAL_RESTRICT");
+              make_copy_constraint (newvi, nonlocal_id);
+           }
 
          stats.total_vars++;
        }
@@ -4518,7 +4566,6 @@ static void
 intra_create_variable_infos (void)
 {
   tree t;
-  struct constraint_expr lhs, rhs;
 
   /* For each incoming pointer argument arg, create the constraint ARG
      = NONLOCAL or a dummy variable if flag_argument_noalias is set.  */
@@ -4536,50 +4583,28 @@ intra_create_variable_infos (void)
       if (POINTER_TYPE_P (TREE_TYPE (t)) && flag_argument_noalias > 0)
        {
          varinfo_t vi;
-         tree heapvar = heapvar_lookup (t);
-
-         lhs.offset = 0;
-         lhs.type = SCALAR;
-         lhs.var  = get_vi_for_tree (t)->id;
+         var_ann_t ann;
 
-         if (heapvar == NULL_TREE)
+         vi = make_constraint_from_heapvar (get_vi_for_tree (t),
+                                            "PARM_NOALIAS");
+         ann = get_var_ann (vi->decl);
+         if (flag_argument_noalias == 1)
            {
-             var_ann_t ann;
-             heapvar = create_tmp_var_raw (ptr_type_node,
-                                           "PARM_NOALIAS");
-             DECL_EXTERNAL (heapvar) = 1;
-             if (gimple_referenced_vars (cfun))
-               add_referenced_var (heapvar);
-
-             heapvar_insert (t, heapvar);
-
-             ann = get_var_ann (heapvar);
-             ann->is_heapvar = 1;
-             if (flag_argument_noalias == 1)
-               ann->noalias_state = NO_ALIAS;
-             else if (flag_argument_noalias == 2)
-               ann->noalias_state = NO_ALIAS_GLOBAL;
-             else if (flag_argument_noalias == 3)
-               ann->noalias_state = NO_ALIAS_ANYTHING;
-             else
-               gcc_unreachable ();
+             ann->noalias_state = NO_ALIAS;
+             make_copy_constraint (vi, nonlocal_id);
            }
-
-         vi = get_vi_for_tree (heapvar);
-         vi->is_artificial_var = 1;
-         vi->is_heap_var = 1;
-         vi->is_unknown_size_var = true;
-         vi->fullsize = ~0;
-         vi->size = ~0;
-         rhs.var = vi->id;
-         rhs.type = ADDRESSOF;
-         rhs.offset = 0;
-         for (p = get_varinfo (lhs.var); p; p = p->next)
+         else if (flag_argument_noalias == 2)
+           {
+             ann->noalias_state = NO_ALIAS_GLOBAL;
+             make_constraint_from (vi, vi->id);
+           }
+         else if (flag_argument_noalias == 3)
            {
-             struct constraint_expr temp = lhs;
-             temp.var = p->id;
-             process_constraint (new_constraint (temp, rhs));
+             ann->noalias_state = NO_ALIAS_ANYTHING;
+             make_constraint_from (vi, vi->id);
            }
+         else
+           gcc_unreachable ();
        }
       else
        {
@@ -4588,6 +4613,9 @@ intra_create_variable_infos (void)
          for (p = arg_vi; p; p = p->next)
            make_constraint_from (p, nonlocal_id);
        }
+      if (POINTER_TYPE_P (TREE_TYPE (t))
+         && TYPE_RESTRICT (TREE_TYPE (t)))
+       make_constraint_from_restrict (get_vi_for_tree (t), "PARM_RESTRICT");
     }
 
   /* Add a constraint for a result decl that is passed by reference.  */
@@ -4704,7 +4732,7 @@ set_uids_in_ptset (bitmap into, bitmap from, struct pt_solution *pt)
          /* Add the decl to the points-to set.  Note that the points-to
             set contains global variables.  */
          bitmap_set_bit (into, DECL_UID (vi->decl));
-         if (is_global_var (vi->decl))
+         if (vi->is_global_var)
            pt->vars_contains_global = true;
        }
     }
@@ -4753,11 +4781,15 @@ find_what_var_points_to (varinfo_t 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)
+  if (pt->anything
+      && (vi->is_artificial_var
+         || !pt->vars_contains_restrict))
     return;
 
   /* Share the final set of variables when possible.  */
@@ -4967,6 +4999,27 @@ 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.  */