re PR middle-end/37870 (ICE in extract_bit_field_1)
authorJakub Jelinek <jakub@redhat.com>
Wed, 29 Oct 2008 16:07:39 +0000 (17:07 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 29 Oct 2008 16:07:39 +0000 (17:07 +0100)
PR middle-end/37870
* expmed.c (extract_bit_field_1): If int_mode_for_mode returns
BLKmode for non-memory, convert using a wider MODE_INT mode
or through memory.

* gcc.target/i386/pr37870.c: New test.

From-SVN: r141430

gcc/ChangeLog
gcc/expmed.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr37870.c [new file with mode: 0644]

index 3168826c8ced5d1b14458791360595fdc025dcf5..44836d5db652605751dbf04f7e4525155d5f6b47 100644 (file)
@@ -1,5 +1,10 @@
 2008-10-29  Jakub Jelinek  <jakub@redhat.com>
 
+       PR middle-end/37870
+       * expmed.c (extract_bit_field_1): If int_mode_for_mode returns
+       BLKmode for non-memory, convert using a wider MODE_INT mode
+       or through memory.
+
        PR middle-end/37913
        * tree-cfgcleanup.c (split_bbs_on_noreturn_calls): Only split bbs
        that haven't been removed yet.
index 5e8d7f30324ed814d9928bba6b6ae4138e9bb59a..0c7e611e188a091bfd495e1a44c7b81e593097fe 100644 (file)
@@ -1,7 +1,7 @@
 /* Medium-level subroutines: convert bit-field store and extract
    and shifts, multiplies and divides to rtl instructions.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -1278,9 +1278,8 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       {
        if (MEM_P (op0))
          op0 = adjust_address (op0, imode, 0);
-       else
+       else if (imode != BLKmode)
          {
-           gcc_assert (imode != BLKmode);
            op0 = gen_lowpart (imode, op0);
 
            /* If we got a SUBREG, force it into a register since we
@@ -1288,6 +1287,24 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
            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
+         {
+           rtx mem = assign_stack_temp (GET_MODE (op0),
+                                        GET_MODE_SIZE (GET_MODE (op0)), 0);
+           emit_move_insn (mem, op0);
+           op0 = adjust_address (mem, BLKmode, 0);
+         }
       }
   }
 
index 2a863f3cb47b12d88793e0d638be6dfa7ce9efdb..070840147c82a0cc06eba745796dd0f2a479a729 100644 (file)
@@ -1,3 +1,8 @@
+2008-10-29  Jakub Jelinek  <jakub@redhat.com>
+
+       PR middle-end/37870
+       * gcc.target/i386/pr37870.c: New test.
+
 2008-10-29  Manuel López-Ibáñez  <manu@gcc.gnu.org>
 
        PR c++/26997
diff --git a/gcc/testsuite/gcc.target/i386/pr37870.c b/gcc/testsuite/gcc.target/i386/pr37870.c
new file mode 100644 (file)
index 0000000..19cfb20
--- /dev/null
@@ -0,0 +1,29 @@
+/* PR middle-end/37870 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+unsigned int
+foo (long double x)
+{
+  struct { char a[8]; unsigned int b:7; } c;
+  __builtin_memcpy (&c, &x, sizeof (c));
+  return c.b;
+}
+
+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;
+}
+
+int
+main (void)
+{
+  if (foo (1.245L) != bar (1.245L)
+      || foo (245.67L) != bar (245.67L)
+      || foo (0.00567L) != bar (0.00567L))
+    __builtin_abort ();
+  return 0;
+}