On Thu, Jan 23, 2025 at 8:43 AM Alexandre Oliva <[email protected]> wrote:
>
>
> When comparing a signed narrow variable with a wider constant that has
> the bit corresponding to the variable's sign bit set, we would check
> that the constant is a sign-extension from that sign bit, and conclude
> that the compare fails if it isn't.
>
> When the signed variable is masked without getting the [lr]l_signbit
> variable set, or when the sign bit itself is masked out, we know the
> sign-extension bits from the extended variable are going to be zero,
> so the constant will only compare equal if it is a zero- rather than
> sign-extension from the narrow variable's precision, therefore, check
> that it satisfies this property, and yield a false compare result
> otherwise.
OK.
Thanks,
Richard.
>
> for gcc/ChangeLog
>
> PR tree-optimization/118572
> * gimple-fold.cc (fold_truth_andor_for_ifcombine): Compare as
> unsigned the variables whose extension bits are masked out.
>
> for gcc/testsuite/ChangeLog
>
> PR tree-optimization/118572
> * gcc.dg/field-merge-24.c: New.
> ---
> gcc/gimple-fold.cc | 20 ++++++++++++++++--
> gcc/testsuite/gcc.dg/field-merge-24.c | 36
> +++++++++++++++++++++++++++++++++
> 2 files changed, 53 insertions(+), 3 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/field-merge-24.c
>
> diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
> index cd9d350349186..13541fe1ef749 100644
> --- a/gcc/gimple-fold.cc
> +++ b/gcc/gimple-fold.cc
> @@ -8552,12 +8552,21 @@ fold_truth_andor_for_ifcombine (enum tree_code code,
> tree truth_type,
> {
> /* Before clipping upper bits of the right-hand operand of the compare,
> check that they're sign or zero extensions, depending on how the
> - left-hand operand would be extended. */
> + left-hand operand would be extended. If it is unsigned, or if
> there's
> + a mask that zeroes out extension bits, whether because we've checked
> + for upper bits in the mask and did not set ll_signbit, or because the
> + sign bit itself is masked out, check that the right-hand operand is
> + zero-extended. */
> bool l_non_ext_bits = false;
> if (ll_bitsize < lr_bitsize)
> {
> wide_int zext = wi::zext (l_const, ll_bitsize);
> - if ((ll_unsignedp ? zext : wi::sext (l_const, ll_bitsize)) ==
> l_const)
> + if ((ll_unsignedp
> + || (ll_and_mask.get_precision ()
> + && (!ll_signbit
> + || ((ll_and_mask & wi::mask (ll_bitsize - 1, true,
> ll_bitsize))
> + == 0)))
> + ? zext : wi::sext (l_const, ll_bitsize)) == l_const)
> l_const = zext;
> else
> l_non_ext_bits = true;
> @@ -8583,7 +8592,12 @@ fold_truth_andor_for_ifcombine (enum tree_code code,
> tree truth_type,
> if (rl_bitsize < rr_bitsize)
> {
> wide_int zext = wi::zext (r_const, rl_bitsize);
> - if ((rl_unsignedp ? zext : wi::sext (r_const, rl_bitsize)) ==
> r_const)
> + if ((rl_unsignedp
> + || (rl_and_mask.get_precision ()
> + && (!rl_signbit
> + || ((rl_and_mask & wi::mask (rl_bitsize - 1, true,
> rl_bitsize))
> + == 0)))
> + ? zext : wi::sext (r_const, rl_bitsize)) == r_const)
> r_const = zext;
> else
> r_non_ext_bits = true;
> diff --git a/gcc/testsuite/gcc.dg/field-merge-24.c
> b/gcc/testsuite/gcc.dg/field-merge-24.c
> new file mode 100644
> index 0000000000000..ce5bce7d0b49c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/field-merge-24.c
> @@ -0,0 +1,36 @@
> +/* { dg-do run } */
> +/* { dg-options "-O2" } */
> +
> +/* PR tree-optimization/118572 */
> +/* Check that signed compares with constants that seem signed in the other
> + compare operand's width get treated as unsigned if its upper bits are
> masked
> + out. */
> +
> +__attribute__((noipa))
> +int test(signed char c)
> +{
> + return (((0x80 & (c&0xff)) != 0) && ((0xc0 & (c&0xff)) == 0x80));
> +}
> +
> +__attribute__((noipa))
> +int test2(signed char c)
> +{
> + return (((-128 & (c&-1)) != 0) && ((-64 & (c&-1)) == -128));
> +}
> +
> +__attribute__((noipa))
> +int test3(signed char c)
> +{
> + return (((0x80 & (c&-1)) != 0) && ((0x1248c0 & (c&-1)) == 0x124880));
> +}
> +
> +__attribute__((noipa))
> +int test4(signed char c)
> +{
> + return (((0x400 & (c&-1)) == 0) && ((0x40 & (c&-1)) == 0x40));
> +}
> +
> +int main() {
> + if (test(0x80) == 0 || test2(-128) == 0 || test3(-128) == 0 || test4(64)
> == 0)
> + __builtin_abort();
> +}
>
>
> --
> Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
> Free Software Activist GNU Toolchain Engineer
> More tolerance and less prejudice are key for inclusion and diversity
> Excluding neuro-others for not behaving ""normal"" is *not* inclusive