Hi,

the deficiency comes from a chicken-and-egg problem during WPA: DECL nodes 
merging depends on type merging, but type merging also depends on DECL nodes 
merging for dynamic types declared at file scope, which easily occurs in Ada.

For the attached trivial testcase, the compiler issues:

/home/eric/svn/gcc/gcc/testsuite/gnat.dg/lto18_pkg1.ads:12:13: warning: type 
of 'lto18_pkg1__proc' does not match original declaration [-Wlto-type-
mismatch]
/home/eric/svn/gcc/gcc/testsuite/gnat.dg/lto18_pkg1.adb:3:3: note: 
'lto18_pkg1__proc' was previously declared here
/home/eric/svn/gcc/gcc/testsuite/gnat.dg/lto18_pkg1.adb:3:3: note: code may be 
misoptimized unless -fno-strict-aliasing is used

The proposed fix is to add a special processing in operand_equal_p/add_expr 
for DECL nodes during WPA.  It contains a tweak for lto_fixup_prevailing_decls 
for the sake of completeness, but it is not necessary for fixing the problem.

Tested on x86_64-suse-linux, OK for the mainline?


2016-07-05  Eric Botcazou  <ebotca...@adacore.com>

        * cgraph.h (symbol_table::decl_assembler_name_hash): Make public.
        * fold-const.c (operand_equal_p) <tcc_declaration>: Add special
        processing during WPA.
        * tree.c (add_expr) <tcc_declaration>: Likewise.
lto/
        * lto.c (walk_simple_constant_arithmetic): New function.
        (LTO_SET_PREVAIL): Use it to fix up DECL nodes in simple expressions.


2016-07-05  Eric Botcazou  <ebotca...@adacore.com>

        * gnat.dg/lto18.adb: New test.
        * gnat.dg/lto18_pkg1.ad[sb]: New helper.
        * gnat.dg/lto18_pkg2.ad[sb]: Likewise.

-- 
Eric Botcazou
Index: cgraph.h
===================================================================
--- cgraph.h	(revision 237999)
+++ cgraph.h	(working copy)
@@ -2175,6 +2175,9 @@ public:
   /* Set the DECL_ASSEMBLER_NAME and update symtab hashtables.  */
   void change_decl_assembler_name (tree decl, tree name);
 
+  /* Hash asmnames ignoring the user specified marks.  */
+  static hashval_t decl_assembler_name_hash (const_tree asmname);
+
   /* Return true if assembler names NAME1 and NAME2 leads to the same symbol
      name.  */
   static bool assembler_names_equal_p (const char *name1, const char *name2);
@@ -2243,9 +2246,6 @@ private:
   /* Remove NODE from assembler name hash.  */
   void unlink_from_assembler_name_hash (symtab_node *node, bool with_clones);
 
-  /* Hash asmnames ignoring the user specified marks.  */
-  static hashval_t decl_assembler_name_hash (const_tree asmname);
-
   /* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL.  */
   static bool decl_assembler_name_equal (tree decl, const_tree asmname);
 
Index: fold-const.c
===================================================================
--- fold-const.c	(revision 237999)
+++ fold-const.c	(working copy)
@@ -3226,6 +3226,17 @@ operand_equal_p (const_tree arg0, const_
 	}
 
     case tcc_declaration:
+      /* During WPA we can be called before the DECL nodes are merged.  */
+      if (flag_wpa
+	  && TREE_CODE (arg0) == VAR_DECL
+	  && (TREE_PUBLIC (arg0) || DECL_EXTERNAL (arg0))
+	  && (TREE_PUBLIC (arg1) || DECL_EXTERNAL (arg1)))
+	return symbol_table::assembler_names_equal_p
+		 (IDENTIFIER_POINTER
+		    (DECL_ASSEMBLER_NAME (const_cast<tree> (arg0))),
+		  IDENTIFIER_POINTER
+		    (DECL_ASSEMBLER_NAME (const_cast<tree> (arg1))));
+
       /* Consider __builtin_sqrt equal to sqrt.  */
       return (TREE_CODE (arg0) == FUNCTION_DECL
 	      && DECL_BUILT_IN (arg0) && DECL_BUILT_IN (arg1)
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 237999)
+++ lto/lto.c	(working copy)
@@ -2506,15 +2506,55 @@ lto_wpa_write_files (void)
   timevar_pop (TV_WHOPR_WPA_IO);
 }
 
+/* Look inside *EXPR into simple arithmetic operations involving constants.
+   Return the address of the outermost non-arithmetic or non-constant node.
+   This should be equivalent to tree.c:skip_simple_constant_arithmetic.  */
 
-/* If TT is a variable or function decl replace it with its
-   prevailing variant.  */
+static tree *
+walk_simple_constant_arithmetic (tree *expr)
+{
+  while (TREE_CODE (*expr) == NON_LVALUE_EXPR)
+    expr = &TREE_OPERAND (*expr, 0);
+
+  while (true)
+    {
+      if (UNARY_CLASS_P (*expr))
+	expr = &TREE_OPERAND (*expr, 0);
+      else if (BINARY_CLASS_P (*expr))
+	{
+	  if (TREE_CONSTANT (TREE_OPERAND (*expr, 1)))
+	    expr = &TREE_OPERAND (*expr, 0);
+	  else if (TREE_CONSTANT (TREE_OPERAND (*expr, 0)))
+	    expr = &TREE_OPERAND (*expr, 1);
+	  else
+	    break;
+	}
+      else
+	break;
+    }
+
+  return expr;
+}
+
+/* If TT is a variable or function decl or a simple expression containing one,
+   replace the occurrence with its prevailing variant.  This should be able to
+   deal with all the expressions attached to _DECL and _TYPE nodes which were
+   streamed into the GIMPLE IR.  */
 #define LTO_SET_PREVAIL(tt) \
   do {\
+    tree *loc; \
     if ((tt) && VAR_OR_FUNCTION_DECL_P (tt) \
 	&& (TREE_PUBLIC (tt) || DECL_EXTERNAL (tt))) \
       { \
-        tt = lto_symtab_prevailing_decl (tt); \
+	tt = lto_symtab_prevailing_decl (tt); \
+	fixed = true; \
+      } \
+    else if ((tt) && EXPR_P (tt) \
+	     && (loc = walk_simple_constant_arithmetic (&tt)) \
+	     && VAR_OR_FUNCTION_DECL_P (*loc) \
+	     && (TREE_PUBLIC (*loc) || DECL_EXTERNAL (*loc))) \
+      { \
+	*loc = lto_symtab_prevailing_decl (*loc); \
 	fixed = true; \
       } \
   } while (0)
Index: tree.c
===================================================================
--- tree.c	(revision 237999)
+++ tree.c	(working copy)
@@ -7878,8 +7878,17 @@ add_expr (const_tree t, inchash::hash &h
 
       if (tclass == tcc_declaration)
 	{
-	  /* DECL's have a unique ID */
-	  hstate.add_wide_int (DECL_UID (t));
+	  /* During WPA we can be called before the DECL nodes are merged.  */
+	  if (flag_wpa
+	      && TREE_CODE (t) == VAR_DECL
+	      && (TREE_PUBLIC (t) || DECL_EXTERNAL (t)))
+	    {
+	      tree x = DECL_ASSEMBLER_NAME (const_cast <tree> (t));
+	      hstate.merge_hash (symbol_table::decl_assembler_name_hash (x));
+	    }
+	  else
+	    /* DECL's have a unique ID */
+	    hstate.add_wide_int (DECL_UID (t));
 	}
       else if (tclass == tcc_comparison && !commutative_tree_code (code))
 	{
-- { dg-do run }
-- { dg-options "-flto" }
-- { dg-require-effective-target lto }

with Lto18_Pkg1;

procedure Lto18 is
  R : Lto18_Pkg1.Rec := (I => 1, A => (others => 0));
begin
  Lto18_Pkg1.Proc (R);
end;
package body Lto18_Pkg1 is

  procedure Proc (R : Rec) is begin null; end;

end Lto18_Pkg1;
with Lto18_Pkg2;

package Lto18_Pkg1 is

  type Arr is array (1 .. Lto18_Pkg2.UB) of Integer;

  type Rec is record
    A : Arr;
    I : Integer;
  end record;

  procedure Proc (R : Rec);

end Lto18_Pkg1;
package Lto18_Pkg2 is

  function UB return Natural;

end Lto18_Pkg2;
package body Lto18_Pkg2 is

  function UB return Natural is begin return 8; end;

end Lto18_Pkg2;

Reply via email to