Patchwork Set current_function_decl in {push,pop}_cfun and push_struct_function

login
register
mail settings
Submitter Martin Jambor
Date Aug. 24, 2012, 1:24 p.m.
Message ID <20120824132400.GA24686@virgil.arch.suse.de>
Download mbox | patch
Permalink /patch/179838/
State New
Headers show

Comments

Martin Jambor - Aug. 24, 2012, 1:24 p.m.
Hi,

On Wed, Aug 22, 2012 at 03:37:48PM +0200, Richard Guenther wrote:
> On Wed, Aug 22, 2012 at 3:04 PM, Martin Jambor <mjambor@suse.cz> wrote:
> > On Tue, Aug 21, 2012 at 01:30:47PM +0200, Richard Guenther wrote:
> >> On Tue, Aug 21, 2012 at 1:27 PM, Martin Jambor <mjambor@suse.cz> wrote:
> >> > On Wed, Aug 15, 2012 at 05:21:04PM +0200, Martin Jambor wrote:
> >> >> Hi,
> >> >>
> >> >> On Fri, Aug 10, 2012 at 04:57:41PM +0200, Eric Botcazou wrote:
> >> >> > > - ada/gcc-interface/utils.c:rest_of_subprog_body_compilation calls
> >> >> > >   dump_function which in turns calls dump_function_to_file which calls
> >> >> > >   push_cfun.  But Ada front end has its idea of the
> >> >> > >   current_function_decl and there is no cfun which is an inconsistency
> >> >> > >   which makes push_cfun assert fail.  I "solved" it by temporarily
> >> >> > >   setting current_function_decl to NULL_TREE.  It's just dumping and I
> >> >> > >   thought that dump_function should be considered middle-end and thus
> >> >> > >   middle-end invariants should apply.
> >> >> >
> >> >> > If you think that calling dump_function from rest_of_subprog_body_compilation
> >> >> > is a layering violation, I don't have a problem with replacing it with a more
> >> >> > "manual" scheme like the one in c-family/c-gimplify.c:c_genericize, provided
> >> >> > that this yields roughly the same output.
> >> >>
> >> >> Richi suggested on IRC that I remove the push/pop_cfun calls from
> >> >> dump_function_to_file.  The only problem seems to be
> >> >> dump_histograms_for_stmt
> >> >
> >> > Yesterday I actually tried and it is not the only problem.  Another
> >> > one is dump_function_to_file->dump_bb->maybe_hot_bb_p which uses cfun
> >> > to read profile_status.  There may be others, this one just blew up
> >> > first when I set cfun to NULL.  And in future someone is quite likely
> >> > to need cfun to dump something new too.
> >> >
> >> > At the same time, re-implementing dumping
> >> > c-family/c-gimplify.c:c_genericize when dump_function suffices seems
> >> > ugly to me.
> >> >
> >> > So I am going to declare dump_function a front-end interface and use
> >> > set_cfun in my original patch in dump_function_to_file like we do in
> >> > other such functions.
> >> >
> >> > I hope that will be OK.  Thanks,
> >>
> >> Setting cfun has side-effects of switching target stuff which might have
> >> code-generation side-effects because of implementation issues we have
> >> with target/optimize attributes.  So I don't think cfun should be changed
> >> just for dumping.
> >>
> >> Can you instead just set current_function_decl and access
> >> struct function via DECL_STRUCT_FUNCTION in the dumpers then?
> >> After all, it it is a front-end interface, the frontend way of saying
> >> "this is the current function" is to set current_function_decl, not the
> >> middle-end cfun.
> >>
> >
> > Like the following?  Tested and bootstrapped on x86_64-linux, it does
> > help avoid the ada hunk in my previous patch.  OK for trunk?
> 
> Ok if nobody complains - btw, I think you miss to restore current_function_decl
> here:
> 
> 
> > *** /tmp/HcgoTd_tree-cfg.c      Wed Aug 22 15:02:30 2012
> > --- gcc/tree-cfg.c      Wed Aug 22 11:53:02 2012
> > *************** move_sese_region_to_fn (struct function
> > *** 6632,6650 ****
> >      */
> >
> >   void
> > ! dump_function_to_file (tree fn, FILE *file, int flags)
> >   {
> > !   tree arg, var;
> >     struct function *dsf;
> >     bool ignore_topmost_bind = false, any_var = false;
> >     basic_block bb;
> >     tree chain;
> > !   bool tmclone = TREE_CODE (fn) == FUNCTION_DECL && decl_is_tm_clone (fn);
> >
> > !   fprintf (file, "%s %s(", current_function_name (),
> > !          tmclone ? "[tm-clone] " : "");
> >
> > !   arg = DECL_ARGUMENTS (fn);
> >     while (arg)
> >       {
> >         print_generic_expr (file, TREE_TYPE (arg), dump_flags);
> > --- 6632,6652 ----
> >      */
> >
> >   void
> > ! dump_function_to_file (tree fndecl, FILE *file, int flags)
> >   {
> > !   tree arg, var, old_current_fndecl = current_function_decl;
> >     struct function *dsf;
> >     bool ignore_topmost_bind = false, any_var = false;
> >     basic_block bb;
> >     tree chain;
> > !   bool tmclone = (TREE_CODE (fndecl) == FUNCTION_DECL
> > !                 && decl_is_tm_clone (fndecl));
> > !   struct function *fun = DECL_STRUCT_FUNCTION (fndecl);
> >
> > !   current_function_decl = fndecl;
> > !   fprintf (file, "%s %s(", function_name (fun), tmclone ? "[tm-clone] " : "");
> >
> > !   arg = DECL_ARGUMENTS (fndecl);
> >     while (arg)
> >       {
> >         print_generic_expr (file, TREE_TYPE (arg), dump_flags);
> > *************** dump_function_to_file (tree fn, FILE *fi
> > *** 6659,6689 ****
> >     fprintf (file, ")\n");
> >
> >     if (flags & TDF_VERBOSE)
> > !     print_node (file, "", fn, 2);
> >
> > !   dsf = DECL_STRUCT_FUNCTION (fn);
> >     if (dsf && (flags & TDF_EH))
> >       dump_eh_tree (file, dsf);
> >
> > !   if (flags & TDF_RAW && !gimple_has_body_p (fn))
> >       {
> > !       dump_node (fn, TDF_SLIM | flags, file);
> >         return;
> >       }
> >
> > -   /* Switch CFUN to point to FN.  */
> > -   push_cfun (DECL_STRUCT_FUNCTION (fn));
> > -
> >     /* When GIMPLE is lowered, the variables are no longer available in
> >        BIND_EXPRs, so display them separately.  */
> > !   if (cfun && cfun->decl == fn && (cfun->curr_properties & PROP_gimple_lcf))
> >       {
> >         unsigned ix;
> >         ignore_topmost_bind = true;
> >
> >         fprintf (file, "{\n");
> > !       if (!VEC_empty (tree, cfun->local_decls))
> > !       FOR_EACH_LOCAL_DECL (cfun, ix, var)
> >           {
> >             print_generic_decl (file, var, flags);
> >             if (flags & TDF_VERBOSE)
> > --- 6661,6688 ----
> >     fprintf (file, ")\n");
> >
> >     if (flags & TDF_VERBOSE)
> > !     print_node (file, "", fndecl, 2);
> >
> > !   dsf = DECL_STRUCT_FUNCTION (fndecl);
> >     if (dsf && (flags & TDF_EH))
> >       dump_eh_tree (file, dsf);
> >
> > !   if (flags & TDF_RAW && !gimple_has_body_p (fndecl))
> >       {
> > !       dump_node (fndecl, TDF_SLIM | flags, file);
> >         return;
> 
> ^^^^
> 
> and maybe other early exits from dump_function_to_file.
> 

Oh, I missed that, there are no further early returns in the function.
I have added another restoration of current_function_decl there and
committed the patch below after retesting.

> Also as said on IRC when you switch current_function_decl you should be
> able to set cfun to NULL (and restore it afterwards, without invoking the
> target hook for cfun switching).  Thus, encapsulating this into a
> push/pop_current_function_decl would be nice.

Good idea, I will incorporate that into my original patch.

Thanks,

Martin



2012-08-24  Martin Jambor  <mjambor@suse.cz>

	* predict.c (maybe_hot_frequency_p): New parameter fun.  Use its decl
	instead of current_function_decl, use profile_status_for_function and
	ENTRY_BLOCK_PTR_FOR_FUNCTION with fun instead of their cfun variants.
	(maybe_hot_count_p): New parameter fun, use
	profile_status_for_function instead of its cfun_variant.
	(maybe_hot_bb_p): New parameter fun, checking-assert it, pass it to
	all callees.
	(maybe_hot_edge_p): Pass cfun to maybe_hot_count_p and
	maybe_hot_frequency_p.
	(probably_never_executed_bb_p): New parameter fun, use its decl
	instead of current_function_decl.
	(optimize_bb_for_size_p): Pass cfun to maybe_hot_bb_p.
	(rtl_profile_for_bb): Likewise.
	(compute_function_frequency): Pass cfun to maybe_hot_bb_p and
	probably_never_executed_bb_p.
	* tree-ssa-operands.c (ssa_operands_active): New operator fun.  Use it
	instead of cfun.
	(update_stmt_operands): Pass cfun as an argument of
	ssa_operands_active.
	(swap_tree_operands): Likewise.
	* gimple-iterator.c (update_modified_stmt): Likewise.
	(update_modified_stmts): Likewise.
	* tree-flow-inline.h (delink_stmt_imm_use): Likewise.
	* tree-ssa.c (delete_tree_ssa): Likewise.
	* bb-reorder.c (bb_to_key): Pass cfun to probably_never_executed_bb_p.
	(push_to_next_round_p): Likewise.
	(find_rarely_executed_basic_blocks_and_crossing_edges ): Likewise.
	* cfg.c: Inlude tree.h.
	(check_bb_profile): Use profile_status_for_function,
	EXIT_BLOCK_PTR_FOR_FUNCTION and ENTRY_BLOCK_PTR_FOR_FUNCTION with
	DECL_STRUCT_FUNCTION (current_function_decl) instead of their cfun
	variants.
	(dump_bb_info): Pass DECL_STRUCT_FUNCTION (current_function_decl) to
	maybe_hot_bb_p and probably_never_executed_bb_p.
	* gimple-pretty-print.c (gimple_dump_bb_buff): Checking-assert that
	DECL_STRUCT_FUNCTION (current_function_decl) is not NULL.  Pass it to
	dump_histograms_for_stmt.
	(dump_gimple_mem_ops): Pass DECL_STRUCT_FUNCTION (current_function_decl)
	as an argument to dump_gimple_mem_ops.
	* tree-cfg.c (dump_function_to_file): Rename parameter fn to fndecl.
	Do not change cfun.  Change and restore current_function_decl.
	* Makefile.in (cfg.o): Include TREE_H in dependencies.

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index dddffb6..9886b6c 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -3047,7 +3047,8 @@  auto-inc-dec.o : auto-inc-dec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(REGS_H) $(FLAGS_H) $(FUNCTION_H) $(EXCEPT_H) $(DIAGNOSTIC_CORE_H) $(RECOG_H) \
    $(EXPR_H) $(TREE_PASS_H) $(DF_H) $(DBGCNT_H) $(TARGET_H)
 cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h dumpfile.h $(DIAGNOSTIC_CORE_H) \
-   $(GGC_H) $(OBSTACK_H) alloc-pool.h $(HASHTAB_H) $(CFGLOOP_H) $(BASIC_BLOCK_H)
+   $(GGC_H) $(OBSTACK_H) alloc-pool.h $(HASHTAB_H) $(CFGLOOP_H) $(TREE_H) \
+   $(BASIC_BLOCK_H)
 cfghooks.o: cfghooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TREE_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TIMEVAR_H) toplev.h $(DIAGNOSTIC_CORE_H) $(CFGLOOP_H)
 cfgexpand.o : cfgexpand.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index 6e1d091..09b5eb0 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -693,9 +693,9 @@  extern struct edge_list *pre_edge_rev_lcm (int, sbitmap *,
 extern void compute_available (sbitmap *, sbitmap *, sbitmap *, sbitmap *);
 
 /* In predict.c */
-extern bool maybe_hot_bb_p (const_basic_block);
+extern bool maybe_hot_bb_p (struct function *, const_basic_block);
 extern bool maybe_hot_edge_p (edge);
-extern bool probably_never_executed_bb_p (const_basic_block);
+extern bool probably_never_executed_bb_p (struct function *, const_basic_block);
 extern bool optimize_bb_for_size_p (const_basic_block);
 extern bool optimize_bb_for_speed_p (const_basic_block);
 extern bool optimize_edge_for_size_p (edge);
diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c
index 0d29b2d..c282fb2 100644
--- a/gcc/bb-reorder.c
+++ b/gcc/bb-reorder.c
@@ -226,7 +226,7 @@  push_to_next_round_p (const_basic_block bb, int round, int number_of_rounds,
 
   block_not_hot_enough = (bb->frequency < exec_th
 			  || bb->count < count_th
-			  || probably_never_executed_bb_p (bb));
+			  || probably_never_executed_bb_p (cfun, bb));
 
   if (there_exists_another_round
       && block_not_hot_enough)
@@ -823,7 +823,7 @@  bb_to_key (basic_block bb)
   /* Do not start in probably never executed blocks.  */
 
   if (BB_PARTITION (bb) == BB_COLD_PARTITION
-      || probably_never_executed_bb_p (bb))
+      || probably_never_executed_bb_p (cfun, bb))
     return BB_FREQ_MAX;
 
   /* Prefer blocks whose predecessor is an end of some trace
@@ -1308,7 +1308,7 @@  find_rarely_executed_basic_blocks_and_crossing_edges (void)
   /* Mark which partition (hot/cold) each basic block belongs in.  */
   FOR_EACH_BB (bb)
     {
-      if (probably_never_executed_bb_p (bb))
+      if (probably_never_executed_bb_p (cfun, bb))
 	BB_SET_PARTITION (bb, BB_COLD_PARTITION);
       else
 	BB_SET_PARTITION (bb, BB_HOT_PARTITION);
diff --git a/gcc/cfg.c b/gcc/cfg.c
index ba83208..3f14d49 100644
--- a/gcc/cfg.c
+++ b/gcc/cfg.c
@@ -55,6 +55,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "ggc.h"
 #include "hashtab.h"
 #include "alloc-pool.h"
+#include "tree.h"
 #include "basic-block.h"
 #include "df.h"
 #include "cfgloop.h" /* FIXME: For struct loop.  */
@@ -404,14 +405,15 @@  check_bb_profile (basic_block bb, FILE * file, int indent, int flags)
   int sum = 0;
   gcov_type lsum;
   edge_iterator ei;
+  struct function *fun = DECL_STRUCT_FUNCTION (current_function_decl);
   char *s_indent = (char *) alloca ((size_t) indent + 1);
   memset ((void *) s_indent, ' ', (size_t) indent);
   s_indent[indent] = '\0';
 
-  if (profile_status == PROFILE_ABSENT)
+  if (profile_status_for_function (fun) == PROFILE_ABSENT)
     return;
 
-  if (bb != EXIT_BLOCK_PTR)
+  if (bb != EXIT_BLOCK_PTR_FOR_FUNCTION (fun))
     {
       FOR_EACH_EDGE (e, ei, bb->succs)
 	sum += e->probability;
@@ -428,7 +430,7 @@  check_bb_profile (basic_block bb, FILE * file, int indent, int flags)
 		 (flags & TDF_COMMENT) ? ";; " : "", s_indent,
 		 (int) lsum, (int) bb->count);
     }
-  if (bb != ENTRY_BLOCK_PTR)
+    if (bb != ENTRY_BLOCK_PTR_FOR_FUNCTION (fun))
     {
       sum = 0;
       FOR_EACH_EDGE (e, ei, bb->preds)
@@ -701,12 +703,13 @@  dump_bb_info (FILE *outf, basic_block bb, int indent, int flags,
 	       s_indent, bb->index, bb_loop_depth (bb));
       if (flags & TDF_DETAILS)
 	{
+	  struct function *fun = DECL_STRUCT_FUNCTION (current_function_decl);
 	  fprintf (outf, ", count " HOST_WIDEST_INT_PRINT_DEC,
 		   (HOST_WIDEST_INT) bb->count);
 	  fprintf (outf, ", freq %i", bb->frequency);
-	  if (maybe_hot_bb_p (bb))
+	  if (maybe_hot_bb_p (fun, bb))
 	    fputs (", maybe hot", outf);
-	  if (probably_never_executed_bb_p (bb))
+	  if (probably_never_executed_bb_p (fun, bb))
 	    fputs (", probably never executed", outf);
 	}
       fputc ('\n', outf);
diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c
index 914685c..3d01566 100644
--- a/gcc/gimple-iterator.c
+++ b/gcc/gimple-iterator.c
@@ -33,7 +33,7 @@  along with GCC; see the file COPYING3.  If not see
 static inline void
 update_modified_stmt (gimple stmt)
 {
-  if (!ssa_operands_active ())
+  if (!ssa_operands_active (cfun))
     return;
   update_stmt_if_modified (stmt);
 }
@@ -46,7 +46,7 @@  update_modified_stmts (gimple_seq seq)
 {
   gimple_stmt_iterator gsi;
 
-  if (!ssa_operands_active ())
+  if (!ssa_operands_active (cfun))
     return;
   for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi))
     update_stmt_if_modified (gsi_stmt (gsi));
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 3b25020..658e0be 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -1817,7 +1817,8 @@  dump_gimple_mem_ops (pretty_printer *buffer, gimple gs, int spc, int flags)
   tree vdef = gimple_vdef (gs);
   tree vuse = gimple_vuse (gs);
 
-  if (!ssa_operands_active () || !gimple_references_memory_p (gs))
+  if (!ssa_operands_active (DECL_STRUCT_FUNCTION (current_function_decl))
+      || !gimple_references_memory_p (gs))
     return;
 
   if (vdef != NULL_TREE)
@@ -2256,7 +2257,9 @@  gimple_dump_bb_buff (pretty_printer *buffer, basic_block bb, int indent,
       INDENT (curr_indent);
       dump_gimple_stmt (buffer, stmt, curr_indent, flags);
       pp_newline_and_flush (buffer);
-      dump_histograms_for_stmt (cfun, buffer->buffer->stream, stmt);
+      gcc_checking_assert (DECL_STRUCT_FUNCTION (current_function_decl));
+      dump_histograms_for_stmt (DECL_STRUCT_FUNCTION (current_function_decl),
+				buffer->buffer->stream, stmt);
     }
 
   dump_implicit_edges (buffer, bb, indent, flags);
diff --git a/gcc/predict.c b/gcc/predict.c
index e1a064d..f0db9f4 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -108,9 +108,9 @@  static const struct predictor_info predictor_info[]= {
 /* Return TRUE if frequency FREQ is considered to be hot.  */
 
 static inline bool
-maybe_hot_frequency_p (int freq)
+maybe_hot_frequency_p (struct function *fun, int freq)
 {
-  struct cgraph_node *node = cgraph_get_node (current_function_decl);
+  struct cgraph_node *node = cgraph_get_node (fun->decl);
   if (!profile_info || !flag_branch_probabilities)
     {
       if (node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
@@ -118,12 +118,13 @@  maybe_hot_frequency_p (int freq)
       if (node->frequency == NODE_FREQUENCY_HOT)
         return true;
     }
-  if (profile_status == PROFILE_ABSENT)
+  if (profile_status_for_function (fun) == PROFILE_ABSENT)
     return true;
   if (node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
-      && freq < (ENTRY_BLOCK_PTR->frequency * 2 / 3))
+      && freq < (ENTRY_BLOCK_PTR_FOR_FUNCTION (fun)->frequency * 2 / 3))
     return false;
-  if (freq < ENTRY_BLOCK_PTR->frequency / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
+  if (freq < (ENTRY_BLOCK_PTR_FOR_FUNCTION (fun)->frequency
+	      / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION)))
     return false;
   return true;
 }
@@ -131,9 +132,9 @@  maybe_hot_frequency_p (int freq)
 /* Return TRUE if frequency FREQ is considered to be hot.  */
 
 static inline bool
-maybe_hot_count_p (gcov_type count)
+maybe_hot_count_p (struct function *fun, gcov_type count)
 {
-  if (profile_status != PROFILE_READ)
+  if (profile_status_for_function (fun) != PROFILE_READ)
     return true;
   /* Code executed at most once is not hot.  */
   if (profile_info->runs >= count)
@@ -146,13 +147,12 @@  maybe_hot_count_p (gcov_type count)
    for maximal performance.  */
 
 bool
-maybe_hot_bb_p (const_basic_block bb)
+maybe_hot_bb_p (struct function *fun, const_basic_block bb)
 {
-  /* Make sure CFUN exists, for dump_bb_info.  */
-  gcc_assert (cfun);
-  if (profile_status == PROFILE_READ)
-    return maybe_hot_count_p (bb->count);
-  return maybe_hot_frequency_p (bb->frequency);
+  gcc_checking_assert (fun);
+  if (profile_status_for_function (fun) == PROFILE_READ)
+    return maybe_hot_count_p (fun, bb->count);
+  return maybe_hot_frequency_p (fun, bb->frequency);
 }
 
 /* Return true if the call can be hot.  */
@@ -193,22 +193,21 @@  bool
 maybe_hot_edge_p (edge e)
 {
   if (profile_status == PROFILE_READ)
-    return maybe_hot_count_p (e->count);
-  return maybe_hot_frequency_p (EDGE_FREQUENCY (e));
+    return maybe_hot_count_p (cfun, e->count);
+  return maybe_hot_frequency_p (cfun, EDGE_FREQUENCY (e));
 }
 
 
 /* Return true in case BB is probably never executed.  */
 
 bool
-probably_never_executed_bb_p (const_basic_block bb)
+probably_never_executed_bb_p (struct function *fun, const_basic_block bb)
 {
-  /* Make sure CFUN exists, for dump_bb_info.  */
-  gcc_assert (cfun);
+  gcc_checking_assert (fun);
   if (profile_info && flag_branch_probabilities)
     return ((bb->count + profile_info->runs / 2) / profile_info->runs) == 0;
   if ((!profile_info || !flag_branch_probabilities)
-      && (cgraph_get_node (current_function_decl)->frequency
+      && (cgraph_get_node (fun->decl)->frequency
 	  == NODE_FREQUENCY_UNLIKELY_EXECUTED))
     return true;
   return false;
@@ -252,7 +251,7 @@  optimize_function_for_speed_p (struct function *fun)
 bool
 optimize_bb_for_size_p (const_basic_block bb)
 {
-  return optimize_function_for_size_p (cfun) || !maybe_hot_bb_p (bb);
+  return optimize_function_for_size_p (cfun) || !maybe_hot_bb_p (cfun, bb);
 }
 
 /* Return TRUE when BB should be optimized for speed.  */
@@ -369,7 +368,7 @@  predictable_edge_p (edge e)
 void
 rtl_profile_for_bb (basic_block bb)
 {
-  crtl->maybe_hot_insn_p = maybe_hot_bb_p (bb);
+  crtl->maybe_hot_insn_p = maybe_hot_bb_p (cfun, bb);
 }
 
 /* Set RTL expansion for edge profile.  */
@@ -2705,12 +2704,12 @@  compute_function_frequency (void)
   node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
   FOR_EACH_BB (bb)
     {
-      if (maybe_hot_bb_p (bb))
+      if (maybe_hot_bb_p (cfun, bb))
 	{
 	  node->frequency = NODE_FREQUENCY_HOT;
 	  return;
 	}
-      if (!probably_never_executed_bb_p (bb))
+      if (!probably_never_executed_bb_p (cfun, bb))
 	node->frequency = NODE_FREQUENCY_NORMAL;
     }
 }
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index c718cc0..247f616 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -6632,19 +6632,21 @@  move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
    */
 
 void
-dump_function_to_file (tree fn, FILE *file, int flags)
+dump_function_to_file (tree fndecl, FILE *file, int flags)
 {
-  tree arg, var;
+  tree arg, var, old_current_fndecl = current_function_decl;
   struct function *dsf;
   bool ignore_topmost_bind = false, any_var = false;
   basic_block bb;
   tree chain;
-  bool tmclone = TREE_CODE (fn) == FUNCTION_DECL && decl_is_tm_clone (fn);
+  bool tmclone = (TREE_CODE (fndecl) == FUNCTION_DECL
+		  && decl_is_tm_clone (fndecl));
+  struct function *fun = DECL_STRUCT_FUNCTION (fndecl);
 
-  fprintf (file, "%s %s(", current_function_name (),
-	   tmclone ? "[tm-clone] " : "");
+  current_function_decl = fndecl;
+  fprintf (file, "%s %s(", function_name (fun), tmclone ? "[tm-clone] " : "");
 
-  arg = DECL_ARGUMENTS (fn);
+  arg = DECL_ARGUMENTS (fndecl);
   while (arg)
     {
       print_generic_expr (file, TREE_TYPE (arg), dump_flags);
@@ -6659,31 +6661,29 @@  dump_function_to_file (tree fn, FILE *file, int flags)
   fprintf (file, ")\n");
 
   if (flags & TDF_VERBOSE)
-    print_node (file, "", fn, 2);
+    print_node (file, "", fndecl, 2);
 
-  dsf = DECL_STRUCT_FUNCTION (fn);
+  dsf = DECL_STRUCT_FUNCTION (fndecl);
   if (dsf && (flags & TDF_EH))
     dump_eh_tree (file, dsf);
 
-  if (flags & TDF_RAW && !gimple_has_body_p (fn))
+  if (flags & TDF_RAW && !gimple_has_body_p (fndecl))
     {
-      dump_node (fn, TDF_SLIM | flags, file);
+      dump_node (fndecl, TDF_SLIM | flags, file);
+      current_function_decl = old_current_fndecl;
       return;
     }
 
-  /* Switch CFUN to point to FN.  */
-  push_cfun (DECL_STRUCT_FUNCTION (fn));
-
   /* When GIMPLE is lowered, the variables are no longer available in
      BIND_EXPRs, so display them separately.  */
-  if (cfun && cfun->decl == fn && (cfun->curr_properties & PROP_gimple_lcf))
+  if (fun && fun->decl == fndecl && (fun->curr_properties & PROP_gimple_lcf))
     {
       unsigned ix;
       ignore_topmost_bind = true;
 
       fprintf (file, "{\n");
-      if (!VEC_empty (tree, cfun->local_decls))
-	FOR_EACH_LOCAL_DECL (cfun, ix, var)
+      if (!VEC_empty (tree, fun->local_decls))
+	FOR_EACH_LOCAL_DECL (fun, ix, var)
 	  {
 	    print_generic_decl (file, var, flags);
 	    if (flags & TDF_VERBOSE)
@@ -6709,26 +6709,27 @@  dump_function_to_file (tree fn, FILE *file, int flags)
 	  }
     }
 
-  if (cfun && cfun->decl == fn && cfun->cfg && basic_block_info)
+  if (fun && fun->decl == fndecl && fun->cfg
+      && basic_block_info_for_function (fun))
     {
       /* If the CFG has been built, emit a CFG-based dump.  */
       if (!ignore_topmost_bind)
 	fprintf (file, "{\n");
 
-      if (any_var && n_basic_blocks)
+      if (any_var && n_basic_blocks_for_function (fun))
 	fprintf (file, "\n");
 
-      FOR_EACH_BB (bb)
+      FOR_EACH_BB_FN (bb, fun)
 	dump_bb (file, bb, 2, flags | TDF_COMMENT);
 
       fprintf (file, "}\n");
     }
-  else if (DECL_SAVED_TREE (fn) == NULL)
+  else if (DECL_SAVED_TREE (fndecl) == NULL)
     {
       /* The function is now in GIMPLE form but the CFG has not been
 	 built yet.  Emit the single sequence of GIMPLE statements
 	 that make up its body.  */
-      gimple_seq body = gimple_body (fn);
+      gimple_seq body = gimple_body (fndecl);
 
       if (gimple_seq_first_stmt (body)
 	  && gimple_seq_first_stmt (body) == gimple_seq_last_stmt (body)
@@ -6751,8 +6752,7 @@  dump_function_to_file (tree fn, FILE *file, int flags)
       int indent;
 
       /* Make a tree based dump.  */
-      chain = DECL_SAVED_TREE (fn);
-
+      chain = DECL_SAVED_TREE (fndecl);
       if (chain && TREE_CODE (chain) == BIND_EXPR)
 	{
 	  if (ignore_topmost_bind)
@@ -6782,11 +6782,9 @@  dump_function_to_file (tree fn, FILE *file, int flags)
     dump_enumerated_decls (file, flags);
   fprintf (file, "\n\n");
 
-  /* Restore CFUN.  */
-  pop_cfun ();
+  current_function_decl = old_current_fndecl;
 }
 
-
 /* Dump FUNCTION_DECL FN to stderr using FLAGS (see TDF_* in tree.h)  */
 
 DEBUG_FUNCTION void
diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h
index 7bd0db3..acb2cc4 100644
--- a/gcc/tree-flow-inline.h
+++ b/gcc/tree-flow-inline.h
@@ -798,7 +798,7 @@  delink_stmt_imm_use (gimple stmt)
    ssa_op_iter iter;
    use_operand_p use_p;
 
-   if (ssa_operands_active ())
+   if (ssa_operands_active (cfun))
      FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_ALL_USES)
        delink_imm_use (use_p);
 }
diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
index 3a1f989..d9b3146 100644
--- a/gcc/tree-ssa-operands.c
+++ b/gcc/tree-ssa-operands.c
@@ -130,16 +130,12 @@  static int n_initialized = 0;
 /*  Return true if the SSA operands cache is active.  */
 
 bool
-ssa_operands_active (void)
+ssa_operands_active (struct function *fun)
 {
-  /* This function may be invoked from contexts where CFUN is NULL
-     (IPA passes), return false for now.  FIXME: operands may be
-     active in each individual function, maybe this function should
-     take CFUN as a parameter.  */
-  if (cfun == NULL)
+  if (fun == NULL)
     return false;
 
-  return cfun->gimple_df && gimple_ssa_operands (cfun)->ops_active;
+  return fun->gimple_df && gimple_ssa_operands (fun)->ops_active;
 }
 
 
@@ -1211,7 +1207,7 @@  update_stmt_operands (gimple stmt)
 {
   /* If update_stmt_operands is called before SSA is initialized, do
      nothing.  */
-  if (!ssa_operands_active ())
+  if (!ssa_operands_active (cfun))
     return;
 
   timevar_push (TV_TREE_OPS);
@@ -1244,7 +1240,7 @@  swap_tree_operands (gimple stmt, tree *exp0, tree *exp1)
      positions of these two operands in their respective immediate use
      lists by adjusting their use pointer to point to the new
      operand position.  */
-  if (ssa_operands_active () && op0 != op1)
+  if (ssa_operands_active (cfun) && op0 != op1)
     {
       use_optype_p use0, use1, ptr;
       use0 = use1 = NULL;
diff --git a/gcc/tree-ssa-operands.h b/gcc/tree-ssa-operands.h
index 2d899dd..76a8bd8 100644
--- a/gcc/tree-ssa-operands.h
+++ b/gcc/tree-ssa-operands.h
@@ -114,7 +114,7 @@  extern void debug_immediate_uses_for (tree var);
 extern void dump_decl_set (FILE *, bitmap);
 extern void debug_decl_set (bitmap);
 
-extern bool ssa_operands_active (void);
+extern bool ssa_operands_active (struct function *);
 
 extern bool virtual_operand_p (tree);
 extern void unlink_stmt_vdef (gimple);
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 97a8ba5..1746c8f 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -1157,7 +1157,7 @@  delete_tree_ssa (void)
   fini_ssanames ();
 
   /* We no longer maintain the SSA operand cache at this point.  */
-  if (ssa_operands_active ())
+  if (ssa_operands_active (cfun))
     fini_ssa_operands ();
 
   htab_delete (cfun->gimple_df->default_defs);