[8/7] ifcvt: Second try in order to avoid unnecessary temporaries

Message ID 1b37f716-ac71-d61e-469c-69aceb371019@linux.ibm.com
State New
Headers
Series None |

Commit Message

Robin Dapp Sept. 28, 2021, 1:17 p.m. UTC
  Hi,

this patch implements the latest of my attempts to avoid some of the 
unnecessary temporaries noce_convert_multiple currently emits.  I named 
it 8/7 because it actually applies on top of the last series that is not 
yet approved while being a rather minor change.

The idea is to go over the list of convertible sets a second time if, 
during the first try, we noticed that we potentially overwrite the 
condition but no later set makes use of it anymore (because it can rely 
on the CC directly instead).  In that case we omit creating a temporary.

The whole series was bootstrapped and regtested on s390, x86 and ppc64.

Regards
  Robin

--

gcc/ChangeLog:

         * ifcvt.c (noce_convert_multiple_sets): Perform a second try 
with less temporaries.
  

Patch

commit dd5a0f8d7d39447025d36ed5305709d38fe3f16b
Author: Robin Dapp <rdapp@linux.ibm.com>
Date:   Fri Sep 17 20:22:10 2021 +0200

    ifcvt: Run second pass if it is possible to omit a temporary.
    
    If one of the to-be-converted SETs requires the original comparison
    (i.e. in order to generate a min/max insn) but no other insn after it
    does, we can omit creating temporaries, thus facilitating costing.

diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 4f3af5e1b00..2243157e32c 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -3261,6 +3261,11 @@  noce_convert_multiple_sets (struct noce_if_info *if_info)
 
   need_cmov_or_rewire (then_bb, &need_no_cmov, &rewired_src);
 
+  int last_needs_comparison = -1;
+  bool second_try = false;
+
+restart:
+
   FOR_BB_INSNS (then_bb, insn)
     {
       /* Skip over non-insns.  */
@@ -3302,8 +3307,12 @@  noce_convert_multiple_sets (struct noce_if_info *if_info)
 	 Therefore we introduce a temporary every time we are about to
 	 overwrite a variable used in the check.  Costing of a sequence with
 	 these is going to be inaccurate so only use temporaries when
-	 needed.  */
-      if (reg_overlap_mentioned_p (target, cond))
+	 needed.
+
+	 If performing a second try, we know how many insns require a
+	 temporary.  For the last of these, we can omit creating one.  */
+      if (reg_overlap_mentioned_p (target, cond)
+	  && (!second_try || count < last_needs_comparison))
 	temp = gen_reg_rtx (GET_MODE (target));
       else
 	temp = target;
@@ -3386,6 +3395,8 @@  noce_convert_multiple_sets (struct noce_if_info *if_info)
 	{
 	  seq = seq1;
 	  temp_dest = temp_dest1;
+	  if (!second_try)
+	    last_needs_comparison = count;
 	}
       else if (seq2 != NULL_RTX)
 	{
@@ -3409,6 +3420,24 @@  noce_convert_multiple_sets (struct noce_if_info *if_info)
       unmodified_insns.safe_push (insn);
     }
 
+    /* If there are insns that overwrite part of the initial
+       comparison, we can still omit creating temporaries for
+       the last of them.
+       As the second try will always create a less expensive,
+       valid sequence, we do not need to compare and can discard
+       the first one.  */
+    if (!second_try && last_needs_comparison >= 0)
+      {
+	end_sequence ();
+	start_sequence ();
+	count = 0;
+	targets.truncate (0);
+	temporaries.truncate (0);
+	unmodified_insns.truncate (0);
+	second_try = true;
+	goto restart;
+      }
+
   /* We must have seen some sort of insn to insert, otherwise we were
      given an empty BB to convert, and we can't handle that.  */
   gcc_assert (!unmodified_insns.is_empty ());