This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Patch to fix unaligned access in float->union assignment
- From: Richard Sandiford <rsandifo at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: 18 Nov 2002 10:18:03 +0000
- Subject: Patch to fix unaligned access in float->union assignment
This patch fixes an unaligned access at -O1 when storing an
SFmode MEM into a DImode union. It seemed to be caused by this
change to store_bit_field:
*************** store_bit_field (str_rtx, bitsize, bitnu
*** 519,530 ****
corresponding size. This can occur on a machine with 64 bit registers
that uses SFmode for float. This can also occur for unaligned float
structure fields. */
! if (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT)
! {
! if (GET_CODE (value) != REG)
! value = copy_to_reg (value);
! value = gen_rtx_SUBREG (word_mode, value, 0);
! }
/* Now OFFSET is nonzero only if OP0 is memory
and is therefore always measured in bytes. */
--- 524,532 ----
corresponding size. This can occur on a machine with 64 bit registers
that uses SFmode for float. This can also occur for unaligned float
structure fields. */
! if (GET_MODE_CLASS (GET_MODE (value)) != MODE_INT
! && GET_MODE_CLASS (GET_MODE (value)) != MODE_PARTIAL_INT)
! value = gen_lowpart (word_mode, value);
/* Now OFFSET is nonzero only if OP0 is memory
and is therefore always measured in bytes. */
which was made to handle CONCATs. The function used to force
the MEM into a register and then access it using a paradoxical
DImode subreg. Now it adjusts the MEM to DImode instead.
Is it OK to reinstate the copy_to_reg() for MEMs, or is
the bug elsewhere?
Tested on sh64-elf, no regressions. Fixes the attached test case.
Richard
* expmed.c (store_bit_field): Move memory values into registers
before obtaining their word_mode lowpart.
Index: expmed.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expmed.c,v
retrieving revision 1.125
diff -c -d -p -F^[(a-zA-Z0-9_^#] -r1.125 expmed.c
*** expmed.c 31 Oct 2002 20:43:07 -0000 1.125
--- expmed.c 15 Nov 2002 16:20:24 -0000
*************** store_bit_field (str_rtx, bitsize, bitnu
*** 535,541 ****
structure fields. */
if (GET_MODE_CLASS (GET_MODE (value)) != MODE_INT
&& GET_MODE_CLASS (GET_MODE (value)) != MODE_PARTIAL_INT)
! value = gen_lowpart (word_mode, value);
/* Now OFFSET is nonzero only if OP0 is memory
and is therefore always measured in bytes. */
--- 535,545 ----
structure fields. */
if (GET_MODE_CLASS (GET_MODE (value)) != MODE_INT
&& GET_MODE_CLASS (GET_MODE (value)) != MODE_PARTIAL_INT)
! {
! if (GET_CODE (value) == MEM)
! value = copy_to_reg (value);
! value = gen_lowpart (word_mode, value);
! }
/* Now OFFSET is nonzero only if OP0 is memory
and is therefore always measured in bytes. */
*** /dev/null Tue Nov 14 21:44:43 2000
--- testsuite/gcc.c-torture/execute/20021112-1.c Fri Nov 15 16:19:38 2002
***************
*** 0 ****
--- 1,18 ----
+ union u { float f; double d; };
+ float f[2] = { 1.0f, 2.0f };
+
+ union u foo (float *pf)
+ {
+ union u u;
+ u.f = *pf;
+ return u;
+ }
+
+ int main ()
+ {
+ if (foo (&f[0]).f != 1.0f)
+ abort ();
+ if (foo (&f[1]).f != 2.0f)
+ abort ();
+ exit (0);
+ }