]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR middle-end/15700 ([unit-at-a-time] Inlining problem leads to miscompilation...
authorRichard Henderson <rth@redhat.com>
Wed, 16 Mar 2005 17:15:11 +0000 (09:15 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Wed, 16 Mar 2005 17:15:11 +0000 (09:15 -0800)
        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

14 files changed:
gcc/ChangeLog
gcc/cgraphunit.c
gcc/passes.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/compile/20040323-1.c
gcc/testsuite/gcc.dg/alias-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/alias-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/alias-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/alias-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/weak/weak-3.c
gcc/testsuite/gcc.dg/weak/weak-9.c
gcc/toplev.c
gcc/tree.h
gcc/varasm.c

index 0714aee8c2184e05fa32b8caf214e3fab99e4c60..d7b1f14df30ccd9b05fe5bcc9efb6cb6e5f8f025 100644 (file)
@@ -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
index 1effef6710a947f4c4da0a86bae070707fadaec8..db0aaaf2adac9cd6218fd3faf803b82e3ada505a 100644 (file)
@@ -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 ();
index 65c183df383402358a2d8e2c5ba22dff5f7965ae..7bb661d0d0ebadc06be0402063938b5f561e2c4d 100644 (file)
@@ -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.  */
index 9f4d667f69f3502d7c1949cb178c44a786f08486..466b77e981686ded5e0dbe48e232a84f6e2788d9 100644 (file)
@@ -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.
index a8d924ab0fc6b293d79d379315847d92b305a146..b5e1ce4a98cb17bc4f9a3d8d7c566f8eef966a17 100644 (file)
@@ -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 (file)
index 0000000..3dc25a9
--- /dev/null
@@ -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 (file)
index 0000000..0a26339
--- /dev/null
@@ -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 (file)
index 0000000..56848c9
--- /dev/null
@@ -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 (file)
index 0000000..3ba101a
--- /dev/null
@@ -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 (); }
index c9448f032cf2d8c3ce7a5bb336272c1177cc4734..2294ebf7b4ee8204e73d9571588e8c64ed0679e5 100644 (file)
@@ -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)
 {
index 95e8f809f38f1521f1f80c3629a6c2ae5224b415..abbd0201c4642f9db6c0b29bf05aae0e894b26ab 100644 (file)
@@ -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));
index 855e04adeb2c2912790b268bf3ed7f2f602613ce..5eb0d0deac96ca22c608fe341b8b12b12420b6ef 100644 (file)
@@ -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.  */
index 1fd1ab6e44b6759d5ca6c29ee33ae24b5e0625b0..3ad2a5142b8d070a41a7eb20e9f4a5cca06bbdfa 100644 (file)
@@ -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);
index 2ec5fe9e554db2c9ea24c22be00f21f8b7699e3b..2f16f7e6057c66f651618c5a5521b86a968edced 100644 (file)
@@ -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