aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/expr.c28
-rw-r--r--gcc/internal-fn.c80
-rw-r--r--gcc/tree.c82
-rw-r--r--gcc/tree.h1
5 files changed, 123 insertions, 81 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6da1d74..50566cc 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,4 +1,15 @@
-2017-02-22 Jeff Law <law@redhat.com>
+2017-02-23 Jakub Jelinek <jakub@redhat.com>
+
+ 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.
+
+2017-02-22 Jeff Law <law@redhat.com>
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 2d8868e..34bbf3d 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 1d84b26..ffe291d 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 %<fallthrough%>");
}
-/* 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 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. */
diff --git a/gcc/tree.h b/gcc/tree.h
index 3b12509..aa137e4 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. */