]> git.ipfire.org Git - thirdparty/gcc.git/commit
[PR target/123010] Simplify shift of sign extracted field to a sign extending shift
authorJeff Law <jeffrey.law@oss.qualcomm.com>
Sun, 4 Jan 2026 16:30:01 +0000 (09:30 -0700)
committerJeff Law <jeffrey.law@oss.qualcomm.com>
Sun, 4 Jan 2026 16:30:01 +0000 (09:30 -0700)
commitbde7b018d4557538cdc8bef57ab073f3ec0d25b8
treee6fd73b413356ea364ec52ee0ab0e4c7fb35299d
parent582ccf3dc8d35c0249b9ef9ab69f6431e830d83d
[PR target/123010] Simplify shift of sign extracted field to a sign extending shift

In pr123010 we have a case where we should be getting a single slliw, but
instead we get a 3-insn sequence.

As noted in the BZ we had this before combine:

> (insn 6 3 13 2 (set (reg:DI 137)
>         (sign_extend:DI (ashift:SI (subreg/s/u:SI (reg/v:DI 135 [ a ]) 0)
>                 (const_int 1 [0x1])))) "j.c":10:14 312 {ashlsi3_extend}
>      (expr_list:REG_DEAD (reg/v:DI 135 [ a ])
>         (nil)))
Which is exactly what we want.  That's a single slliw instruction.  THen
combine generates this:

> (insn 6 3 13 2 (parallel [
>             (set (reg:DI 137)
>                 (sign_extract:DI (reg:DI 139 [ a ])
>                     (const_int 31 [0x1f])
>                     (const_int 0 [0])))
>             (clobber (scratch:DI))
>         ]) "j.c":10:14 333 {*extractdi3}
>      (expr_list:REG_DEAD (reg:DI 139 [ a ])
>         (nil)))
> (insn 13 6 14 2 (set (reg/i:DI 10 a0)
>         (ashift:DI (reg:DI 137)
>             (const_int 1 [0x1]))) "j.c":11:1 297 {ashldi3}
>      (expr_list:REG_DEAD (reg:DI 137)
>         (nil)))
Which is due to a define_insn_and_split mis-behaving a bit.

The first approach was to define an insn for the case where we left shift a
sign extracted bitfield where the sign bit of the bitfield gets shifted into
bit 31.  Theory being this might be a reasonably common occurrence and having a
pattern for it might be useful (and there's a similar pattern one could write
for a small number of zero extended fields getting shifted left as well).
That turns out to be a problem though as the sign extension is obfuscated
making it harder to track the state of the sign bits and thus harder to
eliminate later sign extensions.  Those regressions can be fixed, but doing so
requires the revamp of the sign/zero extension patterns to eliminate several of
the define_insn_and_splits.  Larger change than I really want to do right now.

We could also throttle back the most problematic define_insn_and_split.  It's
likely viable, though probably not the best use of time given my desire to
clean up the define_insn_and_splits, including this one.

We can also recognize this case and simplify it.  Essentially when we have
(ashift (sign_extract ...)) recognize the case when we're extracting a bitfield
starting at bit 0 and the bit field is shifted such that the sign bit of the
bitfield moves into bit position 7, 15 or 31.  In that case we can simplify it
to (sign_extend (ashift ...))

This patch takes the last of those three approaches.  Bootstrapped and
regression tested on x86_64, and riscv (BPI and Pioneer) as well as going
through all the embedded targets without regressions.  I was somewhat worried
about loongarch due to a pattern in its machine description, but the two tests
added with that pattern still pass, so it seems OK too.

PR target/123010
gcc/
* simplify-rtx.cc (simplify_binary_operation_1, case ASHIFT): Simplify
case where a left shift of the sign extracted field can be turned into
a sign extension of a left shift.

gcc/testsuite
* gcc.target/riscv/pr123010.c: New test.
gcc/simplify-rtx.cc
gcc/testsuite/gcc.target/riscv/pr123010.c [new file with mode: 0644]