optimize.c revision 90075
190075Sobrien/* Perform optimizations on tree structure.
290075Sobrien   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
390075Sobrien   Written by Mark Michell (mark@codesourcery.com).
490075Sobrien
590075SobrienThis file is part of GNU CC.
690075Sobrien
790075SobrienGNU CC is free software; you can redistribute it and/or modify it
890075Sobrienunder the terms of the GNU General Public License as published by
990075Sobrienthe Free Software Foundation; either version 2, or (at your option)
1090075Sobrienany later version.
1190075Sobrien
1290075SobrienGNU CC is distributed in the hope that it will be useful, but
1390075SobrienWITHOUT ANY WARRANTY; without even the implied warranty of
1490075SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1590075SobrienGeneral Public License for more details.
1690075Sobrien
1790075SobrienYou should have received a copy of the GNU General Public License
1890075Sobrienalong with GNU CC; see the file COPYING.  If not, write to the Free
1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2090075Sobrien02111-1307, USA.  */
2190075Sobrien
2290075Sobrien#include "config.h"
2390075Sobrien#include "system.h"
2490075Sobrien#include "tree.h"
2590075Sobrien#include "cp-tree.h"
2690075Sobrien#include "rtl.h"
2790075Sobrien#include "insn-config.h"
2890075Sobrien#include "input.h"
2990075Sobrien#include "integrate.h"
3090075Sobrien#include "toplev.h"
3190075Sobrien#include "varray.h"
3290075Sobrien#include "ggc.h"
3390075Sobrien#include "params.h"
3490075Sobrien#include "hashtab.h"
3590075Sobrien#include "debug.h"
3690075Sobrien#include "tree-inline.h"
3790075Sobrien
3890075Sobrien/* Prototypes.  */
3990075Sobrien
4090075Sobrienstatic tree calls_setjmp_r PARAMS ((tree *, int *, void *));
4190075Sobrienstatic void update_cloned_parm PARAMS ((tree, tree));
4290075Sobrienstatic void dump_function PARAMS ((enum tree_dump_index, tree));
4390075Sobrien
4490075Sobrien/* Optimize the body of FN. */
4590075Sobrien
4690075Sobrienvoid
4790075Sobrienoptimize_function (fn)
4890075Sobrien     tree fn;
4990075Sobrien{
5090075Sobrien  dump_function (TDI_original, fn);
5190075Sobrien
5290075Sobrien  /* While in this function, we may choose to go off and compile
5390075Sobrien     another function.  For example, we might instantiate a function
5490075Sobrien     in the hopes of inlining it.  Normally, that wouldn't trigger any
5590075Sobrien     actual RTL code-generation -- but it will if the template is
5690075Sobrien     actually needed.  (For example, if it's address is taken, or if
5790075Sobrien     some other function already refers to the template.)  If
5890075Sobrien     code-generation occurs, then garbage collection will occur, so we
5990075Sobrien     must protect ourselves, just as we do while building up the body
6090075Sobrien     of the function.  */
6190075Sobrien  ++function_depth;
6290075Sobrien
6390075Sobrien  if (flag_inline_trees
6490075Sobrien      /* We do not inline thunks, as (a) the backend tries to optimize
6590075Sobrien         the call to the thunkee, (b) tree based inlining breaks that
6690075Sobrien         optimization, (c) virtual functions are rarely inlineable,
6790075Sobrien         and (d) ASM_OUTPUT_MI_THUNK is there to DTRT anyway.  */
6890075Sobrien      && !DECL_THUNK_P (fn))
6990075Sobrien    {
7090075Sobrien      optimize_inline_calls (fn);
7190075Sobrien
7290075Sobrien      dump_function (TDI_inlined, fn);
7390075Sobrien    }
7490075Sobrien
7590075Sobrien  /* Undo the call to ggc_push_context above.  */
7690075Sobrien  --function_depth;
7790075Sobrien
7890075Sobrien  dump_function (TDI_optimized, fn);
7990075Sobrien}
8090075Sobrien
8190075Sobrien/* Called from calls_setjmp_p via walk_tree.  */
8290075Sobrien
8390075Sobrienstatic tree
8490075Sobriencalls_setjmp_r (tp, walk_subtrees, data)
8590075Sobrien     tree *tp;
8690075Sobrien     int *walk_subtrees ATTRIBUTE_UNUSED;
8790075Sobrien     void *data ATTRIBUTE_UNUSED;
8890075Sobrien{
8990075Sobrien  /* We're only interested in FUNCTION_DECLS.  */
9090075Sobrien  if (TREE_CODE (*tp) != FUNCTION_DECL)
9190075Sobrien    return NULL_TREE;
9290075Sobrien
9390075Sobrien  return setjmp_call_p (*tp) ? *tp : NULL_TREE;
9490075Sobrien}
9590075Sobrien
9690075Sobrien/* Returns non-zero if FN calls `setjmp' or some other function that
9790075Sobrien   can return more than once.  This function is conservative; it may
9890075Sobrien   occasionally return a non-zero value even when FN does not actually
9990075Sobrien   call `setjmp'.  */
10090075Sobrien
10190075Sobrienint
10290075Sobriencalls_setjmp_p (fn)
10390075Sobrien     tree fn;
10490075Sobrien{
10590075Sobrien  return walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
10690075Sobrien				       calls_setjmp_r,
10790075Sobrien				       NULL) != NULL_TREE;
10890075Sobrien}
10990075Sobrien
11090075Sobrien/* CLONED_PARM is a copy of CLONE, generated for a cloned constructor
11190075Sobrien   or destructor.  Update it to ensure that the source-position for
11290075Sobrien   the cloned parameter matches that for the original, and that the
11390075Sobrien   debugging generation code will be able to find the original PARM.  */
11490075Sobrien
11590075Sobrienstatic void
11690075Sobrienupdate_cloned_parm (parm, cloned_parm)
11790075Sobrien     tree parm;
11890075Sobrien     tree cloned_parm;
11990075Sobrien{
12090075Sobrien  DECL_ABSTRACT_ORIGIN (cloned_parm) = parm;
12190075Sobrien
12290075Sobrien  /* We may have taken its address. */
12390075Sobrien  TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm);
12490075Sobrien
12590075Sobrien  /* The definition might have different constness. */
12690075Sobrien  TREE_READONLY (cloned_parm) = TREE_READONLY (parm);
12790075Sobrien
12890075Sobrien  TREE_USED (cloned_parm) = TREE_USED (parm);
12990075Sobrien
13090075Sobrien  /* The name may have changed from the declaration. */
13190075Sobrien  DECL_NAME (cloned_parm) = DECL_NAME (parm);
13290075Sobrien  DECL_SOURCE_FILE (cloned_parm) = DECL_SOURCE_FILE (parm);
13390075Sobrien  DECL_SOURCE_LINE (cloned_parm) = DECL_SOURCE_LINE (parm);
13490075Sobrien}
13590075Sobrien
13690075Sobrien/* FN is a function that has a complete body.  Clone the body as
13790075Sobrien   necessary.  Returns non-zero if there's no longer any need to
13890075Sobrien   process the main body.  */
13990075Sobrien
14090075Sobrienint
14190075Sobrienmaybe_clone_body (fn)
14290075Sobrien     tree fn;
14390075Sobrien{
14490075Sobrien  tree clone;
14590075Sobrien  int first = 1;
14690075Sobrien
14790075Sobrien  /* We only clone constructors and destructors.  */
14890075Sobrien  if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
14990075Sobrien      && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
15090075Sobrien    return 0;
15190075Sobrien
15290075Sobrien  /* Emit the DWARF1 abstract instance.  */
15390075Sobrien  (*debug_hooks->deferred_inline_function) (fn);
15490075Sobrien
15590075Sobrien  /* We know that any clones immediately follow FN in the TYPE_METHODS
15690075Sobrien     list.  */
15790075Sobrien  for (clone = TREE_CHAIN (fn);
15890075Sobrien       clone && DECL_CLONED_FUNCTION_P (clone);
15990075Sobrien       clone = TREE_CHAIN (clone), first = 0)
16090075Sobrien    {
16190075Sobrien      tree parm;
16290075Sobrien      tree clone_parm;
16390075Sobrien      int parmno;
16490075Sobrien      splay_tree decl_map;
16590075Sobrien
16690075Sobrien      /* Update CLONE's source position information to match FN's.  */
16790075Sobrien      DECL_SOURCE_FILE (clone) = DECL_SOURCE_FILE (fn);
16890075Sobrien      DECL_SOURCE_LINE (clone) = DECL_SOURCE_LINE (fn);
16990075Sobrien      DECL_INLINE (clone) = DECL_INLINE (fn);
17090075Sobrien      DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn);
17190075Sobrien      DECL_COMDAT (clone) = DECL_COMDAT (fn);
17290075Sobrien      DECL_WEAK (clone) = DECL_WEAK (fn);
17390075Sobrien      DECL_ONE_ONLY (clone) = DECL_ONE_ONLY (fn);
17490075Sobrien      DECL_SECTION_NAME (clone) = DECL_SECTION_NAME (fn);
17590075Sobrien      DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn);
17690075Sobrien      DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn);
17790075Sobrien      DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn);
17890075Sobrien      DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
17990075Sobrien      TREE_PUBLIC (clone) = TREE_PUBLIC (fn);
18090075Sobrien
18190075Sobrien      /* Adjust the parameter names and locations. */
18290075Sobrien      parm = DECL_ARGUMENTS (fn);
18390075Sobrien      clone_parm = DECL_ARGUMENTS (clone);
18490075Sobrien      /* Update the `this' parameter, which is always first.  */
18590075Sobrien      update_cloned_parm (parm, clone_parm);
18690075Sobrien      parm = TREE_CHAIN (parm);
18790075Sobrien      clone_parm = TREE_CHAIN (clone_parm);
18890075Sobrien      if (DECL_HAS_IN_CHARGE_PARM_P (fn))
18990075Sobrien	parm = TREE_CHAIN (parm);
19090075Sobrien      if (DECL_HAS_VTT_PARM_P (fn))
19190075Sobrien	parm = TREE_CHAIN (parm);
19290075Sobrien      if (DECL_HAS_VTT_PARM_P (clone))
19390075Sobrien	clone_parm = TREE_CHAIN (clone_parm);
19490075Sobrien      for (; parm;
19590075Sobrien	   parm = TREE_CHAIN (parm), clone_parm = TREE_CHAIN (clone_parm))
19690075Sobrien	{
19790075Sobrien	  /* Update this parameter.  */
19890075Sobrien	  update_cloned_parm (parm, clone_parm);
19990075Sobrien	  /* We should only give unused information for one clone. */
20090075Sobrien	  if (!first)
20190075Sobrien	    TREE_USED (clone_parm) = 1;
20290075Sobrien	}
20390075Sobrien
20490075Sobrien      /* Start processing the function.  */
20590075Sobrien      push_to_top_level ();
20690075Sobrien      start_function (NULL_TREE, clone, NULL_TREE, SF_PRE_PARSED);
20790075Sobrien
20890075Sobrien      /* Remap the parameters.  */
20990075Sobrien      decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
21090075Sobrien      for (parmno = 0,
21190075Sobrien	     parm = DECL_ARGUMENTS (fn),
21290075Sobrien	     clone_parm = DECL_ARGUMENTS (clone);
21390075Sobrien	   parm;
21490075Sobrien	   ++parmno,
21590075Sobrien	     parm = TREE_CHAIN (parm))
21690075Sobrien	{
21790075Sobrien	  /* Map the in-charge parameter to an appropriate constant.  */
21890075Sobrien	  if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1)
21990075Sobrien	    {
22090075Sobrien	      tree in_charge;
22190075Sobrien	      in_charge = in_charge_arg_for_name (DECL_NAME (clone));
22290075Sobrien	      splay_tree_insert (decl_map,
22390075Sobrien				 (splay_tree_key) parm,
22490075Sobrien				 (splay_tree_value) in_charge);
22590075Sobrien	    }
22690075Sobrien	  else if (DECL_ARTIFICIAL (parm)
22790075Sobrien		   && DECL_NAME (parm) == vtt_parm_identifier)
22890075Sobrien	    {
22990075Sobrien	      /* For a subobject constructor or destructor, the next
23090075Sobrien		 argument is the VTT parameter.  Remap the VTT_PARM
23190075Sobrien		 from the CLONE to this parameter.  */
23290075Sobrien	      if (DECL_HAS_VTT_PARM_P (clone))
23390075Sobrien		{
23490075Sobrien		  DECL_ABSTRACT_ORIGIN (clone_parm) = parm;
23590075Sobrien		  splay_tree_insert (decl_map,
23690075Sobrien				     (splay_tree_key) parm,
23790075Sobrien				     (splay_tree_value) clone_parm);
23890075Sobrien		  clone_parm = TREE_CHAIN (clone_parm);
23990075Sobrien		}
24090075Sobrien	      /* Otherwise, map the VTT parameter to `NULL'.  */
24190075Sobrien	      else
24290075Sobrien		{
24390075Sobrien		  splay_tree_insert (decl_map,
24490075Sobrien				     (splay_tree_key) parm,
24590075Sobrien				     (splay_tree_value) null_pointer_node);
24690075Sobrien		}
24790075Sobrien	    }
24890075Sobrien	  /* Map other parameters to their equivalents in the cloned
24990075Sobrien	     function.  */
25090075Sobrien	  else
25190075Sobrien	    {
25290075Sobrien	      splay_tree_insert (decl_map,
25390075Sobrien				 (splay_tree_key) parm,
25490075Sobrien				 (splay_tree_value) clone_parm);
25590075Sobrien	      clone_parm = TREE_CHAIN (clone_parm);
25690075Sobrien	    }
25790075Sobrien	}
25890075Sobrien
25990075Sobrien      /* Clone the body.  */
26090075Sobrien      clone_body (clone, fn, decl_map);
26190075Sobrien
26290075Sobrien      /* There are as many statements in the clone as in the
26390075Sobrien	 original.  */
26490075Sobrien      DECL_NUM_STMTS (clone) = DECL_NUM_STMTS (fn);
26590075Sobrien
26690075Sobrien      /* Clean up.  */
26790075Sobrien      splay_tree_delete (decl_map);
26890075Sobrien
26990075Sobrien      /* Now, expand this function into RTL, if appropriate.  */
27090075Sobrien      finish_function (0);
27190075Sobrien      BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
27290075Sobrien      expand_body (clone);
27390075Sobrien      pop_from_top_level ();
27490075Sobrien    }
27590075Sobrien
27690075Sobrien  /* We don't need to process the original function any further.  */
27790075Sobrien  return 1;
27890075Sobrien}
27990075Sobrien
28090075Sobrien/* Dump FUNCTION_DECL FN as tree dump PHASE. */
28190075Sobrien
28290075Sobrienstatic void
28390075Sobriendump_function (phase, fn)
28490075Sobrien     enum tree_dump_index phase;
28590075Sobrien     tree fn;
28690075Sobrien{
28790075Sobrien  FILE *stream;
28890075Sobrien  int flags;
28990075Sobrien
29090075Sobrien  stream = dump_begin (phase, &flags);
29190075Sobrien  if (stream)
29290075Sobrien    {
29390075Sobrien      fprintf (stream, "\n;; Function %s",
29490075Sobrien	       decl_as_string (fn, TFF_DECL_SPECIFIERS));
29590075Sobrien      fprintf (stream, " (%s)\n",
29690075Sobrien	       decl_as_string (DECL_ASSEMBLER_NAME (fn), 0));
29790075Sobrien      fprintf (stream, ";; enabled by -%s\n", dump_flag_name (phase));
29890075Sobrien      fprintf (stream, "\n");
29990075Sobrien
30090075Sobrien      dump_node (fn, TDF_SLIM | flags, stream);
30190075Sobrien      dump_end (phase, stream);
30290075Sobrien    }
30390075Sobrien}
304