expand: Fix ICE in store_bit_field_using_insv [PR93235]
authorJakub Jelinek <jakub@redhat.com>
Thu, 4 Mar 2021 18:38:08 +0000 (19:38 +0100)
committerJakub Jelinek <jakub@redhat.com>
Thu, 4 Mar 2021 18:38:08 +0000 (19:38 +0100)
The following testcase ICEs on aarch64.  The problem is that
op0 is (subreg:HI (reg:HF ...) 0) and because we can't create a SUBREG of a
SUBREG and aarch64 doesn't have HImode insv, only SImode insv,
store_bit_field_using_insv tries to create (subreg:SI (reg:HF ...) 0)
which is not valid for the target and so gen_rtx_SUBREG ICEs.

The following patch fixes it by punting if the to be created SUBREG
doesn't validate, callers of store_bit_field_using_insv can handle
the fallback.

2021-03-04  Jakub Jelinek  <jakub@redhat.com>

PR middle-end/93235
* expmed.c (store_bit_field_using_insv): Return false of xop0 is a
SUBREG and a SUBREG to op_mode can't be created.

* gcc.target/aarch64/pr93235.c: New test.

gcc/expmed.c
gcc/testsuite/gcc.target/aarch64/pr93235.c [new file with mode: 0644]

index d30948e..1fb6317 100644 (file)
@@ -629,9 +629,16 @@ store_bit_field_using_insv (const extraction_insn *insv, rtx op0,
       /* If xop0 is a register, we need it in OP_MODE
         to make it acceptable to the format of insv.  */
       if (GET_CODE (xop0) == SUBREG)
-       /* We can't just change the mode, because this might clobber op0,
-          and we will need the original value of op0 if insv fails.  */
-       xop0 = gen_rtx_SUBREG (op_mode, SUBREG_REG (xop0), SUBREG_BYTE (xop0));
+       {
+         /* If such a SUBREG can't be created, give up.  */
+         if (!validate_subreg (op_mode, GET_MODE (SUBREG_REG (xop0)),
+                               SUBREG_REG (xop0), SUBREG_BYTE (xop0)))
+           return false;
+         /* We can't just change the mode, because this might clobber op0,
+            and we will need the original value of op0 if insv fails.  */
+         xop0 = gen_rtx_SUBREG (op_mode, SUBREG_REG (xop0),
+                                SUBREG_BYTE (xop0));
+       }
       if (REG_P (xop0) && GET_MODE (xop0) != op_mode)
        xop0 = gen_lowpart_SUBREG (op_mode, xop0);
     }
diff --git a/gcc/testsuite/gcc.target/aarch64/pr93235.c b/gcc/testsuite/gcc.target/aarch64/pr93235.c
new file mode 100644 (file)
index 0000000..829ae13
--- /dev/null
@@ -0,0 +1,12 @@
+/* PR middle-end/93235 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-strict-aliasing" } */
+
+struct sfp16 { __fp16 f; };
+struct sfp16
+foo (short x)
+{
+  struct sfp16 a;
+  *(short*)&a.f = x;
+  return a;
+}