> On Fri, Jun 12, 2020 at 11:28 PM Martin Jambor <mjam...@suse.cz> wrote: > > > > Hi, > > > > when Fortran functions pass array descriptors they receive as a > > parameter to another function, they actually rebuild it. Thanks to > > work done mainly by Feng, IPA-CP can already handle the cases when > > they pass directly the values loaded from the original descriptor. > > Unfortunately, perhaps the most important one, stride, is first > > checked against zero and is replaced with one in that case: > > > > _12 = *a_11(D).dim[0].stride; > > if (_12 != 0) > > goto <bb 4>; [50.00%] > > else > > goto <bb 3>; [50.00%] > > > > <bb 3> > > // empty BB > > <bb 4> > > # iftmp.22_9 = PHI <_12(2), 1(3)> > > ... > > parm.6.dim[0].stride = iftmp.22_9; > > ... > > __x_MOD_foo (&parm.6, b_31(D)); > > > > in the most important and hopefully common cases, the incoming value > > is already 1 and we fail to propagate it. > > > > I would therefore like to propose the following way of encoding this > > situation in pass-through jump functions using using ASSERTT_EXPR > > operation code meaning that if the incoming value is the same as the > > "operand" in the jump function, it is passed on, otherwise the result > > is unknown. This of course captures only the single (but most > > important) case but is an improvement and does not need enlarging the > > jump function structure and is simple to pattern match. Encoding that > > zero needs to be changed to one would need another field and matching > > it would be slightly more complicated too. > > > > Bootstrapped and tested on x86_64-linux, LTO bootstrap is underway. OK > > if it passes? > > Looks reasonable - I wonder if we somehow track enough info to > infer the _12 != 0 check in IPA propagation? So whether there's the > possibility to not use "conditional 1" as I understand you do but > "conditional *a_11(D).dim[0].stride"? Because AFAICS you > compare _12 against 1 in IPA propagation to enable the propagation, > why not compare it against 0? Or even allow all cases to be resolved > if _12 is a constant? That is, propagate a "_12 != 0 ? 12 : 1" jump > function which you should be able to resolve in the exact same > way via values_equal_for_ipa_cp_p?
I was wondering, since we can now represent more complex arithmetic operations, if we can express param0 + (param0 != 0) using the jump function w/o use of assert exprs? In general assert exprs seems like good concept to represent conditional jumps though. Honza > > Thanks, > Richard. > > > Thanks, > > > > Martin > > > > > > 2020-06-12 Martin Jambor <mjam...@suse.cz> > > > > * ipa-prop.h (ipa_pass_through_data): Expand comment describing > > operation. > > * ipa-prop.c (analyze_agg_content_value): Detect new special case > > and > > encode it as ASSERT_EXPR. > > * ipa-cp.c (values_equal_for_ipcp_p): Move before > > ipa_get_jf_arith_result. > > (ipa_get_jf_arith_result): Special case ASSERT_EXPR. > > > > testsuite/ > > * gfortran.dg/ipcp-array-2.f90: New test. > > --- > > gcc/ipa-cp.c | 48 ++++--- > > gcc/ipa-prop.c | 148 ++++++++++++++------- > > gcc/ipa-prop.h | 11 +- > > gcc/testsuite/gfortran.dg/ipcp-array-2.f90 | 45 +++++++ > > 4 files changed, 179 insertions(+), 73 deletions(-) > > create mode 100644 gcc/testsuite/gfortran.dg/ipcp-array-2.f90 > > > > diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c > > index b0c8f405260..4a2714c634f 100644 > > --- a/gcc/ipa-cp.c > > +++ b/gcc/ipa-cp.c > > @@ -1290,6 +1290,26 @@ initialize_node_lattices (struct cgraph_node *node) > > } > > } > > > > +/* Return true iff X and Y should be considered equal values by IPA-CP. */ > > + > > +static bool > > +values_equal_for_ipcp_p (tree x, tree y) > > +{ > > + gcc_checking_assert (x != NULL_TREE && y != NULL_TREE); > > + > > + if (x == y) > > + return true; > > + > > + if (TREE_CODE (x) == ADDR_EXPR > > + && TREE_CODE (y) == ADDR_EXPR > > + && TREE_CODE (TREE_OPERAND (x, 0)) == CONST_DECL > > + && TREE_CODE (TREE_OPERAND (y, 0)) == CONST_DECL) > > + return operand_equal_p (DECL_INITIAL (TREE_OPERAND (x, 0)), > > + DECL_INITIAL (TREE_OPERAND (y, 0)), 0); > > + else > > + return operand_equal_p (x, y, 0); > > +} > > + > > /* Return the result of a (possibly arithmetic) operation on the constant > > value INPUT. OPERAND is 2nd operand for binary operation. RES_TYPE is > > the type of the parameter to which the result is passed. Return > > @@ -1307,6 +1327,14 @@ ipa_get_jf_arith_result (enum tree_code opcode, tree > > input, tree operand, > > if (!is_gimple_ip_invariant (input)) > > return NULL_TREE; > > > > + if (opcode == ASSERT_EXPR) > > + { > > + if (values_equal_for_ipcp_p (input, operand)) > > + return input; > > + else > > + return NULL_TREE; > > + } > > + > > if (!res_type) > > { > > if (TREE_CODE_CLASS (opcode) == tcc_comparison) > > @@ -1739,26 +1767,6 @@ ipcp_verify_propagated_values (void) > > } > > } > > > > -/* Return true iff X and Y should be considered equal values by IPA-CP. */ > > - > > -static bool > > -values_equal_for_ipcp_p (tree x, tree y) > > -{ > > - gcc_checking_assert (x != NULL_TREE && y != NULL_TREE); > > - > > - if (x == y) > > - return true; > > - > > - if (TREE_CODE (x) == ADDR_EXPR > > - && TREE_CODE (y) == ADDR_EXPR > > - && TREE_CODE (TREE_OPERAND (x, 0)) == CONST_DECL > > - && TREE_CODE (TREE_OPERAND (y, 0)) == CONST_DECL) > > - return operand_equal_p (DECL_INITIAL (TREE_OPERAND (x, 0)), > > - DECL_INITIAL (TREE_OPERAND (y, 0)), 0); > > - else > > - return operand_equal_p (x, y, 0); > > -} > > - > > /* Return true iff X and Y should be considered equal contexts by IPA-CP. > > */ > > > > static bool > > diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c > > index 71ac0e104d2..16483fb413a 100644 > > --- a/gcc/ipa-prop.c > > +++ b/gcc/ipa-prop.c > > @@ -1704,75 +1704,123 @@ analyze_agg_content_value (struct > > ipa_func_body_info *fbi, > > > > stmt = SSA_NAME_DEF_STMT (rhs1); > > if (!is_gimple_assign (stmt)) > > - return; > > + break; > > > > rhs1 = gimple_assign_rhs1 (stmt); > > } > > > > - code = gimple_assign_rhs_code (stmt); > > - switch (gimple_assign_rhs_class (stmt)) > > + if (gphi *phi = dyn_cast<gphi *> (stmt)) > > { > > - case GIMPLE_SINGLE_RHS: > > - if (is_gimple_ip_invariant (rhs1)) > > + /* Also special case like the following (a is a formal parameter): > > + > > + _12 = *a_11(D).dim[0].stride; > > + ... > > + # iftmp.22_9 = PHI <_12(2), 1(3)> > > + ... > > + parm.6.dim[0].stride = iftmp.22_9; > > + ... > > + __x_MOD_foo (&parm.6, b_31(D)); > > + > > + The aggregate function describing parm.6.dim[0].stride is encoded > > as a > > + PASS-THROUGH jump function with ASSERT_EXPR operation whith > > operand 1 > > + (the constant from the PHI node). */ > > + > > + if (gimple_phi_num_args (phi) != 2) > > + return; > > + tree arg0 = gimple_phi_arg_def (phi, 0); > > + tree arg1 = gimple_phi_arg_def (phi, 1); > > + tree operand; > > + > > + if (is_gimple_ip_invariant (arg1)) > > { > > - agg_value->pass_through.operand = rhs1; > > - return; > > + operand = arg1; > > + rhs1 = arg0; > > } > > - code = NOP_EXPR; > > - break; > > - > > - case GIMPLE_UNARY_RHS: > > - /* NOTE: A GIMPLE_UNARY_RHS operation might not be tcc_unary > > - (truth_not_expr is example), GIMPLE_BINARY_RHS does not imply > > - tcc_binary, this subtleness is somewhat misleading. > > - > > - Since tcc_unary is widely used in IPA-CP code to check an operation > > - with one operand, here we only allow tc_unary operation to avoid > > - possible problem. Then we can use (opclass == tc_unary) or not to > > - distinguish unary and binary. */ > > - if (TREE_CODE_CLASS (code) != tcc_unary || CONVERT_EXPR_CODE_P > > (code)) > > + else if (is_gimple_ip_invariant (arg0)) > > + { > > + operand = arg0; > > + rhs1 = arg1; > > + } > > + else > > return; > > > > rhs1 = get_ssa_def_if_simple_copy (rhs1, &stmt); > > - break; > > + if (!is_gimple_assign (stmt)) > > + return; > > > > - case GIMPLE_BINARY_RHS: > > - { > > - gimple *rhs1_stmt = stmt; > > - gimple *rhs2_stmt = stmt; > > - tree rhs2 = gimple_assign_rhs2 (stmt); > > + code = ASSERT_EXPR; > > + agg_value->pass_through.operand = operand; > > + } > > + else if (is_gimple_assign (stmt)) > > + { > > + code = gimple_assign_rhs_code (stmt); > > + switch (gimple_assign_rhs_class (stmt)) > > + { > > + case GIMPLE_SINGLE_RHS: > > + if (is_gimple_ip_invariant (rhs1)) > > + { > > + agg_value->pass_through.operand = rhs1; > > + return; > > + } > > + code = NOP_EXPR; > > + break; > > > > - rhs1 = get_ssa_def_if_simple_copy (rhs1, &rhs1_stmt); > > - rhs2 = get_ssa_def_if_simple_copy (rhs2, &rhs2_stmt); > > + case GIMPLE_UNARY_RHS: > > + /* NOTE: A GIMPLE_UNARY_RHS operation might not be tcc_unary > > + (truth_not_expr is example), GIMPLE_BINARY_RHS does not imply > > + tcc_binary, this subtleness is somewhat misleading. > > > > - if (is_gimple_ip_invariant (rhs2)) > > + Since tcc_unary is widely used in IPA-CP code to check an > > operation > > + with one operand, here we only allow tc_unary operation to > > avoid > > + possible problem. Then we can use (opclass == tc_unary) or > > not to > > + distinguish unary and binary. */ > > + if (TREE_CODE_CLASS (code) != tcc_unary || CONVERT_EXPR_CODE_P > > (code)) > > + return; > > + > > + rhs1 = get_ssa_def_if_simple_copy (rhs1, &stmt); > > + break; > > + > > + case GIMPLE_BINARY_RHS: > > { > > - agg_value->pass_through.operand = rhs2; > > - stmt = rhs1_stmt; > > - } > > - else if (is_gimple_ip_invariant (rhs1)) > > - { > > - if (TREE_CODE_CLASS (code) == tcc_comparison) > > - code = swap_tree_comparison (code); > > - else if (!commutative_tree_code (code)) > > + gimple *rhs1_stmt = stmt; > > + gimple *rhs2_stmt = stmt; > > + tree rhs2 = gimple_assign_rhs2 (stmt); > > + > > + rhs1 = get_ssa_def_if_simple_copy (rhs1, &rhs1_stmt); > > + rhs2 = get_ssa_def_if_simple_copy (rhs2, &rhs2_stmt); > > + > > + if (is_gimple_ip_invariant (rhs2)) > > + { > > + agg_value->pass_through.operand = rhs2; > > + stmt = rhs1_stmt; > > + } > > + else if (is_gimple_ip_invariant (rhs1)) > > + { > > + if (TREE_CODE_CLASS (code) == tcc_comparison) > > + code = swap_tree_comparison (code); > > + else if (!commutative_tree_code (code)) > > + return; > > + > > + agg_value->pass_through.operand = rhs1; > > + stmt = rhs2_stmt; > > + rhs1 = rhs2; > > + } > > + else > > return; > > > > - agg_value->pass_through.operand = rhs1; > > - stmt = rhs2_stmt; > > - rhs1 = rhs2; > > + if (TREE_CODE_CLASS (code) != tcc_comparison > > + && !useless_type_conversion_p (TREE_TYPE (lhs), > > + TREE_TYPE (rhs1))) > > + return; > > } > > - else > > - return; > > + break; > > > > - if (TREE_CODE_CLASS (code) != tcc_comparison > > - && !useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE > > (rhs1))) > > + default: > > return; > > - } > > - break; > > - > > - default: > > - return; > > - } > > + } > > + } > > + else > > + return; > > > > if (TREE_CODE (rhs1) != SSA_NAME) > > index = load_from_unmodified_param_or_agg (fbi, fbi->info, stmt, > > diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h > > index 168c4c26443..a96dac85962 100644 > > --- a/gcc/ipa-prop.h > > +++ b/gcc/ipa-prop.h > > @@ -94,9 +94,14 @@ struct GTY(()) ipa_pass_through_data > > /* Number of the caller's formal parameter being passed. */ > > int formal_id; > > /* Operation that is performed on the argument before it is passed on. > > - NOP_EXPR means no operation. Otherwise oper must be a simple binary > > - arithmetic operation where the caller's parameter is the first > > operand and > > - operand field from this structure is the second one. */ > > + Special values which have other meaning than in normal contexts: > > + - NOP_EXPR means no operation, not even type conversion. > > + - ASSERT_EXPR means that only the value in operand is allowed to > > pass > > + through (without any change), for all other values the result is > > + unknown. > > + Otherwise operation must be a simple binary or unary arithmetic > > operation > > + where the caller's parameter is the first operand and (for binary > > + operations) the operand field from this structure is the second one. > > */ > > enum tree_code operation; > > /* When the passed value is a pointer, it is set to true only when we are > > certain that no write to the object it points to has occurred since > > the > > diff --git a/gcc/testsuite/gfortran.dg/ipcp-array-2.f90 > > b/gcc/testsuite/gfortran.dg/ipcp-array-2.f90 > > new file mode 100644 > > index 00000000000..9af8fffa7ea > > --- /dev/null > > +++ b/gcc/testsuite/gfortran.dg/ipcp-array-2.f90 > > @@ -0,0 +1,45 @@ > > +! { dg-do compile } > > +! { dg-options "-O3 -fno-inline -fwhole-program -fdump-ipa-cp-details > > -fdump-tree-lversion-details" } > > + > > +module x > > + implicit none > > +contains > > + subroutine foo(a, b) > > + real :: a(:,:) > > + real :: b > > + integer :: i,j > > + b = 0. > > + do j=1,size(a,2) > > + do i=1,size(a,1) > > + b = b + a(i,j) * i * j > > + end do > > + end do > > + end subroutine foo > > + > > + subroutine bar(a, b) > > + real :: a(:,:) > > + real :: b > > + call foo (a,b) > > + end subroutine bar > > + > > +end module x > > + > > +program main > > + use x > > + implicit none > > + integer :: n, m > > + real, dimension(4,3) :: a > > + real, dimension(3,4) :: c > > + real :: b > > + call random_number(a) > > + call bar(a,b) > > + print *,b > > + > > + call random_number(c) > > + call bar(c,b) > > + print *,b > > + > > +end program main > > + > > +! { dg-final { scan-ipa-dump "op assert_expr 1" "cp" } } > > +! { dg-final { scan-tree-dump-not "versioned this loop for when certain > > strides are 1" "lversion" } } > > -- > > 2.26.2 > >