[PATCH][RFC] Simple IPA mod-ref analysis

Richard Guenther rguenther@suse.de
Mon Oct 24 14:10:00 GMT 2011


This sketches a simple local mod-ref analysis, piggy-backed ontop
of the local IPA pure-const machinery (well, just sharing its
pass really).  I am not yet sure how or if it will be possible
to IPA propagate this (other than handling already processed
bodies during local discovery) - we would need to know whether
parameters may reach calls, and in which position - something
that looks more close to IPA CP than IPA pure-const.

Not yet bootstrapped or tested other than on the simple testcase.

Any comments?

Thanks,
Richard.

2011-10-24  Richard Guenther  <rguenther@suse.de>

	* gimple.c (gimple_call_fnspec): Also look in DECL_ATTRIBUTES.
	* ipa-pure-const.c (struct funct_state_d): Add fnspec member.
	(varying_state): Adjust.
	(analyze_function): Populate fnspec.
	(local_pure_const): Set the fnspec attribute.

Index: gcc/gimple.c
===================================================================
*** gcc/gimple.c.orig	2011-10-24 15:14:30.000000000 +0200
--- gcc/gimple.c	2011-10-24 15:14:33.000000000 +0200
*************** gimple_call_flags (const_gimple stmt)
*** 1915,1931 ****
  static tree
  gimple_call_fnspec (const_gimple stmt)
  {
!   tree type, attr;
  
    type = gimple_call_fntype (stmt);
!   if (!type)
!     return NULL_TREE;
  
!   attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type));
!   if (!attr)
!     return NULL_TREE;
  
!   return TREE_VALUE (TREE_VALUE (attr));
  }
  
  /* Detects argument flags for argument number ARG on call STMT.  */
--- 1915,1939 ----
  static tree
  gimple_call_fnspec (const_gimple stmt)
  {
!   tree type, decl, attr;
  
    type = gimple_call_fntype (stmt);
!   if (type)
!     {
!       attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type));
!       if (attr)
! 	return TREE_VALUE (TREE_VALUE (attr));
!     }
  
!   decl = gimple_call_fndecl (stmt);
!   if (decl)
!     {
!       attr = lookup_attribute ("fn spec", DECL_ATTRIBUTES (decl));
!       if (attr)
! 	return TREE_VALUE (TREE_VALUE (attr));
!     }
  
!   return NULL_TREE;
  }
  
  /* Detects argument flags for argument number ARG on call STMT.  */
*************** is_gimple_constant (const_tree t)
*** 2731,2743 ****
      case VECTOR_CST:
        return true;
  
-     /* Vector constant constructors are gimple invariant.  */
-     case CONSTRUCTOR:
-       if (TREE_TYPE (t) && TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
- 	return TREE_CONSTANT (t);
-       else
- 	return false;
- 
      default:
        return false;
      }
--- 2739,2744 ----
Index: gcc/ipa-pure-const.c
===================================================================
*** gcc/ipa-pure-const.c.orig	2011-10-24 15:14:30.000000000 +0200
--- gcc/ipa-pure-const.c	2011-10-24 15:47:34.000000000 +0200
*************** struct funct_state_d
*** 94,104 ****
    bool looping;
  
    bool can_throw;
  };
  
  /* State used when we know nothing about function.  */
  static struct funct_state_d varying_state
!    = { IPA_NEITHER, IPA_NEITHER, true, true, true };
  
  
  typedef struct funct_state_d * funct_state;
--- 94,106 ----
    bool looping;
  
    bool can_throw;
+ 
+   char fnspec[1 + 4 + 1];
  };
  
  /* State used when we know nothing about function.  */
  static struct funct_state_d varying_state
!    = { IPA_NEITHER, IPA_NEITHER, true, true, true, "....." };
  
  
  typedef struct funct_state_d * funct_state;
*************** end:
*** 819,824 ****
--- 821,941 ----
    if (TREE_NOTHROW (decl))
      l->can_throw = false;
  
+   memset (l->fnspec, '.', sizeof (l->fnspec));
+   l->fnspec[5] = '\0';
+ 
+   /* Check properties of the return value.
+      ???  Ignore EH edges.  */
+   if (single_pred_p (EXIT_BLOCK_PTR)
+       && !gsi_end_p (gsi_last_bb (single_pred (EXIT_BLOCK_PTR))))
+     {
+       gimple ret = gsi_stmt (gsi_last_bb (single_pred (EXIT_BLOCK_PTR)));
+       if (gimple_code (ret) == GIMPLE_RETURN)
+ 	{
+ 	  tree retval = gimple_return_retval (ret);
+ 	  if (retval
+ 	      && TREE_CODE (retval) == SSA_NAME
+ 	      && SSA_NAME_IS_DEFAULT_DEF (retval)
+ 	      && TREE_CODE (SSA_NAME_VAR (retval)) == PARM_DECL)
+ 	    {
+ 	      tree arg;
+ 	      unsigned n;
+ 	      for (arg = DECL_ARGUMENTS (decl), n = 1;
+ 		   arg && n <= 4 && arg != SSA_NAME_VAR (retval);
+ 		   arg = DECL_CHAIN (arg))
+ 		++n;
+ 	      /* Returns a parameter.  */
+ 	      if (arg == SSA_NAME_VAR (retval) && n <= 4)
+ 		l->fnspec[0] = '0' + n;
+ 	    }
+ 	  else if (retval
+ 		   && TREE_CODE (retval) == SSA_NAME)
+ 	    {
+ 	      gimple def_stmt = SSA_NAME_DEF_STMT (retval);
+ 	      if (is_gimple_call (def_stmt)
+ 		  && (gimple_call_return_flags (def_stmt) & ERF_NOALIAS))
+ 		l->fnspec[0] = 'm';
+ 	      /* ???  Support ret = PHI <0, malloc ()>, thus returning zero.  */
+ 	    }
+ 	}
+     }
+ 
+   /* Check properties of arguments.  */
+     {
+       tree arg;
+       unsigned n;
+       for (arg = DECL_ARGUMENTS (decl), n = 1; arg && n <= 4;
+ 	   arg = DECL_CHAIN (arg))
+ 	{
+ 	  tree name = gimple_default_def (cfun, arg);
+ 	  if (!name)
+ 	    ;
+ 	  else if (has_zero_uses (name))
+ 	    l->fnspec[n] = 'x';
+ 	  else if (POINTER_TYPE_P (TREE_TYPE (name)))
+ 	    {
+ 	      gimple use_stmt;
+ 	      imm_use_iterator iter;
+ 	      bool escapes = false;
+ 	      bool seen_store = false;
+ 
+ 	      FOR_EACH_IMM_USE_STMT (use_stmt, iter, name)
+ 		{
+ 		  if (gimple_code (use_stmt) == GIMPLE_RETURN)
+ 		    continue;
+ 		  else if (gimple_assign_single_p (use_stmt))
+ 		    {
+ 		      /* Store.  */
+ 		      if (TREE_CODE (gimple_assign_lhs (use_stmt)) != SSA_NAME)
+ 			seen_store = true;
+ 		      /* Not name or an ADDR_EXPR involving name
+ 			 is transfered to the lhs.  */
+ 		      if ((TREE_CODE (gimple_assign_rhs1 (use_stmt))
+ 			   != ADDR_EXPR)
+ 			  && gimple_assign_rhs1 (use_stmt) != name)
+ 			continue;
+ 		      /* Everything else makes name escape.  */
+ 		    }
+ 		  else if (is_gimple_call (use_stmt))
+ 		    {
+ 		      tree lhs = gimple_call_lhs (use_stmt);
+ 		      unsigned m;
+ 		      for (m = 0; m < gimple_call_num_args (use_stmt); ++m)
+ 			{
+ 			  tree carg = gimple_call_arg (use_stmt, m);
+ 			  if (TREE_CODE (carg) == SSA_NAME)
+ 			    {
+ 			      if (gimple_call_arg (use_stmt, m) == name)
+ 				{
+ 				  if (!(gimple_call_arg_flags (use_stmt, m)
+ 					& EAF_NOCLOBBER))
+ 				    seen_store = true;
+ 				  if ((gimple_call_arg_flags (use_stmt, m)
+ 				       & EAF_NOESCAPE))
+ 				    continue;
+ 				  goto escape;
+ 				}
+ 			    }
+ 			  else
+ 			    goto escape;
+ 			}
+ 		      if (TREE_CODE (lhs) != SSA_NAME)
+ 			seen_store = true;
+ 		      continue;
+ 		    }
+ 		  /* Everything else makes name escape.  */
+ 
+ escape:
+ 		  escapes = true;
+ 		  BREAK_FROM_IMM_USE_STMT (iter);
+ 		}
+ 	      if (!escapes)
+ 		l->fnspec[n] = seen_store ? 'w' : 'r';
+ 	    }
+ 	  ++n;
+ 	}
+     }
+ 
    pop_cfun ();
    current_function_decl = old_decl;
    if (dump_file)
*************** end:
*** 831,836 ****
--- 948,954 ----
          fprintf (dump_file, "Function is locally const.\n");
        if (l->pure_const_state == IPA_PURE)
          fprintf (dump_file, "Function is locally pure.\n");
+       fprintf (dump_file, "Function spec is \"%s\".\n", l->fnspec);
      }
    return l;
  }
*************** local_pure_const (void)
*** 1653,1658 ****
--- 1771,1797 ----
  		 lang_hooks.decl_printable_name (current_function_decl,
  						 2));
      }
+     {
+       unsigned n;
+       for (n = 0; n < sizeof (l->fnspec) - 1; ++n)
+ 	if (l->fnspec[n] != '.')
+ 	  break;
+       if (n < sizeof (l->fnspec) - 1)
+ 	{
+ 	  DECL_ATTRIBUTES (current_function_decl)
+ 	    = tree_cons (get_identifier ("fn spec"),
+ 			 build_tree_list (NULL_TREE,
+ 					  build_string (1 + 4,
+ 							l->fnspec)),
+ 			 remove_attribute ("fn spec",
+ 					   DECL_ATTRIBUTES
+ 					     (current_function_decl)));
+ 	  if (dump_file)
+ 	    fprintf (dump_file, "Function specification found: %s (%s)\n",
+ 		     lang_hooks.decl_printable_name (current_function_decl, 2),
+ 		     l->fnspec);
+ 	}
+     }
    free (l);
    if (changed)
      return execute_fixup_cfg ();
Index: gcc/testsuite/gcc.dg/tree-ssa/mod-ref-1.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/tree-ssa/mod-ref-1.c	2011-10-24 15:33:25.000000000 +0200
***************
*** 0 ****
--- 1,25 ----
+ /* { dg-do run } */
+ /* { dg-options "-O" } */
+ 
+ extern void abort (void);
+ extern void link_error (void);
+ 
+ char c;
+ char * __attribute__((noinline,noclone))
+ foo(int i, char *p)
+ {
+   c = *p;
+   return p;
+ }
+ 
+ int main ()
+ {
+   char c = 1;
+   char *c2 = foo(0, &c);
+   if (c != 1)
+     link_error ();
+   *c2 = 2;
+   if (c != 2)
+     abort ();
+   return 0;
+ }



More information about the Gcc-patches mailing list