patch: optimized constant vector initializers

Aldy Hernandez aldyh@redhat.com
Mon Mar 31 21:44:00 GMT 2003


When Stan and I worked on the vector initializer code, we ended up 
treating vector initializers like we currently treat constructors, 
which is inefficient for constants.  For example, for:

	vecfoo = (vecfoo_type) {1, 1, 1, 1};

...we dump to memory, then load into vecfoo.  Most SIMD architectures 
provide either instructions or combination of instructions to load 
constants.  In AltiVec, for example, there are instruction combos for 
loading anything from -255 to +255 (provided all elements are the 
same).  Obviously, there is a fine line between "neat trick" and code 
bloat.

The patch below leaves vector constants as constants, instead of 
treating them like constructors.  So things like {1, 2} get generated 
as:

(const_vector:V2SI [
                 (const_int 1 [0x1])
                 (const_int 2 [0x2])


whereas {1, foo()} will be treated as a constructor.

I have also provided code for PowerPC SIMD variants using this new 
feature.  Other back-end maintainers should do something similar for 
easily synthesized constants in their architectures.

I have been careful not to overdo it in the AltiVec arena, and only 
recognize constants that *I* consider useful and are not too 
complicated to generate.

Surprisingly, the generic parts of the patch are quite small.

Are the generic parts OK for mainline?

2003-02-31  Aldy Hernandez  <aldyh@redhat.com>

	* testsuite/gcc.c-torture/execute/simd-3.c: New.

	* expr.h (is_zeros_p): New prototype.

	* expr.c (expand_expr): Handle VECTOR_CST.
	(is_zeros_p): Un constify.
	(const_vector_from_tree): New.

	* varasm.c (output_constant): Handle VECTOR_CST.

	* c-typeck.c (digest_init): Build a vector constant from a
	VECTOR_TYPE.

	* config/rs6000/rs6000.c: Remove prototype for
	easy_vector_constant.
	(easy_vector_constant): Add mode parameter.  Rewrite to handle
	more easy constants.
	(rs6000_emit_move): Pass mode to easy_vector_constant.
	Call emit_easy_vector_insn for SPE V2SI vector constant moves.
	(emit_easy_vector_insn): New.
	(easy_vector_same): New.
	(EASY_VECTOR_15): New macro.
	(EASY_VECTOR_15_ADD_SELF): New macro.
	(bdesc_2arg): Rename to xorv2si3.
	(easy_vector_constant_add_self): New.
	(input_operand): Allow vector constants.

	* config/rs6000/rs6000.h (PREDICATE_CODES): Add
	easy_vector_constant, easy_vector_constant_add_self.
	(EXTRA_CONSTRAINT): Add 'W'.

	* config/rs6000/rs6000-protos.h: Add prototype for
	easy_vector_constant, emit_easy_vector_insn.

	* config/rs6000/altivec.md (xorv8hi3): New.
	(xorv16qi3): New.
	Remove all _const0 patterns.
	(movv4si_internal): Rewrite to use code.  Add vector constant to
	vector alternative.  Add splitter.
	(movv8hi_internal): Same.
	(movv16qi_internal): Same.
	(movv4sf_internal): Same.
	Change the unspecs for vspltis* to use constants.

	* config/rs6000/spe.md ("xorv4hi3"): New.
	("spe_evxor"): Rename to xorv2si3.
	("xorv1di3"): New.
	Remove all _const0 patterns.
	(movv2si_internal): Rewrite to use code.  Add vector constant to
	alternatives.  Add splitter.
	(movv4hi_internal): Add vector constant to alternatives.
	(movv1di_internal): Same.
	(movv2sf_internal): Same.

Index: testsuite/gcc.c-torture/execute/simd-3.c
===================================================================
RCS file: testsuite/gcc.c-torture/execute/simd-3.c
diff -N testsuite/gcc.c-torture/execute/simd-3.c
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/gcc.c-torture/execute/simd-3.c	31 Mar 2003 21:26:26 -0000
***************
*** 0 ****
--- 1,34 ----
+ typedef int __attribute__((mode(V4SI))) vecint;
+ typedef int __attribute__((mode(SI))) siint;
+
+ vecint i, j, k;
+
+ union {
+   vecint v;
+   siint i[4];
+ } res;
+
+ /* This should go away once we can use == and != on vector types.  */
+ void
+ verify (siint a1, siint a2, siint a3, siint a4,
+ 	siint b1, siint b2, siint b3, siint b4)
+ {
+   if (a1 != b1
+       || a2 != b2
+       || a3 != b3
+       || a4 != b4)
+     abort ();
+ }
+
+ int
+ main ()
+ {
+   i = (vecint) { 5, 5, 5, 5 };
+   j = (vecint) { 10, 10, 10, 10 };
+   k = i + j;
+   res.v = k;
+
+   verify (res.i[0], res.i[1], res.i[2], res.i[3], 15, 15, 15, 15);
+
+   exit (0);
+ }
Index: expr.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.h,v
retrieving revision 1.131
diff -c -p -r1.131 expr.h
*** expr.h	13 Mar 2003 16:05:23 -0000	1.131
--- expr.h	31 Mar 2003 21:26:26 -0000
*************** extern rtx expand_assignment PARAMS ((tr
*** 474,479 ****
--- 474,481 ----
   extern rtx store_expr PARAMS ((tree, rtx, int));
   #endif

+ extern int is_zeros_p PARAMS ((tree));
+
   /* Given an rtx that may include add and multiply operations,
      generate them as insns and return a pseudo-reg containing the 
value.
      Useful after calling expand_expr with 1 as sum_ok.  */
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.516
diff -c -p -r1.516 expr.c
*** expr.c	24 Mar 2003 08:31:29 -0000	1.516
--- expr.c	31 Mar 2003 21:26:30 -0000
*************** static rtx clear_storage_via_libcall PAR
*** 155,161 ****
   static tree clear_storage_libcall_fn PARAMS ((int));
   static rtx compress_float_constant PARAMS ((rtx, rtx));
   static rtx get_subtarget	PARAMS ((rtx));
- static int is_zeros_p		PARAMS ((tree));
   static int mostly_zeros_p	PARAMS ((tree));
   static void store_constructor_field PARAMS ((rtx, unsigned 
HOST_WIDE_INT,
   					     HOST_WIDE_INT, enum machine_mode,
--- 155,160 ----
*************** static rtx do_store_flag	PARAMS ((tree,
*** 175,180 ****
--- 174,180 ----
   static void emit_single_push_insn PARAMS ((enum machine_mode, rtx, 
tree));
   #endif
   static void do_tablejump PARAMS ((rtx, enum machine_mode, rtx, rtx, 
rtx));
+ static rtx const_vector_from_tree PARAMS ((tree));

   /* Record for each mode whether we can move a register directly to or
      from an object of that mode in memory.  If we can't, we won't try
*************** store_expr (exp, target, want_value)
*** 4702,4708 ****
   
   /* Return 1 if EXP just contains zeros.  */

! static int
   is_zeros_p (exp)
        tree exp;
   {
--- 4702,4708 ----
   
   /* Return 1 if EXP just contains zeros.  */

! int
   is_zeros_p (exp)
        tree exp;
   {
*************** expand_expr (exp, target, tmode, modifie
*** 6842,6847 ****
--- 6842,6850 ----

         return temp;

+     case VECTOR_CST:
+       return const_vector_from_tree (exp);
+
       case CONST_DECL:
         return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 
modifier);

*************** vector_mode_valid_p (mode)
*** 10327,10332 ****
--- 10330,10372 ----
     /* If we have support for the inner mode, we can safely emulate it.
        We may not have V2DI, but me can emulate with a pair of DIs.  */
     return mov_optab->handlers[innermode].insn_code != CODE_FOR_nothing;
+ }
+
+ /* Return a CONST_VECTOR rtx for a VECTOR_CST tree.  */
+ static rtx
+ const_vector_from_tree (exp)
+      tree exp;
+ {
+   rtvec v;
+   int units, i;
+   tree link, elt;
+   enum machine_mode inner, mode;
+
+   mode = TYPE_MODE (TREE_TYPE (exp));
+
+   if (is_zeros_p (exp))
+     return CONST0_RTX (mode);
+
+   units = GET_MODE_NUNITS (mode);
+   inner = GET_MODE_INNER (mode);
+
+   v = rtvec_alloc (units);
+
+   link = TREE_VECTOR_CST_ELTS (exp);
+   for (i = 0; link; link = TREE_CHAIN (link), ++i)
+     {
+       elt = TREE_VALUE (link);
+
+       if (TREE_CODE (elt) == REAL_CST)
+ 	RTVEC_ELT (v, i) = CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (elt),
+ 							 inner);
+       else
+ 	RTVEC_ELT (v, i) = immed_double_const (TREE_INT_CST_LOW (elt),
+ 					       TREE_INT_CST_HIGH (elt),
+ 					       inner);
+     }
+
+   return gen_rtx_raw_CONST_VECTOR (mode, v);
   }

   #include "gt-expr.h"
Index: varasm.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/varasm.c,v
retrieving revision 1.335
diff -c -p -r1.335 varasm.c
*** varasm.c	15 Mar 2003 16:30:35 -0000	1.335
--- varasm.c	31 Mar 2003 21:26:31 -0000
*************** output_constant (exp, size, align)
*** 4015,4020 ****
--- 4015,4031 ----
   	  thissize = MIN (TREE_STRING_LENGTH (exp), size);
   	  assemble_string (TREE_STRING_POINTER (exp), thissize);
   	}
+       else if (TREE_CODE (exp) == VECTOR_CST)
+ 	{
+ 	  int elt_size;
+ 	  tree link;
+
+ 	  elt_size = GET_MODE_UNIT_SIZE (TYPE_MODE (TREE_TYPE (exp)));
+
+ 	  link = TREE_VECTOR_CST_ELTS (exp);
+ 	  for (; link; link = TREE_CHAIN (link))
+ 	    output_constant (TREE_VALUE (link), elt_size, align);
+ 	}
         else
   	abort ();
         break;
Index: c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.227
diff -c -p -r1.227 c-typeck.c
*** c-typeck.c	24 Mar 2003 08:31:28 -0000	1.227
--- c-typeck.c	31 Mar 2003 21:26:33 -0000
*************** digest_init (type, init, require_constan
*** 4759,4764 ****
--- 4759,4772 ----
   	}
       }

+   /* Build a VECTOR_CST from a *constant* vector constructor.  If the
+      vector constructor is not constant (e.g. {1,2,3,foo()}) then punt
+      below and handle as a constructor.  */
+   if (code == VECTOR_TYPE
+       && comptypes (TREE_TYPE (inside_init), type)
+       && TREE_CONSTANT (inside_init))
+     return build_vector (type, TREE_OPERAND (inside_init, 1));
+
     /* Any type can be initialized
        from an expression of the same type, optionally with braces.  */

Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.446
diff -c -p -r1.446 rs6000.c
*** config/rs6000/rs6000.c	31 Mar 2003 17:46:57 -0000	1.446
--- config/rs6000/rs6000.c	31 Mar 2003 21:26:37 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 55,60 ****
--- 55,67 ----
   #define TARGET_NO_PROTOTYPE 0
   #endif

+ #define EASY_VECTOR_15(n, x, y) ((n) >= -16 && (n) <= 15 \
+ 				 && easy_vector_same (x, y))
+
+ #define EASY_VECTOR_15_ADD_SELF(n, x, y) ((n) >= 0x10 && (n) <= 0x1e \
+                                           && !((n) & 1)              \
+ 					  && easy_vector_same (x, y))
+
   #define min(A,B)	((A) < (B) ? (A) : (B))
   #define max(A,B)	((A) > (B) ? (A) : (B))

*************** static int first_altivec_reg_to_save PAR
*** 266,272 ****
   static unsigned int compute_vrsave_mask PARAMS ((void));
   static void is_altivec_return_reg PARAMS ((rtx, void *));
   static rtx generate_set_vrsave PARAMS ((rtx, rs6000_stack_t *, int));
! static int easy_vector_constant PARAMS ((rtx));
   static bool is_ev64_opaque_type PARAMS ((tree));
   static rtx rs6000_dwarf_register_span PARAMS ((rtx));

--- 273,280 ----
   static unsigned int compute_vrsave_mask PARAMS ((void));
   static void is_altivec_return_reg PARAMS ((rtx, void *));
   static rtx generate_set_vrsave PARAMS ((rtx, rs6000_stack_t *, int));
! int easy_vector_constant PARAMS ((rtx, enum machine_mode));
! static int easy_vector_same PARAMS ((rtx, enum machine_mode));
   static bool is_ev64_opaque_type PARAMS ((tree));
   static rtx rs6000_dwarf_register_span PARAMS ((rtx));

*************** easy_fp_constant (op, mode)
*** 1416,1463 ****
       abort ();
   }

! /* Return 1 if the operand is a CONST_INT and can be put into a
!    register with one instruction.  */

   static int
! easy_vector_constant (op)
        rtx op;
   {
!   rtx elt;
!   int units, i;

!   if (GET_CODE (op) != CONST_VECTOR)
       return 0;

!   units = CONST_VECTOR_NUNITS (op);

!   /* We can generate 0 easily.  Look for that.  */
!   for (i = 0; i < units; ++i)
!     {
!       elt = CONST_VECTOR_ELT (op, i);

!       /* We could probably simplify this by just checking for equality
! 	 with CONST0_RTX for the current mode, but let's be safe
! 	 instead.  */

!       switch (GET_CODE (elt))
   	{
! 	case CONST_INT:
! 	  if (INTVAL (elt) != 0)
! 	    return 0;
! 	  break;
! 	case CONST_DOUBLE:
! 	  if (CONST_DOUBLE_LOW (elt) != 0 || CONST_DOUBLE_HIGH (elt) != 0)
! 	    return 0;
! 	  break;
! 	default:
! 	  return 0;
   	}
       }

!   /* We could probably generate a few other constants trivially, but
!      gcc doesn't generate them yet.  FIXME later.  */
!   return 1;
   }

   /* Return 1 if the operand is the constant 0.  This works for scalars
--- 1424,1572 ----
       abort ();
   }

! /* Return non zero if all elements of a vector have the same value.  
*/

   static int
! easy_vector_same (op, mode)
!      rtx op;
!      enum machine_mode mode ATTRIBUTE_UNUSED;
! {
!   int units, i, cst;
!
!   units = CONST_VECTOR_NUNITS (op);
!
!   cst = INTVAL (CONST_VECTOR_ELT (op, 0));
!   for (i = 1; i < units; ++i)
!     if (INTVAL (CONST_VECTOR_ELT (op, i)) != cst)
!       break;
!   if (i == units)
!     return 1;
!   return 0;
! }
!
! /* Return 1 if the operand is a CONST_INT and can be put into a
!    register without using memory.  */
!
! int
! easy_vector_constant (op, mode)
        rtx op;
+      enum machine_mode mode;
   {
!   int cst, cst2;

!   if (GET_CODE (op) != CONST_VECTOR
!       || (!TARGET_ALTIVEC
! 	  && !TARGET_SPE))
       return 0;

!   if (zero_constant (op, mode)
!       && ((TARGET_ALTIVEC && ALTIVEC_VECTOR_MODE (mode))
! 	  || (TARGET_SPE && SPE_VECTOR_MODE (mode))))
!     return 1;

!   if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
!     return 0;
!
!   cst  = INTVAL (CONST_VECTOR_ELT (op, 0));
!   cst2 = INTVAL (CONST_VECTOR_ELT (op, 1));
!
!   /* Limit SPE vectors to 15 bits signed.  These we can generate with:
!        li r0, CONSTANT1
!        evmergelo r0, r0, r0
!        li r0, CONSTANT2

!      I don't know how efficient it would be to allow bigger constants,
!      considering we'll have an extra 'ori' for every 'li'.  I doubt 5
!      instructions is better than a 64-bit memory load, but I don't
!      have the e500 timing specs.  */
!   if (TARGET_SPE && mode == V2SImode
!       && cst  >= -0x7fff && cst <= 0x7fff
!       && cst2 >= -0x7fff && cst <= 0x7fff)
!     return 1;
!
!   if (TARGET_ALTIVEC && EASY_VECTOR_15 (cst, op, mode))
!     return 1;
!
!   if (TARGET_ALTIVEC && EASY_VECTOR_15_ADD_SELF (cst, op, mode))
!     return 1;
!
!   return 0;
! }

! /* Same as easy_vector_constant but only for EASY_VECTOR_15_ADD_SELF. 
  */
!
! int
! easy_vector_constant_add_self (op, mode)
!      rtx op;
!      enum machine_mode mode;
! {
!   int cst;
!
!   if (!easy_vector_constant (op, mode))
!     return 0;
!
!   cst = INTVAL (CONST_VECTOR_ELT (op, 0));
!
!   return TARGET_ALTIVEC && EASY_VECTOR_15_ADD_SELF (cst, op, mode);
! }
!
! char *
! output_vec_const_move (operands)
!      rtx *operands;
! {
!   int cst, cst2;
!   enum machine_mode mode;
!   rtx dest, vec;
!
!   dest = operands[0];
!   vec = operands[1];
!
!   cst = INTVAL (CONST_VECTOR_ELT (vec, 0));
!   cst2 = INTVAL (CONST_VECTOR_ELT (vec, 1));
!   mode = GET_MODE (dest);
!
!   if (TARGET_ALTIVEC)
!     {
!       if (zero_constant (vec, mode))
! 	return "vxor %0,%0,%0";
!       else if (EASY_VECTOR_15 (cst, vec, mode))
   	{
! 	  operands[1] = GEN_INT (cst);
! 	  switch (mode)
! 	    {
! 	    case V4SImode:
! 	      return "vspltisw %0,%1";
! 	    case V8HImode:
! 	      return "vspltish %0,%1";
! 	    case V16QImode:
! 	      return "vspltisb %0,%1";
! 	    default:
! 	      abort ();
! 	    }
   	}
+       else if (EASY_VECTOR_15_ADD_SELF (cst, vec, mode))
+ 	return "#";
+       else
+ 	abort ();
       }

!   if (TARGET_SPE)
!     {
!       /* Vector constant 0 is handled as a splitter of V2SI, and in 
the
! 	 pattern of V1DI, V4HI, and V2SF.
!
! 	 FIXME: We should probabl return # and add post reload
! 	 splitters for these, but this way is so easy ;-).
!       */
!       operands[1] = GEN_INT (cst);
!       operands[2] = GEN_INT (cst2);
!       if (cst == cst2)
! 	return "li %0,%1\n\tevmergelo %0,%0,%0";
!       else
! 	return "li %0,%1\n\tevmergelo %0,%0,%0\n\tli %0,%2";
!     }
!
!   abort ();
   }

   /* Return 1 if the operand is the constant 0.  This works for scalars
*************** input_operand (op, mode)
*** 1990,1995 ****
--- 2099,2109 ----
   	  || GET_CODE (op) == CONST_DOUBLE))
       return 1;

+   /* Allow easy vector constants.  */
+   if (GET_CODE (op) == CONST_VECTOR
+       && easy_vector_constant (op, mode))
+     return 1;
+
     /* For floating-point or multi-word mode, the only remaining valid 
type
        is a register.  */
     if (GET_MODE_CLASS (mode) == MODE_FLOAT
*************** rs6000_emit_move (dest, source, mode)
*** 2744,2750 ****
       case V2SImode:
       case V1DImode:
         if (CONSTANT_P (operands[1])
! 	  && !easy_vector_constant (operands[1]))
   	operands[1] = force_const_mem (mode, operands[1]);
         break;

--- 2858,2864 ----
       case V2SImode:
       case V1DImode:
         if (CONSTANT_P (operands[1])
! 	  && !easy_vector_constant (operands[1], mode))
   	operands[1] = force_const_mem (mode, operands[1]);
         break;

Index: config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.260
diff -c -p -r1.260 rs6000.h
*** config/rs6000/rs6000.h	31 Mar 2003 17:46:55 -0000	1.260
--- config/rs6000/rs6000.h	31 Mar 2003 21:26:38 -0000
*************** enum reg_class
*** 1292,1297 ****
--- 1292,1298 ----
      'S' is a constant that can be placed into a 64-bit mask operand
      'T' is a constant that can be placed into a 32-bit mask operand
      'U' is for V.4 small data references.
+    'W' is a vector constant that can be easily generated (no mem 
refs).
      't' is for AND masks that can be performed by two rldic{l,r} 
insns.  */

   #define EXTRA_CONSTRAINT(OP, C)						\
*************** enum reg_class
*** 1305,1310 ****
--- 1306,1312 ----
   		   && (fixed_regs[CR0_REGNO]				\
   		       || !logical_operand (OP, DImode))		\
   		   && !mask64_operand (OP, DImode))			\
+    : (C) == 'W' ? (easy_vector_constant (OP, GET_MODE (OP)))		\
      : 0)

   /* Given an rtx X being reloaded into a reg required to be
*************** extern char rs6000_reg_names[][8];	/* re
*** 2740,2745 ****
--- 2742,2749 ----
     {"got_operand", {SYMBOL_REF, CONST, LABEL_REF}},			   \
     {"got_no_const_operand", {SYMBOL_REF, LABEL_REF}},			   \
     {"easy_fp_constant", {CONST_DOUBLE}},					   \
+   {"easy_vector_constant", {CONST_VECTOR}},				   \
+   {"easy_vector_constant_add_self", {CONST_VECTOR}},			   \
     {"zero_fp_constant", {CONST_DOUBLE}},					   \
     {"reg_or_mem_operand", {SUBREG, MEM, REG}},				   \
     {"lwa_operand", {SUBREG, MEM, REG}},					   \
Index: config/rs6000/rs6000-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.49
diff -c -p -r1.49 rs6000-protos.h
*** config/rs6000/rs6000-protos.h	28 Jan 2003 23:26:28 -0000	1.49
--- config/rs6000/rs6000-protos.h	31 Mar 2003 21:26:38 -0000
*************** extern int got_operand PARAMS ((rtx, enu
*** 54,59 ****
--- 54,61 ----
   extern int got_no_const_operand PARAMS ((rtx, enum machine_mode));
   extern int num_insns_constant PARAMS ((rtx, enum machine_mode));
   extern int easy_fp_constant PARAMS ((rtx, enum machine_mode));
+ extern int easy_vector_constant PARAMS ((rtx, enum machine_mode));
+ extern char *output_vec_const_move PARAMS ((rtx *));
   extern int zero_fp_constant PARAMS ((rtx, enum machine_mode));
   extern int zero_constant PARAMS ((rtx, enum machine_mode));
   extern int volatile_mem_operand PARAMS ((rtx, enum machine_mode));
Index: config/rs6000/altivec.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/altivec.md,v
retrieving revision 1.5
diff -c -p -r1.5 altivec.md
*** config/rs6000/altivec.md	7 Jan 2003 02:54:13 -0000	1.5
--- config/rs6000/altivec.md	31 Mar 2003 21:26:38 -0000
***************
*** 19,24 ****
--- 19,30 ----
   ;; the Free Software Foundation, 59 Temple Place - Suite 330,
   ;; Boston, MA 02111-1307, USA.

+ (define_constants
+   [(UNSPEC_VSPLTISW	141)
+    (UNSPEC_VSPLTISH	140)
+    (UNSPEC_VSPLTISB	139)
+    ])
+
   ;; Generic LVX load instruction.
   (define_insn "altivec_lvx_4si"
     [(set (match_operand:V4SI 0 "altivec_register_operand" "=v")
***************
*** 85,102 ****
     "{ rs6000_emit_move (operands[0], operands[1], V4SImode); DONE; }")

   (define_insn "*movv4si_internal"
!   [(set (match_operand:V4SI 0 "nonimmediate_operand" "=m,v,v,o,r,r")
! 	(match_operand:V4SI 1 "input_operand" "v,m,v,r,o,r"))]
     "TARGET_ALTIVEC"
!   "@
!    stvx %1,%y0
!    lvx %0,%y1
!    vor %0,%1,%1
!    stw%U0 %1,%0\;stw %L1,%L0\;stw %Y1,%Y0\;stw %Z1,%Z0
!    lwz%U1 %0,%1\;lwz %L0,%L1\;lwz %Y0,%Y1\;lwz %Z0,%Z1
!    mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*")
!    (set_attr "length" "*,*,*,16,16,16")])

   (define_expand "movv8hi"
     [(set (match_operand:V8HI 0 "nonimmediate_operand" "")
--- 91,127 ----
     "{ rs6000_emit_move (operands[0], operands[1], V4SImode); DONE; }")

   (define_insn "*movv4si_internal"
!   [(set (match_operand:V4SI 0 "nonimmediate_operand" "=m,v,v,o,r,r,v")
! 	(match_operand:V4SI 1 "input_operand" "v,m,v,r,o,r,W"))]
     "TARGET_ALTIVEC"
!   "*
! {
!   switch (which_alternative)
!     {
!     case 0: return \"stvx %1,%y0\";
!     case 1: return \"lvx %0,%y1\";
!     case 2: return \"vor %0,%1,%1\";
!     case 3: return \"stw%U0 %1,%0\;stw %L1,%L0\;stw %Y1,%Y0\;stw 
%Z1,%Z0\";
!     case 4: return \"lwz%U1 %0,%1\;lwz %L0,%L1\;lwz %Y0,%Y1\;lwz 
%Z0,%Z1\";
!     case 5: return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
!     case 6: return output_vec_const_move (operands);
!     default: abort();
!     }
! }"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*,*")
!    (set_attr "length" "*,*,*,16,16,16,*")])
!
! (define_split
!   [(set (match_operand:V4SI 0 "altivec_register_operand" "")
! 	(match_operand:V4SI 1 "easy_vector_constant_add_self" ""))]
!   "TARGET_ALTIVEC && reload_completed"
!   [(set (match_dup 0)
! 	(unspec:V4SI [(match_dup 3)] UNSPEC_VSPLTISW))
!    (set (match_dup 0)
! 	(plus:V4SI (match_dup 0)
! 		   (match_dup 0)))]
!   "
! { operands[3] = GEN_INT (INTVAL (CONST_VECTOR_ELT (operands[1], 0)) 
 >> 1); }")

   (define_expand "movv8hi"
     [(set (match_operand:V8HI 0 "nonimmediate_operand" "")
***************
*** 105,122 ****
     "{ rs6000_emit_move (operands[0], operands[1], V8HImode); DONE; }")

   (define_insn "*movv8hi_internal1"
!   [(set (match_operand:V8HI 0 "nonimmediate_operand" "=m,v,v,o,r,r")
! 	(match_operand:V8HI 1 "input_operand" "v,m,v,r,o,r"))]
     "TARGET_ALTIVEC"
!   "@
!    stvx %1,%y0
!    lvx %0,%y1
!    vor %0,%1,%1
!    stw%U0 %1,%0\;stw %L1,%L0\;stw %Y1,%Y0\;stw %Z1,%Z0
!    lwz%U1 %0,%1\;lwz %L0,%L1\;lwz %Y0,%Y1\;lwz %Z0,%Z1
!    mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*")
!    (set_attr "length" "*,*,*,16,16,16")])

   (define_expand "movv16qi"
     [(set (match_operand:V16QI 0 "nonimmediate_operand" "")
--- 130,166 ----
     "{ rs6000_emit_move (operands[0], operands[1], V8HImode); DONE; }")

   (define_insn "*movv8hi_internal1"
!   [(set (match_operand:V8HI 0 "nonimmediate_operand" "=m,v,v,o,r,r,v")
! 	(match_operand:V8HI 1 "input_operand" "v,m,v,r,o,r,W"))]
     "TARGET_ALTIVEC"
!   "*
! {
!    switch (which_alternative)
!      {
!      case 0: return \"stvx %1,%y0\";
!      case 1: return \"lvx %0,%y1\";
!      case 2: return \"vor %0,%1,%1\";
!      case 3: return \"stw%U0 %1,%0\;stw %L1,%L0\;stw %Y1,%Y0\;stw 
%Z1,%Z0\";
!      case 4: return \"lwz%U1 %0,%1\;lwz %L0,%L1\;lwz %Y0,%Y1\;lwz 
%Z0,%Z1\";
!      case 5: return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
!      case 6: return output_vec_const_move (operands);
!      default: abort ();
!      }
! }"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*,*")
!    (set_attr "length" "*,*,*,16,16,16,*")])
!
! (define_split
!   [(set (match_operand:V8HI 0 "altivec_register_operand" "")
! 	(match_operand:V8HI 1 "easy_vector_constant_add_self" ""))]
!   "TARGET_ALTIVEC && reload_completed"
!   [(set (match_dup 0)
! 	(unspec:V8HI [(match_dup 3)] UNSPEC_VSPLTISH))
!    (set (match_dup 0)
! 	(plus:V8HI (match_dup 0)
! 		   (match_dup 0)))]
!   "
! { operands[3] = GEN_INT (INTVAL (CONST_VECTOR_ELT (operands[1], 0)) 
 >> 1); }")

   (define_expand "movv16qi"
     [(set (match_operand:V16QI 0 "nonimmediate_operand" "")
***************
*** 125,142 ****
     "{ rs6000_emit_move (operands[0], operands[1], V16QImode); DONE; }")

   (define_insn "*movv16qi_internal1"
!   [(set (match_operand:V16QI 0 "nonimmediate_operand" "=m,v,v,o,r,r")
! 	(match_operand:V16QI 1 "input_operand" "v,m,v,r,o,r"))]
     "TARGET_ALTIVEC"
!   "@
!    stvx %1,%y0
!    lvx %0,%y1
!    vor %0,%1,%1
!    stw%U0 %1,%0\;stw %L1,%L0\;stw %Y1,%Y0\;stw %Z1,%Z0
!    lwz%U1 %0,%1\;lwz %L0,%L1\;lwz %Y0,%Y1\;lwz %Z0,%Z1
!    mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*")
!    (set_attr "length" "*,*,*,16,16,16")])

   (define_expand "movv4sf"
     [(set (match_operand:V4SF 0 "nonimmediate_operand" "")
--- 169,205 ----
     "{ rs6000_emit_move (operands[0], operands[1], V16QImode); DONE; }")

   (define_insn "*movv16qi_internal1"
!   [(set (match_operand:V16QI 0 "nonimmediate_operand" 
"=m,v,v,o,r,r,v")
! 	(match_operand:V16QI 1 "input_operand" "v,m,v,r,o,r,W"))]
     "TARGET_ALTIVEC"
!   "*
! {
!   switch (which_alternative)
!     {
!     case 0: return \"stvx %1,%y0\";
!     case 1: return \"lvx %0,%y1\";
!     case 2: return \"vor %0,%1,%1\";
!     case 3: return \"stw%U0 %1,%0\;stw %L1,%L0\;stw %Y1,%Y0\;stw 
%Z1,%Z0\";
!     case 4: return \"lwz%U1 %0,%1\;lwz %L0,%L1\;lwz %Y0,%Y1\;lwz 
%Z0,%Z1\";
!     case 5: return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
!     case 6: return output_vec_const_move (operands);
!     default: abort ();
!     }
! }"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*,*")
!    (set_attr "length" "*,*,*,16,16,16,*")])
!
! (define_split
!   [(set (match_operand:V16QI 0 "altivec_register_operand" "")
! 	(match_operand:V16QI 1 "easy_vector_constant_add_self" ""))]
!   "TARGET_ALTIVEC && reload_completed"
!   [(set (match_dup 0)
! 	(unspec:V16QI [(match_dup 3)] UNSPEC_VSPLTISB))
!    (set (match_dup 0)
! 	(plus:V16QI (match_dup 0)
! 		   (match_dup 0)))]
!   "
! { operands[3] = GEN_INT (INTVAL (CONST_VECTOR_ELT (operands[1], 0)) 
 >> 1); }")

   (define_expand "movv4sf"
     [(set (match_operand:V4SF 0 "nonimmediate_operand" "")
***************
*** 145,162 ****
     "{ rs6000_emit_move (operands[0], operands[1], V4SFmode); DONE; }")

   (define_insn "*movv4sf_internal1"
!   [(set (match_operand:V4SF 0 "nonimmediate_operand" "=m,v,v,o,r,r")
! 	(match_operand:V4SF 1 "input_operand" "v,m,v,r,o,r"))]
     "TARGET_ALTIVEC"
!   "@
!    stvx %1,%y0
!    lvx %0,%y1
!    vor %0,%1,%1
!    stw%U0 %1,%0\;stw %L1,%L0\;stw %Y1,%Y0\;stw %Z1,%Z0
!    lwz%U1 %0,%1\;lwz %L0,%L1\;lwz %Y0,%Y1\;lwz %Z0,%Z1
!    mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*")
!    (set_attr "length" "*,*,*,16,16,16")])

   (define_insn "get_vrsave_internal"
     [(set (match_operand:SI 0 "register_operand" "=r")
--- 208,232 ----
     "{ rs6000_emit_move (operands[0], operands[1], V4SFmode); DONE; }")

   (define_insn "*movv4sf_internal1"
!   [(set (match_operand:V4SF 0 "nonimmediate_operand" "=m,v,v,o,r,r,v")
! 	(match_operand:V4SF 1 "input_operand" "v,m,v,r,o,r,W"))]
     "TARGET_ALTIVEC"
!   "*
! {
!   switch (which_alternative)
!     {
!     case 0: return \"stvx %1,%y0\";
!     case 1: return \"lvx %0,%y1\";
!     case 2: return \"vor %0,%1,%1\";
!     case 3: return \"stw%U0 %1,%0\;stw %L1,%L0\;stw %Y1,%Y0\;stw 
%Z1,%Z0\";
!     case 4: return \"lwz%U1 %0,%1\;lwz %L0,%L1\;lwz %Y0,%Y1\;lwz 
%Z0,%Z1\";
!     case 5: return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
!     case 6: return output_vec_const_move (operands);
!     default: abort ();
!     }
! }"
!   [(set_attr "type" "vecstore,vecload,vecsimple,store,load,*,*")
!    (set_attr "length" "*,*,*,16,16,16,*")])

   (define_insn "get_vrsave_internal"
     [(set (match_operand:SI 0 "register_operand" "=r")
***************
*** 186,221 ****
   }"
     [(set_attr "type" "*")])

- ;; Vector clears
- (define_insn "*movv4si_const0"
-   [(set (match_operand:V4SI 0 "altivec_register_operand" "=v")
- 	(match_operand:V4SI 1 "zero_constant" ""))]
-   "TARGET_ALTIVEC"
-   "vxor %0,%0,%0"
-   [(set_attr "type" "vecsimple")])
-
- (define_insn "*movv4sf_const0"
-   [(set (match_operand:V4SF 0 "altivec_register_operand" "=v")
- 	(match_operand:V4SF 1 "zero_constant" ""))]
- 					
-   "TARGET_ALTIVEC"
-   "vxor %0,%0,%0"
-   [(set_attr "type" "vecsimple")])
-
- (define_insn "*movv8hi_const0"
-   [(set (match_operand:V8HI 0 "altivec_register_operand" "=v")
- 	(match_operand:V8HI 1 "zero_constant" ""))]
-   "TARGET_ALTIVEC"
-   "vxor %0,%0,%0"
-   [(set_attr "type" "vecsimple")])
-
- (define_insn "*movv16qi_const0"
-   [(set (match_operand:V16QI 0 "altivec_register_operand" "=v")
- 	(match_operand:V16QI 1 "zero_constant" ""))]
-   "TARGET_ALTIVEC"
-   "vxor %0,%0,%0"
-   [(set_attr "type" "vecsimple")])
-
   ;; Simple binary operations.

   (define_insn "addv16qi3"
--- 256,261 ----
***************
*** 1279,1284 ****
--- 1319,1325 ----
     "vsumsws %0,%1,%2"
     [(set_attr "type" "veccomplex")])

+ ;; Vector xor's
   (define_insn "xorv4si3"
     [(set (match_operand:V4SI 0 "register_operand" "=v")
           (xor:V4SI (match_operand:V4SI 1 "register_operand" "v")
***************
*** 1287,1292 ****
--- 1328,1349 ----
     "vxor %0,%1,%2"
     [(set_attr "type" "vecsimple")])

+ (define_insn "xorv8hi3"
+   [(set (match_operand:V8HI 0 "register_operand" "=v")
+         (xor:V8HI (match_operand:V8HI 1 "register_operand" "v")
+                   (match_operand:V8HI 2 "register_operand" "v")))]
+   "TARGET_ALTIVEC"
+   "vxor %0,%1,%2"
+   [(set_attr "type" "vecsimple")])
+
+ (define_insn "xorv16qi3"
+   [(set (match_operand:V16QI 0 "register_operand" "=v")
+         (xor:V16QI (match_operand:V16QI 1 "register_operand" "v")
+ 		   (match_operand:V16QI 2 "register_operand" "v")))]
+   "TARGET_ALTIVEC"
+   "vxor %0,%1,%2"
+   [(set_attr "type" "vecsimple")])
+
   (define_insn "altivec_vspltb"
     [(set (match_operand:V16QI 0 "register_operand" "=v")
           (unspec:V16QI [(match_operand:V16QI 1 "register_operand" "v")
***************
*** 1294,1299 ****
--- 1351,1357 ----
     "TARGET_ALTIVEC"
     "vspltb %0,%1,%2"
     [(set_attr "type" "vecperm")])
+ ;; End of vector xor's

   (define_insn "altivec_vsplth"
     [(set (match_operand:V8HI 0 "register_operand" "=v")
***************
*** 1313,1333 ****

   (define_insn "altivec_vspltisb"
     [(set (match_operand:V16QI 0 "register_operand" "=v")
!         (unspec:V16QI [(match_operand:QI 1 "immediate_operand" "i")] 
139))]
     "TARGET_ALTIVEC"
     "vspltisb %0,%1"
     [(set_attr "type" "vecperm")])

   (define_insn "altivec_vspltish"
     [(set (match_operand:V8HI 0 "register_operand" "=v")
!         (unspec:V8HI [(match_operand:QI 1 "immediate_operand" "i")] 
140))]
     "TARGET_ALTIVEC"
     "vspltish %0,%1"
     [(set_attr "type" "vecperm")])

   (define_insn "altivec_vspltisw"
     [(set (match_operand:V4SI 0 "register_operand" "=v")
!         (unspec:V4SI [(match_operand:QI 1 "immediate_operand" "i")] 
141))]
     "TARGET_ALTIVEC"
     "vspltisw %0,%1"
     [(set_attr "type" "vecperm")])
--- 1371,1394 ----

   (define_insn "altivec_vspltisb"
     [(set (match_operand:V16QI 0 "register_operand" "=v")
!         (unspec:V16QI [(match_operand:QI 1 "immediate_operand" "i")]
! 		      UNSPEC_VSPLTISB))]
     "TARGET_ALTIVEC"
     "vspltisb %0,%1"
     [(set_attr "type" "vecperm")])

   (define_insn "altivec_vspltish"
     [(set (match_operand:V8HI 0 "register_operand" "=v")
!         (unspec:V8HI [(match_operand:QI 1 "immediate_operand" "i")]
! 		     UNSPEC_VSPLTISH))]
     "TARGET_ALTIVEC"
     "vspltish %0,%1"
     [(set_attr "type" "vecperm")])

   (define_insn "altivec_vspltisw"
     [(set (match_operand:V4SI 0 "register_operand" "=v")
!         (unspec:V4SI [(match_operand:QI 1 "immediate_operand" "i")]
! 		     UNSPEC_VSPLTISW))]
     "TARGET_ALTIVEC"
     "vspltisw %0,%1"
     [(set_attr "type" "vecperm")])
Index: config/rs6000/spe.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/spe.md,v
retrieving revision 1.10
diff -c -p -r1.10 spe.md
*** config/rs6000/spe.md	26 Mar 2003 16:24:54 -0000	1.10
--- config/rs6000/spe.md	31 Mar 2003 21:26:39 -0000
***************
*** 2147,2182 ****
     [(set_attr "type" "vecstore")
      (set_attr  "length" "4")])

- ;; SPE vector clears
-
- (define_insn "*movv2si_const0"
-   [(set (match_operand:V2SI 0 "gpc_reg_operand" "=r")
- 	(match_operand:V2SI 1 "zero_constant" ""))]
-   "TARGET_SPE"
-   "evxor %0,%0,%0"
-   [(set_attr "type" "vecsimple")])
-
- (define_insn "*movv2sf_const0"
-   [(set (match_operand:V2SF 0 "gpc_reg_operand" "=r")
- 	(match_operand:V2SF 1 "zero_constant" ""))]
-   "TARGET_SPE"
-   "evxor %0,%0,%0"
-   [(set_attr "type" "vecsimple")])
-
- (define_insn "*movv4hi_const0"
-   [(set (match_operand:V4HI 0 "gpc_reg_operand" "=r")
- 	(match_operand:V4HI 1 "zero_constant" ""))]
-   "TARGET_SPE"
-   "evxor %0,%0,%0"
-   [(set_attr "type" "vecsimple")])
-
- (define_insn "*movv1di_const0"
-   [(set (match_operand:V1DI 0 "gpc_reg_operand" "=r")
- 	(match_operand:V1DI 1 "zero_constant" ""))]
-   "TARGET_SPE"
-   "evxor %0,%0,%0"
-   [(set_attr "type" "vecsimple")])
-
   ;; Vector move instructions.

   (define_expand "movv2si"
--- 2147,2152 ----
***************
*** 2185,2200 ****
     "TARGET_SPE"
     "{ rs6000_emit_move (operands[0], operands[1], V2SImode); DONE; }")

-
   (define_insn "*movv2si_internal"
!   [(set (match_operand:V2SI 0 "nonimmediate_operand" "=m,r,r")
! 	(match_operand:V2SI 1 "input_operand" "r,m,r"))]
     "TARGET_SPE"
!   "@
!    evstdd%X0 %1,%y0
!    evldd%X1 %0,%y1
!    evor %0,%1,%1"
!   [(set_attr "type" "vecload,vecload,vecsimple")])

   (define_expand "movv1di"
     [(set (match_operand:V1DI 0 "nonimmediate_operand" "")
--- 2155,2185 ----
     "TARGET_SPE"
     "{ rs6000_emit_move (operands[0], operands[1], V2SImode); DONE; }")

   (define_insn "*movv2si_internal"
!   [(set (match_operand:V2SI 0 "nonimmediate_operand" "=m,r,r,r")
! 	(match_operand:V2SI 1 "input_operand" "r,m,r,W"))]
     "TARGET_SPE"
!   "*
! {
!   switch (which_alternative)
!     {
!     case 0: return \"evstdd%X0 %1,%y0\";
!     case 1: return \"evldd%X1 %0,%y1\";
!     case 2: return \"evor %0,%1,%1\";
!     case 3: return output_vec_const_move (operands);
!     default: abort ();
!     }
! }"
!   [(set_attr "type" "vecload,vecstore,*,*")
!    (set_attr "length" "*,*,*,12")])
!
! (define_split
!   [(set (match_operand:V2SI 0 "register_operand" "")
! 	(match_operand:V2SI 1 "zero_constant" ""))]
!   "TARGET_SPE && reload_completed"
!   [(set (match_dup 0)
! 	(xor:V2SI (match_dup 0) (match_dup 0)))]
!   "")

   (define_expand "movv1di"
     [(set (match_operand:V1DI 0 "nonimmediate_operand" "")
***************
*** 2203,2216 ****
     "{ rs6000_emit_move (operands[0], operands[1], V1DImode); DONE; }")

   (define_insn "*movv1di_internal"
!   [(set (match_operand:V1DI 0 "nonimmediate_operand" "=m,r,r")
! 	(match_operand:V1DI 1 "input_operand" "r,m,r"))]
     "TARGET_SPE"
     "@
      evstdd%X0 %1,%y0
      evldd%X1 %0,%y1
!    evor %0,%1,%1"
!   [(set_attr "type" "vecload,vecload,vecsimple")])

   (define_expand "movv4hi"
     [(set (match_operand:V4HI 0 "nonimmediate_operand" "")
--- 2188,2203 ----
     "{ rs6000_emit_move (operands[0], operands[1], V1DImode); DONE; }")

   (define_insn "*movv1di_internal"
!   [(set (match_operand:V1DI 0 "nonimmediate_operand" "=m,r,r,r")
! 	(match_operand:V1DI 1 "input_operand" "r,m,r,W"))]
     "TARGET_SPE"
     "@
      evstdd%X0 %1,%y0
      evldd%X1 %0,%y1
!    evor %0,%1,%1
!    evxor %0,%0,%0"
!   [(set_attr "type" "vecload,vecstore,*,*")
!    (set_attr "length" "*,*,*,*")])

   (define_expand "movv4hi"
     [(set (match_operand:V4HI 0 "nonimmediate_operand" "")
***************
*** 2226,2232 ****
      evstdd%X0 %1,%y0
      evldd%X1 %0,%y1
      evor %0,%1,%1"
!   [(set_attr "type" "vecload,vecload,vecsimple")])

   (define_expand "movv2sf"
     [(set (match_operand:V2SF 0 "nonimmediate_operand" "")
--- 2213,2219 ----
      evstdd%X0 %1,%y0
      evldd%X1 %0,%y1
      evor %0,%1,%1"
!   [(set_attr "type" "vecload")])

   (define_expand "movv2sf"
     [(set (match_operand:V2SF 0 "nonimmediate_operand" "")
***************
*** 2235,2248 ****
     "{ rs6000_emit_move (operands[0], operands[1], V2SFmode); DONE; }")

   (define_insn "*movv2sf_internal"
!   [(set (match_operand:V2SF 0 "nonimmediate_operand" "=m,r,r")
! 	(match_operand:V2SF 1 "input_operand" "r,m,r"))]
     "TARGET_SPE"
     "@
      evstdd%X0 %1,%y0
      evldd%X1 %0,%y1
!    evor %0,%1,%1"
!   [(set_attr "type" "vecload,vecload,vecsimple")])

   (define_insn "spe_evmwhssfaa"
     [(set (match_operand:V2SI 0 "gpc_reg_operand" "=r")
--- 2222,2237 ----
     "{ rs6000_emit_move (operands[0], operands[1], V2SFmode); DONE; }")

   (define_insn "*movv2sf_internal"
!   [(set (match_operand:V2SF 0 "nonimmediate_operand" "=m,r,r,r")
! 	(match_operand:V2SF 1 "input_operand" "r,m,r,W"))]
     "TARGET_SPE"
     "@
      evstdd%X0 %1,%y0
      evldd%X1 %0,%y1
!    evor %0,%1,%1
!    evxor %0,%0,%0"
!   [(set_attr "type" "vecload,vecstore,*,*")
!    (set_attr "length" "*,*,*,*")])

   (define_insn "spe_evmwhssfaa"
     [(set (match_operand:V2SI 0 "gpc_reg_operand" "=r")



More information about the Gcc-patches mailing list