From: Richard Sandiford Date: Sat, 19 Jan 2019 12:59:51 +0000 (+0000) Subject: Claw back some of the code size regression in 548.exchange2_r X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e047844bd6af7b167eb06c570c2c79b800165bfb;p=gcc.git Claw back some of the code size regression in 548.exchange2_r This patch tries harder to detect cases in which the inner dimension of an array access is invariant, such as: x(i, :) = 100 It fixes some of the code size regression in 548.exchange2_r, with size improving by 5% compared to before the patch. Of the two other SPEC 2017 tests affected by loop versioning, 554.roms_r improved by a trivial amount (0.3%) and 549.fotonik3d_r didn't change. All three results are with -Ofast -flto. 2019-01-19 Richard Sandiford gcc/ * gimple-loop-versioning.cc (loop_versioning::dump_inner_likelihood): New function, split out from... (loop_versioning::analyze_stride): ...here. (loop_versioning::find_per_loop_multiplication): Use gassign. (loop_versioning::analyze_term_using_scevs): Return a success code. (loop_versioning::analyze_arbitrary_term): New function. (loop_versioning::analyze_address_fragment): Use analyze_arbitrary_term if all else fails. gcc/testsuite/ * gfortran.dg/loop_versioning_1.f90: Bump the number of identified inner strides. * gfortran.dg/loop_versioning_9.f90: New test. * gfortran.dg/loop_versioning_10.f90: Likewise. From-SVN: r268093 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6559a27a9fc..4a4a8ed973c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2019-01-19 Richard Sandiford + + * gimple-loop-versioning.cc (loop_versioning::dump_inner_likelihood): + New function, split out from... + (loop_versioning::analyze_stride): ...here. + (loop_versioning::find_per_loop_multiplication): Use gassign. + (loop_versioning::analyze_term_using_scevs): Return a success code. + (loop_versioning::analyze_arbitrary_term): New function. + (loop_versioning::analyze_address_fragment): Use + analyze_arbitrary_term if all else fails. + 2019-01-18 Segher Boessenkool PR target/88892 diff --git a/gcc/gimple-loop-versioning.cc b/gcc/gimple-loop-versioning.cc index f5e674ba466..2f7cda9c8cb 100644 --- a/gcc/gimple-loop-versioning.cc +++ b/gcc/gimple-loop-versioning.cc @@ -294,10 +294,12 @@ private: bool acceptable_type_p (tree, unsigned HOST_WIDE_INT *); bool multiply_term_by (address_term_info &, tree); inner_likelihood get_inner_likelihood (tree, unsigned HOST_WIDE_INT); + void dump_inner_likelihood (address_info &, address_term_info &); void analyze_stride (address_info &, address_term_info &, tree, struct loop *); bool find_per_loop_multiplication (address_info &, address_term_info &); - void analyze_term_using_scevs (address_info &, address_term_info &); + bool analyze_term_using_scevs (address_info &, address_term_info &); + void analyze_arbitrary_term (address_info &, address_term_info &); void analyze_address_fragment (address_info &); void record_address_fragment (gimple *, unsigned HOST_WIDE_INT, tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT); @@ -803,6 +805,24 @@ loop_versioning::get_inner_likelihood (tree stride, return unlikely_p ? INNER_UNLIKELY : INNER_DONT_KNOW; } +/* Dump the likelihood that TERM's stride is for the innermost dimension. + ADDRESS is the address that contains TERM. */ + +void +loop_versioning::dump_inner_likelihood (address_info &address, + address_term_info &term) +{ + if (term.inner_likelihood == INNER_LIKELY) + dump_printf_loc (MSG_NOTE, address.stmt, "%T is likely to be the" + " innermost dimension\n", term.stride); + else if (term.inner_likelihood == INNER_UNLIKELY) + dump_printf_loc (MSG_NOTE, address.stmt, "%T is probably not the" + " innermost dimension\n", term.stride); + else + dump_printf_loc (MSG_NOTE, address.stmt, "cannot tell whether %T" + " is the innermost dimension\n", term.stride); +} + /* The caller has identified that STRIDE is the stride of interest in TERM, and that the stride is applied in OP_LOOP. Record this information in TERM, deciding whether STRIDE is likely to be for @@ -818,17 +838,7 @@ loop_versioning::analyze_stride (address_info &address, term.inner_likelihood = get_inner_likelihood (stride, term.multiplier); if (dump_enabled_p ()) - { - if (term.inner_likelihood == INNER_LIKELY) - dump_printf_loc (MSG_NOTE, address.stmt, "%T is likely to be the" - " innermost dimension\n", stride); - else if (term.inner_likelihood == INNER_UNLIKELY) - dump_printf_loc (MSG_NOTE, address.stmt, "%T is probably not the" - " innermost dimension\n", stride); - else - dump_printf_loc (MSG_NOTE, address.stmt, "cannot tell whether %T" - " is the innermost dimension\n", stride); - } + dump_inner_likelihood (address, term); /* To be a versioning opportunity we require: @@ -879,7 +889,7 @@ bool loop_versioning::find_per_loop_multiplication (address_info &address, address_term_info &term) { - gimple *mult = maybe_get_assign (term.expr); + gassign *mult = maybe_get_assign (term.expr); if (!mult || gimple_assign_rhs_code (mult) != MULT_EXPR) return false; @@ -909,7 +919,7 @@ loop_versioning::find_per_loop_multiplication (address_info &address, } /* Try to use scalar evolutions to find an address stride for TERM, - which belongs to ADDRESS. + which belongs to ADDRESS. Return true and update TERM if so. Here we are interested in any evolution information we can find, not just evolutions wrt ADDRESS->LOOP. For example, if we find that @@ -917,17 +927,17 @@ loop_versioning::find_per_loop_multiplication (address_info &address, that information can help us eliminate worthless versioning opportunities in inner loops. */ -void +bool loop_versioning::analyze_term_using_scevs (address_info &address, address_term_info &term) { gimple *setter = maybe_get_stmt (term.expr); if (!setter) - return; + return false; struct loop *wrt_loop = loop_containing_stmt (setter); if (!loop_outer (wrt_loop)) - return; + return false; tree chrec = strip_casts (analyze_scalar_evolution (wrt_loop, term.expr)); if (TREE_CODE (chrec) == POLYNOMIAL_CHREC) @@ -955,7 +965,53 @@ loop_versioning::analyze_term_using_scevs (address_info &address, } analyze_stride (address, term, stride, get_chrec_loop (chrec)); + return true; + } + + return false; +} + +/* Address term TERM is an arbitrary term that provides no versioning + opportunities. Analyze it to see whether it contains any likely + inner strides, so that we don't mistakenly version for other + (less likely) candidates. + + This copes with invariant innermost indices such as: + + x(i, :) = 100 + + where the "i" component of the address is invariant in the loop + but provides the real inner stride. + + ADDRESS is the address that contains TERM. */ + +void +loop_versioning::analyze_arbitrary_term (address_info &address, + address_term_info &term) + +{ + /* A multiplication offers two potential strides. Pick the one that + is most likely to be an innermost stride. */ + tree expr = term.expr, alt = NULL_TREE; + gassign *mult = maybe_get_assign (expr); + if (mult && gimple_assign_rhs_code (mult) == MULT_EXPR) + { + expr = strip_casts (gimple_assign_rhs1 (mult)); + alt = strip_casts (gimple_assign_rhs2 (mult)); + } + term.stride = expr; + term.inner_likelihood = get_inner_likelihood (expr, term.multiplier); + if (alt) + { + inner_likelihood alt_l = get_inner_likelihood (alt, term.multiplier); + if (alt_l > term.inner_likelihood) + { + term.stride = alt; + term.inner_likelihood = alt_l; + } } + if (dump_enabled_p ()) + dump_inner_likelihood (address, term); } /* Try to identify loop strides in ADDRESS and try to choose realistic @@ -1038,8 +1094,10 @@ loop_versioning::analyze_address_fragment (address_info &address) find_per_loop_multiplication and analyze_term_using_scevs can handle, but the former is much cheaper than SCEV analysis, so try it first. */ for (unsigned int i = 0; i < address.terms.length (); ++i) - if (!find_per_loop_multiplication (address, address.terms[i])) - analyze_term_using_scevs (address, address.terms[i]); + if (!find_per_loop_multiplication (address, address.terms[i]) + && !analyze_term_using_scevs (address, address.terms[i]) + && !POINTER_TYPE_P (TREE_TYPE (address.terms[i].expr))) + analyze_arbitrary_term (address, address.terms[i]); /* Check for strides that are likely to be for the innermost dimension. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0e4a7784a51..2a59d1b0a4b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-01-19 Richard Sandiford + + * gfortran.dg/loop_versioning_1.f90: Bump the number of identified + inner strides. + * gfortran.dg/loop_versioning_9.f90: New test. + * gfortran.dg/loop_versioning_10.f90: Likewise. + 2019-01-19 Jakub Jelinek PR fortran/88902 diff --git a/gcc/testsuite/gfortran.dg/loop_versioning_1.f90 b/gcc/testsuite/gfortran.dg/loop_versioning_1.f90 index e80f8920d00..144a193d708 100644 --- a/gcc/testsuite/gfortran.dg/loop_versioning_1.f90 +++ b/gcc/testsuite/gfortran.dg/loop_versioning_1.f90 @@ -23,6 +23,6 @@ subroutine f3(x, limit, step) end do end subroutine f3 -! { dg-final { scan-tree-dump-times {likely to be the innermost dimension} 1 "lversion" } } +! { dg-final { scan-tree-dump-times {likely to be the innermost dimension} 2 "lversion" } } ! { dg-final { scan-tree-dump-times {want to version containing loop} 3 "lversion" } } ! { dg-final { scan-tree-dump-times {versioned this loop} 3 "lversion" } } diff --git a/gcc/testsuite/gfortran.dg/loop_versioning_10.f90 b/gcc/testsuite/gfortran.dg/loop_versioning_10.f90 new file mode 100644 index 00000000000..5803527bb3c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/loop_versioning_10.f90 @@ -0,0 +1,31 @@ +! { dg-options "-O3 -fdump-tree-lversion-details" } + +subroutine f1(x) + real :: x(:, :) + x(:, 1) = 100 +end subroutine f1 + +subroutine f2(x, i) + real :: x(:, :) + integer :: i + x(:, i) = 100 +end subroutine f2 + +subroutine f3(x) + real :: x(:, :) + do j = lbound(x, 1), ubound(x, 1) + x(j, 1) = 100 + end do +end subroutine f3 + +subroutine f4(x, i) + real :: x(:, :) + integer :: i + do j = lbound(x, 1), ubound(x, 1) + x(j, i) = 100 + end do +end subroutine f4 + +! { dg-final { scan-tree-dump-times {likely to be the innermost dimension} 6 "lversion" } } +! { dg-final { scan-tree-dump-times {want to version} 4 "lversion" } } +! { dg-final { scan-tree-dump-times {versioned} 4 "lversion" } } diff --git a/gcc/testsuite/gfortran.dg/loop_versioning_9.f90 b/gcc/testsuite/gfortran.dg/loop_versioning_9.f90 new file mode 100644 index 00000000000..7a0fd55eaca --- /dev/null +++ b/gcc/testsuite/gfortran.dg/loop_versioning_9.f90 @@ -0,0 +1,31 @@ +! { dg-options "-O3 -fdump-tree-lversion-details" } + +subroutine f1(x) + real :: x(:, :) + x(1, :) = 100 +end subroutine f1 + +subroutine f2(x, i) + real :: x(:, :) + integer :: i + x(i, :) = 100 +end subroutine f2 + +subroutine f3(x) + real :: x(:, :) + do j = lbound(x, 2), ubound(x, 2) + x(1, j) = 100 + end do +end subroutine f3 + +subroutine f4(x, i) + real :: x(:, :) + integer :: i + do j = lbound(x, 2), ubound(x, 2) + x(i, j) = 100 + end do +end subroutine f4 + +! { dg-final { scan-tree-dump-times {likely to be the innermost dimension} 4 "lversion" } } +! { dg-final { scan-tree-dump-not {want to version} "lversion" } } +! { dg-final { scan-tree-dump-not {versioned} "lversion" } }