Hello,

canonicalizing x+x to x*2 made us regress some vectorization tests on sparc. As suggested by Richard, this lets the vectorizer handle x*2 as x+x if that helps. Let me copy a few remarks I had in the PR:

« We could probably also handle x*3 as x+x+x, but where to stop?

I don't understand why the optab test for LSHIFT_EXPR was using optab_vector, as far as I understand we are creating vec<<3, so optab_scalar makes more sense.

I gave priority to x+x over x<<1, not sure if that's right, it probably doesn't matter much as one will probably be turned into the other in later passes. »

Rainer bootstrapped and regtested the patch on sparc. As a bonus, it now vectorizes one more loop in gcc.dg/vect/vect-iv-9.c, I'll let someone else tweak the test (which will temporarily appear as a FAIL).

2016-06-13  Marc Glisse  <marc.gli...@inria.fr>

        PR tree-optimization/70923
        * tree-vect-patterns.c (vect_recog_mult_pattern): Use optab_scalar
        for LSHIFT_EXPR. Handle 2 * X as X + X.

--
Marc Glisse
Index: gcc/tree-vect-patterns.c
===================================================================
*** gcc/tree-vect-patterns.c	(revision 237336)
--- gcc/tree-vect-patterns.c	(working copy)
*************** vect_recog_vector_vector_shift_pattern (
*** 2166,2189 ****
  
    * Return value: A new stmt that will be used to replace the multiplication
      S1 or S2 stmt.  */
  
  static gimple *
  vect_recog_mult_pattern (vec<gimple *> *stmts,
  			 tree *type_in, tree *type_out)
  {
    gimple *last_stmt = stmts->pop ();
    tree oprnd0, oprnd1, vectype, itype;
!   gimple *pattern_stmt, *def_stmt;
    optab optab;
    stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt);
!   int power2_val, power2_neg_val;
    tree shift;
  
    if (!is_gimple_assign (last_stmt))
      return NULL;
  
    if (gimple_assign_rhs_code (last_stmt) != MULT_EXPR)
      return NULL;
  
    oprnd0 = gimple_assign_rhs1 (last_stmt);
    oprnd1 = gimple_assign_rhs2 (last_stmt);
--- 2166,2189 ----
  
    * Return value: A new stmt that will be used to replace the multiplication
      S1 or S2 stmt.  */
  
  static gimple *
  vect_recog_mult_pattern (vec<gimple *> *stmts,
  			 tree *type_in, tree *type_out)
  {
    gimple *last_stmt = stmts->pop ();
    tree oprnd0, oprnd1, vectype, itype;
!   gimple *pattern_stmt;
    optab optab;
    stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt);
!   int power2_val;
    tree shift;
  
    if (!is_gimple_assign (last_stmt))
      return NULL;
  
    if (gimple_assign_rhs_code (last_stmt) != MULT_EXPR)
      return NULL;
  
    oprnd0 = gimple_assign_rhs1 (last_stmt);
    oprnd1 = gimple_assign_rhs2 (last_stmt);
*************** vect_recog_mult_pattern (vec<gimple *> *
*** 2203,2261 ****
       don't attempt to optimize this.  */
    optab = optab_for_tree_code (MULT_EXPR, vectype, optab_default);
    if (optab != unknown_optab)
      {
        machine_mode vec_mode = TYPE_MODE (vectype);
        int icode = (int) optab_handler (optab, vec_mode);
        if (icode != CODE_FOR_nothing)
  	return NULL;
      }
  
!   /* If target cannot handle vector left shift then we cannot
!      optimize and bail out.  */
!   optab = optab_for_tree_code (LSHIFT_EXPR, vectype, optab_vector);
!   if (!optab
!       || optab_handler (optab, TYPE_MODE (vectype)) == CODE_FOR_nothing)
!     return NULL;
! 
!   power2_val = wi::exact_log2 (oprnd1);
!   power2_neg_val = wi::exact_log2 (wi::neg (oprnd1));
  
!   /* Handle constant operands that are postive or negative powers of 2.  */
!   if (power2_val != -1)
!     {
!       shift = build_int_cst (itype, power2_val);
!       pattern_stmt
! 	= gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL),
! 			       LSHIFT_EXPR, oprnd0, shift);
!     }
!   else if (power2_neg_val != -1)
      {
        /* If the target cannot handle vector NEGATE then we cannot
  	 do the optimization.  */
!       optab = optab_for_tree_code (NEGATE_EXPR, vectype, optab_vector);
        if (!optab
  	  || optab_handler (optab, TYPE_MODE (vectype)) == CODE_FOR_nothing)
  	return NULL;
  
!       shift = build_int_cst (itype, power2_neg_val);
!       def_stmt
  	= gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL),
! 			       LSHIFT_EXPR, oprnd0, shift);
!       new_pattern_def_seq (stmt_vinfo, def_stmt);
        pattern_stmt
! 	 = gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL),
! 				NEGATE_EXPR, gimple_assign_lhs (def_stmt));
      }
    else
      return NULL;
  
    /* Pattern detected.  */
    if (dump_enabled_p ())
      dump_printf_loc (MSG_NOTE, vect_location,
  		     "vect_recog_mult_pattern: detected:\n");
  
    if (dump_enabled_p ())
      dump_gimple_stmt_loc (MSG_NOTE, vect_location, TDF_SLIM,
  			  pattern_stmt,0);
  
    stmts->safe_push (last_stmt);
--- 2203,2271 ----
       don't attempt to optimize this.  */
    optab = optab_for_tree_code (MULT_EXPR, vectype, optab_default);
    if (optab != unknown_optab)
      {
        machine_mode vec_mode = TYPE_MODE (vectype);
        int icode = (int) optab_handler (optab, vec_mode);
        if (icode != CODE_FOR_nothing)
  	return NULL;
      }
  
!   bool negate = wi::neg_p (oprnd1, TYPE_SIGN (TREE_TYPE (oprnd1)));
  
!   if (negate)
      {
        /* If the target cannot handle vector NEGATE then we cannot
  	 do the optimization.  */
!       optab = optab_for_tree_code (NEGATE_EXPR, vectype, optab_default);
        if (!optab
  	  || optab_handler (optab, TYPE_MODE (vectype)) == CODE_FOR_nothing)
  	return NULL;
+       power2_val = wi::exact_log2 (wi::neg (oprnd1));
+     }
+   else
+     {
+       power2_val = wi::exact_log2 (oprnd1);
+     }
  
!   /* Handle constant operands +-2 if target can handle vector addition.  */
!   if (power2_val == 1
!       && (optab = optab_for_tree_code (PLUS_EXPR, vectype, optab_default))
!       && optab_handler (optab, TYPE_MODE (vectype)) != CODE_FOR_nothing)
!     {
!       pattern_stmt
  	= gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL),
! 			       PLUS_EXPR, oprnd0, oprnd0);
!     }
!   /* Handle constant operands that are positive or negative powers of 2
!      if target can handle vector left shift.  */
!   else if (power2_val != -1
! 	   && (optab = optab_for_tree_code (LSHIFT_EXPR, vectype, optab_scalar))
! 	   && optab_handler (optab, TYPE_MODE (vectype)) != CODE_FOR_nothing)
!     {
!       shift = build_int_cst (itype, power2_val);
        pattern_stmt
! 	= gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL),
! 			       LSHIFT_EXPR, oprnd0, shift);
      }
    else
      return NULL;
  
+   if (negate)
+     {
+       tree tmp_var = gimple_assign_lhs (pattern_stmt);
+       new_pattern_def_seq (stmt_vinfo, pattern_stmt);
+       pattern_stmt
+ 	 = gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL),
+ 				NEGATE_EXPR, tmp_var);
+     }
+ 
    /* Pattern detected.  */
    if (dump_enabled_p ())
      dump_printf_loc (MSG_NOTE, vect_location,
  		     "vect_recog_mult_pattern: detected:\n");
  
    if (dump_enabled_p ())
      dump_gimple_stmt_loc (MSG_NOTE, vect_location, TDF_SLIM,
  			  pattern_stmt,0);
  
    stmts->safe_push (last_stmt);

Reply via email to