OSDN Git Service

* emit-rtl.c (widen_memory_access): New.
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 12 Dec 2001 02:47:55 +0000 (02:47 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 12 Dec 2001 02:47:55 +0000 (02:47 +0000)
        * expr.h (widen_memory_access): Declare it.
        * config/alpha/alpha.c (get_aligned_mem): Use it.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@47913 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/alpha/alpha.c
gcc/emit-rtl.c
gcc/expr.h

index 981bcc3..1c6b253 100644 (file)
@@ -1,5 +1,11 @@
 2001-12-11  Richard Henderson  <rth@redhat.com>
 
+       * emit-rtl.c (widen_memory_access): New.
+       * expr.h (widen_memory_access): Declare it.
+       * config/alpha/alpha.c (get_aligned_mem): Use it.
+
+2001-12-11  Richard Henderson  <rth@redhat.com>
+
        * combine.c (simplify_shift_const): Move SHIFT_COUNT_TRUNCATED
        simplification above out of range check.
 
index 66ed079..1120bfb 100644 (file)
@@ -1822,12 +1822,8 @@ get_aligned_mem (ref, paligned_mem, pbitnum)
   if (GET_CODE (base) == PLUS)
     offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
 
-  *paligned_mem = gen_rtx_MEM (SImode, plus_constant (base, offset & ~3));
-  MEM_COPY_ATTRIBUTES (*paligned_mem, ref);
-
-  /* Sadly, we cannot use alias sets here because we may overlap other
-     data in a different alias set.  */
-  set_mem_alias_set (*paligned_mem, 0);
+  *paligned_mem
+    = widen_memory_access (ref, SImode, (offset & ~3) - offset);
 
   if (WORDS_BIG_ENDIAN)
     *pbitnum = GEN_INT (32 - (GET_MODE_BITSIZE (GET_MODE (ref))
index 4238b8c..7c7dfd3 100644 (file)
@@ -2072,6 +2072,84 @@ replace_equiv_address_nv (memref, addr)
 {
   return change_address_1 (memref, VOIDmode, addr, 0);
 }
+
+/* Return a memory reference like MEMREF, but with its mode widened to
+   MODE and offset by OFFSET.  This would be used by targets that e.g.
+   cannot issue QImode memory operations and have to use SImode memory
+   operations plus masking logic.  */
+
+rtx
+widen_memory_access (memref, mode, offset)
+     rtx memref;
+     enum machine_mode mode;
+     HOST_WIDE_INT offset;
+{
+  rtx new = adjust_address_1 (memref, mode, offset, 1, 1);
+  tree expr = MEM_EXPR (new);
+  rtx memoffset = MEM_OFFSET (new);
+  unsigned int size = GET_MODE_SIZE (mode);
+
+  /* If we don't know what offset we were at within the expression, then
+     we can't know if we've overstepped the bounds.  */
+  if (! memoffset && offset != 0)
+    expr = NULL_TREE;
+
+  while (expr)
+    {
+      if (TREE_CODE (expr) == COMPONENT_REF)
+       {
+         tree field = TREE_OPERAND (expr, 1);
+
+         if (! DECL_SIZE_UNIT (field))
+           {
+             expr = NULL_TREE;
+             break;
+           }
+
+         /* Is the field at least as large as the access?  If so, ok,
+            otherwise strip back to the containing structure.  */
+         if (compare_tree_int (DECL_SIZE_UNIT (field), size) >= 0
+             && INTVAL (memoffset) >= 0)
+           break;
+
+         if (! host_integerp (DECL_FIELD_OFFSET (field), 1))
+           {
+             expr = NULL_TREE;
+             break;
+           }
+
+         expr = TREE_OPERAND (expr, 0);
+         memoffset = (GEN_INT (INTVAL (memoffset)
+                      + tree_low_cst (DECL_FIELD_OFFSET (field), 1)
+                      + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+                         / BITS_PER_UNIT)));
+       }
+      /* Similarly for the decl.  */
+      else if (DECL_P (expr)
+              && DECL_SIZE_UNIT (expr)
+              && compare_tree_int (DECL_SIZE_UNIT (expr), size) >= 0
+              && (! memoffset || INTVAL (memoffset) >= 0))
+       break;
+      else
+       {
+         /* The widened memory access overflows the expression, which means
+            that it could alias another expression.  Zap it.  */
+         expr = NULL_TREE;
+         break;
+       }
+    }
+
+  if (! expr)
+    memoffset = NULL_RTX;
+
+  /* The widened memory may alias other stuff, so zap the alias set.  */
+  /* ??? Maybe use get_alias_set on any remaining expression.  */
+
+  MEM_ATTRS (new) = get_mem_attrs (0, expr, memoffset, GEN_INT (size),
+                                  MEM_ALIGN (new), mode);
+
+  return new;
+}
 \f
 /* Return a newly created CODE_LABEL rtx with a unique label number.  */
 
index 192733b..e5b488a 100644 (file)
@@ -646,6 +646,10 @@ extern rtx replace_equiv_address PARAMS ((rtx, rtx));
 /* Likewise, but the reference is not required to be valid.  */
 extern rtx replace_equiv_address_nv PARAMS ((rtx, rtx));
 
+/* Return a memory reference like MEMREF, but with its mode widened to
+   MODE and adjusted by OFFSET.  */
+extern rtx widen_memory_access PARAMS ((rtx, enum machine_mode, HOST_WIDE_INT));
+
 /* Return a memory reference like MEMREF, but which is known to have a
    valid address.  */
 extern rtx validize_mem PARAMS ((rtx));