On Sat, Jan 18, 2025 at 7:02 AM Alexandre Oliva <ol...@adacore.com> wrote: > > > Unlike other access patterns, BIT_FIELD_REFs aren't regarded as > possibly-trapping out of referencing out-of-bounds bits. > > So, if decode_field_reference finds a load that could trap, but whose > inner object can't, bail out if it accesses past the inner object's > size.
I think this is a bug in tree_could_trap_p which is indeed not considering out-of-bound accesses of a VAR_DECL (or any decl), but very conservatively handle ARRAY_REFs. IMO the proper fix might be to use something like get_ref_base_and_extent when analyzing the a tcc_reference sub-tree. Can you open a bugreport to track this? I might want to take that. For the issue at hand ... > This may drop some ifcombine optimizations in VLAs, that could be safe > if we managed to reuse the same pre-existing load for both compares, but > those get optimized later (as in the new testcase). The cases of most > interest are those that merge separate fields, and they necessarily > involve new BIT_FIELD_REFs loads. > > Regstrapped on x86_64-linux-gnu. Ok to install? > > > for gcc/ChangeLog > > PR tree-optimization/118514 > * gimple-fold.cc (decode_field_reference): Refuse to consider > BIT_FIELD_REF of non-trapping object if the original load > could trap for being out-of-bounds. > (make_bit_field_ref): Check that replacement loads could trap > as much as the original loads. > > for gcc/testsuite/ChangeLog > > PR tree-optimization/118514 > * gcc.dg/field-merge-23.c: New. > --- > gcc/gimple-fold.cc | 19 +++++++++++++++---- > gcc/testsuite/gcc.dg/field-merge-23.c | 19 +++++++++++++++++++ > 2 files changed, 34 insertions(+), 4 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/field-merge-23.c > > diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc > index 3c971a29ef045..41b21ecd58a32 100644 > --- a/gcc/gimple-fold.cc > +++ b/gcc/gimple-fold.cc > @@ -7686,10 +7686,16 @@ decode_field_reference (tree *pexp, HOST_WIDE_INT > *pbitsize, > || bs <= shiftrt > || offset != 0 > || TREE_CODE (inner) == PLACEHOLDER_EXPR > - /* Reject out-of-bound accesses (PR79731). */ > - || (! AGGREGATE_TYPE_P (TREE_TYPE (inner)) > - && compare_tree_int (TYPE_SIZE (TREE_TYPE (inner)), > - bp + bs) < 0) > + /* Reject out-of-bound accesses (PR79731). BIT_FIELD_REFs aren't > flagged > + as tree_could_trap_p just because of out-of-range bits, so don't even > + try to optimize loads that could trap if they access out-of-range > bits > + of an object that could not trap (PR118514). */ > + || ((! AGGREGATE_TYPE_P (TREE_TYPE (inner)) > + || (load && tree_could_trap_p (gimple_assign_rhs1 (load)) > + & !tree_could_trap_p (inner))) > + && (!tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (inner))) > + || compare_tree_int (TYPE_SIZE (TREE_TYPE (inner)), > + bp + bs) < 0)) So you fear of missed optimizations when allowing variable size types? I'd have said we should have proof that the generated BIT_FIELD_REF does not access out-of-bounds, in particular the tree_could_trap_p (gimple_assign_rhs1 (load)) & !tree_could_trap_p (inner) (&& btw) looks like bad style. That said, the testcase in the PR is a bit artificial, so we might get away with ignoring the issue for GCC 15 and go for fixing tree_could_trap_p? Did you consider not applying this ifcombine to tree_could_trap_p original refs at all? The short-circuiting that's removed should make this susceptible anyhow? Thanks, Richard. > || (INTEGRAL_TYPE_P (TREE_TYPE (inner)) > && !type_has_mode_precision_p (TREE_TYPE (inner)))) > return NULL_TREE; > @@ -7859,6 +7865,11 @@ make_bit_field_load (location_t loc, tree inner, tree > orig_inner, tree type, > gimple *new_stmt = gsi_stmt (i); > if (gimple_has_mem_ops (new_stmt)) > gimple_set_vuse (new_stmt, reaching_vuse); > + gcc_checking_assert (! (gimple_assign_load_p (point) > + && gimple_assign_load_p (new_stmt)) > + || (tree_could_trap_p (gimple_assign_rhs1 (point)) > + == tree_could_trap_p (gimple_assign_rhs1 > + (new_stmt)))); > } > > gimple_stmt_iterator gsi = gsi_for_stmt (point); > diff --git a/gcc/testsuite/gcc.dg/field-merge-23.c > b/gcc/testsuite/gcc.dg/field-merge-23.c > new file mode 100644 > index 0000000000000..96604d43c9dec > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/field-merge-23.c > @@ -0,0 +1,19 @@ > +/* { dg-do run } */ > +/* { dg-options "-O" } */ > + > +/* PR tree-optimization/118514 */ > + > +/* Check that we don't create BIT_FIELD_REFs that could trap, because they > are > + assumed not to trap and could be pulled out of loops. */ > + > +int a, c = 1; > +unsigned char b[1], d; > +int main() { > + while (a || !c) { > + signed char e = b[1000000000]; > + d = e < 0 || b[1000000000] > 1; > + if (d) > + __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