This patch fixes the original problem that HJL was having with x32 in
PR 47727, it is more constraint than HJL's patch only care about what
is happening inside a CONST;  if we allow it for other cases,
the RTL and generated code is incorrect as it does not have the needed
zero extend.  This allows ILP32 to work correctlya and allows &a + 2 to
be still generated correctly when doing a convert_memory_address_addr_space.


OK?  Bootstrapped and tested on x86_64-linux-gnu (though not with x32 but
visually looked at the failing testcase with a much older compiler).
Also tested on aarch64-linux-gnu with no regressions and also fixing ld.so
for ILP32.

Thanks,
Andrew Pinski

ChangeLog:
        * explow.c (convert_memory_address_addr_space): Rename to ...
        (convert_memory_address_addr_space_1): This.  Add in_const argument.
        Inside a CONST RTL, permute the conversion and addition of constant
        for zero and sign extended pointers.
        (convert_memory_address_addr_space): New function.


---
 gcc/explow.c |   40 ++++++++++++++++++++++++++++------------
 1 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/gcc/explow.c b/gcc/explow.c
index eb7dc85..64017a0 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -310,11 +310,13 @@ break_out_memory_refs (rtx x)
    an address in the address space's address mode, or vice versa (TO_MODE says
    which way).  We take advantage of the fact that pointers are not allowed to
    overflow by commuting arithmetic operations over conversions so that address
-   arithmetic insns can be used.  */
+   arithmetic insns can be used. IN_CONST is true if this conversion is inside
+   a CONST.  */
 
-rtx
-convert_memory_address_addr_space (enum machine_mode to_mode ATTRIBUTE_UNUSED,
-                                  rtx x, addr_space_t as ATTRIBUTE_UNUSED)
+static rtx
+convert_memory_address_addr_space_1 (enum machine_mode to_mode 
ATTRIBUTE_UNUSED,
+                                    rtx x, addr_space_t as ATTRIBUTE_UNUSED,
+                                    bool in_const)
 {
 #ifndef POINTERS_EXTEND_UNSIGNED
   gcc_assert (GET_MODE (x) == to_mode || GET_MODE (x) == VOIDmode);
@@ -370,8 +372,8 @@ convert_memory_address_addr_space (enum machine_mode 
to_mode ATTRIBUTE_UNUSED,
 
     case CONST:
       return gen_rtx_CONST (to_mode,
-                           convert_memory_address_addr_space
-                             (to_mode, XEXP (x, 0), as));
+                           convert_memory_address_addr_space_1
+                             (to_mode, XEXP (x, 0), as, true));
       break;
 
     case PLUS:
@@ -381,16 +383,18 @@ convert_memory_address_addr_space (enum machine_mode 
to_mode ATTRIBUTE_UNUSED,
         does not change it or if one operand is a constant and we are
         using a ptr_extend instruction  (POINTERS_EXTEND_UNSIGNED < 0).
         We can always safely permute them if we are making the address
-        narrower.  */
+        narrower. Inside a CONST RTL, this is safe for both pointers
+        zero or sign extended as pointers cannot wrap. */
       if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode)
          || (GET_CODE (x) == PLUS
              && CONST_INT_P (XEXP (x, 1))
-             && (XEXP (x, 1) == convert_memory_address_addr_space
-                                  (to_mode, XEXP (x, 1), as)
-                 || POINTERS_EXTEND_UNSIGNED < 0)))
+             && ((in_const && POINTERS_EXTEND_UNSIGNED !=0)
+                 || XEXP (x, 1) == convert_memory_address_addr_space_1
+                                    (to_mode, XEXP (x, 1), as, in_const)
+                  || POINTERS_EXTEND_UNSIGNED < 0)))
        return gen_rtx_fmt_ee (GET_CODE (x), to_mode,
-                              convert_memory_address_addr_space
-                                (to_mode, XEXP (x, 0), as),
+                              convert_memory_address_addr_space_1
+                                (to_mode, XEXP (x, 0), as, in_const),
                               XEXP (x, 1));
       break;
 
@@ -402,6 +406,18 @@ convert_memory_address_addr_space (enum machine_mode 
to_mode ATTRIBUTE_UNUSED,
                        x, POINTERS_EXTEND_UNSIGNED);
 #endif /* defined(POINTERS_EXTEND_UNSIGNED) */
 }
+
+/* Given X, a memory address in address space AS' pointer mode, convert it to
+   an address in the address space's address mode, or vice versa (TO_MODE says
+   which way).  We take advantage of the fact that pointers are not allowed to
+   overflow by commuting arithmetic operations over conversions so that address
+   arithmetic insns can be used.  */
+
+rtx
+convert_memory_address_addr_space (enum machine_mode to_mode, rtx x, 
addr_space_t as)
+{
+  return convert_memory_address_addr_space_1 (to_mode, x, as, false);
+}
 
 /* Return something equivalent to X but valid as a memory address for something
    of mode MODE in the named address space AS.  When X is not itself valid,
-- 
1.7.2.5

Reply via email to