This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR37870, ICE in extract_bit_field_1 (take 2)


On Fri, Oct 24, 2008 at 08:13:47AM -0700, Ian Lance Taylor wrote:
> Ian Lance Taylor <iant@google.com> writes:
> 
> > We are not supposed to take a subreg of a floating point mode.  We
> > currently permit word_mode subregs of a floating point value, which is
> > probably why your patch works.  But we want to get away from that.
> > See validate_subeg.  Conceptually this is because machines with
> > separate floating point registers generally don't have access to the
> > individual words in the register, so we wind up forcing the value into
> > memory anyhow.
> >
> > The right choice here may be to somehow push the value into memory.
> 
> Or, if there is a larger integer mode, copy the value into a new
> register with that mode.

Like this?  Tested on x86_64-linux.

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.

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

--- gcc/expmed.c.jj	2008-10-07 23:01:42.000000000 +0200
+++ gcc/expmed.c	2008-10-29 15:45:14.000000000 +0100
@@ -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, unsign
       {
 	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, 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
+	  {
+	    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);
+	  }
       }
   }
 
--- gcc/testsuite/gcc.target/i386/pr37870.c.jj	2008-10-29 15:46:34.000000000 +0100
+++ gcc/testsuite/gcc.target/i386/pr37870.c	2008-10-29 15:35:22.000000000 +0100
@@ -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;
+}


	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]