This is the mail archive of the 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]

Another missing TRULY_NOOP_TRUNCATION in extract_bit_field_1

According to rtl.texi, the semantics of a LHS paradoxical subreg are:

  Paradoxical @code{subreg}s can be used as both lvalues and rvalues.
  When used as an lvalue, the low-order bits of the source value
  are stored in @var{reg} and the high-order bits are discarded.

I think it follows directly from this that on !TRULY_NOOP_TRUNCATION targets,
the middle-end is not allowed to create LHS paradoxical subregs between
!TRULY_NOOP_TRUNCATION machine modes in general.  Of course, just like for
low-part subregs, if the middle-end has extra information about the value,
such that ignoring the upper bits creates a properly truncated value, it can
still use an LHS paradoxical subreg.

The ext(z)v expanders only come in word_mode so to extract an SI field
extract_bit_field_1 currently uses an LHS paradoxical subreg:

 (set (subreg:DI (reg:SI 196) 0) (zero_extract:DI (reg:DI 194)
                                   (const_int 32)
                                   (const_int 16)))

Specifically on MIPS64, if the MSB of the extracted value is set this will
create an incorrect SI value.  (SI values in registers need to be 64-bit

There is already code in extract_bit_field_1 to use convert_move to set target
(convert_extracted_bit_field->convert_to_mode->convert_move).  This is
currently used if the target is not a register and is in a different mode than
the mode the extraction.  After my change we'd also use this path for the

Bootstrapped and tested on x86_64-linux-gnu and on mips64octeon-linux-gnu
together with the fix from PR/37859.

The gcc.dg/torture/pr19683-1.c failure mentioned in is resolved after this

Next thing is to look at the MIPS extzv patterns to see if they need an update
after this patch.

OK to install?


	* expmed.c (extract_bit_field_1): Also use a temporary and
	convert_extracted_bit_field when the conversion from ext_mode to
	the target mode requires explicit truncation.

	* gcc.c-torture/execute/20081024-1.c: New test.

Index: expmed.c
--- expmed.c	(revision 141180)
+++ expmed.c	(working copy)
@@ -1516,7 +1516,13 @@ extract_bit_field_1 (rtx str_rtx, unsign
       if (GET_MODE (xtarget) != ext_mode)
-	  if (REG_P (xtarget))
+	  /* Don't use LHS paradoxical subreg if explicit truncation is needed
+	     between the mode of the extraction (word_mode) and the target
+	     mode.  Instead, create a temporary and use convert_move to set
+	     the target.  */
+	  if (REG_P (xtarget)
+					GET_MODE_BITSIZE (ext_mode)))
 	      xtarget = gen_lowpart (ext_mode, xtarget);
 	      if (GET_MODE_SIZE (ext_mode)
Index: testsuite/gcc.c-torture/execute/20081024-1.c
--- testsuite/gcc.c-torture/execute/20081024-1.c	(revision 0)
+++ testsuite/gcc.c-torture/execute/20081024-1.c	(revision 0)
@@ -0,0 +1,24 @@
+extern void abort (void);
+struct s
+  unsigned long long a:16;
+  unsigned long long b:32;
+  unsigned long long c:16;
+__attribute__ ((noinline)) unsigned
+f (struct s s, unsigned i)
+  return s.b == i;
+struct s s = { 1, 0x87654321u, 2};
+main ()
+  if (!f (s, 0x87654321u))
+    abort ();
+  return 0;

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