[8/7] ifcvt: Second try in order to avoid unnecessary temporaries
Commit Message
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.
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.
@@ -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 ());