aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorTamar Christina <tamar.christina@arm.com>2017-08-08 13:15:44 +0000
committerTamar Christina <tnfchris@gcc.gnu.org>2017-08-08 13:15:44 +0000
commit336a06a163f7a761f7c3b223a1dd9a1b81cda2cb (patch)
tree27330a1034c99eb6062da9796c581d294554ee1f /gcc
parentb115e80367277d58bc5476c3c748cf7ec2432a10 (diff)
downloadgcc-336a06a163f7a761f7c3b223a1dd9a1b81cda2cb.zip
gcc-336a06a163f7a761f7c3b223a1dd9a1b81cda2cb.tar.gz
gcc-336a06a163f7a761f7c3b223a1dd9a1b81cda2cb.tar.bz2
re PR middle-end/19706 (Recognize common Fortran usages of copysign.)
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/internal-fn.def1
-rw-r--r--gcc/optabs.def1
-rw-r--r--gcc/tree-ssa-math-opts.c88
4 files changed, 100 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6051e8f..5eef8e0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index a9a3f76..b121115 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -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)
diff --git a/gcc/optabs.def b/gcc/optabs.def
index f21f226..54afe2d 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -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")
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index 7ac1659..87940b6 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -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)))