OSDN Git Service

2003-06-06 H.J. Lu <hongjiu.lu@intel.com>
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index ba7db15..7adaca0 100644 (file)
@@ -1456,6 +1456,18 @@ convert_modes (mode, oldmode, x, unsignedp)
 
 #define STORE_MAX_PIECES  MIN (MOVE_MAX_PIECES, 2 * sizeof (HOST_WIDE_INT))
 
+/* Determine whether the LEN bytes can be moved by using several move
+   instructions.  Return nonzero if a call to move_by_pieces should
+   succeed.  */
+
+int
+can_move_by_pieces (len, align)
+     unsigned HOST_WIDE_INT len;
+     unsigned int align;
+{
+  return MOVE_BY_PIECES_P (len, align);
+}
+
 /* Generate several move instructions to copy LEN bytes from block FROM to
    block TO.  (These are MEM rtx's with BLKmode).  The caller must pass FROM
    and TO through protect_from_queue before calling.
@@ -1463,13 +1475,18 @@ convert_modes (mode, oldmode, x, unsignedp)
    If PUSH_ROUNDING is defined and TO is NULL, emit_single_push_insn is
    used to push FROM to the stack.
 
-   ALIGN is maximum alignment we can assume.  */
+   ALIGN is maximum stack alignment we can assume.
 
-void
-move_by_pieces (to, from, len, align)
+   If ENDP is 0 return to, if ENDP is 1 return memory at the end ala
+   mempcpy, and if ENDP is 2 return memory the end minus one byte ala
+   stpcpy.  */
+
+rtx
+move_by_pieces (to, from, len, align, endp)
      rtx to, from;
      unsigned HOST_WIDE_INT len;
      unsigned int align;
+     int endp;
 {
   struct move_by_pieces data;
   rtx to_addr, from_addr = XEXP (from, 0);
@@ -1477,6 +1494,8 @@ move_by_pieces (to, from, len, align)
   enum machine_mode mode = VOIDmode, tmode;
   enum insn_code icode;
 
+  align = MIN (to ? MEM_ALIGN (to) : align, MEM_ALIGN (from));
+
   data.offset = 0;
   data.from_addr = from_addr;
   if (to)
@@ -1581,6 +1600,36 @@ move_by_pieces (to, from, len, align)
   /* The code above should have handled everything.  */
   if (data.len > 0)
     abort ();
+
+  if (endp)
+    {
+      rtx to1;
+
+      if (data.reverse)
+       abort ();
+      if (data.autinc_to)
+       {
+         if (endp == 2)
+           {
+             if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0)
+               emit_insn (gen_add2_insn (data.to_addr, constm1_rtx));
+             else
+               data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr,
+                                                               -1));
+           }
+         to1 = adjust_automodify_address (data.to, QImode, data.to_addr,
+                                          data.offset);
+       }
+      else
+       {
+         if (endp == 2)
+           --data.offset;
+         to1 = adjust_address (data.to, QImode, data.offset);
+       }
+      return to1;
+    }
+  else
+    return data.to;
 }
 
 /* Return number of insns required to move L bytes by pieces.
@@ -1758,7 +1807,7 @@ emit_block_move (x, y, size, method)
     }
 
   if (GET_CODE (size) == CONST_INT && MOVE_BY_PIECES_P (INTVAL (size), align))
-    move_by_pieces (x, y, INTVAL (size), align);
+    move_by_pieces (x, y, INTVAL (size), align, 0);
   else if (emit_block_move_via_movstr (x, y, size, align))
     ;
   else if (may_use_call)
@@ -2012,7 +2061,7 @@ init_block_move_fn (asmspec)
 {
   if (!block_move_fn)
     {
-      tree fn, args;
+      tree args, fn;
 
       if (TARGET_MEM_FUNCTIONS)
        {
@@ -2162,61 +2211,26 @@ move_block_to_reg (regno, x, nregs, mode)
 }
 
 /* Copy all or part of a BLKmode value X out of registers starting at REGNO.
-   The number of registers to be filled is NREGS.  SIZE indicates the number
-   of bytes in the object X.  */
+   The number of registers to be filled is NREGS.  */
 
 void
-move_block_from_reg (regno, x, nregs, size)
+move_block_from_reg (regno, x, nregs)
      int regno;
      rtx x;
      int nregs;
-     int size;
 {
   int i;
-#ifdef HAVE_store_multiple
-  rtx pat;
-  rtx last;
-#endif
-  enum machine_mode mode;
 
   if (nregs == 0)
     return;
 
-  /* If SIZE is that of a mode no bigger than a word, just use that
-     mode's store operation.  */
-  if (size <= UNITS_PER_WORD
-      && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
-    {
-      emit_move_insn (adjust_address (x, mode, 0), gen_rtx_REG (mode, regno));
-      return;
-    }
-
-  /* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned
-     to the left before storing to memory.  Note that the previous test
-     doesn't handle all cases (e.g. SIZE == 3).  */
-  if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
-    {
-      rtx tem = operand_subword (x, 0, 1, BLKmode);
-      rtx shift;
-
-      if (tem == 0)
-       abort ();
-
-      shift = expand_shift (LSHIFT_EXPR, word_mode,
-                           gen_rtx_REG (word_mode, regno),
-                           build_int_2 ((UNITS_PER_WORD - size)
-                                        * BITS_PER_UNIT, 0), NULL_RTX, 0);
-      emit_move_insn (tem, shift);
-      return;
-    }
-
   /* See if the machine can do this with a store multiple insn.  */
 #ifdef HAVE_store_multiple
   if (HAVE_store_multiple)
     {
-      last = get_last_insn ();
-      pat = gen_store_multiple (x, gen_rtx_REG (word_mode, regno),
-                               GEN_INT (nregs));
+      rtx last = get_last_insn ();
+      rtx pat = gen_store_multiple (x, gen_rtx_REG (word_mode, regno),
+                                   GEN_INT (nregs));
       if (pat)
        {
          emit_insn (pat);
@@ -2771,15 +2785,19 @@ can_store_by_pieces (len, constfun, constfundata, align)
 /* Generate several move instructions to store LEN bytes generated by
    CONSTFUN to block TO.  (A MEM rtx with BLKmode).  CONSTFUNDATA is a
    pointer which will be passed as argument in every CONSTFUN call.
-   ALIGN is maximum alignment we can assume.  */
+   ALIGN is maximum alignment we can assume.
+   If ENDP is 0 return to, if ENDP is 1 return memory at the end ala
+   mempcpy, and if ENDP is 2 return memory the end minus one byte ala
+   stpcpy.  */
 
-void
-store_by_pieces (to, len, constfun, constfundata, align)
+rtx
+store_by_pieces (to, len, constfun, constfundata, align, endp)
      rtx to;
      unsigned HOST_WIDE_INT len;
      rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode));
      PTR constfundata;
      unsigned int align;
+     int endp;
 {
   struct store_by_pieces data;
 
@@ -2791,6 +2809,35 @@ store_by_pieces (to, len, constfun, constfundata, align)
   data.len = len;
   data.to = to;
   store_by_pieces_1 (&data, align);
+  if (endp)
+    {
+      rtx to1;
+
+      if (data.reverse)
+       abort ();
+      if (data.autinc_to)
+       {
+         if (endp == 2)
+           {
+             if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0)
+               emit_insn (gen_add2_insn (data.to_addr, constm1_rtx));
+             else
+               data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr,
+                                                               -1));
+           }
+         to1 = adjust_automodify_address (data.to, QImode, data.to_addr,
+                                          data.offset);
+       }
+      else
+       {
+         if (endp == 2)
+           --data.offset;
+         to1 = adjust_address (data.to, QImode, data.offset);
+       }
+      return to1;
+    }
+  else
+    return data.to;
 }
 
 /* Generate several move instructions to clear LEN bytes of block TO.  (A MEM
@@ -3199,7 +3246,7 @@ emit_move_insn (x, y)
 {
   enum machine_mode mode = GET_MODE (x);
   rtx y_cst = NULL_RTX;
-  rtx last_insn;
+  rtx last_insn, set;
 
   x = protect_from_queue (x, 1);
   y = protect_from_queue (y, 0);
@@ -3217,9 +3264,10 @@ emit_move_insn (x, y)
          && (last_insn = compress_float_constant (x, y)))
        return last_insn;
 
+      y_cst = y;
+
       if (!LEGITIMATE_CONSTANT_P (y))
        {
-         y_cst = y;
          y = force_const_mem (mode, y);
 
          /* If the target's cannot_force_const_mem prevented the spill,
@@ -3250,7 +3298,10 @@ emit_move_insn (x, y)
 
   last_insn = emit_move_insn_1 (x, y);
 
-  if (y_cst && GET_CODE (x) == REG)
+  if (y_cst && GET_CODE (x) == REG
+      && (set = single_set (last_insn)) != NULL_RTX
+      && SET_DEST (set) == x
+      && ! rtx_equal_p (y_cst, SET_SRC (set)))
     set_unique_reg_note (last_insn, REG_EQUAL, y_cst);
 
   return last_insn;
@@ -3343,19 +3394,15 @@ emit_move_insn_1 (x, y)
          /* Note that the real part always precedes the imag part in memory
             regardless of machine's endianness.  */
 #ifdef STACK_GROWS_DOWNWARD
-         emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_rtx_MEM (submode, XEXP (x, 0)),
-                     gen_imagpart (submode, y)));
-         emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_rtx_MEM (submode, XEXP (x, 0)),
-                     gen_realpart (submode, y)));
+         emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
+                         gen_imagpart (submode, y));
+         emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
+                         gen_realpart (submode, y));
 #else
-         emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_rtx_MEM (submode, XEXP (x, 0)),
-                     gen_realpart (submode, y)));
-         emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (gen_rtx_MEM (submode, XEXP (x, 0)),
-                     gen_imagpart (submode, y)));
+         emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
+                         gen_realpart (submode, y));
+         emit_move_insn (gen_rtx_MEM (submode, XEXP (x, 0)),
+                         gen_imagpart (submode, y));
 #endif
        }
       else
@@ -3430,10 +3477,8 @@ emit_move_insn_1 (x, y)
                  || GET_CODE (imagpart_x) == SUBREG))
            emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
 
-         emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (realpart_x, realpart_y));
-         emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
-                    (imagpart_x, imagpart_y));
+         emit_move_insn (realpart_x, realpart_y);
+         emit_move_insn (imagpart_x, imagpart_y);
        }
 
       return get_last_insn ();
@@ -3654,8 +3699,7 @@ compress_float_constant (x, y)
       last_insn = get_last_insn ();
 
       if (GET_CODE (x) == REG)
-       REG_NOTES (last_insn)
-         = gen_rtx_EXPR_LIST (REG_EQUAL, y, REG_NOTES (last_insn));
+       set_unique_reg_note (last_insn, REG_EQUAL, y);
 
       return last_insn;
     }
@@ -3884,6 +3928,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
          && PUSH_ARGS
          && GET_CODE (size) == CONST_INT
          && skip == 0
+         && MEM_ALIGN (xinner) >= align
          && (MOVE_BY_PIECES_P ((unsigned) INTVAL (size) - used, align))
          /* Here we avoid the case of a structure whose weak alignment
             forces many pushes of a small amount of data,
@@ -3901,7 +3946,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
              && where_pad != none && where_pad != stack_direction)
            anti_adjust_stack (GEN_INT (extra));
 
-         move_by_pieces (NULL, xinner, INTVAL (size) - used, align);
+         move_by_pieces (NULL, xinner, INTVAL (size) - used, align, 0);
        }
       else
 #endif /* PUSH_ROUNDING  */
@@ -5014,7 +5059,7 @@ store_constructor (exp, target, cleared, size)
            {
              rtx offset_rtx;
 
-             if (contains_placeholder_p (offset))
+             if (CONTAINS_PLACEHOLDER_P (offset))
                offset = build (WITH_RECORD_EXPR, sizetype,
                                offset, make_tree (TREE_TYPE (exp), target));
 
@@ -5626,9 +5671,10 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, unsignedp, type,
       /* If the field isn't aligned enough to store as an ordinary memref,
         store it as a bit field.  */
       || (mode != BLKmode
-         && ((SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target))
-              && (MEM_ALIGN (target) < GET_MODE_ALIGNMENT (mode)))
-             || bitpos % GET_MODE_ALIGNMENT (mode)))
+         && ((((MEM_ALIGN (target) < GET_MODE_ALIGNMENT (mode))
+               || bitpos % GET_MODE_ALIGNMENT (mode))
+              && SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (target)))
+             || (bitpos % BITS_PER_UNIT != 0)))              
       /* If the RHS and field are a constant size and the size of the
         RHS isn't the same size as the bitfield, we must use bitfield
         operations.  */
@@ -5830,8 +5876,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
             made during type construction.  */
          if (this_offset == 0)
            break;
-         else if (! TREE_CONSTANT (this_offset)
-                  && contains_placeholder_p (this_offset))
+         else if (CONTAINS_PLACEHOLDER_P (this_offset))
            this_offset = build (WITH_RECORD_EXPR, sizetype, this_offset, exp);
 
          offset = size_binop (PLUS_EXPR, offset, this_offset);
@@ -5861,11 +5906,9 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
          /* If the index has a self-referential type, pass it to a
             WITH_RECORD_EXPR; if the component size is, pass our
             component to one.  */
-         if (! TREE_CONSTANT (index)
-             && contains_placeholder_p (index))
+         if (CONTAINS_PLACEHOLDER_P (index))
            index = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, exp);
-         if (! TREE_CONSTANT (unit_size)
-             && contains_placeholder_p (unit_size))
+         if (CONTAINS_PLACEHOLDER_P (unit_size))
            unit_size = build (WITH_RECORD_EXPR, sizetype, unit_size, array);
 
          offset = size_binop (PLUS_EXPR, offset,
@@ -6752,25 +6795,17 @@ expand_expr (exp, target, tmode, modifier)
     case LABEL_DECL:
       {
        tree function = decl_function_context (exp);
-       /* Handle using a label in a containing function.  */
-       if (function != current_function_decl
-           && function != inline_function_decl && function != 0)
-         {
-           struct function *p = find_function_data (function);
-           p->expr->x_forced_labels
-             = gen_rtx_EXPR_LIST (VOIDmode, label_rtx (exp),
-                                  p->expr->x_forced_labels);
-         }
+       /* Labels in containing functions, or labels used from initializers,
+          must be forced.  */
+       if (modifier == EXPAND_INITIALIZER
+           || (function != current_function_decl
+               && function != inline_function_decl
+               && function != 0))
+         temp = force_label_rtx (exp);
        else
-         {
-           if (modifier == EXPAND_INITIALIZER)
-             forced_labels = gen_rtx_EXPR_LIST (VOIDmode,
-                                                label_rtx (exp),
-                                                forced_labels);
-         }
+         temp = label_rtx (exp);
 
-       temp = gen_rtx_MEM (FUNCTION_MODE,
-                           gen_rtx_LABEL_REF (Pmode, label_rtx (exp)));
+       temp = gen_rtx_MEM (FUNCTION_MODE, gen_rtx_LABEL_REF (Pmode, temp));
        if (function != current_function_decl
            && function != inline_function_decl && function != 0)
          LABEL_REF_NONLOCAL_P (XEXP (temp, 0)) = 1;
@@ -7202,7 +7237,9 @@ expand_expr (exp, target, tmode, modifier)
                        && ((TREE_CODE (type) == VECTOR_TYPE
                             && !is_zeros_p (exp))
                            || ! mostly_zeros_p (exp)))))
-              || (modifier == EXPAND_INITIALIZER && TREE_CONSTANT (exp)))
+              || ((modifier == EXPAND_INITIALIZER
+                   || modifier == EXPAND_CONST_ADDRESS)
+                  && TREE_CONSTANT (exp)))
        {
          rtx constructor = output_constant_def (exp, 1);
 
@@ -7571,9 +7608,10 @@ expand_expr (exp, target, tmode, modifier)
            /* If the field isn't aligned enough to fetch as a memref,
               fetch it as a bit field.  */
            || (mode1 != BLKmode
-               && ((TYPE_ALIGN (TREE_TYPE (tem)) < GET_MODE_ALIGNMENT (mode)
+               && (((TYPE_ALIGN (TREE_TYPE (tem)) < GET_MODE_ALIGNMENT (mode)
+                     || (bitpos % GET_MODE_ALIGNMENT (mode) != 0))
                     && SLOW_UNALIGNED_ACCESS (mode1, MEM_ALIGN (op0)))
-                   || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)))
+                   || (bitpos % BITS_PER_UNIT != 0)))
            /* If the type and the field are a constant size and the
               size of the type isn't the same size as the bitfield,
               we must use bitfield operations.  */