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? 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