* [PATCH][LTO] Clean up type variant handling, allow bootstrap
@ 2009-08-17 15:46 Richard Guenther
2009-08-17 16:53 ` Diego Novillo
0 siblings, 1 reply; 3+ messages in thread
From: Richard Guenther @ 2009-08-17 15:46 UTC (permalink / raw)
To: gcc-patches; +Cc: Diego Novillo
This is my work-in-progress patch that enables bootstrapping with -flto
on i?86 (I'm currently checking x86_64). The key is still the
gimple_get_alias_set hunk - all the rest is fixing fallout.
The main fixing is from properly streaming TYPE_MAIN_VARIANT and
keeping the variant chains intact (see also the trunk patches I did,
still referenced in the patch - I'm currently merging from trunk again).
In the process of debugging all this I placed a lot of asserts
throughout the code - whopr seems to depend on that we do not stream
non-canonical types, which is what the lto_fixup_* hunks and the
cache preloading hunks fix. In the turn of fixing that I broke
the current -funsigned-char hack, so I simply removed it.
That's basically it. I will likely remove most of the checking I
inserted before committing this, maybe keep the variant chain
verifying in free-lang-data, wrapped inside ENABLE_CHECKING.
The free_lang_data_in_block change is also odd - I am hitting
CONST_DECLs with a FUNCTION_DECL context during streaming out
of the abstract origin of a function. But we assert that the
decl-context of all CONST_DECLs is NULL - for some reason.
The hack will pessimize debug info some more. Why again do we
not want to stream DECL_CONTEXT properly?
I'm currently re-bootstrapping and testing this, but previous
testing shows a single regression, the -funsigned-char lto test.
Any comments?
Thanks,
Richard.
2009-08-17 Richard Guenther <rguenther@suse.de>
PR lto/41071
* gimple.c (compare_type_names_p): Do not look at the
types main variant.
(gimple_register_type): Unlink a non-main-variant from its
variant chain if we will use a different type for it.
(gimple_get_alias_set): Pointers to CV qualified variants
have the same alias-set as unqualified variants.
* tree.c (free_lang_data_in_type): Do not free the variant chains.
(free_lang_data_in_block): Insert hack to free lang data in
abstract origins of the block as well.
* lto-streamer-out.c (lto_output_ts_type_tree_pointers): Do
not output TYPE_NEXT_VARIANT.
(output_type_ref): Remove hack for char_type_node.
* lto-streamer-in.c (lto_input_ts_type_tree_pointers): Do not
input TYPE_NEXT_VARIANT but instead reconstruct it on-the-fly.
* lto-streamer.c (lto_streamer_cache_insert_1): Add debugging code.
Remove hack for char_type_node.
(lto_record_common_node): Canonicalize types of nodes we record.
(lto_get_common_nodes): Record integer and size types first.
Defer to lto_record_common_node for registering and canonicalizing
types.
lto/
* lto.c (lto_fixup_type): Fixup the types main-variant. Keep
the variant chains intact.
(lto_fixup_constructor): New function.
(lto_fixup_tree): Replace all types. Properly fixup
constructors and constants.
Index: gcc/gimple.c
===================================================================
*** gcc/gimple.c.orig 2009-08-17 12:59:36.000000000 +0200
--- gcc/gimple.c 2009-08-17 13:00:07.000000000 +0200
*************** lookup_type_pair (tree t1, tree t2, htab
*** 3185,3192 ****
static bool
compare_type_names_p (tree t1, tree t2)
{
- tree variant1 = TYPE_MAIN_VARIANT (t1);
- tree variant2 = TYPE_MAIN_VARIANT (t2);
tree name1 = TYPE_NAME (t1);
tree name2 = TYPE_NAME (t2);
--- 3185,3190 ----
*************** compare_type_names_p (tree t1, tree t2)
*** 3215,3228 ****
if (name1 == name2)
return true;
- /* If either type has a variant type, compare that. This finds
- the case where a struct is typedef'ed in one module but referred
- to as 'struct foo' in the other; here, the main type for one is
- 'foo', and for the other 'foo_t', but the variants have the same
- name 'foo'. */
- if (variant1 != t1 || variant2 != t2)
- return compare_type_names_p (variant1, variant2);
-
return false;
}
--- 3213,3218 ----
*************** gimple_register_type (tree t)
*** 3908,3928 ****
}
slot = htab_find_slot (gimple_types, t, INSERT);
! if (*slot)
{
! tree new_type = (tree) *((tree *) slot);
/* Do not merge types with different addressability. */
gcc_assert (TREE_ADDRESSABLE (t) == TREE_ADDRESSABLE (new_type));
if (getenv ("MERGE_TYPE_DEBUG"))
{
! if (t != new_type)
{
! fprintf (stderr, "Merged with existing compatible type: %p - ",
! *slot);
! print_generic_stmt (stderr, new_type, 0);
}
}
t = new_type;
--- 3898,3931 ----
}
slot = htab_find_slot (gimple_types, t, INSERT);
! if (*slot
! && *(tree *)slot != t)
{
! tree new_type = *((tree *) slot);
/* Do not merge types with different addressability. */
gcc_assert (TREE_ADDRESSABLE (t) == TREE_ADDRESSABLE (new_type));
if (getenv ("MERGE_TYPE_DEBUG"))
{
! fprintf (stderr, "Merged with existing compatible type: %p - ", *slot);
! print_generic_stmt (stderr, new_type, 0);
! }
!
! /* If t is not its main variant then make t unreachable from its
! main variant list. Otherwise we'd queue up a lot of duplicates
! here. */
! if (t != TYPE_MAIN_VARIANT (t))
! {
! tree tem = TYPE_MAIN_VARIANT (t);
! while (tem && TYPE_NEXT_VARIANT (tem) != t)
! tem = TYPE_NEXT_VARIANT (tem);
! if (tem)
{
! TYPE_NEXT_VARIANT (tem) = TYPE_NEXT_VARIANT (t);
! TYPE_NEXT_VARIANT (t) = NULL_TREE;
}
+ gcc_assert (TYPE_NEXT_VARIANT (t) == NULL_TREE);
}
t = new_type;
*************** gimple_get_alias_set (tree t)
*** 4183,4188 ****
--- 4186,4221 ----
if (t1 != t)
return get_alias_set (t1);
}
+ else if (POINTER_TYPE_P (t))
+ {
+ tree t1;
+
+ /* Unfortunately, there is no canonical form of a pointer type.
+ In particular, if we have `typedef int I', then `int *', and
+ `I *' are different types. So, we have to pick a canonical
+ representative. We do this below.
+
+ Technically, this approach is actually more conservative that
+ it needs to be. In particular, `const int *' and `int *'
+ should be in different alias sets, according to the C and C++
+ standard, since their types are not the same, and so,
+ technically, an `int **' and `const int **' cannot point at
+ the same thing.
+
+ But, the standard is wrong. In particular, this code is
+ legal C++:
+
+ int *ip;
+ int **ipp = &ip;
+ const int* const* cipp = ipp;
+ And, it doesn't make sense for that to be legal unless you
+ can dereference IPP and CIPP. So, we ignore cv-qualifiers on
+ the pointed-to types. This issue has been reported to the
+ C++ committee. */
+ t1 = build_type_no_quals (t);
+ if (t1 != t)
+ return get_alias_set (t1);
+ }
return -1;
}
Index: gcc/lto/lto.c
===================================================================
*** gcc/lto/lto.c.orig 2009-08-17 12:59:36.000000000 +0200
--- gcc/lto/lto.c 2009-08-17 13:00:07.000000000 +0200
*************** lto_fixup_field_decl (tree t, void *data
*** 1202,1207 ****
--- 1202,1209 ----
static void
lto_fixup_type (tree t, void *data)
{
+ tree tem;
+
lto_fixup_common (t, data);
LTO_FIXUP_SUBTREE (TYPE_CACHED_VALUES (t));
LTO_FIXUP_SUBTREE (TYPE_SIZE (t));
*************** lto_fixup_type (tree t, void *data)
*** 1215,1221 ****
LTO_FIXUP_SUBTREE (t->type.minval);
LTO_FIXUP_SUBTREE (t->type.maxval);
! LTO_FIXUP_SUBTREE (TYPE_NEXT_VARIANT (t));
LTO_FIXUP_SUBTREE (TYPE_MAIN_VARIANT (t));
/* Accessor is for derived node types only. */
--- 1217,1262 ----
LTO_FIXUP_SUBTREE (t->type.minval);
LTO_FIXUP_SUBTREE (t->type.maxval);
! /* When we get a new main variant type unlink us from the old
! variant list and put us on the new one. This will queue up
! a lot of variant types which we might want to unlink
! automatically in gimple_register_type. */
! tem = gimple_register_type (TYPE_MAIN_VARIANT (t));
! if (tem != TYPE_MAIN_VARIANT (t))
! {
! /* Unlink us from the chain. If we were a main variant, adjust
! our siblings first - they will unlink themselves. */
! if (TYPE_MAIN_VARIANT (t) == t)
! LTO_FIXUP_SUBTREE (TYPE_NEXT_VARIANT (t));
! else
! {
! tree tem2 = TYPE_MAIN_VARIANT (t);
! while (tem2 && TYPE_NEXT_VARIANT (tem2) != t)
! tem2 = TYPE_NEXT_VARIANT (tem2);
! /* We might be not on our main variants list as we are
! unlinked from it in gimple_register_type in case we
! have a duplicate. */
! if (tem2)
! {
! TYPE_NEXT_VARIANT (tem2) = TYPE_NEXT_VARIANT (t);
! TYPE_NEXT_VARIANT (t) = NULL_TREE;
! }
! }
! gcc_assert (TYPE_NEXT_VARIANT (t) == NULL_TREE);
!
! /* If we became our main variant, there is nothing to do.
! Else link us in the list of variants. */
! if (tem == t)
! ;
! else
! {
! TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (tem);
! TYPE_NEXT_VARIANT (tem) = t;
! }
!
! /* Finally update our main variant link. */
! TYPE_MAIN_VARIANT (t) = tem;
! }
LTO_FIXUP_SUBTREE (TYPE_MAIN_VARIANT (t));
/* Accessor is for derived node types only. */
*************** lto_fixup_binfo (tree t, void *data)
*** 1259,1264 ****
--- 1300,1324 ----
}
}
+ /* Fix up fields of a CONSTRUCTOR T. DATA points to fix-up states. */
+
+ static void
+ lto_fixup_constructor (tree t, void *data)
+ {
+ unsigned HOST_WIDE_INT idx;
+ constructor_elt *ce;
+
+ LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TREE_TYPE (t));
+
+ for (idx = 0;
+ VEC_iterate(constructor_elt, CONSTRUCTOR_ELTS (t), idx, ce);
+ idx++)
+ {
+ LTO_FIXUP_SUBTREE (ce->index);
+ LTO_FIXUP_SUBTREE (ce->value);
+ }
+ }
+
/* A walk_tree callback used by lto_fixup_state. TP is the pointer to the
current tree. WALK_SUBTREES indicates if the subtrees will be walked.
DATA is a pointer set to record visited nodes. */
*************** lto_fixup_tree (tree *tp, int *walk_subt
*** 1312,1317 ****
--- 1372,1384 ----
t = prevailing;
}
}
+ else if (TYPE_P (t))
+ {
+ /* Replace t with the prevailing type. We don't want to insert the
+ other type in the seen set as we want to replace all instances of it. */
+ t = gimple_register_type (t);
+ *tp = t;
+ }
pointer_set_insert (fixup_data->seen, t);
*************** lto_fixup_tree (tree *tp, int *walk_subt
*** 1350,1355 ****
--- 1417,1426 ----
default:
if (TYPE_P (t))
lto_fixup_type (t, data);
+ else if (TREE_CODE (t) == CONSTRUCTOR)
+ lto_fixup_constructor (t, data);
+ else if (CONSTANT_CLASS_P (t))
+ LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TREE_TYPE (t));
else if (EXPR_P (t))
{
/* walk_tree only handles TREE_OPERANDs. Do the rest here. */
Index: gcc/tree.c
===================================================================
*** gcc/tree.c.orig 2009-08-17 12:59:36.000000000 +0200
--- gcc/tree.c 2009-08-17 16:18:11.000000000 +0200
*************** free_lang_data_in_type (tree type)
*** 4223,4237 ****
/* FIXME lto: This will break debug info generation. */
TYPE_STUB_DECL (type) = NULL_TREE;
! /* Remove type variants other than the main variant. This is both
! wasteful and it may introduce infinite loops when the types are
! read from disk and merged (since the variant will be the same
! type as the main variant, traversing type variants will get into
! an infinite loop). */
! if (TYPE_MAIN_VARIANT (type))
! TYPE_NEXT_VARIANT (TYPE_MAIN_VARIANT (type)) = NULL_TREE;
!
! TYPE_NEXT_VARIANT (type) = NULL_TREE;
}
--- 4223,4244 ----
/* FIXME lto: This will break debug info generation. */
TYPE_STUB_DECL (type) = NULL_TREE;
! {
! tree tem = TYPE_MAIN_VARIANT (type);
! while (tem && tem != type)
! {
! gcc_assert (TYPE_MAIN_VARIANT (tem) == TYPE_MAIN_VARIANT (type));
! gcc_assert (TYPE_NEXT_VARIANT (tem) != tem);
! tem = TYPE_NEXT_VARIANT (tem);
! }
! gcc_assert (tem != NULL_TREE);
! while (TYPE_NEXT_VARIANT (tem))
! {
! gcc_assert (TYPE_MAIN_VARIANT (tem) == TYPE_MAIN_VARIANT (type));
! gcc_assert (TYPE_NEXT_VARIANT (tem) != tem);
! tem = TYPE_NEXT_VARIANT (tem);
! }
! }
}
*************** free_lang_data_in_block (tree fn, tree b
*** 4288,4293 ****
--- 4295,4316 ----
tp = &TREE_CHAIN (*tp);
}
+ /* Also remove the vars from the abstract origin as we stream that out
+ being confused about CONST_DECLs with non-NULL DECL_CONTEXT.
+ FIXME lto. Better would be to allow non-NULL DECL_CONTEXT there. */
+ if (BLOCK_ABSTRACT_ORIGIN (block)
+ && TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block)) == BLOCK)
+ {
+ tp = &BLOCK_VARS (BLOCK_ABSTRACT_ORIGIN (block));
+ while (*tp)
+ {
+ if (!pointer_set_contains (locals, *tp))
+ *tp = TREE_CHAIN (*tp);
+ else
+ tp = &TREE_CHAIN (*tp);
+ }
+ }
+
for (t = BLOCK_SUBBLOCKS (block); t; t = BLOCK_CHAIN (t))
free_lang_data_in_block (fn, t, locals);
}
Index: gcc/lto-streamer-out.c
===================================================================
*** gcc/lto-streamer-out.c.orig 2009-08-17 12:59:36.000000000 +0200
--- gcc/lto-streamer-out.c 2009-08-17 16:20:07.000000000 +0200
*************** output_record_start (struct output_block
*** 367,378 ****
static void
output_type_ref (struct output_block *ob, tree node)
{
- /* FIXME lto. This is a hack, the use of -funsigned-char should be
- reflected in the IL by changing every reference to char_type_node
- into unsigned_char_type_node in pass_ipa_free_lang_data. */
- if (flag_signed_char == 0 && node == char_type_node)
- node = unsigned_char_type_node;
-
output_record_start (ob, LTO_type_ref);
lto_output_type_ref_index (ob->decl_state, ob->main_stream, node);
}
--- 367,372 ----
*************** lto_output_ts_type_tree_pointers (struct
*** 1072,1078 ****
lto_output_tree_or_ref (ob, TYPE_NAME (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MINVAL (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MAXVAL (expr), ref_p);
! lto_output_tree_or_ref (ob, TYPE_NEXT_VARIANT (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MAIN_VARIANT (expr), ref_p);
if (TREE_CODE (expr) == RECORD_TYPE || TREE_CODE (expr) == UNION_TYPE)
lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
--- 1066,1092 ----
lto_output_tree_or_ref (ob, TYPE_NAME (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MINVAL (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MAXVAL (expr), ref_p);
! {
! tree tem = TYPE_MAIN_VARIANT (expr);
! while (tem && tem != expr)
! {
! gcc_assert (TYPE_MAIN_VARIANT (tem) == TYPE_MAIN_VARIANT (expr));
! gcc_assert (TYPE_NEXT_VARIANT (tem) != tem);
! tem = TYPE_NEXT_VARIANT (tem);
! }
! /* We can end up refering to types we shouldn't refer to but
! which register_gimple_type assigned to something else.
! Odd but happens. Should be harmless. */
! gcc_assert (tem != NULL_TREE);
! while (tem && TYPE_NEXT_VARIANT (tem))
! {
! gcc_assert (TYPE_MAIN_VARIANT (tem) == TYPE_MAIN_VARIANT (expr));
! gcc_assert (TYPE_NEXT_VARIANT (tem) != tem);
! tem = TYPE_NEXT_VARIANT (tem);
! }
! }
! /* Do not output TYPE_NEXT_VARIANT, it will be re-constructed on-the-fly
! on read-in. */
lto_output_tree_or_ref (ob, TYPE_MAIN_VARIANT (expr), ref_p);
if (TREE_CODE (expr) == RECORD_TYPE || TREE_CODE (expr) == UNION_TYPE)
lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
*************** lto_write_tree (struct output_block *ob,
*** 1385,1390 ****
--- 1399,1409 ----
{
struct bitpack_d *bp;
+ /* If we are streaming out a type make sure it is the canonical variant. */
+ if (flag_wpa
+ && TYPE_P (expr))
+ gcc_assert (expr == gimple_register_type (expr));
+
/* Write the header, containing everything needed to materialize
EXPR on the reading side. */
lto_output_tree_header (ob, expr, ix);
Index: gcc/lto-streamer-in.c
===================================================================
*** gcc/lto-streamer-in.c.orig 2009-08-17 12:59:36.000000000 +0200
--- gcc/lto-streamer-in.c 2009-08-17 13:00:07.000000000 +0200
*************** lto_input_ts_type_tree_pointers (struct
*** 1990,1997 ****
TYPE_NAME (expr) = lto_input_tree (ib, data_in);
TYPE_MINVAL (expr) = lto_input_tree (ib, data_in);
TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in);
- TYPE_NEXT_VARIANT (expr) = lto_input_tree (ib, data_in);
TYPE_MAIN_VARIANT (expr) = lto_input_tree (ib, data_in);
if (TREE_CODE (expr) == RECORD_TYPE || TREE_CODE (expr) == UNION_TYPE)
TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
TYPE_CONTEXT (expr) = lto_input_tree (ib, data_in);
--- 1990,2004 ----
TYPE_NAME (expr) = lto_input_tree (ib, data_in);
TYPE_MINVAL (expr) = lto_input_tree (ib, data_in);
TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in);
TYPE_MAIN_VARIANT (expr) = lto_input_tree (ib, data_in);
+ /* Queue the node in the main variant chain. We can't stream the
+ next variant because we might pick up a common tree node as
+ our main variant. */
+ if (TYPE_MAIN_VARIANT (expr) != expr)
+ {
+ TYPE_NEXT_VARIANT (expr) = TYPE_NEXT_VARIANT (TYPE_MAIN_VARIANT (expr));
+ TYPE_NEXT_VARIANT (TYPE_MAIN_VARIANT (expr)) = expr;
+ }
if (TREE_CODE (expr) == RECORD_TYPE || TREE_CODE (expr) == UNION_TYPE)
TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
TYPE_CONTEXT (expr) = lto_input_tree (ib, data_in);
Index: gcc/cp/decl.c
===================================================================
*** gcc/cp/decl.c.orig 2009-08-17 12:59:36.000000000 +0200
--- gcc/cp/decl.c 2009-08-17 13:00:07.000000000 +0200
*************** build_ptrmemfunc_type (tree type)
*** 7056,7065 ****
/* If this is not the unqualified form of this pointer-to-member
type, set the TYPE_MAIN_VARIANT for this type to be the
unqualified type. Since they are actually RECORD_TYPEs that are
! not variants of each other, we must do this manually. */
if (cp_type_quals (type) != TYPE_UNQUALIFIED)
{
! t = build_qualified_type (t, cp_type_quals (type));
TYPE_MAIN_VARIANT (t) = unqualified_variant;
TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (unqualified_variant);
TYPE_NEXT_VARIANT (unqualified_variant) = t;
--- 7056,7069 ----
/* If this is not the unqualified form of this pointer-to-member
type, set the TYPE_MAIN_VARIANT for this type to be the
unqualified type. Since they are actually RECORD_TYPEs that are
! not variants of each other, we must do this manually.
! As we just built a new type there is no need to do yet another copy. */
if (cp_type_quals (type) != TYPE_UNQUALIFIED)
{
! int type_quals = cp_type_quals (type);
! TYPE_READONLY (t) = (type_quals & TYPE_QUAL_CONST) != 0;
! TYPE_VOLATILE (t) = (type_quals & TYPE_QUAL_VOLATILE) != 0;
! TYPE_RESTRICT (t) = (type_quals & TYPE_QUAL_RESTRICT) != 0;
TYPE_MAIN_VARIANT (t) = unqualified_variant;
TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (unqualified_variant);
TYPE_NEXT_VARIANT (unqualified_variant) = t;
*************** finish_enum (tree enumtype)
*** 11164,11170 ****
/* Set the underlying type of the enumeration type to the
computed enumeration type, restricted to the enumerator
values. */
! ENUM_UNDERLYING_TYPE (enumtype) = copy_node (underlying_type);
set_min_and_max_values_for_integral_type
(ENUM_UNDERLYING_TYPE (enumtype), precision, unsignedp);
}
--- 11168,11175 ----
/* Set the underlying type of the enumeration type to the
computed enumeration type, restricted to the enumerator
values. */
! ENUM_UNDERLYING_TYPE (enumtype)
! = build_distinct_type_copy (underlying_type);
set_min_and_max_values_for_integral_type
(ENUM_UNDERLYING_TYPE (enumtype), precision, unsignedp);
}
Index: gcc/cp/tree.c
===================================================================
*** gcc/cp/tree.c.orig 2009-08-17 12:59:36.000000000 +0200
--- gcc/cp/tree.c 2009-08-17 13:00:07.000000000 +0200
*************** cp_build_reference_type (tree to_type, b
*** 700,711 ****
if (TYPE_REF_IS_RVALUE (t))
return t;
! t = copy_node (lvalue_ref);
TYPE_REF_IS_RVALUE (t) = true;
TYPE_NEXT_REF_TO (t) = TYPE_NEXT_REF_TO (lvalue_ref);
TYPE_NEXT_REF_TO (lvalue_ref) = t;
- TYPE_MAIN_VARIANT (t) = t;
if (TYPE_STRUCTURAL_EQUALITY_P (to_type))
SET_TYPE_STRUCTURAL_EQUALITY (t);
--- 700,710 ----
if (TYPE_REF_IS_RVALUE (t))
return t;
! t = build_distinct_type_copy (lvalue_ref);
TYPE_REF_IS_RVALUE (t) = true;
TYPE_NEXT_REF_TO (t) = TYPE_NEXT_REF_TO (lvalue_ref);
TYPE_NEXT_REF_TO (lvalue_ref) = t;
if (TYPE_STRUCTURAL_EQUALITY_P (to_type))
SET_TYPE_STRUCTURAL_EQUALITY (t);
Index: gcc/fortran/trans-expr.c
===================================================================
*** gcc/fortran/trans-expr.c.orig 2009-08-17 12:59:36.000000000 +0200
--- gcc/fortran/trans-expr.c 2009-08-17 13:00:07.000000000 +0200
*************** gfc_trans_scalar_assign (gfc_se * lse, g
*** 4432,4460 ****
gfc_add_expr_to_block (&block, tmp);
}
}
else
{
gfc_add_block_to_block (&block, &lse->pre);
gfc_add_block_to_block (&block, &rse->pre);
- /* TODO This is rather obviously the wrong place to do this.
- However, a number of testcases, such as function_kinds_1
- and function_types_2 fail without it, by ICEing at
- fold_const: 2710 (fold_convert_loc). */
- if (ts.type == BT_DERIVED
- && gfc_option.flag_whole_file
- && (TYPE_MAIN_VARIANT (TREE_TYPE (rse->expr))
- != TYPE_MAIN_VARIANT (TREE_TYPE (lse->expr))))
- {
- tmp = gfc_evaluate_now (rse->expr, &block);
- TYPE_MAIN_VARIANT (TREE_TYPE (tmp))
- = TYPE_MAIN_VARIANT (TREE_TYPE (lse->expr));
- }
- else
- tmp = rse->expr;
-
gfc_add_modify (&block, lse->expr,
! fold_convert (TREE_TYPE (lse->expr), tmp));
}
gfc_add_block_to_block (&block, &lse->post);
--- 4432,4452 ----
gfc_add_expr_to_block (&block, tmp);
}
}
+ else if (ts.type == BT_DERIVED)
+ {
+ gfc_add_block_to_block (&block, &lse->pre);
+ gfc_add_block_to_block (&block, &rse->pre);
+ tmp = gfc_evaluate_now (rse->expr, &block);
+ tmp = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lse->expr), rse->expr);
+ gfc_add_modify (&block, lse->expr, tmp);
+ }
else
{
gfc_add_block_to_block (&block, &lse->pre);
gfc_add_block_to_block (&block, &rse->pre);
gfc_add_modify (&block, lse->expr,
! fold_convert (TREE_TYPE (lse->expr), rse->expr));
}
gfc_add_block_to_block (&block, &lse->post);
Index: gcc/lto-streamer.c
===================================================================
*** gcc/lto-streamer.c.orig 2009-08-17 13:00:06.000000000 +0200
--- gcc/lto-streamer.c 2009-08-17 16:20:06.000000000 +0200
*************** lto_streamer_cache_insert_1 (struct lto_
*** 500,511 ****
gcc_assert (t);
- /* If -funsigned-char is given, replace references to 'char' with
- 'unsigned char'. FIXME lto, this should be done in
- free_lang_data. */
- if (flag_signed_char == 0 && TYPE_P (t) && t == char_type_node)
- t = unsigned_char_type_node;
-
d_entry.base.from = t;
slot = htab_find_slot (cache->node_map, &d_entry, INSERT);
if (*slot == NULL)
--- 500,505 ----
*************** lto_streamer_cache_insert_1 (struct lto_
*** 556,561 ****
--- 550,558 ----
stream is not necessary as we will not need to read
forward in the stream. */
lto_streamer_cache_add_to_node_array (cache, ix, t, -1);
+
+ if (getenv ("STREAMER_DEBUG"))
+ fprintf (stderr, "duplicate ");
}
/* Indicate that T was already in the cache. */
*************** lto_streamer_cache_insert_1 (struct lto_
*** 568,573 ****
--- 565,576 ----
if (offset_p)
*offset_p = offset;
+ if (getenv ("STREAMER_DEBUG"))
+ {
+ fprintf (stderr, "inserting at %i[%u]%s ", ix, offset,
+ existed_p ? " (present)" : "");
+ print_generic_stmt (stderr, t, 0);
+ }
return existed_p;
}
*************** lto_streamer_cache_get (struct lto_strea
*** 662,673 ****
SEEN_NODES. */
static void
! lto_record_common_node (tree node, VEC(tree, heap) **common_nodes,
struct pointer_set_t *seen_nodes)
{
if (node == NULL_TREE)
return;
/* Return if node is already seen. */
if (pointer_set_insert (seen_nodes, node))
return;
--- 665,681 ----
SEEN_NODES. */
static void
! lto_record_common_node (tree *nodep, VEC(tree, heap) **common_nodes,
struct pointer_set_t *seen_nodes)
{
+ tree node = *nodep;
+
if (node == NULL_TREE)
return;
+ if (TYPE_P (node))
+ *nodep = node = gimple_register_type (node);
+
/* Return if node is already seen. */
if (pointer_set_insert (seen_nodes, node))
return;
*************** lto_record_common_node (tree node, VEC(t
*** 676,693 ****
if (tree_node_can_be_shared (node))
{
! if (TYPE_P (node))
! lto_record_common_node (TYPE_MAIN_VARIANT (node), common_nodes,
! seen_nodes);
!
! if (TREE_CODE (node) == ARRAY_TYPE)
! lto_record_common_node (TREE_TYPE (node), common_nodes, seen_nodes);
}
}
! /* Generate a vector of common nodes and register them in the gimple
! type table as merge targets. */
static VEC(tree,heap) *
lto_get_common_nodes (void)
--- 684,699 ----
if (tree_node_can_be_shared (node))
{
! if (POINTER_TYPE_P (node)
! || TREE_CODE (node) == COMPLEX_TYPE
! || TREE_CODE (node) == ARRAY_TYPE)
! lto_record_common_node (&TREE_TYPE (node), common_nodes, seen_nodes);
}
}
! /* Generate a vector of common nodes and make sure they are merged
! properly according to the the gimple type table. */
static VEC(tree,heap) *
lto_get_common_nodes (void)
*************** lto_get_common_nodes (void)
*** 720,753 ****
seen_nodes = pointer_set_create ();
- /* char_type_node is special, we have to prefer merging the other
- char variants into it because the middle-end has pointer comparisons
- with it. */
- gimple_register_type (char_type_node);
-
- for (i = 0; i < TI_MAX; i++)
- {
- tree t = global_trees[i];
- if (t && TYPE_P (t))
- gimple_register_type (t);
- lto_record_common_node (global_trees[i], &common_nodes, seen_nodes);
- }
-
for (i = 0; i < itk_none; i++)
! {
! tree t = integer_types[i];
! if (t && TYPE_P (t))
! gimple_register_type (t);
! lto_record_common_node (integer_types[i], &common_nodes, seen_nodes);
! }
for (i = 0; i < TYPE_KIND_LAST; i++)
! {
! tree t = sizetype_tab[i];
! if (t && TYPE_P (t))
! gimple_register_type (t);
! lto_record_common_node (sizetype_tab[i], &common_nodes, seen_nodes);
! }
pointer_set_destroy (seen_nodes);
--- 726,739 ----
seen_nodes = pointer_set_create ();
for (i = 0; i < itk_none; i++)
! lto_record_common_node (&integer_types[i], &common_nodes, seen_nodes);
for (i = 0; i < TYPE_KIND_LAST; i++)
! lto_record_common_node (&sizetype_tab[i], &common_nodes, seen_nodes);
!
! for (i = 0; i < TI_MAX; i++)
! lto_record_common_node (&global_trees[i], &common_nodes, seen_nodes);
pointer_set_destroy (seen_nodes);
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH][LTO] Clean up type variant handling, allow bootstrap
2009-08-17 15:46 [PATCH][LTO] Clean up type variant handling, allow bootstrap Richard Guenther
@ 2009-08-17 16:53 ` Diego Novillo
2009-08-18 12:11 ` Richard Guenther
0 siblings, 1 reply; 3+ messages in thread
From: Diego Novillo @ 2009-08-17 16:53 UTC (permalink / raw)
To: Richard Guenther; +Cc: gcc-patches
On Mon, Aug 17, 2009 at 10:33, Richard Guenther<rguenther@suse.de> wrote:
> The free_lang_data_in_block change is also odd - I am hitting
> CONST_DECLs with a FUNCTION_DECL context during streaming out
> of the abstract origin of a function. But we assert that the
> decl-context of all CONST_DECLs is NULL - for some reason.
> The hack will pessimize debug info some more. Why again do we
> not want to stream DECL_CONTEXT properly?
Initially, we were pulling in C++-specific trees this way. If it's no
longer needed, then that's fine.
> Any comments?
All that fixup code for WPA is a bit odd, but that is something we can
leave for later.
Diego.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH][LTO] Clean up type variant handling, allow bootstrap
2009-08-17 16:53 ` Diego Novillo
@ 2009-08-18 12:11 ` Richard Guenther
0 siblings, 0 replies; 3+ messages in thread
From: Richard Guenther @ 2009-08-18 12:11 UTC (permalink / raw)
To: Diego Novillo; +Cc: gcc-patches
[-- Attachment #1: Type: TEXT/PLAIN, Size: 13663 bytes --]
On Mon, 17 Aug 2009, Diego Novillo wrote:
> On Mon, Aug 17, 2009 at 10:33, Richard Guenther<rguenther@suse.de> wrote:
>
> > The free_lang_data_in_block change is also odd - I am hitting
> > CONST_DECLs with a FUNCTION_DECL context during streaming out
> > of the abstract origin of a function. Â But we assert that the
> > decl-context of all CONST_DECLs is NULL - for some reason.
> > The hack will pessimize debug info some more. Â Why again do we
> > not want to stream DECL_CONTEXT properly?
>
> Initially, we were pulling in C++-specific trees this way. If it's no
> longer needed, then that's fine.
>
> > Any comments?
>
> All that fixup code for WPA is a bit odd, but that is something we can
> leave for later.
Well, currently we do not fixup types TYPE_MAIN_VARIANT at all
(thus, it stays the non-merged variants). This sounds wrong.
And just fixing that runs into issues with WPA.
We may not need to keep the variant chains, and the other lto_fixup_*
changes are to fix the asserts I placed (mainly the assert that for
WPA we only stream the canonical merged type variants).
I will test the following less invasive change (we can resort to
the variant chain rebuilding variant later if it works out).
It will break g++.dg/lto/pr40818 due to the CONST_DECL issue at least
(I don't like my BLOCK_ABSTRACT_ORIGIN hack there).
Probably the other lto_fixup_* changes are useful for memory usage
reasons (otherwise we'll keep references to that unused types).
So, if the following bootstraps and tests on and it fixes the bootstrap
with -flto issue as well then I'm going to apply that despite the
two regressions I know it will cause.
Richard.
2009-08-17 Richard Guenther <rguenther@suse.de>
PR lto/41071
* gimple.c (compare_type_names_p): Do not look at the
types main variant.
(gimple_get_alias_set): Pointers to CV qualified variants
have the same alias-set as unqualified variants.
* lto-streamer-out.c (lto_output_ts_type_tree_pointers): Do
not output TYPE_NEXT_VARIANT.
(output_type_ref): Remove hack for char_type_node.
* lto-streamer-in.c (lto_input_ts_type_tree_pointers): Do not
input TYPE_NEXT_VARIANT.
* lto-streamer.c (lto_streamer_cache_insert_1): Add debugging code.
Remove hack for char_type_node.
(lto_record_common_node): Canonicalize types of nodes we record.
(lto_get_common_nodes): Record integer and size types first.
Defer to lto_record_common_node for registering and canonicalizing
types.
lto/
* lto.c (lto_fixup_type): Fixup the types main-variant. Zero
the types next-variant.
Index: gcc/gimple.c
===================================================================
*** gcc/gimple.c.orig 2009-08-18 12:37:36.000000000 +0200
--- gcc/gimple.c 2009-08-18 12:37:53.000000000 +0200
*************** lookup_type_pair (tree t1, tree t2, htab
*** 3185,3192 ****
static bool
compare_type_names_p (tree t1, tree t2)
{
- tree variant1 = TYPE_MAIN_VARIANT (t1);
- tree variant2 = TYPE_MAIN_VARIANT (t2);
tree name1 = TYPE_NAME (t1);
tree name2 = TYPE_NAME (t2);
--- 3185,3190 ----
*************** compare_type_names_p (tree t1, tree t2)
*** 3215,3228 ****
if (name1 == name2)
return true;
- /* If either type has a variant type, compare that. This finds
- the case where a struct is typedef'ed in one module but referred
- to as 'struct foo' in the other; here, the main type for one is
- 'foo', and for the other 'foo_t', but the variants have the same
- name 'foo'. */
- if (variant1 != t1 || variant2 != t2)
- return compare_type_names_p (variant1, variant2);
-
return false;
}
--- 3213,3218 ----
*************** gimple_get_alias_set (tree t)
*** 4183,4188 ****
--- 4173,4208 ----
if (t1 != t)
return get_alias_set (t1);
}
+ else if (POINTER_TYPE_P (t))
+ {
+ tree t1;
+
+ /* Unfortunately, there is no canonical form of a pointer type.
+ In particular, if we have `typedef int I', then `int *', and
+ `I *' are different types. So, we have to pick a canonical
+ representative. We do this below.
+
+ Technically, this approach is actually more conservative that
+ it needs to be. In particular, `const int *' and `int *'
+ should be in different alias sets, according to the C and C++
+ standard, since their types are not the same, and so,
+ technically, an `int **' and `const int **' cannot point at
+ the same thing.
+
+ But, the standard is wrong. In particular, this code is
+ legal C++:
+
+ int *ip;
+ int **ipp = &ip;
+ const int* const* cipp = ipp;
+ And, it doesn't make sense for that to be legal unless you
+ can dereference IPP and CIPP. So, we ignore cv-qualifiers on
+ the pointed-to types. This issue has been reported to the
+ C++ committee. */
+ t1 = build_type_no_quals (t);
+ if (t1 != t)
+ return get_alias_set (t1);
+ }
return -1;
}
Index: gcc/lto-streamer-out.c
===================================================================
*** gcc/lto-streamer-out.c.orig 2009-08-18 12:37:36.000000000 +0200
--- gcc/lto-streamer-out.c 2009-08-18 12:37:53.000000000 +0200
*************** output_record_start (struct output_block
*** 367,378 ****
static void
output_type_ref (struct output_block *ob, tree node)
{
- /* FIXME lto. This is a hack, the use of -funsigned-char should be
- reflected in the IL by changing every reference to char_type_node
- into unsigned_char_type_node in pass_ipa_free_lang_data. */
- if (flag_signed_char == 0 && node == char_type_node)
- node = unsigned_char_type_node;
-
output_record_start (ob, LTO_type_ref);
lto_output_type_ref_index (ob->decl_state, ob->main_stream, node);
}
--- 367,372 ----
*************** lto_output_ts_type_tree_pointers (struct
*** 1072,1079 ****
lto_output_tree_or_ref (ob, TYPE_NAME (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MINVAL (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MAXVAL (expr), ref_p);
- lto_output_tree_or_ref (ob, TYPE_NEXT_VARIANT (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MAIN_VARIANT (expr), ref_p);
if (TREE_CODE (expr) == RECORD_TYPE || TREE_CODE (expr) == UNION_TYPE)
lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_CONTEXT (expr), ref_p);
--- 1066,1073 ----
lto_output_tree_or_ref (ob, TYPE_NAME (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MINVAL (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MAXVAL (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_MAIN_VARIANT (expr), ref_p);
+ /* Do not stream out TYPE_NEXT_VARIANT. */
if (TREE_CODE (expr) == RECORD_TYPE || TREE_CODE (expr) == UNION_TYPE)
lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
lto_output_tree_or_ref (ob, TYPE_CONTEXT (expr), ref_p);
Index: gcc/lto-streamer.c
===================================================================
*** gcc/lto-streamer.c.orig 2009-08-18 12:37:36.000000000 +0200
--- gcc/lto-streamer.c 2009-08-18 12:37:53.000000000 +0200
*************** lto_streamer_cache_insert_1 (struct lto_
*** 500,511 ****
gcc_assert (t);
- /* If -funsigned-char is given, replace references to 'char' with
- 'unsigned char'. FIXME lto, this should be done in
- free_lang_data. */
- if (flag_signed_char == 0 && TYPE_P (t) && t == char_type_node)
- t = unsigned_char_type_node;
-
d_entry.base.from = t;
slot = htab_find_slot (cache->node_map, &d_entry, INSERT);
if (*slot == NULL)
--- 500,505 ----
*************** lto_streamer_cache_insert_1 (struct lto_
*** 556,561 ****
--- 550,558 ----
stream is not necessary as we will not need to read
forward in the stream. */
lto_streamer_cache_add_to_node_array (cache, ix, t, -1);
+
+ if (getenv ("STREAMER_DEBUG"))
+ fprintf (stderr, "duplicate ");
}
/* Indicate that T was already in the cache. */
*************** lto_streamer_cache_insert_1 (struct lto_
*** 568,573 ****
--- 565,576 ----
if (offset_p)
*offset_p = offset;
+ if (getenv ("STREAMER_DEBUG"))
+ {
+ fprintf (stderr, "inserting at %i[%u]%s ", ix, offset,
+ existed_p ? " (present)" : "");
+ print_generic_stmt (stderr, t, 0);
+ }
return existed_p;
}
*************** lto_streamer_cache_get (struct lto_strea
*** 662,673 ****
SEEN_NODES. */
static void
! lto_record_common_node (tree node, VEC(tree, heap) **common_nodes,
struct pointer_set_t *seen_nodes)
{
if (node == NULL_TREE)
return;
/* Return if node is already seen. */
if (pointer_set_insert (seen_nodes, node))
return;
--- 665,681 ----
SEEN_NODES. */
static void
! lto_record_common_node (tree *nodep, VEC(tree, heap) **common_nodes,
struct pointer_set_t *seen_nodes)
{
+ tree node = *nodep;
+
if (node == NULL_TREE)
return;
+ if (TYPE_P (node))
+ *nodep = node = gimple_register_type (node);
+
/* Return if node is already seen. */
if (pointer_set_insert (seen_nodes, node))
return;
*************** lto_record_common_node (tree node, VEC(t
*** 676,693 ****
if (tree_node_can_be_shared (node))
{
! if (TYPE_P (node))
! lto_record_common_node (TYPE_MAIN_VARIANT (node), common_nodes,
! seen_nodes);
!
! if (TREE_CODE (node) == ARRAY_TYPE)
! lto_record_common_node (TREE_TYPE (node), common_nodes, seen_nodes);
}
}
! /* Generate a vector of common nodes and register them in the gimple
! type table as merge targets. */
static VEC(tree,heap) *
lto_get_common_nodes (void)
--- 684,699 ----
if (tree_node_can_be_shared (node))
{
! if (POINTER_TYPE_P (node)
! || TREE_CODE (node) == COMPLEX_TYPE
! || TREE_CODE (node) == ARRAY_TYPE)
! lto_record_common_node (&TREE_TYPE (node), common_nodes, seen_nodes);
}
}
! /* Generate a vector of common nodes and make sure they are merged
! properly according to the the gimple type table. */
static VEC(tree,heap) *
lto_get_common_nodes (void)
*************** lto_get_common_nodes (void)
*** 720,753 ****
seen_nodes = pointer_set_create ();
- /* char_type_node is special, we have to prefer merging the other
- char variants into it because the middle-end has pointer comparisons
- with it. */
- gimple_register_type (char_type_node);
-
- for (i = 0; i < TI_MAX; i++)
- {
- tree t = global_trees[i];
- if (t && TYPE_P (t))
- gimple_register_type (t);
- lto_record_common_node (global_trees[i], &common_nodes, seen_nodes);
- }
-
for (i = 0; i < itk_none; i++)
! {
! tree t = integer_types[i];
! if (t && TYPE_P (t))
! gimple_register_type (t);
! lto_record_common_node (integer_types[i], &common_nodes, seen_nodes);
! }
for (i = 0; i < TYPE_KIND_LAST; i++)
! {
! tree t = sizetype_tab[i];
! if (t && TYPE_P (t))
! gimple_register_type (t);
! lto_record_common_node (sizetype_tab[i], &common_nodes, seen_nodes);
! }
pointer_set_destroy (seen_nodes);
--- 726,739 ----
seen_nodes = pointer_set_create ();
for (i = 0; i < itk_none; i++)
! lto_record_common_node (&integer_types[i], &common_nodes, seen_nodes);
for (i = 0; i < TYPE_KIND_LAST; i++)
! lto_record_common_node (&sizetype_tab[i], &common_nodes, seen_nodes);
!
! for (i = 0; i < TI_MAX; i++)
! lto_record_common_node (&global_trees[i], &common_nodes, seen_nodes);
pointer_set_destroy (seen_nodes);
Index: gcc/lto-streamer-in.c
===================================================================
*** gcc/lto-streamer-in.c.orig 2009-08-18 12:37:34.000000000 +0200
--- gcc/lto-streamer-in.c 2009-08-18 12:37:53.000000000 +0200
*************** lto_input_ts_type_tree_pointers (struct
*** 1990,1997 ****
TYPE_NAME (expr) = lto_input_tree (ib, data_in);
TYPE_MINVAL (expr) = lto_input_tree (ib, data_in);
TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in);
- TYPE_NEXT_VARIANT (expr) = lto_input_tree (ib, data_in);
TYPE_MAIN_VARIANT (expr) = lto_input_tree (ib, data_in);
if (TREE_CODE (expr) == RECORD_TYPE || TREE_CODE (expr) == UNION_TYPE)
TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
TYPE_CONTEXT (expr) = lto_input_tree (ib, data_in);
--- 1990,1997 ----
TYPE_NAME (expr) = lto_input_tree (ib, data_in);
TYPE_MINVAL (expr) = lto_input_tree (ib, data_in);
TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in);
TYPE_MAIN_VARIANT (expr) = lto_input_tree (ib, data_in);
+ /* We do not care about TYPE_NEXT_VARIANT. */
if (TREE_CODE (expr) == RECORD_TYPE || TREE_CODE (expr) == UNION_TYPE)
TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
TYPE_CONTEXT (expr) = lto_input_tree (ib, data_in);
Index: gcc/lto/lto.c
===================================================================
*** gcc/lto/lto.c.orig 2009-08-18 12:37:34.000000000 +0200
--- gcc/lto/lto.c 2009-08-18 12:37:53.000000000 +0200
*************** lto_fixup_type (tree t, void *data)
*** 1215,1222 ****
LTO_FIXUP_SUBTREE (t->type.minval);
LTO_FIXUP_SUBTREE (t->type.maxval);
! LTO_FIXUP_SUBTREE (TYPE_NEXT_VARIANT (t));
! LTO_FIXUP_SUBTREE (TYPE_MAIN_VARIANT (t));
/* Accessor is for derived node types only. */
LTO_FIXUP_SUBTREE (t->type.binfo);
--- 1215,1222 ----
LTO_FIXUP_SUBTREE (t->type.minval);
LTO_FIXUP_SUBTREE (t->type.maxval);
! LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TYPE_MAIN_VARIANT (t));
! TYPE_NEXT_VARIANT (t) = NULL_TREE;
/* Accessor is for derived node types only. */
LTO_FIXUP_SUBTREE (t->type.binfo);
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2009-08-18 10:41 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-08-17 15:46 [PATCH][LTO] Clean up type variant handling, allow bootstrap Richard Guenther
2009-08-17 16:53 ` Diego Novillo
2009-08-18 12:11 ` Richard Guenther
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).