This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[Committed] store_bit_field: Handle paradoxical subregs properly
Hi Roger,
> On Wed, 19 Apr 2006, Andreas Krebbel wrote:
> > However gcc creates wrong code for it without:
> > http://gcc.gnu.org/ml/gcc-patches/2006-03/msg01793.html
>
> Ahh, sorry for the chicken and egg situation. I was wondering why
> it was taking a while to commit your change after the approval,
> but I'd forgotten about the patch interdependency on s390/s390x.
No problem. The delay was caused by one week vacation on my side.
> The first patch, the one cited above, is also OK for mainline, but
> now that the ICE is resolved it would be nice to add an execution
> test to the testsuite to confirm that the code generation problem is
> fixed and doesn't regress in future. A suitable execution test
> case is pre-approved, though you should post it to this list when
> you commit it.
Ok. I've committed the attached patch.
Bootstrapped on i686, s390 and s390x.
Bye,
-Andreas-
2006-04-25 Andreas Krebbel <krebbel1@de.ibm.com>
* expmed.c (store_bit_field): Handle paradoxical subregs on big endian
machines.
2006-04-25 Andreas Krebbel <krebbel1@de.ibm.com>
* gcc.dg/20060425-1.c: New testcase.
Index: gcc/expmed.c
===================================================================
*** gcc/expmed.c.orig 2006-03-12 19:44:58.000000000 +0100
--- gcc/expmed.c 2006-04-25 09:35:50.000000000 +0200
*************** store_bit_field (rtx str_rtx, unsigned H
*** 363,369 ****
meaningful at a much higher level; when structures are copied
between memory and regs, the higher-numbered regs
always get higher addresses. */
! bitnum += SUBREG_BYTE (op0) * BITS_PER_UNIT;
op0 = SUBREG_REG (op0);
}
--- 363,387 ----
meaningful at a much higher level; when structures are copied
between memory and regs, the higher-numbered regs
always get higher addresses. */
! int inner_mode_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)));
! int outer_mode_size = GET_MODE_SIZE (GET_MODE (op0));
!
! byte_offset = 0;
!
! /* Paradoxical subregs need special handling on big endian machines. */
! if (SUBREG_BYTE (op0) == 0 && inner_mode_size < outer_mode_size)
! {
! int difference = inner_mode_size - outer_mode_size;
!
! if (WORDS_BIG_ENDIAN)
! byte_offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
! if (BYTES_BIG_ENDIAN)
! byte_offset += difference % UNITS_PER_WORD;
! }
! else
! byte_offset = SUBREG_BYTE (op0);
!
! bitnum += byte_offset * BITS_PER_UNIT;
op0 = SUBREG_REG (op0);
}
Index: gcc/testsuite/gcc.dg/20060425-1.c
===================================================================
*** /dev/null 1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/20060425-1.c 2006-04-25 10:04:14.000000000 +0200
***************
*** 0 ****
--- 1,38 ----
+ /* { dg-do run } */
+ /* { dg-options "-O1" } */
+
+ /* This failed because if conversion didn't handle insv patterns properly. */
+
+ void abort (void);
+
+ union y
+ {
+ int a;
+ unsigned short b;
+ };
+
+ void __attribute__ ((noinline))
+ bar (unsigned short u, union y v)
+ {
+ if (u != 1)
+ abort ();
+ }
+
+ void __attribute__ ((noinline))
+ foo (int check)
+ {
+ union y x;
+
+ if (check != 0)
+ x.b = 1;
+ else
+ x.b = 2;
+ bar (x.b, x);
+ }
+
+ int
+ main ()
+ {
+ foo (1);
+ return 0;
+ }