On Thu, Feb 13, 2025 at 4:23 PM Alexandre Oliva <ol...@adacore.com> wrote: > > > A compare with zero may be taken as a sign bit test by > fold_truth_andor_for_ifcombine, but the operand may be extended from a > narrower field. If the operand was narrower, the bitsize will reflect > the narrowing conversion, but if it was wider, we'll only know whether > the field is sign- or zero-extended from unsignedp, but we won't know > whether it needed to be extended, because arg will have changed to the > narrower variable when we get to the point in which we can compute the > arg width. If it's sign-extended, we're testing the right bit, but if > it's zero-extended, there isn't any bit we can test. > > Instead of punting and leaving the foldable compare to be figured out > by another pass, arrange for the sign bit resulting from the widening > zero-extension to be taken as zero, so that the modified compare will > yield the desired result. > > While at that, avoid swapping the right-hand compare operands when > we've already determined that it was a signbit test: it no use to even > try. > > Regstrapped on x86_64-linux-gnu. Ok to install?
OK. Thanks, Richard. > > for gcc/ChangeLog > > PR tree-optimization/118805 > * gimple-fold.cc (fold_truth_andor_for_combine): Detect and > cope with zero-extension in signbit tests. Reject swapping > right-compare operands if rsignbit. > > for gcc/testsuite/ChangeLog > > PR tree-optimization/118805 > * gcc.dg/field-merge-26.c: New. > --- > gcc/gimple-fold.cc | 22 +++++++++++++++++----- > gcc/testsuite/gcc.dg/field-merge-26.c | 20 ++++++++++++++++++++ > 2 files changed, 37 insertions(+), 5 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/field-merge-26.c > > diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc > index 29191685a43c5..0380c7af4c213 100644 > --- a/gcc/gimple-fold.cc > +++ b/gcc/gimple-fold.cc > @@ -8090,14 +8090,16 @@ fold_truth_andor_for_ifcombine (enum tree_code code, > tree truth_type, > > /* Prepare to turn compares of signed quantities with zero into sign-bit > tests. We need not worry about *_reversep here for these compare > - rewrites: loads will have already been reversed before compares. */ > - bool lsignbit = false, rsignbit = false; > + rewrites: loads will have already been reversed before compares. Save > the > + precision, because [lr]l_arg may change and we won't be able to tell how > + wide it was originally. */ > + unsigned lsignbit = 0, rsignbit = 0; > if ((lcode == LT_EXPR || lcode == GE_EXPR) > && integer_zerop (lr_arg) > && INTEGRAL_TYPE_P (TREE_TYPE (ll_arg)) > && !TYPE_UNSIGNED (TREE_TYPE (ll_arg))) > { > - lsignbit = true; > + lsignbit = TYPE_PRECISION (TREE_TYPE (ll_arg)); > lcode = (lcode == LT_EXPR ? NE_EXPR : EQ_EXPR); > } > /* Turn compares of unsigned quantities with powers of two into > @@ -8130,7 +8132,7 @@ fold_truth_andor_for_ifcombine (enum tree_code code, > tree truth_type, > && INTEGRAL_TYPE_P (TREE_TYPE (rl_arg)) > && !TYPE_UNSIGNED (TREE_TYPE (rl_arg))) > { > - rsignbit = true; > + rsignbit = TYPE_PRECISION (TREE_TYPE (rl_arg)); > rcode = (rcode == LT_EXPR ? NE_EXPR : EQ_EXPR); > } > else if ((rcode == LT_EXPR || rcode == GE_EXPR) > @@ -8204,7 +8206,7 @@ fold_truth_andor_for_ifcombine (enum tree_code code, > tree truth_type, > || ! operand_equal_p (ll_inner, rl_inner, 0)) > { > /* Try swapping the operands. */ > - if (ll_reversep != rr_reversep > + if (ll_reversep != rr_reversep || rsignbit > || !operand_equal_p (ll_inner, rr_inner, 0)) > return 0; > > @@ -8284,6 +8286,14 @@ fold_truth_andor_for_ifcombine (enum tree_code code, > tree truth_type, > if (lsignbit) > { > wide_int sign = wi::mask (ll_bitsize - 1, true, ll_bitsize); > + /* If ll_arg is zero-extended and we're testing the sign bit, we know > + what the result should be. Shifting the sign bit out of sign will > get > + us to mask the entire field out, yielding zero, i.e., the sign bit of > + the zero-extended value. We know the masked value is being compared > + with zero, so the compare will get us the result we're looking > + for: TRUE if EQ_EXPR, FALSE if NE_EXPR. */ > + if (lsignbit > ll_bitsize && ll_unsignedp) > + sign <<= 1; > if (!ll_and_mask.get_precision ()) > ll_and_mask = sign; > else > @@ -8303,6 +8313,8 @@ fold_truth_andor_for_ifcombine (enum tree_code code, > tree truth_type, > if (rsignbit) > { > wide_int sign = wi::mask (rl_bitsize - 1, true, rl_bitsize); > + if (rsignbit > rl_bitsize && ll_unsignedp) > + sign <<= 1; > if (!rl_and_mask.get_precision ()) > rl_and_mask = sign; > else > diff --git a/gcc/testsuite/gcc.dg/field-merge-26.c > b/gcc/testsuite/gcc.dg/field-merge-26.c > new file mode 100644 > index 0000000000000..96d7e7205c5f2 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/field-merge-26.c > @@ -0,0 +1,20 @@ > +/* { dg-do run } */ > +/* { dg-options "-O1 -fno-tree-ccp -fno-tree-copy-prop -fno-tree-forwprop > -fno-tree-fre" } */ > + > +/* PR tree-optimization/118805 */ > + > +/* Test that ifcombine doesn't get confused by tests for the sign bit of > + extended values that would normally be folded before. */ > + > +unsigned char a = 255; > +int b; > +int main() { > + int c = 0; > + if (c > a && a >= 255) > + __builtin_abort (); > + if (c <= a && a == 254) > + __builtin_abort (); > + if (a < c || a != 255) > + __builtin_abort (); > + return 0; > +} > > > -- > 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