From: Jakub Jelinek Date: Thu, 23 Feb 2017 07:49:06 +0000 (+0100) Subject: re PR middle-end/79665 (gcc's signed (x*x)/200 is slower than clang's) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b607e75e25261ac2c81d71fe1a4dcf5fcd166603;p=gcc.git re PR middle-end/79665 (gcc's signed (x*x)/200 is slower than clang's) PR middle-end/79665 * internal-fn.c (get_range_pos_neg): Moved to ... * tree.c (get_range_pos_neg): ... here. No longer static. * tree.h (get_range_pos_neg): New prototype. * expr.c (expand_expr_real_2) : If both arguments are known to be in between 0 and signed maximum inclusive, try to expand both unsigned and signed divmod and use the cheaper one from those. From-SVN: r245676 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6da1d74115f..50566cc8685 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,4 +1,15 @@ -2017-02-22 Jeff Law +2017-02-23 Jakub Jelinek + + PR middle-end/79665 + * internal-fn.c (get_range_pos_neg): Moved to ... + * tree.c (get_range_pos_neg): ... here. No longer static. + * tree.h (get_range_pos_neg): New prototype. + * expr.c (expand_expr_real_2) : If both arguments + are known to be in between 0 and signed maximum inclusive, try to + expand both unsigned and signed divmod and use the cheaper one from + those. + +2017-02-22 Jeff Law PR tree-optimization/79578 * tree-ssa-dse.c (clear_bytes_written_by): Use operand_equal_p diff --git a/gcc/expr.c b/gcc/expr.c index 2d8868e52ce..34bbf3d7b47 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -8809,6 +8809,34 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, where some terms of the dividend have coeffs divisible by it. */ expand_operands (treeop0, treeop1, subtarget, &op0, &op1, EXPAND_NORMAL); + if (SCALAR_INT_MODE_P (mode) + && optimize >= 2 + && get_range_pos_neg (treeop0) == 1 + && get_range_pos_neg (treeop1) == 1) + { + /* If both arguments are known to be positive when interpreted + as signed, we can expand it as both signed and unsigned + division or modulo. Choose the cheaper sequence in that case. */ + bool speed_p = optimize_insn_for_speed_p (); + do_pending_stack_adjust (); + start_sequence (); + rtx uns_ret = expand_divmod (0, code, mode, op0, op1, target, 1); + rtx_insn *uns_insns = get_insns (); + end_sequence (); + start_sequence (); + rtx sgn_ret = expand_divmod (0, code, mode, op0, op1, target, 0); + rtx_insn *sgn_insns = get_insns (); + end_sequence (); + unsigned uns_cost = seq_cost (uns_insns, speed_p); + unsigned sgn_cost = seq_cost (sgn_insns, speed_p); + if (uns_cost < sgn_cost || (uns_cost == sgn_cost && unsignedp)) + { + emit_insn (uns_insns); + return uns_ret; + } + emit_insn (sgn_insns); + return sgn_ret; + } return expand_divmod (0, code, mode, op0, op1, target, unsignedp); case RDIV_EXPR: diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index 1d84b260bf1..ffe291d62cf 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -413,86 +413,6 @@ expand_FALLTHROUGH (internal_fn, gcall *call) "invalid use of attribute %"); } -/* Helper function for expand_addsub_overflow. Return 1 - if ARG interpreted as signed in its precision is known to be always - positive or 2 if ARG is known to be always negative, or 3 if ARG may - be positive or negative. */ - -static int -get_range_pos_neg (tree arg) -{ - if (arg == error_mark_node) - return 3; - - int prec = TYPE_PRECISION (TREE_TYPE (arg)); - int cnt = 0; - if (TREE_CODE (arg) == INTEGER_CST) - { - wide_int w = wi::sext (arg, prec); - if (wi::neg_p (w)) - return 2; - else - return 1; - } - while (CONVERT_EXPR_P (arg) - && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0))) - && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec) - { - arg = TREE_OPERAND (arg, 0); - /* Narrower value zero extended into wider type - will always result in positive values. */ - if (TYPE_UNSIGNED (TREE_TYPE (arg)) - && TYPE_PRECISION (TREE_TYPE (arg)) < prec) - return 1; - prec = TYPE_PRECISION (TREE_TYPE (arg)); - if (++cnt > 30) - return 3; - } - - if (TREE_CODE (arg) != SSA_NAME) - return 3; - wide_int arg_min, arg_max; - while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE) - { - gimple *g = SSA_NAME_DEF_STMT (arg); - if (is_gimple_assign (g) - && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g))) - { - tree t = gimple_assign_rhs1 (g); - if (INTEGRAL_TYPE_P (TREE_TYPE (t)) - && TYPE_PRECISION (TREE_TYPE (t)) <= prec) - { - if (TYPE_UNSIGNED (TREE_TYPE (t)) - && TYPE_PRECISION (TREE_TYPE (t)) < prec) - return 1; - prec = TYPE_PRECISION (TREE_TYPE (t)); - arg = t; - if (++cnt > 30) - return 3; - continue; - } - } - return 3; - } - if (TYPE_UNSIGNED (TREE_TYPE (arg))) - { - /* For unsigned values, the "positive" range comes - below the "negative" range. */ - if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED)) - return 1; - if (wi::neg_p (wi::sext (arg_min, prec), SIGNED)) - return 2; - } - else - { - if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED)) - return 1; - if (wi::neg_p (wi::sext (arg_max, prec), SIGNED)) - return 2; - } - return 3; -} - /* Return minimum precision needed to represent all values of ARG in SIGNed integral type. */ diff --git a/gcc/tree.c b/gcc/tree.c index 3e63415e673..42c8a2ddd8a 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -14205,6 +14205,88 @@ verify_type (const_tree t) } +/* Return 1 if ARG interpreted as signed in its precision is known to be + always positive or 2 if ARG is known to be always negative, or 3 if + ARG may be positive or negative. */ + +int +get_range_pos_neg (tree arg) +{ + if (arg == error_mark_node) + return 3; + + int prec = TYPE_PRECISION (TREE_TYPE (arg)); + int cnt = 0; + if (TREE_CODE (arg) == INTEGER_CST) + { + wide_int w = wi::sext (arg, prec); + if (wi::neg_p (w)) + return 2; + else + return 1; + } + while (CONVERT_EXPR_P (arg) + && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg, 0))) + && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg, 0))) <= prec) + { + arg = TREE_OPERAND (arg, 0); + /* Narrower value zero extended into wider type + will always result in positive values. */ + if (TYPE_UNSIGNED (TREE_TYPE (arg)) + && TYPE_PRECISION (TREE_TYPE (arg)) < prec) + return 1; + prec = TYPE_PRECISION (TREE_TYPE (arg)); + if (++cnt > 30) + return 3; + } + + if (TREE_CODE (arg) != SSA_NAME) + return 3; + wide_int arg_min, arg_max; + while (get_range_info (arg, &arg_min, &arg_max) != VR_RANGE) + { + gimple *g = SSA_NAME_DEF_STMT (arg); + if (is_gimple_assign (g) + && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (g))) + { + tree t = gimple_assign_rhs1 (g); + if (INTEGRAL_TYPE_P (TREE_TYPE (t)) + && TYPE_PRECISION (TREE_TYPE (t)) <= prec) + { + if (TYPE_UNSIGNED (TREE_TYPE (t)) + && TYPE_PRECISION (TREE_TYPE (t)) < prec) + return 1; + prec = TYPE_PRECISION (TREE_TYPE (t)); + arg = t; + if (++cnt > 30) + return 3; + continue; + } + } + return 3; + } + if (TYPE_UNSIGNED (TREE_TYPE (arg))) + { + /* For unsigned values, the "positive" range comes + below the "negative" range. */ + if (!wi::neg_p (wi::sext (arg_max, prec), SIGNED)) + return 1; + if (wi::neg_p (wi::sext (arg_min, prec), SIGNED)) + return 2; + } + else + { + if (!wi::neg_p (wi::sext (arg_min, prec), SIGNED)) + return 1; + if (wi::neg_p (wi::sext (arg_max, prec), SIGNED)) + return 2; + } + return 3; +} + + + + /* Return true if ARG is marked with the nonnull attribute in the current function signature. */ diff --git a/gcc/tree.h b/gcc/tree.h index 3b12509e7df..aa137e4132b 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4876,6 +4876,7 @@ extern bool gimple_canonical_types_compatible_p (const_tree, const_tree, bool trust_type_canonical = true); extern bool type_with_interoperable_signedness (const_tree); extern bitmap get_nonnull_args (const_tree); +extern int get_range_pos_neg (tree); /* Return simplified tree code of type that is used for canonical type merging. */