OSDN Git Service

* config/spu/spu-protos.h (spu_split_immediate): Renamed from
authortsmigiel <tsmigiel@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 9 Dec 2006 01:22:39 +0000 (01:22 +0000)
committertsmigiel <tsmigiel@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 9 Dec 2006 01:22:39 +0000 (01:22 +0000)
        spu_split_address.
        (cpat_const_p, gen_cpat_const): Add.
        * config/spu/spu.c (immediate_class): New enum.
        (cpat_info, classify_immediate): New.
        (print_operand): Use S, D, T instead of F, G, H.  Use
        classify_immediate.  Handle cpat cases.
        (spu_split_immediate):  Renamed from spu_split_address.  Split all
        immediates that can be split.
        (immediate_load_p): Use classify_immediate.
        (spu_legitimate_constant_p): Accept everything except some cases of
        CONST_VECTOR.
        (spu_expand_move): Use spu_split_immedate.
        (fsmbi_const_p): Use classify_immediate.
        (cpat_const_p): New.
        (gen_cpat_const: New.
        * config/spu/constraints.md (j,k,l): New constraints for cpat
        instructions.
        * config/spu/spu.md (unnamed splitter): Change address splitter to
        handle all immediates.
        (_mov<mode>, _movdi, _movti): Handle i, j, k constraints for cpat
        instructions.
        (cpat, _cpat, splitter): Generate a TImode constant for cpat patterns
        when possible.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@119682 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/spu/constraints.md
gcc/config/spu/spu-protos.h
gcc/config/spu/spu.c
gcc/config/spu/spu.md

index b2ad353..27358a0 100644 (file)
@@ -1,3 +1,30 @@
+2006-12-08  Trevor Smigiel  <trevor_smigiel@playstation.sony.com>
+
+       * config/spu/spu-protos.h (spu_split_immediate): Renamed from
+       spu_split_address.
+       (cpat_const_p, gen_cpat_const): Add.
+       * config/spu/spu.c (immediate_class): New enum.
+       (cpat_info, classify_immediate): New.
+       (print_operand): Use S, D, T instead of F, G, H.  Use
+       classify_immediate.  Handle cpat cases.
+       (spu_split_immediate):  Renamed from spu_split_address.  Split all
+       immediates that can be split.
+       (immediate_load_p): Use classify_immediate.
+       (spu_legitimate_constant_p): Accept everything except some cases of
+       CONST_VECTOR.
+       (spu_expand_move): Use spu_split_immedate.
+       (fsmbi_const_p): Use classify_immediate.
+       (cpat_const_p): New.
+       (gen_cpat_const: New.
+       * config/spu/constraints.md (j,k,l): New constraints for cpat
+       instructions.
+       * config/spu/spu.md (unnamed splitter): Change address splitter to
+       handle all immediates.
+       (_mov<mode>, _movdi, _movti): Handle i, j, k constraints for cpat
+       instructions.
+       (cpat, _cpat, splitter): Generate a TImode constant for cpat patterns
+       when possible.
+
 2006-12-08  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
 
        PR target/30039
index 4fa96ce..45aafd0 100644 (file)
@@ -18,7 +18,7 @@
 
 \f
 ;; GCC standard constraints:  g, i, m, n, o, p, r, s, E-H, I-P, V, X
-;; unused for SPU:  E-H, L, Q, d, e, h, j-l, q, t-z
+;; unused for SPU:  E-H, L, Q, d, e, h, q, t-z
 
 ;; For most immediate constraints we have 3 variations to deal with the
 ;; fact const_int has no mode.  One variation treats const_int as 32 bit,
   "An immediate which can be loaded with fsmbi."
   (and (match_code "const_int,const_double,const_vector")
        (match_test "fsmbi_const_p (op)")))
+
+(define_constraint "j"
+  "An immediate which can be loaded with one of the cbd/chd/cwd/cdd instructions.  const_int is treated as a 32 bit value."
+  (and (match_code "const_int,const_double,const_vector")
+       (match_test "cpat_const_p (op, SImode)")))
+
+(define_constraint "k"
+  "An immediate which can be loaded with one of the cbd/chd/cwd/cdd instructions.  const_int is treated as a 64 bit value."
+  (and (match_code "const_int,const_double,const_vector")
+       (match_test "cpat_const_p (op, DImode)")))
+
+(define_constraint "l"
+  "An immediate which can be loaded with one of the cbd/chd/cwd/cdd instructions."
+  (and (match_code "const_double,const_vector")
+       (match_test "cpat_const_p (op, TImode)")))
+
 \f
 ;; Integer constraints
 
index 3239745..710c833 100644 (file)
@@ -34,7 +34,7 @@ extern HOST_WIDE_INT const_double_to_hwint (rtx x);
 extern rtx hwint_to_const_double (enum machine_mode mode, HOST_WIDE_INT v);
 extern void print_operand_address (FILE * file, register rtx addr);
 extern void print_operand (FILE * file, rtx x, int code);
-extern void spu_split_address (rtx * ops);
+extern int spu_split_immediate (rtx * ops);
 extern int spu_saved_regs_size (void);
 extern int direct_return (void);
 extern void spu_expand_prologue (void);
@@ -69,6 +69,8 @@ extern void spu_split_load (rtx * ops);
 extern void spu_split_store (rtx * ops);
 extern int spu_valid_move (rtx * ops);
 extern int fsmbi_const_p (rtx x);
+extern int cpat_const_p (rtx x, enum machine_mode mode);
+extern rtx gen_cpat_const (rtx * ops);
 extern void constant_to_array (enum machine_mode mode, rtx x,
                               unsigned char *arr);
 extern rtx array_to_constant (enum machine_mode mode, unsigned char *arr);
index 03843fd..70f09c5 100644 (file)
@@ -143,9 +143,22 @@ enum spu_immediate {
   SPU_ORBI,
   SPU_IOHL
 };
+enum immediate_class
+{
+  IC_POOL,                     /* constant pool */
+  IC_IL1,                      /* one il* instruction */
+  IC_IL2,                      /* both ilhu and iohl instructions */
+  IC_IL1s,                     /* one il* instruction */
+  IC_IL2s,                     /* both ilhu and iohl instructions */
+  IC_FSMBI,                    /* the fsmbi instruction */
+  IC_CPAT,                     /* one of the c*d instructions */
+};
 
 static enum spu_immediate which_immediate_load (HOST_WIDE_INT val);
 static enum spu_immediate which_logical_immediate (HOST_WIDE_INT val);
+static int cpat_info(unsigned char *arr, int size, int *prun, int *pstart);
+static enum immediate_class classify_immediate (rtx op,
+                                               enum machine_mode mode);
 
 /* Built in types.  */
 tree spu_builtin_types[SPU_BTI_MAX];
@@ -972,24 +985,22 @@ print_operand (FILE * file, rtx x, int code)
   HOST_WIDE_INT val;
   unsigned char arr[16];
   int xcode = GET_CODE (x);
+  int i, info;
   if (GET_MODE (x) == VOIDmode)
     switch (code)
       {
-      case 'H':                        /* 128 bits, signed */
       case 'L':                        /* 128 bits, signed */
       case 'm':                        /* 128 bits, signed */
       case 'T':                        /* 128 bits, signed */
       case 't':                        /* 128 bits, signed */
        mode = TImode;
        break;
-      case 'G':                        /* 64 bits, signed */
       case 'K':                        /* 64 bits, signed */
       case 'k':                        /* 64 bits, signed */
       case 'D':                        /* 64 bits, signed */
       case 'd':                        /* 64 bits, signed */
        mode = DImode;
        break;
-      case 'F':                        /* 32 bits, signed */
       case 'J':                        /* 32 bits, signed */
       case 'j':                        /* 32 bits, signed */
       case 's':                        /* 32 bits, signed */
@@ -1062,34 +1073,62 @@ print_operand (FILE * file, rtx x, int code)
     case 't':                  /* 128 bits, signed */
     case 'd':                  /* 64 bits, signed */
     case 's':                  /* 32 bits, signed */
-      if (xcode == CONST_INT
-         || xcode == CONST_DOUBLE || xcode == CONST_VECTOR)
+      if (CONSTANT_P (x))
        {
-         gcc_assert (immediate_load_p (x, mode));
-         constant_to_array (mode, x, arr);
-         val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
-         val = trunc_int_for_mode (val, SImode);
-         switch (which_immediate_load (val))
-         {
-         case SPU_IL:
-           break;
-         case SPU_ILA:
-           fprintf (file, "a");
-           break;
-         case SPU_ILH:
-           fprintf (file, "h");
-           break;
-         case SPU_ILHU:
-           fprintf (file, "hu");
-           break;
-         default:
-           gcc_unreachable();
-         }
+         enum immediate_class c = classify_immediate (x, mode);
+         switch (c)
+           {
+           case IC_IL1:
+             constant_to_array (mode, x, arr);
+             val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
+             val = trunc_int_for_mode (val, SImode);
+             switch (which_immediate_load (val))
+               {
+               case SPU_IL:
+                 break;
+               case SPU_ILA:
+                 fprintf (file, "a");
+                 break;
+               case SPU_ILH:
+                 fprintf (file, "h");
+                 break;
+               case SPU_ILHU:
+                 fprintf (file, "hu");
+                 break;
+               default:
+                 gcc_unreachable ();
+               }
+             break;
+           case IC_CPAT:
+             constant_to_array (mode, x, arr);
+             cpat_info (arr, GET_MODE_SIZE (mode), &info, 0);
+             if (info == 1)
+               fprintf (file, "b");
+             else if (info == 2)
+               fprintf (file, "h");
+             else if (info == 4)
+               fprintf (file, "w");
+             else if (info == 8)
+               fprintf (file, "d");
+             break;
+           case IC_IL1s:
+             if (xcode == CONST_VECTOR)
+               {
+                 x = CONST_VECTOR_ELT (x, 0);
+                 xcode = GET_CODE (x);
+               }
+             if (xcode == SYMBOL_REF || xcode == LABEL_REF || xcode == CONST)
+               fprintf (file, "a");
+             else if (xcode == HIGH)
+               fprintf (file, "hu");
+             break;
+           case IC_FSMBI:
+           case IC_IL2:
+           case IC_IL2s:
+           case IC_POOL:
+             abort ();
+           }
        }
-      else if (xcode == SYMBOL_REF || xcode == LABEL_REF || xcode == CONST)
-       fprintf (file, "a");
-      else if (xcode == HIGH)
-       fprintf (file, "hu");
       else
        gcc_unreachable ();
       return;
@@ -1097,59 +1136,68 @@ print_operand (FILE * file, rtx x, int code)
     case 'T':                  /* 128 bits, signed */
     case 'D':                  /* 64 bits, signed */
     case 'S':                  /* 32 bits, signed */
-      if (xcode == CONST_INT
-         || xcode == CONST_DOUBLE || xcode == CONST_VECTOR)
+      if (CONSTANT_P (x))
        {
-         gcc_assert (immediate_load_p (x, mode));
-         constant_to_array (mode, x, arr);
-         val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
-         val = trunc_int_for_mode (val, SImode);
-         switch (which_immediate_load (val))
+         enum immediate_class c = classify_immediate (x, mode);
+         switch (c)
            {
-           case SPU_IL:
-           case SPU_ILA:
+           case IC_IL1:
+             constant_to_array (mode, x, arr);
+             val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
+             val = trunc_int_for_mode (val, SImode);
+             switch (which_immediate_load (val))
+               {
+               case SPU_IL:
+               case SPU_ILA:
+                 break;
+               case SPU_ILH:
+               case SPU_ILHU:
+                 val = trunc_int_for_mode (((arr[0] << 8) | arr[1]), HImode);
+                 break;
+               default:
+                 gcc_unreachable ();
+               }
+             fprintf (file, HOST_WIDE_INT_PRINT_DEC, val);
              break;
-           case SPU_ILH:
-           case SPU_ILHU:
-             val = trunc_int_for_mode (((arr[0] << 8) | arr[1]), HImode);
+           case IC_FSMBI:
+             constant_to_array (mode, x, arr);
+             val = 0;
+             for (i = 0; i < 16; i++)
+               {
+                 val <<= 1;
+                 val |= arr[i] & 1;
+               }
+             print_operand (file, GEN_INT (val), 0);
+             break;
+           case IC_CPAT:
+             constant_to_array (mode, x, arr);
+             cpat_info (arr, GET_MODE_SIZE (mode), 0, &info);
+             fprintf (file, HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)info);
+             break;
+           case IC_IL1s:
+             if (xcode == CONST_VECTOR)
+               {
+                 x = CONST_VECTOR_ELT (x, 0);
+                 xcode = GET_CODE (x);
+               }
+             if (xcode == HIGH)
+               {
+                 output_addr_const (file, XEXP (x, 0));
+                 fprintf (file, "@h");
+               }
+             else
+               output_addr_const (file, x);
              break;
-           default:
-             gcc_unreachable();
+           case IC_IL2:
+           case IC_IL2s:
+           case IC_POOL:
+             abort ();
            }
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC, val);
-       }
-      else if (xcode == CONST || xcode == SYMBOL_REF || xcode == LABEL_REF)
-       output_addr_const (file, x);
-      else if (xcode == HIGH)
-       {
-         output_addr_const (file, XEXP (x, 0));
-         fprintf (file, "@h");
        }
       else
        gcc_unreachable ();
       return;
 
-    case 'F':
-    case 'G':
-    case 'H':
-      if (xcode == CONST_INT
-         || xcode == CONST_DOUBLE || xcode == CONST_VECTOR)
-       {                       /* immediate operand for fsmbi */
-         int i;
-         HOST_WIDE_INT val = 0;
-         unsigned char arr[16];
-         constant_to_array (mode, x, arr);
-         for (i = 0; i < 16; i++)
-           {
-             val <<= 1;
-             val |= arr[i] & 1;
-           }
-         print_operand (file, GEN_INT (val), 0);
-       }
-      else
-       gcc_unreachable();
-      return;
-
     case 'C':
       if (xcode == CONST_INT)
        {
@@ -1246,7 +1294,7 @@ print_operand (FILE * file, rtx x, int code)
       else if (xcode == MEM)
        output_address (XEXP (x, 0));
       else if (xcode == CONST_VECTOR)
-       output_addr_const (file, CONST_VECTOR_ELT (x, 0));
+       print_operand (file, CONST_VECTOR_ELT (x, 0), 0);
       else
        output_addr_const (file, x);
       return;
@@ -1276,23 +1324,76 @@ get_pic_reg (void)
 
 /* Split constant addresses to handle cases that are too large.  Also, add in
    the pic register when in PIC mode. */
-void
-spu_split_address (rtx * ops)
+int
+spu_split_immediate (rtx * ops)
 {
-  if (TARGET_LARGE_MEM
-      || (GET_CODE (ops[1]) == CONST && !legitimate_const (ops[1], 0)))
-    {
-      emit_insn (gen_high (ops[0], ops[1]));
-      emit_insn (gen_low (ops[0], ops[0], ops[1]));
-    }
-  else if (flag_pic)
-    emit_insn (gen_pic (ops[0], ops[1]));
-  if (flag_pic)
+  enum machine_mode mode = GET_MODE (ops[0]);
+  enum immediate_class c = classify_immediate (ops[1], mode);
+
+  switch (c)
     {
-      rtx pic_reg = get_pic_reg ();
-      emit_insn (gen_addsi3 (ops[0], ops[0], pic_reg));
-      current_function_uses_pic_offset_table = 1;
+    case IC_IL2:
+      {
+       unsigned char arrhi[16];
+       unsigned char arrlo[16];
+       rtx to, hi, lo;
+       int i;
+       constant_to_array (mode, ops[1], arrhi);
+       to = no_new_pseudos ? ops[0] : gen_reg_rtx (mode);
+       for (i = 0; i < 16; i += 4)
+         {
+           arrlo[i + 2] = arrhi[i + 2];
+           arrlo[i + 3] = arrhi[i + 3];
+           arrlo[i + 0] = arrlo[i + 1] = 0;
+           arrhi[i + 2] = arrhi[i + 3] = 0;
+         }
+       hi = array_to_constant (mode, arrhi);
+       lo = array_to_constant (mode, arrlo);
+       emit_move_insn (to, hi);
+       emit_insn (gen_rtx_SET
+                  (VOIDmode, ops[0], gen_rtx_IOR (mode, to, lo)));
+       return 1;
+      }
+    case IC_POOL:
+      if (reload_in_progress || reload_completed)
+       {
+         rtx mem = force_const_mem (mode, ops[1]);
+         if (TARGET_LARGE_MEM)
+           {
+             rtx addr = gen_rtx_REG (Pmode, REGNO (ops[0]));
+             emit_move_insn (addr, XEXP (mem, 0));
+             mem = replace_equiv_address (mem, addr);
+           }
+         emit_move_insn (ops[0], mem);
+         return 1;
+       }
+      break;
+    case IC_IL1s:
+    case IC_IL2s:
+      if (reload_completed && GET_CODE (ops[1]) != HIGH)
+       {
+         if (c == IC_IL2s)
+           {
+             emit_insn (gen_high (ops[0], ops[1]));
+             emit_insn (gen_low (ops[0], ops[0], ops[1]));
+           }
+         else if (flag_pic)
+           emit_insn (gen_pic (ops[0], ops[1]));
+         if (flag_pic)
+           {
+             rtx pic_reg = get_pic_reg ();
+             emit_insn (gen_addsi3 (ops[0], ops[0], pic_reg));
+             current_function_uses_pic_offset_table = 1;
+           }
+         return flag_pic || c == IC_IL2s;
+       }
+      break;
+    case IC_IL1:
+    case IC_FSMBI:
+    case IC_CPAT:
+      break;
     }
+  return 0;
 }
 
 /* SAVING is TRUE when we are generating the actual load and store
@@ -2202,38 +2303,154 @@ which_immediate_load (HOST_WIDE_INT val)
   return SPU_NONE;
 }
 
+/* Return true when OP can be loaded by one of the il instructions, or
+   when flow2 is not completed and OP can be loaded using ilhu and iohl. */
 int
 immediate_load_p (rtx op, enum machine_mode mode)
 {
+  if (CONSTANT_P (op))
+    {
+      enum immediate_class c = classify_immediate (op, mode);
+      return c == IC_IL1 || (!flow2_completed && c == IC_IL2);
+    }
+  return 0;
+}
+
+/* Return true if the first SIZE bytes of arr is a constant that can be
+   generated with cbd, chd, cwd or cdd.  When non-NULL, PRUN and PSTART
+   represent the size and offset of the instruction to use. */
+static int
+cpat_info(unsigned char *arr, int size, int *prun, int *pstart)
+{
+  int cpat, run, i, start;
+  cpat = 1;
+  run = 0;
+  start = -1;
+  for (i = 0; i < size && cpat; i++)
+    if (arr[i] != i+16)
+      { 
+       if (!run)
+         {
+           start = i;
+           if (arr[i] == 3)
+             run = 1;
+           else if (arr[i] == 2 && arr[i+1] == 3)
+             run = 2;
+           else if (arr[i] == 0)
+             {
+               while (arr[i+run] == run && i+run < 16)
+                 run++;
+               if (run != 4 && run != 8)
+                 cpat = 0;
+             }
+           else
+             cpat = 0;
+           if ((i & (run-1)) != 0)
+             cpat = 0;
+           i += run;
+         }
+       else
+         cpat = 0;
+      }
+  if (cpat)
+    {
+      if (run == 0)
+       run = 1;
+      if (prun)
+       *prun = run;
+      if (pstart)
+       *pstart = start == -1 ? 16-run : start;
+      return 1;
+    }
+  return 0;
+}
+
+/* OP is a CONSTANT_P.  Determine what instructions can be used to load
+   it into a regiser.  MODE is only valid when OP is a CONST_INT. */
+static enum immediate_class
+classify_immediate (rtx op, enum machine_mode mode)
+{
   HOST_WIDE_INT val;
   unsigned char arr[16];
-  int i, j;
+  int i, j, repeated, fsmbi;
+
+  gcc_assert (CONSTANT_P (op));
+
   if (GET_MODE (op) != VOIDmode)
     mode = GET_MODE (op);
 
-  gcc_assert (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE
-             || GET_CODE (op) == CONST_VECTOR);
-
-  /* V4SI with all identical symbols is valid. */
+  /* A V4SI const_vector with all identical symbols is ok. */
   if (mode == V4SImode
-      && GET_CODE (CONST_VECTOR_ELT (op, 0)) == SYMBOL_REF)
-    return !TARGET_LARGE_MEM && !flag_pic
-          && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)
-          && CONST_VECTOR_ELT (op, 1) == CONST_VECTOR_ELT (op, 2)
-          && CONST_VECTOR_ELT (op, 2) == CONST_VECTOR_ELT (op, 3);
+      && GET_CODE (op) == CONST_VECTOR
+      && GET_CODE (CONST_VECTOR_ELT (op, 0)) != CONST_INT
+      && GET_CODE (CONST_VECTOR_ELT (op, 0)) != CONST_DOUBLE
+      && CONST_VECTOR_ELT (op, 0) == CONST_VECTOR_ELT (op, 1)
+      && CONST_VECTOR_ELT (op, 1) == CONST_VECTOR_ELT (op, 2)
+      && CONST_VECTOR_ELT (op, 2) == CONST_VECTOR_ELT (op, 3))
+    op = CONST_VECTOR_ELT (op, 0);
+
+  switch (GET_CODE (op))
+    {
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return TARGET_LARGE_MEM ? IC_IL2s : IC_IL1s;
 
-  constant_to_array (mode, op, arr);
+    case CONST:
+      return TARGET_LARGE_MEM
+       || !legitimate_const (op, 0) ? IC_IL2s : IC_IL1s;
 
-  /* Check that bytes are repeated. */
-  for (i = 4; i < 16; i += 4)
-    for (j = 0; j < 4; j++)
-      if (arr[j] != arr[i + j])
-       return 0;
+    case HIGH:
+      return IC_IL1s;
 
-  val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
-  val = trunc_int_for_mode (val, SImode);
+    case CONST_VECTOR:
+      for (i = 0; i < GET_MODE_NUNITS (mode); i++)
+       if (GET_CODE (CONST_VECTOR_ELT (op, i)) != CONST_INT
+           && GET_CODE (CONST_VECTOR_ELT (op, i)) != CONST_DOUBLE)
+         return IC_POOL;
+      /* Fall through. */
+
+    case CONST_INT:
+    case CONST_DOUBLE:
+      constant_to_array (mode, op, arr);
+
+      /* Check that each 4-byte slot is identical. */
+      repeated = 1;
+      for (i = 4; i < 16; i += 4)
+       for (j = 0; j < 4; j++)
+         if (arr[j] != arr[i + j])
+           repeated = 0;
 
-  return which_immediate_load (val) != SPU_NONE;
+      if (repeated)
+       {
+         val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
+         val = trunc_int_for_mode (val, SImode);
+
+         if (which_immediate_load (val) != SPU_NONE)
+           return IC_IL1;
+       }
+
+      /* Any mode of 2 bytes or smaller can be loaded with an il
+         instruction. */
+      gcc_assert (GET_MODE_SIZE (mode) > 2);
+
+      fsmbi = 1;
+      for (i = 0; i < 16 && fsmbi; i++)
+       if (arr[i] != 0 && arr[i] != 0xff)
+         fsmbi = 0;
+      if (fsmbi)
+       return IC_FSMBI;
+
+      if (cpat_info (arr, GET_MODE_SIZE (mode), 0, 0))
+       return IC_CPAT;
+
+      if (repeated)
+       return IC_IL2;
+
+      return IC_POOL;
+    default:
+      break;
+    }
+  gcc_unreachable ();
 }
 
 static enum spu_immediate
@@ -2361,31 +2578,7 @@ arith_immediate_p (rtx op, enum machine_mode mode,
 int
 spu_legitimate_constant_p (rtx x)
 {
-  unsigned char arr[16];
-  int i, j;
-
-  if (GET_CODE (x) == HIGH
-      || GET_CODE (x) == CONST
-      || GET_CODE (x) == SYMBOL_REF
-      || GET_CODE (x) == LABEL_REF)
-    return 1;
-
-  if (fsmbi_const_p (x))
-    return 1;
-
-  if (GET_CODE (x) == CONST_INT)
-    return (INTVAL (x) >= -0x80000000ll && INTVAL (x) <= 0x7fffffffll)
-      || ((INTVAL (x) >> 32) & 0xffffffffll) == (INTVAL (x) & 0xffffffffll);
-
-  if (GET_MODE (x) == SFmode)
-    return 1;
-
-  if (GET_MODE (x) == DFmode)
-    {
-      HOST_WIDE_INT val = const_double_to_hwint (x);
-      return ((val >> 32) & 0xffffffffll) == (val & 0xffffffffll);
-    }
-
+  int i;
   /* V4SI with all identical symbols is valid. */
   if (GET_MODE (x) == V4SImode
       && (GET_CODE (CONST_VECTOR_ELT (x, 0)) == SYMBOL_REF
@@ -2401,15 +2594,6 @@ spu_legitimate_constant_p (rtx x)
       if (GET_CODE (CONST_VECTOR_ELT (x, i)) != CONST_INT
          && GET_CODE (CONST_VECTOR_ELT (x, i)) != CONST_DOUBLE)
        return 0;
-
-  constant_to_array (SImode, x, arr);
-
-  /* Check that bytes are repeated. */
-  for (i = 4; i < 16; i += 4)
-    for (j = 0; j < 4; j++)
-      if (arr[j] != arr[i + j])
-       return 0;
-
   return 1;
 }
 
@@ -3069,56 +3253,8 @@ spu_expand_mov (rtx * ops, enum machine_mode mode)
     }
   if (reload_in_progress || reload_completed)
     {
-      enum machine_mode mode = GET_MODE (ops[0]);
-      if (GET_CODE (ops[1]) == CONST_INT
-         && (mode == DImode || mode == TImode)
-         && ((INTVAL (ops[1]) >> 32) & 0xffffffffll) !=
-         (INTVAL (ops[1]) & 0xffffffffll))
-       {
-         rtx mem = force_const_mem (mode, ops[1]);
-         if (TARGET_LARGE_MEM)
-           {
-             rtx addr = gen_rtx_REG (Pmode, REGNO (ops[0]));
-             emit_move_insn (addr, XEXP (mem, 0));
-             mem = replace_equiv_address (mem, addr);
-           }
-         emit_move_insn (ops[0], mem);
-         return 1;
-       }
-      else if ((GET_CODE (ops[1]) == CONST_INT
-               || GET_CODE (ops[1]) == CONST_DOUBLE
-               || GET_CODE (ops[1]) == CONST_VECTOR)
-              && !immediate_load_p (ops[1], mode)
-              && !fsmbi_const_p (ops[1]))
-       {
-         unsigned char arrlo[16];
-         unsigned char arrhi[16];
-         rtx to = ops[0], hi, lo;
-         int i;
-         constant_to_array (mode, ops[1], arrhi);
-         for (i = 0; i < 16; i += 4)
-           {
-             arrlo[i + 2] = arrhi[i + 2];
-             arrlo[i + 3] = arrhi[i + 3];
-             arrlo[i + 0] = arrlo[i + 1] = 0;
-             arrhi[i + 2] = arrhi[i + 3] = 0;
-           }
-         if (mode == SFmode)
-           {
-             to = spu_gen_subreg (SImode, ops[0]);
-             mode = SImode;
-           }
-         else if (mode == V4SFmode)
-           {
-             to = spu_gen_subreg (V4SImode, ops[0]);
-             mode = V4SImode;
-           }
-         hi = array_to_constant (mode, arrhi);
-         lo = array_to_constant (mode, arrlo);
-         emit_move_insn (to, hi);
-         emit_insn (gen_rtx_SET (VOIDmode, to, gen_rtx_IOR (mode, to, lo)));
-         return 1;
-       }
+      if (CONSTANT_P (ops[1]))
+       return spu_split_immediate (ops);
       return 0;
     }
   else
@@ -3474,19 +3610,59 @@ spu_valid_move (rtx * ops)
 int
 fsmbi_const_p (rtx x)
 {
-  enum machine_mode mode;
-  unsigned char arr[16];
-  int i;
+  if (CONSTANT_P (x))
+    {
+      /* We can always choose DImode for CONST_INT because the high bits
+         of an SImode will always be all 1s, i.e., valid for fsmbi. */
+      enum immediate_class c = classify_immediate (x, DImode);
+      return c == IC_FSMBI;
+    }
+  return 0;
+}
+
+/* Return TRUE if x is a CONST_INT, CONST_DOUBLE or CONST_VECTOR that
+   can be generated using the cbd, chd, cwd or cdd instruction. */
+int
+cpat_const_p (rtx x, enum machine_mode mode)
+{
+  if (CONSTANT_P (x))
+    {
+      enum immediate_class c = classify_immediate (x, mode);
+      return c == IC_CPAT;
+    }
+  return 0;
+}
 
-  /* We can always choose DImode for CONST_INT because the high bits of
-     an SImode will always be all 1s, i.e., valid for fsmbi. */
-  mode = GET_CODE (x) == CONST_INT ? DImode : GET_MODE (x);
-  constant_to_array (mode, x, arr);
+rtx
+gen_cpat_const (rtx * ops)
+{
+  unsigned char dst[16];
+  int i, offset, shift, isize;
+  if (GET_CODE (ops[3]) != CONST_INT
+      || GET_CODE (ops[2]) != CONST_INT
+      || (GET_CODE (ops[1]) != CONST_INT
+         && GET_CODE (ops[1]) != REG))
+    return 0;
+  if (GET_CODE (ops[1]) == REG
+      && (!REG_POINTER (ops[1])
+         || REGNO_POINTER_ALIGN (ORIGINAL_REGNO (ops[1])) < 128))
+    return 0;
 
   for (i = 0; i < 16; i++)
-    if (arr[i] != 0 && arr[i] != 0xff)
-      return 0;
-  return 1;
+    dst[i] = i + 16;
+  isize = INTVAL (ops[3]);
+  if (isize == 1)
+    shift = 3;
+  else if (isize == 2)
+    shift = 2;
+  else
+    shift = 0;
+  offset = (INTVAL (ops[2]) +
+           (GET_CODE (ops[1]) ==
+            CONST_INT ? INTVAL (ops[1]) : 0)) & 15;
+  for (i = 0; i < isize; i++)
+    dst[offset + i] = i + shift;
+  return array_to_constant (TImode, dst);
 }
 
 /* Convert a CONST_INT, CONST_DOUBLE, or CONST_VECTOR into a 16 byte
index 4f04880..9cb0dc7 100644 (file)
   })
 
 (define_split 
-  [(set (match_operand:SI 0 "spu_reg_operand" "=r")
-       (match_operand:SI 1 "immediate_operand" "s"))]
-
-  "(flag_pic || TARGET_LARGE_MEM
-    || (GET_CODE (operands[1]) == CONST
-        && !legitimate_const (operands[1], 0)))
-   && (reload_in_progress || reload_completed)
-   && (GET_CODE (operands[1]) == CONST
-       || GET_CODE (operands[1]) == SYMBOL_REF
-       || GET_CODE (operands[1]) == LABEL_REF)"
-  [(parallel
-    [(set (match_dup:SI 0)
-         (match_dup:SI 1))
-     (use (const_int 0))])
-   (set (match_dup:SI 0)
-       (plus:SI (match_dup:SI 0)
-                (match_dup:SI 2)))]
+  [(set (match_operand 0 "spu_reg_operand")
+       (match_operand 1 "immediate_operand"))]
+
+  ""
+  [(set (match_dup 0)
+       (high (match_dup 1)))
+   (set (match_dup 0)
+       (lo_sum (match_dup 0)
+               (match_dup 1)))]
   {
-    spu_split_address(operands);
-    DONE;
+    if (spu_split_immediate (operands))
+      DONE;
+    FAIL;
   })
 
 (define_insn "pic"
 ;; move internal
 
 (define_insn "_mov<mode>"
-  [(set (match_operand:MOV 0 "spu_nonimm_operand" "=r,r,r,r,m")
-       (match_operand:MOV 1 "spu_mov_operand" "r,A,f,m,r"))]
+  [(set (match_operand:MOV 0 "spu_nonimm_operand" "=r,r,r,r,r,m")
+       (match_operand:MOV 1 "spu_mov_operand" "r,A,f,j,m,r"))]
   "spu_valid_move (operands)"
   "@
    ori\t%0,%1,0
    il%s1\t%0,%S1
-   fsmbi\t%0,%F1
+   fsmbi\t%0,%S1
+   c%s1d\t%0,%S1($sp)
    lq%p1\t%0,%1
    stq%p0\t%1,%0"
-  [(set_attr "type" "fx2,fx2,shuf,load,store")])
+  [(set_attr "type" "fx2,fx2,shuf,shuf,load,store")])
 
 (define_insn "high"
   [(set (match_operand:SI 0 "spu_reg_operand" "=r")
   "iohl\t%0,%2@l")
 
 (define_insn "_movdi"
-  [(set (match_operand:DI 0 "spu_nonimm_operand" "=r,r,r,r,m")
-       (match_operand:DI 1 "spu_mov_operand" "r,a,f,m,r"))]
+  [(set (match_operand:DI 0 "spu_nonimm_operand" "=r,r,r,r,r,m")
+       (match_operand:DI 1 "spu_mov_operand" "r,a,f,k,m,r"))]
   "spu_valid_move (operands)"
   "@
    ori\t%0,%1,0
    il%d1\t%0,%D1
-   fsmbi\t%0,%G1
+   fsmbi\t%0,%D1
+   c%d1d\t%0,%D1($sp)
    lq%p1\t%0,%1
    stq%p0\t%1,%0"
-  [(set_attr "type" "fx2,fx2,shuf,load,store")])
+  [(set_attr "type" "fx2,fx2,shuf,shuf,load,store")])
 
 (define_insn "_movti"
-  [(set (match_operand:TI 0 "spu_nonimm_operand" "=r,r,r,r,m")
-       (match_operand:TI 1 "spu_mov_operand" "r,U,f,m,r"))]
+  [(set (match_operand:TI 0 "spu_nonimm_operand" "=r,r,r,r,r,m")
+       (match_operand:TI 1 "spu_mov_operand" "r,U,f,l,m,r"))]
   "spu_valid_move (operands)"
   "@
    ori\t%0,%1,0
    il%t1\t%0,%T1
-   fsmbi\t%0,%H1
+   fsmbi\t%0,%T1
+   c%t1d\t%0,%T1($sp)
    lq%p1\t%0,%1
    stq%p0\t%1,%0"
-  [(set_attr "type" "fx2,fx2,shuf,load,store")])
+  [(set_attr "type" "fx2,fx2,shuf,shuf,load,store")])
 
 (define_insn_and_split "load"
   [(set (match_operand 0 "spu_reg_operand" "=r")
   { spu_split_store(operands); DONE; })
 
 ;; Operand 3 is the number of bytes. 1:b 2:h 4:w 8:d
-(define_insn "cpat"
+
+(define_expand "cpat"
   [(set (match_operand:TI 0 "spu_reg_operand" "=r,r")
-        (unspec:TI [(match_operand:SI 1 "spu_reg_operand" "r,r")
-                    (match_operand:SI 2 "spu_nonmem_operand" "r,n")
+       (unspec:TI [(match_operand:SI 1 "spu_reg_operand" "r,r")
+                   (match_operand:SI 2 "spu_nonmem_operand" "r,n")
+                   (match_operand:SI 3 "immediate_operand" "i,i")] UNSPEC_CPAT))]
+  ""
+  {
+    rtx x = gen_cpat_const (operands);
+    if (x)
+      {
+        emit_move_insn (operands[0], x);
+        DONE;
+      }
+  })
+
+(define_insn "_cpat"
+  [(set (match_operand:TI 0 "spu_reg_operand" "=r,r")
+       (unspec:TI [(match_operand:SI 1 "spu_reg_operand" "r,r")
+                   (match_operand:SI 2 "spu_nonmem_operand" "r,n")
                    (match_operand:SI 3 "immediate_operand" "i,i")] UNSPEC_CPAT))]
   ""
   "@
    c%M3d\t%0,%C2(%1)"
   [(set_attr "type" "shuf")])
 
+(define_split
+  [(set (match_operand:TI 0 "spu_reg_operand")
+       (unspec:TI [(match_operand:SI 1 "spu_nonmem_operand")
+                   (match_operand:SI 2 "immediate_operand")
+                   (match_operand:SI 3 "immediate_operand")] UNSPEC_CPAT))]
+  ""
+  [(set (match_dup:TI 0)
+        (match_dup:TI 4))]
+  {
+    operands[4] = gen_cpat_const (operands);
+    if (!operands[4])
+      FAIL;
+  })
 \f
 ;; extend