OSDN Git Service

* tree.h (DECIMAL_FLOAT_TYPE_P): New.
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 904d4fc..e46e3e7 100644 (file)
@@ -1940,11 +1940,11 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
       if (start < finish)
        {
          inner = GET_MODE (tmps[start]);
-         bytepos = subreg_lowpart_offset (outer, inner);
+         bytepos = subreg_lowpart_offset (inner, outer);
          if (INTVAL (XEXP (XVECEXP (src, 0, start), 1)) == bytepos)
            {
              temp = simplify_gen_subreg (outer, tmps[start],
-                                         inner, bytepos);
+                                         inner, 0);
              if (temp)
                {
                  emit_move_insn (dst, temp);
@@ -1959,11 +1959,11 @@ emit_group_store (rtx orig_dst, rtx src, tree type ATTRIBUTE_UNUSED, int ssize)
          && start < finish - 1)
        {
          inner = GET_MODE (tmps[finish - 1]);
-         bytepos = subreg_lowpart_offset (outer, inner);
+         bytepos = subreg_lowpart_offset (inner, outer);
          if (INTVAL (XEXP (XVECEXP (src, 0, finish - 1), 1)) == bytepos)
            {
              temp = simplify_gen_subreg (outer, tmps[finish - 1],
-                                         inner, bytepos);
+                                         inner, 0);
              if (temp)
                {
                  emit_move_insn (dst, temp);
@@ -3096,6 +3096,38 @@ emit_move_ccmode (enum machine_mode mode, rtx x, rtx y)
   return ret;
 }
 
+/* Return true if word I of OP lies entirely in the
+   undefined bits of a paradoxical subreg.  */
+
+static bool
+undefined_operand_subword_p (rtx op, int i)
+{
+  enum machine_mode innermode, innermostmode;
+  int offset;
+  if (GET_CODE (op) != SUBREG)
+    return false;
+  innermode = GET_MODE (op);
+  innermostmode = GET_MODE (SUBREG_REG (op));
+  offset = i * UNITS_PER_WORD + SUBREG_BYTE (op);
+  /* The SUBREG_BYTE represents offset, as if the value were stored in
+     memory, except for a paradoxical subreg where we define
+     SUBREG_BYTE to be 0; undo this exception as in
+     simplify_subreg.  */
+  if (SUBREG_BYTE (op) == 0
+      && GET_MODE_SIZE (innermostmode) < GET_MODE_SIZE (innermode))
+    {
+      int difference = (GET_MODE_SIZE (innermostmode) - GET_MODE_SIZE (innermode));
+      if (WORDS_BIG_ENDIAN)
+       offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+      if (BYTES_BIG_ENDIAN)
+       offset += difference % UNITS_PER_WORD;
+    }
+  if (offset >= GET_MODE_SIZE (innermostmode)
+      || offset <= -GET_MODE_SIZE (word_mode))
+    return true;
+  return false;
+}
+
 /* A subroutine of emit_move_insn_1.  Generate a move from Y into X.
    MODE is any multi-word or full-word mode that lacks a move_insn
    pattern.  Note that you will get better code if you define such
@@ -3133,7 +3165,14 @@ emit_move_multi_word (enum machine_mode mode, rtx x, rtx y)
        i++)
     {
       rtx xpart = operand_subword (x, i, 1, mode);
-      rtx ypart = operand_subword (y, i, 1, mode);
+      rtx ypart;
+
+      /* Do not generate code for a move if it would come entirely
+        from the undefined bits of a paradoxical subreg.  */
+      if (undefined_operand_subword_p (y, i))
+       continue;
+
+      ypart = operand_subword (y, i, 1, mode);
 
       /* If we can't get a part of Y, put Y into memory if it is a
         constant.  Otherwise, force it into a register.  Then we must
@@ -3346,7 +3385,11 @@ compress_float_constant (rtx x, rtx y)
        }
       else
        continue;
+
+      /* For CSE's benefit, force the compressed constant pool entry
+        into a new pseudo.  This constant may be used in different modes,
+        and if not, combine will put things back together for us.  */
+      trunc_y = force_reg (srcmode, trunc_y);
       emit_unop_insn (ic, x, trunc_y, UNKNOWN);
       last_insn = get_last_insn ();
 
@@ -3984,13 +4027,16 @@ expand_assignment (tree to, tree from)
   rtx result;
 
   /* Don't crash if the lhs of the assignment was erroneous.  */
-
   if (TREE_CODE (to) == ERROR_MARK)
     {
       result = expand_normal (from);
       return;
     }
 
+  /* Optimize away no-op moves without side-effects.  */
+  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
@@ -5325,7 +5371,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
          }
        
        /* Inform later passes that the old value is dead.  */
-       if (!cleared && REG_P (target))
+       if (!cleared && !vector && REG_P (target))
          emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
 
         /* Store each element of the constructor into the corresponding
@@ -6068,6 +6114,19 @@ safe_from_p (rtx x, tree exp, int top_p)
                return safe_from_p (x, exp, 0);
            }
        }
+      else if (TREE_CODE (exp) == CONSTRUCTOR)
+       {
+         constructor_elt *ce;
+         unsigned HOST_WIDE_INT idx;
+
+         for (idx = 0;
+              VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), idx, ce);
+              idx++)
+           if ((ce->index != NULL_TREE && !safe_from_p (x, ce->index, 0))
+               || !safe_from_p (x, ce->value, 0))
+             return 0;
+         return 1;
+       }
       else if (TREE_CODE (exp) == ERROR_MARK)
        return 1;       /* An already-visited SAVE_EXPR? */
       else
@@ -6880,14 +6939,23 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return temp;
 
     case VECTOR_CST:
-      if (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_INT
-         || GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_FLOAT)
-       return const_vector_from_tree (exp);
-      else
-       return expand_expr (build_constructor_from_list
-                           (TREE_TYPE (exp),
-                            TREE_VECTOR_CST_ELTS (exp)),
-                           ignore ? const0_rtx : target, tmode, modifier);
+      {
+       tree tmp = NULL_TREE;
+       if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+         return const_vector_from_tree (exp);
+       if (GET_MODE_CLASS (mode) == MODE_INT)
+         {
+           tree type_for_mode = lang_hooks.types.type_for_mode (mode, 1);
+           if (type_for_mode)
+             tmp = fold_unary (VIEW_CONVERT_EXPR, type_for_mode, exp);
+         }
+       if (!tmp)
+         tmp = build_constructor_from_list (type,
+                                            TREE_VECTOR_CST_ELTS (exp));
+       return expand_expr (tmp, ignore ? const0_rtx : target,
+                           tmode, modifier);
+      }
 
     case CONST_DECL:
       return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
@@ -7717,7 +7785,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       else if (!MEM_P (op0))
        {
          /* If the operand is not a MEM, force it into memory.  Since we
-            are going to be be changing the mode of the MEM, don't call
+            are going to be changing the mode of the MEM, don't call
             force_const_mem for constants because we don't allow pool
             constants to change mode.  */
          tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));