This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFH] subreg of a vector without going through memory


On Mon, 5 Nov 2012, Richard Sandiford wrote:

Marc Glisse <marc.glisse@inria.fr> writes:
* simplify-rtx.c (simplify_subreg): For vectors, create a VEC_SELECT.

Probably not helpful, sorry, but a subreg->vec_select transformation feels like it's going in the wrong direction. Going from vec_select to subreg would be OK from a "layering" perspective (although whether it's a good idea or not is another question), but not the other way. E.g. we convert can convert truncate to subreg, but should never convert subreg to truncate.

Thanks, it is helpful to know what the right direction is supposed to be :-)


One problem is that subregs can be lvalues as well as rvalues,
whereas vec_select is always an rvalue.

Hmm indeed. Not sure how to test that.


Also, it's invalid to form a non-lowpart subreg of a word or subword register, so having general vec_select handling feels like it's coping with input that ought to be rejected with a null return.

Ah, even if it was the right direction, I should limit it to memory and registers larger than a word, ok.



So if I understand you, the x86 back-end is missing define_insns for movs of subregs. And I should duplicate in simplify_subreg any code from simplify_binary_operation(VEC_SELECT,...) that might apply. And maybe add code that recognizes when a VEC_SELECT could be a SUBREG, but maybe not.


(this other patch I was writing (untested) sounds less useful then, I'll just attach it here so it doesn't get lost)

Well, I guess there are worse issues with vectors to handle first, as can be seen when compiling this for SSE2, which produces no less than 36 mov instructions :-(

typedef double vec4 __attribute__((vector_size(32)));

void f(vec4*x){
  *x+=*x**x;
}

Good thing next stage1 is far away, I am getting way too confused...

--
Marc Glisse
*** /data/repos/gcc/pristine/gcc/simplify-rtx.c	2012-11-03 19:59:03.541603422 +0100
--- simplify-rtx.c	2012-11-05 12:35:15.843396247 +0100
*************** simplify_binary_operation_1 (enum rtx_co
*** 3485,3528 ****
  	      rtx subop0, subop1;
  
  	      gcc_assert (i0 < 2 && i1 < 2);
  	      subop0 = XEXP (trueop0, i0);
  	      subop1 = XEXP (trueop0, i1);
  
  	      return simplify_gen_binary (VEC_CONCAT, mode, subop0, subop1);
  	    }
  	}
  
!       if (XVECLEN (trueop1, 0) == 1
! 	  && CONST_INT_P (XVECEXP (trueop1, 0, 0))
! 	  && GET_CODE (trueop0) == VEC_CONCAT)
  	{
! 	  rtx vec = trueop0;
! 	  int offset = INTVAL (XVECEXP (trueop1, 0, 0)) * GET_MODE_SIZE (mode);
  
! 	  /* Try to find the element in the VEC_CONCAT.  */
! 	  while (GET_MODE (vec) != mode
! 		 && GET_CODE (vec) == VEC_CONCAT)
  	    {
! 	      HOST_WIDE_INT vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0)));
! 	      if (offset < vec_size)
! 		vec = XEXP (vec, 0);
  	      else
  		{
! 		  offset -= vec_size;
! 		  vec = XEXP (vec, 1);
  		}
! 	      vec = avoid_constant_pool_reference (vec);
  	    }
  
! 	  if (GET_MODE (vec) == mode)
! 	    return vec;
  	}
  
        return 0;
      case VEC_CONCAT:
        {
  	enum machine_mode op0_mode = (GET_MODE (trueop0) != VOIDmode
  				      ? GET_MODE (trueop0)
  				      : GET_MODE_INNER (mode));
  	enum machine_mode op1_mode = (GET_MODE (trueop1) != VOIDmode
  				      ? GET_MODE (trueop1)
--- 3485,3562 ----
  	      rtx subop0, subop1;
  
  	      gcc_assert (i0 < 2 && i1 < 2);
  	      subop0 = XEXP (trueop0, i0);
  	      subop1 = XEXP (trueop0, i1);
  
  	      return simplify_gen_binary (VEC_CONCAT, mode, subop0, subop1);
  	    }
  	}
  
!       /* Detect if all the elements come from the same subpart of a concat.  */
!       if (GET_CODE (trueop0) == VEC_CONCAT)
  	{
! 	  rtx new_op0 = NULL_RTX;
! 	  rtx new_op1 = NULL_RTX;
! 	  int first = 0;
! 	  int second = 0;
! 	  unsigned nelts_first_half = 1;
! 	  if (VECTOR_MODE_P (GET_CODE (trueop0)))
! 	    {
! 	      rtx first_half = XEXP (trueop0, 0);
! 	      enum machine_mode mode0 = GET_MODE (first_half);
! 	      int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode0));
! 	      nelts_first_half = (GET_MODE_SIZE (mode0) / elt_size);
! 	    }
  
! 	  for (int i = 0; i < XVECLEN (trueop1, 0); i++)
  	    {
! 	      rtx j = XVECEXP (trueop1, 0, i);
! 	      if (!CONST_INT_P (j))
! 		{
! 		  first++;
! 		  second++;
! 		  break;
! 		}
! 	      if (INTVAL (j) < nelts_first_half)
! 		first++;
  	      else
+ 		second++;
+ 	    }
+ 
+ 	  if (second == 0)
+ 	    {
+ 	      new_op0 = XEXP (trueop0, 0);
+ 	      new_op1 = trueop1;
+ 	    }
+ 	  else if (first == 0)
+ 	    {
+ 	      int len = XVECLEN (trueop1, 0);
+ 	      rtvec vec = rtvec_alloc (len);
+ 	      for (int i = 0; i < len; i++)
  		{
! 		  int j = INTVAL (XVECEXP (trueop1, 0, i)) - nelts_first_half;
! 		  RTVEC_ELT (vec, i) = GEN_INT (j);
  		}
! 	      new_op0 = XEXP (trueop0, 1);
! 	      new_op1 = gen_rtx_PARALLEL (VOIDmode, vec);
  	    }
  
! 	  if (new_op0)
! 	    {
! 	      if (VECTOR_MODE_P (GET_CODE (new_op0)))
! 		return simplify_gen_binary (VEC_SELECT, mode, new_op0, new_op1);
! 	      if (VECTOR_MODE_P (mode))
! 		return simplify_gen_unary (VEC_DUPLICATE, mode, new_op0,
! 					   GET_MODE (new_op0));
! 	      return new_op0;
! 	    }
  	}
  
        return 0;
      case VEC_CONCAT:
        {
  	enum machine_mode op0_mode = (GET_MODE (trueop0) != VOIDmode
  				      ? GET_MODE (trueop0)
  				      : GET_MODE_INNER (mode));
  	enum machine_mode op1_mode = (GET_MODE (trueop1) != VOIDmode
  				      ? GET_MODE (trueop1)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]