This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Another missing TRULY_NOOP_TRUNCATION in extract_bit_field_1
- From: Adam Nemet <anemet at caviumnetworks dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 24 Oct 2008 12:13:58 -0700
- Subject: 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
sign-extended.)
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
!TRULY_NOOP_TRUNCATION case.
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
http://gcc.gnu.org/ml/gcc-patches/2008-08/msg02334.html is resolved after this
patch.
Next thing is to look at the MIPS extzv patterns to see if they need an update
after this patch.
OK to install?
Adam
* 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.
testsuite/
* 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)
+ && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (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};
+
+int
+main ()
+{
+ if (!f (s, 0x87654321u))
+ abort ();
+ return 0;
+}