On Sat, Jan 18, 2025 at 7:02 AM Alexandre Oliva <[email protected]> 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