expand: Use less costly from sign and zero extensions for values where value range says they don't have MSB set [PR120434]

On top of the just posted patch, the following patch attempts to
use value range to see if MSB is known to be false and for scalar integral
extension in that case tries to expand both sign and zero extension and
chooses based on RTX costs the cheaper one (if the costs are the same
uses what it used before, TYPE_UNSIGNED (TREE_TYPE (treeop0)) based.

The patch regresses the gcc.target/i386/pr78103-3.c test, will post
a separate patch for that momentarily (with the intent that if all 3
patches are approved, I'll commit the PR78103 related one before this one).

2025-06-10  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/120434
	* expr.cc (expand_expr_real_2) <CASE_CONVERT>: If get_range_pos_neg
	at -O2 for scalar integer extension suggests the most significant
	bit of op0 is not set, try both unsigned and signed conversion and
	choose the cheaper one.  If both are the same cost, choose one
	based on TYPE_UNSIGNED (TREE_TYPE (treeop0)).

	* gcc.target/i386/pr120434-2.c: New test.
This commit is contained in:
Jakub Jelinek
2025-06-10 20:06:14 +02:00
committed by Jakub Jelinek
parent 54da199f28
commit 2e4688a720
2 changed files with 74 additions and 5 deletions

View File

@@ -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;
}

View File

@@ -0,0 +1,15 @@
/* PR middle-end/120434 */
/* { dg-do compile { target lp64 } } */
/* { dg-options "-O2 -mtune=generic -masm=att" } */
/* { dg-final { scan-assembler-not "\tmovslq\t%edi, %rdi" } } */
/* { dg-final { scan-assembler "\tmovl\t%edi, %edi" } } */
extern unsigned long long foo (unsigned long long x);
unsigned long long
bar (int x)
{
if (x < 50)
return 0;
return foo (x);
}