[PATCH][RFC] Define and use middle-end semantics of DECL_BY_REFERENCE

Richard Guenther rguenther@suse.de
Mon Jul 27 16:04:00 GMT 2009


This lays out semantics for DECL_BY_REFERENCE passed parameters and uses
it from alias-analysis.  The ultimate goal is to use this mechanism to
properly implement aliasing constraints from Fortran for array descriptor
parameters.

The middle-end with this patch assumes that all PARM_DECLs that have
DECL_BY_REFERENCE set point to an object of the pointed-to type
(not some other type and not some larger or smaller object).

This allows us to track fields of the pointed-to memory for pointer
analysis.  In particular we can honor restrict qualification of
pointer members of structures (which we'll change the Fortran frontend
to provide for the data member of the array descriptor).

The patch extents points-to analysis to track (for now only for) 
restrict qualified decl-by-reference pointers as pointing to
separate objects.  They are still considered global memory, thus
stores to them are not dead after returning from the function
(in C++ those at least might escape to the destructor of the object
if the type is TREE_ADDRESSABLE).

The cp/typeck.c piece is to give the patch some more coverage, it's a
hack that will not be part of a final commit.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

Any comments?  Anybody thinks that the requirements for DECL_BY_REFERENCE
are not sound?

Thanks,
Richard.

2009-07-27  Richard Guenther  <rguenther@suse.de>

	* tree-ssa-structalias.c (create_variable_info_for): Remove
	strange whole-program condition, prepare to be called for non-globals.
	(intra_create_variable_infos): For restrict qualified DECL_BY_REFERENCE
	params build a representative with known type and track its fields.

	cp/
	* typeck.c (decay_conversion): Avoid decaying away restrict
	qualifiers on pointers.

	* g++.dg/tree-ssa/restrict-1.C: New testcase.
	* gcc.dg/tree-ssa/restrict-4.c: Likewise.

Index: trunk/gcc/tree-ssa-structalias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-structalias.c	2009-07-16 12:09:43.000000000 +0200
--- trunk/gcc/tree-ssa-structalias.c	2009-07-16 12:40:35.000000000 +0200
*************** create_variable_info_for (tree decl, con
*** 4518,4530 ****
  	  newvi->fullsize = vi->fullsize;
  	  newvi->may_have_pointers = fo->may_have_pointers;
  	  insert_into_field_list (vi, newvi);
! 	  if (newvi->is_global_var
! 	      && (!flag_whole_program || !in_ipa_mode)
  	      && newvi->may_have_pointers)
  	    {
  	       if (fo->only_restrict_pointers)
  		 make_constraint_from_restrict (newvi, "GLOBAL_RESTRICT");
! 	       make_copy_constraint (newvi, nonlocal_id);
  	    }
  
  	  stats.total_vars++;
--- 4518,4530 ----
  	  newvi->fullsize = vi->fullsize;
  	  newvi->may_have_pointers = fo->may_have_pointers;
  	  insert_into_field_list (vi, newvi);
! 	  if ((newvi->is_global_var || TREE_CODE (decl) == PARM_DECL)
  	      && newvi->may_have_pointers)
  	    {
  	       if (fo->only_restrict_pointers)
  		 make_constraint_from_restrict (newvi, "GLOBAL_RESTRICT");
! 	       if (newvi->is_global_var && !in_ipa_mode)
! 		 make_copy_constraint (newvi, nonlocal_id);
  	    }
  
  	  stats.total_vars++;
*************** intra_create_variable_infos (void)
*** 4588,4598 ****
        if (!could_have_pointers (t))
  	continue;
  
        /* If flag_argument_noalias is set, then function pointer
  	 arguments are guaranteed not to point to each other.  In that
  	 case, create an artificial variable PARM_NOALIAS and the
  	 constraint ARG = &PARM_NOALIAS.  */
!       if (POINTER_TYPE_P (TREE_TYPE (t)) && flag_argument_noalias > 0)
  	{
  	  varinfo_t vi;
  	  var_ann_t ann;
--- 4588,4626 ----
        if (!could_have_pointers (t))
  	continue;
  
+       if (DECL_BY_REFERENCE (t)
+ 	  && POINTER_TYPE_P (TREE_TYPE (t))
+ 	  && TYPE_RESTRICT (TREE_TYPE (t)))
+ 	{
+ 	  struct constraint_expr lhsc, rhsc;
+ 	  varinfo_t vi;
+ 	  tree heapvar = heapvar_lookup (t);
+ 	  if (heapvar == NULL_TREE)
+ 	    {
+ 	      var_ann_t ann;
+ 	      heapvar = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (t)),
+ 					    "PARM_NOALIAS");
+ 	      DECL_EXTERNAL (heapvar) = 1;
+ 	      heapvar_insert (t, heapvar);
+ 	      ann = get_var_ann (heapvar);
+ 	      ann->is_heapvar = 1;
+ 	    }
+ 	  if (gimple_referenced_vars (cfun))
+ 	    add_referenced_var (heapvar);
+ 	  lhsc.var = get_vi_for_tree (t)->id;
+ 	  lhsc.type = SCALAR;
+ 	  lhsc.offset = 0;
+ 	  rhsc.var = (vi = get_vi_for_tree (heapvar))->id;
+ 	  rhsc.type = ADDRESSOF;
+ 	  rhsc.offset = 0;
+ 	  process_constraint (new_constraint (lhsc, rhsc));
+ 	  vi->is_restrict_var = 1;
+ 	}
        /* If flag_argument_noalias is set, then function pointer
  	 arguments are guaranteed not to point to each other.  In that
  	 case, create an artificial variable PARM_NOALIAS and the
  	 constraint ARG = &PARM_NOALIAS.  */
!       else if (POINTER_TYPE_P (TREE_TYPE (t)) && flag_argument_noalias > 0)
  	{
  	  varinfo_t vi;
  	  var_ann_t ann;
*************** intra_create_variable_infos (void)
*** 4623,4631 ****
  	  varinfo_t arg_vi = get_vi_for_tree (t);
  
  	  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");
      }
--- 4651,4661 ----
  	  varinfo_t arg_vi = get_vi_for_tree (t);
  
  	  for (p = arg_vi; p; p = p->next)
! 	    if (p->may_have_pointers)
! 	      make_constraint_from (p, nonlocal_id);
  	}
!       if (!DECL_BY_REFERENCE (t)
! 	  && POINTER_TYPE_P (TREE_TYPE (t))
  	  && TYPE_RESTRICT (TREE_TYPE (t)))
  	make_constraint_from_restrict (get_vi_for_tree (t), "PARM_RESTRICT");
      }
Index: trunk/gcc/cp/typeck.c
===================================================================
*** trunk.orig/gcc/cp/typeck.c	2009-07-14 15:53:31.000000000 +0200
--- trunk/gcc/cp/typeck.c	2009-07-16 12:21:20.000000000 +0200
*************** decay_conversion (tree exp)
*** 1686,1692 ****
       Non-class rvalues always have cv-unqualified types.  */
    type = TREE_TYPE (exp);
    if (!CLASS_TYPE_P (type) && cp_type_quals (type))
!     exp = build_nop (TYPE_MAIN_VARIANT (type), exp);
  
    return exp;
  }
--- 1686,1705 ----
       Non-class rvalues always have cv-unqualified types.  */
    type = TREE_TYPE (exp);
    if (!CLASS_TYPE_P (type) && cp_type_quals (type))
!     {
!       if (!POINTER_TYPE_P (type)
! 	  || !CP_TYPE_RESTRICT_P (type))
! 	exp = build_nop (TYPE_MAIN_VARIANT (type), exp);
!       else if (POINTER_TYPE_P (type))
! 	{
! 	  if (!CP_TYPE_CONST_P (type)
! 	      && !CP_TYPE_VOLATILE_P (type))
! 	    ;
! 	  else
! 	    exp = build_nop (build_qualified_type (TYPE_MAIN_VARIANT (type),
! 						   TYPE_QUAL_RESTRICT), exp);
! 	}
!     }
  
    return exp;
  }
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/restrict-1.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/g++.dg/tree-ssa/restrict-1.C	2009-07-16 12:26:59.000000000 +0200
***************
*** 0 ****
--- 1,20 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2 -fdump-tree-lim-details" } */
+ 
+ struct Foo
+ {
+   Foo();
+   Foo(const Foo&);
+   int n;
+   int * __restrict__ p;
+ };
+ void bar(Foo f, int * __restrict__ q)
+ {
+   for (int i = 0; i < f.n; ++i)
+     {
+       *q += f.p[i];
+     }
+ }
+ 
+ /* { dg-final { scan-tree-dump "Executing store motion" "lim" } } */
+ /* { dg-final { cleanup-tree-dump "lim" } } */
Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/restrict-4.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/tree-ssa/restrict-4.c	2009-07-16 12:43:27.000000000 +0200
***************
*** 0 ****
--- 1,19 ----
+ /* { dg-do compile }  */
+ /* { dg-options "-O2 -fdump-tree-lim-details" } */
+ 
+ struct Foo
+ {
+   int n;
+   int * __restrict__ p;
+ };
+ void bar(struct Foo f, int * __restrict__ q)
+ {
+   int i;
+   for (i = 0; i < f.n; ++i)
+     {
+       *q += f.p[i];
+     }
+ }
+ 
+ /* { dg-final { scan-tree-dump "Executing store motion" "lim" } } */
+ /* { dg-final { cleanup-tree-dump "lim" } } */



More information about the Gcc-patches mailing list