Commit e4d5432a by Richard Henderson Committed by Richard Henderson

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
parent 5f6c8a56
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
......
......@@ -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 ();
......
......@@ -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. */
......
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.
......
/* 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
......
/* { 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 (); }
/* { 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 (); }
/* { dg-do link } */
/* { dg-require-alias "" } */
/* { dg-options "" } */
static inline int foo () { return 0; }
static int bar () __attribute__ ((alias ("foo")));
int main () { return bar (); }
/* { 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 (); }
......@@ -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)
{
......
......@@ -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));
......
......@@ -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. */
......
......@@ -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);
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment