tree-optimize.c: New file.
authorRichard Henderson <rth@redhat.com>
Fri, 29 Aug 2003 23:21:13 +0000 (16:21 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Fri, 29 Aug 2003 23:21:13 +0000 (16:21 -0700)
gcc/
        * tree-optimize.c: New file.
        * Makefile.in (OBJS-archive): Add tree-optimize.o.
        (tree-optimize.o): New.
        * c-decl.c (store_parm_decls): Use allocate_struct_function.
        (finish_function): Don't free_after_parsing or free_after_compilation.
        (set_save_expr_context): Move to tree-optimize.c.
        (c_expand_body_1): Use tree_rest_of_compilation.
        * c-lang.c (LANG_HOOKS_RTL_EXPAND_STMT): New.
        * objc/objc-lang.c (LANG_HOOKS_RTL_EXPAND_STMT): New.
        * c-objc-common.c (expand_deferred_fns): Don't emit unused inlines;
        iterate until closure.
        * langhooks-def.h (LANG_HOOKS_RTL_EXPAND_START,
        LANG_HOOKS_RTL_EXPAND_STMT, LANG_HOOKS_RTL_EXPAND_END): New.
        (LANG_HOOKS_RTL_EXPAND_INITIALIZER): New.
        * langhooks.h (struct lang_hooks_for_rtl_expansion): New.
        * toplev.h (tree_rest_of_compilation): Declare it.

gcc/cp/
        * cp-lang.c (LANG_HOOKS_RTL_EXPAND_START): New.
        (LANG_HOOKS_RTL_EXPAND_STMT): New.
        * cp-tree.h (cxx_expand_function_start): Declare.
        * decl.c (start_function): Use allocate_struct_function.
        Move stmts_are_full_exprs_p assertion from expand_body.
        Do not free_after_parsing or free_after_compilation.
        (cxx_push_function_context): Move code to set struct function
        data from genrtl_start_function.
        * optimize.c (optimize_function): Don't inc/dec function_depth.
        * semantics.c (expand_body): Use tree_rest_of_compilation.
        (cxx_expand_function_start): Rename from genrtl_start_function,
        omit bits done by tree_rest_of_compilation.
        (genrtl_finish_function): Remove.
        (clear_decl_rtl): Move to ../tree-optimize.c.

Co-Authored-By: Jason Merrill <jason@redhat.com>
From-SVN: r70933

16 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-decl.c
gcc/c-lang.c
gcc/c-objc-common.c
gcc/cp/ChangeLog
gcc/cp/cp-lang.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/optimize.c
gcc/cp/semantics.c
gcc/langhooks-def.h
gcc/langhooks.h
gcc/objc/objc-lang.c
gcc/toplev.h
gcc/tree-optimize.c [new file with mode: 0644]

index d573615b6e3b3e270810cfe95c47a9aa8afe791b..fdabb62d39d3fd742165688651c89b4458320d43 100644 (file)
@@ -1,3 +1,22 @@
+2003-08-29  Richard Henderson  <rth@redhat.com>
+
+       * tree-optimize.c: New file.
+       * Makefile.in (OBJS-archive): Add tree-optimize.o.
+       (tree-optimize.o): New.
+       * c-decl.c (store_parm_decls): Use allocate_struct_function.
+       (finish_function): Don't free_after_parsing or free_after_compilation.
+       (set_save_expr_context): Move to tree-optimize.c.
+       (c_expand_body_1): Use tree_rest_of_compilation.
+       * c-lang.c (LANG_HOOKS_RTL_EXPAND_STMT): New.
+       * objc/objc-lang.c (LANG_HOOKS_RTL_EXPAND_STMT): New.
+       * c-objc-common.c (expand_deferred_fns): Don't emit unused inlines;
+       iterate until closure.
+       * langhooks-def.h (LANG_HOOKS_RTL_EXPAND_START,
+       LANG_HOOKS_RTL_EXPAND_STMT, LANG_HOOKS_RTL_EXPAND_END): New.
+       (LANG_HOOKS_RTL_EXPAND_INITIALIZER): New.
+       * langhooks.h (struct lang_hooks_for_rtl_expansion): New.
+       * toplev.h (tree_rest_of_compilation): Declare it.
+
 2003-08-29  Richard Henderson  <rth@redhat.com>
 
        * function.h (struct function): Add rtl_inline_init, saved_for_inline.
index 94569eb237adf60a49a88de390f36495162c380c..3ea2c569d748c6be2a1c048245bf823406535c55 100644 (file)
@@ -845,7 +845,7 @@ OBJS-common = \
 
 OBJS-md = $(out_object_file)
 OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) hashtable.o tree-inline.o           \
-  cgraph.o cgraphunit.o
+  tree-optimize.o cgraph.o cgraphunit.o
 
 OBJS = $(OBJS-common) $(out_object_file) $(OBJS-archive)
 
@@ -1466,10 +1466,13 @@ tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) flags.h fu
 tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    $(C_TREE_H) flags.h langhooks.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \
    $(EXPR_H) $(SPLAY_TREE_H) tree-dump.h
-tree-inline.o : tree-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
-   $(RTL_H) $(EXPR_H) flags.h $(PARAMS_H) input.h insn-config.h $(INTEGRATE_H) \
-   $(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) toplev.h langhooks.h \
-   $(C_COMMON_H) tree-inline.h cgraph.h
+tree-inline.o : tree-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(TREE_H) $(RTL_H) $(EXPR_H) flags.h $(PARAMS_H) input.h insn-config.h \
+   $(INTEGRATE_H) $(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) toplev.h \
+   langhooks.h $(C_COMMON_H) tree-inline.h cgraph.h
+tree-optimize.o : tree-optimize.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+   $(TREE_H) toplev.h langhooks.h cgraph.h $(TIMEVAR_H) function.h $(GGC_H)
+
 print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
    $(GGC_H) langhooks.h real.h
 stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
index 51491d283e54ab23da9fd0a68949a59542348e82..eef6e6df7b5d80dd55812b878d2b6a52219c097a 100644 (file)
@@ -6032,7 +6032,7 @@ store_parm_decls (void)
   gen_aux_info_record (fndecl, 1, 0, prototype);
 
   /* Initialize the RTL code for the function.  */
-  init_function_start (fndecl);
+  allocate_struct_function (fndecl);
 
   /* Begin the statement tree for this function.  */
   begin_stmt_tree (&DECL_SAVED_TREE (fndecl));
@@ -6142,11 +6142,8 @@ finish_function (int nested, int can_defer_p)
       && DECL_INLINE (fndecl))
     warning ("no return statement in function returning non-void");
 
-  /* Clear out memory we no longer need.  */
-  free_after_parsing (cfun);
-  /* Since we never call rest_of_compilation, we never clear
-     CFUN.  Do so explicitly.  */
-  free_after_compilation (cfun);
+  /* We're leaving the context of this function, so zap cfun.  It's still in
+     DECL_SAVED_INSNS, and we'll restore it in tree_rest_of_compilation.  */
   cfun = NULL;
 
   if (flag_unit_at_a_time && can_defer_p)
@@ -6239,25 +6236,6 @@ c_expand_deferred_function (tree fndecl)
     }
 }
 
-/* Called to move the SAVE_EXPRs for parameter declarations in a
-   nested function into the nested function.  DATA is really the
-   nested FUNCTION_DECL.  */
-
-static tree
-set_save_expr_context (tree *tp,
-                      int *walk_subtrees,
-                      void *data)
-{
-  if (TREE_CODE (*tp) == SAVE_EXPR && !SAVE_EXPR_CONTEXT (*tp))
-    SAVE_EXPR_CONTEXT (*tp) = (tree) data;
-  /* Do not walk back into the SAVE_EXPR_CONTEXT; that will cause
-     circularity.  */
-  else if (DECL_P (*tp))
-    *walk_subtrees = 0;
-
-  return NULL_TREE;
-}
-
 /* Generate the RTL for the body of FNDECL.  If NESTED_P is nonzero,
    then we are already in the process of generating RTL for another
    function.  If can_defer_p is zero, we won't attempt to defer the
@@ -6266,78 +6244,14 @@ set_save_expr_context (tree *tp,
 static void
 c_expand_body_1 (tree fndecl, int nested_p)
 {
-  timevar_push (TV_EXPAND);
-
   if (nested_p)
     {
       /* Make sure that we will evaluate variable-sized types involved
         in our function's type.  */
       expand_pending_sizes (DECL_LANG_SPECIFIC (fndecl)->pending_sizes);
-      /* Squirrel away our current state.  */
-      push_function_context ();
     }
 
-  /* Initialize the RTL code for the function.  */
-  current_function_decl = fndecl;
-  input_location = DECL_SOURCE_LOCATION (fndecl);
-  init_function_start (fndecl);
-
-  /* This function is being processed in whole-function mode.  */
-  cfun->x_whole_function_mode_p = 1;
-
-  /* Even though we're inside a function body, we still don't want to
-     call expand_expr to calculate the size of a variable-sized array.
-     We haven't necessarily assigned RTL to all variables yet, so it's
-     not safe to try to expand expressions involving them.  */
-  immediate_size_expand = 0;
-  cfun->x_dont_save_pending_sizes_p = 1;
-
-  /* Set up parameters and prepare for return, for the function.  */
-  expand_function_start (fndecl, 0);
-
-  /* If the function has a variably modified type, there may be
-     SAVE_EXPRs in the parameter types.  Their context must be set to
-     refer to this function; they cannot be expanded in the containing
-     function.  */
-  if (decl_function_context (fndecl)
-      && variably_modified_type_p (TREE_TYPE (fndecl)))
-    walk_tree (&TREE_TYPE (fndecl), set_save_expr_context, fndecl,
-              NULL);
-
-  /* If this function is `main', emit a call to `__main'
-     to run global initializers, etc.  */
-  if (DECL_NAME (fndecl)
-      && MAIN_NAME_P (DECL_NAME (fndecl))
-      && DECL_FILE_SCOPE_P (fndecl))
-    expand_main_function ();
-
-  /* Generate the RTL for this function.  */
-  expand_stmt (DECL_SAVED_TREE (fndecl));
-
-  /* We hard-wired immediate_size_expand to zero above.
-     expand_function_end will decrement this variable.  So, we set the
-     variable to one here, so that after the decrement it will remain
-     zero.  */
-  immediate_size_expand = 1;
-
-  /* Allow language dialects to perform special processing.  */
-  if (lang_expand_function_end)
-    (*lang_expand_function_end) ();
-
-  /* Generate rtl for function exit.  */
-  expand_function_end ();
-
-  /* If this is a nested function, protect the local variables in the stack
-     above us from being collected while we're compiling this function.  */
-  if (nested_p)
-    ggc_push_context ();
-
-  /* Run the optimizers and output the assembler code for this function.  */
-  rest_of_compilation (fndecl);
-
-  /* Undo the GC context switch.  */
-  if (nested_p)
-    ggc_pop_context ();
+  tree_rest_of_compilation (fndecl);
 
   /* With just -Wextra, complain only if function returns both with
      and without a value.  */
@@ -6346,46 +6260,6 @@ c_expand_body_1 (tree fndecl, int nested_p)
       && current_function_returns_null)
     warning ("this function may return with or without a value");
 
-  /* If requested, warn about function definitions where the function will
-     return a value (usually of some struct or union type) which itself will
-     take up a lot of stack space.  */
-
-  if (warn_larger_than && !DECL_EXTERNAL (fndecl) && TREE_TYPE (fndecl))
-    {
-      tree ret_type = TREE_TYPE (TREE_TYPE (fndecl));
-
-      if (ret_type && TYPE_SIZE_UNIT (ret_type)
-         && TREE_CODE (TYPE_SIZE_UNIT (ret_type)) == INTEGER_CST
-         && 0 < compare_tree_int (TYPE_SIZE_UNIT (ret_type),
-                                  larger_than_size))
-       {
-          const location_t *locus = &DECL_SOURCE_LOCATION (fndecl);
-         unsigned int size_as_int
-           = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type));
-
-         if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0)
-           warning ("%Hsize of return value of '%D' is %u bytes",
-                     locus, fndecl, size_as_int);
-         else
-           warning ("%Hsize of return value of '%D' is larger than %wd bytes",
-                     locus, fndecl, larger_than_size);
-       }
-    }
-
-  if (DECL_SAVED_INSNS (fndecl) == 0 && ! nested_p
-      && ! flag_inline_trees)
-    {
-      /* Stop pointing to the local nodes about to be freed.
-        But DECL_INITIAL must remain nonzero so we know this
-        was an actual function definition.
-        For a nested function, this is done in c_pop_function_context.
-        If rest_of_compilation set this to 0, leave it 0.  */
-      if (DECL_INITIAL (fndecl) != 0)
-       DECL_INITIAL (fndecl) = error_mark_node;
-
-      DECL_ARGUMENTS (fndecl) = 0;
-    }
-
   if (DECL_STATIC_CONSTRUCTOR (fndecl))
     {
       if (targetm.have_ctors_dtors)
@@ -6403,11 +6277,6 @@ c_expand_body_1 (tree fndecl, int nested_p)
       else
        static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
     }
-
-  if (nested_p)
-    /* Return to the enclosing function.  */
-    pop_function_context ();
-  timevar_pop (TV_EXPAND);
 }
 
 /* Like c_expand_body_1 but only for unnested functions.  */
index 93437a3733d339eb9047fea34e8edaf62e773402..fb1741dea136f0395e5a64db0a35a95a13f776bb 100644 (file)
@@ -90,6 +90,9 @@ enum c_language_kind c_language = clk_c;
 #undef LANG_HOOKS_DECL_UNINIT
 #define LANG_HOOKS_DECL_UNINIT c_decl_uninit
 
+#undef LANG_HOOKS_RTL_EXPAND_STMT
+#define LANG_HOOKS_RTL_EXPAND_STMT expand_stmt
+
 /* Attribute hooks.  */
 #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
 #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table
index b5f263fe35c7c0cc1e18950a1572037fdca61970..16e0cffec32e8946edc0e6cb65e26270ffa1a82f 100644 (file)
@@ -289,20 +289,43 @@ static void
 expand_deferred_fns (void)
 {
   unsigned int i;
+  bool reconsider;
 
-  for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_fns); i++)
+  do
     {
-      tree decl = VARRAY_TREE (deferred_fns, i);
-
-      if (! TREE_ASM_WRITTEN (decl))
+      reconsider = false;
+      for (i = 0; i < VARRAY_ACTIVE_SIZE (deferred_fns); i++)
        {
-         /* For static inline functions, delay the decision whether to
-            emit them or not until wrapup_global_declarations.  */
-         if (! TREE_PUBLIC (decl))
-           DECL_DEFER_OUTPUT (decl) = 1;
+         tree decl = VARRAY_TREE (deferred_fns, i);
+
+         if (TREE_ASM_WRITTEN (decl))
+           continue;
+
+         /* "extern inline" says the symbol exists externally,
+             which means we should *never* expand it locally 
+             unless we're actually inlining it.  */
+         /* ??? Why did we queue these in the first place?  */
+         if (DECL_DECLARED_INLINE_P (decl) && DECL_EXTERNAL (decl))
+           continue;
+             
+         /* With flag_keep_inline_functions, we're emitting everything,
+            so we never need to reconsider.  */
+         if (flag_keep_inline_functions)
+           ;
+         /* Must emit all public functions.  C doesn't have COMDAT
+            functions, so we don't need to check that, like C++.  */
+         else if (TREE_PUBLIC (decl))
+           reconsider = true;
+         /* Must emit if the symbol is referenced.  */
+         else if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
+           reconsider = true;
+         else
+           continue;
+
          c_expand_deferred_function (decl);
        }
     }
+  while (reconsider);
 
   deferred_fns = 0;
 }
index 60c81ab4fad703e5fc5085bedaf5a468335e3e9b..503a3b86e5be5746aee5afa878a8337ae6903863 100644 (file)
@@ -1,3 +1,21 @@
+2003-08-29  Richard Henderson  <rth@redhat.com>
+           Jason Merrill <jason@redhat.com>
+
+       * cp-lang.c (LANG_HOOKS_RTL_EXPAND_START): New.
+       (LANG_HOOKS_RTL_EXPAND_STMT): New.
+       * cp-tree.h (cxx_expand_function_start): Declare.
+       * decl.c (start_function): Use allocate_struct_function.
+       Move stmts_are_full_exprs_p assertion from expand_body.
+       Do not free_after_parsing or free_after_compilation.
+       (cxx_push_function_context): Move code to set struct function
+       data from genrtl_start_function.
+       * optimize.c (optimize_function): Don't inc/dec function_depth.
+       * semantics.c (expand_body): Use tree_rest_of_compilation.
+       (cxx_expand_function_start): Rename from genrtl_start_function,
+       omit bits done by tree_rest_of_compilation.
+       (genrtl_finish_function): Remove.
+       (clear_decl_rtl): Move to ../tree-optimize.c.
+
 2003-08-29  Gabriel Dos Reis  <gdr@integrable-solutions.net>
 
        PR c++/11811
index 8ca93610dab806ec692126632e892e35fde6abea..4d5ed27b3c7ddd1c4e8824ab529b56d85c06770f 100644 (file)
@@ -115,6 +115,11 @@ static void cxx_initialize_diagnostics (diagnostic_context *);
 #undef LANG_HOOKS_FUNCTION_FINAL
 #define LANG_HOOKS_FUNCTION_FINAL cxx_pop_function_context
 
+#undef LANG_HOOKS_RTL_EXPAND_START
+#define LANG_HOOKS_RTL_EXPAND_START cxx_expand_function_start
+#undef LANG_HOOKS_RTL_EXPAND_STMT
+#define LANG_HOOKS_RTL_EXPAND_STMT expand_stmt
+
 /* Attribute hooks.  */
 #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
 #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table
index e1ad9df35e775f1abf358b64328e28fba6e5665d..1a2f06e1ad205edc551e5e8cf3b25bf1a2c6abd4 100644 (file)
@@ -4137,6 +4137,7 @@ extern tree finish_alignof                        (tree);
 extern void finish_decl_cleanup                 (tree, tree);
 extern void finish_eh_cleanup                   (tree);
 extern void expand_body                         (tree);
+extern void cxx_expand_function_start          (void);
 extern tree nullify_returns_r                (tree *, int *, void *);
 extern void do_pushlevel                        (scope_kind);
 extern tree do_poplevel                         (void);
index 0f6d09061b8bd3f62895da3b08e028242c16b926..b4eb0192eb8100dc048f937a3901cba187b75fe2 100644 (file)
@@ -13539,7 +13539,7 @@ start_function (tree declspecs, tree declarator, tree attrs, int flags)
      CFUN set up, and our per-function variables initialized.
      FIXME factor out the non-RTL stuff.  */
   bl = current_binding_level;
-  init_function_start (decl1);
+  allocate_struct_function (decl1);
   current_binding_level = bl;
 
   /* Even though we're inside a function body, we still don't want to
@@ -14084,6 +14084,10 @@ finish_function (int flags)
     }
   poplevel (1, 0, 1);
 
+  /* Statements should always be full-expressions at the outermost set
+     of curly braces for a function.  */
+  my_friendly_assert (stmts_are_full_exprs_p (), 19990831);
+
   /* Set up the named return value optimization, if we can.  Here, we
      eliminate the copy from the nrv into the RESULT_DECL and any cleanup
      for the nrv.  genrtl_start_function and declare_return_variable
@@ -14154,12 +14158,9 @@ finish_function (int flags)
         inline function, as we might never be compiled separately.  */
       && (DECL_INLINE (fndecl) || processing_template_decl))
     warning ("no return statement in function returning non-void");
-    
-  /* Clear out memory we no longer need.  */
-  free_after_parsing (cfun);
-  /* Since we never call rest_of_compilation, we never clear
-     CFUN.  Do so explicitly.  */
-  free_after_compilation (cfun);
+
+  /* We're leaving the context of this function, so zap cfun.  It's still in
+     DECL_SAVED_INSNS, and we'll restore it in tree_rest_of_compilation.  */
   cfun = NULL;
 
   /* If this is an in-class inline definition, we may have to pop the
@@ -14479,6 +14480,31 @@ cxx_push_function_context (struct function * f)
   /* Whenever we start a new function, we destroy temporaries in the
      usual way.  */
   current_stmt_tree ()->stmts_are_full_exprs_p = 1;
+
+  if (f->decl)
+    {
+      tree fn = f->decl;
+
+      current_function_is_thunk = DECL_THUNK_P (fn);
+
+      if (DECL_SAVED_FUNCTION_DATA (fn))
+       {
+         /* If we already parsed this function, and we're just expanding it
+            now, restore saved state.  */
+         *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (fn);
+
+         /* If we decided that we didn't want to inline this function,
+            make sure the back-end knows that.  */
+         if (!current_function_cannot_inline)
+           current_function_cannot_inline = cp_function_chain->cannot_inline;
+
+         /* We don't need the saved data anymore.  Unless this is an inline
+            function; we need the named return value info for
+            cp_copy_res_decl_for_inlining.  */
+         if (! DECL_INLINE (fn))
+           DECL_SAVED_FUNCTION_DATA (fn) = NULL;
+       }
+    }
 }
 
 /* Free the language-specific parts of F, now that we've finished
index 4cb5c695f3433cb6257c277f9979511b2ac48991..8c604e3bf8b179d4e3f808cd80257af46d6118e6 100644 (file)
@@ -49,17 +49,6 @@ optimize_function (tree fn)
 {
   dump_function (TDI_original, fn);
 
-  /* While in this function, we may choose to go off and compile
-     another function.  For example, we might instantiate a function
-     in the hopes of inlining it.  Normally, that wouldn't trigger any
-     actual RTL code-generation -- but it will if the template is
-     actually needed.  (For example, if it's address is taken, or if
-     some other function already refers to the template.)  If
-     code-generation occurs, then garbage collection will occur, so we
-     must protect ourselves, just as we do while building up the body
-     of the function.  */
-  ++function_depth;
-
   if (flag_inline_trees
       /* We do not inline thunks, as (a) the backend tries to optimize
          the call to the thunkee, (b) tree based inlining breaks that
@@ -72,9 +61,6 @@ optimize_function (tree fn)
       dump_function (TDI_inlined, fn);
     }
   
-  /* Undo the call to ggc_push_context above.  */
-  --function_depth;
-  
   dump_function (TDI_optimized, fn);
 }
 
index c38bdd3681a0677d1d8834e5b6c1d2dbd265146c..c9f3675d3072d50fb583da740f658615d469fdd5 100644 (file)
@@ -59,9 +59,7 @@ static void genrtl_try_block (tree);
 static void genrtl_eh_spec_block (tree);
 static void genrtl_handler (tree);
 static void cp_expand_stmt (tree);
-static void genrtl_start_function (tree);
-static void genrtl_finish_function (tree);
-static tree clear_decl_rtl (tree *, int *, void *);
+
 
 /* Finish processing the COND, the SUBSTMT condition for STMT.  */
 
@@ -2863,9 +2861,6 @@ expand_body (tree fn)
   location_t saved_loc;
   tree saved_function;
   
-  if (flag_unit_at_a_time && !cgraph_global_info_ready)
-    abort ();
-
   /* Compute the appropriate object-file linkage for inline
      functions.  */
   if (DECL_DECLARED_INLINE_P (fn))
@@ -2879,61 +2874,35 @@ expand_body (tree fn)
   if (DECL_EXTERNAL (fn))
     return;
 
-  /* Save the current file name and line number.  When we expand the
-     body of the function, we'll set INPUT_LOCATION so that
-     error-messages come out in the right places.  */
+  /* ??? When is this needed?  */
   saved_loc = input_location;
   saved_function = current_function_decl;
-  input_location = DECL_SOURCE_LOCATION (fn);
-  current_function_decl = fn;
 
   timevar_push (TV_INTEGRATION);
-
-  /* Optimize the body of the function before expanding it.  */
   optimize_function (fn);
-
   timevar_pop (TV_INTEGRATION);
-  timevar_push (TV_EXPAND);
-
-  genrtl_start_function (fn);
-  current_function_is_thunk = DECL_THUNK_P (fn);
-
-  /* Expand the body.  */
-  expand_stmt (DECL_SAVED_TREE (fn));
-
-  /* Statements should always be full-expressions at the outermost set
-     of curly braces for a function.  */
-  my_friendly_assert (stmts_are_full_exprs_p (), 19990831);
-
-  /* The outermost statement for a function contains the line number
-     recorded when we finished processing the function.  */
-  input_line = STMT_LINENO (DECL_SAVED_TREE (fn));
-
-  /* Generate code for the function.  */
-  genrtl_finish_function (fn);
 
-  /* If possible, obliterate the body of the function so that it can
-     be garbage collected.  */
-  if (dump_enabled_p (TDI_all))
-    /* Keep the body; we're going to dump it.  */
-    ;
-  else if (DECL_INLINE (fn) && flag_inline_trees)
-    /* We might need the body of this function so that we can expand
-       it inline somewhere else.  */
-    ;
-  else
-    /* We don't need the body; blow it away.  */
-    DECL_SAVED_TREE (fn) = NULL_TREE;
+  tree_rest_of_compilation (fn);
 
-  /* And restore the current source position.  */
   current_function_decl = saved_function;
   input_location = saved_loc;
-  extract_interface_info ();
 
-  timevar_pop (TV_EXPAND);
+  extract_interface_info ();
 
   /* Emit any thunks that should be emitted at the same time as FN.  */
   emit_associated_thunks (fn);
+
+  /* If this function is marked with the constructor attribute, add it
+     to the list of functions to be called along with constructors
+     from static duration objects.  */
+  if (DECL_STATIC_CONSTRUCTOR (fn))
+    static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
+
+  /* If this function is marked with the destructor attribute, add it
+     to the list of functions to be called along with destructors from
+     static duration objects.  */
+  if (DECL_STATIC_DESTRUCTOR (fn))
+    static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
 }
 
 /* Generate RTL for FN.  */
@@ -3062,197 +3031,16 @@ nullify_returns_r (tree* tp, int* walk_subtrees, void* data)
 
 /* Start generating the RTL for FN.  */
 
-static void
-genrtl_start_function (tree fn)
+void
+cxx_expand_function_start (void)
 {
-  /* Tell everybody what function we're processing.  */
-  current_function_decl = fn;
-  /* Get the RTL machinery going for this function.  */
-  init_function_start (fn);
   /* Let everybody know that we're expanding this function, not doing
      semantic analysis.  */
   expanding_p = 1;
 
-  /* Even though we're inside a function body, we still don't want to
-     call expand_expr to calculate the size of a variable-sized array.
-     We haven't necessarily assigned RTL to all variables yet, so it's
-     not safe to try to expand expressions involving them.  */
-  immediate_size_expand = 0;
-  cfun->x_dont_save_pending_sizes_p = 1;
-
-  /* Let the user know we're compiling this function.  */
-  announce_function (fn);
-
-  /* Initialize the per-function data.  */
-  my_friendly_assert (!DECL_PENDING_INLINE_P (fn), 20000911);
-  if (DECL_SAVED_FUNCTION_DATA (fn))
-    {
-      /* If we already parsed this function, and we're just expanding it
-        now, restore saved state.  */
-      *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (fn);
-
-      /* This function is being processed in whole-function mode; we
-        already did semantic analysis.  */
-      cfun->x_whole_function_mode_p = 1;
-
-      /* If we decided that we didn't want to inline this function,
-        make sure the back-end knows that.  */
-      if (!current_function_cannot_inline)
-       current_function_cannot_inline = cp_function_chain->cannot_inline;
-
-      /* We don't need the saved data anymore.  Unless this is an inline
-         function; we need the named return value info for
-         cp_copy_res_decl_for_inlining.  */
-      if (! DECL_INLINE (fn))
-       DECL_SAVED_FUNCTION_DATA (fn) = NULL;
-    }
-
-  /* Keep track of how many functions we're presently expanding.  */
-  ++function_depth;
-
-  /* Create a binding level for the parameters.  */
-  expand_function_start (fn, /*parms_have_cleanups=*/0);
-  /* If this function is `main'.  */
-  if (DECL_MAIN_P (fn))
-    expand_main_function ();
-
   /* Give our named return value the same RTL as our RESULT_DECL.  */
   if (current_function_return_value)
-    COPY_DECL_RTL (DECL_RESULT (fn), current_function_return_value);
-}
-
-/* Finish generating the RTL for FN.  */
-
-static void
-genrtl_finish_function (tree fn)
-{
-  tree t;
-
-#if 0
-  if (write_symbols != NO_DEBUG)
-    {
-      /* Keep this code around in case we later want to control debug info
-        based on whether a type is "used".  (jason 1999-11-11) */
-
-      tree ttype = target_type (fntype);
-      tree parmdecl;
-
-      if (IS_AGGR_TYPE (ttype))
-       /* Let debugger know it should output info for this type.  */
-       note_debug_info_needed (ttype);
-
-      for (parmdecl = DECL_ARGUMENTS (fndecl); parmdecl; parmdecl = TREE_CHAIN (parmdecl))
-       {
-         ttype = target_type (TREE_TYPE (parmdecl));
-         if (IS_AGGR_TYPE (ttype))
-           /* Let debugger know it should output info for this type.  */
-           note_debug_info_needed (ttype);
-       }
-    }
-#endif
-
-  /* Clean house because we will need to reorder insns here.  */
-  do_pending_stack_adjust ();
-
-  /* If we have a named return value, we need to force a return so that
-     the return register is USEd.  */
-  if (DECL_NAME (DECL_RESULT (fn)))
-    emit_jump (return_label);
-
-  /* We hard-wired immediate_size_expand to zero in start_function.
-     Expand_function_end will decrement this variable.  So, we set the
-     variable to one here, so that after the decrement it will remain
-     zero.  */
-  immediate_size_expand = 1;
-
-  /* Generate rtl for function exit.  */
-  expand_function_end ();
-
-  /* If this is a nested function (like a template instantiation that
-     we're compiling in the midst of compiling something else), push a
-     new GC context.  That will keep local variables on the stack from
-     being collected while we're doing the compilation of this
-     function.  */
-  if (function_depth > 1)
-    ggc_push_context ();
-
-  /* There's no need to defer outputting this function any more; we
-     know we want to output it.  */
-  DECL_DEFER_OUTPUT (fn) = 0;
-
-  /* Run the optimizers and output the assembler code for this
-     function.  */
-  rest_of_compilation (fn);
-
-  /* Undo the call to ggc_push_context above.  */
-  if (function_depth > 1)
-    ggc_pop_context ();
-
-#if 0
-  /* Keep this code around in case we later want to control debug info
-     based on whether a type is "used".  (jason 1999-11-11) */
-
-  if (ctype && TREE_ASM_WRITTEN (fn))
-    note_debug_info_needed (ctype);
-#endif
-
-  /* If this function is marked with the constructor attribute, add it
-     to the list of functions to be called along with constructors
-     from static duration objects.  */
-  if (DECL_STATIC_CONSTRUCTOR (fn))
-    static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
-
-  /* If this function is marked with the destructor attribute, add it
-     to the list of functions to be called along with destructors from
-     static duration objects.  */
-  if (DECL_STATIC_DESTRUCTOR (fn))
-    static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
-
-  --function_depth;
-
-  /* In C++, we should never be saving RTL for the function.  */
-  my_friendly_assert (!DECL_SAVED_INSNS (fn), 20010903);
-
-  /* Since we don't need the RTL for this function anymore, stop
-     pointing to it.  That's especially important for LABEL_DECLs,
-     since you can reach all the instructions in the function from the
-     CODE_LABEL stored in the DECL_RTL for the LABEL_DECL.  Walk the
-     BLOCK-tree, clearing DECL_RTL for LABEL_DECLs and non-static
-     local variables.  */
-  walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
-                               clear_decl_rtl,
-                               NULL);
-
-  /* Clear out the RTL for the arguments.  */
-  for (t = DECL_ARGUMENTS (fn); t; t = TREE_CHAIN (t))
-    {
-      SET_DECL_RTL (t, NULL_RTX);
-      DECL_INCOMING_RTL (t) = NULL_RTX;
-    }
-
-  if (!(flag_inline_trees && DECL_INLINE (fn)))
-    /* DECL_INITIAL must remain nonzero so we know this was an
-       actual function definition.  */
-    DECL_INITIAL (fn) = error_mark_node;
-  
-  /* Let the error reporting routines know that we're outside a
-     function.  For a nested function, this value is used in
-     pop_cp_function_context and then reset via pop_function_context.  */
-  current_function_decl = NULL_TREE;
-}
-
-/* Clear out the DECL_RTL for the non-static variables in BLOCK and
-   its sub-blocks.  */
-
-static tree
-clear_decl_rtl (tree* tp, 
-                int* walk_subtrees ATTRIBUTE_UNUSED , 
-                void* data ATTRIBUTE_UNUSED )
-{
-  if (nonstatic_local_decl_p (*tp)) 
-    SET_DECL_RTL (*tp, NULL_RTX);
-    
-  return NULL_TREE;
+    COPY_DECL_RTL (DECL_RESULT (cfun->decl), current_function_return_value);
 }
 
 /* Perform initialization related to this module.  */
index 56c24c79739df614817492b6c5147f21df22a476..ee30749f536ca358fccf90231f75dfb4deaa308d 100644 (file)
@@ -123,6 +123,10 @@ extern void lhd_initialize_diagnostics (struct diagnostic_context *);
 #define LANG_HOOKS_FUNCTION_ENTER_NESTED lhd_do_nothing_f
 #define LANG_HOOKS_FUNCTION_LEAVE_NESTED lhd_do_nothing_f
 
+#define LANG_HOOKS_RTL_EXPAND_START    lhd_do_nothing
+#define LANG_HOOKS_RTL_EXPAND_STMT     (void *) abort
+#define LANG_HOOKS_RTL_EXPAND_END      lhd_do_nothing
+
 /* Attribute hooks.  */
 #define LANG_HOOKS_ATTRIBUTE_TABLE             NULL
 #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE      NULL
@@ -186,6 +190,12 @@ extern void lhd_initialize_diagnostics (struct diagnostic_context *);
   LANG_HOOKS_FUNCTION_LEAVE_NESTED             \
 }
 
+#define LANG_HOOKS_RTL_EXPAND_INITIALIZER {    \
+  LANG_HOOKS_RTL_EXPAND_START,                 \
+  LANG_HOOKS_RTL_EXPAND_STMT,                  \
+  LANG_HOOKS_RTL_EXPAND_END                    \
+}
+
 /* Tree dump hooks.  */
 extern bool lhd_tree_dump_dump_tree (void *, tree);
 extern int lhd_tree_dump_type_quals (tree);
@@ -289,7 +299,8 @@ extern int lhd_tree_dump_type_quals (tree);
   LANG_HOOKS_CALLGRAPH_INITIALIZER, \
   LANG_HOOKS_TREE_DUMP_INITIALIZER, \
   LANG_HOOKS_DECLS, \
-  LANG_HOOKS_FOR_TYPES_INITIALIZER \
+  LANG_HOOKS_FOR_TYPES_INITIALIZER, \
+  LANG_HOOKS_RTL_EXPAND_INITIALIZER \
 }
 
 #endif /* GCC_LANG_HOOKS_DEF_H */
index 7bcd4353734047b76b53eefafc19b0f9d972833a..109dfa1a818641f48b043fb2885e9229acdf448c 100644 (file)
@@ -77,6 +77,19 @@ struct lang_hooks_for_functions
   void (*leave_nested) (struct function *);
 };
 
+/* Lang hooks for rtl code generation.  */
+struct lang_hooks_for_rtl_expansion
+{
+  /* Called after expand_function_start, but before expanding the body.  */
+  void (*start) (void);
+
+  /* Called to expand each statement.  */
+  void (*stmt) (tree);
+
+  /* Called after expanding the body but before expand_function_end.  */
+  void (*end) (void);
+};
+
 /* The following hooks are used by tree-dump.c.  */
 
 struct lang_hooks_for_tree_dump
@@ -387,6 +400,8 @@ struct lang_hooks
 
   struct lang_hooks_for_types types;
 
+  struct lang_hooks_for_rtl_expansion rtl_expand;
+
   /* Whenever you add entries here, make sure you adjust langhooks-def.h
      and langhooks.c accordingly.  */
 };
index 7a330ce3b61249eb32152fec7e7ab0213e944de3..3f70122302c4f157dad8ec3c8cbaec87e1e56b5b 100644 (file)
@@ -87,6 +87,9 @@ enum c_language_kind c_language = clk_objc;
 #undef LANG_HOOKS_FUNCTION_LEAVE_NESTED
 #define LANG_HOOKS_FUNCTION_LEAVE_NESTED c_pop_function_context
 
+#undef LANG_HOOKS_RTL_EXPAND_STMT
+#define LANG_HOOKS_RTL_EXPAND_STMT expand_stmt
+
 /* Attribute hooks.  */
 #undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
 #define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE c_common_attribute_table
index 5adab615f91bb55d491c5044d712c4e3bada3e79..3ebd8e493f2ed39ce9dcd48d4efb58b43cef209d 100644 (file)
@@ -66,6 +66,7 @@ extern void inform (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
 extern void rest_of_decl_compilation (tree, const char *, int, int);
 extern void rest_of_type_compilation (tree, int);
 extern void rest_of_compilation (tree);
+extern void tree_rest_of_compilation (tree);
 
 extern void announce_function (tree);
 
diff --git a/gcc/tree-optimize.c b/gcc/tree-optimize.c
new file mode 100644 (file)
index 0000000..e5bea3e
--- /dev/null
@@ -0,0 +1,250 @@
+/* Control and data flow functions for trees.
+   Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "toplev.h"
+#include "tree.h"
+#include "tree-inline.h"
+#include "flags.h"
+#include "langhooks.h"
+#include "cgraph.h"
+#include "timevar.h"
+#include "tm.h"
+#include "function.h"
+#include "ggc.h"
+
+
+/* Called to move the SAVE_EXPRs for parameter declarations in a
+   nested function into the nested function.  DATA is really the
+   nested FUNCTION_DECL.  */
+
+static tree
+set_save_expr_context (tree *tp,
+                      int *walk_subtrees,
+                      void *data)
+{
+  if (TREE_CODE (*tp) == SAVE_EXPR && !SAVE_EXPR_CONTEXT (*tp))
+    SAVE_EXPR_CONTEXT (*tp) = (tree) data;
+  /* Do not walk back into the SAVE_EXPR_CONTEXT; that will cause
+     circularity.  */
+  else if (DECL_P (*tp))
+    *walk_subtrees = 0;
+
+  return NULL;
+}
+
+/* Clear out the DECL_RTL for the non-static local variables in BLOCK and
+   its sub-blocks.  DATA is the decl of the function being processed.  */
+
+static tree
+clear_decl_rtl (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
+{
+  bool nonstatic_p, local_p;
+  tree t = *tp;
+
+  switch (TREE_CODE (t))
+    {
+    case VAR_DECL:
+      nonstatic_p = !TREE_STATIC (t) && !DECL_EXTERNAL (t);
+      local_p = DECL_CONTEXT (t) == data;
+      break;
+
+    case PARM_DECL:
+    case LABEL_DECL:
+      nonstatic_p = true;
+      local_p = DECL_CONTEXT (t) == data;
+      break;
+
+    case RESULT_DECL:
+      nonstatic_p = local_p = true;
+      break;
+
+    default:
+      nonstatic_p = local_p = false;
+      break;
+    }
+
+  if (nonstatic_p && local_p)
+    SET_DECL_RTL (t, NULL);
+
+  return NULL;
+}
+
+/* For functions-as-trees languages, this performs all optimization and
+   compilation for FNDECL.  */
+
+void
+tree_rest_of_compilation (tree fndecl)
+{
+  static int nesting = -1;
+
+  timevar_push (TV_EXPAND);
+
+  ++nesting;
+
+  if (flag_unit_at_a_time && !cgraph_global_info_ready)
+    abort ();
+
+  if (nesting > 0)
+    /* Squirrel away our current state.  */
+    push_function_context ();
+
+  /* Initialize the RTL code for the function.  */
+  current_function_decl = fndecl;
+  input_location = DECL_SOURCE_LOCATION (fndecl);
+  init_function_start (fndecl);
+
+  /* This function is being processed in whole-function mode.  */
+  cfun->x_whole_function_mode_p = 1;
+
+  /* Even though we're inside a function body, we still don't want to
+     call expand_expr to calculate the size of a variable-sized array.
+     We haven't necessarily assigned RTL to all variables yet, so it's
+     not safe to try to expand expressions involving them.  */
+  immediate_size_expand = 0;
+  cfun->x_dont_save_pending_sizes_p = 1;
+
+  /* If the function has a variably modified type, there may be
+     SAVE_EXPRs in the parameter types.  Their context must be set to
+     refer to this function; they cannot be expanded in the containing
+     function.  */
+  if (decl_function_context (fndecl)
+      && variably_modified_type_p (TREE_TYPE (fndecl)))
+    walk_tree (&TREE_TYPE (fndecl), set_save_expr_context, fndecl,
+              NULL);
+
+  /* Set up parameters and prepare for return, for the function.  */
+  expand_function_start (fndecl, 0);
+
+  /* Allow language dialects to perform special processing.  */
+  (*lang_hooks.rtl_expand.start) ();
+
+  /* If this function is `main', emit a call to `__main'
+     to run global initializers, etc.  */
+  if (DECL_NAME (fndecl)
+      && MAIN_NAME_P (DECL_NAME (fndecl))
+      && DECL_FILE_SCOPE_P (fndecl))
+    expand_main_function ();
+
+  /* Generate the RTL for this function.  */
+  (*lang_hooks.rtl_expand.stmt) (DECL_SAVED_TREE (fndecl));
+
+  /* We hard-wired immediate_size_expand to zero above.
+     expand_function_end will decrement this variable.  So, we set the
+     variable to one here, so that after the decrement it will remain
+     zero.  */
+  immediate_size_expand = 1;
+
+  /* Allow language dialects to perform special processing.  */
+  (*lang_hooks.rtl_expand.end) ();
+
+  /* Generate rtl for function exit.  */
+  expand_function_end ();
+
+  /* If this is a nested function, protect the local variables in the stack
+     above us from being collected while we're compiling this function.  */
+  if (nesting > 0)
+    ggc_push_context ();
+
+  /* There's no need to defer outputting this function any more; we
+     know we want to output it.  */
+  DECL_DEFER_OUTPUT (fndecl) = 0;
+
+  /* Run the optimizers and output the assembler code for this function.  */
+  rest_of_compilation (fndecl);
+
+  /* Undo the GC context switch.  */
+  if (nesting > 0)
+    ggc_pop_context ();
+
+  /* If requested, warn about function definitions where the function will
+     return a value (usually of some struct or union type) which itself will
+     take up a lot of stack space.  */
+  if (warn_larger_than && !DECL_EXTERNAL (fndecl) && TREE_TYPE (fndecl))
+    {
+      tree ret_type = TREE_TYPE (TREE_TYPE (fndecl));
+
+      if (ret_type && TYPE_SIZE_UNIT (ret_type)
+         && TREE_CODE (TYPE_SIZE_UNIT (ret_type)) == INTEGER_CST
+         && 0 < compare_tree_int (TYPE_SIZE_UNIT (ret_type),
+                                  larger_than_size))
+       {
+          const location_t *locus = &DECL_SOURCE_LOCATION (fndecl);
+         unsigned int size_as_int
+           = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type));
+
+         if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0)
+           warning ("%Hsize of return value of '%D' is %u bytes",
+                     locus, fndecl, size_as_int);
+         else
+           warning ("%Hsize of return value of '%D' is larger than %wd bytes",
+                     locus, fndecl, larger_than_size);
+       }
+    }
+
+  /* ??? Looks like some of this could be combined.  */
+
+  /* If possible, obliterate the body of the function so that it can
+     be garbage collected.  */
+  if (dump_enabled_p (TDI_all))
+    /* Keep the body; we're going to dump it.  */
+    ;
+  else if (DECL_INLINE (fndecl) && flag_inline_trees)
+    /* We might need the body of this function so that we can expand
+       it inline somewhere else.  */
+    ;
+  else
+    /* We don't need the body; blow it away.  */
+    DECL_SAVED_TREE (fndecl) = NULL;
+
+  /* Since we don't need the RTL for this function anymore, stop pointing to
+     it.  That's especially important for LABEL_DECLs, since you can reach all
+     the instructions in the function from the CODE_LABEL stored in the
+     DECL_RTL for the LABEL_DECL.  Walk the BLOCK-tree, clearing DECL_RTL for
+     LABEL_DECLs and non-static local variables.  Note that we must check the
+     context of the variables, otherwise processing a nested function can kill
+     the rtl of a variable from an outer function.  */
+  walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
+                               clear_decl_rtl,
+                               fndecl);
+
+  if (DECL_SAVED_INSNS (fndecl) == 0 && ! nesting && ! flag_inline_trees)
+    {
+      /* Stop pointing to the local nodes about to be freed.
+        But DECL_INITIAL must remain nonzero so we know this
+        was an actual function definition.
+        For a nested function, this is done in c_pop_function_context.
+        If rest_of_compilation set this to 0, leave it 0.  */
+      if (DECL_INITIAL (fndecl) != 0)
+       DECL_INITIAL (fndecl) = error_mark_node;
+
+      DECL_ARGUMENTS (fndecl) = 0;
+    }
+
+  if (nesting > 0)
+    /* Return to the enclosing function.  */
+    pop_function_context ();
+
+  --nesting;
+
+  timevar_pop (TV_EXPAND);
+}