On Sat, Dec 21, 2024 at 6:05 AM Alexandre Oliva <ol...@adacore.com> wrote:
>
> On Dec 20, 2024, Jakub Jelinek <ja...@redhat.com> wrote:
>
> > On Wed, Dec 18, 2024 at 12:59:11AM -0300, Alexandre Oliva wrote:
> >> * gcc.dg/field-merge-16.c: New.
>
> > Note the test FAILs on i686-linux or on x86_64-linux with -m32.
>
> Indeed, thanks. Here's a fix.
>
>
> On 32-bit hosts, data types with 64-bit alignment aren't getting
> treated as desired by ifcombine field-merging: we limit the choice of
> modes at BITS_PER_WORD sizes, but when deciding the boundary for a
> split, we'd limit the choice only by the alignment, so we wouldn't
> even consider a split at an odd 32-bit boundary. Fix that by limiting
> the boundary choice by word choice as well.
>
> Now, this would still leave misaligned 64-bit fields in 64-bit-aligned
> data structures unhandled by ifcombine on 32-bit hosts. We already
> need to loading them as double words, and if they're not byte-aligned,
> the code gets really ugly, but ifcombine could improve it if it allows
> double-word loads as a last resort. I've added that.
>
> Regstrapped on x86_64-linux-gnu. Ok to install?
OK.
Thanks,
Richard.
>
> for gcc/ChangeLog
>
> * gimple-fold.cc (fold_truth_andor_for_ifcombine): Limit
> boundary choice by word size as well. Try aligned double-word
> loads as a last resort.
>
> for gcc/testsuite/ChangeLog
>
> * gcc.dg/field-merge-17.c: New.
> ---
> gcc/gimple-fold.cc | 30 +++++++++++++++++++---
> gcc/testsuite/gcc.dg/field-merge-17.c | 46
> +++++++++++++++++++++++++++++++++
> 2 files changed, 73 insertions(+), 3 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/field-merge-17.c
>
> diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
> index 2d6e2074416f5..0e832158a47b3 100644
> --- a/gcc/gimple-fold.cc
> +++ b/gcc/gimple-fold.cc
> @@ -8381,16 +8381,40 @@ fold_truth_andor_for_ifcombine (enum tree_code code,
> tree truth_type,
> {
> /* Consider the possibility of recombining loads if any of the
> fields straddles across an alignment boundary, so that either
> - part can be loaded along with the other field. */
> + part can be loaded along with the other field. Since we
> + limit access modes to BITS_PER_WORD, don't exceed that,
> + otherwise on a 32-bit host and a 64-bit-aligned data
> + structure, we'll fail the above for a field that straddles
> + across two words, and would fail here for not even trying to
> + split it at between 32-bit words. */
> HOST_WIDE_INT boundary = compute_split_boundary_from_align
> - (ll_align, ll_bitpos, ll_bitsize, rl_bitpos, rl_bitsize);
> + (MIN (ll_align, BITS_PER_WORD),
> + ll_bitpos, ll_bitsize, rl_bitpos, rl_bitsize);
>
> if (boundary < 0
> || !get_best_mode (boundary - first_bit, first_bit, 0,
> ll_end_region,
> ll_align, BITS_PER_WORD, volatilep, &lnmode)
> || !get_best_mode (end_bit - boundary, boundary, 0, ll_end_region,
> ll_align, BITS_PER_WORD, volatilep, &lnmode2))
> - return 0;
> + {
> + if (ll_align <= BITS_PER_WORD)
> + return 0;
> +
> + /* As a last resort, try double-word access modes. This
> + enables us to deal with misaligned double-word fields
> + that straddle across 3 separate words. */
> + boundary = compute_split_boundary_from_align
> + (MIN (ll_align, 2 * BITS_PER_WORD),
> + ll_bitpos, ll_bitsize, rl_bitpos, rl_bitsize);
> + if (boundary < 0
> + || !get_best_mode (boundary - first_bit, first_bit,
> + 0, ll_end_region, ll_align, 2 *
> BITS_PER_WORD,
> + volatilep, &lnmode)
> + || !get_best_mode (end_bit - boundary, boundary,
> + 0, ll_end_region, ll_align, 2 *
> BITS_PER_WORD,
> + volatilep, &lnmode2))
> + return 0;
> + }
>
> /* If we can't have a single load, but can with two, figure out whether
> the two compares can be separated, i.e., whether the entirety of the
> diff --git a/gcc/testsuite/gcc.dg/field-merge-17.c
> b/gcc/testsuite/gcc.dg/field-merge-17.c
> new file mode 100644
> index 0000000000000..06c8ec16e86c6
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/field-merge-17.c
> @@ -0,0 +1,46 @@
> +/* { dg-do run } */
> +/* { dg-options "-O -fdump-tree-ifcombine-details" } */
> +
> +/* Check that we can optimize misaligned double-words. */
> +
> +struct s {
> + short a;
> + long long b;
> + int c;
> + long long d;
> + short e;
> +} __attribute__ ((packed, aligned (8)));
> +
> +struct s p = { 0, 0, 0, 0, 0 };
> +
> +__attribute__ ((__noinline__, __noipa__, __noclone__))
> +int fp ()
> +{
> + if (p.a
> + || p.b
> + || p.c
> + || p.d
> + || p.e)
> + return 1;
> + else
> + return -1;
> +}
> +
> +int main () {
> + /* Unlikely, but play safe. */
> + if (sizeof (long long) == sizeof (short))
> + return 0;
> + if (fp () > 0)
> + __builtin_abort ();
> + unsigned char *pc = (unsigned char *)&p;
> + for (int i = 0; i < sizeof (p); i++)
> + {
> + pc[i] = 1;
> + if (fp () < 0)
> + __builtin_abort ();
> + pc[i] = 0;
> + }
> + return 0;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "optimizing" 4 "ifcombine" } } */
>
>
> --
> 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