explow, aarch64: Fix force-Pmode-to-mem for ILP32 [PR97269]
authorRichard Sandiford <richard.sandiford@arm.com>
Tue, 5 Jan 2021 11:29:10 +0000 (11:29 +0000)
committerRichard Sandiford <richard.sandiford@arm.com>
Tue, 5 Jan 2021 11:29:10 +0000 (11:29 +0000)
This patch fixes a mode/rtx mismatch for ILP32 targets in:

  mem = force_const_mem (ptr_mode, imm);

where imm can be Pmode rather than ptr_mode.

The patch uses convert_memory_address to convert the Pmode address
to ptr_mode before the call.  However, immediate addresses can in
general contain unspecs, and convert_memory_address wasn't set up
to handle those.

The patch therefore adds some generic unspec handling to
convert_memory_address_addr_space_1.  As the comment says, we can add
a target hook if this behaviour turns out to be wrong for some targets.
But I think what the patch does is a strict improvement over the status
quo: without it, we would try to force the unspec into a register,
but nevertheless wrap the result in a (const ...).  That in turn
would be invalid rtl and seems bound to generate an ICE later.

I tested the explow.c part using -fstack-protector with local hacks
to force SYMBOL_FORCE_TO_MEM for UNSPEC_SALT_ADDR.

Fixes c-c++-common/torture/pr57945.c and various other tests.

gcc/
PR target/97269
* explow.c (convert_memory_address_addr_space_1): Handle UNSPECs
nested in CONSTs.
* config/aarch64/aarch64.c (aarch64_expand_mov_immediate): Use
convert_memory_address to convert symbolic immediates to ptr_mode
before forcing them to memory.

gcc/config/aarch64/aarch64.c
gcc/explow.c

index a96b84cd927b44cbb650ae7fb4b7c7c0ad6f3db7..88106bbcaf80129565a584a243cca5b0334785fa 100644 (file)
@@ -5224,8 +5224,11 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm)
       switch (sty)
        {
        case SYMBOL_FORCE_TO_MEM:
+         if (int_mode != ptr_mode)
+           imm = convert_memory_address (ptr_mode, imm);
+
          if (const_offset != 0
-             && targetm.cannot_force_const_mem (int_mode, imm))
+             && targetm.cannot_force_const_mem (ptr_mode, imm))
            {
              gcc_assert (can_create_pseudo_p ());
              base = aarch64_force_temporary (int_mode, dest, base);
index c47486921e08f4bd05051c930182cbb82a7bfdc2..b6da277f6896a75e66319ad326ec3d84f89fa073 100644 (file)
@@ -378,6 +378,26 @@ convert_memory_address_addr_space_1 (scalar_int_mode to_mode ATTRIBUTE_UNUSED,
        }
       break;
 
+    case UNSPEC:
+      /* Assume that all UNSPECs in a constant address can be converted
+        operand-by-operand.  We could add a target hook if some targets
+        require different behavior.  */
+      if (in_const && GET_MODE (x) == from_mode)
+       {
+         unsigned int n = XVECLEN (x, 0);
+         rtvec v = gen_rtvec (n);
+         for (unsigned int i = 0; i < n; ++i)
+           {
+             rtx op = XVECEXP (x, 0, i);
+             if (GET_MODE (op) == from_mode)
+               op = convert_memory_address_addr_space_1 (to_mode, op, as,
+                                                         in_const, no_emit);
+             RTVEC_ELT (v, i) = op;
+           }
+         return gen_rtx_UNSPEC (to_mode, v, XINT (x, 1));
+       }
+      break;
+
     default:
       break;
     }