re PR middle-end/19706 (Recognize common Fortran usages of copysign.)
authorTamar Christina <tamar.christina@arm.com>
Tue, 8 Aug 2017 13:15:44 +0000 (13:15 +0000)
committerTamar Christina <tnfchris@gcc.gnu.org>
Tue, 8 Aug 2017 13:15:44 +0000 (13:15 +0000)
2017-08-08  Tamar Christina  <tamar.christina@arm.com>
    Andrew Pinski <pinskia@gmail.com>

PR middle-end/19706
* internal-fn.def (XORSIGN): New.
* optabs.def (xorsign_optab): New.
* tree-ssa-math-opts.c (is_copysign_call_with_1): New.
(convert_expand_mult_copysign): New.
(pass_optimize_widening_mul::execute): Call convert_expand_mult_copysign.

Co-Authored-By: Andrew Pinski <pinskia@gmail.com>
From-SVN: r250956

gcc/ChangeLog
gcc/internal-fn.def
gcc/optabs.def
gcc/tree-ssa-math-opts.c

index 6051e8f50689c088f536522db707514e8ef7425f..5eef8e083be4a90a90ec6e2ed375e411fc79599c 100644 (file)
@@ -1,3 +1,13 @@
+2017-08-08  Tamar Christina  <tamar.christina@arm.com>
+           Andrew Pinski <pinskia@gmail.com>
+
+       PR middle-end/19706
+       * internal-fn.def (XORSIGN): New.
+       * optabs.def (xorsign_optab): New.
+       * tree-ssa-math-opts.c (is_copysign_call_with_1): New.
+       (convert_expand_mult_copysign): New.
+       (pass_optimize_widening_mul::execute): Call convert_expand_mult_copysign.
+
 2017-08-08  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
 
        PR tree-optimization/81354
index a9a3f7606eb2a79f64dab1b7fdeef0d308e3061d..b1211159845f07faa60c3daf527bffcf485af768 100644 (file)
@@ -129,6 +129,7 @@ DEF_INTERNAL_FLT_FN (REMAINDER, ECF_CONST, remainder, binary)
 DEF_INTERNAL_FLT_FN (SCALB, ECF_CONST, scalb, binary)
 DEF_INTERNAL_FLT_FN (FMIN, ECF_CONST, fmin, binary)
 DEF_INTERNAL_FLT_FN (FMAX, ECF_CONST, fmax, binary)
+DEF_INTERNAL_OPTAB_FN (XORSIGN, ECF_CONST, xorsign, binary)
 
 /* FP scales.  */
 DEF_INTERNAL_FLT_FN (LDEXP, ECF_CONST, ldexp, binary)
index f21f2267ec2118d5cd0e74b18721525a564d16f2..54afe2d796ee9af3bd7b25d93eb0789a70e47c7b 100644 (file)
@@ -255,6 +255,7 @@ OPTAB_D (asin_optab, "asin$a2")
 OPTAB_D (atan2_optab, "atan2$a3")
 OPTAB_D (atan_optab, "atan$a2")
 OPTAB_D (copysign_optab, "copysign$F$a3")
+OPTAB_D (xorsign_optab, "xorsign$F$a3")
 OPTAB_D (cos_optab, "cos$a2")
 OPTAB_D (exp10_optab, "exp10$a2")
 OPTAB_D (exp2_optab, "exp2$a2")
index 7ac1659fa0670b7080685f3f9513939807073a63..87940b6e00db0d34a472504cf70923d1d334eccb 100644 (file)
@@ -3145,6 +3145,93 @@ is_widening_mult_p (gimple *stmt,
   return true;
 }
 
+/* Check to see if the CALL statement is an invocation of copysign
+   with 1. being the first argument.  */
+static bool
+is_copysign_call_with_1 (gimple *call)
+{
+  gcall *c = dyn_cast <gcall *> (call);
+  if (! c)
+    return false;
+
+  enum combined_fn code = gimple_call_combined_fn (c);
+
+  if (code == CFN_LAST)
+    return false;
+
+  if (builtin_fn_p (code))
+    {
+      switch (as_builtin_fn (code))
+       {
+       CASE_FLT_FN (BUILT_IN_COPYSIGN):
+       CASE_FLT_FN_FLOATN_NX (BUILT_IN_COPYSIGN):
+         return real_onep (gimple_call_arg (c, 0));
+       default:
+         return false;
+       }
+    }
+
+  if (internal_fn_p (code))
+    {
+      switch (as_internal_fn (code))
+       {
+       case IFN_COPYSIGN:
+         return real_onep (gimple_call_arg (c, 0));
+       default:
+         return false;
+       }
+    }
+
+   return false;
+}
+
+/* Try to expand the pattern x * copysign (1, y) into xorsign (x, y).
+   This only happens when the the xorsign optab is defined, if the
+   pattern is not a xorsign pattern or if expansion fails FALSE is
+   returned, otherwise TRUE is returned.  */
+static bool
+convert_expand_mult_copysign (gimple *stmt, gimple_stmt_iterator *gsi)
+{
+  tree treeop0, treeop1, lhs, type;
+  location_t loc = gimple_location (stmt);
+  lhs = gimple_assign_lhs (stmt);
+  treeop0 = gimple_assign_rhs1 (stmt);
+  treeop1 = gimple_assign_rhs2 (stmt);
+  type = TREE_TYPE (lhs);
+  machine_mode mode = TYPE_MODE (type);
+
+  if (HONOR_SNANS (type) || !has_single_use (lhs))
+    return false;
+
+  if (TREE_CODE (treeop0) == SSA_NAME && TREE_CODE (treeop1) == SSA_NAME)
+    {
+      gimple *call0 = SSA_NAME_DEF_STMT (treeop0);
+      if (!is_copysign_call_with_1 (call0))
+       {
+         call0 = SSA_NAME_DEF_STMT (treeop1);
+         if (!is_copysign_call_with_1 (call0))
+           return false;
+
+         treeop1 = treeop0;
+       }
+
+       if (optab_handler (xorsign_optab, mode) == CODE_FOR_nothing)
+         return false;
+
+       gcall *c = as_a<gcall*> (call0);
+       treeop0 = gimple_call_arg (c, 1);
+
+       gcall *call_stmt
+         = gimple_build_call_internal (IFN_XORSIGN, 2, treeop1, treeop0);
+       gimple_set_lhs (call_stmt, lhs);
+       gimple_set_location (call_stmt, loc);
+       gsi_replace (gsi, call_stmt, true);
+       return true;
+    }
+
+  return false;
+}
+
 /* Process a single gimple statement STMT, which has a MULT_EXPR as
    its rhs, and try to convert it into a WIDEN_MULT_EXPR.  The return
    value is true iff we converted the statement.  */
@@ -4114,6 +4201,7 @@ pass_optimize_widening_mul::execute (function *fun)
                {
                case MULT_EXPR:
                  if (!convert_mult_to_widen (stmt, &gsi)
+                     && !convert_expand_mult_copysign (stmt, &gsi)
                      && convert_mult_to_fma (stmt,
                                              gimple_assign_rhs1 (stmt),
                                              gimple_assign_rhs2 (stmt)))