The attached patch optimizes
      __result_f = __builtin_powif (-1.0e+0, k);
to
  powi_cond_4 = k_1(D) & 1;
  powi_5 = powi_cond_4 ? -1.0e+0 : 1.0e+0;

I did an all-language (all,ada,go,objc++) bootstrap and regtest on x86-64-gnu-linux.
OK for the trunk?


Additionally, I would like to thank Thomas, who tried several approaches (e.g. fold_builtin_powi - which turned out to failed when called during optimization time, as regimplifing had problems with the COND_EXPR) and paved the way for this patch. And to Jakub, who gave helpful hints.

Note: Other replacements are also possible, e.g. "1.0 - (float) ((k & 1) << 1)". However, the condition above turned out to be fasted as Jakub expected and Thomas has tested (see PR).


Tobias
2013-05-30  Tobias Brusnu  <bur...@net-b.de>

	PR middle-end/57073
	* tree-ssa-math-opts.c (execute_cse_sincos): Optimize
	powi (-1.0, k) to (k & 1) ? -1.0 : 1.0.

2013-05-30  Tobias Brusnu  <bur...@net-b.de>

	PR middle-end/57073
	* gfortran.dg/power_6.f90: New.

diff --git a/gcc/testsuite/gfortran.dg/power_6.f90 b/gcc/testsuite/gfortran.dg/power_6.f90
new file mode 100644
index 0000000..65d1bd0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/power_6.f90
@@ -0,0 +1,15 @@
+! { dg-do compile }
+! { dg-options "-O1 -fdump-tree-optimized" }
+!
+! PR middle-end/57073
+! See also PR 57073
+!
+real function f(k)
+  integer, value :: k
+  f = (-1.0)**k
+end
+
+! { dg-final { scan-tree-dump-not "__builtin_powif"  "optimized" } }
+! { dg-final { scan-tree-dump "powi_cond_\[0-9\] = k_\[0-9\]\\(D\\) & 1;"  "optimized" } }
+! { dg-final { scan-tree-dump "powi_\[0-9\] = powi_cond_\[0-9\] \\? -1.0e\\+0 : 1.0e\\+0;"  "optimized" } }
+! { dg-final { cleanup-tree-dump "optimized" } }
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index a94172d..a15c404 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -1445,12 +1445,43 @@ execute_cse_sincos (void)
 		CASE_FLT_FN (BUILT_IN_POWI):
 		  arg0 = gimple_call_arg (stmt, 0);
 		  arg1 = gimple_call_arg (stmt, 1);
-		  if (!host_integerp (arg1, 0))
-		    break;
-
-		  n = TREE_INT_CST_LOW (arg1);
 		  loc = gimple_location (stmt);
-		  result = gimple_expand_builtin_powi (&gsi, loc, arg0, n);
+
+		  if (real_minus_onep (arg0)
+		      && TREE_CODE (TREE_TYPE (arg1)) == INTEGER_TYPE
+		      && !host_integerp (arg1,0))
+		    {
+                      tree t0, t1, cond, one, minus_one;
+		      gimple stmt;
+
+		      t0 = TREE_TYPE (arg0);
+		      t1 = TREE_TYPE (arg1);
+		      one = build_real (t0, dconst1);
+		      minus_one = build_real (t0, dconstm1);
+
+		      cond = make_temp_ssa_name (t1, NULL, "powi_cond");
+		      stmt = gimple_build_assign_with_ops (BIT_AND_EXPR, cond,
+							   arg1,
+							   build_int_cst (t1,
+									  1));
+		      gimple_set_location (stmt, loc);
+		      gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
+
+		      result = make_temp_ssa_name (t0, NULL, "powi");
+		      stmt = gimple_build_assign_with_ops (COND_EXPR, result,
+							   cond,
+							   minus_one, one);
+		      gimple_set_location (stmt, loc);
+		      gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
+		    }
+		  else
+		    {
+		      if (!host_integerp (arg1, 0))
+			break;
+
+		      n = TREE_INT_CST_LOW (arg1);
+		      result = gimple_expand_builtin_powi (&gsi, loc, arg0, n);
+		    }
 
 		  if (result)
 		    {

Reply via email to