This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[lto] PATCH: Read FUNCTION_DECLs from DWARF


Kenny, Sandra, et. al. --

This patch implements support for reading a FUNCTION_DECL from DWARF,
and most -- but not quite enough -- of the API required to begin
reading the in LTO information written out for function bodies.

The LTO front-end can now read in a function, like:

  void f(void) {}

However, there are two gaping holes:

* In lto-elf.c, the lto_elf_{map,unmap}_fn_body routines are not
  implemented, so we do not actually get a handle to LTO function body
  data.

* In lto-read.c, the lto_read_function_body function is a skeleton,
  ignores the data it is provided, and always makes a function that
  immediate returns.  (Which happens to be right for the example
  above: a broken clock is right twice a day...)

Slightly less gaping:

* In lto-symtab.c, lto_symtab_merge_fn needs to actually merge
  functions across object files, in the same way that
  lto_symtab_merge_var does.  (In fact, it's quite possible these two
  functions can share some code.)

Kenny, you should be able to drop your reader into lto-read.c.

Sandra, so that Kenny's reader can actually get some data, would you
please write up lto_elf_{map,unmap}_fn_body?  I think that most of the
code you need is already lto_elf_file_open; here, you need to find
sections named .lto_* while the code in lto_elf_file_open looks for
.debug_{info,abbrev}.   Presumably, this could be refactored in some
way?

After that, Sandra, you could go after the function-merging code, as
that will be necessary to actually demonstrate cross-module inlining;
we have to know that in:

  a.c
  ---
  extern void f(void);
  void g(void) { f(); }
  
  b.c
  ---
  void f(void) {}

both functions "f" are actually the same.  That's also going to mean
that lto_resolve_fn_ref has to work, which also means that the
lto_fn_ref has to work.

Unfortunately, I'm about to drop into a black hole of businss travel,
so I'm probably not going to get a chance to write a lot more code
until mid-October, especially given that I want to move 4.2/4.1.2
along, which may require fixing some PRs.  But, of course, I'll do my
best to respond to any questions about the bugs^Hcode I've already
written.

Thanks,

--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

2006-09-10  Mark Mitchell  <mark@codesourcery.com>

	gcc/
	* tree.c (build_function_type): Adjust comment to match new API.

2006-09-10  Mark Mitchell  <mark@codesourcery.com>

	* lto.h (lto_file_vtable): New structure.
	(lto_file): Add vtable pointer.
	(lto_file_init): Add vtable paramter.
	(lto_read_function_body): New function.
	(lto_symtab_merge_fn): New function.
	* lto.c (lto_file_init): Add vtable parameter.
	(lto_read_form): Fill in entries for DW_AT_prototyped,
	DW_AT_frame_base.
	(lto_read_subroutine_type_subprogram_DIE): New function.
	(lto_read_DIE): Fill in entries for DW_TAG_subroutine_type and
	DW_TAG_subprogram.
	* lto-elf.c (lto_elf_vile_vtable): New variable.
	(lto_elf_file_open): Pass it to lto_file_init.
	(lto_elf_map_fn_body): New function.
	(lto_elf_unmap_fn_body): Likewise.
	* lto-read.c: New file.
	* lto-symtab.c (lto_symtab_merge_fn): New function.
	* lto-lang.c (LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION): Define to
	tree_rest_of_compilation.
	* Make-lang.in (LTO_OBJS): Add lto-read.o
	(lto-read.o): New target.

Index: tree.c
===================================================================
--- tree.c	(revision 116837)
+++ tree.c	(working copy)
@@ -5262,12 +5262,10 @@ get_inner_array_type (tree array)
   return type;
 }
 
-/* Construct, lay out and return
-   the type of functions returning type VALUE_TYPE
-   given arguments of types ARG_TYPES.
-   ARG_TYPES is a chain of TREE_LIST nodes whose TREE_VALUEs
-   are data type nodes for the arguments of the function.
-   If such a type has already been constructed, reuse it.  */
+/* Construct, lay out and return the type of functions returning type
+   VALUE_TYPE given arguments of types ARG_TYPES.  ARG_TYPES is a
+   TREE_VEC of _TYPE nodes for the arguments of the function.  If such
+   a type has already been constructed, reuse it.  */
 
 tree
 build_function_type (tree value_type, tree arg_types)
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 116837)
+++ lto/lto.c	(working copy)
@@ -252,8 +252,11 @@ lto_abbrev_fd_close (lto_abbrev_fd *fd)
 
 /* Initialize FILE, an LTO file object for FILENAME.  */
 void
-lto_file_init (lto_file *file, const char *filename)
+lto_file_init (lto_file *file, 
+	       const lto_file_vtable *vtable,
+	       const char *filename)
 {
+  file->vtable = vtable;
   file->filename = filename;
   lto_info_fd_init (&file->debug_info, ".debug_info", file);
   lto_abbrev_fd_init (&file->debug_abbrev, ".debug_abbrev", file);
@@ -719,7 +722,7 @@ lto_read_form (lto_info_fd *info_fd, 
     DW_cl_error, /* padding */
     DW_cl_string, /* producer */
     DW_cl_error, /* padding */
-    DW_cl_error, /* prototyped */
+    DW_cl_flag, /* prototyped */
     DW_cl_error, /* padding */
     DW_cl_error, /* padding */
     DW_cl_error, /* return_addr */
@@ -744,7 +747,7 @@ lto_read_form (lto_info_fd *info_fd, 
     DW_cl_error, /* discr_list */
     DW_cl_constant, /* encoding */
     DW_cl_flag, /* external */
-    DW_cl_error, /* frame_base */
+    DW_cl_block | DW_cl_loclistptr, /* frame_base */
     DW_cl_error, /* friend */
     DW_cl_error, /* identifier_case */
     DW_cl_error, /* macro_info */
@@ -1750,6 +1753,159 @@ lto_read_variable_formal_parameter_const
 }
 
 static tree
+lto_read_subroutine_type_subprogram_DIE (lto_info_fd *fd,
+					 const DWARF2_abbrev *abbrev,
+					 lto_context *context)
+{
+  tree ret_type;
+  tree arg_types;
+  tree type;
+  tree name;
+  bool external;
+  VEC(tree,heap) *parms;
+  unsigned n_parms;
+  unsigned i;
+  bool prototyped;
+  tree result;
+
+  gcc_assert (abbrev->tag == DW_TAG_subroutine_type
+	      || abbrev->tag == DW_TAG_subprogram);
+
+  ret_type = NULL_TREE;
+  prototyped = false;
+  name = NULL_TREE;
+  external = false;
+
+  if (abbrev->tag == DW_TAG_subroutine_type)
+    {
+      LTO_BEGIN_READ_ATTRS ()
+	{
+	case DW_AT_type:
+	  ret_type = lto_read_referenced_type_DIE (fd,
+						   context,
+						   attr_data.u.reference);
+	  break;
+
+	case DW_AT_prototyped:
+	  prototyped = attr_data.u.flag;
+	  break;
+	}
+      LTO_END_READ_ATTRS ();
+    }
+  else
+    {
+      LTO_BEGIN_READ_ATTRS ()
+	{
+	case DW_AT_decl_column:
+	case DW_AT_decl_file:
+	case DW_AT_decl_line:
+	  /* Ignore.  */
+	  break;
+
+	case DW_AT_low_pc:
+	case DW_AT_high_pc:
+	case DW_AT_ranges:
+	case DW_AT_frame_base:
+	  /* Ignore.  */
+	  break;
+
+	case DW_AT_name:
+	  name = lto_get_identifier (&attr_data);
+	  break;
+
+	case DW_AT_external:
+	  external = attr_data.u.flag;
+	  break;
+
+	case DW_AT_type:
+	  ret_type = lto_read_referenced_type_DIE (fd,
+						   context,
+						   attr_data.u.reference);
+	  break;
+
+	case DW_AT_prototyped:
+	  prototyped = attr_data.u.flag;
+	  break;
+	}
+      LTO_END_READ_ATTRS ();
+    }
+
+
+  /* The DWARF3 specification says that a return type is only
+     specified for functions that return a value.  Therefore,
+     functions without an explicit return type return "void".  */
+  if (!ret_type)
+    ret_type = void_type_node;
+ 
+  if (!prototyped)
+    sorry ("support for unprototyped functions not yet implemented");
+
+  parms = lto_collect_child_DIEs (fd, abbrev, context);
+  n_parms = VEC_length (tree, parms);
+  arg_types = make_tree_vec (n_parms + prototyped ? 1 : 0);
+  for (i = 0; i < n_parms; ++i)
+    {
+      tree parm = VEC_index (tree, parms, i);
+      if (TREE_CODE (parm) != PARM_DECL)
+	lto_file_corrupt_error ((lto_fd *)fd);
+      TREE_VEC_ELT (arg_types, i) = TREE_TYPE (parm);
+    }
+  if (prototyped)
+    TREE_VEC_ELT (arg_types, n_parms) = void_type_node;
+  VEC_free (tree, heap, parms);
+
+  /* Build the function type.  */
+  type = build_function_type (ret_type, arg_types);
+  if (abbrev->tag == DW_TAG_subroutine_type)
+    result = type;
+  else
+    {
+      void *body;
+      lto_file *file;
+      const char *name_str;
+
+      if (!name)
+	lto_file_corrupt_error ((lto_fd *)fd);
+
+      result = build_decl (FUNCTION_DECL, name, type);
+      TREE_PUBLIC (result) = external;
+      /* Load the body of the function.  */
+      file = fd->base.file;
+      body = file->vtable->map_fn_body (file, name_str);
+      if (body)
+	{
+	  /* This function has a definition.  */
+	  TREE_STATIC (result) = 1;
+	  DECL_EXTERNAL (result) = 0;
+	}
+      else
+	DECL_EXTERNAL (result) = 1;
+      /* If the function has already been declared, merge the
+	 declarations.  */
+      result = lto_symtab_merge_fn (result);
+      if (result != error_mark_node)
+	{
+	  if (body)
+	    {
+	      DECL_RESULT (result)
+		= build_decl (RESULT_DECL, NULL_TREE,
+			      TYPE_MAIN_VARIANT (ret_type));
+	      allocate_struct_function (result);
+	      lto_read_function_body (fd, context, result, body);
+	      file->vtable->unmap_fn_body (file, name_str, body);
+	    }
+	  rest_of_decl_compilation (result,
+				    /*top_level=*/1,
+				    /*at_end=*/0);
+	  if (body)
+	    cgraph_finalize_function (result, /*nested=*/false);
+	}
+    }
+
+  return result;
+}
+
+static tree
 lto_read_pointer_type_DIE (lto_info_fd *fd,
 			   const DWARF2_abbrev *abbrev,
 			   lto_context *context)
@@ -1998,7 +2154,7 @@ lto_read_DIE (lto_info_fd *fd, lto_conte
       NULL, /* string_type */
       NULL, /* structure_type */
       NULL, /* padding */
-      NULL, /* subroutine_type */
+      lto_read_subroutine_type_subprogram_DIE,
       NULL, /* typedef */
       NULL, /* union_type */
       NULL, /* unspecified_parameters */
@@ -2023,7 +2179,7 @@ lto_read_DIE (lto_info_fd *fd, lto_conte
       NULL, /* namelist */
       NULL, /* namelist_item */
       NULL, /* packed_type */
-      NULL, /* subprogram */
+      lto_read_subroutine_type_subprogram_DIE,
       NULL, /* template_type_param */
       NULL, /* template_value_param */
       NULL, /* thrown_type */
Index: lto/Make-lang.in
===================================================================
--- lto/Make-lang.in	(revision 116837)
+++ lto/Make-lang.in	(working copy)
@@ -26,7 +26,8 @@
 # The name of the LTO compiler.
 LTO_EXE = lto1$(exeext)
 # The LTO-specific object files inclued in $(LTO_EXE).
-LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-elf.o lto/lto-symtab.o
+LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-elf.o lto/lto-read.o \
+	lto/lto-symtab.o
 LTO_H = lto/lto.h $(HASHTAB_H) $(TREE_H)
 
 ########################################################################
@@ -82,5 +83,7 @@ lto/lto.o: lto/lto.c $(CONFIG_H) $(CGRAP
 	$(GGC_H) opts.h $(SYSTEM_H) toplev.h $(TM_H) $(LTO_H)
 lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
 	toplev.h $(LTO_H) 
+lto/lto-read.o: lto/lto-read.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
+	$(LTO_H) $(TREE_GIMPLE_H)
 lto/lto-symtab.o: lto/lto-symtab.c $(CONFIG_H) coretypes.h \
 	$(SYSTEM_H) toplev.h $(LTO_H) lto/lto-tree.h
Index: lto/lto-elf.c
===================================================================
--- lto/lto-elf.c	(revision 116837)
+++ lto/lto-elf.c	(working copy)
@@ -38,6 +38,20 @@ struct lto_elf_file 
 };
 typedef struct lto_elf_file lto_elf_file;
 
+/* Forward Declarations */
+
+static void *
+lto_elf_map_fn_body (lto_file *file, const char *fn);
+
+static void
+lto_elf_unmap_fn_body (lto_file *file, const char *fn, void *data);
+
+/* The vtable for ELF input files.  */
+static const lto_file_vtable lto_elf_file_vtable = {
+  lto_elf_map_fn_body,
+  lto_elf_unmap_fn_body
+};
+
 lto_file *
 lto_elf_file_open (const char *filename)
 {
@@ -52,7 +66,7 @@ lto_elf_file_open (const char *filename)
   /* Set up.  */
   elf_file = XNEW (lto_elf_file);
   result = (lto_file *)elf_file;
-  lto_file_init (result, filename);
+  lto_file_init (result, &lto_elf_file_vtable, filename);
   elf_file->fd = -1;
   elf_file->elf = NULL;
 
@@ -245,3 +259,20 @@ lto_elf_file_close (lto_file *file)
     close (elf_file->fd);
   lto_file_close (file);
 }
+
+void *
+lto_elf_map_fn_body (lto_file *file ATTRIBUTE_UNUSED, 
+		     const char *fn ATTRIBUTE_UNUSED)
+{
+  /* ??? Look in the ELF file to find the actual data, which should be
+     in the section named ".lto_FN".  */
+  return (void *)0x1;
+}
+
+void
+lto_elf_unmap_fn_body (lto_file *file ATTRIBUTE_UNUSED, 
+		       const char *fn ATTRIBUTE_UNUSED, 
+		       void *data ATTRIBUTE_UNUSED)
+{
+  return;
+}
Index: lto/lto.h
===================================================================
--- lto/lto.h	(revision 116837)
+++ lto/lto.h	(working copy)
@@ -79,9 +79,23 @@ typedef struct lto_abbrev_fd
   DWARF2_abbrev **abbrevs;
 } lto_abbrev_fd;
 
+/* The virtual function table for an lto_file.  */
+typedef struct lto_file_vtable
+{
+  /* Return the address of the function-body data for the function
+     named FN, or NULL if the data is not available.  */
+  void *(*map_fn_body)(lto_file *file, const char *fn);
+  /* DATA is the non-NULL address returned by a previous call to
+     MAP_FN_BODY, with the same value of FN.  Release any resources
+     allocated by MAP_FN_BODY.  */
+  void (*unmap_fn_body)(lto_file *file, const char *fn, void *data);
+} lto_file_vtable;
+
 /* An input file.  */
 struct lto_file
 {
+  /* Virtual functions implemented by the derived file class.  */
+  const lto_file_vtable *vtable;
   /* The name of the file.  */
   const char *filename;
   /* The contents of the .debug_info section.  */
@@ -107,8 +121,10 @@ typedef struct lto_ref
 extern void lto_main (int debug_p);
 
 /* Initialize the newly allocated FILE, which corresponds to
-   FILENAME.  */
-extern void lto_file_init (lto_file *file, const char *filename);
+   FILENAME.  VTABLE is the virtual table for FILE.  */
+extern void lto_file_init (lto_file *file, 
+			   const lto_file_vtable *vtable,
+			   const char *filename);
 
 /* Free resources associated with FILE.  FILE itself will be
    deallocated by this function.  */
@@ -143,6 +159,22 @@ extern lto_file *lto_elf_file_open (cons
 /* Close an ELF input file.  */
 extern void lto_elf_file_close (lto_file *file);
 
+/* lto-read.c */
+
+/* FN is a FUNCTION_DECL.  DATA is the LTO data written out during
+   ordinary compilation, encoding the body of FN.  FD and CONTEXT may
+   be passed back to the lto_resolve__ref functions to retrieve
+   information about glogal entities.  Upon return, DECL_SAVED_TREE
+   for FN contains the reconstituted body of FN and DECL_INITIAL
+   contains the BLOCK tree for the function.  However, it is not this
+   function's responsibility to provide FN to the optimizers or
+   code-generators; that will be done by the caller.  */
+extern void
+lto_read_function_body (lto_info_fd *fd,
+			lto_context *context,
+			tree fn,
+			const void *data);
+
 /* lto-symtab.c */
 
 /* The NEW_VAR (a VAR_DECL) has just been read.  If there is an
@@ -157,4 +189,7 @@ extern void lto_elf_file_close (lto_file
    NEW_VAR is returned.  */
 extern tree lto_symtab_merge_var (tree new_var);
 
+/* Like lto_symtab_merge_var, but for functions.  */
+extern tree lto_symtab_merge_fn (tree new_fn);
+
 #endif /* LTO_H */
Index: lto/lto-read.c
===================================================================
--- lto/lto-read.c	(revision 0)
+++ lto/lto-read.c	(revision 0)
@@ -0,0 +1,50 @@
+/* LTO function reader.
+   Copyright 2006 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, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "tree-gimple.h"
+#include "tree-iterator.h"
+#include "lto.h"
+
+void
+lto_read_function_body (lto_info_fd *fd ATTRIBUTE_UNUSED,
+			lto_context *context ATTRIBUTE_UNUSED,
+			tree fn,
+			const void *data ATTRIBUTE_UNUSED)
+{
+  tree return_expr;
+  tree stmt_list;
+  tree_stmt_iterator i;
+  tree body;
+
+  /* ??? For now, just pretend the function returns immediately.  */
+  return_expr = build1 (RETURN_EXPR, void_type_node, NULL_TREE);
+  stmt_list = alloc_stmt_list ();
+  i = tsi_start (stmt_list);
+  tsi_link_after (&i, return_expr, TSI_NEW_STMT);
+  body = build3 (BIND_EXPR, NULL_TREE, NULL_TREE, stmt_list, NULL_TREE);
+  DECL_SAVED_TREE (fn) = body;
+  DECL_INITIAL (fn) = make_node (BLOCK);
+
+  return;
+}
Index: lto/lto-symtab.c
===================================================================
--- lto/lto-symtab.c	(revision 116837)
+++ lto/lto-symtab.c	(working copy)
@@ -173,3 +173,10 @@ lto_symtab_merge_var (tree new_var) 
 
   return old_var;
 }
+
+tree
+lto_symtab_merge_fn (tree new_fn)
+{
+  /* ??? For now, assume all functions are distinct.  */
+  return new_fn;
+}
Index: lto/lto-lang.c
===================================================================
--- lto/lto-lang.c	(revision 116837)
+++ lto/lto-lang.c	(working copy)
@@ -187,6 +187,8 @@ lto_init (void)
 #define LANG_HOOKS_INIT lto_init
 #undef LANG_HOOKS_PARSE_FILE
 #define LANG_HOOKS_PARSE_FILE lto_main
+#undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION
+#define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION tree_rest_of_compilation
 
 const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]