http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57297
Richard Biener <rguenth at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |NEW Last reconfirmed| |2013-05-16 CC| |jamborm at gcc dot gnu.org Ever confirmed|0 |1 --- Comment #2 from Richard Biener <rguenth at gcc dot gnu.org> --- This MEM[(struct __class_poly_list_Node_type_p *)&node] = node_17; MEM[(struct __class_poly_list_Node_type_p *)&node + 4B] = &__vtab_poly_list_Node_type; MEM[(struct node_type *)integer_node_4].next = VIEW_CONVERT_EXPR<struct __class_poly_list_Node_type_p>(MEM[(struct __class_poly_list_Node_type &)&node]); certainly looks suspicious - we store to node with alias type (struct __class_poly_list_Node_type_p *) and load from the same location with alias type (struct __class_poly_list_Node_type &). Now, the frontend generated code doesn't have the above as it appears only via some inlining: append_node (struct list_type & restrict list, struct __class_poly_list_Node_type & new_node) { ... _9 = list_4(D)->tail._data; _9->next = VIEW_CONVERT_EXPR<struct __class_poly_list_Node_type_p>(*new_node_6(D)); and _19 = __builtin_malloc (16); node._data = _19; ... _26 = node._data; __builtin_memset (_26, 0, 16); node._vptr = &__vtab_poly_list_Node_type; _29 = node._vptr; _30 = _29->_size; _31 = (unsigned long) _30; _32 = node._vptr; _33 = _32->_def_init; _34 = node._data; __builtin_memcpy (_34, _33, _31); append_node (&list, &node); It is early SRA that re-materializes in that way before the aggregate copy: MEM[(struct __class_poly_list_Node_type_p *)&node] = node$_data_28; MEM[(struct __class_poly_list_Node_type_p *)&node + 8B] = node$_vptr_20; list.head = VIEW_CONVERT_EXPR<struct __class_poly_list_Node_type_p>(MEM[(struct __class_poly_list_Node_type &)&node]); Access trees for node (UID: 1941): access { base = (1941)'node', offset = 0, size = 128, expr = node, type = struct __class_poly_list_Node_type_p, grp_read = 1, grp_write = 1, grp_assignment_read = 1, grp_assignment_write = 1, grp_scalar_read = 0, grp_scalar_write = 0, grp_total_scalarization = 1, grp_hint = 1, grp_covered = 1, grp_unscalarizable_region = 0, grp_unscalarized_data = 0, grp_partial_lhs = 0, grp_to_be_replaced = 0, grp_to_be_debug_replaced = 0, grp_maybe_modified = 0, grp_not_necessarilly_dereferenced = 0 * access { base = (1941)'node', offset = 0, size = 64, expr = node._data, type = struct node_type *, grp_read = 1, grp_write = 1, grp_assignment_read = 1, grp_assignment_write = 1, grp_scalar_read = 1, grp_scalar_write = 1, grp_total_scalarization = 1, grp_hint = 1, grp_covered = 1, grp_unscalarizable_region = 0, grp_unscalarized_data = 0, grp_partial_lhs = 0, grp_to_be_replaced = 1, grp_to_be_debug_replaced = 0, grp_maybe_modified = 0, grp_not_necessarilly_dereferenced = 0 * access { base = (1941)'node', offset = 64, size = 64, expr = node._vptr, type = struct __vtype_poly_list_Node_type * {ref-all}, grp_read = 1, grp_write = 1, grp_assignment_read = 1, grp_assignment_write = 1, grp_scalar_read = 1, grp_scalar_write = 1, grp_total_scalarization = 1, grp_hint = 1, grp_covered = 1, grp_unscalarizable_region = 0, grp_unscalarized_data = 0, grp_partial_lhs = 0, grp_to_be_replaced = 1, grp_to_be_debug_replaced = 0, grp_maybe_modified = 0, grp_not_necessarilly_dereferenced = 0 that replacement is not 100% correct. Coming from Therefore, I specially handle a fourth case, happening when there is a specific type cast or it is impossible to locate a scalarized subaccess on the other side of the expression. If that happens, I simply "refresh" the RHS by storing in it is scalarized components leave the original statement there to do the copying and then load the scalar replacements of the LHS. This is what the first branch does. */ if (modify_this_stmt || gimple_has_volatile_ops (*stmt) || contains_vce_or_bfcref_p (rhs) || contains_vce_or_bfcref_p (lhs)) { with list.head = VIEW_CONVERT_EXPR<struct __class_poly_list_Node_type_p>(MEM[(struct __class_poly_list_Node_type &)&node]); build_ref_for_offset ends up creating a MEM_REF with different alias pointer type than "the original" (note that there may be multiple originals and AFAIK we don't make any attempt to "merge" them conservatively). Re-materializing the original variable will always be hard. I believe that Index: gcc/tree-sra.c =================================================================== --- gcc/tree-sra.c (revision 198420) +++ gcc/tree-sra.c (working copy) @@ -3158,7 +3158,7 @@ sra_modify_assign (gimple *stmt, gimple_ if (modify_this_stmt || gimple_has_volatile_ops (*stmt) - || contains_vce_or_bfcref_p (rhs) + || contains_bitfld_comp_ref_p (rhs) || contains_vce_or_bfcref_p (lhs)) { if (access_has_children_p (racc)) should work. But note that the frontend already geneated wrong-code with the above assignment list.head = VIEW_CONVERT_EXPR<struct __class_poly_list_Node_type_p>(MEM[(struct __class_poly_list_Node_type &)&node]); which comes from _9->next = VIEW_CONVERT_EXPR<struct __class_poly_list_Node_type_p>(*new_node_6(D)); as this is reading from 'node' with a different alias set than was stored to (via the simple component-refs). But SRA is likely required to expose this situation to the scheduler. Confirmed as a frontend issue. I can see a difference with the proposed Frontend patch but the alias sets are unchanged.