Ping: [PATCH] Treat "p" in asms as addressing VOIDmode

Message ID mpt5y14g3vt.fsf@arm.com
State New
Headers
Series Ping: [PATCH] Treat "p" in asms as addressing VOIDmode |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gcc_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 fail Patch failed to apply

Commit Message

Richard Sandiford Dec. 11, 2023, 3:23 p.m. UTC
  Ping

---

check_asm_operands was inconsistent about how it handled "p" after
RA compared to before RA.  Before RA it tested the address with a
void (unknown) memory mode:

	    case CT_ADDRESS:
	      /* Every address operand can be reloaded to fit.  */
	      result = result || address_operand (op, VOIDmode);
	      break;

After RA it deferred to constrain_operands, which used the mode
of the operand:

		if ((GET_MODE (op) == VOIDmode
		     || SCALAR_INT_MODE_P (GET_MODE (op)))
		    && (strict <= 0
			|| (strict_memory_address_p
			     (recog_data.operand_mode[opno], op))))
		  win = true;

Using the mode of the operand matches reload's behaviour:

      else if (insn_extra_address_constraint
	       (lookup_constraint (constraints[i])))
	{
	  address_operand_reloaded[i]
	    = find_reloads_address (recog_data.operand_mode[i], (rtx*) 0,
				    recog_data.operand[i],
				    recog_data.operand_loc[i],
				    i, operand_type[i], ind_levels, insn);

It allowed the special predicate address_operand to be used, with the
mode of the operand being the mode of the addressed memory, rather than
the mode of the address itself.  For example, vax has:

(define_insn "*movaddr<mode>"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
	(match_operand:VAXfp 1 "address_operand" "p"))
   (clobber (reg:CC VAX_PSL_REGNUM))]
  "reload_completed"
  "mova<VAXfp:fsfx> %a1,%0")

where operand 1 is an SImode expression that can address memory of
mode VAXfp.  GET_MODE (recog_data.operand[1]) is SImode (or VOIDmode),
but recog_data.operand_mode[1] is <VAXfp:MODE>mode.

But AFAICT, ira and lra (like pre-reload check_asm_operands) do not
do this, and instead pass VOIDmode.  So I think this traditional use
of address_operand is effectively an old-reload-only feature.

And it seems like no modern port cares.  I think ports have generally
moved to using different address constraints instead, rather than
relying on "p" with different operand modes.  Target-specific address
constraints post-date the code above.

The big advantage of using different constraints is that it works
for asms too.  And that (to finally get to the point) is the problem
fixed in this patch.  For the aarch64 test:

  void f(char *p) { asm("prfm pldl1keep, %a0\n" :: "p" (p + 6)); }

everything up to and including RA required the operand to be a
valid VOIDmode address.  But post-RA check_asm_operands and
constrain_operands instead required it to be valid for
recog_data.operand_mode[0].  Since asms have no syntax for
specifying an operand mode that's separate from the operand itself,
operand_mode[0] is simply Pmode (i.e. DImode).

This meant that we required one mode before RA and a different mode
after RA.  On AArch64, VOIDmode is treated as a wildcard and so has a
more conservative/restricted range than DImode.  So if a post-RA pass
tried to form a new address, it would use a laxer condition than the
pre-RA passes.

This happened with the late-combine pass that I posted in October:
https://gcc.gnu.org/pipermail/gcc-patches/2023-October/634166.html
which in turn triggered an error from aarch64_print_operand_address.

This patch takes the (hopefully) conservative fix of using VOIDmode for
asms but continuing to use the operand mode for .md insns, so as not
to break ports that still use reload.

Fixing this made me realise that recog_level2 was doing duplicate
work for asms after RA.

Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?

Richard


gcc/
	* recog.cc (constrain_operands): Pass VOIDmode to
	strict_memory_address_p for 'p' constraints in asms.
	* rtl-ssa/changes.cc (recog_level2): Skip redundant constrain_operands
	for asms.

gcc/testsuite/
	* gcc.target/aarch64/prfm_imm_offset_2.c: New test.
---
 gcc/recog.cc                                   | 18 +++++++++++-------
 gcc/rtl-ssa/changes.cc                         |  4 +++-
 .../gcc.target/aarch64/prfm_imm_offset_2.c     |  2 ++
 3 files changed, 16 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/prfm_imm_offset_2.c
  

Patch

diff --git a/gcc/recog.cc b/gcc/recog.cc
index eaab79c25d7..bff7be1aec1 100644
--- a/gcc/recog.cc
+++ b/gcc/recog.cc
@@ -3191,13 +3191,17 @@  constrain_operands (int strict, alternative_mask alternatives)
 		   strictly valid, i.e., that all pseudos requiring hard regs
 		   have gotten them.  We also want to make sure we have a
 		   valid mode.  */
-		if ((GET_MODE (op) == VOIDmode
-		     || SCALAR_INT_MODE_P (GET_MODE (op)))
-		    && (strict <= 0
-			|| (strict_memory_address_p
-			     (recog_data.operand_mode[opno], op))))
-		  win = true;
-		break;
+		{
+		  auto mem_mode = (recog_data.is_asm
+				   ? VOIDmode
+				   : recog_data.operand_mode[opno]);
+		  if ((GET_MODE (op) == VOIDmode
+		       || SCALAR_INT_MODE_P (GET_MODE (op)))
+		      && (strict <= 0
+			  || strict_memory_address_p (mem_mode, op)))
+		    win = true;
+		  break;
+		}
 
 		/* No need to check general_operand again;
 		   it was done in insn-recog.cc.  Well, except that reload
diff --git a/gcc/rtl-ssa/changes.cc b/gcc/rtl-ssa/changes.cc
index 2f2d12d5f30..443d0575df5 100644
--- a/gcc/rtl-ssa/changes.cc
+++ b/gcc/rtl-ssa/changes.cc
@@ -986,8 +986,10 @@  recog_level2 (insn_change &change, add_regno_clobber_fn add_regno_clobber)
       pat = newpat;
     }
 
+  // check_asm_operands checks the constraints after RA, so we don't
+  // need to do it again.
   INSN_CODE (rtl) = icode;
-  if (reload_completed)
+  if (reload_completed && !asm_p)
     {
       extract_insn (rtl);
       if (!constrain_operands (1, get_preferred_alternatives (rtl)))
diff --git a/gcc/testsuite/gcc.target/aarch64/prfm_imm_offset_2.c b/gcc/testsuite/gcc.target/aarch64/prfm_imm_offset_2.c
new file mode 100644
index 00000000000..04e3fb72c45
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/prfm_imm_offset_2.c
@@ -0,0 +1,2 @@ 
+/* { dg-options "-O2" } */
+void f(char *p) { asm("prfm pldl1keep, %a0\n" :: "p" (p + 6)); }