From 5de7bf5bc98ec9edc6838a443521204d0eca7605 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 5 Jan 2021 19:13:29 +0100 Subject: [PATCH] expand: Fold x - y < 0 to x < y during expansion [PR94802] My earlier patch to simplify x - y < 0 etc. for signed subtraction with undefined overflow into x < y in match.pd regressed some tests, even when it was guarded to be post-IPA, the following patch thus attempts to optimize that during expansion instead (which is the last time we can do it, afterwards we lose the information whether it was x - y < 0 or (int) ((unsigned) x - y) < 0 for which we couldn't optimize it. 2021-01-05 Jakub Jelinek PR tree-optimization/94802 * expr.h (maybe_optimize_sub_cmp_0): Declare. * expr.c: Include tree-pretty-print.h and flags.h. (maybe_optimize_sub_cmp_0): New function. (do_store_flag): Use it. * cfgexpand.c (expand_gimple_cond): Likewise. * gcc.target/i386/pr94802.c: New test. * gcc.dg/Wstrict-overflow-25.c: Remove xfail. --- gcc/cfgexpand.c | 8 ++++ gcc/expr.c | 41 +++++++++++++++++++++ gcc/expr.h | 1 + gcc/testsuite/gcc.dg/Wstrict-overflow-25.c | 2 +- gcc/testsuite/gcc.target/i386/pr94802.c | 59 ++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr94802.c diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 1d3f96f..b73019b 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -2621,6 +2621,14 @@ expand_gimple_cond (basic_block bb, gcond *stmt) && TREE_CODE (op1) == INTEGER_CST) code = maybe_optimize_mod_cmp (code, &op0, &op1); + /* Optimize (x - y) < 0 into x < y if x - y has undefined overflow. */ + if (!TYPE_UNSIGNED (TREE_TYPE (op0)) + && (code == LT_EXPR || code == LE_EXPR + || code == GT_EXPR || code == GE_EXPR) + && integer_zerop (op1) + && TREE_CODE (op0) == SSA_NAME) + maybe_optimize_sub_cmp_0 (code, &op0, &op1); + last2 = last = get_last_insn (); extract_true_false_edges_from_block (bb, &true_edge, &false_edge); diff --git a/gcc/expr.c b/gcc/expr.c index d472eea..04ef5ad 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -62,6 +62,8 @@ along with GCC; see the file COPYING3. If not see #include "ccmp.h" #include "gimple-fold.h" #include "rtx-vector-builder.h" +#include "tree-pretty-print.h" +#include "flags.h" /* If this is nonzero, we do not bother generating VOLATILE @@ -12275,6 +12277,37 @@ maybe_optimize_mod_cmp (enum tree_code code, tree *arg0, tree *arg1) *arg1 = c4; return code == EQ_EXPR ? LE_EXPR : GT_EXPR; } + +/* Optimize x - y < 0 into x < 0 if x - y has undefined overflow. */ + +void +maybe_optimize_sub_cmp_0 (enum tree_code code, tree *arg0, tree *arg1) +{ + gcc_checking_assert (code == GT_EXPR || code == GE_EXPR + || code == LT_EXPR || code == LE_EXPR); + gcc_checking_assert (integer_zerop (*arg1)); + + if (!optimize) + return; + + gimple *stmt = get_def_for_expr (*arg0, MINUS_EXPR); + if (stmt == NULL) + return; + + tree treeop0 = gimple_assign_rhs1 (stmt); + tree treeop1 = gimple_assign_rhs2 (stmt); + if (!TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (treeop0))) + return; + + if (issue_strict_overflow_warning (WARN_STRICT_OVERFLOW_COMPARISON)) + warning_at (gimple_location (stmt), OPT_Wstrict_overflow, + "assuming signed overflow does not occur when " + "simplifying % to %", + op_symbol_code (code), op_symbol_code (code)); + + *arg0 = treeop0; + *arg1 = treeop1; +} /* Generate code to calculate OPS, and exploded expression using a store-flag instruction and return an rtx for the result. @@ -12363,6 +12396,14 @@ do_store_flag (sepops ops, rtx target, machine_mode mode) } } + /* Optimize (x - y) < 0 into x < y if x - y has undefined overflow. */ + if (!unsignedp + && (ops->code == LT_EXPR || ops->code == LE_EXPR + || ops->code == GT_EXPR || ops->code == GE_EXPR) + && integer_zerop (arg1) + && TREE_CODE (arg0) == SSA_NAME) + maybe_optimize_sub_cmp_0 (ops->code, &arg0, &arg1); + /* Get the rtx comparison code to use. We know that EXP is a comparison operation of some type. Some comparisons against 1 and -1 can be converted to comparisons with zero. Do so here so that the tests diff --git a/gcc/expr.h b/gcc/expr.h index 6f99680..1f0177a 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -298,6 +298,7 @@ extern tree string_constant (tree, tree *, tree *, tree *); extern tree byte_representation (tree, tree *, tree *, tree *); extern enum tree_code maybe_optimize_mod_cmp (enum tree_code, tree *, tree *); +extern void maybe_optimize_sub_cmp_0 (enum tree_code, tree *, tree *); /* Two different ways of generating switch statements. */ extern int try_casesi (tree, tree, tree, tree, rtx, rtx, rtx, profile_probability); diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-25.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-25.c index 774474d..0091644 100644 --- a/gcc/testsuite/gcc.dg/Wstrict-overflow-25.c +++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-25.c @@ -7,5 +7,5 @@ int foo (int x, int y) { - return x - y < 0; /* { dg-warning "assuming signed overflow does not occur" "correct warning" { xfail *-*-* } } */ + return x - y < 0; /* { dg-warning "assuming signed overflow does not occur" "correct warning" } */ } diff --git a/gcc/testsuite/gcc.target/i386/pr94802.c b/gcc/testsuite/gcc.target/i386/pr94802.c new file mode 100644 index 0000000..6c1bc66 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr94802.c @@ -0,0 +1,59 @@ +/* PR tree-optimization/94802 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -masm=att" } */ +/* { dg-final { scan-assembler-not "\ttestl\t" } } */ +/* { dg-final { scan-assembler-times "\tcmpl\t" 8 } } */ + +void foo (void); + +int +f1 (int a, int b) +{ + return (a - b) >= 0; +} + +int +f2 (int a, int b) +{ + return (a - b) > 0; +} + +int +f3 (int a, int b) +{ + return (a - b) <= 0; +} + +int +f4 (int a, int b) +{ + return (a - b) < 0; +} + +void +f5 (int a, int b) +{ + if ((a - b) >= 0) + foo (); +} + +void +f6 (int a, int b) +{ + if ((a - b) > 0) + foo (); +} + +void +f7 (int a, int b) +{ + if ((a - b) <= 0) + foo (); +} + +void +f8 (int a, int b) +{ + if ((a - b) < 0) + foo (); +} -- 2.7.4