This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[lto] PATCH: Read FUNCTION_DECLs from DWARF
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org, sandra at codesourcery dot com, zadeck at naturalbridge dot com
- Date: Sun, 10 Sep 2006 22:39:43 -0700
- Subject: [lto] PATCH: Read FUNCTION_DECLs from DWARF
- Reply-to: mark at codesourcery dot com
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, <o_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;