This addresses a defect in handling movmisalign-handled stores
when they are wrapped in component-references (think of a
vector mode aggregate containing a single vector, wrapped with
a BIT_FIELD_REF to store a single vector element).  I ran into
this issue while trying to fix PR50444 (and made SRA create
such wrapped movmisalign-handled stores).  We cannot simply
use expand_normal on the inner reference if that possibly
goes through the movmisalign path as that would produce
an rvalue instead of a MEM we can re-use.  A simple fix is
to delay expanding the destination and instead build a pseudo
with the contents we can store via movmisalign.

That the MEM_REF path now goes the handled_component_p path
unconditionally unconvered an issue in store_field which
sets MEM_IN_STRUCT_P to any non-MEM_SCALAR_P destination.
But that's clearly wrong for MEMs where we have no idea
whether they are scalar or part of a struct (which is the
reason this is a tri-state flag combo).  Thus the 2nd patchlet
below.

Bootstrapped and tested on x86_64-unknown-linux-gnu, ok for trunk?

Thanks,
Richard.

2012-01-24  Richard Guenther  <rguent...@suse.de>

        PR tree-optimization/50444
        * expr.c (expand_assignment): Handle misaligned bases consistently,
        even when wrapped inside component references.

Index: gcc/expr.c
===================================================================
*** gcc/expr.c  (revision 183470)
--- gcc/expr.c  (working copy)
*************** expand_assignment (tree to, tree from, b
*** 4556,4564 ****
  {
    rtx to_rtx = 0;
    rtx result;
-   enum machine_mode mode;
-   unsigned int align;
-   enum insn_code icode;
  
    /* Don't crash if the lhs of the assignment was erroneous.  */
    if (TREE_CODE (to) == ERROR_MARK)
--- 4556,4561 ----
*************** expand_assignment (tree to, tree from, b
*** 4571,4647 ****
    if (operand_equal_p (to, from, 0))
      return;
  
-   mode = TYPE_MODE (TREE_TYPE (to));
-   if ((TREE_CODE (to) == MEM_REF
-        || TREE_CODE (to) == TARGET_MEM_REF)
-       && mode != BLKmode
-       && ((align = get_object_or_type_alignment (to))
-         < GET_MODE_ALIGNMENT (mode))
-       && ((icode = optab_handler (movmisalign_optab, mode))
-         != CODE_FOR_nothing))
-     {
-       struct expand_operand ops[2];
-       enum machine_mode address_mode;
-       rtx reg, op0, mem;
- 
-       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, 0))));
-         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 (TREE_TYPE (TREE_OPERAND (to, 0))));
-         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 ();
-       if (TREE_THIS_VOLATILE (to))
-       MEM_VOLATILE_P (mem) = 1;
- 
-       create_fixed_operand (&ops[0], mem);
-       create_input_operand (&ops[1], reg, mode);
-       /* The movmisalign<mode> pattern cannot fail, else the assignment would
-          silently be omitted.  */
-       expand_insn (icode, 2, ops);
-       return;
-     }
- 
    /* Assignment of a structure component needs special treatment
       if the structure component's rtx is not simply a MEM.
       Assignment of an array element at a constant index, and assignment of
       an array element in an unaligned packed structure field, has the same
       problem.  */
    if (handled_component_p (to)
!       /* ???  We only need to handle MEM_REF here if the access is not
!          a full access of the base object.  */
!       || (TREE_CODE (to) == MEM_REF
!         && TREE_CODE (TREE_OPERAND (to, 0)) == ADDR_EXPR)
        || TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
      {
        enum machine_mode mode1;
--- 4568,4581 ----
    if (operand_equal_p (to, from, 0))
      return;
  
    /* Assignment of a structure component needs special treatment
       if the structure component's rtx is not simply a MEM.
       Assignment of an array element at a constant index, and assignment of
       an array element in an unaligned packed structure field, has the same
       problem.  */
    if (handled_component_p (to)
!       || TREE_CODE (to) == MEM_REF
!       || TREE_CODE (to) == TARGET_MEM_REF
        || TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
      {
        enum machine_mode mode1;
*************** expand_assignment (tree to, tree from, b
*** 4652,4657 ****
--- 4586,4595 ----
        int unsignedp;
        int volatilep = 0;
        tree tem;
+       enum machine_mode mode;
+       unsigned int align;
+       enum insn_code icode;
+       bool misalignp;
  
        push_temp_slots ();
        tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
*************** expand_assignment (tree to, tree from, b
*** 4664,4671 ****
  
        /* 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.
--- 4602,4624 ----
  
        /* If we are going to use store_bit_field and extract_bit_field,
         make sure to_rtx will be safe for multiple use.  */
!       mode = TYPE_MODE (TREE_TYPE (tem));
!       if ((TREE_CODE (tem) == MEM_REF
!          || TREE_CODE (tem) == TARGET_MEM_REF)
!         && mode != BLKmode
!         && ((align = get_object_or_type_alignment (tem))
!             < GET_MODE_ALIGNMENT (mode))
!         && ((icode = optab_handler (movmisalign_optab, mode))
!             != CODE_FOR_nothing))
!       {
!         misalignp = true;
!         to_rtx = gen_reg_rtx (mode);
!       }
!       else
!       {
!         misalignp = false;
!         to_rtx = expand_normal (tem);
!       }
  
        /* If the bitfield is volatile, we want to access it in the
         field's mode, not the computed mode.
*************** expand_assignment (tree to, tree from, b
*** 4811,4816 ****
--- 4764,4819 ----
                                  nontemporal);
        }
  
+       if (misalignp)
+       {
+         struct expand_operand ops[2];
+         enum machine_mode address_mode;
+         rtx op0, mem;
+ 
+         if (TREE_CODE (tem) == MEM_REF)
+           {
+             addr_space_t as = TYPE_ADDR_SPACE
+                 (TREE_TYPE (TREE_TYPE (TREE_OPERAND (tem, 0))));
+             tree base = TREE_OPERAND (tem, 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 (tem, 1)))
+               {
+                 rtx off = immed_double_int_const (mem_ref_offset (tem),
+                                                   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, tem, 0);
+             set_mem_addr_space (mem, as);
+           }
+         else if (TREE_CODE (tem) == TARGET_MEM_REF)
+           {
+             addr_space_t as = TYPE_ADDR_SPACE
+                 (TREE_TYPE (TREE_TYPE (TREE_OPERAND (tem, 0))));
+             struct mem_address addr;
+ 
+             get_address_description (tem, &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, tem, 0);
+             set_mem_addr_space (mem, as);
+           }
+         else
+           gcc_unreachable ();
+         if (TREE_THIS_VOLATILE (tem))
+           MEM_VOLATILE_P (mem) = 1;
+ 
+         create_fixed_operand (&ops[0], mem);
+         create_input_operand (&ops[1], to_rtx, mode);
+         /* The movmisalign<mode> pattern cannot fail, else the assignment
+            would silently be omitted.  */
+         expand_insn (icode, 2, ops);
+       }
+ 
        if (result)
        preserve_temp_slots (result);
        free_temp_slots ();


2012-01-24  Richard Guenther  <rguent...@suse.de>

        * expr.c (store_field): Do not set MEM_IN_STRUCT_P.

Index: gcc/expr.c
===================================================================
--- gcc/expr.c  (revision 183470)
+++ gcc/expr.c  (working copy)
@@ -6429,8 +6432,6 @@ store_field (rtx target, HOST_WIDE_INT b
       if (to_rtx == target)
        to_rtx = copy_rtx (to_rtx);
 
-      if (!MEM_SCALAR_P (to_rtx))
-       MEM_IN_STRUCT_P (to_rtx) = 1;
       if (!MEM_KEEP_ALIAS_SET_P (to_rtx) && MEM_ALIAS_SET (to_rtx) != 0)
        set_mem_alias_set (to_rtx, alias_set);
 

Reply via email to