re PR target/24178 (generates code that produces unaligned access exceptions)
authorRichard Henderson <rth@redhat.com>
Wed, 2 Nov 2005 18:20:07 +0000 (10:20 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Wed, 2 Nov 2005 18:20:07 +0000 (10:20 -0800)
        PR target/24178
        * config/alpha/alpha.c (get_aligned_mem): Honor alignment given
        by MEM_ALIGN.

From-SVN: r106388

gcc/ChangeLog
gcc/config/alpha/alpha.c
gcc/testsuite/gcc.target/alpha/pr24178.c [new file with mode: 0644]

index e6d1b9c6b5b1cc09aa992db21a624cd4fd83ad55..f2b2f54e377249d7cb67073d002a2c01cd5852a9 100644 (file)
@@ -1,3 +1,9 @@
+2005-11-02  Richard Henderson  <rth@redhat.com>
+
+       PR target/24178
+       * config/alpha/alpha.c (get_aligned_mem): Honor alignment given
+       by MEM_ALIGN.
+
 2005-11-01  Richard Henderson  <rth@redhat.com>
 
        PR 21518
index 89b292c3d7f82fcc48ceddb202135a964e6c2467..ec53778ce1837488caf45cde777a3eb9b34d816f 100644 (file)
@@ -1487,7 +1487,7 @@ void
 get_aligned_mem (rtx ref, rtx *paligned_mem, rtx *pbitnum)
 {
   rtx base;
-  HOST_WIDE_INT offset = 0;
+  HOST_WIDE_INT disp, offset;
 
   gcc_assert (GET_CODE (ref) == MEM);
 
@@ -1495,23 +1495,34 @@ get_aligned_mem (rtx ref, rtx *paligned_mem, rtx *pbitnum)
       && ! memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
     {
       base = find_replacement (&XEXP (ref, 0));
-
       gcc_assert (memory_address_p (GET_MODE (ref), base));
     }
   else
     base = XEXP (ref, 0);
 
   if (GET_CODE (base) == PLUS)
-    offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
+    disp = INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
+  else
+    disp = 0;
+
+  /* Find the byte offset within an aligned word.  If the memory itself is
+     claimed to be aligned, believe it.  Otherwise, aligned_memory_operand
+     will have examined the base register and determined it is aligned, and
+     thus displacements from it are naturally alignable.  */
+  if (MEM_ALIGN (ref) >= 32)
+    offset = 0;
+  else
+    offset = disp & 3;
 
-  *paligned_mem
-    = widen_memory_access (ref, SImode, (offset & ~3) - offset);
+  /* Access the entire aligned word.  */
+  *paligned_mem = widen_memory_access (ref, SImode, -offset);
 
+  /* Convert the byte offset within the word to a bit offset.  */
   if (WORDS_BIG_ENDIAN)
-    *pbitnum = GEN_INT (32 - (GET_MODE_BITSIZE (GET_MODE (ref))
-                             + (offset & 3) * 8));
+    offset = 32 - (GET_MODE_BITSIZE (GET_MODE (ref)) + offset * 8);
   else
-    *pbitnum = GEN_INT ((offset & 3) * 8);
+    offset *= 8;
+  *pbitnum = GEN_INT (offset);
 }
 
 /* Similar, but just get the address.  Handle the two reload cases.
diff --git a/gcc/testsuite/gcc.target/alpha/pr24178.c b/gcc/testsuite/gcc.target/alpha/pr24178.c
new file mode 100644 (file)
index 0000000..0a31aa7
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcpu=ev4" } */
+
+struct S {
+    long l;
+    unsigned char c;
+};
+unsigned long f(unsigned char *p10) {
+    struct S *p = (struct S *) (p10 + 10);
+    return p->c;
+}
+
+/* { dg-final { scan-assembler "ldl.*,18\\(" } } */