diff options
Diffstat (limited to 'gcc/expr.cc')
-rw-r--r-- | gcc/expr.cc | 82 |
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)) |