Hi, so this is variant without the BLKmode subreg that passes testing on ppc64-linux. The case of parlallel and copy_blkmode_to_reg appears to be handled upstream in expand_assignment.
Honza * expr.c (store_expr_with_bounds): Handle aggregate moves from BLKmode. * gimple-expr.c (useless_type_conversion_p): Do not use TYPE_CANONICAL to define gimple type system; compare aggregates only by size. Index: expr.c =================================================================== --- expr.c (revision 228267) +++ expr.c (working copy) @@ -5462,7 +5462,13 @@ store_expr_with_bounds (tree exp, rtx ta { if (GET_MODE (temp) != GET_MODE (target) && GET_MODE (temp) != VOIDmode) { - if (GET_MODE (target) == BLKmode) + if (GET_MODE (temp) == BLKmode && GET_MODE (target) != BLKmode) + { + gcc_assert (AGGREGATE_TYPE_P (TREE_TYPE (exp))); + gcc_assert (MEM_P (temp)); + temp = adjust_address_nv (temp, GET_MODE (target), 0); + } + else if (GET_MODE (target) == BLKmode) { /* Handle calls that return BLKmode values in registers. */ if (REG_P (temp) && TREE_CODE (exp) == CALL_EXPR) Index: gimple-expr.c =================================================================== --- gimple-expr.c (revision 228267) +++ gimple-expr.c (working copy) @@ -87,11 +87,6 @@ useless_type_conversion_p (tree outer_ty if (inner_type == outer_type) return true; - /* If we know the canonical types, compare them. */ - if (TYPE_CANONICAL (inner_type) - && TYPE_CANONICAL (inner_type) == TYPE_CANONICAL (outer_type)) - return true; - /* Changes in machine mode are never useless conversions unless we deal with aggregate types in which case we defer to later checks. */ if (TYPE_MODE (inner_type) != TYPE_MODE (outer_type) @@ -270,12 +265,23 @@ useless_type_conversion_p (tree outer_ty return true; } - /* For aggregates we rely on TYPE_CANONICAL exclusively and require - explicit conversions for types involving to be structurally - compared types. */ + /* For aggregates compare only the size and mode. Accesses to fields do have + a type information by themselves and thus we only care if we can i.e. + use the types in move operations. */ else if (AGGREGATE_TYPE_P (inner_type) && TREE_CODE (inner_type) == TREE_CODE (outer_type)) - return false; + return (!TYPE_SIZE (outer_type) + || (TYPE_SIZE (inner_type) + && operand_equal_p (TYPE_SIZE (inner_type), + TYPE_SIZE (outer_type), 0))); + + else if (TREE_CODE (inner_type) == OFFSET_TYPE + && TREE_CODE (inner_type) == TREE_CODE (outer_type)) + return useless_type_conversion_p (TREE_TYPE (outer_type), + TREE_TYPE (inner_type)) + && useless_type_conversion_p + (TYPE_OFFSET_BASETYPE (outer_type), + TYPE_OFFSET_BASETYPE (inner_type)); return false; }