[RFC/PATCH] ira: Consider matching constraints with param [PR100328]

Message ID c8ca748c-d7fd-6fb1-5ef2-567935d38722@linux.ibm.com
State New
Headers show
Series
  • [RFC/PATCH] ira: Consider matching constraints with param [PR100328]
Related show

Commit Message

Marek Polacek via Gcc-patches June 9, 2021, 5:18 a.m.
Hi,

PR100328 has some details about this issue, I am trying to
brief it here.  In the hottest function LBM_performStreamCollideTRT
of SPEC2017 bmk 519.lbm_r, there are many FMA style expressions
(27 FMA, 19 FMS, 11 FNMA).  On rs6000, this kind of FMA style
insn has two flavors: FLOAT_REG and VSX_REG, the VSX_REG reg
class have 64 registers whose foregoing 32 ones make up the
whole FLOAT_REG.  There are some differences for these two
flavors, taking "*fma<mode>4_fpr" as example:

(define_insn "*fma<mode>4_fpr"
  [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<Ff>,wa,wa")
	(fma:SFDF
	  (match_operand:SFDF 1 "gpc_reg_operand" "%<Ff>,wa,wa")
	  (match_operand:SFDF 2 "gpc_reg_operand" "<Ff>,wa,0")
	  (match_operand:SFDF 3 "gpc_reg_operand" "<Ff>,0,wa")))]

// wa => A VSX register (VSR), vs0…vs63, aka. VSX_REG.
// <Ff> (f/d) => A floating point register, aka. FLOAT_REG.

So for VSX_REG, we only have the destructive form, when VSX_REG
alternative being used, the operand 2 or operand 3 is required
to be the same as operand 0.  reload has to take care of this
constraint and create some non-free register copies if required.

Assuming one fma insn looks like:
  op0 = FMA (op1, op2, op3)

The best regclass of them are VSX_REG, when op1,op2,op3 are all dead,
IRA simply creates three shuffle copies for them (here the operand
order matters, since with the same freq, the one with smaller number
takes preference), but IMO both op2 and op3 should take higher priority
in copy queue due to the matching constraint.

I noticed that there is one function ira_get_dup_out_num, which meant
to create this kind of constraint copy, but the below code looks to
refuse to create if there is an alternative which has valid regclass
without spilled need. 

      default:
	{
	  enum constraint_num cn = lookup_constraint (str);
	  enum reg_class cl = reg_class_for_constraint (cn);
	  if (cl != NO_REGS
	      && !targetm.class_likely_spilled_p (cl))
	    goto fail

	 ...

I cooked one patch attached to make ira respect this kind of matching
constraint guarded with one parameter.  As I stated in the PR, I was
not sure this is on the right track.  The RFC patch is to check the
matching constraint in all alternatives, if there is one alternative
with matching constraint and matches the current preferred regclass
(or best of allocno?), it will record the output operand number and
further create one constraint copy for it.  Normally it can get the
priority against shuffle copies and the matching constraint will get
satisfied with higher possibility, reload doesn't create extra copies
to meet the matching constraint or the desirable register class when
it has to.

For FMA A,B,C,D, I think ideally copies A/B, A/C, A/D can firstly stay
as shuffle copies, and later any of A,B,C,D gets assigned by one
hardware register which is a VSX register (VSX_REG) but not a FP
register (FLOAT_REG), which means it has to pay costs once we can NOT
go with VSX alternatives, so at that time it's important to respect
the matching constraint then we can increase the freq for the remaining
copies related to this (A/B, A/C, A/D).  This idea requires some side
tables to record some information and seems a bit complicated in the
current framework, so the proposed patch aggressively emphasizes the
matching constraint at the time of creating copies.

Any comments are highly appreciated!

BR,
Kewen
---
 gcc/config/rs6000/rs6000.c |  3 ++
 gcc/ira.c                  | 69 ++++++++++++++++++++++++++++++++++----
 gcc/params.opt             |  4 +++
 3 files changed, 70 insertions(+), 6 deletions(-)

-- 
2.17.1

Patch

diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 5ae40d6f4ce..eb9c4284f91 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -4852,6 +4852,9 @@  rs6000_option_override_internal (bool global_init_p)
 	 ap = __builtin_next_arg (0).  */
       if (DEFAULT_ABI != ABI_V4)
 	targetm.expand_builtin_va_start = NULL;
+
+      SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+			   param_ira_consider_dup_in_all_alts, 1);
     }
 
   rs6000_override_options_after_change ();
diff --git a/gcc/ira.c b/gcc/ira.c
index b93588d8a9f..beebee7499b 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -1937,10 +1939,16 @@  ira_get_dup_out_num (int op_num, alternative_mask alts)
     return -1;
   str = recog_data.constraints[op_num];
   use_commut_op_p = false;
+
+  rtx op = recog_data.operand[op_num];
+  int op_no = reg_or_subregno (op);
+  enum reg_class op_pref_cl = reg_preferred_class (op_no);
+  machine_mode op_mode = GET_MODE (op);
+
   for (;;)
     {
-      rtx op = recog_data.operand[op_num];
-      
+      bool saw_reg_cstr = false;
+
       for (curr_alt = 0, ignore_p = !TEST_BIT (alts, curr_alt),
 	   original = -1;;)
 	{
@@ -1963,9 +1971,25 @@  ira_get_dup_out_num (int op_num, alternative_mask alts)
 		{
 		  enum constraint_num cn = lookup_constraint (str);
 		  enum reg_class cl = reg_class_for_constraint (cn);
-		  if (cl != NO_REGS
-		      && !targetm.class_likely_spilled_p (cl))
-		    goto fail;
+		  if (cl != NO_REGS && !targetm.class_likely_spilled_p (cl))
+		    {
+		      if (param_ira_consider_dup_in_all_alts
+			  && op_pref_cl != NO_REGS)
+			{
+			  /* If it's free to move from one preferred class to
+			     the one without matching constraint, it doesn't
+			     have to respect this constraint with costs.  */
+			  if (cl != op_pref_cl
+			      && (ira_reg_class_intersect[cl][op_pref_cl]
+				  != NO_REGS)
+			      && (ira_may_move_in_cost[op_mode][op_pref_cl][cl]
+				  == 0))
+			    goto fail;
+			  saw_reg_cstr = true;
+			}
+		      else
+			goto fail;
+		    }
 		  if (constraint_satisfied_p (op, cn))
 		    goto fail;
 		  break;
@@ -1979,7 +2003,40 @@  ira_get_dup_out_num (int op_num, alternative_mask alts)
 		  str = end;
 		  if (original != -1 && original != n)
 		    goto fail;
-		  original = n;
+		  if (param_ira_consider_dup_in_all_alts && saw_reg_cstr)
+		    {
+		      rtx out = recog_data.operand[n];
+		      if (!REG_P (out)
+			  && (GET_CODE (out) != SUBREG
+			      || !REG_P (SUBREG_REG (out))))
+			goto fail;
+		      int out_no = reg_or_subregno (out);
+		      if (out_no >= FIRST_PSEUDO_REGISTER)
+			{
+			  const char *out_alts = recog_data.constraints[n];
+			  int tot = curr_alt;
+			  while (tot > 0)
+			    {
+			      if (out_alts[0] == ',')
+				tot--;
+			      out_alts++;
+			    }
+			  enum reg_class out_cl = NO_REGS;
+			  while (*out_alts != '\0' && *out_alts != ',')
+			    {
+			      enum constraint_num cn
+				= lookup_constraint (out_alts);
+			      out_cl = reg_class_for_constraint (cn);
+			      if (out_cl != NO_REGS)
+				break;
+			    }
+			  /* Respect this as it's for preferred rclass.  */
+			  if (out_cl == op_pref_cl)
+			    original = n;
+			}
+		    }
+		  else
+		    original = n;
 		  continue;
 		}
 	      }
diff --git a/gcc/params.opt b/gcc/params.opt
index 7c7aa78992a..7d9d3a5876d 100644
--- a/gcc/params.opt
+++ b/gcc/params.opt
@@ -326,6 +326,10 @@  Max size of conflict table in MB.
 Common Joined UInteger Var(param_ira_max_loops_num) Init(100) Param Optimization
 Max loops number for regional RA.
 
+-param=ira-consider-dup-in-all-alts=
+Common Joined UInteger Var(param_ira_consider_dup_in_all_alts) Init(0) IntegerRange(0, 1) Param Optimization
+Control ira to continue to find matching constraint (duplicated operand number) even if it has encountered some contraint that has the appropriate register class, it will skip those alternatives whose constraint don't have the same register class as which the operand prefers.
+
 -param=iv-always-prune-cand-set-bound=
 Common Joined UInteger Var(param_iv_always_prune_cand_set_bound) Init(10) Param Optimization
 If number of candidates in the set is smaller, we always try to remove unused ivs during its optimization.