[PATCH] PowerPC vec_init, vec_set, vec_extract (PR target/18506)

David Edelsohn dje@watson.ibm.com
Tue Jul 26 19:18:00 GMT 2005


	Appended is an initial implementation of the GCC vec_init,
vec_set, and vec_extract patterns for Altivec.  V4SFmode is not supported
in this version.

	There are lots of other Altivec tricks with greater or lesser
degrees of benefit.  I am not looking for comments that method X should be
implemented as well.

	I am interested in feedback about the algorithms that are
implemented in the patch, especially whether vec_set is beneficial.

Thanks, David


	PR target/18506
	* config/rs6000/altivec.md (vec_init<mode>): New.
	(vec_set<mode>): New.
	(vec_extract<mode>): New.
	* config/rs6000/rs6000.c (rs6000_expand_vector_init): New.
	(rs6000_expand_vector_set): New.
	(rs6000_expand_vector_extract): New.
	* config/rs6000/rs6000-protos.h: Declare new functions.

Index: altivec.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/altivec.md,v
retrieving revision 1.40
diff -c -p -r1.40 altivec.md
*** altivec.md	25 Jun 2005 01:22:05 -0000	1.40
--- altivec.md	26 Jul 2005 17:37:34 -0000
***************
*** 1771,1776 ****
--- 1771,1845 ----
    "stve<VI_char>x %1,%y0"
    [(set_attr "type" "vecstore")])
  
+ (define_expand "vec_init<mode>"
+   [(match_operand:VI 0 "register_operand" "")
+    (match_operand 1 "" "")]
+   "TARGET_ALTIVEC"
+ {
+   rs6000_expand_vector_init (operands[0], operands[1]);
+   DONE;
+ })
+ 
+ (define_expand "vec_setv4si"
+   [(match_operand:V4SI 0 "register_operand" "")
+    (match_operand:SI 1 "register_operand" "")
+    (match_operand 2 "const_int_operand" "")]
+   "TARGET_ALTIVEC"
+ {
+   rs6000_expand_vector_set (operands[0], operands[1], INTVAL (operands[2]));
+   DONE;
+ })
+ 
+ (define_expand "vec_setv8hi"
+   [(match_operand:V8HI 0 "register_operand" "")
+    (match_operand:HI 1 "register_operand" "")
+    (match_operand 2 "const_int_operand" "")]
+   "TARGET_ALTIVEC"
+ {
+   rs6000_expand_vector_set (operands[0], operands[1], INTVAL (operands[2]));
+   DONE;
+ })
+ 
+ (define_expand "vec_setv16qii"
+   [(match_operand:V16QI 0 "register_operand" "")
+    (match_operand:QI 1 "register_operand" "")
+    (match_operand 2 "const_int_operand" "")]
+   "TARGET_ALTIVEC"
+ {
+   rs6000_expand_vector_set (operands[0], operands[1], INTVAL (operands[2]));
+   DONE;
+ })
+ 
+ (define_expand "vec_extractv4si"
+   [(match_operand:SI 0 "register_operand" "")
+    (match_operand:V4SI 1 "register_operand" "")
+    (match_operand 2 "const_int_operand" "")]
+   "TARGET_ALTIVEC"
+ {
+   rs6000_expand_vector_extract (operands[0], operands[1], INTVAL (operands[2]));
+   DONE;
+ })
+ 
+ (define_expand "vec_extractv8hi"
+   [(match_operand:HI 0 "register_operand" "")
+    (match_operand:V8HI 1 "register_operand" "")
+    (match_operand 2 "const_int_operand" "")]
+   "TARGET_ALTIVEC"
+ {
+   rs6000_expand_vector_extract (operands[0], operands[1], INTVAL (operands[2]));
+   DONE;
+ })
+ 
+ (define_expand "vec_extractv16qi"
+   [(match_operand:QI 0 "register_operand" "")
+    (match_operand:V16QI 1 "register_operand" "")
+    (match_operand 2 "const_int_operand" "")]
+   "TARGET_ALTIVEC"
+ {
+   rs6000_expand_vector_extract (operands[0], operands[1], INTVAL (operands[2]));
+   DONE;
+ })
+ 
  ;; Generate
  ;;    vspltis? SCRATCH0,0
  ;;    vsubu?m SCRATCH2,SCRATCH1,%1
Index: rs6000-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.104
diff -c -p -r1.104 rs6000-protos.h
*** rs6000-protos.h	15 Jul 2005 01:44:38 -0000	1.104
--- rs6000-protos.h	26 Jul 2005 17:37:34 -0000
*************** extern rtx rs6000_got_register (rtx);
*** 50,55 ****
--- 50,58 ----
  extern rtx find_addr_reg (rtx);
  extern rtx gen_easy_vector_constant_add_self (rtx);
  extern const char *output_vec_const_move (rtx *);
+ extern void rs6000_expand_vector_init (rtx, rtx);
+ extern void rs6000_expand_vector_set (rtx, rtx, int);
+ extern void rs6000_expand_vector_extract (rtx, rtx, int);
  extern void build_mask64_2_operands (rtx, rtx *);
  extern int expand_block_clear (rtx[]);
  extern int expand_block_move (rtx[]);
Index: rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.855
diff -c -p -r1.855 rs6000.c
*** rs6000.c	15 Jul 2005 01:44:35 -0000	1.855
--- rs6000.c	26 Jul 2005 17:37:35 -0000
*************** output_vec_const_move (rtx *operands)
*** 2179,2184 ****
--- 2179,2348 ----
      return "li %0,%1\n\tevmergelo %0,%0,%0\n\tli %0,%2";
  }
  
+ /* Initialize vector TARGET to VALS.  */
+ 
+ void
+ rs6000_expand_vector_init (rtx target, rtx vals)
+ {
+   enum machine_mode mode = GET_MODE (target);
+   enum machine_mode inner_mode = GET_MODE_INNER (mode);
+   int n_elts = GET_MODE_NUNITS (mode);
+   int n_var = 0, one_var = -1;
+   bool all_same = true, all_const_zero = true;
+   rtx x, mem;
+   int i;
+ 
+   for (i = 0; i < n_elts; ++i)
+     {
+       x = XVECEXP (vals, 0, i);
+       if (!CONSTANT_P (x))
+ 	++n_var, one_var = i;
+       else if (x != CONST0_RTX (inner_mode))
+ 	all_const_zero = false;
+ 
+       if (i > 0 && !rtx_equal_p (x, XVECEXP (vals, 0, 0)))
+ 	all_same = false;
+     }
+ 
+   if (n_var == 0)
+     {
+       if (all_const_zero)
+ 	{
+ 	  /* Zero register.  */
+ 	  emit_insn (gen_rtx_SET (VOIDmode, target,
+ 				  gen_rtx_XOR (mode, target, target)));
+ 	  return;
+ 	}
+       else if (easy_vector_same (vals, mode))
+ 	{
+ 	  /* Splat immediate.  */
+ 	  x = gen_rtx_VEC_DUPLICATE (mode, CONST_VECTOR_ELT (vals, 0));
+ 	  emit_insn (gen_rtx_SET (VOIDmode, target, x));
+ 	  return;
+ 	}
+       else if (all_same)
+ 	;	/* Splat vector element.  */
+       else
+ 	{
+ 	  /* Load from constant pool.  */
+ 	  emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0)));
+ 	  return;
+ 	}
+     }
+ 
+   /* Store value to stack temp.  Load vector element.  Splat.  */
+   if (all_same)
+     {
+       mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode), 0);
+       emit_move_insn (change_address (mem, inner_mode, NULL),
+ 		      XVECEXP (vals, 0, 0));
+       x = gen_rtx_UNSPEC (VOIDmode,
+ 			  gen_rtvec (1, const0_rtx), 196);
+       emit_insn (gen_rtx_PARALLEL (VOIDmode,
+ 				   gen_rtvec (2,
+ 					      gen_rtx_SET (VOIDmode,
+ 							   target, mem),
+ 					      x)));
+       x = gen_rtx_VEC_SELECT (inner_mode, target,
+ 			      gen_rtx_PARALLEL (VOIDmode,
+ 						gen_rtvec (1, const0_rtx)));
+       emit_insn (gen_rtx_SET (VOIDmode, target,
+ 			      gen_rtx_VEC_DUPLICATE (mode, x)));
+       return;
+     }
+ 
+   /* One field is non-constant.  Load constant then overwrite
+      varying field.  */
+   if (n_var == 1)
+     {
+       rtx copy = copy_rtx (vals);
+ 
+       /* Load constant part of vector, substititute neighboring value for
+ 	 varying element.  */
+       XVECEXP (copy, 0, one_var) = XVECEXP (vals, 0, (one_var + 1) % n_elts);
+       rs6000_expand_vector_init (target, copy);
+ 
+       /* Insert variable.  */
+       rs6000_expand_vector_set (target, XVECEXP (vals, 0, one_var), one_var);
+       return;
+     }
+ 
+   /* Construct the vector in memory one field at a time
+      and load the whole vector.  */
+   mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
+   for (i = 0; i < n_elts; i++)
+     emit_move_insn (adjust_address (mem, inner_mode,
+ 				    i * GET_MODE_SIZE (inner_mode)),
+ 		    XVECEXP (vals, 0, i));
+   emit_move_insn (target, mem);
+ }
+ 
+ /* Set field ELT of TARGET to VAL.  */
+ 
+ void
+ rs6000_expand_vector_set (rtx target, rtx val, int elt)
+ {
+   enum machine_mode mode = GET_MODE (target);
+   enum machine_mode inner_mode = GET_MODE_INNER (mode);
+   rtx reg = gen_reg_rtx (mode);
+   rtx mask, mem, x;
+   int width = GET_MODE_SIZE (inner_mode);
+   int i;
+ 
+   /* Load single variable value.  */
+   mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode), 0);
+   emit_move_insn (change_address (mem, inner_mode, NULL), val);
+   x = gen_rtx_UNSPEC (VOIDmode,
+ 		      gen_rtvec (1, const0_rtx), 196);
+   emit_insn (gen_rtx_PARALLEL (VOIDmode,
+ 			       gen_rtvec (2,
+ 					  gen_rtx_SET (VOIDmode,
+ 						       reg, mem),
+ 					  x)));
+ 
+   /* Linear sequence.  */
+   mask = gen_rtx_PARALLEL (V16QImode, rtvec_alloc (16));
+   for (i = 0; i < 16; ++i)
+     XVECEXP (mask, 0, i) = GEN_INT (i);
+ 
+   /* Set permute mask to insert element into target.  */
+   for (i = 0; i < width; ++i)
+     XVECEXP (mask, 0, elt*width + i)
+       = GEN_INT (i + 0x10);
+   x = gen_rtx_CONST_VECTOR (V16QImode, XVEC (mask, 0));
+   x = gen_rtx_UNSPEC (mode,
+ 		      gen_rtvec (3, target, reg,
+ 				 force_reg (V16QImode, x)),
+ 		      144);
+   emit_insn (gen_rtx_SET (VOIDmode, target, x));
+ }
+ 
+ /* Extract field ELT from VEC into TARGET.  */
+ 
+ void
+ rs6000_expand_vector_extract (rtx target, rtx vec, int elt)
+ {
+   enum machine_mode mode = GET_MODE (vec);
+   enum machine_mode inner_mode = GET_MODE_INNER (mode);
+   rtx mem, x;
+ 
+   /* Allocate mode-sized buffer.  */
+   mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
+ 
+   /* Add offset to field within buffer matching vector element.  */
+   mem = adjust_address (mem, mode, elt * GET_MODE_SIZE (inner_mode));
+ 
+   /* Store single field into mode-sized buffer.  */
+   x = gen_rtx_UNSPEC (VOIDmode,
+ 		      gen_rtvec (1, const0_rtx), 203);
+   emit_insn (gen_rtx_PARALLEL (VOIDmode,
+ 			       gen_rtvec (2,
+ 					  gen_rtx_SET (VOIDmode,
+ 						       mem, vec),
+ 					  x)));
+   emit_move_insn (target, change_address (mem, inner_mode, NULL));
+ }
+ 
  int
  mask64_1or2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED,
  		       bool allow_one)



More information about the Gcc-patches mailing list