From: Bill Schmidt Date: Wed, 18 Apr 2012 12:25:17 +0000 (+0000) Subject: re PR tree-optimization/52976 (Revision 186384 breaks the polyhedron tests aermod... X-Git-Tag: misc/gccgo-go1_1_2~3430 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c2723bdeb0d4e2ed329fef1b54acf74410c4de63;p=thirdparty%2Fgcc.git re PR tree-optimization/52976 (Revision 186384 breaks the polyhedron tests aermod.f90 and doduc.f90 at -O3 -ffast-math) gcc: 2012-04-18 Bill Schmidt PR tree-optimization/52976 * tree-ssa-reassoc.c (stmt_is_power_of_op): New function. (decrement_power): Likewise. (propagate_op_to_single_use): Likewise. (zero_one_operation): Handle __builtin_pow* calls in linearized expression trees; factor logic into propagate_op_to_single_use. (undistribute_ops_list): Allow operands with repeat counts > 1. gcc/testsuite: 2012-04-18 Bill Schmidt PR tree-optimization/52976 gfortran.dg/reassoc_7.f: New test. gfortran.dg/reassoc_8.f: Likewise. gfortran.dg/reassoc_9.f: Likewise. gfortran.dg/reassoc_10.f: Likewise. From-SVN: r186567 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0bd86f3d2b29..46cf8e483461 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2012-04-18 Bill Schmidt + + PR tree-optimization/52976 + * tree-ssa-reassoc.c (stmt_is_power_of_op): New function. + (decrement_power): Likewise. + (propagate_op_to_single_use): Likewise. + (zero_one_operation): Handle __builtin_pow* calls in linearized + expression trees; factor logic into propagate_op_to_single_use. + (undistribute_ops_list): Allow operands with repeat counts > 1. + 2012-04-18 Richard Guenther PR tree-optimization/44688 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fba4c22ee6a4..8c8202e6b465 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2012-04-18 Bill Schmidt + + PR tree-optimization/52976 + gfortran.dg/reassoc_7.f: New test. + gfortran.dg/reassoc_8.f: Likewise. + gfortran.dg/reassoc_9.f: Likewise. + gfortran.dg/reassoc_10.f: Likewise. + 2012-04-18 Paolo Carlini PR c++/52422 diff --git a/gcc/testsuite/gfortran.dg/reassoc_10.f b/gcc/testsuite/gfortran.dg/reassoc_10.f new file mode 100644 index 000000000000..698e2c49bb47 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/reassoc_10.f @@ -0,0 +1,17 @@ +! { dg-do compile } +! { dg-options "-O3 -ffast-math -fdump-tree-optimized" } + + SUBROUTINE S55199(P,Q,Dvdph) + implicit none + real(8) :: c1,c2,c3,P,Q,Dvdph + c1=0.1d0 + c2=0.2d0 + c3=0.3d0 + Dvdph = c1 + 2.*P*c2 + 3.*P**2*Q**3*c3 + END + +! There should be five multiplies following un-distribution +! and power expansion. + +! { dg-final { scan-tree-dump-times " \\\* " 5 "optimized" } } +! { dg-final { cleanup-tree-dump "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/reassoc_7.f b/gcc/testsuite/gfortran.dg/reassoc_7.f new file mode 100644 index 000000000000..4f70ef6f9dd0 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/reassoc_7.f @@ -0,0 +1,16 @@ +! { dg-do compile } +! { dg-options "-O3 -ffast-math -fdump-tree-optimized" } + + SUBROUTINE S55199(P,Dvdph) + implicit none + real(8) :: c1,c2,c3,P,Dvdph + c1=0.1d0 + c2=0.2d0 + c3=0.3d0 + Dvdph = c1 + 2.*P*c2 + 3.*P**2*c3 + END + +! There should be two multiplies following un-distribution. + +! { dg-final { scan-tree-dump-times " \\\* " 2 "optimized" } } +! { dg-final { cleanup-tree-dump "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/reassoc_8.f b/gcc/testsuite/gfortran.dg/reassoc_8.f new file mode 100644 index 000000000000..4a6ea72f220f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/reassoc_8.f @@ -0,0 +1,17 @@ +! { dg-do compile } +! { dg-options "-O3 -ffast-math -fdump-tree-optimized" } + + SUBROUTINE S55199(P,Dvdph) + implicit none + real(8) :: c1,c2,c3,P,Dvdph + c1=0.1d0 + c2=0.2d0 + c3=0.3d0 + Dvdph = c1 + 2.*P**2*c2 + 3.*P**3*c3 + END + +! There should be three multiplies following un-distribution +! and power expansion. + +! { dg-final { scan-tree-dump-times " \\\* " 3 "optimized" } } +! { dg-final { cleanup-tree-dump "optimized" } } diff --git a/gcc/testsuite/gfortran.dg/reassoc_9.f b/gcc/testsuite/gfortran.dg/reassoc_9.f new file mode 100644 index 000000000000..53950ee9bc91 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/reassoc_9.f @@ -0,0 +1,17 @@ +! { dg-do compile } +! { dg-options "-O3 -ffast-math -fdump-tree-optimized" } + + SUBROUTINE S55199(P,Dvdph) + implicit none + real(8) :: c1,c2,c3,P,Dvdph + c1=0.1d0 + c2=0.2d0 + c3=0.3d0 + Dvdph = c1 + 2.*P**2*c2 + 3.*P**4*c3 + END + +! There should be three multiplies following un-distribution +! and power expansion. + +! { dg-final { scan-tree-dump-times " \\\* " 3 "optimized" } } +! { dg-final { cleanup-tree-dump "optimized" } } diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index 854ce005a348..314b8041d9ba 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -1020,6 +1020,98 @@ oecount_cmp (const void *p1, const void *p2) return c1->id - c2->id; } +/* Return TRUE iff STMT represents a builtin call that raises OP + to some exponent. */ + +static bool +stmt_is_power_of_op (gimple stmt, tree op) +{ + tree fndecl; + + if (!is_gimple_call (stmt)) + return false; + + fndecl = gimple_call_fndecl (stmt); + + if (!fndecl + || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL) + return false; + + switch (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))) + { + CASE_FLT_FN (BUILT_IN_POW): + CASE_FLT_FN (BUILT_IN_POWI): + return (operand_equal_p (gimple_call_arg (stmt, 0), op, 0)); + + default: + return false; + } +} + +/* Given STMT which is a __builtin_pow* call, decrement its exponent + in place and return the result. Assumes that stmt_is_power_of_op + was previously called for STMT and returned TRUE. */ + +static HOST_WIDE_INT +decrement_power (gimple stmt) +{ + REAL_VALUE_TYPE c, cint; + HOST_WIDE_INT power; + tree arg1; + + switch (DECL_FUNCTION_CODE (gimple_call_fndecl (stmt))) + { + CASE_FLT_FN (BUILT_IN_POW): + arg1 = gimple_call_arg (stmt, 1); + c = TREE_REAL_CST (arg1); + power = real_to_integer (&c) - 1; + real_from_integer (&cint, VOIDmode, power, 0, 0); + gimple_call_set_arg (stmt, 1, build_real (TREE_TYPE (arg1), cint)); + return power; + + CASE_FLT_FN (BUILT_IN_POWI): + arg1 = gimple_call_arg (stmt, 1); + power = TREE_INT_CST_LOW (arg1) - 1; + gimple_call_set_arg (stmt, 1, build_int_cst (TREE_TYPE (arg1), power)); + return power; + + default: + gcc_unreachable (); + } +} + +/* Find the single immediate use of STMT's LHS, and replace it + with OP. Remove STMT. If STMT's LHS is the same as *DEF, + replace *DEF with OP as well. */ + +static void +propagate_op_to_single_use (tree op, gimple stmt, tree *def) +{ + tree lhs; + gimple use_stmt; + use_operand_p use; + gimple_stmt_iterator gsi; + + if (is_gimple_call (stmt)) + lhs = gimple_call_lhs (stmt); + else + lhs = gimple_assign_lhs (stmt); + + gcc_assert (has_single_use (lhs)); + single_imm_use (lhs, &use, &use_stmt); + if (lhs == *def) + *def = op; + SET_USE (use, op); + if (TREE_CODE (op) != SSA_NAME) + update_stmt (use_stmt); + gsi = gsi_for_stmt (stmt); + gsi_remove (&gsi, true); + release_defs (stmt); + + if (is_gimple_call (stmt)) + unlink_stmt_vdef (stmt); +} + /* Walks the linear chain with result *DEF searching for an operation with operand OP and code OPCODE removing that from the chain. *DEF is updated if there is only one operand but no operation left. */ @@ -1031,7 +1123,17 @@ zero_one_operation (tree *def, enum tree_code opcode, tree op) do { - tree name = gimple_assign_rhs1 (stmt); + tree name; + + if (opcode == MULT_EXPR + && stmt_is_power_of_op (stmt, op)) + { + if (decrement_power (stmt) == 1) + propagate_op_to_single_use (op, stmt, def); + return; + } + + name = gimple_assign_rhs1 (stmt); /* If this is the operation we look for and one of the operands is ours simply propagate the other operand into the stmts @@ -1040,24 +1142,27 @@ zero_one_operation (tree *def, enum tree_code opcode, tree op) && (name == op || gimple_assign_rhs2 (stmt) == op)) { - gimple use_stmt; - use_operand_p use; - gimple_stmt_iterator gsi; if (name == op) name = gimple_assign_rhs2 (stmt); - gcc_assert (has_single_use (gimple_assign_lhs (stmt))); - single_imm_use (gimple_assign_lhs (stmt), &use, &use_stmt); - if (gimple_assign_lhs (stmt) == *def) - *def = name; - SET_USE (use, name); - if (TREE_CODE (name) != SSA_NAME) - update_stmt (use_stmt); - gsi = gsi_for_stmt (stmt); - gsi_remove (&gsi, true); - release_defs (stmt); + propagate_op_to_single_use (name, stmt, def); return; } + /* We might have a multiply of two __builtin_pow* calls, and + the operand might be hiding in the rightmost one. */ + if (opcode == MULT_EXPR + && gimple_assign_rhs_code (stmt) == opcode + && TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME) + { + gimple stmt2 = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt)); + if (stmt_is_power_of_op (stmt2, op)) + { + if (decrement_power (stmt2) == 1) + propagate_op_to_single_use (op, stmt2, def); + return; + } + } + /* Continue walking the chain. */ gcc_assert (name != op && TREE_CODE (name) == SSA_NAME); @@ -1222,7 +1327,6 @@ undistribute_ops_list (enum tree_code opcode, dcode = gimple_assign_rhs_code (oe1def); if ((dcode != MULT_EXPR && dcode != RDIV_EXPR) - || oe1->count != 1 || !is_reassociable_op (oe1def, dcode, loop)) continue; @@ -1266,8 +1370,6 @@ undistribute_ops_list (enum tree_code opcode, oecount c; void **slot; size_t idx; - if (oe1->count != 1) - continue; c.oecode = oecode; c.cnt = 1; c.id = next_oecount_id++; @@ -1336,7 +1438,7 @@ undistribute_ops_list (enum tree_code opcode, FOR_EACH_VEC_ELT (operand_entry_t, subops[i], j, oe1) { - if (oe1->op == c->op && oe1->count == 1) + if (oe1->op == c->op) { SET_BIT (candidates2, i); ++nr_candidates2;