Optimise CONCAT handling in emit_group_load
authorRichard Sandiford <richard.sandiford@arm.com>
Wed, 16 Nov 2016 10:21:22 +0000 (10:21 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Wed, 16 Nov 2016 10:21:22 +0000 (10:21 +0000)
The CONCAT handling in emit_group_load chooses between doing
an extraction from a single component or forcing the whole
thing to memory and extracting from there.  The condition for
the former (more efficient) option was:

  if ((bytepos == 0 && bytelen == slen0)
      || (bytepos != 0 && bytepos + bytelen <= slen))

On the one hand this seems dangerous, since the second line
allows bit ranges that start in the first component and leak
into the second.  On the other hand it seems strange to allow
references that start after the first byte of the second
component but not those that start after the first byte
of the first component.  This led to a pessimisation of
things like gcc.dg/builtins-54.c for hppa64-hp-hpux11.23.

This patch simply checks whether the reference is contained
within a single component.  It also makes sure that we do
an extraction on anything that doesn't span the whole
component (even if it's constant).

gcc/
2016-11-15  Richard Sandiford  <richard.sandiford@arm.com>
    Alan Hayward  <alan.hayward@arm.com>
    David Sherwood  <david.sherwood@arm.com>

* expr.c (emit_group_load_1): Tighten check for whether an
access involves only one operand of a CONCAT.  Use extract_bit_field
for constants if the bit range does span the whole operand.

Co-Authored-By: Alan Hayward <alan.hayward@arm.com>
Co-Authored-By: David Sherwood <david.sherwood@arm.com>
From-SVN: r242477

gcc/ChangeLog
gcc/expr.c

index fe1d9c3b257063d71e0154868fa03454ad70be3e..a9263afaef24272bc68c7802efeb184a2f48ea94 100644 (file)
@@ -1,3 +1,11 @@
+2016-11-16  Richard Sandiford  <richard.sandiford@arm.com>
+           Alan Hayward  <alan.hayward@arm.com>
+           David Sherwood  <david.sherwood@arm.com>
+
+       * expr.c (emit_group_load_1): Tighten check for whether an
+       access involves only one operand of a CONCAT.  Use extract_bit_field
+       for constants if the bit range does span the whole operand.
+
 2016-11-16  Richard Sandiford  <richard.sandiford@arm.com>
            Alan Hayward  <alan.hayward@arm.com>
            David Sherwood  <david.sherwood@arm.com>
index 0b0946de3457051ec848fceafe412ed8a08acc5f..985c2b3285f9289eeaac43293f85195b5f3d0d5b 100644 (file)
@@ -2175,19 +2175,22 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
        {
          unsigned int slen = GET_MODE_SIZE (GET_MODE (src));
          unsigned int slen0 = GET_MODE_SIZE (GET_MODE (XEXP (src, 0)));
+         unsigned int elt = bytepos / slen0;
+         unsigned int subpos = bytepos % slen0;
 
-         if ((bytepos == 0 && bytelen == slen0)
-             || (bytepos != 0 && bytepos + bytelen <= slen))
+         if (subpos + bytelen <= slen0)
            {
              /* The following assumes that the concatenated objects all
                 have the same size.  In this case, a simple calculation
                 can be used to determine the object and the bit field
                 to be extracted.  */
-             tmps[i] = XEXP (src, bytepos / slen0);
-             if (! CONSTANT_P (tmps[i])
-                 && (!REG_P (tmps[i]) || GET_MODE (tmps[i]) != mode))
+             tmps[i] = XEXP (src, elt);
+             if (subpos != 0
+                 || subpos + bytelen != slen0
+                 || (!CONSTANT_P (tmps[i])
+                     && (!REG_P (tmps[i]) || GET_MODE (tmps[i]) != mode)))
                tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT,
-                                            (bytepos % slen0) * BITS_PER_UNIT,
+                                            subpos * BITS_PER_UNIT,
                                             1, NULL_RTX, mode, mode, false);
            }
          else