This fixes the code difference -O3 vs. -O3 -flto reported in PR56295.
For the -flto run we are confused by the extra MEM_REF we wrap every
global decl with in the IL (that is to support seamless and alias-correct
replacement of global decls with their prevailing decl).  The following
un-wraps the decl again if the extra MEM_REF has no semantic meaning
(we also do that in fold_stmt, I chose to duplicate the code in a
slightly stricter form here - eventually we should simply fold all
stmts, we have got extra information like global initializers available
at LTRANS time after all).

LTO bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

Richard.

2013-02-12  Richard Biener  <rguent...@suse.de>

        PR lto/56295
        * gimple-streamer-in.c (input_gimple_stmt): Strip MEM_REFs off
        decls again if possible.

Index: gcc/gimple-streamer-in.c
===================================================================
*** gcc/gimple-streamer-in.c    (revision 195973)
--- gcc/gimple-streamer-in.c    (working copy)
*************** input_gimple_stmt (struct lto_input_bloc
*** 143,164 ****
      case GIMPLE_DEBUG:
        for (i = 0; i < num_ops; i++)
        {
!         tree op = stream_read_tree (ib, data_in);
          gimple_set_op (stmt, i, op);
          if (!op)
            continue;
  
!         if (TREE_CODE (op) == ADDR_EXPR)
!           op = TREE_OPERAND (op, 0);
!         while (handled_component_p (op))
            {
!             if (TREE_CODE (op) == COMPONENT_REF)
                {
                  /* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled
                     by decl merging.  */
                  tree field, type, tem;
                  tree closest_match = NULL_TREE;
!                 field = TREE_OPERAND (op, 1);
                  type = DECL_CONTEXT (field);
                  for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
                    {
--- 143,165 ----
      case GIMPLE_DEBUG:
        for (i = 0; i < num_ops; i++)
        {
!         tree *opp, op = stream_read_tree (ib, data_in);
          gimple_set_op (stmt, i, op);
          if (!op)
            continue;
  
!         opp = gimple_op_ptr (stmt, i);
!         if (TREE_CODE (*opp) == ADDR_EXPR)
!           opp = &TREE_OPERAND (*opp, 0);
!         while (handled_component_p (*opp))
            {
!             if (TREE_CODE (*opp) == COMPONENT_REF)
                {
                  /* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled
                     by decl merging.  */
                  tree field, type, tem;
                  tree closest_match = NULL_TREE;
!                 field = TREE_OPERAND (*opp, 1);
                  type = DECL_CONTEXT (field);
                  for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
                    {
*************** input_gimple_stmt (struct lto_input_bloc
*** 186,197 ****
                      if (warning_at (gimple_location (stmt), 0,
                                      "use of type %<%E%> with two mismatching "
                                      "declarations at field %<%E%>",
!                                     type, TREE_OPERAND (op, 1)))
                        {
                          if (TYPE_FIELDS (type))
                            inform (DECL_SOURCE_LOCATION (TYPE_FIELDS (type)),
                                    "original type declared here");
!                         inform (DECL_SOURCE_LOCATION (TREE_OPERAND (op, 1)),
                                  "field in mismatching type declared here");
                          if (TYPE_NAME (TREE_TYPE (field))
                              && (TREE_CODE (TYPE_NAME (TREE_TYPE (field)))
--- 187,198 ----
                      if (warning_at (gimple_location (stmt), 0,
                                      "use of type %<%E%> with two mismatching "
                                      "declarations at field %<%E%>",
!                                     type, TREE_OPERAND (*opp, 1)))
                        {
                          if (TYPE_FIELDS (type))
                            inform (DECL_SOURCE_LOCATION (TYPE_FIELDS (type)),
                                    "original type declared here");
!                         inform (DECL_SOURCE_LOCATION (TREE_OPERAND (*opp, 1)),
                                  "field in mismatching type declared here");
                          if (TYPE_NAME (TREE_TYPE (field))
                              && (TREE_CODE (TYPE_NAME (TREE_TYPE (field)))
*************** input_gimple_stmt (struct lto_input_bloc
*** 208,235 ****
                                    "type of mismatching field declared here");
                        }
                      /* And finally fixup the types.  */
!                     TREE_OPERAND (op, 0)
                        = build1 (VIEW_CONVERT_EXPR, type,
!                                 TREE_OPERAND (op, 0));
                    }
                  else
!                   TREE_OPERAND (op, 1) = tem;
                }
!             else if ((TREE_CODE (op) == ARRAY_REF
!                       || TREE_CODE (op) == ARRAY_RANGE_REF)
!                      && (TREE_CODE (TREE_TYPE (TREE_OPERAND (op, 0)))
                           != ARRAY_TYPE))
                {
                  /* And ARRAY_REFs to objects that had mismatched types
                     during symbol merging to avoid ICEs.  */
!                 TREE_OPERAND (op, 0)
                    = build1 (VIEW_CONVERT_EXPR,
!                             build_array_type (TREE_TYPE (op), NULL_TREE),
!                             TREE_OPERAND (op, 0));
                }
  
!             op = TREE_OPERAND (op, 0);
            }
        }
        if (is_gimple_call (stmt))
        {
--- 209,252 ----
                                    "type of mismatching field declared here");
                        }
                      /* And finally fixup the types.  */
!                     TREE_OPERAND (*opp, 0)
                        = build1 (VIEW_CONVERT_EXPR, type,
!                                 TREE_OPERAND (*opp, 0));
                    }
                  else
!                   TREE_OPERAND (*opp, 1) = tem;
                }
!             else if ((TREE_CODE (*opp) == ARRAY_REF
!                       || TREE_CODE (*opp) == ARRAY_RANGE_REF)
!                      && (TREE_CODE (TREE_TYPE (TREE_OPERAND (*opp, 0)))
                           != ARRAY_TYPE))
                {
                  /* And ARRAY_REFs to objects that had mismatched types
                     during symbol merging to avoid ICEs.  */
!                 TREE_OPERAND (*opp, 0)
                    = build1 (VIEW_CONVERT_EXPR,
!                             build_array_type (TREE_TYPE (*opp), NULL_TREE),
!                             TREE_OPERAND (*opp, 0));
                }
  
!             opp = &TREE_OPERAND (*opp, 0);
            }
+         /* At LTO output time we wrap all global decls in MEM_REFs to
+            allow seamless replacement with prevailing decls.  Undo this
+            here if the prevailing decl allows for this.
+            ???  Maybe we should simply fold all stmts.  */
+         if (TREE_CODE (*opp) == MEM_REF
+             && TREE_CODE (TREE_OPERAND (*opp, 0)) == ADDR_EXPR
+             && integer_zerop (TREE_OPERAND (*opp, 1))
+             && (TREE_THIS_VOLATILE (*opp)
+                 == TREE_THIS_VOLATILE
+                      (TREE_OPERAND (TREE_OPERAND (*opp, 0), 0)))
+             && !TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (*opp, 1)))
+             && (TREE_TYPE (*opp)
+                 == TREE_TYPE (TREE_TYPE (TREE_OPERAND (*opp, 1))))
+             && (TREE_TYPE (*opp)
+                 == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*opp, 0), 0))))
+           *opp = TREE_OPERAND (TREE_OPERAND (*opp, 0), 0);
        }
        if (is_gimple_call (stmt))
        {

Reply via email to