# [PATCH][RFC] Do some vectorizer-friendly canonicalization before vectorization

Richard Guenther rguenther@suse.de
Mon Nov 20 16:53:00 GMT 2006

```Currently, especially with -funsafe-math-optimizations, we pessimize
vectorization by canonicalizing multiplications to calls to pow ().
This patch addresses this by doing a different canonicalization (or
tree-level expansion dependent on how you view this) before
vectorization.

This is a simple prototype hooked into the vectorizer and only
transforming loop bodies.  The only transformations implemented
for this are pow (x, 2) to x * x and pow (x, 0.5) to sqrt (x) because
both x * x and sqrt (x) are easy to vectorize.

Does this look like a reasonable approach?

Thanks,
Richard.

--
Richard Guenther <rguenther@suse.de>
Novell / SUSE Labs

2006-11-20  Richard Guenther  <rguenther@suse.de>

* tree-vectorizer.c (maybe_replace_pow_expr): New static
helper.
(vect_prepare_loop): New function.
(vectorize_loops): Call vect_prepare_loop to canonicalize
some statements in a vectorizer friendly manner.

Index: tree-vectorizer.c
===================================================================
*** tree-vectorizer.c	(revision 119010)
--- tree-vectorizer.c	(working copy)
*************** vect_is_simple_iv_evolution (unsigned lo
*** 2141,2146 ****
--- 2141,2220 ----
return true;
}

+ /* Replace a pow or powi expression by multiplication and/or sqrt.
+    This basically does pow expansion on trees.  */
+
+ static void
+ maybe_replace_pow_expr (block_stmt_iterator *bsi)
+ {
+   tree stmt = bsi_stmt (*bsi);
+   tree fn = get_callee_fndecl (TREE_OPERAND (stmt, 1));
+   tree arglist = TREE_OPERAND (TREE_OPERAND (stmt, 1), 1);
+   tree base = TREE_VALUE (arglist);
+   tree exp = TREE_VALUE (TREE_CHAIN (arglist));
+
+   /* Catch squaring.  */
+   if ((host_integerp (exp, 0)
+        && TREE_INT_CST_LOW (exp) == 2)
+       || (TREE_CODE (exp) == REAL_CST
+ 	  && REAL_VALUES_EQUAL (TREE_REAL_CST (exp), dconst2)))
+     {
+       TREE_OPERAND (stmt, 1) = build2 (MULT_EXPR, TREE_TYPE (base),
+ 				       base, base);
+       return;
+     }
+
+   /* Catch square root.  */
+   if (TREE_CODE (exp) == REAL_CST
+       && REAL_VALUES_EQUAL (TREE_REAL_CST (exp), dconsthalf))
+     {
+       tree newfn = mathfn_built_in (TREE_TYPE (base), BUILT_IN_SQRT);
+       tree newarglist = build_tree_list (NULL_TREE, base);
+       TREE_OPERAND (stmt, 1) = build_function_call_expr (newfn, newarglist);
+       return;
+     }
+
+   /* TODO: Catch stuff that requires flag_unsafe_math_optimizations.  */
+ }
+
+ /* Prepare LOOP for vectorizer analysis by transforming harder
+    to vectorize statements into easier ones.  */
+
+ static void
+ vect_prepare_loop (struct loop *loop)
+ {
+   basic_block *bbs = get_loop_body (loop);
+   unsigned i;
+
+   for (i = 0; i < loop->num_nodes; ++i)
+     {
+       block_stmt_iterator bsi;
+
+       for (bsi = bsi_start (bbs[i]); !bsi_end_p (bsi); bsi_next (&bsi))
+ 	{
+ 	  tree fn, arglist;
+ 	  tree stmt = bsi_stmt (bsi);
+
+ 	  /* We only care about calls and math.  */
+ 	  if (TREE_CODE (stmt) != MODIFY_EXPR
+ 	      || TREE_CODE (TREE_OPERAND (stmt, 1)) != CALL_EXPR)
+ 	    continue;
+
+ 	  fn = get_callee_fndecl (TREE_OPERAND (stmt, 1));
+ 	  arglist = TREE_OPERAND (TREE_OPERAND (stmt, 1), 1);
+ 	  switch (DECL_FUNCTION_CODE (fn))
+ 	    {
+ 	    case BUILT_IN_POWF:
+ 	    case BUILT_IN_POW:
+ 	      if (TREE_CODE (TREE_VALUE (TREE_CHAIN (arglist))) == REAL_CST
+ 		  || TREE_CODE (TREE_VALUE (TREE_CHAIN (arglist))) == INTEGER_CST)
+ 		maybe_replace_pow_expr (&bsi);
+
+ 	    default:;
+ 	    }
+ 	}
+     }
+ }

/* Function vectorize_loops.

*************** vectorize_loops (struct loops *loops)
*** 2174,2179 ****
--- 2248,2254 ----
continue;

vect_loop_location = find_loop_location (loop);
+       vect_prepare_loop (loop);
loop_vinfo = vect_analyze_loop (loop);
loop->aux = loop_vinfo;

```