aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-math-opts.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2020-10-06 10:32:22 +0200
committerJakub Jelinek <jakub@redhat.com>2020-10-06 10:32:22 +0200
commitbf510679bb3f9bfd6019666065016bb26a5b5466 (patch)
tree55da62e4b535db3b797d597c28674e659e57f56d /gcc/tree-ssa-math-opts.c
parent952adf021889b5e055085d0ed63942ff97d913de (diff)
downloadgcc-bf510679bb3f9bfd6019666065016bb26a5b5466.zip
gcc-bf510679bb3f9bfd6019666065016bb26a5b5466.tar.gz
gcc-bf510679bb3f9bfd6019666065016bb26a5b5466.tar.bz2
divmod: Match and expand DIVMOD even in some cases of constant divisor [PR97282]
As written in the comment, tree-ssa-math-opts.c wouldn't create a DIVMOD ifn call for division + modulo by constant for the fear that during expansion we could generate better code for those cases. If the divisoris a power of two, that is certainly the case always, but otherwise expand_divmod can punt in many cases, e.g. if the division type's precision is above HOST_BITS_PER_WIDE_INT, we don't even call choose_multiplier, because it works on HOST_WIDE_INTs (true, something we should fix eventually now that we have wide_ints), or if pre/post shift is larger than BITS_PER_WORD. So, the following patch recognizes DIVMOD with constant last argument even when it is unclear if expand_divmod will be able to optimize it, and then during DIVMOD expansion if the divisor is constant attempts to expand it as division + modulo and if they actually don't contain any libcalls or division/modulo, they are kept as is, otherwise that sequence is thrown away and divmod optab or libcall is used. 2020-10-06 Jakub Jelinek <jakub@redhat.com> PR rtl-optimization/97282 * tree-ssa-math-opts.c (divmod_candidate_p): Don't return false for constant op2 if it is not a power of two and the type has precision larger than HOST_BITS_PER_WIDE_INT or BITS_PER_WORD. * internal-fn.c (contains_call_div_mod): New function. (expand_DIVMOD): If last argument is a constant, try to expand it as TRUNC_DIV_EXPR followed by TRUNC_MOD_EXPR, but if the sequence contains any calls or {,U}{DIV,MOD} rtxes, throw it away and use divmod optab or divmod libfunc. * gcc.target/i386/pr97282.c: New test.
Diffstat (limited to 'gcc/tree-ssa-math-opts.c')
-rw-r--r--gcc/tree-ssa-math-opts.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index bdbb9d9..4927255 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -3567,9 +3567,24 @@ divmod_candidate_p (gassign *stmt)
/* Disable the transform if either is a constant, since division-by-constant
may have specialized expansion. */
- if (CONSTANT_CLASS_P (op1) || CONSTANT_CLASS_P (op2))
+ if (CONSTANT_CLASS_P (op1))
return false;
+ if (CONSTANT_CLASS_P (op2))
+ {
+ if (integer_pow2p (op2))
+ return false;
+
+ if (TYPE_PRECISION (type) <= HOST_BITS_PER_WIDE_INT
+ && TYPE_PRECISION (type) <= BITS_PER_WORD)
+ return false;
+
+ /* If the divisor is not power of 2 and the precision wider than
+ HWI, expand_divmod punts on that, so in that case it is better
+ to use divmod optab or libfunc. Similarly if choose_multiplier
+ might need pre/post shifts of BITS_PER_WORD or more. */
+ }
+
/* Exclude the case where TYPE_OVERFLOW_TRAPS (type) as that should
expand using the [su]divv optabs. */
if (TYPE_OVERFLOW_TRAPS (type))