This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[lto][patch] Update decl merging to use symbol resolution
- From: "Rafael Espindola" <espindola at google dot com>
- To: "GCC Patches" <gcc-patches at gcc dot gnu dot org>
- Cc: "Diego Novillo" <dnovillo at google dot com>
- Date: Thu, 25 Sep 2008 15:25:29 +0100
- Subject: [lto][patch] Update decl merging to use symbol resolution
While working to get lto1 to use the symbol resolution generated by
the linker, I noticed that lto_symtab_merge_decl is a bit confused (or
confusing) with two types of decl merging. The first one in what
happens in cc1 when looking at things like
--------------------------
extern int a;
int a;
--------------------------
In this case it should merge things like visibility if they differ.
The other case is lto1 looking at two object files. Here I don't think
there should be a merge. The implementation should overwrite the decl
if that is possible or abort with an error message.
This patch does that. lto_symtab_compatible could be improved a bit,
but I think this patch is already a good improvement as it is.
Bootstrapped and regression tested on linux x86-64.
2008-09-25 Rafael Espindola <espindola@google.com>
* lto-symtab.c (lto_symtab_compatible): New.
(lto_symtab_overwrite_decl): New.
(lto_symtab_merge_decl): Refactor to use the above functions
and the resolution from lang_identifier.
* lto-tree.h: Include plugin-api.h.
(lang_identifier): Add resolution.
(LTO_IDENTIFIER_RESOLUTION): New.
Cheers,
--
Rafael Avila de Espindola
Google | Gordon House | Barrow Street | Dublin 4 | Ireland
Registered in Dublin, Ireland | Registration Number: 368047
diff --git a/gcc/lto/lto-symtab.c b/gcc/lto/lto-symtab.c
index 2edea62..0c61a44 100644
--- a/gcc/lto/lto-symtab.c
+++ b/gcc/lto/lto-symtab.c
@@ -249,54 +249,14 @@ lto_least_common_multiple (unsigned a, unsigned b)
return (a * b) / gcd (a, b);
}
-/* Common helper function for merging variable and function declarations. */
-static tree
-lto_symtab_merge_decl (tree new_decl,
- enum ld_plugin_symbol_resolution resolution
- ATTRIBUTE_UNUSED)
-{
- tree old_decl;
- tree name;
+/* Check if OLD_DECL and NEW_DECL are compatible. */
+
+static bool
+lto_symtab_compatible (tree old_decl, tree new_decl)
+{
tree merged_type = NULL_TREE;
tree merged_result = NULL_TREE;
- gcc_assert (TREE_CODE (new_decl) == VAR_DECL
- || TREE_CODE (new_decl) == FUNCTION_DECL);
-
- /* Variables with internal linkage do not need to be merged.
- Note that we do not add these variables to lto_global_var_decls,
- as they have already been processed by rest_of_decl_compilation
- just after they were internalized by input_var_decl. */
- if (!TREE_PUBLIC (new_decl))
- return new_decl;
-
- /* Check that declarations reaching this function do not have
- properties inconsistent with having external linkage. If any of
- these asertions fail, then the object file reader has failed to
- detect these cases and issue appropriate error messages. */
- /* FIXME lto: The assertion below may fail incorrectly on a static
- class member. The problem seems to be the (documented) fact
- that DECL_NONLOCAL may be set for class instance variables as
- well as for variables referenced from inner functions. */
- /*gcc_assert (!DECL_NONLOCAL (new_decl));*/
- if (TREE_CODE (new_decl) == VAR_DECL)
- {
- gcc_assert (TREE_STATIC (new_decl));
- gcc_assert (!DECL_REGISTER (new_decl));
- gcc_assert (!(DECL_EXTERNAL (new_decl) && DECL_INITIAL (new_decl)));
- }
- /* Retrieve the previous declaration. */
- name = DECL_ASSEMBLER_NAME (new_decl);
- old_decl = LTO_IDENTIFIER_DECL (name);
- /* If there was no previous declaration, then there is nothing to
- merge. */
- if (!old_decl)
- {
- LTO_IDENTIFIER_DECL (name) = new_decl;
- VEC_safe_push (tree, gc, lto_global_var_decls, new_decl);
- return new_decl;
- }
- /* Check for inconsistencies. */
if (TREE_CODE (old_decl) != TREE_CODE (new_decl))
{
switch (TREE_CODE (new_decl))
@@ -304,11 +264,11 @@ lto_symtab_merge_decl (tree new_decl,
case VAR_DECL:
gcc_assert (TREE_CODE (old_decl) == FUNCTION_DECL);
error ("function %qD redeclared as variable", old_decl);
- return error_mark_node;
+ return false;
case FUNCTION_DECL:
gcc_assert (TREE_CODE (old_decl) == VAR_DECL);
error ("variable %qD redeclared as function", old_decl);
- return error_mark_node;
+ return false;
default:
gcc_unreachable ();
}
@@ -387,14 +347,14 @@ lto_symtab_merge_decl (tree new_decl,
{
error ("type of %qD does not match original declaration",
new_decl);
- return error_mark_node;
+ return false;
}
}
if (DECL_UNSIGNED (old_decl) != DECL_UNSIGNED (new_decl))
{
error ("signedness of %qD does not match original declaration",
new_decl);
- return error_mark_node;
+ return false;
}
if (!tree_int_cst_equal (DECL_SIZE (old_decl),
DECL_SIZE (new_decl))
@@ -414,7 +374,7 @@ lto_symtab_merge_decl (tree new_decl,
{
error ("size of %qD does not match original declaration",
new_decl);
- return error_mark_node;
+ return false;
}
}
/* Report an error if user-specified alignments do not match. */
@@ -423,7 +383,7 @@ lto_symtab_merge_decl (tree new_decl,
{
error ("alignment of %qD does not match original declaration",
new_decl);
- return error_mark_node;
+ return false;
}
if (DECL_MODE (old_decl) != DECL_MODE (new_decl))
{
@@ -440,7 +400,7 @@ lto_symtab_merge_decl (tree new_decl,
{
error ("machine mode of %qD does not match original declaration",
new_decl);
- return error_mark_node;
+ return false;
}
}
if (!lto_compatible_attributes_p (old_decl,
@@ -449,7 +409,7 @@ lto_symtab_merge_decl (tree new_decl,
{
error ("attributes applied to %qD are incompatible with original "
"declaration", new_decl);
- return error_mark_node;
+ return false;
}
/* FIXME: DWARF doesn't include a "weak" attribute, so where is that
info supposed to come from? */
@@ -465,7 +425,7 @@ lto_symtab_merge_decl (tree new_decl,
&& !DECL_IS_BUILTIN (new_decl))
{
error ("%qD has already been defined", new_decl);
- return error_mark_node;
+ return false;
}
/* We do not require matches for:
@@ -484,62 +444,126 @@ lto_symtab_merge_decl (tree new_decl,
object file.
Therefore, at this point we have decided to merge the declarations. */
- TREE_SIDE_EFFECTS (old_decl) |= TREE_SIDE_EFFECTS (new_decl);
- TREE_CONSTANT (old_decl) |= TREE_CONSTANT (new_decl);
- TREE_ADDRESSABLE (old_decl) |= TREE_ADDRESSABLE (new_decl);
- TREE_THIS_VOLATILE (old_decl) |= TREE_THIS_VOLATILE (new_decl);
- TREE_READONLY (old_decl) |= TREE_READONLY (new_decl);
- DECL_EXTERNAL (old_decl) &= DECL_EXTERNAL (new_decl);
-
- /* Adjust the alignment to the smallest common alignment. */
- if (DECL_ALIGN (old_decl) != DECL_ALIGN (new_decl))
- DECL_ALIGN (old_decl) = lto_least_common_multiple (DECL_ALIGN (old_decl),
- DECL_ALIGN (new_decl));
- /* If either alignment is user-specified, regard the merged alignment as such. */
- DECL_USER_ALIGN (old_decl) |= DECL_USER_ALIGN (new_decl);
-
- DECL_WEAK (old_decl) &= DECL_WEAK (new_decl);
- DECL_PRESERVE_P (old_decl) |= DECL_PRESERVE_P (new_decl);
- if (merged_type)
+ return true;
+}
+
+/* Overwrite DEST with SRC. */
+
+static void
+lto_symtab_overwrite_decl (tree dest, tree src)
+{
+ TREE_SIDE_EFFECTS (dest) = TREE_SIDE_EFFECTS (src);
+ TREE_CONSTANT (dest) = TREE_CONSTANT (src);
+ TREE_ADDRESSABLE (dest) = TREE_ADDRESSABLE (src);
+ TREE_THIS_VOLATILE (dest) = TREE_THIS_VOLATILE (src);
+ TREE_READONLY (dest) = TREE_READONLY (src);
+ DECL_EXTERNAL (dest) = DECL_EXTERNAL (src);
+
+ DECL_ALIGN (dest) = DECL_ALIGN (src);
+
+ DECL_USER_ALIGN (dest) = DECL_USER_ALIGN (src);
+
+ DECL_WEAK (dest) = DECL_WEAK (src);
+
+ DECL_PRESERVE_P (dest) = DECL_PRESERVE_P (src);
+
+ TREE_TYPE (dest) = TREE_TYPE (src);
+ DECL_MODE (dest) = DECL_MODE (src);
+
+ if (TREE_CODE (src) == FUNCTION_DECL)
{
- TREE_TYPE (old_decl) = merged_type;
- DECL_MODE (old_decl) = TYPE_MODE (merged_type);
- if (merged_result)
- {
- DECL_RESULT (old_decl) = merged_result;
- DECL_CONTEXT (DECL_RESULT (old_decl)) = old_decl;
- }
+ DECL_RESULT (dest) = DECL_RESULT (src);
+ if (DECL_RESULT (dest))
+ DECL_CONTEXT (DECL_RESULT (dest)) = dest;
+ TREE_STATIC (dest) = TREE_STATIC (src);
+ DECL_DECLARED_INLINE_P (dest) = DECL_DECLARED_INLINE_P (src);
+ }
+
+ if (TREE_CODE (src) == VAR_DECL)
+ {
+ DECL_INITIAL (dest) = DECL_INITIAL (src);
+ DECL_SIZE (dest) = DECL_SIZE (src);
+ DECL_SIZE_UNIT (dest) = DECL_SIZE_UNIT (src);
}
+}
+
+/* Common helper function for merging variable and function declarations. */
+static tree
+lto_symtab_merge_decl (tree new_decl,
+ enum ld_plugin_symbol_resolution resolution)
+{
+ tree old_decl;
+ tree name;
+ ld_plugin_symbol_resolution_t old_resolution;
+
+ gcc_assert (TREE_CODE (new_decl) == VAR_DECL
+ || TREE_CODE (new_decl) == FUNCTION_DECL);
+
+ gcc_assert (TREE_PUBLIC (new_decl));
+
+ /* Check that declarations reaching this function do not have
+ properties inconsistent with having external linkage. If any of
+ these asertions fail, then the object file reader has failed to
+ detect these cases and issue appropriate error messages. */
+ /* FIXME lto: The assertion below may fail incorrectly on a static
+ class member. The problem seems to be the (documented) fact
+ that DECL_NONLOCAL may be set for class instance variables as
+ well as for variables referenced from inner functions. */
+ /*gcc_assert (!DECL_NONLOCAL (new_decl));*/
if (TREE_CODE (new_decl) == VAR_DECL)
{
- if (DECL_INITIAL (new_decl))
- {
- gcc_assert (!DECL_INITIAL (old_decl));
- DECL_INITIAL (old_decl) = DECL_INITIAL (new_decl);
- }
- if (!DECL_SIZE (old_decl))
- {
- DECL_SIZE (old_decl) = DECL_SIZE (new_decl);
- DECL_SIZE_UNIT (old_decl) = DECL_SIZE_UNIT (new_decl);
- }
+ gcc_assert (TREE_STATIC (new_decl));
+ gcc_assert (!DECL_REGISTER (new_decl));
+ gcc_assert (!(DECL_EXTERNAL (new_decl) && DECL_INITIAL (new_decl)));
+ }
+ /* Retrieve the previous declaration. */
+ name = DECL_ASSEMBLER_NAME (new_decl);
+ old_decl = LTO_IDENTIFIER_DECL (name);
+ /* If there was no previous declaration, then there is nothing to
+ merge. */
+ if (!old_decl)
+ {
+ LTO_IDENTIFIER_DECL (name) = new_decl;
+ LTO_IDENTIFIER_RESOLUTION (name) = resolution;
+ VEC_safe_push (tree, gc, lto_global_var_decls, new_decl);
+ return new_decl;
}
- if (TREE_CODE (new_decl) == FUNCTION_DECL)
+
+ /* The linker may ask us to combine two incompatible symbols. */
+ if (!lto_symtab_compatible (old_decl, new_decl))
+ return error_mark_node;
+
+ old_resolution = LTO_IDENTIFIER_RESOLUTION (name);
+
+ gcc_assert (resolution != LDPR_UNKNOWN && resolution != LDPR_UNDEF
+ && old_resolution != LDPR_UNKNOWN
+ && old_resolution != LDPR_UNDEF);
+
+ if (resolution == LDPR_PREVAILING_DEF
+ || resolution == LDPR_PREVAILING_DEF_IRONLY)
{
- TREE_STATIC (old_decl) |= TREE_STATIC (new_decl);
- DECL_DECLARED_INLINE_P (old_decl) &= DECL_DECLARED_INLINE_P (new_decl);
- if (!DECL_RESULT (old_decl) && DECL_RESULT (new_decl))
- {
- DECL_RESULT (old_decl) = DECL_RESULT (new_decl);
- DECL_CONTEXT (DECL_RESULT (old_decl)) = old_decl;
- }
+ gcc_assert (old_resolution == LDPR_PREEMPTED_IR
+ || old_resolution == LDPR_RESOLVED_IR);
+ lto_symtab_overwrite_decl (old_decl, new_decl);
+ LTO_IDENTIFIER_RESOLUTION (name) = resolution;
+ return old_decl;
}
- /* We cannot free NEW_DECL just yet, as we still have a reference
- to it in the globals vector and possibly other places that need
- to be backpatched. Function global_vector_fixup is responsible
- for performing the backpatching, and then freeing the previous
- node that it replaced, which will be the node discarded here by
- the merge. */
+ if (resolution == LDPR_PREEMPTED_REG
+ || resolution == LDPR_RESOLVED_EXEC
+ || resolution == LDPR_RESOLVED_DYN)
+ gcc_assert (old_resolution == LDPR_PREEMPTED_REG
+ || old_resolution == LDPR_RESOLVED_EXEC
+ || old_resolution == LDPR_RESOLVED_DYN);
+
+ if (resolution == LDPR_PREEMPTED_IR
+ || resolution == LDPR_RESOLVED_IR)
+ gcc_assert (old_resolution == LDPR_PREVAILING_DEF
+ || old_resolution == LDPR_PREVAILING_DEF_IRONLY
+ || old_resolution == LDPR_PREEMPTED_IR
+ || old_resolution == LDPR_RESOLVED_IR);
+
+ lto_symtab_overwrite_decl (new_decl, old_decl);
return old_decl;
}
diff --git a/gcc/lto/lto-tree.h b/gcc/lto/lto-tree.h
index 126ec26..263d9ca 100644
--- a/gcc/lto/lto-tree.h
+++ b/gcc/lto/lto-tree.h
@@ -22,11 +22,14 @@ Boston, MA 02110-1301, USA. */
#ifndef GCC_LTO_TREE_H
#define GCC_LTO_TREE_H
+#include "plugin-api.h"
+
struct lang_identifier GTY(())
{
struct tree_identifier base;
/* LTO_IDENTIFIER_DECL */
tree decl;
+ enum ld_plugin_symbol_resolution resolution;
};
struct lang_decl GTY(())
@@ -67,6 +70,9 @@ union lang_tree_node GTY(
#define LTO_IDENTIFIER_DECL(NODE) \
(LANG_IDENTIFIER_CAST (NODE)->decl)
+#define LTO_IDENTIFIER_RESOLUTION(NODE) \
+ (LANG_IDENTIFIER_CAST (NODE)->resolution)
+
/* Vector to keep track of external variables we've seen so far. */
extern GTY(()) VEC(tree,gc) *lto_global_var_decls;