[Commited, SPU] Generate constants with cbd, chd, cwd and cdd.

trevor_smigiel@playstation.sony.com trevor_smigiel@playstation.sony.com
Sat Dec 9 01:23:00 GMT 2006


The "Generate Controls" instructions, called cpat instructions in the
code, load constants representing shuffle patterns.  This patch enables
the mov patters to identify these constants and generate the correct
instruction.  It also changes the UNSPEC_CPAT to a CONST_DOUBLE when it
can.

Trevor

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.

-------------- next part --------------
Index: gcc/config/spu/spu-protos.h
===================================================================
--- gcc/config/spu/spu-protos.h	(revision 119681)
+++ gcc/config/spu/spu-protos.h	(working copy)
@@ -34,7 +34,7 @@ extern HOST_WIDE_INT const_double_to_hwi
 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: gcc/config/spu/spu.c
===================================================================
--- gcc/config/spu/spu.c	(revision 119681)
+++ gcc/config/spu/spu.c	(working copy)
@@ -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 c
   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 c
     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 c
     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 c
       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);
 
-  constant_to_array (mode, op, arr);
+  switch (GET_CODE (op))
+    {
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return TARGET_LARGE_MEM ? 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 CONST:
+      return TARGET_LARGE_MEM
+	|| !legitimate_const (op, 0) ? IC_IL2s : IC_IL1s;
 
-  val = (arr[0] << 24) | (arr[1] << 16) | (arr[2] << 8) | arr[3];
-  val = trunc_int_for_mode (val, SImode);
+    case HIGH:
+      return IC_IL1s;
+
+    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);
 
-  return which_immediate_load (val) != SPU_NONE;
+      /* 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;
+
+      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_
 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_
     }
   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: gcc/config/spu/constraints.md
===================================================================
--- gcc/config/spu/constraints.md	(revision 119681)
+++ gcc/config/spu/constraints.md	(working copy)
@@ -18,7 +18,7 @@
 
 
 ;; 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,
@@ -84,6 +84,22 @@ (define_constraint "f"
   "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)")))
+
 
 ;; Integer constraints
 
Index: gcc/config/spu/spu.md
===================================================================
--- gcc/config/spu/spu.md	(revision 119681)
+++ gcc/config/spu/spu.md	(working copy)
@@ -238,26 +238,19 @@ (define_expand "mov<mode>"
   })
 
 (define_split 
-  [(set (match_operand:SI 0 "spu_reg_operand" "=r")
-	(match_operand:SI 1 "immediate_operand" "s"))]
+  [(set (match_operand 0 "spu_reg_operand")
+	(match_operand 1 "immediate_operand"))]
 
-  "(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_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"
@@ -285,16 +278,17 @@ (define_insn "load_pic_offset"
 ;; 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")
@@ -310,28 +304,30 @@ (define_insn "low"
   "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")
@@ -358,10 +354,26 @@ (define_insn_and_split "store"
   { 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")
+		    (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")
+	(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))]
   ""
   "@
@@ -369,6 +381,19 @@ (define_insn "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;
+  })
 
 ;; extend
 


More information about the Gcc-patches mailing list