The register_operand predicate can match subreg, then we'd have a subreg of subreg and it's invalid. Use lowpart_subreg to avoid the nested subreg.
gcc/ChangeLog: * config/loongarch/loongarch.md (crc_combine): Avoid nested subreg. gcc/testsuite/ChangeLog: * gcc.c-torture/compile/pr120708.c: New test. --- Bootstrapped and regtested on loongarch64-linux-gnu. Ok for trunk and releases/gcc-15? gcc/config/loongarch/loongarch.md | 3 ++- .../gcc.c-torture/compile/pr120708.c | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr120708.c diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md index a13398fdff4..8cf2ac90c64 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -4603,9 +4603,10 @@ (define_insn_and_split "*crc_combine" "&& true" [(set (match_dup 3) (match_dup 2)) (set (match_dup 0) - (unspec:SI [(match_dup 3) (subreg:SI (match_dup 1) 0)] CRC))] + (unspec:SI [(match_dup 3) (match_dup 1)] CRC))] { operands[3] = gen_reg_rtx (<MODE>mode); + operands[1] = lowpart_subreg (SImode, operands[1], DImode); }) ;; With normal or medium code models, if the only use of a pc-relative diff --git a/gcc/testsuite/gcc.c-torture/compile/pr120708.c b/gcc/testsuite/gcc.c-torture/compile/pr120708.c new file mode 100644 index 00000000000..9b37e608d7f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr120708.c @@ -0,0 +1,20 @@ +typedef __UINT8_TYPE__ uint8_t; +typedef __UINT32_TYPE__ uint32_t; + +typedef struct +{ + uint32_t dword[2]; + uint8_t byte[8]; +} reg64_t; +reg64_t TestF20F_opgd, TestF20F_oped; + +void +TestF20F () +{ + TestF20F_opgd.dword[0] ^= TestF20F_oped.byte[0]; + for (int i = 0; i < 8; i++) + if (TestF20F_opgd.dword[0] & 1) + TestF20F_opgd.dword[0] = TestF20F_opgd.dword[0] >> 1 ^ (uint32_t)2197175160UL; + else + TestF20F_opgd.dword[0] = TestF20F_opgd.dword[0] >> 1; +} -- 2.50.0