On Mon, 13 Jan 2025, Alexandre Oliva wrote:

> 
> If a single-bit bitfield takes up the sign bit of a storage unit,
> comparing the corresponding bitfield between two objects loads the
> storage units, XORs them, converts the result to signed char, and
> compares it with zero: ((signed char)(a.<byte> ^ c.<byte>) >= 0).
> 
> fold_truth_andor_for_ifcombine recognizes the compare with zero as a
> sign bit test, then it decomposes the XOR into an equality test.
> 
> The problem is that, after this decomposition, that figures out the
> width of the accessed fields, we apply the sign bit mask to the
> left-hand operand of the compare, but we failed to also apply it to
> the right-hand operand when both were taken from the same XOR.
> 
> This patch fixes that.
> 
> Regstrapped on x86_64-linux-gnu.  Ok to install?

OK.

Thanks,
Richard.

> 
> for  gcc/ChangeLog
> 
>       PR tree-optimization/118409
>       * gimple-fold.cc (fold_truth_andor_for_ifcombine): Apply the
>       signbit mask to the right-hand XOR operand too.
> 
> for  gcc/testsuite/ChangeLog
> 
>       PR tree-optimization/118409
>       * gcc.dg/field-merge-20.c: New.
> ---
>  gcc/gimple-fold.cc                    |   20 ++++++++++
>  gcc/testsuite/gcc.dg/field-merge-20.c |   64 
> +++++++++++++++++++++++++++++++++
>  2 files changed, 84 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.dg/field-merge-20.c
> 
> diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
> index a3987c4590ae6..93ed8b3abb056 100644
> --- a/gcc/gimple-fold.cc
> +++ b/gcc/gimple-fold.cc
> @@ -8270,6 +8270,16 @@ fold_truth_andor_for_ifcombine (enum tree_code code, 
> tree truth_type,
>       ll_and_mask = sign;
>        else
>       ll_and_mask &= sign;
> +      if (l_xor)
> +     {
> +       if (!lr_and_mask.get_precision ())
> +         lr_and_mask = sign;
> +       else
> +         lr_and_mask &= sign;
> +       if (l_const.get_precision ())
> +         l_const &= wide_int::from (lr_and_mask,
> +                                    l_const.get_precision (), UNSIGNED);
> +     }
>      }
>  
>    if (rsignbit)
> @@ -8279,6 +8289,16 @@ fold_truth_andor_for_ifcombine (enum tree_code code, 
> tree truth_type,
>       rl_and_mask = sign;
>        else
>       rl_and_mask &= sign;
> +      if (r_xor)
> +     {
> +       if (!rr_and_mask.get_precision ())
> +         rr_and_mask = sign;
> +       else
> +         rr_and_mask &= sign;
> +       if (r_const.get_precision ())
> +         r_const &= wide_int::from (rr_and_mask,
> +                                    r_const.get_precision (), UNSIGNED);
> +     }
>      }
>  
>    /* If either comparison code is not correct for our logical operation,
> diff --git a/gcc/testsuite/gcc.dg/field-merge-20.c 
> b/gcc/testsuite/gcc.dg/field-merge-20.c
> new file mode 100644
> index 0000000000000..44ac7fae50dc5
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/field-merge-20.c
> @@ -0,0 +1,64 @@
> +/* { dg-do run } */
> +/* { dg-options "-O1" } */
> +
> +/* tree-optimization/118409 */
> +
> +/* Check that tests involving a sign bit of a storage unit are handled
> +   correctly.  The compares are turned into xor tests by earlier passes, and
> +   ifcombine has to propagate the sign bit mask to the right hand of the
> +   compare extracted from the xor, otherwise we'll retain unwanted bits for 
> the
> +   compare.  */
> +
> +typedef struct {
> +    int p : __CHAR_BIT__;
> +    int d : 1;
> +    int b : __CHAR_BIT__ - 2;
> +    int e : 1;
> +} g;
> +
> +g a = {.d = 1, .e = 1}, c = {.b = 1, .d = 1, .e = 1};
> +
> +__attribute__((noipa))
> +int f1 ()
> +{
> +  if (a.d == c.d
> +      && a.e == c.e)
> +    return 0;
> +  return -1;
> +}
> +
> +__attribute__((noipa))
> +int f2 ()
> +{
> +  if (a.d != c.d
> +      || a.e != c.e)
> +    return -1;
> +  return 0;
> +}
> +
> +__attribute__((noipa))
> +int f3 ()
> +{
> +  if (c.d == a.d
> +      && c.e == a.e)
> +    return 0;
> +  return -1;
> +}
> +
> +__attribute__((noipa))
> +int f4 ()
> +{
> +  if (c.d != a.d
> +      || c.e != a.e)
> +    return -1;
> +  return 0;
> +}
> +
> +int main() {
> +  if (f1 () < 0
> +      || f2 () < 0
> +      || f3 () < 0
> +      || f4 () < 0)
> +    __builtin_abort();
> +  return 0;
> +}
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to