aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/expr.cc')
-rw-r--r--gcc/expr.cc82
1 files changed, 71 insertions, 11 deletions
diff --git a/gcc/expr.cc b/gcc/expr.cc
index b3b46a2..ac4fdfa 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -9681,8 +9681,8 @@ expand_expr_divmod (tree_code code, machine_mode mode, tree treeop0,
|| code == CEIL_MOD_EXPR || code == ROUND_MOD_EXPR);
if (SCALAR_INT_MODE_P (mode)
&& optimize >= 2
- && get_range_pos_neg (treeop0) == 1
- && get_range_pos_neg (treeop1) == 1)
+ && get_range_pos_neg (treeop0, currently_expanding_gimple_stmt) == 1
+ && get_range_pos_neg (treeop1, currently_expanding_gimple_stmt) == 1)
{
/* If both arguments are known to be positive when interpreted
as signed, we can expand it as both signed and unsigned
@@ -9879,14 +9879,68 @@ expand_expr_real_2 (const_sepops ops, rtx target, machine_mode tmode,
op0 = gen_rtx_fmt_e (TYPE_UNSIGNED (TREE_TYPE (treeop0))
? ZERO_EXTEND : SIGN_EXTEND, mode, op0);
+ else if (SCALAR_INT_MODE_P (GET_MODE (op0))
+ && optimize >= 2
+ && SCALAR_INT_MODE_P (mode)
+ && (GET_MODE_SIZE (as_a <scalar_int_mode> (mode))
+ > GET_MODE_SIZE (as_a <scalar_int_mode> (GET_MODE (op0))))
+ && get_range_pos_neg (treeop0,
+ currently_expanding_gimple_stmt) == 1)
+ {
+ /* If argument is known to be positive when interpreted
+ as signed, we can expand it as both sign and zero
+ extension. Choose the cheaper sequence in that case. */
+ bool speed_p = optimize_insn_for_speed_p ();
+ rtx uns_ret = NULL_RTX, sgn_ret = NULL_RTX;
+ do_pending_stack_adjust ();
+ start_sequence ();
+ if (target == NULL_RTX)
+ uns_ret = convert_to_mode (mode, op0, 1);
+ else
+ convert_move (target, op0, 1);
+ rtx_insn *uns_insns = end_sequence ();
+ start_sequence ();
+ if (target == NULL_RTX)
+ sgn_ret = convert_to_mode (mode, op0, 0);
+ else
+ convert_move (target, op0, 0);
+ rtx_insn *sgn_insns = end_sequence ();
+ unsigned uns_cost = seq_cost (uns_insns, speed_p);
+ unsigned sgn_cost = seq_cost (sgn_insns, speed_p);
+ bool was_tie = false;
+
+ /* If costs are the same then use as tie breaker the other other
+ factor. */
+ if (uns_cost == sgn_cost)
+ {
+ uns_cost = seq_cost (uns_insns, !speed_p);
+ sgn_cost = seq_cost (sgn_insns, !speed_p);
+ was_tie = true;
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, ";; positive extension:%s unsigned cost: %u; "
+ "signed cost: %u\n",
+ was_tie ? " (needed tie breaker)" : "",
+ uns_cost, sgn_cost);
+ if (uns_cost < sgn_cost
+ || (uns_cost == sgn_cost && TYPE_UNSIGNED (TREE_TYPE (treeop0))))
+ {
+ emit_insn (uns_insns);
+ sgn_ret = uns_ret;
+ }
+ else
+ emit_insn (sgn_insns);
+ if (target == NULL_RTX)
+ op0 = sgn_ret;
+ else
+ op0 = target;
+ }
else if (target == 0)
- op0 = convert_to_mode (mode, op0,
- TYPE_UNSIGNED (TREE_TYPE
- (treeop0)));
+ op0 = convert_to_mode (mode, op0, TYPE_UNSIGNED (TREE_TYPE (treeop0)));
else
{
- convert_move (target, op0,
- TYPE_UNSIGNED (TREE_TYPE (treeop0)));
+ convert_move (target, op0, TYPE_UNSIGNED (TREE_TYPE (treeop0)));
op0 = target;
}
@@ -11366,11 +11420,16 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
/* ??? internal call expansion doesn't follow the usual API
of returning the destination RTX and being passed a desired
target. */
+ if (modifier == EXPAND_WRITE)
+ return DECL_RTL (SSA_NAME_VAR (exp));
rtx dest = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
tree tmplhs = make_tree (TREE_TYPE (exp), dest);
- gimple_call_set_lhs (g, tmplhs);
+ tree var_or_id = SSA_NAME_VAR (exp);
+ if (!var_or_id)
+ var_or_id = SSA_NAME_IDENTIFIER (exp);
+ SET_SSA_NAME_VAR_OR_IDENTIFIER (exp, tmplhs);
expand_internal_call (as_a <gcall *> (g));
- gimple_call_set_lhs (g, exp);
+ SET_SSA_NAME_VAR_OR_IDENTIFIER (exp, var_or_id);
return dest;
}
@@ -13217,7 +13276,7 @@ maybe_optimize_pow2p_mod_cmp (enum tree_code code, tree *arg0, tree *arg1)
|| integer_zerop (*arg1)
/* If c is known to be non-negative, modulo will be expanded as unsigned
modulo. */
- || get_range_pos_neg (treeop0) == 1)
+ || get_range_pos_neg (treeop0, currently_expanding_gimple_stmt) == 1)
return code;
/* x % c == d where d < 0 && d <= -c should be always false. */
@@ -13349,7 +13408,8 @@ maybe_optimize_mod_cmp (enum tree_code code, tree *arg0, tree *arg1)
/* If both operands are known to have the sign bit clear, handle
even the signed modulo case as unsigned. treeop1 is always
positive >= 2, checked above. */
- if (!TYPE_UNSIGNED (type) && get_range_pos_neg (treeop0) != 1)
+ if (!TYPE_UNSIGNED (type)
+ && get_range_pos_neg (treeop0, currently_expanding_gimple_stmt) != 1)
sgn = SIGNED;
if (!TYPE_UNSIGNED (type))