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