This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: PATCH: Handle ZERO_EXTEND offsettable address
> This patch also handles SIGN_EXTEND. Tested on Linux/x32. OK to
> install?
I'd cautious here, that's uncharted territory and the SIGN_EXTEND case isn't
covered by your testing.
> 2012-11-10 H.J. Lu <hongjiu.lu@intel.com>
>
> PR middle-end/55247
> PR middle-end/55259
> * emit-rtl.c (adjust_address_1): Handle ZERO_EXTEND and
> SIGN_EXTEND.
The new transformation is:
(zero_extend ADDR) + CONST_INT -> (zero_extend (ADDR + CONST_INT))
but in convert_memory_address_addr_space we do the opposite:
(zero_extend (ADDR + CONST_INT)) -> (zero_extend ADDR) + CONST_INT
Which one is the canonical form in the end?
> @@ -2109,6 +2111,20 @@ adjust_address_1 (rtx memref, enum machine_mode mode,
> HOST_WIDE_INT offset, addr = gen_rtx_LO_SUM (address_mode, XEXP (addr, 0),
> plus_constant (address_mode,
> XEXP (addr, 1), offset));
> + /* We permute zero/sign-extension and addition operation only if
> + converting the constant does not change it. */
> + else if ((GET_CODE (addr) == ZERO_EXTEND
> + || GET_CODE (addr) == SIGN_EXTEND)
> + && (x = GEN_INT (offset),
> + x == convert_memory_address_addr_space (address_mode,
> + x,
> + attrs.addrspace)))
> + {
> + enum rtx_code code = GET_CODE (addr);
> + addr = XEXP (addr, 0);
> + addr = plus_constant (GET_MODE (addr), addr, offset);
> + addr = gen_rtx_fmt_e (code, address_mode, addr);
> + }
You need to test the truncation here, not the extension. Moreover, the
transformation is valid only under a no-overflow assumption, so I think we
need to explicitly request pointer_mode (or else restrict the transformation
to small offsets).
> diff --git a/gcc/recog.c b/gcc/recog.c
> index ee68e30..a916ef6 100644
> --- a/gcc/recog.c
> +++ b/gcc/recog.c
> @@ -1934,15 +1934,22 @@ int
> offsettable_address_addr_space_p (int strictp, enum machine_mode mode, rtx
> y, addr_space_t as)
> {
> - enum rtx_code ycode = GET_CODE (y);
> + enum rtx_code ycode;
> rtx z;
> - rtx y1 = y;
> + rtx y1;
> rtx *y2;
> int (*addressp) (enum machine_mode, rtx, addr_space_t) =
> (strictp ? strict_memory_address_addr_space_p
>
> : memory_address_addr_space_p);
>
> unsigned int mode_sz = GET_MODE_SIZE (mode);
>
> + /* Allow zero-extended or sign-extended address. */
> + if (GET_CODE (y) == ZERO_EXTEND || GET_CODE (y) == SIGN_EXTEND)
> + y = XEXP (y, 0);
> +
> + ycode = GET_CODE (y);
> + y1 = y;
> +
> if (CONSTANT_ADDRESS_P (y))
> return 1;
That's not fully correct since you don't test the final form of the address.
You instead need to duplicate the adjust_address_1 change here:
/* The offset added here is chosen as the maximum offset that
any instruction could need to add when operating on something
of the specified mode. We assume that if Y and Y+c are
valid addresses then so is Y+d for all 0<d<c. adjust_address will
go inside a LO_SUM here, so we do so as well. */
if (GET_CODE (y) == LO_SUM
&& mode != BLKmode
&& mode_sz <= GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT)
z = gen_rtx_LO_SUM (GET_MODE (y), XEXP (y, 0),
plus_constant (GET_MODE (y), XEXP (y, 1),
mode_sz - 1));
else
z = plus_constant (GET_MODE (y), y, mode_sz - 1);
Adjusted patch attached.
--
Eric Botcazou
Index: emit-rtl.c
===================================================================
--- emit-rtl.c (revision 193322)
+++ emit-rtl.c (working copy)
@@ -2071,10 +2071,12 @@ adjust_address_1 (rtx memref, enum machi
rtx new_rtx;
enum machine_mode address_mode;
int pbits;
- struct mem_attrs attrs, *defattrs;
+ struct mem_attrs attrs = *get_mem_attrs (memref), *defattrs;
unsigned HOST_WIDE_INT max_align;
-
- attrs = *get_mem_attrs (memref);
+#ifdef POINTERS_EXTEND_UNSIGNED
+ enum machine_mode pointer_mode
+ = targetm.addr_space.pointer_mode (attrs.addrspace);
+#endif
/* If there are no changes, just return the original memory reference. */
if (mode == GET_MODE (memref) && !offset
@@ -2109,6 +2111,18 @@ adjust_address_1 (rtx memref, enum machi
addr = gen_rtx_LO_SUM (address_mode, XEXP (addr, 0),
plus_constant (address_mode,
XEXP (addr, 1), offset));
+#ifdef POINTERS_EXTEND_UNSIGNED
+ /* If MEMREF is a ZERO_EXTEND from pointer_mode and the offset is valid
+ in that mode, we merge it into the ZERO_EXTEND. We take advantage of
+ the fact that pointers are not allowed to overflow. */
+ else if (POINTERS_EXTEND_UNSIGNED > 0
+ && GET_CODE (addr) == ZERO_EXTEND
+ && GET_MODE (XEXP (addr, 0)) == pointer_mode
+ && trunc_int_for_mode (offset, pointer_mode) == offset)
+ addr = gen_rtx_ZERO_EXTEND (address_mode,
+ plus_constant (pointer_mode,
+ XEXP (addr, 0), offset));
+#endif
else
addr = plus_constant (address_mode, addr, offset);
}
Index: recog.c
===================================================================
--- recog.c (revision 193322)
+++ recog.c (working copy)
@@ -1943,6 +1943,9 @@ offsettable_address_addr_space_p (int st
(strictp ? strict_memory_address_addr_space_p
: memory_address_addr_space_p);
unsigned int mode_sz = GET_MODE_SIZE (mode);
+#ifdef POINTERS_EXTEND_UNSIGNED
+ enum machine_mode pointer_mode = targetm.addr_space.pointer_mode (as);
+#endif
if (CONSTANT_ADDRESS_P (y))
return 1;
@@ -1992,6 +1995,15 @@ offsettable_address_addr_space_p (int st
z = gen_rtx_LO_SUM (GET_MODE (y), XEXP (y, 0),
plus_constant (GET_MODE (y), XEXP (y, 1),
mode_sz - 1));
+#ifdef POINTERS_EXTEND_UNSIGNED
+ /* Likewise for a ZERO_EXTEND from pointer_mode. */
+ else if (POINTERS_EXTEND_UNSIGNED > 0
+ && GET_CODE (y) == ZERO_EXTEND
+ && GET_MODE (XEXP (y, 0)) == pointer_mode)
+ z = gen_rtx_ZERO_EXTEND (GET_MODE (y),
+ plus_constant (pointer_mode, XEXP (y, 0),
+ mode_sz - 1));
+#endif
else
z = plus_constant (GET_MODE (y), y, mode_sz - 1);