Attach patch file. Feng ________________________________________ From: Gcc-patches <gcc-patches-boun...@gcc.gnu.org> on behalf of Feng Xue OS via Gcc-patches <gcc-patches@gcc.gnu.org> Sent: Thursday, September 3, 2020 5:27 PM To: Richard Biener; gcc-patches@gcc.gnu.org Subject: [PATCH 2/2 V3] Simplify plusminus-mult-with-convert expr in forwprop (PR 94234)
This patch is to handle simplification of plusminus-mult-with-convert expression as ((T) X) +- ((T) Y), in which at least one of (X, Y) is result of multiplication. This is done in forwprop pass. We try to transform it to (T) (X +- Y), and resort to gimple-matcher to fold (X +- Y) instead of manually code pattern recognition. Regards, Feng --- 2020-09-03 Feng Xue <f...@os.amperecomputing.com> gcc/ PR tree-optimization/94234 * tree-ssa-forwprop.c (simplify_plusminus_mult_with_convert): New function. (fwprop_ssa_val): Move it before its new caller. (pass_forwprop::execute): Add call to simplify_plusminus_mult_with_convert. gcc/testsuite/ PR tree-optimization/94234 * gcc.dg/pr94234-3.c: New test.
From 98c4b97989207dcef5742e9cb451799feafd125e Mon Sep 17 00:00:00 2001 From: Feng Xue <f...@os.amperecomputing.com> Date: Mon, 17 Aug 2020 23:00:35 +0800 Subject: [PATCH] tree-optimization/94234 - simplify plusminus-mult-with-convert in forwprop For expression as ((T) X) +- ((T) Y), and at lease of (X, Y) is result of multification, try to transform it to (T) (X +- Y), and apply simplification on (X +- Y) if possible. In this way, we can avoid creating almost duplicated rule to handle plusminus-mult-with-convert variant. 2020-09-03 Feng Xue <f...@os.amperecomputing.com> gcc/ PR tree-optimization/94234 * tree-ssa-forwprop.c (simplify_plusminus_mult_with_convert): New function. (fwprop_ssa_val): Move it before its new caller. (pass_forwprop::execute): Add call to simplify_plusminus_mult_with_convert. gcc/testsuite/ PR tree-optimization/94234 * gcc.dg/pr94234-3.c: New test. --- gcc/testsuite/gcc.dg/pr94234-3.c | 42 ++++++++ gcc/tree-ssa-forwprop.c | 168 +++++++++++++++++++++++++++---- 2 files changed, 191 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr94234-3.c diff --git a/gcc/testsuite/gcc.dg/pr94234-3.c b/gcc/testsuite/gcc.dg/pr94234-3.c new file mode 100644 index 00000000000..9bb9b46bd96 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr94234-3.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-forwprop1" } */ + +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; + +ptrdiff_t foo1 (char *a, size_t n) +{ + char *b1 = a + 8 * n; + char *b2 = a + 8 * (n - 1); + + return b1 - b2; +} + +int use_ptr (char *a, char *b); + +ptrdiff_t foo2 (char *a, size_t n) +{ + char *b1 = a + 8 * (n - 1); + char *b2 = a + 8 * n; + + use_ptr (b1, b2); + + return b1 - b2; +} + +int use_int (int i); + +unsigned goo (unsigned m_param, unsigned n_param) +{ + unsigned b1 = m_param * (n_param + 2); + unsigned b2 = m_param * (n_param + 1); + int r = (int)(b1) - (int)(b2); + + use_int (r); + + return r; +} + +/* { dg-final { scan-tree-dump-times "return 8;" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "return -8;" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "return m_param" 1 "forwprop1" } } */ diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index e2d008dfb92..7b9d46ec919 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -338,6 +338,25 @@ remove_prop_source_from_use (tree name) return cfg_changed; } +/* Primitive "lattice" function for gimple_simplify. */ + +static tree +fwprop_ssa_val (tree name) +{ + /* First valueize NAME. */ + if (TREE_CODE (name) == SSA_NAME + && SSA_NAME_VERSION (name) < lattice.length ()) + { + tree val = lattice[SSA_NAME_VERSION (name)]; + if (val) + name = val; + } + /* We continue matching along SSA use-def edges for SSA names + that are not single-use. Currently there are no patterns + that would cause any issues with that. */ + return name; +} + /* Return the rhs of a gassign *STMT in a form of a single tree, converted to type TYPE. @@ -1821,6 +1840,133 @@ simplify_rotate (gimple_stmt_iterator *gsi) return true; } +/* Given ((T) X) +- ((T) Y), and at least one of (X, Y) is result of + multiplication, if the expr can be transformed to (T) (X +- Y) in terms of + two's complement computation, apply simplification on (X +- Y) if it is + possible. As a prerequisite, outer result type (T) has precision not more + than that of inner operand type. */ + +static bool +simplify_plusminus_mult_with_convert (gimple_stmt_iterator *gsi) +{ + gimple *stmt = gsi_stmt (*gsi); + tree lhs = gimple_assign_lhs (stmt); + tree rtype = TREE_TYPE (lhs); + tree ctype = NULL_TREE; + enum tree_code code = gimple_assign_rhs_code (stmt); + + if (code != PLUS_EXPR && code != MINUS_EXPR) + return false; + + /* Skip arithemtic operations that need to preserve overflow for trapping + or sanitization. */ + if (!INTEGRAL_TYPE_P (rtype) + || TYPE_OVERFLOW_TRAPS (rtype) || TYPE_OVERFLOW_SANITIZED (rtype)) + return false; + + tree arg[2] = { gimple_assign_rhs1 (stmt), gimple_assign_rhs2 (stmt) }; + bool any_single_use = false; + bool has_mult = false; + + for (int i = 0; i < 2; i++) + { + if (TREE_CODE (arg[i]) == SSA_NAME) + { + tree def_arg, tem; + enum tree_code def_code; + + defcodefor_name (arg[i], &def_code, &def_arg, NULL); + + if (!CONVERT_EXPR_CODE_P (def_code)) + return false; + + if (!ctype) + { + ctype = TREE_TYPE (def_arg); + + if (!INTEGRAL_TYPE_P (ctype) + || TYPE_PRECISION (ctype) < TYPE_PRECISION (rtype)) + return false; + + if (i) + { + /* The other operand should be a constant, convert it to + inner operand type. */ + arg[0] = wide_int_to_tree (ctype, wi::to_wide (arg[0])); + } + } + else if (!types_compatible_p (ctype, TREE_TYPE (def_arg))) + return false; + + defcodefor_name (def_arg, &def_code, &tem, NULL); + + if (def_code == MULT_EXPR) + has_mult = true; + + if (has_single_use (arg[i])) + any_single_use = true; + + arg[i] = def_arg; + } + else if (TREE_CODE (arg[i]) == INTEGER_CST) + { + if (!ctype) + return false; + + /* This operand is a constant, convert it to inner operand type. */ + arg[i] = wide_int_to_tree (ctype, wi::to_wide (arg[i])); + } + else + return false; + } + + if (!has_mult) + return false; + + gimple_seq seq = NULL; + gimple_seq *pseq = any_single_use ? &seq : NULL; + gimple *g; + tree val; + + if (TYPE_OVERFLOW_WRAPS (ctype)) + /* Arithmetic operation on inner operands is using two's complement + representation in both overflow and normal cases, UB will not occur + and type conversion is trivial. */ + ; + else if (TYPE_SIGN (ctype) == TYPE_SIGN (rtype)) + /* Both outer result type and inner operand type are signed. Here outer + result type should be TYPE_OVERFLOW_UNDEFINED, and inner operand type + also does not incur overflow since it is larger. It is UB-safe to do + arithmetic operation on large signed type, and truncate to small + signed type. */ + ; + else + /* Outer result type is unsigned, while inner operand type is signed. We + only consider a case, in which final simplification result on inner + operands is a simple value (constant or existing SSA). In this + situation, although operation on inner operands is of signed type, it + computes value for outer unsigned type. So we need not to care about + its overflowness. */ + pseq = NULL; + + if (!(val = gimple_simplify (code, ctype, arg[0], arg[1], pseq, + fwprop_ssa_val))) + return false; + + if (TREE_CODE (val) == INTEGER_CST) + g = gimple_build_assign (lhs, NOP_EXPR, + wide_int_to_tree (rtype, wi::to_wide (val))); + else if (TREE_CODE (val) == SSA_NAME) + g = gimple_build_assign (lhs, NOP_EXPR, val); + else + return false; + + if (seq) + gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT); + + gsi_replace (gsi, g, false); + return true; +} /* Check whether an array contains a valid ctz table. */ static bool @@ -2640,25 +2786,6 @@ simplify_vector_constructor (gimple_stmt_iterator *gsi) } -/* Primitive "lattice" function for gimple_simplify. */ - -static tree -fwprop_ssa_val (tree name) -{ - /* First valueize NAME. */ - if (TREE_CODE (name) == SSA_NAME - && SSA_NAME_VERSION (name) < lattice.length ()) - { - tree val = lattice[SSA_NAME_VERSION (name)]; - if (val) - name = val; - } - /* We continue matching along SSA use-def edges for SSA names - that are not single-use. Currently there are no patterns - that would cause any issues with that. */ - return name; -} - /* Main entry point for the forward propagation and statement combine optimizer. */ @@ -3154,6 +3281,9 @@ pass_forwprop::execute (function *fun) || code == BIT_XOR_EXPR) && simplify_rotate (&gsi)) changed = true; + else if (TREE_CODE_CLASS (code) == tcc_binary + && simplify_plusminus_mult_with_convert (&gsi)) + changed = true; else if (code == VEC_PERM_EXPR) { int did_something = simplify_permutation (&gsi); -- 2.17.1