aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@gcc.gnu.org>2017-02-23 08:49:06 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2017-02-23 08:49:06 +0100
commitb607e75e25261ac2c81d71fe1a4dcf5fcd166603 (patch)
treec83ce2682d44020d9ccc173ce01b86a17929c8a2 /gcc/tree.c
parent18eb304e5f35d745dcb1a9bb41a2879a364f59fe (diff)
downloadgcc-b607e75e25261ac2c81d71fe1a4dcf5fcd166603.zip
gcc-b607e75e25261ac2c81d71fe1a4dcf5fcd166603.tar.gz
gcc-b607e75e25261ac2c81d71fe1a4dcf5fcd166603.tar.bz2
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) <case TRUNC_DIV_EXPR>: 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
Diffstat (limited to 'gcc/tree.c')
-rw-r--r--gcc/tree.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/gcc/tree.c b/gcc/tree.c
index 3e63415..42c8a2d 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. */