On Tue, Oct 20, 2020 at 10:57 PM Vladimir Makarov <vmaka...@redhat.com> wrote:
>
>
> On 2020-10-20 1:33 a.m., Hongtao Liu wrote:
> > On Mon, Oct 19, 2020 at 11:38 PM Vladimir Makarov <vmaka...@redhat.com> 
> > wrote:
> >>
> >> On 2020-10-11 8:58 p.m., Hongtao Liu wrote:
> >>> Hi:
> >>>     This is done in 2 steps:
> >>>     1. Extend special memory constraint to handle non MEM_P cases, i.e.
> >>> (vec_duplicate:V4SF (mem:SF (addr)))
> >>>     2. Refactor implementation of *_bcst{_1,_2,_3} patterns. Add new
> >>> predicate bcst_mem_operand and corresponding constraint "Br" to merge
> >>> "$(pattern)_bcst{_1,_2,_3}" into "$(pattern)", also delete those
> >>> separate "*_bcst{_1,_2,_3}" patterns.
> >>>
> >>>     Bootstrap is ok, regression test on i386 backend is ok.
> >>>
> >>> gcc/ChangeLog:
> >>>
> >>>           PR target/87767
> >>>           * ira-costs.c (record_operand_costs): Extract memory operand
> >>>           from recog_data.operand[i] for record_address_regs.
> >>>           (record_reg_classes): Extract memory operand from OP for
> >>>           conditional judgement MEM_P.
> >>>           * ira.c (ira_setup_alts): Ditto.
> >>>           * lra-constraints.c (extract_mem_from_operand): New function.
> >>>           (satisfies_memory_constraint_p): Extract memory operand from
> >>>           OP for decompose_mem_address, return false when there's no
> >>>           memory operand inside OP.
> >>>           (process_alt_operands): Remove MEM_P (op) since it would be
> >>>           judged in satisfies_memory_constraint_p.
> >>>           * recog.c (asm_operand_ok): Extract memory operand from OP for
> >>>           judgement of memory_operand (OP, VOIDmode).
> >>>           (constrain_operands): Don't unwrapper unary operator when
> >>>           there's memory operand inside.
> >>>           * rtl.h (extract_mem_from_operand): New decl.
> >>
> >> Thank you for working on the PR.  In general patch is ok for me. The
> >> only thing is
> >>
> >> +/* For special_memory_operand, it could be false for MEM_P (op),
> >> +   i.e. bcst_mem_operand in i386 backend.
> >> +   Extract and return real memory operand or op.  */
> >> +rtx
> >> +extract_mem_from_operand (rtx op)
> >> +{
> >> +  if (MEM_P (op))
> >> +    return op;
> >> +  /* Only allow one memory_operand inside special memory operand.  */
> >>
> >> The comment contradicts to the below code which returns the first memory 
> >> operand (not the only one).
> >>
> > Yes.
> >
> >> +  subrtx_var_iterator::array_type array;
> >> +  FOR_EACH_SUBRTX_VAR (iter, array, op, ALL)
> >> +    {
> >> +      rtx x = *iter;
> >> +      if (MEM_P (x))
> >> +       return x;
> >> +    }
> >> +
> >> +  return op;
> >> +}
> >> +
> >>
> >> I think the code should look like
> >>
> >> /* For special_memory_operand, it could be false for MEM_P (op),
> >>      i.e. bcst_mem_operand in i386 backend.
> >>      Extract and return real memory operand or op.  */
> >> rtx
> >> extract_mem_from_operand (rtx op)
> >> {
> >>     if (MEM_P (op))
> >>       return op;
> >>     /* Only allow one memory_operand inside special memory operand.  */
> >>     subrtx_var_iterator::array_type array;
> >>     rtx res = op;
> >>     FOR_EACH_SUBRTX_VAR (iter, array, op, ALL)
> >>       {
> >>         rtx x = *iter;
> >>         if (!MEM_P (x) || res != op)
> >>           return op;
> >>         res = op;
> > Assume you want to assign res with x.
> > Also in the iteration, x would first be op which would be false for
> > MEM_P, then op would be returned.
> > That's not what you mean, so i changed to
> >
> >    /* Only allow one memory_operand inside special memory operand.  */
> >    subrtx_var_iterator::array_type array;
> >    rtx res = op;
> >    FOR_EACH_SUBRTX_VAR (iter, array, op, ALL)
> >      {
> >        rtx x = *iter;
> >        if (!MEM_P (x))
> >          continue;
> >        /* Return op when there're multiple memory operands.  */
> >        if (res != op)
> >          return op;
> >        else
> >          res = x;
> >      }
>
> Actually I wanted to have constraint satisfying rtx with memory covered
> by **only unary** operator(s).  Your code satisfies memory covered by
> non-unary operators (e.g. binary ones).
>
> Why do I prefer less general constraint? Because other operands of
> operator containing the memory might need reloads too and the more
> general constraint will ignore this. If this situation is impossible
> now, it might be possible in the future.
>

Got your point.

> My proposed code is wrong as I forgot that FOR_EACH_SUBRTX_VAR processes
> sub-rtx recursively.  Thank you for starting the discussion.  Now I
> think the code should look like
>
> /* For special_memory_operand, it could be false for MEM_P (op),
>      i.e. bcst_mem_operand in i386 backend.
>      Extract and return real memory operand or op.  */
> rtx
> extract_mem_from_operand (rtx op)
> {
>    for (rtx x = op;; x = XEXP (x, 0)) {
>
>     if (MEM_P (x))
>       return x;
>     if (GET_RTX_LENGTH (GET_CODE (x)) != 1 || GET_RTX_FORMAT (GET_CODE
> (x))[0] != 'e')
>       break;
>
>    }
>
>    return op;
>
> }
>
> Let me know what do you think.
>

Changed, and it passed the i386/x86-64 regression test.

Update patch.

-- 
BR,
Hongtao
From 65e7fa0807d31a17d6772f4292176ad4ecbb571d Mon Sep 17 00:00:00 2001
From: liuhongt <hongtao....@intel.com>
Date: Sat, 26 Sep 2020 15:08:32 +0800
Subject: [PATCH 1/2] Extend special_memory_constraint.

For operand with special_memory_constraint, there could be a wrapper
for memory_operand. Extract mem for operand for conditional judgement
like MEM_P, also for record_address_regs.

gcc/ChangeLog:

	PR target/87767
	* ira-costs.c (record_operand_costs): Extract memory operand
	from recog_data.operand[i] for record_address_regs.
	(record_reg_classes): Extract memory operand from OP for
	conditional judgement MEM_P.
	* ira.c (ira_setup_alts): Ditto.
	* lra-constraints.c (extract_mem_from_operand): New function.
	(satisfies_memory_constraint_p): Extract memory operand from
	OP for decompose_mem_address, return false when there's no
	memory operand inside OP.
	(process_alt_operands): Remove MEM_P (op) since it would be
	judged in satisfies_memory_constraint_p.
	* recog.c (asm_operand_ok): Extract memory operand from OP for
	judgement of memory_operand (OP, VOIDmode).
	(constrain_operands): Don't unwrapper unary operator when
	there's memory operand inside.
	* rtl.h (extract_mem_from_operand): New decl.
---
 gcc/ira-costs.c       | 12 +++++++-----
 gcc/ira.c             |  2 +-
 gcc/lra-constraints.c | 28 +++++++++++++++++++++++-----
 gcc/recog.c           |  7 +++++--
 gcc/rtl.h             |  1 +
 5 files changed, 37 insertions(+), 13 deletions(-)

diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c
index 6891156b5aa..aeda6588bcd 100644
--- a/gcc/ira-costs.c
+++ b/gcc/ira-costs.c
@@ -781,7 +781,8 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops,
 
 		    case CT_SPECIAL_MEMORY:
 		      insn_allows_mem[i] = allows_mem[i] = 1;
-		      if (MEM_P (op) && constraint_satisfied_p (op, cn))
+		      if (MEM_P (extract_mem_from_operand (op))
+			  && constraint_satisfied_p (op, cn))
 			win = 1;
 		      break;
 
@@ -1397,15 +1398,16 @@ record_operand_costs (rtx_insn *insn, enum reg_class *pref)
      commutative.  */
   for (i = 0; i < recog_data.n_operands; i++)
     {
+      rtx op_mem = extract_mem_from_operand (recog_data.operand[i]);
       memcpy (op_costs[i], init_cost, struct_costs_size);
 
       if (GET_CODE (recog_data.operand[i]) == SUBREG)
 	recog_data.operand[i] = SUBREG_REG (recog_data.operand[i]);
 
-      if (MEM_P (recog_data.operand[i]))
-	record_address_regs (GET_MODE (recog_data.operand[i]),
-			     MEM_ADDR_SPACE (recog_data.operand[i]),
-			     XEXP (recog_data.operand[i], 0),
+      if (MEM_P (op_mem))
+	record_address_regs (GET_MODE (op_mem),
+			     MEM_ADDR_SPACE (op_mem),
+			     XEXP (op_mem, 0),
 			     0, MEM, SCRATCH, frequency * 2);
       else if (constraints[i][0] == 'p'
 	       || (insn_extra_address_constraint
diff --git a/gcc/ira.c b/gcc/ira.c
index 27d1b3c857d..a61138c6e94 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -1868,7 +1868,7 @@ ira_setup_alts (rtx_insn *insn)
 
 			case CT_MEMORY:
 			case CT_SPECIAL_MEMORY:
-			  if (MEM_P (op))
+			  if (MEM_P (extract_mem_from_operand (op)))
 			    goto op_success;
 			  win_p = true;
 			  break;
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index f761d7dfe3c..b5c010d5030 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -416,14 +416,34 @@ valid_address_p (rtx op, struct address_info *ad,
   return valid_address_p (ad->mode, *ad->outer, ad->as);
 }
 
+/* For special_memory_operand, it could be false for MEM_P (op),
+   i.e. bcst_mem_operand in i386 backend.
+   Extract and return real memory operand or op.  */
+rtx
+extract_mem_from_operand (rtx op)
+{
+  for (rtx x = op;; x = XEXP (x, 0))
+    {
+      if (MEM_P (x))
+	return x;
+      if (GET_RTX_LENGTH (GET_CODE (x)) != 1
+	  || GET_RTX_FORMAT (GET_CODE (x))[0] != 'e')
+	break;
+    }
+  return op;
+}
+
 /* Return true if the eliminated form of memory reference OP satisfies
    extra (special) memory constraint CONSTRAINT.  */
 static bool
 satisfies_memory_constraint_p (rtx op, enum constraint_num constraint)
 {
   struct address_info ad;
+  rtx mem = extract_mem_from_operand (op);
+  if (!MEM_P (mem))
+    return false;
 
-  decompose_mem_address (&ad, op);
+  decompose_mem_address (&ad, mem);
   address_eliminator eliminator (&ad);
   return constraint_satisfied_p (op, constraint);
 }
@@ -2406,8 +2426,7 @@ process_alt_operands (int only_alternative)
 		      break;
 
 		    case CT_MEMORY:
-		      if (MEM_P (op)
-			  && satisfies_memory_constraint_p (op, cn))
+		      if (satisfies_memory_constraint_p (op, cn))
 			win = true;
 		      else if (spilled_pseudo_p (op))
 			win = true;
@@ -2448,8 +2467,7 @@ process_alt_operands (int only_alternative)
 		      break;
 
 		    case CT_SPECIAL_MEMORY:
-		      if (MEM_P (op)
-			  && satisfies_memory_constraint_p (op, cn))
+		      if (satisfies_memory_constraint_p (op, cn))
 			win = true;
 		      else if (spilled_pseudo_p (op))
 			win = true;
diff --git a/gcc/recog.c b/gcc/recog.c
index ce83b7f5218..d3552ec63eb 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -1798,7 +1798,8 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
 	    case CT_MEMORY:
 	    case CT_SPECIAL_MEMORY:
 	      /* Every memory operand can be reloaded to fit.  */
-	      result = result || memory_operand (op, VOIDmode);
+	      result = result || memory_operand (extract_mem_from_operand (op),
+						 VOIDmode);
 	      break;
 
 	    case CT_ADDRESS:
@@ -2584,7 +2585,9 @@ constrain_operands (int strict, alternative_mask alternatives)
 
 	  /* A unary operator may be accepted by the predicate, but it
 	     is irrelevant for matching constraints.  */
-	  if (UNARY_P (op))
+	  /* For special_memory_operand, there could be a memory operand inside,
+	     and it would cause a mismatch for constraint_satisfied_p.  */
+	  if (UNARY_P (op) && op == extract_mem_from_operand (op))
 	    op = XEXP (op, 0);
 
 	  if (GET_CODE (op) == SUBREG)
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 0872cc408eb..fcec9dc6387 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -4324,6 +4324,7 @@ extern rtx gen_hard_reg_clobber (machine_mode, unsigned int);
 extern rtx get_reg_known_value (unsigned int);
 extern bool get_reg_known_equiv_p (unsigned int);
 extern rtx get_reg_base_value (unsigned int);
+extern rtx extract_mem_from_operand (rtx);
 
 #ifdef STACK_REGS
 extern int stack_regs_mentioned (const_rtx insn);
-- 
2.18.1

Reply via email to