On Dec 20, 2024, Jakub Jelinek <[email protected]> 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