aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2023-05-19 12:58:32 +0200
committerJakub Jelinek <jakub@redhat.com>2023-05-19 12:58:32 +0200
commitbd0f2828432918a16e93d9e9021a5927143b8dde (patch)
treedd3ffe4b3e718ccb5e852b31bbd2fc0d42dc5ee9 /gcc
parent62d08a67c83b4a089866c6d19e82d70ee5b8aed1 (diff)
downloadgcc-bd0f2828432918a16e93d9e9021a5927143b8dde.zip
gcc-bd0f2828432918a16e93d9e9021a5927143b8dde.tar.gz
gcc-bd0f2828432918a16e93d9e9021a5927143b8dde.tar.bz2
tree-ssa-math-opts: Pattern recognize some further hand written forms of signed __builtin_mul_overflow{,_p} [PR105776]
In the pattern recognition of signed __builtin_mul_overflow{,_p} we check for result of unsigned division (which follows unsigned multiplication) being equality compared against one of the multiplication's argument (the one not used in the division) and check for the comparison to be done against same precision cast of the argument (because division's result is unsigned and the argument is signed). But as shown in this PR, one can write it equally as comparison done in the signed type, i.e. compare division's result cast to corresponding signed type against the argument. The following patch handles even those cases. 2023-05-19 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/105776 * tree-ssa-math-opts.cc (arith_overflow_check_p): If cast_stmt is non-NULL, allow division statement to have a cast as single imm use rather than comparison/condition. (match_arith_overflow): In that case remove the cast stmt in addition to the division statement. * gcc.target/i386/pr105776.c: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/testsuite/gcc.target/i386/pr105776.c43
-rw-r--r--gcc/tree-ssa-math-opts.cc25
2 files changed, 68 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.target/i386/pr105776.c b/gcc/testsuite/gcc.target/i386/pr105776.c
new file mode 100644
index 0000000..56878bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr105776.c
@@ -0,0 +1,43 @@
+/* PR tree-optimization/105776 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -masm=att" } */
+/* { dg-final { scan-tree-dump-times " = \.MUL_OVERFLOW " 5 "optimized" } } */
+/* { dg-final { scan-assembler-times "\timull\t" 5 } } */
+/* { dg-final { scan-assembler-times "\tsetno\t" 5 } } */
+
+int
+foo (unsigned x, unsigned y)
+{
+ unsigned int r = x * y;
+ return !x || ((int) r / (int) x) == (int) y;
+}
+
+int
+bar (unsigned x, unsigned y)
+{
+ return !x || ((int) (x * y) / (int) x) == (int) y;
+}
+
+int
+baz (unsigned x, unsigned y)
+{
+ if (x == 0)
+ return 1;
+ return ((int) (x * y) / (int) x) == y;
+}
+
+int
+qux (unsigned x, unsigned y, unsigned *z)
+{
+ unsigned int r = x * y;
+ *z = r;
+ return !x || ((int) r / (int) x) == (int) y;
+}
+
+int
+corge (unsigned x, unsigned y, unsigned *z)
+{
+ unsigned int r = x * y;
+ *z = r;
+ return !x || ((int) r / (int) x) == y;
+}
diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc
index d80d53d..9c9ca57 100644
--- a/gcc/tree-ssa-math-opts.cc
+++ b/gcc/tree-ssa-math-opts.cc
@@ -3802,6 +3802,21 @@ arith_overflow_check_p (gimple *stmt, gimple *cast_stmt, gimple *&use_stmt,
use_operand_p use;
if (!single_imm_use (divlhs, &use, &cur_use_stmt))
return 0;
+ if (cast_stmt && gimple_assign_cast_p (cur_use_stmt))
+ {
+ tree cast_lhs = gimple_assign_lhs (cur_use_stmt);
+ if (INTEGRAL_TYPE_P (TREE_TYPE (cast_lhs))
+ && TYPE_UNSIGNED (TREE_TYPE (cast_lhs))
+ && (TYPE_PRECISION (TREE_TYPE (cast_lhs))
+ == TYPE_PRECISION (TREE_TYPE (divlhs)))
+ && single_imm_use (cast_lhs, &use, &cur_use_stmt))
+ {
+ cast_stmt = NULL;
+ divlhs = cast_lhs;
+ }
+ else
+ return 0;
+ }
}
if (gimple_code (cur_use_stmt) == GIMPLE_COND)
{
@@ -4390,6 +4405,16 @@ match_arith_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
gimple_stmt_iterator gsi2 = gsi_for_stmt (orig_use_stmt);
maybe_optimize_guarding_check (mul_stmts, use_stmt, orig_use_stmt,
cfg_changed);
+ use_operand_p use;
+ gimple *cast_stmt;
+ if (single_imm_use (gimple_assign_lhs (orig_use_stmt), &use,
+ &cast_stmt)
+ && gimple_assign_cast_p (cast_stmt))
+ {
+ gimple_stmt_iterator gsi3 = gsi_for_stmt (cast_stmt);
+ gsi_remove (&gsi3, true);
+ release_ssa_name (gimple_assign_lhs (cast_stmt));
+ }
gsi_remove (&gsi2, true);
release_ssa_name (gimple_assign_lhs (orig_use_stmt));
}