OSDN Git Service

(TARGET_CPU_CPP_BUILTINS): Add builtin assert of cpu=xstormy16.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 8701c3d..f949930 100644 (file)
@@ -1557,19 +1557,37 @@ gen_group_rtx (rtx orig)
   return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
 }
 
-/* Emit code to move a block ORIG_SRC of type TYPE to a block DST,
-   where DST is non-consecutive registers represented by a PARALLEL.
-   SSIZE represents the total size of block ORIG_SRC in bytes, or -1
-   if not known.  */
+/* A subroutine of emit_group_load.  Arguments as for emit_group_load,
+   except that values are placed in TMPS[i], and must later be moved
+   into corresponding XEXP (XVECEXP (DST, 0, i), 0) element.  */
 
-void
-emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
+static void
+emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
 {
-  rtx *tmps, src;
+  rtx src;
   int start, i;
+  enum machine_mode m = GET_MODE (orig_src);
 
   gcc_assert (GET_CODE (dst) == PARALLEL);
 
+  if (!SCALAR_INT_MODE_P (m)
+      && !MEM_P (orig_src) && GET_CODE (orig_src) != CONCAT)
+    {
+      enum machine_mode imode = int_mode_for_mode (GET_MODE (orig_src));
+      if (imode == BLKmode)
+       src = assign_stack_temp (GET_MODE (orig_src), ssize, 0);
+      else
+       src = gen_reg_rtx (imode);
+      if (imode != BLKmode)
+       src = gen_lowpart (GET_MODE (orig_src), src);
+      emit_move_insn (src, orig_src);
+      /* ...and back again.  */
+      if (imode != BLKmode)
+       src = gen_lowpart (imode, src);
+      emit_group_load_1 (tmps, dst, src, type, ssize);
+      return;
+    }
+
   /* Check for a NULL entry, used to indicate that the parameter goes
      both on the stack and in registers.  */
   if (XEXP (XVECEXP (dst, 0, 0), 0))
@@ -1577,8 +1595,6 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
   else
     start = 1;
 
-  tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));
-
   /* Process the pieces.  */
   for (i = start; i < XVECLEN (dst, 0); i++)
     {
@@ -1654,11 +1670,12 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
          else
            {
              rtx mem;
-             
+
              gcc_assert (!bytepos);
              mem = assign_stack_temp (GET_MODE (src), slen, 0);
              emit_move_insn (mem, src);
-             tmps[i] = adjust_address (mem, mode, 0);
+             tmps[i] = extract_bit_field (mem, bytelen * BITS_PER_UNIT,
+                                          0, 1, NULL_RTX, mode, mode);
            }
        }
       /* FIXME: A SIMD parallel will eventually lead to a subreg of a
@@ -1689,10 +1706,61 @@ emit_group_load (rtx dst, rtx orig_src, tree type ATTRIBUTE_UNUSED, int ssize)
        tmps[i] = expand_shift (LSHIFT_EXPR, mode, tmps[i],
                                build_int_cst (NULL_TREE, shift), tmps[i], 0);
     }
+}
+
+/* Emit code to move a block SRC of type TYPE to a block DST,
+   where DST is non-consecutive registers represented by a PARALLEL.
+   SSIZE represents the total size of block ORIG_SRC in bytes, or -1
+   if not known.  */
+
+void
+emit_group_load (rtx dst, rtx src, tree type, int ssize)
+{
+  rtx *tmps;
+  int i;
+
+  tmps = alloca (sizeof (rtx) * XVECLEN (dst, 0));
+  emit_group_load_1 (tmps, dst, src, type, ssize);
 
   /* Copy the extracted pieces into the proper (probable) hard regs.  */
-  for (i = start; i < XVECLEN (dst, 0); i++)
-    emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
+  for (i = 0; i < XVECLEN (dst, 0); i++)
+    {
+      rtx d = XEXP (XVECEXP (dst, 0, i), 0);
+      if (d == NULL)
+       continue;
+      emit_move_insn (d, tmps[i]);
+    }
+}
+
+/* Similar, but load SRC into new pseudos in a format that looks like
+   PARALLEL.  This can later be fed to emit_group_move to get things
+   in the right place.  */
+
+rtx
+emit_group_load_into_temps (rtx parallel, rtx src, tree type, int ssize)
+{
+  rtvec vec;
+  int i;
+
+  vec = rtvec_alloc (XVECLEN (parallel, 0));
+  emit_group_load_1 (&RTVEC_ELT (vec, 0), parallel, src, type, ssize);
+
+  /* Convert the vector to look just like the original PARALLEL, except
+     with the computed values.  */
+  for (i = 0; i < XVECLEN (parallel, 0); i++)
+    {
+      rtx e = XVECEXP (parallel, 0, i);
+      rtx d = XEXP (e, 0);
+
+      if (d)
+       {
+         d = force_reg (GET_MODE (d), RTVEC_ELT (vec, i));
+         e = alloc_EXPR_LIST (REG_NOTE_KIND (e), d, XEXP (e, 1));
+       }
+      RTVEC_ELT (vec, i) = e;
+    }
+
+  return gen_rtx_PARALLEL (GET_MODE (parallel), vec);
 }
 
 /* Emit code to move a block SRC to block DST, where SRC and DST are
@@ -1713,6 +1781,27 @@ emit_group_move (rtx dst, rtx src)
                    XEXP (XVECEXP (src, 0, i), 0));
 }
 
+/* Move a group of registers represented by a PARALLEL into pseudos.  */
+
+rtx
+emit_group_move_into_temps (rtx src)
+{
+  rtvec vec = rtvec_alloc (XVECLEN (src, 0));
+  int i;
+
+  for (i = 0; i < XVECLEN (src, 0); i++)
+    {
+      rtx e = XVECEXP (src, 0, i);
+      rtx d = XEXP (e, 0);
+
+      if (d)
+       e = alloc_EXPR_LIST (REG_NOTE_KIND (e), copy_to_reg (d), XEXP (e, 1));
+      RTVEC_ELT (vec, i) = e;
+    }
+
+  return gen_rtx_PARALLEL (GET_MODE (src), vec);
+}
+
 /* Emit code to move a block SRC to a block ORIG_DST of type TYPE,
    where SRC is non-consecutive registers represented by a PARALLEL.
    SSIZE represents the total size of block ORIG_DST, or -1 if not
@@ -1723,9 +1812,25 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
 {
   rtx *tmps, dst;
   int start, i;
+  enum machine_mode m = GET_MODE (orig_dst);
 
   gcc_assert (GET_CODE (src) == PARALLEL);
 
+  if (!SCALAR_INT_MODE_P (m)
+      && !MEM_P (orig_dst) && GET_CODE (orig_dst) != CONCAT)
+    {
+      enum machine_mode imode = int_mode_for_mode (GET_MODE (orig_dst));
+      if (imode == BLKmode)
+        dst = assign_stack_temp (GET_MODE (orig_dst), ssize, 0);
+      else
+        dst = gen_reg_rtx (imode);
+      emit_group_store (dst, src, type, ssize);
+      if (imode != BLKmode)
+        dst = gen_lowpart (GET_MODE (orig_dst), dst);
+      emit_move_insn (orig_dst, dst);
+      return;
+    }
+
   /* Check for a NULL entry, used to indicate that the parameter goes
      both on the stack and in registers.  */
   if (XEXP (XVECEXP (src, 0, 0), 0))
@@ -3738,14 +3843,6 @@ expand_assignment (tree to, tree from)
 /* Generate code for computing expression EXP,
    and storing the value into TARGET.
 
-   If WANT_VALUE & 1 is nonzero, return a copy of the value
-   not in TARGET, so that we can be sure to use the proper
-   value in a containing expression even if TARGET has something
-   else stored in it.  If possible, we copy the value through a pseudo
-   and return that pseudo.  Or, if the value is constant, we try to
-   return the constant.  In some cases, we return a pseudo
-   copied *from* TARGET.
-
    If the mode is BLKmode then we may return TARGET itself.
    It turns out that in BLKmode it doesn't cause a problem.
    because C has no operators that could combine two different
@@ -3753,27 +3850,22 @@ expand_assignment (tree to, tree from)
    with no sequence point.  Will other languages need this to
    be more thorough?
 
-   If WANT_VALUE & 1 is 0, we return NULL, to make sure
-   to catch quickly any cases where the caller uses the value
-   and fails to set WANT_VALUE.
-
-   If WANT_VALUE & 2 is set, this is a store into a call param on the
+   If CALL_PARAM_P is nonzero, this is a store into a call param on the
    stack, and block moves may need to be treated specially.  */
 
 rtx
-store_expr (tree exp, rtx target, int want_value)
+store_expr (tree exp, rtx target, int call_param_p)
 {
   rtx temp;
   rtx alt_rtl = NULL_RTX;
   int dont_return_target = 0;
-  int dont_store_target = 0;
 
   if (VOID_TYPE_P (TREE_TYPE (exp)))
     {
       /* C++ can generate ?: expressions with a throw expression in one
         branch and an rvalue in the other. Here, we resolve attempts to
         store the throw expression's nonexistent result.  */
-      gcc_assert (!want_value);
+      gcc_assert (!call_param_p);
       expand_expr (exp, const0_rtx, VOIDmode, 0);
       return NULL_RTX;
     }
@@ -3782,8 +3874,8 @@ store_expr (tree exp, rtx target, int want_value)
       /* Perform first part of compound expression, then assign from second
         part.  */
       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
-                  want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
-      return store_expr (TREE_OPERAND (exp, 1), target, want_value);
+                  call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL);
+      return store_expr (TREE_OPERAND (exp, 1), target, call_param_p);
     }
   else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode)
     {
@@ -3797,40 +3889,15 @@ store_expr (tree exp, rtx target, int want_value)
       do_pending_stack_adjust ();
       NO_DEFER_POP;
       jumpifnot (TREE_OPERAND (exp, 0), lab1);
-      store_expr (TREE_OPERAND (exp, 1), target, want_value & 2);
+      store_expr (TREE_OPERAND (exp, 1), target, call_param_p);
       emit_jump_insn (gen_jump (lab2));
       emit_barrier ();
       emit_label (lab1);
-      store_expr (TREE_OPERAND (exp, 2), target, want_value & 2);
+      store_expr (TREE_OPERAND (exp, 2), target, call_param_p);
       emit_label (lab2);
       OK_DEFER_POP;
 
-      return want_value & 1 ? target : NULL_RTX;
-    }
-  else if ((want_value & 1) != 0
-          && MEM_P (target)
-          && ! MEM_VOLATILE_P (target)
-          && GET_MODE (target) != BLKmode)
-    /* If target is in memory and caller wants value in a register instead,
-       arrange that.  Pass TARGET as target for expand_expr so that,
-       if EXP is another assignment, WANT_VALUE will be nonzero for it.
-       We know expand_expr will not use the target in that case.
-       Don't do this if TARGET is volatile because we are supposed
-       to write it and then read it.  */
-    {
-      temp = expand_expr (exp, target, GET_MODE (target),
-                         want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
-      if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
-       {
-         /* If TEMP is already in the desired TARGET, only copy it from
-            memory and don't store it there again.  */
-         if (temp == target
-             || (rtx_equal_p (temp, target)
-                 && ! side_effects_p (temp) && ! side_effects_p (target)))
-           dont_store_target = 1;
-         temp = copy_to_reg (temp);
-       }
-      dont_return_target = 1;
+      return NULL_RTX;
     }
   else if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
     /* If this is a scalar in a register that is stored in a wider mode
@@ -3840,14 +3907,13 @@ store_expr (tree exp, rtx target, int want_value)
     {
       rtx inner_target = 0;
 
-      /* If we don't want a value, we can do the conversion inside EXP,
-        which will often result in some optimizations.  Do the conversion
-        in two steps: first change the signedness, if needed, then
-        the extend.  But don't do this if the type of EXP is a subtype
-        of something else since then the conversion might involve
-        more than just converting modes.  */
-      if ((want_value & 1) == 0
-         && INTEGRAL_TYPE_P (TREE_TYPE (exp))
+      /* We can do the conversion inside EXP, which will often result
+        in some optimizations.  Do the conversion in two steps: first
+        change the signedness, if needed, then the extend.  But don't
+        do this if the type of EXP is a subtype of something else
+        since then the conversion might involve more than just
+        converting modes.  */
+      if (INTEGRAL_TYPE_P (TREE_TYPE (exp))
          && TREE_TYPE (TREE_TYPE (exp)) == 0
          && (!lang_hooks.reduce_bit_field_operations
              || (GET_MODE_PRECISION (GET_MODE (target))
@@ -3868,15 +3934,7 @@ store_expr (tree exp, rtx target, int want_value)
        }
 
       temp = expand_expr (exp, inner_target, VOIDmode,
-                         want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
-
-      /* If TEMP is a MEM and we want a result value, make the access
-        now so it gets done only once.  Strictly speaking, this is
-        only necessary if the MEM is volatile, or if the address
-        overlaps TARGET.  But not performing the load twice also
-        reduces the amount of rtl we generate and then have to CSE.  */
-      if (MEM_P (temp) && (want_value & 1) != 0)
-       temp = copy_to_reg (temp);
+                         call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL);
 
       /* If TEMP is a VOIDmode constant, use convert_modes to make
         sure that we properly convert it.  */
@@ -3892,31 +3950,12 @@ store_expr (tree exp, rtx target, int want_value)
       convert_move (SUBREG_REG (target), temp,
                    SUBREG_PROMOTED_UNSIGNED_P (target));
 
-      /* If we promoted a constant, change the mode back down to match
-        target.  Otherwise, the caller might get confused by a result whose
-        mode is larger than expected.  */
-
-      if ((want_value & 1) != 0 && GET_MODE (temp) != GET_MODE (target))
-       {
-         if (GET_MODE (temp) != VOIDmode)
-           {
-             temp = gen_lowpart_SUBREG (GET_MODE (target), temp);
-             SUBREG_PROMOTED_VAR_P (temp) = 1;
-             SUBREG_PROMOTED_UNSIGNED_SET (temp,
-               SUBREG_PROMOTED_UNSIGNED_P (target));
-           }
-         else
-           temp = convert_modes (GET_MODE (target),
-                                 GET_MODE (SUBREG_REG (target)),
-                                 temp, SUBREG_PROMOTED_UNSIGNED_P (target));
-       }
-
-      return want_value & 1 ? temp : NULL_RTX;
+      return NULL_RTX;
     }
   else
     {
       temp = expand_expr_real (exp, target, GET_MODE (target),
-                              (want_value & 2
+                              (call_param_p
                                ? EXPAND_STACK_PARM : EXPAND_NORMAL),
                               &alt_rtl);
       /* Return TARGET if it's a specified hardware register.
@@ -3930,7 +3969,7 @@ store_expr (tree exp, rtx target, int want_value)
            && REGNO (target) < FIRST_PSEUDO_REGISTER)
          && !(MEM_P (target) && MEM_VOLATILE_P (target))
          && ! rtx_equal_p (temp, target)
-         && (CONSTANT_P (temp) || (want_value & 1) != 0))
+         && CONSTANT_P (temp))
        dont_return_target = 1;
     }
 
@@ -3966,7 +4005,6 @@ store_expr (tree exp, rtx target, int want_value)
        || (temp != target && (side_effects_p (temp)
                              || side_effects_p (target))))
       && TREE_CODE (exp) != ERROR_MARK
-      && ! dont_store_target
       /* If store_expr stores a DECL whose DECL_RTL(exp) == TARGET,
         but TARGET is not valid memory reference, TEMP will differ
         from TARGET although it is really the same location.  */
@@ -4004,7 +4042,7 @@ store_expr (tree exp, rtx target, int want_value)
          if (GET_CODE (size) == CONST_INT
              && INTVAL (size) < TREE_STRING_LENGTH (exp))
            emit_block_move (target, temp, size,
-                            (want_value & 2
+                            (call_param_p
                              ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
          else
            {
@@ -4015,7 +4053,7 @@ store_expr (tree exp, rtx target, int want_value)
                              size_int (TREE_STRING_LENGTH (exp)));
              rtx copy_size_rtx
                = expand_expr (copy_size, NULL_RTX, VOIDmode,
-                              (want_value & 2
+                              (call_param_p
                                ? EXPAND_STACK_PARM : EXPAND_NORMAL));
              rtx label = 0;
 
@@ -4023,7 +4061,7 @@ store_expr (tree exp, rtx target, int want_value)
              copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx,
                                               TYPE_UNSIGNED (sizetype));
              emit_block_move (target, temp, copy_size_rtx,
-                              (want_value & 2
+                              (call_param_p
                                ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
 
              /* Figure out how much is left in TARGET that we have to clear.
@@ -4067,7 +4105,7 @@ store_expr (tree exp, rtx target, int want_value)
                         int_size_in_bytes (TREE_TYPE (exp)));
       else if (GET_MODE (temp) == BLKmode)
        emit_block_move (target, temp, expr_size (exp),
-                        (want_value & 2
+                        (call_param_p
                          ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
       else
        {
@@ -4077,24 +4115,7 @@ store_expr (tree exp, rtx target, int want_value)
        }
     }
 
-  /* If we don't want a value, return NULL_RTX.  */
-  if ((want_value & 1) == 0)
-    return NULL_RTX;
-
-  /* If we are supposed to return TEMP, do so as long as it isn't a MEM.
-     ??? The latter test doesn't seem to make sense.  */
-  else if (dont_return_target && !MEM_P (temp))
-    return temp;
-
-  /* Return TARGET itself if it is a hard register.  */
-  else if ((want_value & 1) != 0
-          && GET_MODE (target) != BLKmode
-          && ! (REG_P (target)
-                && REGNO (target) < FIRST_PSEUDO_REGISTER))
-    return copy_to_reg (target);
-
-  else
-    return target;
+  return NULL_RTX;
 }
 \f
 /* Examine CTOR.  Discover how many scalar fields are set to nonzero
@@ -4261,7 +4282,7 @@ count_type_elements (tree type)
 
 /* Return 1 if EXP contains mostly (3/4)  zeros.  */
 
-int
+static int
 mostly_zeros_p (tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
@@ -7209,7 +7230,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            /* Store data into beginning of memory target.  */
            store_expr (TREE_OPERAND (exp, 0),
                        adjust_address (target, TYPE_MODE (valtype), 0),
-                       modifier == EXPAND_STACK_PARM ? 2 : 0);
+                       modifier == EXPAND_STACK_PARM);
 
          else
            {
@@ -7980,13 +8001,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        op1 = gen_label_rtx ();
        jumpifnot (TREE_OPERAND (exp, 0), op0);
        store_expr (TREE_OPERAND (exp, 1), temp,
-                 modifier == EXPAND_STACK_PARM ? 2 : 0);
+                 modifier == EXPAND_STACK_PARM);
 
        emit_jump_insn (gen_jump (op1));
        emit_barrier ();
        emit_label (op0);
        store_expr (TREE_OPERAND (exp, 2), temp,
-                 modifier == EXPAND_STACK_PARM ? 2 : 0);
+                 modifier == EXPAND_STACK_PARM);
 
        emit_label (op1);
        OK_DEFER_POP;