r141430 as a fix for PR37870 added a memory fallback to 
extract_bit_field_1 and another case punning through a larger integer
mode (as suggested by Ian).  That path is broken as it happily creates

(set (subreg:XF (reg:TI ..)) (...))

on i?86 when we optimize the added testcase

unsigned int
bar (long double x)
{
  union { struct { char a[8]; unsigned int b:7; } c; long double d; } u;
  u.d = x;
  return u.c.b;
}

on GIMPLE to

bar (long double x)
{
  unsigned int _3;
  <unnamed-unsigned:7> _4;

;;   basic block 2, loop depth 0
;;    pred:       ENTRY
  _4 = BIT_FIELD_REF <x_2(D), 7, 64>;
  _3 = (unsigned int) _4;
  return _3;


Bootstrapped and tested on x86_64-unknown-linux-gnu (also with -m32)
and the code replaced with a gcc_unreachable ().

I don't see how a subreg can be ever valid as it will be necessarily
converting to a non-integer mode of different size (otherwise 
int_mode_for_mode would have returned non-BLKmode).  I can't think
of a condition that would need to be satisfied where the subreg
would be valid either.

Ok for GCC 7?  (it'll be done as part of said GIMPLE optimization).

The testcase gcc.target/i386/pr37870.c will already ICE with that
patch, so no additional testcase.

Thanks,
Richard.

2016-04-04  Richard Biener  <rguent...@suse.de>

        PR middle-end/37870
        * expmed.c (extract_bit_field_1): Remove broken case
        using a wider MODE_INT mode.

Index: gcc/expmed.c
===================================================================
--- gcc/expmed.c        (revision 234708)
+++ gcc/expmed.c        (working copy)
@@ -1647,17 +1647,6 @@ extract_bit_field_1 (rtx str_rtx, unsign
            if (GET_CODE (op0) == SUBREG)
              op0 = force_reg (imode, op0);
          }
-       else if (REG_P (op0))
-         {
-           rtx reg, subreg;
-           imode = smallest_mode_for_size (GET_MODE_BITSIZE (GET_MODE (op0)),
-                                           MODE_INT);
-           reg = gen_reg_rtx (imode);
-           subreg = gen_lowpart_SUBREG (GET_MODE (op0), reg);
-           emit_move_insn (subreg, op0);
-           op0 = reg;
-           bitnum += SUBREG_BYTE (subreg) * BITS_PER_UNIT;
-         }
        else
          {
            HOST_WIDE_INT size = GET_MODE_SIZE (GET_MODE (op0));

Reply via email to