summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2001-12-12 02:47:55 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2001-12-12 02:47:55 +0000
commit8259ab073a26c51edd402611be081ae3af277cb9 (patch)
treed0c847cd9f0510c842ba5ecc5cdd2721a76aa489
parentf095ddef663b35d7eafdbbf7c26423775eefc608 (diff)
downloadgcc-8259ab073a26c51edd402611be081ae3af277cb9.tar.gz
* emit-rtl.c (widen_memory_access): New.
* 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
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/config/alpha/alpha.c8
-rw-r--r--gcc/emit-rtl.c78
-rw-r--r--gcc/expr.h4
4 files changed, 90 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 981bcc30aa5..1c6b2539b18 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 66ed07947f7..1120bfb9599 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -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))
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 4238b8c7762..7c7dfd3f172 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -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;
+}
/* Return a newly created CODE_LABEL rtx with a unique label number. */
diff --git a/gcc/expr.h b/gcc/expr.h
index 192733b9a5c..e5b488aec33 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -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));