http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48493
--- Comment #5 from Richard Guenther <rguenth at gcc dot gnu.org> 2011-06-21 10:45:20 UTC --- Of course it was. The branch merge allows s to be allocated in registers so we expand from MEM[(T * {ref-all})&s + 1B] = x_2(D); and we run into the movmisalign_optab code in expand_assignment which is supported for DImode with the commandline args. But we probably shouldn't try the movmisalign path when the destination is a CONCAT. So something like the following might work (fixes the testcase, otehrwise completely untested) Index: expr.c =================================================================== --- expr.c (revision 175138) +++ expr.c (working copy) @@ -4122,6 +4122,12 @@ expand_assignment (tree to, tree from, b rtx result; enum machine_mode mode; int align, icode; + enum machine_mode mode1; + HOST_WIDE_INT bitsize, bitpos; + tree offset; + int unsignedp; + int volatilep = 0; + tree tem; /* Don't crash if the lhs of the assignment was erroneous. */ if (TREE_CODE (to) == ERROR_MARK) @@ -4134,9 +4140,18 @@ expand_assignment (tree to, tree from, b if (operand_equal_p (to, from, 0)) return; + tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1, + &unsignedp, &volatilep, true); + + /* If we are going to use store_bit_field and extract_bit_field, + make sure to_rtx will be safe for multiple use. */ + + to_rtx = expand_normal (tem); + mode = TYPE_MODE (TREE_TYPE (to)); - if ((TREE_CODE (to) == MEM_REF - || TREE_CODE (to) == TARGET_MEM_REF) + if (MEM_P (to_rtx) + && (TREE_CODE (to) == MEM_REF + || TREE_CODE (to) == TARGET_MEM_REF) && mode != BLKmode && ((align = MAX (TYPE_ALIGN (TREE_TYPE (to)), get_object_alignment (to, BIGGEST_ALIGNMENT))) @@ -4150,39 +4165,7 @@ expand_assignment (tree to, tree from, b reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL); reg = force_not_mem (reg); - if (TREE_CODE (to) == MEM_REF) - { - addr_space_t as - = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 1)))); - tree base = TREE_OPERAND (to, 0); - address_mode = targetm.addr_space.address_mode (as); - op0 = expand_expr (base, NULL_RTX, VOIDmode, EXPAND_NORMAL); - op0 = convert_memory_address_addr_space (address_mode, op0, as); - if (!integer_zerop (TREE_OPERAND (to, 1))) - { - rtx off - = immed_double_int_const (mem_ref_offset (to), address_mode); - op0 = simplify_gen_binary (PLUS, address_mode, op0, off); - } - op0 = memory_address_addr_space (mode, op0, as); - mem = gen_rtx_MEM (mode, op0); - set_mem_attributes (mem, to, 0); - set_mem_addr_space (mem, as); - } - else if (TREE_CODE (to) == TARGET_MEM_REF) - { - addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (to)); - struct mem_address addr; - - get_address_description (to, &addr); - op0 = addr_for_mem_ref (&addr, as, true); - op0 = memory_address_addr_space (mode, op0, as); - mem = gen_rtx_MEM (mode, op0); - set_mem_attributes (mem, to, 0); - set_mem_addr_space (mem, as); - } - else - gcc_unreachable (); + mem = to_rtx; if (TREE_THIS_VOLATILE (to)) MEM_VOLATILE_P (mem) = 1; @@ -4211,21 +4194,7 @@ expand_assignment (tree to, tree from, b && TREE_CODE (TREE_OPERAND (to, 0)) == ADDR_EXPR) || TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE) { - enum machine_mode mode1; - HOST_WIDE_INT bitsize, bitpos; - tree offset; - int unsignedp; - int volatilep = 0; - tree tem; - push_temp_slots (); - tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1, - &unsignedp, &volatilep, true); - - /* If we are going to use store_bit_field and extract_bit_field, - make sure to_rtx will be safe for multiple use. */ - - to_rtx = expand_normal (tem); /* If the bitfield is volatile, we want to access it in the field's mode, not the computed mode.