expand: Fix ICE in store_bit_field_using_insv [PR93235]

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.
This commit is contained in:
Jakub Jelinek 2021-03-04 19:38:08 +01:00
parent 87dc3d0d36
commit 0ad6de3883
2 changed files with 22 additions and 3 deletions

View 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)
{
/* 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));
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);
}

View File

@ -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;
}