https://gcc.gnu.org/g:5d675c9bef7c53baa310703efd6b7af65f68e22d
commit r17-4062-g5d675c9bef7c53baa310703efd6b7af65f68e22d Author: Kyrylo Tkachov <[email protected]> Date: Sun Sep 6 12:57:10 2026 +0200 ifcvt: factor the sign-bit-splat constant selection noce_try_sign_bit_splat has two arms that narrow the -1/0 splat down to a constant, one for each orientation of the test. They are twenty-five identical lines apart from which of the two arm constants they use, including the cost comparison that picks between a mask, a left shift and a right shift. Move that into noce_splat_to_const and call it from both arms. No functional change. gcc/ChangeLog: * ifcvt.cc (noce_splat_to_const): New function. (noce_try_sign_bit_splat): Use it for both orientations. Signed-off-by: Kyrylo Tkachov <[email protected]> Diff: --- gcc/ifcvt.cc | 92 +++++++++++++++++++++++++----------------------------------- 1 file changed, 38 insertions(+), 54 deletions(-) diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc index 42a86ac0ed40..6d90857c12d7 100644 --- a/gcc/ifcvt.cc +++ b/gcc/ifcvt.cc @@ -1411,6 +1411,42 @@ noce_try_move (struct noce_if_info *if_info) return false; } +/* TEMP holds an all-ones or all-zeros splat of a tested sign bit. Return an + rtx that narrows it to VAL or zero, expanded into TARGET where possible, or + NULL_RTX if the expansion failed. + + The obvious form is a mask, but since the value is known to be -1 or 0 a + shift is sometimes cheaper: a logical right shift constructs 2^n-1 and a + left shift constructs ~(2^n-1). Some targets do not have efficient shifts, + so build the RTL for each applicable form and expand the cheapest. */ + +static rtx +noce_splat_to_const (machine_mode mode, rtx temp, HOST_WIDE_INT val, + rtx target) +{ + rtx and_form = gen_rtx_AND (mode, temp, GEN_INT (val)); + rtx shift_left = gen_rtx_ASHIFT (mode, temp, GEN_INT (ctz_hwi (val))); + HOST_WIDE_INT rshift_count + = clz_hwi (val) & (GET_MODE_PRECISION (mode).to_constant () - 1); + rtx shift_right = gen_rtx_LSHIFTRT (mode, temp, GEN_INT (rshift_count)); + bool speed_p = optimize_insn_for_speed_p (); + + if (exact_log2 (val + 1) >= 0 + && (rtx_cost (shift_right, mode, SET, 1, speed_p) + < rtx_cost (and_form, mode, SET, 1, speed_p))) + return expand_simple_binop (mode, LSHIFTRT, temp, GEN_INT (rshift_count), + target, false, OPTAB_WIDEN); + + if (exact_log2 (~val + 1) >= 0 + && (rtx_cost (shift_left, mode, SET, 1, speed_p) + < rtx_cost (and_form, mode, SET, 1, speed_p))) + return expand_simple_binop (mode, ASHIFT, temp, GEN_INT (ctz_hwi (val)), + target, false, OPTAB_WIDEN); + + return expand_simple_binop (mode, AND, temp, GEN_INT (val), target, false, + OPTAB_WIDEN); +} + /* If a sign bit test is selecting across constants, we may be able to generate efficient code utilizing the -1/0 result of a sign bit splat idiom. @@ -1507,33 +1543,7 @@ noce_try_sign_bit_splat (struct noce_if_info *if_info) goto fail; } - /* Since we know the value is currently -1 or 0, some constants may - be more easily handled by shifting the value again. A right - logical shift constructs 2^n-1 constants a left shift constructs - ~(2^n-1) constants. Given some targets don't have efficient - shifts, generate the obvious RTL for both forms and select the - one with smaller cost. */ - rtx and_form = gen_rtx_AND (mode, temp, GEN_INT (val_a)); - rtx shift_left = gen_rtx_ASHIFT (mode, temp, GEN_INT (ctz_hwi (val_a))); - HOST_WIDE_INT rshift_count - = (clz_hwi (val_a) & (GET_MODE_PRECISION (mode).to_constant() - 1)); - rtx shift_right = gen_rtx_LSHIFTRT (mode, temp, GEN_INT (rshift_count)); - bool speed_p = optimize_insn_for_speed_p (); - if (exact_log2 (val_a + 1) >= 0 - && (rtx_cost (shift_right, mode, SET, 1, speed_p) - < rtx_cost (and_form, mode, SET, 1, speed_p))) - temp = expand_simple_binop (mode, LSHIFTRT, temp, - GEN_INT (rshift_count), - if_info->x, false, OPTAB_WIDEN); - else if (exact_log2 (~val_a + 1) >= 0 - && (rtx_cost (shift_left, mode, SET, 1, speed_p) - < rtx_cost (and_form, mode, SET, 1, speed_p))) - temp = expand_simple_binop (mode, ASHIFT, temp, - GEN_INT (ctz_hwi (val_a)), - if_info->x, false, OPTAB_WIDEN); - else - temp = expand_simple_binop (mode, AND, temp, GEN_INT (val_a), - if_info->x, false, OPTAB_WIDEN); + temp = noce_splat_to_const (mode, temp, val_a, if_info->x); } /* Same cases, but with the test or arms swapped. These can be realized as well, though it typically costs @@ -1559,33 +1569,7 @@ noce_try_sign_bit_splat (struct noce_if_info *if_info) goto fail; } - /* Since we know the value is currently -1 or 0, some constants may - be more easily handled by shifting the value again. A right - logical shift constructs 2^n-1 constants a left shift constructs - ~(2^n-1) constants. Given some targets don't have efficient - shifts, generate the obvious RTL for both forms and select the - one with smaller cost. */ - rtx and_form = gen_rtx_AND (mode, temp, GEN_INT (val_b)); - rtx shift_left = gen_rtx_ASHIFT (mode, temp, GEN_INT (ctz_hwi (val_b))); - HOST_WIDE_INT rshift_count - = (clz_hwi (val_b) & (GET_MODE_PRECISION (mode).to_constant() - 1)); - rtx shift_right = gen_rtx_LSHIFTRT (mode, temp, GEN_INT (rshift_count)); - bool speed_p = optimize_insn_for_speed_p (); - if (exact_log2 (val_b + 1) >= 0 - && (rtx_cost (shift_right, mode, SET, 1, speed_p) - < rtx_cost (and_form, mode, SET, 1, speed_p))) - temp = expand_simple_binop (mode, LSHIFTRT, temp, - GEN_INT (rshift_count), - if_info->x, false, OPTAB_WIDEN); - else if (exact_log2 (~val_b + 1) >= 0 - && (rtx_cost (shift_left, mode, SET, 1, speed_p) - < rtx_cost (and_form, mode, SET, 1, speed_p))) - temp = expand_simple_binop (mode, ASHIFT, temp, - GEN_INT (ctz_hwi (val_b)), - if_info->x, false, OPTAB_WIDEN); - else - temp = expand_simple_binop (mode, AND, temp, GEN_INT (val_b), - if_info->x, false, OPTAB_WIDEN); + temp = noce_splat_to_const (mode, temp, val_b, if_info->x); } /* Nothing worked. */ else
