]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ext-dce: Fix subreg_lsb is_constant assumption
authorRichard Sandiford <richard.sandiford@arm.com>
Mon, 7 Jul 2025 08:10:38 +0000 (09:10 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Mon, 7 Jul 2025 08:10:38 +0000 (09:10 +0100)
ext-dce had:

  if (SUBREG_P (dst) && SUBREG_BYTE (dst).is_constant ())
    {
      bit = subreg_lsb (dst).to_constant ();
      if (bit >= HOST_BITS_PER_WIDE_INT)
bit = HOST_BITS_PER_WIDE_INT - 1;
      dst = SUBREG_REG (dst);

But a constant SUBREG_BYTE doesn't guarantee a constant subreg_lsb.
If the SUBREG_REG is a pair of N-bit registers on a big-endian target,
the most significant end has a SUBREG_BYTE of 0 but a subreg_lsb of N.
This N would then be non-constant for variable-length registers.

The patch fixes gcc.dg/torture/pr120276.c and other failures on
aarch64_be-elf.

gcc/
* ext-dce.cc (ext_dce_process_uses): Apply is_constant directly
to the subreg_lsb.

gcc/ext-dce.cc

index afe7afe21fd720ff153970c7681e4d27290f9ce8..e7635fb7a394a7bc2a0f0f9b1b13c504da579fd6 100644 (file)
@@ -651,9 +651,8 @@ ext_dce_process_uses (rtx_insn *insn, rtx obj,
 
          /* ?!? How much of this should mirror SET handling, potentially
             being shared?   */
-         if (SUBREG_P (dst) && SUBREG_BYTE (dst).is_constant ())
+         if (SUBREG_P (dst) && subreg_lsb (dst).is_constant (&bit))
            {
-             bit = subreg_lsb (dst).to_constant ();
              if (bit >= HOST_BITS_PER_WIDE_INT)
                bit = HOST_BITS_PER_WIDE_INT - 1;
              dst = SUBREG_REG (dst);