aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2005-03-16 09:15:11 -0800
committerRichard Henderson <rth@gcc.gnu.org>2005-03-16 09:15:11 -0800
commite4d5432a7343e870ebcee2fb510afc694dcc80ac (patch)
treedea6e2717e4d542e86bb9d06e16d59fe24986dbf
parent5f6c8a56a726b191f7a603caa0b7dc65f2e3e5bf (diff)
downloadgcc-e4d5432a7343e870ebcee2fb510afc694dcc80ac.zip
gcc-e4d5432a7343e870ebcee2fb510afc694dcc80ac.tar.gz
gcc-e4d5432a7343e870ebcee2fb510afc694dcc80ac.tar.bz2
re PR middle-end/15700 ([unit-at-a-time] Inlining problem leads to miscompilation of glibc)
PR middle-end/15700 * varasm.c (struct alias_pair): Rename from struct output_def_pair. (alias_pairs): Rename from output_defs. (find_decl_and_mark_needed): Split out from assemble_alias. (do_assemble_alias): New. (assemble_output_def): Remove. (finish_aliases_1, finish_aliases_2): New. (process_pending_assemble_output_defs): Remove. (assemble_alias): Defer aliases for which we don't yet have a non-external decl for the target symbol. * passes.c (rest_of_decl_compilation): Register variables with cgraph. * cgraphunit.c (cgraph_finalize_compilation_unit): Use finish_aliases_1. * toplev.c (compile_file): Use finish_aliases_2 instead of process_pending_assemble_output_defs. * tree.h (finish_aliases_1, finish_aliases_2): Declare. (process_pending_assemble_output_defs): Remove. * gcc.c-torture/compile/20040323-1.c: Don't xfail for solaris. (_rtld_global): New. * gcc.dg/weak/weak-3.c (ffoox1f, ffoox1g): Define. * gcc.dg/weak/weak-9.c (notf1, notf2, notf3, notf4): Define. * gcc.dg/alias-3.c: New. * gcc.dg/alias-4.c: New. * gcc.dg/alias-5.c: New. * gcc.dg/alias-6.c: New. From-SVN: r96564
-rw-r--r--gcc/ChangeLog19
-rw-r--r--gcc/cgraphunit.c2
-rw-r--r--gcc/passes.c4
-rw-r--r--gcc/testsuite/ChangeLog13
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/20040323-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/alias-3.c11
-rw-r--r--gcc/testsuite/gcc.dg/alias-4.c11
-rw-r--r--gcc/testsuite/gcc.dg/alias-5.c7
-rw-r--r--gcc/testsuite/gcc.dg/alias-6.c7
-rw-r--r--gcc/testsuite/gcc.dg/weak/weak-3.c4
-rw-r--r--gcc/testsuite/gcc.dg/weak/weak-9.c9
-rw-r--r--gcc/toplev.c5
-rw-r--r--gcc/tree.h3
-rw-r--r--gcc/varasm.c252
14 files changed, 228 insertions, 121 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0714aee..d7b1f14 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,22 @@
+2005-03-16 Richard Henderson <rth@redhat.com>
+
+ PR middle-end/15700
+ * varasm.c (struct alias_pair): Rename from struct output_def_pair.
+ (alias_pairs): Rename from output_defs.
+ (find_decl_and_mark_needed): Split out from assemble_alias.
+ (do_assemble_alias): New.
+ (assemble_output_def): Remove.
+ (finish_aliases_1, finish_aliases_2): New.
+ (process_pending_assemble_output_defs): Remove.
+ (assemble_alias): Defer aliases for which we don't yet have a
+ non-external decl for the target symbol.
+ * passes.c (rest_of_decl_compilation): Register variables with cgraph.
+ * cgraphunit.c (cgraph_finalize_compilation_unit): Use finish_aliases_1.
+ * toplev.c (compile_file): Use finish_aliases_2 instead of
+ process_pending_assemble_output_defs.
+ * tree.h (finish_aliases_1, finish_aliases_2): Declare.
+ (process_pending_assemble_output_defs): Remove.
+
2005-03-16 Daniel Berlin <dberlin@dberlin.org>
Fix PR tree-optimization/20489
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 1effef6..db0aaaf 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -680,6 +680,8 @@ cgraph_finalize_compilation_unit (void)
{
struct cgraph_node *node;
+ finish_aliases_1 ();
+
if (!flag_unit_at_a_time)
{
cgraph_assemble_pending_functions ();
diff --git a/gcc/passes.c b/gcc/passes.c
index 65c183d..7bb661d 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -251,6 +251,10 @@ rest_of_decl_compilation (tree decl,
debug_hooks->type_decl (decl, !top_level);
timevar_pop (TV_SYMOUT);
}
+
+ /* Let cgraph know about the existance of variables. */
+ if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
+ cgraph_varpool_node (decl);
}
/* Called after finishing a record, union or enumeral type. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 9f4d667..466b77e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,16 @@
+2005-03-16 Richard Henderson <rth@redhat.com>
+
+ PR middle-end/15700
+ * gcc.c-torture/compile/20040323-1.c: Don't xfail for solaris.
+ (_rtld_global): New.
+ * gcc.dg/weak/weak-3.c (ffoox1f, ffoox1g): Define.
+ * gcc.dg/weak/weak-9.c (notf1, notf2, notf3, notf4): Define.
+
+ * gcc.dg/alias-3.c: New.
+ * gcc.dg/alias-4.c: New.
+ * gcc.dg/alias-5.c: New.
+ * gcc.dg/alias-6.c: New.
+
2005-03-15 Geoffrey Keating <geoffk@apple.com>
* gcc.dg/cpp/ucnid-7.c: New.
diff --git a/gcc/testsuite/gcc.c-torture/compile/20040323-1.c b/gcc/testsuite/gcc.c-torture/compile/20040323-1.c
index a8d924a..b5e1ce4 100644
--- a/gcc/testsuite/gcc.c-torture/compile/20040323-1.c
+++ b/gcc/testsuite/gcc.c-torture/compile/20040323-1.c
@@ -1,7 +1,7 @@
/* PR middle-end/14694 */
/* { dg-require-alias "" } */
-/* { dg-xfail-if "undefined alias" { "*-*-solaris2.*" } { "*" } { "" } } */
+unsigned int _rtld_global;
extern unsigned int _rtld_local __attribute__ ((alias ("_rtld_global")));
unsigned int
diff --git a/gcc/testsuite/gcc.dg/alias-3.c b/gcc/testsuite/gcc.dg/alias-3.c
new file mode 100644
index 0000000..3dc25a9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/alias-3.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+/* { dg-options "" } */
+
+extern int foo();
+
+int baz () { return foo(); }
+
+static inline int bar () __attribute__ ((alias ("foo"))); /* { dg-error "aliased to" } */
+
+int main () { return bar (); }
diff --git a/gcc/testsuite/gcc.dg/alias-4.c b/gcc/testsuite/gcc.dg/alias-4.c
new file mode 100644
index 0000000..0a26339
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/alias-4.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-alias "" } */
+/* { dg-options "-O2 -funit-at-a-time" } */
+
+extern int foo();
+
+int baz () { return foo(); }
+
+static inline int bar () __attribute__ ((alias ("foo"))); /* { dg-error "aliased to" } */
+
+int main () { return bar (); }
diff --git a/gcc/testsuite/gcc.dg/alias-5.c b/gcc/testsuite/gcc.dg/alias-5.c
new file mode 100644
index 0000000..56848c9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/alias-5.c
@@ -0,0 +1,7 @@
+/* { dg-do link } */
+/* { dg-require-alias "" } */
+/* { dg-options "" } */
+
+static inline int foo () { return 0; }
+static int bar () __attribute__ ((alias ("foo")));
+int main () { return bar (); }
diff --git a/gcc/testsuite/gcc.dg/alias-6.c b/gcc/testsuite/gcc.dg/alias-6.c
new file mode 100644
index 0000000..3ba101a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/alias-6.c
@@ -0,0 +1,7 @@
+/* { dg-do link } */
+/* { dg-require-alias "" } */
+/* { dg-options "-O2 -funit-at-a-time" } */
+
+static inline int foo () { return 0; }
+static int bar () __attribute__ ((alias ("foo")));
+int main () { return bar (); }
diff --git a/gcc/testsuite/gcc.dg/weak/weak-3.c b/gcc/testsuite/gcc.dg/weak/weak-3.c
index c9448f0..2294ebf 100644
--- a/gcc/testsuite/gcc.dg/weak/weak-3.c
+++ b/gcc/testsuite/gcc.dg/weak/weak-3.c
@@ -52,18 +52,18 @@ void * foo1e (void)
extern void * ffoo1f (void);
-extern void * ffoox1f (void);
void * foo1f (void)
{
if (ffoo1f) /* { dg-warning "" } */
ffoo1f ();
return 0;
}
+void * ffoox1f (void) { return (void *)0; }
extern void * ffoo1f (void) __attribute__((weak, alias ("ffoox1f"))); /* { dg-warning "weak declaration" "weak declaration" } */
extern void * ffoo1g (void);
-extern void * ffoox1g (void);
+void * ffoox1g (void) { return (void *)0; }
extern void * ffoo1g (void) __attribute__((weak, alias ("ffoox1g")));
void * foo1g (void)
{
diff --git a/gcc/testsuite/gcc.dg/weak/weak-9.c b/gcc/testsuite/gcc.dg/weak/weak-9.c
index 95e8f80..abbd020 100644
--- a/gcc/testsuite/gcc.dg/weak/weak-9.c
+++ b/gcc/testsuite/gcc.dg/weak/weak-9.c
@@ -7,10 +7,11 @@
/* { dg-final { scan-assembler "weak\[^ \t\]*\[ \t\]_?f2" } } */
/* { dg-final { scan-assembler "weak\[^ \t\]*\[ \t\]_?f3" } } */
/* { dg-final { scan-assembler "weak\[^ \t\]*\[ \t\]_?f4" } } */
-/* { dg-final { scan-assembler "notf1" } } */
-/* { dg-final { scan-assembler "notf2" } } */
-/* { dg-final { scan-assembler "notf3" } } */
-/* { dg-final { scan-assembler "notf4" } } */
+
+void notf1() { }
+void notf2() { }
+void notf3() { }
+void notf4() { }
void f1() __attribute__((weak, alias("notf1")));
void f2() __attribute__((alias("notf2"), weak));
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 855e04a..5eb0d0d 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -1009,8 +1009,8 @@ compile_file (void)
return;
lang_hooks.decls.final_write_globals ();
-
cgraph_varpool_assemble_pending_decls ();
+ finish_aliases_2 ();
/* This must occur after the loop to output deferred functions.
Else the coverage initializer would not be emitted if all the
@@ -1045,9 +1045,6 @@ compile_file (void)
expander can also generate them. */
process_pending_assemble_externals ();
- /* Flush any pending equate directives. */
- process_pending_assemble_output_defs ();
-
/* Attach a special .ident directive to the end of the file to identify
the version of GCC which compiled this code. The format of the .ident
string is patterned after the ones produced by native SVR4 compilers. */
diff --git a/gcc/tree.h b/gcc/tree.h
index 1fd1ab6..3ad2a51 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3739,7 +3739,8 @@ extern void mark_decl_referenced (tree);
extern void notice_global_symbol (tree);
extern void set_user_assembler_name (tree, const char *);
extern void process_pending_assemble_externals (void);
-extern void process_pending_assemble_output_defs (void);
+extern void finish_aliases_1 (void);
+extern void finish_aliases_2 (void);
/* In stmt.c */
extern void expand_computed_goto (tree);
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 2ec5fe9..2f16f7e 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -4335,55 +4335,139 @@ globalize_decl (tree decl)
targetm.asm_out.globalize_label (asm_out_file, name);
}
-/* Some targets do not allow a forward or undefined reference in a
- ASM_OUTPUT_DEF. Thus, a mechanism is needed to defer the output of
- this assembler code. The following struct holds the declaration
- and target for a deferred output define. */
-struct output_def_pair GTY(())
+/* We have to be able to tell cgraph about the needed-ness of the target
+ of an alias. This requires that the decl have been defined. Aliases
+ that preceed their definition have to be queued for later processing. */
+
+struct alias_pair GTY(())
{
tree decl;
tree target;
};
-typedef struct output_def_pair *output_def_pair;
+typedef struct alias_pair *alias_pair;
/* Define gc'd vector type. */
-DEF_VEC_GC_P(output_def_pair);
+DEF_VEC_GC_P(alias_pair);
-/* Vector of output_def_pair pointers. */
-static GTY(()) VEC(output_def_pair) *output_defs;
+static GTY(()) VEC(alias_pair) *alias_pairs;
-#ifdef ASM_OUTPUT_DEF
-/* Output the assembler code for a define (equate) using ASM_OUTPUT_DEF
- or ASM_OUTPUT_DEF_FROM_DECLS. The function defines the symbol whose
- tree node is DECL to have the value of the tree node TARGET. */
+/* Given an assembly name, find the decl it is associated with. At the
+ same time, mark it needed for cgraph. */
+
+static tree
+find_decl_and_mark_needed (tree decl, tree target)
+{
+ struct cgraph_node *fnode = NULL;
+ struct cgraph_varpool_node *vnode = NULL;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ fnode = cgraph_node_for_asm (target);
+ if (fnode == NULL)
+ vnode = cgraph_varpool_node_for_asm (target);
+ }
+ else
+ {
+ vnode = cgraph_varpool_node_for_asm (target);
+ if (vnode == NULL)
+ fnode = cgraph_node_for_asm (target);
+ }
+
+ if (fnode)
+ {
+ cgraph_mark_needed_node (fnode);
+ return fnode->decl;
+ }
+ else if (vnode)
+ {
+ cgraph_varpool_mark_needed_node (vnode);
+ return vnode->decl;
+ }
+ else
+ return NULL_TREE;
+}
static void
-assemble_output_def (tree decl ATTRIBUTE_UNUSED, tree target ATTRIBUTE_UNUSED)
+do_assemble_alias (tree decl, tree target)
{
-#ifdef ASM_OUTPUT_DEF_FROM_DECLS
+ TREE_ASM_WRITTEN (decl) = 1;
+ TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
+
+#ifdef ASM_OUTPUT_DEF
+ /* Make name accessible from other files, if appropriate. */
+
+ if (TREE_PUBLIC (decl))
+ {
+ globalize_decl (decl);
+ maybe_assemble_visibility (decl);
+ }
+
+# ifdef ASM_OUTPUT_DEF_FROM_DECLS
ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);
-#else
+# else
ASM_OUTPUT_DEF (asm_out_file,
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
IDENTIFIER_POINTER (target));
+# endif
+#elif defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
+ {
+ const char *name;
+ tree *p, t;
+
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+# ifdef ASM_WEAKEN_DECL
+ ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
+# else
+ ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
+# endif
+ /* Remove this function from the pending weak list so that
+ we do not emit multiple .weak directives for it. */
+ for (p = &weak_decls; (t = *p) ; )
+ if (DECL_ASSEMBLER_NAME (decl) == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
+ *p = TREE_CHAIN (t);
+ else
+ p = &TREE_CHAIN (t);
+ }
#endif
}
-#endif
-/* Process the vector of pending assembler defines. */
+/* First pass of completing pending aliases. Make sure that cgraph knows
+ which symbols will be required. */
void
-process_pending_assemble_output_defs (void)
+finish_aliases_1 (void)
{
-#ifdef ASM_OUTPUT_DEF
unsigned i;
- output_def_pair p;
+ alias_pair p;
- for (i = 0; VEC_iterate (output_def_pair, output_defs, i, p); i++)
- assemble_output_def (p->decl, p->target);
+ for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
+ {
+ tree target_decl;
+
+ target_decl = find_decl_and_mark_needed (p->decl, p->target);
+ if (target_decl == NULL)
+ error ("%J%qD aliased to undefined symbol %qE",
+ p->decl, p->decl, p->target);
+ else if (DECL_EXTERNAL (target_decl))
+ error ("%J%qD aliased to external symbol %qE",
+ p->decl, p->decl, p->target);
+ }
+}
- output_defs = NULL;
-#endif
+/* Second pass of completing pending aliases. Emit the actual assembly.
+ This happens at the end of compilation and thus it is assured that the
+ target symbol has been emitted. */
+
+void
+finish_aliases_2 (void)
+{
+ unsigned i;
+ alias_pair p;
+
+ for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
+ do_assemble_alias (p->decl, p->target);
+
+ alias_pairs = NULL;
}
/* Emit an assembler directive to make the symbol for DECL an alias to
@@ -4392,101 +4476,51 @@ process_pending_assemble_output_defs (void)
void
assemble_alias (tree decl, tree target)
{
- /* We must force creation of DECL_RTL for debug info generation, even though
- we don't use it here. */
- make_decl_rtl (decl);
-
-#ifdef ASM_OUTPUT_DEF
- /* Make name accessible from other files, if appropriate. */
+ tree target_decl;
- if (TREE_PUBLIC (decl))
+#if !defined (ASM_OUTPUT_DEF)
+# if !defined(ASM_OUTPUT_WEAK_ALIAS) && !defined (ASM_WEAKEN_DECL)
+ error ("%Jalias definitions not supported in this configuration", decl);
+ return;
+# else
+ if (!DECL_WEAK (decl))
{
- globalize_decl (decl);
- maybe_assemble_visibility (decl);
+ error ("%Jonly weak aliases are supported in this configuration", decl);
+ return;
}
+# endif
+#endif
- if (TARGET_DEFERRED_OUTPUT_DEFS (decl, target))
- {
- output_def_pair p;
+ /* We must force creation of DECL_RTL for debug info generation, even though
+ we don't use it here. */
+ make_decl_rtl (decl);
+ TREE_USED (decl) = 1;
- p = ggc_alloc (sizeof (struct output_def_pair));
- p->decl = decl;
- p->target = target;
- VEC_safe_push (output_def_pair, output_defs, p);
- }
- else
- assemble_output_def (decl, target);
-#else /* !ASM_OUTPUT_DEF */
-#if defined (ASM_OUTPUT_WEAK_ALIAS) || defined (ASM_WEAKEN_DECL)
- if (DECL_WEAK (decl))
- {
- const char *name;
- tree *p, t;
+ /* A quirk of the initial implementation of aliases required that the user
+ add "extern" to all of them. Which is silly, but now historical. Do
+ note that the symbol is in fact locally defined. */
+ DECL_EXTERNAL (decl) = 0;
- name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-#ifdef ASM_WEAKEN_DECL
- ASM_WEAKEN_DECL (asm_out_file, decl, name, IDENTIFIER_POINTER (target));
-#else
- ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
-#endif
- /* Remove this function from the pending weak list so that
- we do not emit multiple .weak directives for it. */
- for (p = &weak_decls; (t = *p) ; )
- if (DECL_ASSEMBLER_NAME (decl)
- == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))
- *p = TREE_CHAIN (t);
- else
- p = &TREE_CHAIN (t);
- }
+ /* Allow aliases to aliases. */
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ cgraph_node (decl);
else
- warning ("only weak aliases are supported in this configuration");
+ cgraph_varpool_node (decl);
-#else
- warning ("alias definitions not supported in this configuration; ignored");
-#endif
-#endif
-
- /* Tell cgraph that the aliased symbol is needed. We *could* be more
- specific and tell cgraph about the relationship between the two
- symbols, but given that aliases virtually always exist for a reason,
- it doesn't seem worthwhile. */
- if (flag_unit_at_a_time)
+ /* If the target has already been emitted, we don't have to queue the
+ alias. This saves a tad o memory. */
+ target_decl = find_decl_and_mark_needed (decl, target);
+ if (target_decl && TREE_ASM_WRITTEN (target_decl))
+ do_assemble_alias (decl, target);
+ else
{
- struct cgraph_node *fnode = NULL;
- struct cgraph_varpool_node *vnode = NULL;
-
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- fnode = cgraph_node_for_asm (target);
- if (fnode != NULL)
- cgraph_mark_needed_node (fnode);
- else
- {
- vnode = cgraph_varpool_node_for_asm (target);
- if (vnode != NULL)
- cgraph_varpool_mark_needed_node (vnode);
- }
- }
- else
- {
- vnode = cgraph_varpool_node_for_asm (target);
- if (vnode != NULL)
- cgraph_varpool_mark_needed_node (vnode);
- else
- {
- fnode = cgraph_node_for_asm (target);
- if (fnode != NULL)
- cgraph_mark_needed_node (fnode);
- }
- }
+ alias_pair p;
- if (fnode == NULL && vnode == NULL)
- warning ("%qD aliased to undefined symbol %qE", decl, target);
+ p = ggc_alloc (sizeof (struct alias_pair));
+ p->decl = decl;
+ p->target = target;
+ VEC_safe_push (alias_pair, alias_pairs, p);
}
-
- TREE_USED (decl) = 1;
- TREE_ASM_WRITTEN (decl) = 1;
- TREE_ASM_WRITTEN (DECL_ASSEMBLER_NAME (decl)) = 1;
}
/* Emit an assembler directive to set symbol for DECL visibility to