Hi: --- OK, I think sth is amiss here upthread. insv/extv do look like they are designed to work on integer modes (but docs do not say anything about this here). In fact the caller of extract_bit_field_using_extv is named extract_integral_bit_field. Of course nothing seems to check what kind of modes we're dealing with, but we're for example happily doing expand_shift in 'mode'. In the extract_integral_bit_field call 'mode' is some integer mode and op0 is HFmode? From the above I get it's the other way around? In that case we should wrap the call to extract_integral_bit_field, extracting in an integer mode with the same size as 'mode' and then converting the result as (subreg:HF (reg:HI ...)). --- This is a separate patch as a follow up of upper comments. gcc/ChangeLog:
* expmed.c (extract_bit_field_1): Wrap the call to extract_integral_bit_field, extracting in an integer mode with the same size as 'tmode' and then converting the result as (subreg:tmode (reg:imode)). gcc/testsuite/ChangeLog: * gcc.target/i386/float16-5.c: New test. --- gcc/expmed.c | 19 +++++++++++++++++++ gcc/testsuite/gcc.target/i386/float16-5.c | 12 ++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/float16-5.c diff --git a/gcc/expmed.c b/gcc/expmed.c index 3143f38e057..72790693ef0 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -1850,6 +1850,25 @@ extract_bit_field_1 (rtx str_rtx, poly_uint64 bitsize, poly_uint64 bitnum, op0_mode = opt_scalar_int_mode (); } + /* Make sure we are playing with integral modes. Pun with subregs + if we aren't. When tmode is HFmode, op0 is SImode, there will be ICE + in extract_integral_bit_field. */ + if (int_mode_for_mode (tmode).exists (&imode) + && imode != tmode + && imode != GET_MODE (op0)) + { + rtx ret = extract_integral_bit_field (op0, op0_mode, + bitsize.to_constant (), + bitnum.to_constant (), unsignedp, + NULL, imode, imode, + reverse, fallback_p); + gcc_assert (ret); + + if (!REG_P (ret)) + ret = force_reg (imode, ret); + return gen_lowpart_SUBREG (tmode, ret); + } + /* It's possible we'll need to handle other cases here for polynomial bitnum and bitsize. */ diff --git a/gcc/testsuite/gcc.target/i386/float16-5.c b/gcc/testsuite/gcc.target/i386/float16-5.c new file mode 100644 index 00000000000..ebc0af1490b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/float16-5.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-msse2 -O2" } */ +_Float16 +foo (int a) +{ + union { + int a; + _Float16 b; + }c; + c.a = a; + return c.b; +} -- 2.27.0