[incremental] Patch: FYI: cleanups; initial success

Tom Tromey tromey@redhat.com
Sat Sep 8 00:20:00 GMT 2007


I'm checking this in on the incremental-compiler branch.

This is a few random cleanups.  When processing a file after the first
compilation has finished, various modules may not have cleaned up
after themselves.  This is particularly true with the somewhat odd
approach of fork()ing before code generation -- a module might clean
up but the cleanup may only occur in the child.

Parts of this patch are a stopgap.  Later I plan to clean a few of
these things up a bit, since the current approach is hard to reason
about, and because multi-threading will require more anyhow.  For the
front end I think I will split the init langhook into two, one for the
compiler as a whole and one for each compilation (or maybe move stuff
into parse_file -- haven't decided).  For other modules, we'll have to
see -- abstractly I'd like to completely separate the front end from
the middle end: no more calling debug hooks from the FE, perhaps have
cgraph understand that state is per-thread ("per compilation job").
However, this may be too hard.

With this patch I can:

   gcc --server
   export GCCSERVER=t
   make

on a real-world project (zenity, from Gnome).  (There are caveats: -g
still doesn't work; the link step fails since I haven't fixed gcc.c
for this yet; there is a severe code-gen bug.)

This takes about half the compilation time of an ordinary, server-less
'make'; this is consistent with the --combine results.

Next I plan to fix the codegen problem and the -g problem.  I want to
have something demo-able, then I plan to do a round of cleanups.

Tom

ChangeLog:
2007-09-07  Tom Tromey  <tromey@redhat.com>

	* c-pragma.c (init_pragma): Free pragma vector if already
	allocated.
	* c-lang.c (LANG_HOOKS_CLEAR_BINDING_STACK): Define.
	* c-tree.h (c_clear_binding_stack): Declare.
	* c-decl.c (c_init_decl_processing): Only initialize some things
	once.
	(c_clear_binding_stack): New function.
	(c_write_global_declarations): Move code to
	c_clear_binding_stack.
	* dwarf2out.c (dwarf2out_init): Initialize more globals.
	* server.c (server_main_loop): Print server pid.
	* cgraphunit.c (first_analyzed, first_analyzed_var, counter): Move
	out of function scope.
	(cgraph_unit_reset): Reset them.
	* toplev.c (compile_file): Return bool.
	(do_compile): Exit child process in server mode.
	(toplev_server_mode): New function.

Index: toplev.c
===================================================================
--- toplev.c	(revision 128210)
+++ toplev.c	(working copy)
@@ -111,7 +111,7 @@
 
 static void crash_signal (int) ATTRIBUTE_NORETURN;
 static void setup_core_dumping (void);
-static void compile_file (void);
+static bool compile_file (void);
 
 /* Nonzero to dump debug info whilst parsing (-dy option).  */
 static int set_yydebug;
@@ -1031,9 +1031,10 @@
 }
 
 /* Compile an entire translation unit.  Write a file of assembly
-   output and various debugging dumps.  */
+   output and various debugging dumps.  Returns true if the caller
+   should exit after cleanup.  This is only valid in server mode.  */
 
-static void
+static bool
 compile_file (void)
 {
   /* Initialize yet another pass.  */
@@ -1057,18 +1058,15 @@
   timevar_pop (TV_PARSE);
 
   if (flag_syntax_only)
-    return;
+    return false;
 
   if (server_mode && server_start_back_end ())
-    return;
+    return false;
 
   lang_hooks.decls.final_write_globals ();
 
   if (errorcount || sorrycount)
-    {
-      /* FIXME: server mode... */
-      return;
-    }
+    return true;
 
   varpool_assemble_pending_decls ();
   finish_aliases_2 ();
@@ -1124,13 +1122,7 @@
      assembly file after this point.  */
   targetm.asm_out.file_end ();
 
-  /* FIXME: this is a bit lame, but our caller doesn't know if we
-     forked.  */
-  if (server_mode)
-    {
-      finalize ();
-      exit (0);
-    }
+  return true;
 }
 
 /* Parse a -d... command line switch.  */
@@ -2161,6 +2153,8 @@
   /* Don't do any more if an error has already occurred.  */
   if (!errorcount)
     {
+      bool should_exit = false;
+
       /* This must be run always, because it is needed to compute the FP
 	 predefined macros, such as __LDBL_MAX__, for targets using non
 	 default FP formats.  */
@@ -2172,9 +2166,16 @@
 
       /* Language-dependent initialization.  Returns true on success.  */
       if (lang_dependent_init (main_input_filename))
-	compile_file ();
+	should_exit = compile_file ();
 
       finalize ();
+
+      if (should_exit && server_mode)
+	{
+	  /* We forked in compile_file, and this is the child process.
+	     The compile is done, so exit.  */
+	  exit (0);
+	}
     }
 
   /* Stop timing and print the times.  */
Index: cgraphunit.c
===================================================================
--- cgraphunit.c	(revision 128210)
+++ cgraphunit.c	(working copy)
@@ -170,11 +170,20 @@
 static GTY (()) tree static_ctors;
 static GTY (()) tree static_dtors;
 
+/* Keep track of already processed nodes when called multiple times
+   for intermodule optimization.  */
+static struct cgraph_node *first_analyzed;
+static struct varpool_node *first_analyzed_var;
+static int counter = 0;
+
 void
 cgraph_unit_reset (void)
 {
   static_ctors = NULL_TREE;
   static_dtors = NULL_TREE;
+  first_analyzed = NULL;
+  first_analyzed_var = NULL;
+  counter = 0;
 }
 
 /* When target does not have ctors and dtors, we call all constructor
@@ -874,11 +883,7 @@
 static void
 cgraph_analyze_functions (void)
 {
-  /* Keep track of already processed nodes when called multiple times for
-     intermodule optimization.  */
-  static struct cgraph_node *first_analyzed;
   struct cgraph_node *first_processed = first_analyzed;
-  static struct varpool_node *first_analyzed_var;
   struct cgraph_node *node, *next;
 
   process_function_and_variable_attributes (first_processed,
@@ -1401,7 +1406,6 @@
 void
 cgraph_build_static_cdtor (char which, tree body, int priority)
 {
-  static int counter = 0;
   char which_buf[16];
   tree decl, name, resdecl;
 
Index: c-tree.h
===================================================================
--- c-tree.h	(revision 127677)
+++ c-tree.h	(working copy)
@@ -649,6 +649,7 @@
 
 /* In c-decl.c */
 extern void c_finish_incomplete_decl (tree);
+extern void c_clear_binding_stack (void);
 extern void c_write_global_declarations (void);
 
 /* In order for the format checking to accept the C frontend
Index: dwarf2out.c
===================================================================
--- dwarf2out.c	(revision 127650)
+++ dwarf2out.c	(working copy)
@@ -14276,6 +14276,37 @@
 static void
 dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
 {
+  /* In server mode we might have been previously initialized.  So,
+     reset some things there that we may not clean up when forked.  */
+#ifdef DWARF2_DEBUGGING_INFO
+  next_die_offset = 0;
+  current_function_has_inlines = false;
+#endif
+  comp_unit_die = NULL;
+  limbo_die_list = NULL;
+  line_info_table_in_use = 0;
+  have_multiple_function_sections = false;
+  separate_line_info_table = NULL;
+  separate_line_info_table_allocated = 0;
+  separate_line_info_table_in_use = 0;
+  arange_table = NULL;
+  arange_table_allocated = 0;
+  arange_table_in_use = 0;
+  ranges_table = NULL;
+  ranges_table_allocated = 0;
+  ranges_table_in_use = 0;
+  ranges_by_label = NULL;
+  ranges_by_label_allocated = 0;
+  ranges_by_label_in_use = 0;
+  have_location_lists = false;
+  loclabel_num = 0;
+  last_emitted_file = NULL;
+  label_num = 0;
+  file_table_last_lookup = NULL;
+  text_section_used = false;
+  cold_text_section_used = false;
+  cold_text_section = NULL;
+
   /* Allocate the file_table.  */
   file_table = htab_create_ggc (50, file_table_hash,
 				file_table_eq, NULL);
Index: server.c
===================================================================
--- server.c	(revision 128210)
+++ server.c	(working copy)
@@ -295,7 +295,7 @@
 
   write (fd, &reply, 1);
   close (fd);
-  fprintf (stderr, "server is ready\n");
+  fprintf (stderr, "server is ready; pid = %ld\n", (long) getpid ());
 
   listen (sockfd, 5);
 
Index: c-decl.c
===================================================================
--- c-decl.c	(revision 127677)
+++ c-decl.c	(working copy)
@@ -2881,14 +2881,23 @@
 void
 c_init_decl_processing (void)
 {
+  static bool did_it = false;
+
   location_t save_loc = input_location;
 
   /* Initialize reserved words for parser.  */
-  c_parse_init ();
+  if (!did_it)
+    {
+      /* FIXME: should redo this but also reset things which were
+	 previously reserved words.  Must look at the canonical
+	 spelling issue; see comment there.  */
+      c_parse_init ();
+    }
 
   current_function_decl = 0;
 
-  gcc_obstack_init (&parser_obstack);
+  if (!did_it)
+    gcc_obstack_init (&parser_obstack);
 
   /* Make the externals scope.  */
   push_scope ();
@@ -2904,18 +2913,22 @@
   input_location.line = 0;
 #endif
 
-  build_common_tree_nodes (flag_signed_char, false);
+  if (!did_it)
+    {
+      build_common_tree_nodes (flag_signed_char, false);
 
-  c_common_nodes_and_builtins ();
+      c_common_nodes_and_builtins ();
 
-  /* In C, comparisons and TRUTH_* expressions have type int.  */
-  truthvalue_type_node = integer_type_node;
-  truthvalue_true_node = integer_one_node;
-  truthvalue_false_node = integer_zero_node;
+      /* In C, comparisons and TRUTH_* expressions have type int.  */
+      truthvalue_type_node = integer_type_node;
+      truthvalue_true_node = integer_one_node;
+      truthvalue_false_node = integer_zero_node;
 
-  /* Even in C99, which has a real boolean type.  */
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("_Bool"),
-			boolean_type_node));
+      /* Even in C99, which has a real boolean type.  */
+      pushdecl (build_decl (TYPE_DECL, get_identifier ("_Bool"),
+			    boolean_type_node));
+    }
+  did_it = true;
 
   input_location = save_loc;
 
@@ -8013,9 +8026,10 @@
 static GTY(()) tree ext_block;
 
 void
-c_write_global_declarations (void)
+c_clear_binding_stack (void)
 {
-  tree t;
+  /* Clear this in case of early exit.  */
+  ext_block = NULL;
 
   /* We don't want to do this if generating a PCH.  */
   if (pch_file)
@@ -8027,6 +8041,7 @@
     return;
 
   /* Close the external scope.  */
+  /* FIXME: we're keeping ext_block around too long in the server.  */
   ext_block = pop_scope ();
   external_scope = 0;
   gcc_assert (!current_scope);
@@ -8042,7 +8057,16 @@
 	  dump_end (TDI_tu, stream);
 	}
     }
+}
 
+void
+c_write_global_declarations (void)
+{
+  tree t;
+
+  if (!ext_block)
+    return;
+
   /* Process all file scopes in this compilation, and the external_scope,
      through wrapup_global_declarations and check_global_declarations.  */
   for (t = all_translation_units; t; t = TREE_CHAIN (t))
Index: c-pragma.c
===================================================================
--- c-pragma.c	(revision 127650)
+++ c-pragma.c	(working copy)
@@ -920,6 +920,9 @@
 void
 init_pragma (void)
 {
+  if (registered_pragmas)
+    VEC_free (pragma_handler, heap, registered_pragmas);
+
   if (flag_openmp && !flag_preprocess_only)
     {
       struct omp_pragma_def { const char *name; unsigned int id; };
Index: c-lang.c
===================================================================
--- c-lang.c	(revision 127650)
+++ c-lang.c	(working copy)
@@ -43,6 +43,8 @@
 #define LANG_HOOKS_NAME "GNU C"
 #undef LANG_HOOKS_INIT
 #define LANG_HOOKS_INIT c_objc_common_init
+#undef LANG_HOOKS_CLEAR_BINDING_STACK
+#define LANG_HOOKS_CLEAR_BINDING_STACK c_clear_binding_stack
 
 /* Each front end provides its own lang hook initializer.  */
 const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;



More information about the Gcc-patches mailing list