From 336a06a163f7a761f7c3b223a1dd9a1b81cda2cb Mon Sep 17 00:00:00 2001 From: Tamar Christina Date: Tue, 8 Aug 2017 13:15:44 +0000 Subject: [PATCH] re PR middle-end/19706 (Recognize common Fortran usages of copysign.) 2017-08-08 Tamar Christina Andrew Pinski 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 From-SVN: r250956 --- gcc/ChangeLog | 10 +++++ gcc/internal-fn.def | 1 + gcc/optabs.def | 1 + gcc/tree-ssa-math-opts.c | 88 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6051e8f5068..5eef8e083be 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2017-08-08 Tamar Christina + Andrew Pinski + + 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 PR tree-optimization/81354 diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index a9a3f7606eb..b1211159845 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 f21f2267ec2..54afe2d796e 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 7ac1659fa06..87940b6e00d 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 (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 (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))) -- 2.30.2