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]

Re: [lto] PATCH: Read FUNCTION_DECLs from DWARF


Let me do a round of testing with this, and I will have my code up today.

kenny

Mark Mitchell wrote:
> 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]