In expand, a bunch of places chose between 2 sequences based on if the cost
is less. Currently this is done manually and does NOT always print out
which one is selected and their costs.
This adds a 2 classes which is designed to record the sequences and choose one
of
them based on their cost.
This is a RFC rather than a full patch as I don't like the class names I came
up with.
It transform one example to use the new class to show how it will be used.
There is at least one place where I was going to choose between more than 2
sequences, that
is why I used a vec here (though with a reserved space for 3 elements). I
suspect this would
be used more if this in is in place as it should make it easier add a new
sequence for choosing.
Note I know I misspelled choose as chose. I will correct before submitting the
full path; but I
wanted to get people thoughts on the overall idea before fixing it up.
The 2 questions I have is:
1) is this a good idea to handle the choice between 2 (or more) sequences done
this way or should the code kept like it was before?
2) better names for the 2 structs/classes?
gcc/ChangeLog:
* expr.cc (sequence_with_cost): New struct.
(chose_sequence): New struct.
(expand_expr_divmod): Use sequence_with_cost/chose_sequence
for choosing between unsigned/signed div/mod sequence.
Signed-off-by: Andrew Pinski <[email protected]>
---
gcc/expr.cc | 85 +++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 63 insertions(+), 22 deletions(-)
diff --git a/gcc/expr.cc b/gcc/expr.cc
index 4a699101bb5..1a4397959f6 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -67,6 +67,58 @@ along with GCC; see the file COPYING3. If not see
#include "flags.h"
#include "internal-fn.h"
+namespace {
+ struct sequence_with_cost
+ {
+ rtx_insn *m_seq;
+ rtx m_target;
+ const char *m_name;
+ unsigned m_cost;
+ unsigned m_alt_cost;
+ unsigned m_index;
+ static int cmp(const void *av, const void *bv)
+ {
+ const sequence_with_cost *a = (const sequence_with_cost*)av;
+ const sequence_with_cost *b = (const sequence_with_cost*)bv;
+ if (a->m_cost == b->m_cost)
+ {
+ if (a->m_alt_cost == b->m_alt_cost)
+ return a->m_index - b->m_index;
+ return a->m_alt_cost - b->m_alt_cost;
+ }
+ return a->m_cost - b->m_cost;
+ }
+ };
+ struct chose_sequence
+ {
+ auto_vec<sequence_with_cost, 3> m_seqs;
+ void push_seq (rtx_insn *seq, rtx t, const char *name)
+ {
+ bool speed_p = optimize_insn_for_speed_p ();
+ unsigned cost = seq_cost (seq, speed_p);
+ unsigned alt_cost = seq_cost (seq, !speed_p);
+ m_seqs.safe_push({seq, t, name, cost, alt_cost, m_seqs.length()});
+ }
+ const sequence_with_cost &chose (const char *name)
+ {
+ gcc_assert (m_seqs.length () != 0);
+ if (m_seqs.length () == 1)
+ return m_seqs[0];
+ m_seqs.qsort (sequence_with_cost::cmp);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, ";; sorted costs for %s:\n", name);
+ for (auto &e : m_seqs)
+ {
+ fprintf (dump_file, ";; %u, %s: ", e.m_index, e.m_name);
+ fprintf (dump_file, "%u (alt: %u)\n", e.m_cost, e.m_alt_cost);
+ }
+ }
+ return m_seqs[0];
+ }
+ };
+}
+
/* If this is nonzero, we do not bother generating VOLATILE
around volatile memory references, and we are willing to
@@ -9765,7 +9817,6 @@ expand_expr_divmod (tree_code code, machine_mode mode,
tree treeop0,
/* If both arguments are known to be positive when interpreted
as signed, we can expand it as both signed and unsigned
division or modulo. Choose the cheaper sequence in that case. */
- bool speed_p = optimize_insn_for_speed_p ();
do_pending_stack_adjust ();
start_sequence ();
rtx uns_ret = expand_divmod (mod_p, code, mode, op0, op1, target, 1);
@@ -9773,31 +9824,21 @@ expand_expr_divmod (tree_code code, machine_mode mode,
tree treeop0,
start_sequence ();
rtx sgn_ret = expand_divmod (mod_p, code, mode, op0, op1, target, 0);
rtx_insn *sgn_insns = end_sequence ();
- unsigned uns_cost = seq_cost (uns_insns, speed_p);
- unsigned sgn_cost = seq_cost (sgn_insns, speed_p);
- bool was_tie = false;
-
- /* If costs are the same then use as tie breaker the other other
- factor. */
- if (uns_cost == sgn_cost)
+ chose_sequence seqs;
+ /* Prefer based on the original signedness seq for tie breaker. */
+ if (unsignedp)
{
- uns_cost = seq_cost (uns_insns, !speed_p);
- sgn_cost = seq_cost (sgn_insns, !speed_p);
- was_tie = true;
+ seqs.push_seq (uns_insns, uns_ret, "unsigned");
+ seqs.push_seq (sgn_insns, sgn_ret, "signed");
}
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, ";; positive division:%s unsigned cost: %u; "
- "signed cost: %u\n",
- was_tie ? " (needed tie breaker)" : "", uns_cost, sgn_cost);
-
- if (uns_cost < sgn_cost || (uns_cost == sgn_cost && unsignedp))
+ else
{
- emit_insn (uns_insns);
- return uns_ret;
+ seqs.push_seq (sgn_insns, sgn_ret, "signed");
+ seqs.push_seq (uns_insns, uns_ret, "unsigned");
}
- emit_insn (sgn_insns);
- return sgn_ret;
+ const auto &seq_with_cost = seqs.chose ("positive division");
+ emit_insn (seq_with_cost.m_seq);
+ return seq_with_cost.m_target;
}
return expand_divmod (mod_p, code, mode, op0, op1, target, unsignedp);
}
--
2.43.0