From e8beba1cfc761cc35762283b3b44a355ef05e25b Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Tue, 5 Jan 2021 11:29:10 +0000 Subject: [PATCH] explow, aarch64: Fix force-Pmode-to-mem for ILP32 [PR97269] 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 | 5 ++++- gcc/explow.c | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index a96b84cd927..88106bbcaf8 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -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); diff --git a/gcc/explow.c b/gcc/explow.c index c47486921e0..b6da277f689 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -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; } -- 2.30.2