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)) {