From 6787268a289bdbc32920b13b4697eaf756f9f7e0 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 31 Aug 2023 16:15:10 +0100 Subject: [PATCH] aarch64: Fix return register handling in untyped_call To: gcc-patches@gcc.gnu.org While working on another patch, I hit a problem with the aarch64 expansion of untyped_call. The expander emits the usual: (set (mem ...) (reg resN)) instructions to store the result registers to memory, but it didn't say in RTL where those resN results came from. This eventually led to a failure of gcc.dg/torture/stackalign/builtin-return-2.c, via regrename. This patch turns the untyped call from a plain call to a call_value, to represent that the call returns (or might return) a useful value. The patch also uses a PARALLEL return rtx to represent all the possible return registers. gcc/ * config/aarch64/aarch64.md (untyped_call): Emit a call_value rather than a call. List each possible destination register in the call pattern. --- gcc/config/aarch64/aarch64.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 90f9ee658c5..97d27677985 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -934,7 +934,25 @@ { int i; - emit_call_insn (gen_call (operands[0], const0_rtx, NULL)); + /* Generate a PARALLEL that contains all of the register results. + The offsets are somewhat arbitrary, since we don't know the + actual return type. The main thing we need to avoid is having + overlapping byte ranges, since those might give the impression + that two registers are known to have data in common. */ + rtvec rets = rtvec_alloc (XVECLEN (operands[2], 0)); + unsigned HOST_WIDE_INT offset = 0; + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx reg = SET_SRC (XVECEXP (operands[2], 0, i)); + gcc_assert (REG_P (reg)); + rtx offset_rtx = gen_int_mode (offset, Pmode); + rtx piece = gen_rtx_EXPR_LIST (VOIDmode, reg, offset_rtx); + RTVEC_ELT (rets, i) = piece; + offset += GET_MODE_SIZE (GET_MODE (reg)); + } + rtx ret = gen_rtx_PARALLEL (VOIDmode, rets); + + emit_call_insn (gen_call_value (ret, operands[0], const0_rtx, NULL)); for (i = 0; i < XVECLEN (operands[2], 0); i++) { -- 2.35.3