This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[lto] Stream BLOCK nodes
- From: Diego Novillo <dnovillo at google dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 26 May 2009 16:26:59 -0400
- Subject: [lto] Stream BLOCK nodes
This patch adds support for streaming BLOCK nodes. This is the
first step towards supporting debug info in gimple files.
This is still work in progress. In particular, I had to disable
the streaming of BLOCK_VARS because it's causing failures in 3
libstdc++ tests. I am working on a fix, but the patch was
already growing too large. I added a FIXME note that I will be
removing shortly.
Tested on x86_64.
* lto-function-out.c (output_expr_operand): Move forward
declaration earlier in the file.
(output_tree_flags): Handle BLOCK nodes.
(output_block_or_decl): New.
(output_tree_block): New.
(output_tree_with_context): Call it to handle BLOCK nodes.
Handle BLOCK nodes when detecting nodes that have been
written out already.
(output_expr_operand): Handle every unhandled code with
the default label.
(output_local_var_decl): If DECL does not have a name,
set DECL_NAME to D.<uid>.
Write DECL_VALUE_EXPR, if it has one.
(output_gimple_stmt): Write gimple_block (STMT).
(lto_static_init): Remove BLOCK from set
lto_types_needed_for.
(output_function): Create a hash table for OB->MAIN_HASH_TABLE.
Write DECL_INITIAL (FUNCTION).
* lto-function-in.c (input_expr_operand): Forward declare.
(input_local_var_decl): Read DECL_VALUE_EXPR, if needed.
(input_gimple_stmt): Read gimple_block for STMT.
(input_function): Read DECL_INITIAL for FN_DECL.
(input_block_or_decl): New.
(input_tree_block): New.
(input_tree_operand): Call it.
* lto-tags.h (enum LTO_tags): Add LTO_block.
* lto-tree-tags.def: Call MAP_EXPR_TAG for LTO_block.
Call SET_NAME for LTO_block.
* lto-tree-flags.def: Remove asm_written_flag from BLOCK,
QUAL_UNION_TYPE, RECORD_TYPE and UNION_TYPE.
Index: lto-function-out.c
===================================================================
--- lto-function-out.c (revision 147598)
+++ lto-function-out.c (working copy)
@@ -62,6 +62,7 @@ const char *LTO_tree_tag_names[LTO_tree_
/* Forward declarations to break cyclical dependencies. */
static void output_record_start (struct output_block *, tree, tree,
unsigned int);
+static void output_expr_operand (struct output_block *, tree);
/* The index of the last eh_region seen for an instruction. The
eh_region for an instruction is only emitted if it different from
@@ -143,9 +144,6 @@ string_slot_free (void *p)
}
-/* The output stream that contains the abbrev table for all of the
- functions in this compilation unit. */
-static void output_expr_operand (struct output_block *, tree);
/* Clear the line info stored in DATA_IN. */
@@ -580,6 +578,8 @@ output_tree_flags (struct output_block *
inside a function. */
xloc = expand_location (DECL_SOURCE_LOCATION (expr));
}
+ else if (TREE_CODE (expr) == BLOCK)
+ xloc = expand_location (BLOCK_SOURCE_LOCATION (expr));
if (xloc.file)
{
@@ -963,6 +963,88 @@ output_constructor (struct output_block
}
}
+
+/* Helper for output_tree_block. T is either a FUNCTION_DECL or a
+ BLOCK. If T is a FUNCTION_DECL, write a reference to it (to avoid
+ duplicate definitions on the reader side). Otherwise, write it as
+ a regular tree node. OB is as in output_tree_block.
+
+ FIXME lto, this would not be needed if streaming of nodes in the
+ global context was unified with streaming of function bodies. */
+
+static void
+output_block_or_decl (struct output_block *ob, tree t)
+{
+ if (t == NULL_TREE)
+ output_zero (ob);
+ else if (TREE_CODE (t) == FUNCTION_DECL)
+ output_expr_operand (ob, t);
+ else if (TREE_CODE (t) == BLOCK)
+ output_tree (ob, t);
+ else
+ gcc_unreachable ();
+}
+
+
+/* Write symbol binding block BLOCK to output block OB. */
+
+static void
+output_tree_block (struct output_block *ob, tree block)
+{
+ unsigned HOST_WIDE_INT block_flags;
+ unsigned i;
+ tree t;
+ static struct function *last_cfun = NULL;
+ static struct pointer_set_t *local_syms = NULL;
+ static unsigned last_block_num = 0;
+
+ BLOCK_NUMBER (block) = last_block_num++;
+
+ block_flags = 0;
+ lto_set_flag (&block_flags, BLOCK_ABSTRACT (block));
+ lto_set_flags (&block_flags, BLOCK_NUMBER (block), 31);
+ output_sleb128 (ob, block_flags);
+
+ /* Note that we are only interested in emitting the symbols that are
+ actually referenced in CFUN. Create a set of local symbols to
+ use as a filter for BLOCK_VARS. */
+ if (last_cfun != cfun)
+ {
+ if (local_syms)
+ pointer_set_destroy (local_syms);
+
+ local_syms = pointer_set_create ();
+ for (t = cfun->local_decls; t; t = TREE_CHAIN (t))
+ {
+ tree v = TREE_VALUE (t);
+ if (TREE_CODE (v) != TYPE_DECL)
+ pointer_set_insert (local_syms, v);
+ }
+
+ last_cfun = cfun;
+ }
+
+ /* FIXME lto. Disabled for now. This is causing regressions in
+ libstdc++ testsuite
+ (testsuite/23_containers/list/check_construct_destroy.cc). */
+ for (t = BLOCK_VARS (block); t && 0; t = TREE_CHAIN (t))
+ if (TREE_CODE (t) != TYPE_DECL && pointer_set_contains (local_syms, t))
+ output_expr_operand (ob, t);
+ output_zero (ob);
+
+ output_sleb128 (ob, VEC_length (tree, BLOCK_NONLOCALIZED_VARS (block)));
+ for (i = 0; VEC_iterate (tree, BLOCK_NONLOCALIZED_VARS (block), i, t); i++)
+ output_expr_operand (ob, t);
+
+ output_block_or_decl (ob, BLOCK_SUPERCONTEXT (block));
+ output_block_or_decl (ob, BLOCK_ABSTRACT_ORIGIN (block));
+ output_block_or_decl (ob, BLOCK_FRAGMENT_ORIGIN (block));
+ output_block_or_decl (ob, BLOCK_FRAGMENT_CHAIN (block));
+ output_tree (ob, BLOCK_CHAIN (block));
+ output_tree (ob, BLOCK_SUBBLOCKS (block));
+}
+
+
/* Output EXPR to the main stream in OB. */
static void
@@ -1266,23 +1348,6 @@ output_expr_operand (struct output_block
break;
}
- /* This is the error case, these are type codes that will either
- never happen or that we have not gotten around to dealing
- with are here. */
- case BIND_EXPR:
- case BLOCK:
- case CATCH_EXPR:
- case EH_FILTER_EXPR:
- case OMP_CRITICAL:
- case OMP_FOR:
- case OMP_MASTER:
- case OMP_ORDERED:
- case OMP_PARALLEL:
- case OMP_SECTIONS:
- case OMP_SINGLE:
- case TARGET_MEM_REF:
- case TRY_CATCH_EXPR:
- case TRY_FINALLY_EXPR:
default:
/* We cannot have forms that are not explicity handled. So when
this is triggered, there is some form that is not being
@@ -1677,6 +1751,9 @@ output_gimple_stmt (struct output_block
/* Emit location information for the statement. */
output_stmt_location (ob, stmt);
+ /* Emit the lexical block holding STMT. */
+ output_tree (ob, gimple_block (stmt));
+
/* Emit the tuple header. FIXME lto. This is emitting fields that are not
necessary to emit (e.g., gimple_statement_base.bb,
gimple_statement_base.block). */
@@ -1940,6 +2017,7 @@ lto_static_init (void)
/* These forms never need types. */
sbitmap_ones (lto_types_needed_for);
RESET_BIT (lto_types_needed_for, ASM_EXPR);
+ RESET_BIT (lto_types_needed_for, BLOCK);
RESET_BIT (lto_types_needed_for, CASE_LABEL_EXPR);
RESET_BIT (lto_types_needed_for, FIELD_DECL);
RESET_BIT (lto_types_needed_for, FUNCTION_DECL);
@@ -2031,7 +2109,8 @@ lto_static_init_local (void)
static int function_num;
#endif
-/* Output FN. */
+
+/* Output the body of function NODE->DECL. */
static void
output_function (struct cgraph_node *node)
@@ -2045,6 +2124,8 @@ output_function (struct cgraph_node *nod
LTO_SET_DEBUGGING_STREAM (debug_main_stream, main_data);
clear_line_info (ob);
ob->cgraph_node = node;
+ ob->main_hash_table = htab_create (37, lto_hash_global_slot_node,
+ lto_eq_global_slot_node, free);
gcc_assert (!current_function_decl && !cfun);
@@ -2092,9 +2173,13 @@ output_function (struct cgraph_node *nod
else
output_zero (ob);
- /* Output any exception-handling regions. */
+ /* Output any exception handling regions. */
output_eh_regions (ob, fn);
+ /* Output DECL_INITIAL for the function, which contains the tree of
+ lexical scopes. */
+ output_tree (ob, DECL_INITIAL (function));
+
/* Output the head of the arguments list. */
LTO_DEBUG_INDENT_TOKEN ("decl_arguments");
if (DECL_ARGUMENTS (function))
@@ -2714,8 +2799,6 @@ output_function_decl (struct output_bloc
output_tree_with_context (ob, decl->decl_non_common.result, decl);
output_tree (ob, decl->decl_non_common.vindex);
- /* omit initial -- should be written with body */
-
if (decl->function_decl.personality)
{
/* FIXME lto: We have to output the index since the symbol table
@@ -3189,7 +3272,10 @@ output_tree_with_context (struct output_
fprintf (stderr, "\n");
#endif
- if (TYPE_P (expr) || DECL_P (expr) || TREE_CODE (expr) == TREE_BINFO)
+ if (TYPE_P (expr)
+ || DECL_P (expr)
+ || TREE_CODE (expr) == TREE_BINFO
+ || TREE_CODE (expr) == BLOCK)
{
unsigned int global_index;
/* FIXME lto: There are decls that pass the predicate above, but which
@@ -3213,7 +3299,6 @@ output_tree_with_context (struct output_
case NAMESPACE_DECL:
case TRANSLATION_UNIT_DECL:
case LABEL_DECL:
- break;
case VOID_TYPE:
case INTEGER_TYPE:
case REAL_TYPE:
@@ -3231,8 +3316,8 @@ output_tree_with_context (struct output_
case QUAL_UNION_TYPE:
case FUNCTION_TYPE:
case METHOD_TYPE:
- break;
case TREE_BINFO:
+ case BLOCK:
break;
default:
@@ -3283,6 +3368,11 @@ output_tree_with_context (struct output_
switch (code)
{
+ case BLOCK:
+ output_global_record_start (ob, expr, NULL, LTO_block);
+ output_tree_block (ob, expr);
+ break;
+
case COMPLEX_CST:
if (TREE_CODE (TREE_REALPART (expr)) == REAL_CST)
{
@@ -3564,31 +3654,13 @@ output_tree_with_context (struct output_
break;
}
- /* This is the error case, these are type codes that will either
- never happen or that we have not gotten around to dealing
- with are here. */
- case BIND_EXPR:
- case BLOCK:
- case CATCH_EXPR:
- case EH_FILTER_EXPR:
- case OMP_CRITICAL:
- case OMP_FOR:
- case OMP_MASTER:
- case OMP_ORDERED:
- case OMP_PARALLEL:
- case OMP_SECTIONS:
- case OMP_SINGLE:
- case TARGET_MEM_REF:
- case TRY_CATCH_EXPR:
- case TRY_FINALLY_EXPR:
default:
if (TREE_CODE (expr) >= NUM_TREE_CODES)
{
/* EXPR is a language-specific tree node, which has no meaning
- outside of the front-end. Something along the lines of
- http://gcc.gnu.org/ml/gcc-patches/2008-03/msg00349.html
- should be implemented. */
- error ("Unimplemented code (FE-specific): %d", (int) code);
+ outside of the front end. These nodes should have been
+ cleaned up by pass_ipa_free_lang_data. */
+ error ("Invalid FE-specific tree code: %d", (int) code);
gcc_unreachable ();
}
else
Index: lto-function-in.c
===================================================================
--- lto-function-in.c (revision 147598)
+++ lto-function-in.c (working copy)
@@ -59,6 +59,8 @@ static tree input_tree_operand (struct l
tree, enum LTO_tags);
static tree input_local_decl (struct lto_input_block *, struct data_in *,
struct function *, unsigned int);
+static tree input_expr_operand (struct lto_input_block *, struct data_in *,
+ struct function *, enum LTO_tags);
/* Map between LTO tags and tree codes. */
static enum tree_code tag_to_expr[LTO_tree_last_tag];
@@ -1736,6 +1748,7 @@ input_gimple_stmt (struct lto_input_bloc
size_t i, nbytes;
char *buf;
location_t location;
+ tree block;
if (tag == LTO_gimple_asm)
code = GIMPLE_ASM;
@@ -1768,6 +1781,9 @@ input_gimple_stmt (struct lto_input_bloc
/* Read location information. */
location = input_stmt_location (ib, data_in);
+ /* Read lexical block reference. */
+ block = input_tree (ib, data_in);
+
/* Read the tuple header. FIXME lto. This seems unnecessarily slow
and it is reading pointers in the tuple that need to be re-built
locally (e.g, basic block, lexical block, operand vectors, etc). */
@@ -1827,7 +1843,7 @@ input_gimple_stmt (struct lto_input_bloc
should disappear after we fix the unnecessary fields that are
written for every tuple. */
gimple_set_bb (stmt, NULL);
- gimple_set_block (stmt, NULL);
+ gimple_set_block (stmt, block);
if (gimple_has_ops (stmt))
{
gimple_set_def_ops (stmt, NULL);
@@ -1958,8 +1974,6 @@ input_function (tree fn_decl, struct dat
fn = DECL_STRUCT_FUNCTION (fn_decl);
tag = input_record_start (ib);
- DECL_INITIAL (fn_decl) = DECL_SAVED_TREE (fn_decl) = make_node (BLOCK);
- BLOCK_ABSTRACT_ORIGIN (DECL_SAVED_TREE (fn_decl)) = fn_decl;
clear_line_info (data_in);
gimple_register_cfg_hooks ();
@@ -1994,8 +2008,18 @@ input_function (tree fn_decl, struct dat
if (tag)
fn->nonlocal_goto_save_area = input_expr_operand (ib, data_in, fn, tag);
+ /* Read the exception handling regions in the function. */
input_eh_regions (ib, data_in, fn);
+ /* Read the tree of lexical scopes for the function. */
+ DECL_INITIAL (fn_decl) = input_tree (ib, data_in);
+ if (DECL_INITIAL (fn_decl) == NULL_TREE)
+ {
+ DECL_INITIAL (fn_decl) = make_node (BLOCK);
+ BLOCK_ABSTRACT_ORIGIN (DECL_SAVED_TREE (fn_decl)) = fn_decl;
+ }
+ DECL_SAVED_TREE (fn_decl) = DECL_INITIAL (fn_decl);
+
LTO_DEBUG_INDENT_TOKEN ("decl_arguments");
tag = input_record_start (ib);
if (tag)
@@ -3283,6 +3307,87 @@ input_type_tree (struct lto_input_block
}
+/* Helper for input_tree_block. Read a FUNCTION_DECL reference or a
+ BLOCK from IB using descriptors in DATA_IN. */
+
+static tree
+input_block_or_decl (struct lto_input_block *ib, struct data_in *data_in)
+{
+ enum LTO_tags tag;
+
+ /* FIXME lto, this would not be needed if streaming of trees in
+ global context was unified with trees in function bodies. */
+ tag = input_record_start (ib);
+
+ if (tag == LTO_null)
+ return NULL_TREE;
+ else if (tag == LTO_function_decl0)
+ return lto_file_decl_data_get_fn_decl (data_in->file_data,
+ lto_input_uleb128 (ib));
+ else if (tag == LTO_block || tag == LTO_tree_pickle_reference)
+ return input_tree_operand (ib, data_in, NULL, tag);
+ else
+ gcc_unreachable ();
+}
+
+
+/* Read a BLOCK tree from input block IB using descriptors in DATA_IN. */
+
+static tree
+input_tree_block (struct lto_input_block *ib, struct data_in *data_in)
+{
+ unsigned HOST_WIDE_INT block_flags;
+ tree block;
+ unsigned i, vlen;
+ enum LTO_tags tag;
+ tree first, curr, prev;
+
+ block = make_node (BLOCK);
+
+ global_vector_enter (data_in, block);
+
+ block_flags = lto_input_sleb128 (ib);
+ BLOCK_NUMBER (block) = lto_get_flags (&block_flags, 31);
+ BLOCK_ABSTRACT (block) = lto_get_flag (&block_flags);
+
+ first = prev = NULL_TREE;
+ tag = input_record_start (ib);
+ while (tag)
+ {
+ curr = input_expr_operand (ib, data_in, cfun, tag);
+ if (prev)
+ TREE_CHAIN (prev) = curr;
+ else
+ first = curr;
+
+ TREE_CHAIN (curr) = NULL_TREE;
+ prev = curr;
+ tag = input_record_start (ib);
+ }
+ BLOCK_VARS (block) = first;
+
+
+ vlen = lto_input_sleb128 (ib);
+ for (i = 0; i < vlen; i++)
+ {
+ tree var;
+
+ tag = input_record_start (ib);
+ var = input_expr_operand (ib, data_in, cfun, tag);
+ VEC_safe_push (tree, gc, BLOCK_NONLOCALIZED_VARS (block), var);
+ }
+
+ BLOCK_SUPERCONTEXT (block) = input_block_or_decl (ib, data_in);
+ BLOCK_ABSTRACT_ORIGIN (block) = input_block_or_decl (ib, data_in);
+ BLOCK_FRAGMENT_ORIGIN (block) = input_block_or_decl (ib, data_in);
+ BLOCK_FRAGMENT_CHAIN (block) = input_block_or_decl (ib, data_in);
+ BLOCK_CHAIN (block) = input_tree (ib, data_in);
+ BLOCK_SUBBLOCKS (block) = input_tree (ib, data_in);
+
+ return block;
+}
+
+
/* Read a node in the body of function FN from input block IB using
descriptors in DATA_IN. TAG indicates the kind of tree that is
expected to be read. */
@@ -3359,6 +3464,10 @@ input_tree_operand (struct lto_input_blo
switch (code)
{
+ case BLOCK:
+ result = input_tree_block (ib, data_in);
+ break;
+
case COMPLEX_CST:
{
tree elt_type = input_type_tree (ib, data_in);
Index: lto-tree-tags.def
===================================================================
--- lto-tree-tags.def (revision 147597)
+++ lto-tree-tags.def (working copy)
@@ -65,6 +65,7 @@
MAP_EXPR_TAG(ARRAY_RANGE_REF, LTO_array_range_ref)
MAP_EXPR_TAG(ARRAY_REF, LTO_array_ref)
MAP_EXPR_TAG(ARRAY_TYPE, LTO_array_type)
+ MAP_EXPR_TAG(BLOCK, LTO_block)
MAP_EXPR_TAG(BOOLEAN_TYPE, LTO_boolean_type)
MAP_EXPR_TAG(COMPLEX_TYPE, LTO_complex_type)
MAP_EXPR_TAG(COMPONENT_REF, LTO_component_ref)
@@ -215,6 +216,7 @@
SET_NAME (LTO_bit_field_ref1, "bit_field_ref1")
SET_NAME (LTO_bit_not_expr, "bit_not_expr")
SET_NAME (LTO_bit_xor_expr, "bit_xor_expr")
+ SET_NAME (LTO_block, "block")
SET_NAME (LTO_case_label_expr0, "case_label_expr0")
SET_NAME (LTO_case_label_expr1, "case_label_expr1")
SET_NAME (LTO_case_label_expr2, "case_label_expr2")
Index: lto-tags.h
===================================================================
--- lto-tags.h (revision 147597)
+++ lto-tags.h (working copy)
@@ -307,6 +307,8 @@ enum LTO_tags
LTO_bit_not_expr,
LTO_bit_xor_expr,
+ LTO_block,
+
/* Call_exprs are terminated by a 0 to indicate the end of the
parameter list. Variant 1 indicates the presence of a call
chain. */
Index: lto-tree-flags.def
===================================================================
--- lto-tree-flags.def (revision 147597)
+++ lto-tree-flags.def (working copy)
@@ -193,7 +193,6 @@
END_EXPR_CASE (BIT_XOR_EXPR)
START_EXPR_CASE (BLOCK)
- ADD_EXPR_FLAG (asm_written_flag)
END_EXPR_CASE (BLOCK)
START_EXPR_CASE (BOOLEAN_TYPE)
@@ -597,7 +596,6 @@
END_EXPR_CASE (PREINCREMENT_EXPR)
START_EXPR_CASE (QUAL_UNION_TYPE)
- ADD_EXPR_FLAG (asm_written_flag)
ADD_TYPE_FLAG (no_force_blk_flag)
END_EXPR_CASE (QUAL_UNION_TYPE)
@@ -622,7 +620,6 @@
END_EXPR_CASE (REAL_TYPE)
START_EXPR_CASE (RECORD_TYPE)
- ADD_EXPR_FLAG (asm_written_flag)
ADD_TYPE_FLAG (no_force_blk_flag)
END_EXPR_CASE (RECORD_TYPE)
@@ -775,7 +772,6 @@
END_EXPR_CASE (UNGT_EXPR)
START_EXPR_CASE (UNION_TYPE)
- ADD_EXPR_FLAG (asm_written_flag)
ADD_TYPE_FLAG (no_force_blk_flag)
ADD_TYPE_FLAG (transparent_union_flag)
END_EXPR_CASE (UNION_TYPE)