OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index ff88fcd..4c248e0 100644 (file)
@@ -4439,113 +4439,88 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
 /* In the C++ memory model, consecutive bit fields in a structure are
    considered one memory location.
 
-   Given a COMPONENT_REF, this function returns the bit range of
-   consecutive bits in which this COMPONENT_REF belongs in.  The
-   values are returned in *BITSTART and *BITEND.  If either the C++
-   memory model is not activated, or this memory access is not thread
-   visible, 0 is returned in *BITSTART and *BITEND.
-
-   EXP is the COMPONENT_REF.
-   INNERDECL is the actual object being referenced.
-   BITPOS is the position in bits where the bit starts within the structure.
-   BITSIZE is size in bits of the field being referenced in EXP.
-
-   For example, while storing into FOO.A here...
-
-      struct {
-        BIT 0:
-          unsigned int a : 4;
-         unsigned int b : 1;
-       BIT 8:
-         unsigned char c;
-         unsigned int d : 6;
-      } foo;
-
-   ...we are not allowed to store past <b>, so for the layout above, a
-   range of 0..7 (because no one cares if we store into the
-   padding).  */
+   Given a COMPONENT_REF EXP at position (BITPOS, OFFSET), this function
+   returns the bit range of consecutive bits in which this COMPONENT_REF
+   belongs.  The values are returned in *BITSTART and *BITEND.  *BITPOS
+   and *OFFSET may be adjusted in the process.
+
+   If the access does not need to be restricted, 0 is returned in both
+   *BITSTART and *BITEND.  */
 
 static void
 get_bit_range (unsigned HOST_WIDE_INT *bitstart,
               unsigned HOST_WIDE_INT *bitend,
-              tree exp, tree innerdecl,
-              HOST_WIDE_INT bitpos, HOST_WIDE_INT bitsize)
+              tree exp,
+              HOST_WIDE_INT *bitpos,
+              tree *offset)
 {
-  tree field, record_type, fld;
-  bool found_field = false;
-  bool prev_field_is_bitfield;
+  HOST_WIDE_INT bitoffset;
+  tree field, repr;
 
   gcc_assert (TREE_CODE (exp) == COMPONENT_REF);
 
-  /* If other threads can't see this value, no need to restrict stores.  */
-  if (ALLOW_STORE_DATA_RACES
-      || ((TREE_CODE (innerdecl) == MEM_REF
-          || TREE_CODE (innerdecl) == TARGET_MEM_REF)
-         && !ptr_deref_may_alias_global_p (TREE_OPERAND (innerdecl, 0)))
-      || (DECL_P (innerdecl)
-         && ((TREE_CODE (innerdecl) == VAR_DECL
-              && DECL_THREAD_LOCAL_P (innerdecl))
-             || !TREE_STATIC (innerdecl))))
+  field = TREE_OPERAND (exp, 1);
+  repr = DECL_BIT_FIELD_REPRESENTATIVE (field);
+  /* If we do not have a DECL_BIT_FIELD_REPRESENTATIVE there is no
+     need to limit the range we can access.  */
+  if (!repr)
     {
       *bitstart = *bitend = 0;
       return;
     }
 
-  /* Bit field we're storing into.  */
-  field = TREE_OPERAND (exp, 1);
-  record_type = DECL_FIELD_CONTEXT (field);
-
-  /* Count the contiguous bitfields for the memory location that
-     contains FIELD.  */
-  *bitstart = 0;
-  prev_field_is_bitfield = true;
-  for (fld = TYPE_FIELDS (record_type); fld; fld = DECL_CHAIN (fld))
+  /* If we have a DECL_BIT_FIELD_REPRESENTATIVE but the enclosing record is
+     part of a larger bit field, then the representative does not serve any
+     useful purpose.  This can occur in Ada.  */
+  if (handled_component_p (TREE_OPERAND (exp, 0)))
     {
-      tree t, offset;
-      enum machine_mode mode;
-      int unsignedp, volatilep;
-
-      if (TREE_CODE (fld) != FIELD_DECL)
-       continue;
-
-      t = build3 (COMPONENT_REF, TREE_TYPE (exp),
-                 unshare_expr (TREE_OPERAND (exp, 0)),
-                 fld, NULL_TREE);
-      get_inner_reference (t, &bitsize, &bitpos, &offset,
-                          &mode, &unsignedp, &volatilep, true);
-
-      if (field == fld)
-       found_field = true;
-
-      if (DECL_BIT_FIELD_TYPE (fld) && bitsize > 0)
-       {
-         if (prev_field_is_bitfield == false)
-           {
-             *bitstart = bitpos;
-             prev_field_is_bitfield = true;
-           }
-       }
-      else
+      enum machine_mode rmode;
+      HOST_WIDE_INT rbitsize, rbitpos;
+      tree roffset;
+      int unsignedp;
+      int volatilep = 0;
+      get_inner_reference (TREE_OPERAND (exp, 0), &rbitsize, &rbitpos,
+                          &roffset, &rmode, &unsignedp, &volatilep, false);
+      if ((rbitpos % BITS_PER_UNIT) != 0)
        {
-         prev_field_is_bitfield = false;
-         if (found_field)
-           break;
+         *bitstart = *bitend = 0;
+         return;
        }
     }
-  gcc_assert (found_field);
 
-  if (fld)
-    {
-      /* We found the end of the bit field sequence.  Include the
-        padding up to the next field and be done.  */
-      *bitend = bitpos - 1;
-    }
+  /* Compute the adjustment to bitpos from the offset of the field
+     relative to the representative.  DECL_FIELD_OFFSET of field and
+     repr are the same by construction if they are not constants,
+     see finish_bitfield_layout.  */
+  if (host_integerp (DECL_FIELD_OFFSET (field), 1)
+      && host_integerp (DECL_FIELD_OFFSET (repr), 1))
+    bitoffset = (tree_low_cst (DECL_FIELD_OFFSET (field), 1)
+                - tree_low_cst (DECL_FIELD_OFFSET (repr), 1)) * BITS_PER_UNIT;
   else
+    bitoffset = 0;
+  bitoffset += (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+               - tree_low_cst (DECL_FIELD_BIT_OFFSET (repr), 1));
+
+  /* If the adjustment is larger than bitpos, we would have a negative bit
+     position for the lower bound and this may wreak havoc later.  This can
+     occur only if we have a non-null offset, so adjust offset and bitpos
+     to make the lower bound non-negative.  */
+  if (bitoffset > *bitpos)
     {
-      /* If this is the last element in the structure, include the padding
-        at the end of structure.  */
-      *bitend = TREE_INT_CST_LOW (TYPE_SIZE (record_type)) - 1;
+      HOST_WIDE_INT adjust = bitoffset - *bitpos;
+
+      gcc_assert ((adjust % BITS_PER_UNIT) == 0);
+      gcc_assert (*offset != NULL_TREE);
+
+      *bitpos += adjust;
+      *offset
+       = size_binop (MINUS_EXPR, *offset, size_int (adjust / BITS_PER_UNIT));
+      *bitstart = 0;
     }
+  else
+    *bitstart = *bitpos - bitoffset;
+
+  *bitend = *bitstart + tree_low_cst (DECL_SIZE (repr), 1) - 1;
 }
 
 /* Returns true if the MEM_REF REF refers to an object that does not
@@ -4593,6 +4568,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
   if ((TREE_CODE (to) == MEM_REF
        || TREE_CODE (to) == TARGET_MEM_REF)
       && mode != BLKmode
+      && !mem_ref_refers_to_non_mem_p (to)
       && ((align = get_object_or_type_alignment (to))
          < GET_MODE_ALIGNMENT (mode))
       && ((icode = optab_handler (movmisalign_optab, mode))
@@ -4666,6 +4642,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
       int volatilep = 0;
       tree tem;
       bool misalignp;
+      rtx mem = NULL_RTX;
 
       push_temp_slots ();
       tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
@@ -4673,8 +4650,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
 
       if (TREE_CODE (to) == COMPONENT_REF
          && DECL_BIT_FIELD_TYPE (TREE_OPERAND (to, 1)))
-       get_bit_range (&bitregion_start, &bitregion_end,
-                      to, tem, bitpos, bitsize);
+       get_bit_range (&bitregion_start, &bitregion_end, to, &bitpos, &offset);
 
       /* If we are going to use store_bit_field and extract_bit_field,
         make sure to_rtx will be safe for multiple use.  */
@@ -4686,8 +4662,44 @@ expand_assignment (tree to, tree from, bool nontemporal)
          && ((icode = optab_handler (movmisalign_optab, mode))
              != CODE_FOR_nothing))
        {
+         enum machine_mode address_mode;
+         rtx op0;
+         struct expand_operand ops[2];
+         addr_space_t as = TYPE_ADDR_SPACE
+             (TREE_TYPE (TREE_TYPE (TREE_OPERAND (tem, 0))));
+         tree base = TREE_OPERAND (tem, 0);
+
          misalignp = true;
          to_rtx = gen_reg_rtx (mode);
+
+         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);
+         if (TREE_THIS_VOLATILE (tem))
+           MEM_VOLATILE_P (mem) = 1;
+
+         /* If the misaligned store doesn't overwrite all bits, perform
+            rmw cycle on MEM.  */
+         if (bitsize != GET_MODE_BITSIZE (mode))
+           {
+             create_input_operand (&ops[0], to_rtx, mode);
+             create_fixed_operand (&ops[1], mem);
+             /* The movmisalign<mode> pattern cannot fail, else the assignment
+                would silently be omitted.  */
+             expand_insn (icode, 2, ops);
+
+             mem = copy_rtx (mem);
+           }
        }
       else
        {
@@ -4842,26 +4854,6 @@ expand_assignment (tree to, tree from, bool nontemporal)
       if (misalignp)
        {
          struct expand_operand ops[2];
-         enum machine_mode address_mode;
-         rtx op0, mem;
-         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);
-         if (TREE_THIS_VOLATILE (tem))
-           MEM_VOLATILE_P (mem) = 1;
 
          create_fixed_operand (&ops[0], mem);
          create_input_operand (&ops[1], to_rtx, mode);
@@ -6716,6 +6708,24 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   /* Otherwise, split it up.  */
   if (offset)
     {
+      /* Avoid returning a negative bitpos as this may wreak havoc later.  */
+      if (double_int_negative_p (bit_offset))
+        {
+         double_int mask
+           = double_int_mask (BITS_PER_UNIT == 8
+                              ? 3 : exact_log2 (BITS_PER_UNIT));
+         double_int tem = double_int_and_not (bit_offset, mask);
+         /* TEM is the bitpos rounded to BITS_PER_UNIT towards -Inf.
+            Subtract it to BIT_OFFSET and add it (scaled) to OFFSET.  */
+         bit_offset = double_int_sub (bit_offset, tem);
+         tem = double_int_rshift (tem,
+                                  BITS_PER_UNIT == 8
+                                  ? 3 : exact_log2 (BITS_PER_UNIT),
+                                  HOST_BITS_PER_DOUBLE_INT, true);
+         offset = size_binop (PLUS_EXPR, offset,
+                              double_int_to_tree (sizetype, tem));
+       }
+
       *pbitpos = double_int_to_shwi (bit_offset);
       *poffset = offset;
     }
@@ -7414,7 +7424,12 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
      generating ADDR_EXPR of something that isn't an LVALUE.  The only
      exception here is STRING_CST.  */
   if (CONSTANT_CLASS_P (exp))
-    return XEXP (expand_expr_constant (exp, 0, modifier), 0);
+    {
+      result = XEXP (expand_expr_constant (exp, 0, modifier), 0);
+      if (modifier < EXPAND_SUM)
+       result = force_operand (result, target);
+      return result;
+    }
 
   /* Everything must be something allowed by is_gimple_addressable.  */
   switch (TREE_CODE (exp))
@@ -7433,7 +7448,11 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
 
     case CONST_DECL:
       /* Expand the initializer like constants above.  */
-      return XEXP (expand_expr_constant (DECL_INITIAL (exp), 0, modifier), 0);
+      result = XEXP (expand_expr_constant (DECL_INITIAL (exp),
+                                          0, modifier), 0);
+      if (modifier < EXPAND_SUM)
+       result = force_operand (result, target);
+      return result;
 
     case REALPART_EXPR:
       /* The real part of the complex number is always first, therefore
@@ -8573,8 +8592,9 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       /* In case we have to reduce the result to bitfield precision
-        expand this as XOR with a proper constant instead.  */
-      if (reduce_bit_field)
+        for unsigned bitfield expand this as XOR with a proper constant
+        instead.  */
+      if (reduce_bit_field && TYPE_UNSIGNED (type))
        temp = expand_binop (mode, xor_optab, op0,
                             immed_double_int_const
                               (double_int_mask (TYPE_PRECISION (type)), mode),
@@ -8676,6 +8696,54 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
 
       if (!target)
        target = gen_reg_rtx (TYPE_MODE (type));
+      else
+       /* If target overlaps with op1, then either we need to force
+          op1 into a pseudo (if target also overlaps with op0),
+          or write the complex parts in reverse order.  */
+       switch (GET_CODE (target))
+         {
+         case CONCAT:
+           if (reg_overlap_mentioned_p (XEXP (target, 0), op1))
+             {
+               if (reg_overlap_mentioned_p (XEXP (target, 1), op0))
+                 {
+                 complex_expr_force_op1:
+                   temp = gen_reg_rtx (GET_MODE_INNER (GET_MODE (target)));
+                   emit_move_insn (temp, op1);
+                   op1 = temp;
+                   break;
+                 }
+             complex_expr_swap_order:
+               /* Move the imaginary (op1) and real (op0) parts to their
+                  location.  */
+               write_complex_part (target, op1, true);
+               write_complex_part (target, op0, false);
+
+               return target;
+             }
+           break;
+         case MEM:
+           temp = adjust_address_nv (target,
+                                     GET_MODE_INNER (GET_MODE (target)), 0);
+           if (reg_overlap_mentioned_p (temp, op1))
+             {
+               enum machine_mode imode = GET_MODE_INNER (GET_MODE (target));
+               temp = adjust_address_nv (target, imode,
+                                         GET_MODE_SIZE (imode));
+               if (reg_overlap_mentioned_p (temp, op0))
+                 goto complex_expr_force_op1;
+               goto complex_expr_swap_order;
+             }
+           break;
+         default:
+           if (reg_overlap_mentioned_p (target, op1))
+             {
+               if (reg_overlap_mentioned_p (target, op0))
+                 goto complex_expr_force_op1;
+               goto complex_expr_swap_order;
+             }
+           break;
+         }
 
       /* Move the real (op0) and imaginary (op1) parts to their location.  */
       write_complex_part (target, op0, false);
@@ -9637,6 +9705,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        orig_op0 = op0
          = expand_expr (tem,
                         (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
+                         && COMPLETE_TYPE_P (TREE_TYPE (tem))
                          && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
                              != INTEGER_CST)
                          && modifier != EXPAND_STACK_PARM