]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR target/19518 ([alpha] unrecognizable insn (set (reg:V4HI) (const_vector:V4HI...
authorRichard Henderson <rth@redhat.com>
Thu, 20 Jan 2005 03:59:00 +0000 (19:59 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Thu, 20 Jan 2005 03:59:00 +0000 (19:59 -0800)
        PR target/19518
        * config/alpha/alpha.c (alpha_rtx_costs): Handle HIGH.
        (alpha_preferred_reload_class): Handle CONST_VECTOR.
        (alpha_emit_set_const_1): Add no_output parameter; don't emit
        rtl if true.
        (alpha_emit_set_const): Likewise.  Make static.
        (alpha_emit_set_long_const): Make static.
        (alpha_extract_integer): Split out from alpha_expand_mov.
        (alpha_split_const_mov): Likewise.
        (alpha_expand_mov): Use them.  Handle CONST_VECTOR.
        (alpha_legitimate_constant_p): New.
        * config/alpha/alpha-protos.h: Update.
        * config/alpha/alpha.h (REGISTER_MOVE_COST): Correct fp<->gp cost.
        (LEGITIMATE_CONSTANT_P): Re-implement with a function.
        * config/alpha/alpha.md (movsi): Add n alternative.
        (movsi_nt_vms, movdi_er_nofix, movdi_er_fix, movdi_fix): Likewise.
        (mov<VEC>_fix, mov<VEC>_nofix): Add i alternative.
        (splitters for all of the above): Use alpha_split_const_mov.
        * config/alpha/predicates.md (non_add_const_operand): New.
        (non_zero_const_operand): New.
        (input_operand): Use alpha_legitimate_constant_p after reload.

From-SVN: r93943

gcc/ChangeLog
gcc/config/alpha/alpha-protos.h
gcc/config/alpha/alpha.c
gcc/config/alpha/alpha.h
gcc/config/alpha/alpha.md
gcc/config/alpha/predicates.md
gcc/testsuite/gcc.target/alpha/alpha.exp [new file with mode: 0644]
gcc/testsuite/gcc.target/alpha/pr19518.c [new file with mode: 0644]

index 5141fc03c8cb62d542b8533e20d6526e7bafdbf7..540ad52fe0612742996b3ebe13594e04bed25a4b 100644 (file)
@@ -1,3 +1,27 @@
+2005-01-19  Richard Henderson  <rth@redhat.com>
+
+       PR target/19518
+       * config/alpha/alpha.c (alpha_rtx_costs): Handle HIGH.
+       (alpha_preferred_reload_class): Handle CONST_VECTOR.
+       (alpha_emit_set_const_1): Add no_output parameter; don't emit
+       rtl if true.
+       (alpha_emit_set_const): Likewise.  Make static.
+       (alpha_emit_set_long_const): Make static.
+       (alpha_extract_integer): Split out from alpha_expand_mov.
+       (alpha_split_const_mov): Likewise.
+       (alpha_expand_mov): Use them.  Handle CONST_VECTOR.
+       (alpha_legitimate_constant_p): New.
+       * config/alpha/alpha-protos.h: Update.
+       * config/alpha/alpha.h (REGISTER_MOVE_COST): Correct fp<->gp cost.
+       (LEGITIMATE_CONSTANT_P): Re-implement with a function.
+       * config/alpha/alpha.md (movsi): Add n alternative.
+       (movsi_nt_vms, movdi_er_nofix, movdi_er_fix, movdi_fix): Likewise.
+       (mov<VEC>_fix, mov<VEC>_nofix): Add i alternative.
+       (splitters for all of the above): Use alpha_split_const_mov.
+       * config/alpha/predicates.md (non_add_const_operand): New.
+       (non_zero_const_operand): New.
+       (input_operand): Use alpha_legitimate_constant_p after reload.
+
 2005-01-19  Zdenek Dvorak  <dvorakz@suse.cz>
 
        PR tree-optimization/19038
index 24f24e6b2bf12b226bdc0e53f9b81236ab2a6470..d1ffada3dcfa3fc5518816c6a567604710fafbbe 100644 (file)
@@ -42,6 +42,7 @@ extern bool alpha_extra_constraint (rtx, int);
 extern rtx alpha_tablejump_addr_vec (rtx);
 extern rtx alpha_tablejump_best_label (rtx);
 
+extern bool alpha_legitimate_constant_p (rtx);
 extern bool alpha_legitimate_address_p (enum machine_mode, rtx, int);
 extern rtx alpha_legitimize_address (rtx, rtx, enum machine_mode);
 extern rtx alpha_legitimize_reload_address (rtx, enum machine_mode,
@@ -56,8 +57,7 @@ extern enum reg_class secondary_reload_class (enum reg_class,
                                              enum machine_mode, rtx, int);
 
 extern void alpha_set_memflags (rtx, rtx);
-extern rtx alpha_emit_set_const (rtx, enum machine_mode, HOST_WIDE_INT, int);
-extern rtx alpha_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
+extern bool alpha_split_const_mov (enum machine_mode, rtx *);
 extern bool alpha_expand_mov (enum machine_mode, rtx *);
 extern bool alpha_expand_mov_nobwx (enum machine_mode, rtx *);
 extern void alpha_expand_movmisalign (enum machine_mode, rtx *);
index aed7ada56190eab741127b3089bfd0cf3e500795..037dc4ad33e70bcd3912f0f505bf37b7c3bab976 100644 (file)
@@ -1384,6 +1384,11 @@ alpha_rtx_costs (rtx x, int code, int outer_code, int *total)
        *total = COSTS_N_INSNS (optimize_size ? 1 : alpha_memory_latency);
       return true;
 
+    case HIGH:
+      /* This is effectively an add_operand.  */
+      *total = 2;
+      return true;
+
     case PLUS:
     case MINUS:
       if (float_mode_p)
@@ -1557,7 +1562,9 @@ alpha_preferred_reload_class(rtx x, enum reg_class class)
     return class;
 
   /* These sorts of constants we can easily drop to memory.  */
-  if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
+  if (GET_CODE (x) == CONST_INT
+      || GET_CODE (x) == CONST_DOUBLE
+      || GET_CODE (x) == CONST_VECTOR)
     {
       if (class == FLOAT_REGS)
        return NO_REGS;
@@ -1679,11 +1686,16 @@ alpha_set_memflags (rtx insn, rtx ref)
   for_each_rtx (base_ptr, alpha_set_memflags_1, (void *) ref);
 }
 \f
-/* Internal routine for alpha_emit_set_const to check for N or below insns.  */
+static rtx alpha_emit_set_const (rtx, enum machine_mode, HOST_WIDE_INT,
+                                int, bool);
+
+/* Internal routine for alpha_emit_set_const to check for N or below insns.
+   If NO_OUTPUT is true, then we only check to see if N insns are possible,
+   and return pc_rtx if successful.  */
 
 static rtx
 alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
-                       HOST_WIDE_INT c, int n)
+                       HOST_WIDE_INT c, int n, bool no_output)
 {
   HOST_WIDE_INT new;
   int i, bits;
@@ -1722,6 +1734,8 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
             emit_move_insn to gen_movdi.  So instead, since we know exactly
             what we want, create it explicitly.  */
 
+         if (no_output)
+           return pc_rtx;
          if (target == NULL)
            target = gen_reg_rtx (mode);
          emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (c)));
@@ -1729,6 +1743,8 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
        }
       else if (n >= 2 + (extra != 0))
        {
+         if (no_output)
+           return pc_rtx;
          if (no_new_pseudos)
            {
              emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (high << 16)));
@@ -1781,14 +1797,26 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
         high bits.  */
 
       new = ((c & 0xffff) ^ 0x8000) - 0x8000;
-      if (new != 0
-          && (temp = alpha_emit_set_const (subtarget, mode, c - new, i)) != 0)
-       return expand_binop (mode, add_optab, temp, GEN_INT (new),
-                            target, 0, OPTAB_WIDEN);
+      if (new != 0)
+       {
+          temp = alpha_emit_set_const (subtarget, mode, c - new, i, no_output);
+         if (temp)
+           {
+             if (no_output)
+               return temp;
+             return expand_binop (mode, add_optab, temp, GEN_INT (new),
+                                  target, 0, OPTAB_WIDEN);
+           }
+       }
 
       /* Next try complementing.  */
-      if ((temp = alpha_emit_set_const (subtarget, mode, ~ c, i)) != 0)
-       return expand_unop (mode, one_cmpl_optab, temp, target, 0);
+      temp = alpha_emit_set_const (subtarget, mode, ~c, i, no_output);
+      if (temp)
+       {
+         if (no_output)
+           return temp;
+         return expand_unop (mode, one_cmpl_optab, temp, target, 0);
+       }
 
       /* Next try to form a constant and do a left shift.  We can do this
         if some low-order bits are zero; the exact_log2 call below tells
@@ -1799,16 +1827,26 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
         bits to shift, but try all possibilities in case a ZAPNOT will
         be useful.  */
 
-      if ((bits = exact_log2 (c & - c)) > 0)
+      bits = exact_log2 (c & -c);
+      if (bits > 0)
        for (; bits > 0; bits--)
-         if ((temp = (alpha_emit_set_const
-                      (subtarget, mode, c >> bits, i))) != 0
-             || ((temp = (alpha_emit_set_const
-                         (subtarget, mode,
-                          ((unsigned HOST_WIDE_INT) c) >> bits, i)))
-                 != 0))
-           return expand_binop (mode, ashl_optab, temp, GEN_INT (bits),
-                                target, 0, OPTAB_WIDEN);
+         {
+           new = c >> bits;
+           temp = alpha_emit_set_const (subtarget, mode, new, i, no_output);
+           if (!temp && c < 0)
+             {
+               new = (unsigned HOST_WIDE_INT)c >> bits;
+               temp = alpha_emit_set_const (subtarget, mode, new,
+                                            i, no_output);
+             }
+           if (temp)
+             {
+               if (no_output)
+                 return temp;
+               return expand_binop (mode, ashl_optab, temp, GEN_INT (bits),
+                                    target, 0, OPTAB_WIDEN);
+             }
+         }
 
       /* Now try high-order zero bits.  Here we try the shifted-in bits as
         all zero and all ones.  Be careful to avoid shifting outside the
@@ -1816,35 +1854,53 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
       /* On narrow hosts, don't shift a 1 into the high bit, since we'll
         confuse the recursive call and set all of the high 32 bits.  */
 
-      if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
-                  - floor_log2 (c) - 1 - (HOST_BITS_PER_WIDE_INT < 64))) > 0)
+      bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
+             - floor_log2 (c) - 1 - (HOST_BITS_PER_WIDE_INT < 64));
+      if (bits > 0)
        for (; bits > 0; bits--)
-         if ((temp = alpha_emit_set_const (subtarget, mode,
-                                           c << bits, i)) != 0
-             || ((temp = (alpha_emit_set_const
-                          (subtarget, mode,
-                           ((c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1)),
-                           i)))
-                 != 0))
-           return expand_binop (mode, lshr_optab, temp, GEN_INT (bits),
-                                target, 1, OPTAB_WIDEN);
+         {
+           new = c << bits;
+           temp = alpha_emit_set_const (subtarget, mode, new, i, no_output);
+           if (!temp)
+             {
+               new = (c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1);
+               temp = alpha_emit_set_const (subtarget, mode, new,
+                                            i, no_output);
+             }
+           if (temp)
+             {
+               if (no_output)
+                 return temp;
+               return expand_binop (mode, lshr_optab, temp, GEN_INT (bits),
+                                    target, 1, OPTAB_WIDEN);
+             }
+         }
 
       /* Now try high-order 1 bits.  We get that with a sign-extension.
         But one bit isn't enough here.  Be careful to avoid shifting outside
         the mode and to avoid shifting outside the host wide int size.  */
 
-      if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
-                  - floor_log2 (~ c) - 2)) > 0)
+      bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
+             - floor_log2 (~ c) - 2);
+      if (bits > 0)
        for (; bits > 0; bits--)
-         if ((temp = alpha_emit_set_const (subtarget, mode,
-                                           c << bits, i)) != 0
-             || ((temp = (alpha_emit_set_const
-                          (subtarget, mode,
-                           ((c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1)),
-                           i)))
-                 != 0))
-           return expand_binop (mode, ashr_optab, temp, GEN_INT (bits),
-                                target, 0, OPTAB_WIDEN);
+         {
+           new = c << bits;
+           temp = alpha_emit_set_const (subtarget, mode, new, i, no_output);
+           if (!temp)
+             {
+               new = (c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1);
+               temp = alpha_emit_set_const (subtarget, mode, new,
+                                            i, no_output);
+             }
+           if (temp)
+             {
+               if (no_output)
+                 return temp;
+               return expand_binop (mode, ashr_optab, temp, GEN_INT (bits),
+                                    target, 0, OPTAB_WIDEN);
+             }
+         }
     }
 
 #if HOST_BITS_PER_WIDE_INT == 64
@@ -1863,10 +1919,17 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
   if (mode == SImode)
     new = ((new & 0xffffffff) ^ 0x80000000) - 0x80000000;
 
-  if (new != c && new != -1
-      && (temp = alpha_emit_set_const (subtarget, mode, new, n - 1)) != 0)
-    return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new),
-                        target, 0, OPTAB_WIDEN);
+  if (new != c)
+    {
+      temp = alpha_emit_set_const (subtarget, mode, new, n - 1, no_output);
+      if (temp)
+       {
+         if (no_output)
+           return temp;
+         return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new),
+                              target, 0, OPTAB_WIDEN);
+       }
+    }
 #endif
 
   return 0;
@@ -1878,32 +1941,46 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
    emitted.  If it would take more than N insns, zero is returned and no
    insns and emitted.  */
 
-rtx
+static rtx
 alpha_emit_set_const (rtx target, enum machine_mode mode,
-                     HOST_WIDE_INT c, int n)
+                     HOST_WIDE_INT c, int n, bool no_output)
 {
-  rtx result = 0;
+  enum machine_mode orig_mode = mode;
   rtx orig_target = target;
+  rtx result = 0;
   int i;
 
   /* If we can't make any pseudos, TARGET is an SImode hard register, we
      can't load this constant in one insn, do this in DImode.  */
   if (no_new_pseudos && mode == SImode
-      && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER
-      && (result = alpha_emit_set_const_1 (target, mode, c, 1)) == 0)
+      && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER)
+    {
+      result = alpha_emit_set_const_1 (target, mode, c, 1, no_output);
+      if (result)
+       return result;
+
+      target = no_output ? NULL : gen_lowpart (DImode, target);
+      mode = DImode;
+    }
+  else if (mode == V8QImode || mode == V4HImode || mode == V2SImode)
     {
-      target = gen_lowpart (DImode, target);
+      target = no_output ? NULL : gen_lowpart (DImode, target);
       mode = DImode;
     }
 
   /* Try 1 insn, then 2, then up to N.  */
   for (i = 1; i <= n; i++)
     {
-      result = alpha_emit_set_const_1 (target, mode, c, i);
+      result = alpha_emit_set_const_1 (target, mode, c, i, no_output);
       if (result)
        {
-         rtx insn = get_last_insn ();
-         rtx set = single_set (insn);
+         rtx insn, set;
+
+         if (no_output)
+           return result;
+
+         insn = get_last_insn ();
+         set = single_set (insn);
          if (! CONSTANT_P (SET_SRC (set)))
            set_unique_reg_note (get_last_insn (), REG_EQUAL, GEN_INT (c));
          break;
@@ -1911,8 +1988,13 @@ alpha_emit_set_const (rtx target, enum machine_mode mode,
     }
 
   /* Allow for the case where we changed the mode of TARGET.  */
-  if (result == target)
-    result = orig_target;
+  if (result)
+    {
+      if (result == target)
+       result = orig_target;
+      else if (mode != orig_mode)
+       result = gen_lowpart (orig_mode, result);
+    }
 
   return result;
 }
@@ -1922,7 +2004,7 @@ alpha_emit_set_const (rtx target, enum machine_mode mode,
    exponential run times encountered when looking for longer sequences
    with alpha_emit_set_const.  */
 
-rtx
+static rtx
 alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
 {
   HOST_WIDE_INT d1, d2, d3, d4;
@@ -1976,6 +2058,114 @@ alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
   return target;
 }
 
+/* Given an integral CONST_INT, CONST_DOUBLE, or CONST_VECTOR, return 
+   the low 64 bits.  */
+
+static void
+alpha_extract_integer (rtx x, HOST_WIDE_INT *p0, HOST_WIDE_INT *p1)
+{
+  HOST_WIDE_INT i0, i1;
+
+  if (GET_CODE (x) == CONST_VECTOR)
+    x = simplify_subreg (DImode, x, GET_MODE (x), 0);
+
+
+  if (GET_CODE (x) == CONST_INT)
+    {
+      i0 = INTVAL (x);
+      i1 = -(i0 < 0);
+    }
+  else if (HOST_BITS_PER_WIDE_INT >= 64)
+    {
+      i0 = CONST_DOUBLE_LOW (x);
+      i1 = -(i0 < 0);
+    }
+  else
+    {
+      i0 = CONST_DOUBLE_LOW (x);
+      i1 = CONST_DOUBLE_HIGH (x);
+    }
+
+  *p0 = i0;
+  *p1 = i1;
+}
+
+/* Implement LEGITIMATE_CONSTANT_P.  This is all constants for which we
+   are willing to load the value into a register via a move pattern.
+   Normally this is all symbolic constants, integral constants that
+   take three or fewer instructions, and floating-point zero.  */
+
+bool
+alpha_legitimate_constant_p (rtx x)
+{
+  enum machine_mode mode = GET_MODE (x);
+  HOST_WIDE_INT i0, i1;
+
+  switch (GET_CODE (x))
+    {
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case HIGH:
+      return true;
+
+    case CONST_DOUBLE:
+      if (x == CONST0_RTX (mode))
+       return true;
+      if (FLOAT_MODE_P (mode))
+       return false;
+      goto do_integer;
+
+    case CONST_VECTOR:
+      if (x == CONST0_RTX (mode))
+       return true;
+      if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
+       return false;
+      if (GET_MODE_SIZE (mode) != 8)
+       return false;
+      goto do_integer;
+
+    case CONST_INT:
+    do_integer:
+      if (TARGET_BUILD_CONSTANTS)
+       return true;
+      alpha_extract_integer (x, &i0, &i1);
+      if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == (-i0 < 0))
+        return alpha_emit_set_const_1 (x, mode, i0, 3, true) != NULL;
+      return false;
+
+    default:
+      return false;
+    }
+}
+
+/* Operand 1 is known to be a constant, and should require more than one
+   instruction to load.  Emit that multi-part load.  */
+
+bool
+alpha_split_const_mov (enum machine_mode mode, rtx *operands)
+{
+  HOST_WIDE_INT i0, i1;
+  rtx temp = NULL_RTX;
+
+  alpha_extract_integer (operands[1], &i0, &i1);
+
+  if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == -(i0 < 0))
+    temp = alpha_emit_set_const (operands[0], mode, i0, 3, false);
+
+  if (!temp && TARGET_BUILD_CONSTANTS)
+    temp = alpha_emit_set_long_const (operands[0], i0, i1);
+
+  if (temp)
+    {
+      if (!rtx_equal_p (operands[0], temp))
+       emit_move_insn (operands[0], temp);
+      return true;
+    }
+
+  return false;
+}
+
 /* Expand a move instruction; return true if all work is done.
    We don't handle non-bwx subword loads here.  */
 
@@ -2008,40 +2198,11 @@ alpha_expand_mov (enum machine_mode mode, rtx *operands)
 
   /* Split large integers.  */
   if (GET_CODE (operands[1]) == CONST_INT
-      || GET_CODE (operands[1]) == CONST_DOUBLE)
+      || GET_CODE (operands[1]) == CONST_DOUBLE
+      || GET_CODE (operands[1]) == CONST_VECTOR)
     {
-      HOST_WIDE_INT i0, i1;
-      rtx temp = NULL_RTX;
-
-      if (GET_CODE (operands[1]) == CONST_INT)
-       {
-         i0 = INTVAL (operands[1]);
-         i1 = -(i0 < 0);
-       }
-      else if (HOST_BITS_PER_WIDE_INT >= 64)
-       {
-         i0 = CONST_DOUBLE_LOW (operands[1]);
-         i1 = -(i0 < 0);
-       }
-      else
-       {
-         i0 = CONST_DOUBLE_LOW (operands[1]);
-         i1 = CONST_DOUBLE_HIGH (operands[1]);
-       }
-
-      if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == -(i0 < 0))
-       temp = alpha_emit_set_const (operands[0], mode, i0, 3);
-
-      if (!temp && TARGET_BUILD_CONSTANTS)
-       temp = alpha_emit_set_long_const (operands[0], i0, i1);
-
-      if (temp)
-       {
-         if (rtx_equal_p (operands[0], temp))
-           return true;
-         operands[1] = temp;
-         return false;
-       }
+      if (alpha_split_const_mov (mode, operands))
+       return true;
     }
 
   /* Otherwise we've nothing left but to drop the thing to memory.  */
@@ -7029,7 +7190,8 @@ alpha_expand_epilogue (void)
       else
        {
          rtx tmp = gen_rtx_REG (DImode, 23);
-         FRP (sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size, 3));
+         FRP (sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size,
+                                              3, false));
          if (!sp_adj2)
            {
              /* We can't drop new things to memory this late, afaik,
index e9a409816a17080aeec01a80a54cfc8a8d21c956..21a634c39ec834c0f272e6a663a4c16e53e6306c 100644 (file)
@@ -884,10 +884,10 @@ enum reg_class {
    reduce the impact of not being able to allocate a pseudo to a
    hard register.  */
 
-#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2)       \
-  (((CLASS1) == FLOAT_REGS) == ((CLASS2) == FLOAT_REGS)        \
-   ? 2                                                 \
-   : TARGET_FIX ? 3 : 4+2*alpha_memory_latency)
+#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2)               \
+  (((CLASS1) == FLOAT_REGS) == ((CLASS2) == FLOAT_REGS)        ? 2     \
+   : TARGET_FIX ? ((CLASS1) == FLOAT_REGS ? 6 : 8)             \
+   : 4+2*alpha_memory_latency)
 
 /* A C expressions returning the cost of moving data of MODE from a register to
    or from memory.
@@ -1213,9 +1213,7 @@ do {                                              \
 /* Include all constant integers and constant doubles, but not
    floating-point, except for floating-point zero.  */
 
-#define LEGITIMATE_CONSTANT_P(X)               \
-  (GET_MODE_CLASS (GET_MODE (X)) != MODE_FLOAT \
-   || (X) == CONST0_RTX (GET_MODE (X)))
+#define LEGITIMATE_CONSTANT_P  alpha_legitimate_constant_p
 
 /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
    and check its validity for a certain class.
index 2679324d10a5f63c21598f6f13c2ecec32e1c6b3..0f68d36b93bdaf58bc76f0ef5896886ea4d1e5f5 100644 (file)
 })
 
 (define_insn "*movsi"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m")
-       (match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ"))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m")
+       (match_operand:SI 1 "input_operand" "rJ,K,L,n,m,rJ"))]
   "(TARGET_ABI_OSF || TARGET_ABI_UNICOSMK)
    && (register_operand (operands[0], SImode)
        || reg_or_0_operand (operands[1], SImode))"
    bis $31,%r1,%0
    lda %0,%1($31)
    ldah %0,%h1($31)
+   #
    ldl %0,%1
    stl %r1,%0"
-  [(set_attr "type" "ilog,iadd,iadd,ild,ist")])
+  [(set_attr "type" "ilog,iadd,iadd,multi,ild,ist")])
 
 (define_insn "*movsi_nt_vms"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m")
-       (match_operand:SI 1 "input_operand" "rJ,K,L,s,m,rJ"))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m")
+       (match_operand:SI 1 "input_operand" "rJ,K,L,s,n,m,rJ"))]
   "(TARGET_ABI_WINDOWS_NT || TARGET_ABI_OPEN_VMS)
     && (register_operand (operands[0], SImode)
         || reg_or_0_operand (operands[1], SImode))"
    lda %0,%1
    ldah %0,%h1
    lda %0,%1
+   #
    ldl %0,%1
    stl %r1,%0"
-  [(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist")])
+  [(set_attr "type" "ilog,iadd,iadd,ldsym,multi,ild,ist")])
 
 (define_insn "*movhi_nobwx"
   [(set (match_operand:HI 0 "register_operand" "=r,r")
 
 (define_split
   [(set (match_operand:SI 0 "register_operand" "")
-       (match_operand:SI 1 "const_int_operand" ""))]
-  "! add_operand (operands[1], SImode)"
-  [(set (match_dup 0) (match_dup 2))
-   (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 3)))]
+       (match_operand:SI 1 "non_add_const_operand" ""))]
+  ""
+  [(const_int 0)]
 {
-  rtx tem
-    = alpha_emit_set_const (operands[0], SImode, INTVAL (operands[1]), 2);
-
-  if (tem == operands[0])
+  if (alpha_split_const_mov (SImode, operands))
     DONE;
   else
     FAIL;
 })
 
 (define_insn "*movdi_er_nofix"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q")
-       (match_operand:DI 1 "input_operand" "rJ,K,L,T,s,m,rJ,*fJ,Q,*f"))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,r,m,*f,*f,Q")
+       (match_operand:DI 1 "input_operand" "rJ,K,L,T,s,n,m,rJ,*fJ,Q,*f"))]
   "TARGET_EXPLICIT_RELOCS && ! TARGET_FIX
    && (register_operand (operands[0], DImode)
        || reg_or_0_operand (operands[1], DImode))"
    ldah %0,%h1($31)
    #
    #
+   #
    ldq%A1 %0,%1
    stq%A0 %r1,%0
    fmov %R1,%0
    ldt %0,%1
    stt %R1,%0"
-  [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")
-   (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*")])
+  [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,multi,ild,ist,fcpys,fld,fst")
+   (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*,*")])
 
 ;; The 'U' constraint matches symbolic operands on Unicos/Mk. Those should
 ;; have been split up by the rules above but we shouldn't reject the
 ;; possibility of them getting through.
 
 (define_insn "*movdi_nofix"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q")
-       (match_operand:DI 1 "input_operand" "rJ,K,L,U,s,m,rJ,*fJ,Q,*f"))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,r,m,*f,*f,Q")
+       (match_operand:DI 1 "input_operand" "rJ,K,L,U,s,n,m,rJ,*fJ,Q,*f"))]
   "! TARGET_FIX
    && (register_operand (operands[0], DImode)
        || reg_or_0_operand (operands[1], DImode))"
    ldah %0,%h1($31)
    laum %0,%t1($31)\;sll %0,32,%0\;lalm %0,%t1(%0)\;lal %0,%t1(%0)
    lda %0,%1
+   #
    ldq%A1 %0,%1
    stq%A0 %r1,%0
    cpys %R1,%R1,%0
    ldt %0,%1
    stt %R1,%0"
-  [(set_attr "type" "ilog,iadd,iadd,ldsym,ldsym,ild,ist,fcpys,fld,fst")
-   (set_attr "length" "*,*,*,16,*,*,*,*,*,*")])
+  [(set_attr "type" "ilog,iadd,iadd,ldsym,ldsym,multi,ild,ist,fcpys,fld,fst")
+   (set_attr "length" "*,*,*,16,*,*,*,*,*,*,*")])
 
 (define_insn "*movdi_er_fix"
   [(set (match_operand:DI 0 "nonimmediate_operand"
-                               "=r,r,r,r,r,r, m, *f,*f, Q, r,*f")
+                               "=r,r,r,r,r,r,r, m, *f,*f, Q, r,*f")
        (match_operand:DI 1 "input_operand"
-                               "rJ,K,L,T,s,m,rJ,*fJ, Q,*f,*f, r"))]
+                               "rJ,K,L,T,s,n,m,rJ,*fJ, Q,*f,*f, r"))]
   "TARGET_EXPLICIT_RELOCS && TARGET_FIX
    && (register_operand (operands[0], DImode)
        || reg_or_0_operand (operands[1], DImode))"
    ldah %0,%h1($31)
    #
    #
+   #
    ldq%A1 %0,%1
    stq%A0 %r1,%0
    fmov %R1,%0
    stt %R1,%0
    ftoit %1,%0
    itoft %1,%0"
-  [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst,ftoi,itof")
-   (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*,*,*")])
+  [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,multi,ild,ist,fcpys,fld,fst,ftoi,itof")
+   (set_attr "usegp" "*,*,*,yes,*,*,*,*,*,*,*,*,*")])
 
 (define_insn "*movdi_fix"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,m,*f,*f,Q,r,*f")
-       (match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,*fJ,Q,*f,*f,r"))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q,r,*f")
+       (match_operand:DI 1 "input_operand" "rJ,K,L,s,n,m,rJ,*fJ,Q,*f,*f,r"))]
   "! TARGET_EXPLICIT_RELOCS && TARGET_FIX
    && (register_operand (operands[0], DImode)
        || reg_or_0_operand (operands[1], DImode))"
    lda %0,%1($31)
    ldah %0,%h1($31)
    lda %0,%1
+   #
    ldq%A1 %0,%1
    stq%A0 %r1,%0
    cpys %R1,%R1,%0
    stt %R1,%0
    ftoit %1,%0
    itoft %1,%0"
-  [(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst,ftoi,itof")])
+  [(set_attr "type" "ilog,iadd,iadd,ldsym,multi,ild,ist,fcpys,fld,fst,ftoi,itof")])
 
 ;; VMS needs to set up "vms_base_regno" for unwinding.  This move
 ;; often appears dead to the life analysis code, at which point we
 
 (define_split
   [(set (match_operand:DI 0 "register_operand" "")
-       (match_operand:DI 1 "const_int_operand" ""))]
-  "! add_operand (operands[1], DImode)"
-  [(set (match_dup 0) (match_dup 2))
-   (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))]
+       (match_operand:DI 1 "non_add_const_operand" ""))]
+  ""
+  [(const_int 0)]
 {
-  rtx tem
-    = alpha_emit_set_const (operands[0], DImode, INTVAL (operands[1]), 2);
-
-  if (tem == operands[0])
+  if (alpha_split_const_mov (DImode, operands))
     DONE;
   else
     FAIL;
     DONE;
 })
 
+(define_split
+  [(set (match_operand:VEC 0 "register_operand" "")
+       (match_operand:VEC 1 "non_zero_const_operand" ""))]
+  ""
+  [(const_int 0)]
+{
+  if (alpha_split_const_mov (<MODE>mode, operands))
+    DONE;
+  else
+    FAIL;
+})
+
+
 (define_expand "movmisalign<mode>"
   [(set (match_operand:VEC 0 "nonimmediate_operand" "")
         (match_operand:VEC 1 "general_operand" ""))]
 })
 
 (define_insn "*mov<mode>_fix"
-  [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,m,*f,*f,m,r,*f")
-       (match_operand:VEC 1 "input_operand" "rW,m,rW,*fW,m,*f,*f,r"))]
+  [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,r,m,*f,*f,m,r,*f")
+       (match_operand:VEC 1 "input_operand" "rW,i,m,rW,*fW,m,*f,*f,r"))]
   "TARGET_FIX
    && (register_operand (operands[0], <MODE>mode)
        || reg_or_0_operand (operands[1], <MODE>mode))"
   "@
    bis $31,%r1,%0
+   #
    ldq %0,%1
    stq %r1,%0
    cpys %R1,%R1,%0
    stt %R1,%0
    ftoit %1,%0
    itoft %1,%0"
-  [(set_attr "type" "ilog,ild,ist,fcpys,fld,fst,ftoi,itof")])
+  [(set_attr "type" "ilog,multi,ild,ist,fcpys,fld,fst,ftoi,itof")])
 
 (define_insn "*mov<mode>_nofix"
-  [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,m,*f,*f,m")
-       (match_operand:VEC 1 "input_operand" "rW,m,rW,*fW,m,*f"))]
+  [(set (match_operand:VEC 0 "nonimmediate_operand" "=r,r,r,m,*f,*f,m")
+       (match_operand:VEC 1 "input_operand" "rW,i,m,rW,*fW,m,*f"))]
   "! TARGET_FIX
    && (register_operand (operands[0], <MODE>mode)
        || reg_or_0_operand (operands[1], <MODE>mode))"
   "@
    bis $31,%r1,%0
+   #
    ldq %0,%1
    stq %r1,%0
    cpys %R1,%R1,%0
    ldt %0,%1
    stt %R1,%0"
-  [(set_attr "type" "ilog,ild,ist,fcpys,fld,fst")])
+  [(set_attr "type" "ilog,multi,ild,ist,fcpys,fld,fst")])
 
 (define_insn "uminv8qi3"
   [(set (match_operand:V8QI 0 "register_operand" "=r")
index b060dd17741d7e5f3caabda5859ccb5fcdaa737f..6a58ed679054fd1b131dd5e4a2b7f879e077561b 100644 (file)
                 || CONST_OK_FOR_LETTER_P (INTVAL (op), 'O')")
     (match_operand 0 "register_operand")))
 
+;; Return 1 if the operand is a non-symbolic constant operand that
+;; does not satisfy add_operand.
+(define_predicate "non_add_const_operand"
+  (and (match_code "const_int,const_double,const_vector")
+       (not (match_operand 0 "add_operand"))))
+
+;; Return 1 if the operand is a non-symbolic, non-zero constant operand.
+(define_predicate "non_zero_const_operand"
+  (and (match_code "const_int,const_double,const_vector")
+       (match_test "op != CONST0_RTX (mode)")))
+
 ;; Return 1 if OP is the constant 4 or 8.
 (define_predicate "const48_operand"
   (and (match_code "const_int")
              && general_operand (op, mode));
 
     case CONST_DOUBLE:
+      return op == CONST0_RTX (mode);
+
     case CONST_VECTOR:
+      if (reload_in_progress || reload_completed)
+       return alpha_legitimate_constant_p (op);
       return op == CONST0_RTX (mode);
 
     case CONST_INT:
-      return mode == QImode || mode == HImode || add_operand (op, mode);
+      if (mode == QImode || mode == HImode)
+       return true;
+      if (reload_in_progress || reload_completed)
+       return alpha_legitimate_constant_p (op);
+      return add_operand (op, mode);
 
     default:
       abort ();
diff --git a/gcc/testsuite/gcc.target/alpha/alpha.exp b/gcc/testsuite/gcc.target/alpha/alpha.exp
new file mode 100644 (file)
index 0000000..47ad3e1
--- /dev/null
@@ -0,0 +1,41 @@
+#   Copyright (C) 2005 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Exit immediately if this isn't an Alpha target.
+if ![istarget alpha*-*-*] then {
+  return
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \
+       "" $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.target/alpha/pr19518.c b/gcc/testsuite/gcc.target/alpha/pr19518.c
new file mode 100644 (file)
index 0000000..42c58b5
--- /dev/null
@@ -0,0 +1,60 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcpu=ev67" } */
+
+typedef short INT16;
+typedef unsigned int CARD32;
+typedef unsigned short CARD16;
+typedef unsigned char CARD8;
+typedef struct _Picture *PicturePtr;
+typedef int FbStride;
+typedef unsigned long __m64;
+extern __m64 load8888 (__m64);
+static __inline __m64 _mm_adds_pu8(__m64 __m1, __m64 __m2)
+{
+    return __m1 + __builtin_alpha_minsb8(__m2, ~__m1);
+}
+static __inline __m64 _mm_packs_pu16(__m64 __m1, __m64 __m2)
+{
+    __m1 = __builtin_alpha_minuw4(__m1, 0x00ff00ff00ff00ff);
+    __m2 = __builtin_alpha_minuw4(__m2, 0x00ff00ff00ff00ff);
+    return __m1 | (__m2 << 32);
+}
+typedef unsigned long long ullong;
+static __inline__ __m64 pix_multiply(__m64 a)
+{
+    if (a)
+       return a;
+}
+static __inline__ __m64 over(__m64 src, __m64 srca, __m64 dest)
+{
+    return _mm_adds_pu8(src, pix_multiply(dest));
+}
+
+void fbCompositeSolid_nx8888mmx(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
+                               INT16 yDst, CARD16 width, CARD16 height)
+{
+    CARD32 src;
+    CARD32 *dstLine, *dst;
+    CARD16 w;
+    FbStride dstStride;
+    __m64 vsrc, vsrca;
+    vsrc = load8888(src);
+    while (height--) {
+       dst = dstLine;
+       dstLine += dstStride;
+       while (w && (unsigned long) dst & 7) {
+           *dst = _mm_packs_pu16(_mm_adds_pu8(vsrc, load8888(*dst)),
+                                 _mm_setzero_si64());
+           dst++;
+       }
+       while (w >= 2) {
+           __m64 dest0, dest1;
+           *(__m64 *) dst = _mm_packs_pu16(dest0, dest1);
+           w -= 2;
+       }
+       while (w) {
+           *dst = _mm_packs_pu16(_mm_adds_pu8(vsrc, pix_multiply(0)), 0);
+           w--;
+       }
+    }
+}