[PATCH] Move profiling to SSA

Richard Guenther rguenther@suse.de
Fri Sep 24 17:34:00 GMT 2010


On Fri, 24 Sep 2010, Jan Hubicka wrote:

> > 
> > This moves profile (and coverage) instrumentation to SSA, removing
> > the need of a separate early inliner and this eventually killing
> > the last non-SSA inlining path (well, not quite yet I guess).
> > 
> > The only issue is non-local gotos which need some new attribute
> > for the profile functions, Honza had some patch for this that needs
> > updating.
> Hi,
> thanks for working on this (it is quite long time on my TODO, but IPA/LTO
> fixes still take apriority)
> 
> this patch adds leaf attribute broken up and updated
> http://gcc.gnu.org/ml/gcc-patches/2010-06/msg01329.html
> 
> It does not modify non-C frontend to handle it nor annotate builtin definitions
> Richard asked me to do incrementally.
> 
> In addition to updating it to current tree, I also added stmt_can_make_abnormal_goto
> code so Richard actually can use it to solve problem with profiling builtins.
> While making new testcase I noticed that ipa-reference also needs updating in
> ipa_reference_get_not_read_global and ipa_reference_get_not_written_global
> 
> I did not updated RTL land to avoid construcion of abnormal goto edges on leaf
> functions.  This is something that can be done incrementally using REG_NOTE
> annotating the call statement.  It is probably not really important however.
> 
> Bootstrapped/regtested x86_64-linux, OK?

Ok.

Thanks!
Richard.

> Honza
> 
> 	* doc/extend.texi: (attribute leaf): Document.
> 	* tree.c (local_define_builtin): Handle ECF_LEAF.
> 	(build_common_builtin_nodes): Set ECF_LEAF where needed.
> 	* tree.h (ECF_LEAF): New.
> 	* ipa-reference.c (propagate_bits): For leaf calls propagate ever overwrittable
> 	and unavailable functions.
> 	(ipa_init): Put all_module_statics into optimization_summary_obstack.
> 	(copy_global_bitmap): Do not copy all_module_statics.
> 	(read_write_all_from_decl): Use cgraph_node argument; handle ECF_LEAF.
> 	(propagate): Handle overwritable and unavailable leaf functions;
> 	initialize global info for overwritable and unavailable leaf functions;
> 	do not free all module statics.
> 	(ipa_reference_get_not_read_global, ipa_reference_get_not_written_global):
> 	leaf calls don't clobber local statics.
> 	* calls.c (flags_from_decl_or_type): Handle leaf.
> 	* tree-cfg.c (stmt_can_make_abnormal_goto): Leaf functions can't do
> 	abnormal gotos.
> 
> 	* c-common.c (handle_leaf_attribute): New function.
> 	(struct attribute_spec c_common_att): Add leaf.
> 
> 	* gcc.dg/tree-ssa/leaf.c: New testcase.
> Index: doc/extend.texi
> ===================================================================
> *** doc/extend.texi	(revision 164477)
> --- doc/extend.texi	(working copy)
> *************** SRAM. The function will be put into a sp
> *** 2671,2676 ****
> --- 2671,2701 ----
>   @code{.l1.text}. With @option{-mfdpic}, callers of such functions will use
>   an inlined PLT.
>   
> + @item leaf
> + @cindex @code{leaf} function attribute
> + Calls to external functions with this attribute must return to the current
> + compilation unit only by return or by exception handling. In particular, leaf
> + functions are not allowed to call callback function passed to it from current
> + compilation unit or directly call functions exported by the unit or longjmp
> + into the unit.  Still leaf function might call functions from other complation
> + units and thus they are not neccesarily leaf in the sense that they contains no
> + function calls at all.
> + 
> + The attribute is intended for library functions to improve dataflow analysis.
> + Compiler takes the hint that any data not escaping current compilation unit can
> + not be used or modified by the leaf function.  For example, function @code{sin}
> + is leaf, function @code{qsort} is not.
> + 
> + Note that the leaf functions might invoke signals and signal handlers might be
> + defined in the current compilation unit and use static variables. Only
> + compliant way to write such a signal handler is to declare such variables
> + @code{volatile}.
> + 
> + The attribute has no effect on functions defined within current compilation
> + unit.  This is to allow easy merging of multiple compilation units into one,
> + for example, by using the link time optimization.  For this reason the
> + attribute is not allowed on types to annotate indirect calls.
> + 
>   @item long_call/short_call
>   @cindex indirect calls on ARM
>   This attribute specifies how a particular function is called on
> Index: c-family/c-common.c
> ===================================================================
> *** c-family/c-common.c	(revision 164477)
> --- c-family/c-common.c	(working copy)
> *************** static tree handle_hot_attribute (tree *
> *** 308,313 ****
> --- 308,314 ----
>   static tree handle_cold_attribute (tree *, tree, tree, int, bool *);
>   static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
>   static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
> + static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
>   static tree handle_always_inline_attribute (tree *, tree, tree, int,
>   					    bool *);
>   static tree handle_gnu_inline_attribute (tree *, tree, tree, int, bool *);
> *************** const struct attribute_spec c_common_att
> *** 570,575 ****
> --- 571,578 ----
>   			      handle_noinline_attribute },
>     { "noclone",                0, 0, true,  false, false,
>   			      handle_noclone_attribute },
> +   { "leaf",                   0, 0, true,  false, false,
> + 			      handle_leaf_attribute },
>     { "always_inline",          0, 0, true,  false, false,
>   			      handle_always_inline_attribute },
>     { "gnu_inline",             0, 0, true,  false, false,
> *************** handle_gnu_inline_attribute (tree *node,
> *** 5870,5875 ****
> --- 5873,5900 ----
>         *no_add_attrs = true;
>       }
>   
> +   return NULL_TREE;
> + }
> + 
> + /* Handle a "leaf" attribute; arguments as in
> +    struct attribute_spec.handler.  */
> + 
> + static tree
> + handle_leaf_attribute (tree *node, tree name,
> + 		       tree ARG_UNUSED (args),
> + 		       int ARG_UNUSED (flags), bool *no_add_attrs)
> + {
> +   if (TREE_CODE (*node) != FUNCTION_DECL)
> +     {
> +       warning (OPT_Wattributes, "%qE attribute ignored", name);
> +       *no_add_attrs = true;
> +     }
> +   if (!TREE_PUBLIC (*node))
> +     {
> +       warning (OPT_Wattributes, "%qE attribute has no effect on unit local functions", name);
> +       *no_add_attrs = true;
> +     }
> + 
>     return NULL_TREE;
>   }
>   
> Index: tree.c
> ===================================================================
> *** tree.c	(revision 164477)
> --- tree.c	(working copy)
> *************** local_define_builtin (const char *name,
> *** 9224,9229 ****
> --- 9224,9232 ----
>       TREE_NOTHROW (decl) = 1;
>     if (ecf_flags & ECF_MALLOC)
>       DECL_IS_MALLOC (decl) = 1;
> +   if (ecf_flags & ECF_LEAF)
> +     DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("leaf"),
> + 					NULL, DECL_ATTRIBUTES (decl));
>   
>     built_in_decls[code] = decl;
>     implicit_built_in_decls[code] = decl;
> *************** build_common_builtin_nodes (void)
> *** 9247,9256 ****
>   
>         if (built_in_decls[BUILT_IN_MEMCPY] == NULL)
>   	local_define_builtin ("__builtin_memcpy", ftype, BUILT_IN_MEMCPY,
> ! 			      "memcpy", ECF_NOTHROW);
>         if (built_in_decls[BUILT_IN_MEMMOVE] == NULL)
>   	local_define_builtin ("__builtin_memmove", ftype, BUILT_IN_MEMMOVE,
> ! 			      "memmove", ECF_NOTHROW);
>       }
>   
>     if (built_in_decls[BUILT_IN_MEMCMP] == NULL)
> --- 9250,9259 ----
>   
>         if (built_in_decls[BUILT_IN_MEMCPY] == NULL)
>   	local_define_builtin ("__builtin_memcpy", ftype, BUILT_IN_MEMCPY,
> ! 			      "memcpy", ECF_NOTHROW | ECF_LEAF);
>         if (built_in_decls[BUILT_IN_MEMMOVE] == NULL)
>   	local_define_builtin ("__builtin_memmove", ftype, BUILT_IN_MEMMOVE,
> ! 			      "memmove", ECF_NOTHROW | ECF_LEAF);
>       }
>   
>     if (built_in_decls[BUILT_IN_MEMCMP] == NULL)
> *************** build_common_builtin_nodes (void)
> *** 9259,9265 ****
>   					const_ptr_type_node, size_type_node,
>   					NULL_TREE);
>         local_define_builtin ("__builtin_memcmp", ftype, BUILT_IN_MEMCMP,
> ! 			    "memcmp", ECF_PURE | ECF_NOTHROW);
>       }
>   
>     if (built_in_decls[BUILT_IN_MEMSET] == NULL)
> --- 9262,9268 ----
>   					const_ptr_type_node, size_type_node,
>   					NULL_TREE);
>         local_define_builtin ("__builtin_memcmp", ftype, BUILT_IN_MEMCMP,
> ! 			    "memcmp", ECF_PURE | ECF_NOTHROW | ECF_LEAF);
>       }
>   
>     if (built_in_decls[BUILT_IN_MEMSET] == NULL)
> *************** build_common_builtin_nodes (void)
> *** 9268,9274 ****
>   					ptr_type_node, integer_type_node,
>   					size_type_node, NULL_TREE);
>         local_define_builtin ("__builtin_memset", ftype, BUILT_IN_MEMSET,
> ! 			    "memset", ECF_NOTHROW);
>       }
>   
>     if (built_in_decls[BUILT_IN_ALLOCA] == NULL)
> --- 9271,9277 ----
>   					ptr_type_node, integer_type_node,
>   					size_type_node, NULL_TREE);
>         local_define_builtin ("__builtin_memset", ftype, BUILT_IN_MEMSET,
> ! 			    "memset", ECF_NOTHROW | ECF_LEAF);
>       }
>   
>     if (built_in_decls[BUILT_IN_ALLOCA] == NULL)
> *************** build_common_builtin_nodes (void)
> *** 9276,9282 ****
>         ftype = build_function_type_list (ptr_type_node,
>   					size_type_node, NULL_TREE);
>         local_define_builtin ("__builtin_alloca", ftype, BUILT_IN_ALLOCA,
> ! 			    "alloca", ECF_MALLOC | ECF_NOTHROW);
>       }
>   
>     /* If we're checking the stack, `alloca' can throw.  */
> --- 9279,9285 ----
>         ftype = build_function_type_list (ptr_type_node,
>   					size_type_node, NULL_TREE);
>         local_define_builtin ("__builtin_alloca", ftype, BUILT_IN_ALLOCA,
> ! 			    "alloca", ECF_MALLOC | ECF_NOTHROW | ECF_LEAF);
>       }
>   
>     /* If we're checking the stack, `alloca' can throw.  */
> *************** build_common_builtin_nodes (void)
> *** 9288,9294 ****
>   				    ptr_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_init_trampoline", ftype,
>   			BUILT_IN_INIT_TRAMPOLINE,
> ! 			"__builtin_init_trampoline", ECF_NOTHROW);
>   
>     ftype = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_adjust_trampoline", ftype,
> --- 9291,9297 ----
>   				    ptr_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_init_trampoline", ftype,
>   			BUILT_IN_INIT_TRAMPOLINE,
> ! 			"__builtin_init_trampoline", ECF_NOTHROW | ECF_LEAF);
>   
>     ftype = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_adjust_trampoline", ftype,
> *************** build_common_builtin_nodes (void)
> *** 9322,9333 ****
>   
>     ftype = build_function_type_list (ptr_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_stack_save", ftype, BUILT_IN_STACK_SAVE,
> ! 			"__builtin_stack_save", ECF_NOTHROW);
>   
>     ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_stack_restore", ftype,
>   			BUILT_IN_STACK_RESTORE,
> ! 			"__builtin_stack_restore", ECF_NOTHROW);
>   
>     ftype = build_function_type_list (void_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_profile_func_enter", ftype,
> --- 9325,9336 ----
>   
>     ftype = build_function_type_list (ptr_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_stack_save", ftype, BUILT_IN_STACK_SAVE,
> ! 			"__builtin_stack_save", ECF_NOTHROW | ECF_LEAF);
>   
>     ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_stack_restore", ftype,
>   			BUILT_IN_STACK_RESTORE,
> ! 			"__builtin_stack_restore", ECF_NOTHROW | ECF_LEAF);
>   
>     ftype = build_function_type_list (void_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_profile_func_enter", ftype,
> *************** build_common_builtin_nodes (void)
> *** 9342,9348 ****
>         ftype = build_function_type_list (void_type_node, NULL_TREE);
>         local_define_builtin ("__builtin_cxa_end_cleanup", ftype,
>   			    BUILT_IN_CXA_END_CLEANUP,
> ! 			    "__cxa_end_cleanup", ECF_NORETURN);
>       }
>   
>     ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
> --- 9345,9351 ----
>         ftype = build_function_type_list (void_type_node, NULL_TREE);
>         local_define_builtin ("__builtin_cxa_end_cleanup", ftype,
>   			    BUILT_IN_CXA_END_CLEANUP,
> ! 			    "__cxa_end_cleanup", ECF_NORETURN | ECF_LEAF);
>       }
>   
>     ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
> *************** build_common_builtin_nodes (void)
> *** 9361,9372 ****
>     ftype = build_function_type_list (ptr_type_node,
>   				    integer_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_eh_pointer", ftype, BUILT_IN_EH_POINTER,
> ! 			"__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW);
>   
>     tmp = lang_hooks.types.type_for_mode (targetm.eh_return_filter_mode (), 0);
>     ftype = build_function_type_list (tmp, integer_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_eh_filter", ftype, BUILT_IN_EH_FILTER,
> ! 			"__builtin_eh_filter", ECF_PURE | ECF_NOTHROW);
>   
>     ftype = build_function_type_list (void_type_node,
>   				    integer_type_node, integer_type_node,
> --- 9364,9375 ----
>     ftype = build_function_type_list (ptr_type_node,
>   				    integer_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_eh_pointer", ftype, BUILT_IN_EH_POINTER,
> ! 			"__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW | ECF_LEAF);
>   
>     tmp = lang_hooks.types.type_for_mode (targetm.eh_return_filter_mode (), 0);
>     ftype = build_function_type_list (tmp, integer_type_node, NULL_TREE);
>     local_define_builtin ("__builtin_eh_filter", ftype, BUILT_IN_EH_FILTER,
> ! 			"__builtin_eh_filter", ECF_PURE | ECF_NOTHROW | ECF_LEAF);
>   
>     ftype = build_function_type_list (void_type_node,
>   				    integer_type_node, integer_type_node,
> *************** build_common_builtin_nodes (void)
> *** 9408,9418 ****
>   
>   	built_in_names[mcode] = concat ("__mul", mode_name_buf, "3", NULL);
>           local_define_builtin (built_in_names[mcode], ftype, mcode,
> ! 			      built_in_names[mcode], ECF_CONST | ECF_NOTHROW);
>   
>   	built_in_names[dcode] = concat ("__div", mode_name_buf, "3", NULL);
>           local_define_builtin (built_in_names[dcode], ftype, dcode,
> ! 			      built_in_names[dcode], ECF_CONST | ECF_NOTHROW);
>         }
>     }
>   }
> --- 9411,9421 ----
>   
>   	built_in_names[mcode] = concat ("__mul", mode_name_buf, "3", NULL);
>           local_define_builtin (built_in_names[mcode], ftype, mcode,
> ! 			      built_in_names[mcode], ECF_CONST | ECF_NOTHROW | ECF_LEAF);
>   
>   	built_in_names[dcode] = concat ("__div", mode_name_buf, "3", NULL);
>           local_define_builtin (built_in_names[dcode], ftype, dcode,
> ! 			      built_in_names[dcode], ECF_CONST | ECF_NOTHROW | ECF_LEAF);
>         }
>     }
>   }
> Index: tree.h
> ===================================================================
> *** tree.h	(revision 164477)
> --- tree.h	(working copy)
> *************** extern tree build_duplicate_type (tree);
> *** 5224,5229 ****
> --- 5224,5231 ----
>   /* Function does not read or write memory (but may have side effects, so
>      it does not necessarily fit ECF_CONST).  */
>   #define ECF_NOVOPS		  (1 << 9)
> + /* The function does not lead to calls within current function unit.  */
> + #define ECF_LEAF		  (1 << 10)
>   
>   extern int flags_from_decl_or_type (const_tree);
>   extern int call_expr_flags (const_tree);
> Index: ipa-reference.c
> ===================================================================
> *** ipa-reference.c	(revision 164477)
> --- ipa-reference.c	(working copy)
> *************** ipa_reference_get_not_read_global (struc
> *** 200,205 ****
> --- 200,207 ----
>     info = get_reference_optimization_summary (fn);
>     if (info)
>       return info->statics_not_read;
> +   else if (flags_from_decl_or_type (fn->decl) & ECF_LEAF)
> +     return all_module_statics;
>     else
>       return NULL;
>   }
> *************** ipa_reference_get_not_written_global (st
> *** 217,222 ****
> --- 219,226 ----
>     info = get_reference_optimization_summary (fn);
>     if (info)
>       return info->statics_not_written;
> +   else if (flags_from_decl_or_type (fn->decl) & ECF_LEAF)
> +     return all_module_statics;
>     else
>       return NULL;
>   }
> *************** propagate_bits (ipa_reference_global_var
> *** 299,307 ****
>     for (e = x->callees; e; e = e->next_callee)
>       {
>         struct cgraph_node *y = e->callee;
>   
>         /* Only look into nodes we can propagate something.  */
> !       if (cgraph_function_body_availability (e->callee) > AVAIL_OVERWRITABLE)
>   	{
>   	  int flags = flags_from_decl_or_type (e->callee->decl);
>   	  if (get_reference_vars_info (y))
> --- 303,315 ----
>     for (e = x->callees; e; e = e->next_callee)
>       {
>         struct cgraph_node *y = e->callee;
> +       enum availability avail;
>   
> +       avail = cgraph_function_body_availability (e->callee);
>         /* Only look into nodes we can propagate something.  */
> !       if (avail > AVAIL_OVERWRITABLE
> ! 	  || (avail == AVAIL_OVERWRITABLE
> ! 	      && (flags_from_decl_or_type (e->callee->decl) & ECF_LEAF)))
>   	{
>   	  int flags = flags_from_decl_or_type (e->callee->decl);
>   	  if (get_reference_vars_info (y))
> *************** read_write_all_from_decl (struct cgraph_
> *** 573,589 ****
>   {
>     tree decl = node->decl;
>     int flags = flags_from_decl_or_type (decl);
> !   if (flags & ECF_CONST)
>       ;
>     else if ((flags & ECF_PURE)
>   	   || cgraph_node_cannot_return (node))
> !     *read_all = true;
>     else
>       {
>          /* TODO: To be able to produce sane results, we should also handle
>   	  common builtins, in particular throw.  */
>         *read_all = true;
>         *write_all = true;
>       }
>   }
>   
> --- 581,608 ----
>   {
>     tree decl = node->decl;
>     int flags = flags_from_decl_or_type (decl);
> !   if ((flags & ECF_LEAF)
> !       && cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
> !     ;
> !   else if (flags & ECF_CONST)
>       ;
>     else if ((flags & ECF_PURE)
>   	   || cgraph_node_cannot_return (node))
> !     {
> !       *read_all = true;
> !       if (dump_file && (dump_flags & TDF_DETAILS))
> !          fprintf (dump_file, "   %s/%i -> read all\n",
> ! 		  cgraph_node_name (node), node->uid);
> !     }
>     else
>       {
>          /* TODO: To be able to produce sane results, we should also handle
>   	  common builtins, in particular throw.  */
>         *read_all = true;
>         *write_all = true;
> +       if (dump_file && (dump_flags & TDF_DETAILS))
> +          fprintf (dump_file, "   %s/%i -> read all, write all\n",
> + 		  cgraph_node_name (node), node->uid);
>       }
>   }
>   
> *************** propagate (void)
> *** 629,634 ****
> --- 648,658 ----
>         node_info = get_reference_vars_info (node);
>         gcc_assert (node_info);
>   
> + 
> +       if (dump_file && (dump_flags & TDF_DETAILS))
> + 	fprintf (dump_file, "Starting cycle with %s/%i\n",
> + 		  cgraph_node_name (node), node->uid);
> + 
>         node_l = &node_info->local;
>         node_g = &node_info->global;
>   
> *************** propagate (void)
> *** 647,655 ****
>   	if (!(ie->indirect_info->ecf_flags & ECF_CONST))
>   	  {
>   	    read_all = true;
>   	    if (!cgraph_edge_cannot_lead_to_return (ie)
>   		&& !(ie->indirect_info->ecf_flags & ECF_PURE))
> ! 	      write_all = true;
>   	  }
>   
>   
> --- 671,685 ----
>   	if (!(ie->indirect_info->ecf_flags & ECF_CONST))
>   	  {
>   	    read_all = true;
> + 	    if (dump_file && (dump_flags & TDF_DETAILS))
> + 	       fprintf (dump_file, "   indirect call -> read all\n");
>   	    if (!cgraph_edge_cannot_lead_to_return (ie)
>   		&& !(ie->indirect_info->ecf_flags & ECF_PURE))
> ! 	      {
> ! 		if (dump_file && (dump_flags & TDF_DETAILS))
> ! 		   fprintf (dump_file, "   indirect call -> write all\n");
> ! 	        write_all = true;
> ! 	      }
>   	  }
>   
>   
> *************** propagate (void)
> *** 659,664 ****
> --- 689,697 ----
>         w = w_info->next_cycle;
>         while (w && (!read_all || !write_all))
>   	{
> + 	  if (dump_file && (dump_flags & TDF_DETAILS))
> + 	    fprintf (dump_file, "  Visiting %s/%i\n",
> + 		      cgraph_node_name (w), w->uid);
>   	  /* When function is overwrittable, we can not assume anything.  */
>   	  if (cgraph_function_body_availability (w) <= AVAIL_OVERWRITABLE)
>   	    read_write_all_from_decl (w, &read_all, &write_all);
> *************** propagate (void)
> *** 671,679 ****
>   	    if (!(ie->indirect_info->ecf_flags & ECF_CONST))
>   	      {
>   		read_all = true;
>   		if (!cgraph_edge_cannot_lead_to_return (ie)
>   		    && !(ie->indirect_info->ecf_flags & ECF_PURE))
> ! 		  write_all = true;
>   	      }
>   
>   	  w_info = (struct ipa_dfs_info *) w->aux;
> --- 704,718 ----
>   	    if (!(ie->indirect_info->ecf_flags & ECF_CONST))
>   	      {
>   		read_all = true;
> + 		if (dump_file && (dump_flags & TDF_DETAILS))
> + 		   fprintf (dump_file, "   indirect call -> read all\n");
>   		if (!cgraph_edge_cannot_lead_to_return (ie)
>   		    && !(ie->indirect_info->ecf_flags & ECF_PURE))
> ! 		  {
> ! 		    write_all = true;
> ! 		    if (dump_file && (dump_flags & TDF_DETAILS))
> ! 		       fprintf (dump_file, "   indirect call -> write all\n");
> ! 		  }
>   	      }
>   
>   	  w_info = (struct ipa_dfs_info *) w->aux;
> *************** propagate (void)
> *** 841,847 ****
>           continue;
>   
>         node_info = get_reference_vars_info (node);
> !       if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE)
>   	{
>   	  node_g = &node_info->global;
>   
> --- 880,887 ----
>           continue;
>   
>         node_info = get_reference_vars_info (node);
> !       if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE
> ! 	  || (flags_from_decl_or_type (node->decl) & ECF_LEAF))
>   	{
>   	  node_g = &node_info->global;
>   
> Index: testsuite/gcc.dg/tree-ssa/leaf.c
> ===================================================================
> *** testsuite/gcc.dg/tree-ssa/leaf.c	(revision 0)
> --- testsuite/gcc.dg/tree-ssa/leaf.c	(revision 0)
> ***************
> *** 0 ****
> --- 1,20 ----
> + /* { dg-do compile } */
> + /* { dg-options "-O2 -fdump-tree-optimized" } */
> + static int local_static;
> + void __attribute__ ((leaf)) leaf_call (void);
> + 
> + int
> + clobber_it (void)
> + {
> +   return local_static++;
> + }
> + int
> + test (void)
> + {
> +   local_static = 9;
> +   leaf_call ();
> +   return local_static;
> + }
> + /* { dg-final { scan-tree-dump-times "return 9" 1 "optimized"} } */
> +  
> + /* { dg-final { cleanup-tree-dump "optimized" } } */
> Index: calls.c
> ===================================================================
> *** calls.c	(revision 164477)
> --- calls.c	(working copy)
> *************** flags_from_decl_or_type (const_tree exp)
> *** 610,615 ****
> --- 610,617 ----
>   
>         if (DECL_IS_NOVOPS (exp))
>   	flags |= ECF_NOVOPS;
> +       if (lookup_attribute ("leaf", DECL_ATTRIBUTES (exp)))
> + 	flags |= ECF_LEAF;
>   
>         if (TREE_NOTHROW (exp))
>   	flags |= ECF_NOTHROW;
> Index: tree-cfg.c
> ===================================================================
> *** tree-cfg.c	(revision 164477)
> --- tree-cfg.c	(working copy)
> *************** stmt_can_make_abnormal_goto (gimple t)
> *** 2314,2320 ****
>     if (computed_goto_p (t))
>       return true;
>     if (is_gimple_call (t))
> !     return gimple_has_side_effects (t) && cfun->has_nonlocal_label;
>     return false;
>   }
>   
> --- 2314,2321 ----
>     if (computed_goto_p (t))
>       return true;
>     if (is_gimple_call (t))
> !     return (gimple_has_side_effects (t) && cfun->has_nonlocal_label
> ! 	    && !(gimple_call_flags (t) & ECF_LEAF));
>     return false;
>   }
>   
> 
> 

-- 
Richard Guenther <rguenther@suse.de>
Novell / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 - GF: Markus Rex



More information about the Gcc-patches mailing list