Commit e047844b by Richard Sandiford Committed by Richard Sandiford

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  <richard.sandiford@arm.com>

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
parent b9e25708
2019-01-19 Richard Sandiford <richard.sandiford@arm.com>
* 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 <segher@kernel.crashing.org> 2019-01-18 Segher Boessenkool <segher@kernel.crashing.org>
PR target/88892 PR target/88892
......
...@@ -294,10 +294,12 @@ private: ...@@ -294,10 +294,12 @@ private:
bool acceptable_type_p (tree, unsigned HOST_WIDE_INT *); bool acceptable_type_p (tree, unsigned HOST_WIDE_INT *);
bool multiply_term_by (address_term_info &, tree); bool multiply_term_by (address_term_info &, tree);
inner_likelihood get_inner_likelihood (tree, unsigned HOST_WIDE_INT); 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 &, void analyze_stride (address_info &, address_term_info &,
tree, struct loop *); tree, struct loop *);
bool find_per_loop_multiplication (address_info &, address_term_info &); 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 analyze_address_fragment (address_info &);
void record_address_fragment (gimple *, unsigned HOST_WIDE_INT, void record_address_fragment (gimple *, unsigned HOST_WIDE_INT,
tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT); tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT);
...@@ -803,6 +805,24 @@ loop_versioning::get_inner_likelihood (tree stride, ...@@ -803,6 +805,24 @@ loop_versioning::get_inner_likelihood (tree stride,
return unlikely_p ? INNER_UNLIKELY : INNER_DONT_KNOW; 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 /* The caller has identified that STRIDE is the stride of interest
in TERM, and that the stride is applied in OP_LOOP. Record this in TERM, and that the stride is applied in OP_LOOP. Record this
information in TERM, deciding whether STRIDE is likely to be for information in TERM, deciding whether STRIDE is likely to be for
...@@ -818,17 +838,7 @@ loop_versioning::analyze_stride (address_info &address, ...@@ -818,17 +838,7 @@ loop_versioning::analyze_stride (address_info &address,
term.inner_likelihood = get_inner_likelihood (stride, term.multiplier); term.inner_likelihood = get_inner_likelihood (stride, term.multiplier);
if (dump_enabled_p ()) if (dump_enabled_p ())
{ dump_inner_likelihood (address, term);
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);
}
/* To be a versioning opportunity we require: /* To be a versioning opportunity we require:
...@@ -879,7 +889,7 @@ bool ...@@ -879,7 +889,7 @@ bool
loop_versioning::find_per_loop_multiplication (address_info &address, loop_versioning::find_per_loop_multiplication (address_info &address,
address_term_info &term) 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) if (!mult || gimple_assign_rhs_code (mult) != MULT_EXPR)
return false; return false;
...@@ -909,7 +919,7 @@ loop_versioning::find_per_loop_multiplication (address_info &address, ...@@ -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, /* 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, Here we are interested in any evolution information we can find,
not just evolutions wrt ADDRESS->LOOP. For example, if we find that 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, ...@@ -917,17 +927,17 @@ loop_versioning::find_per_loop_multiplication (address_info &address,
that information can help us eliminate worthless versioning opportunities that information can help us eliminate worthless versioning opportunities
in inner loops. */ in inner loops. */
void bool
loop_versioning::analyze_term_using_scevs (address_info &address, loop_versioning::analyze_term_using_scevs (address_info &address,
address_term_info &term) address_term_info &term)
{ {
gimple *setter = maybe_get_stmt (term.expr); gimple *setter = maybe_get_stmt (term.expr);
if (!setter) if (!setter)
return; return false;
struct loop *wrt_loop = loop_containing_stmt (setter); struct loop *wrt_loop = loop_containing_stmt (setter);
if (!loop_outer (wrt_loop)) if (!loop_outer (wrt_loop))
return; return false;
tree chrec = strip_casts (analyze_scalar_evolution (wrt_loop, term.expr)); tree chrec = strip_casts (analyze_scalar_evolution (wrt_loop, term.expr));
if (TREE_CODE (chrec) == POLYNOMIAL_CHREC) if (TREE_CODE (chrec) == POLYNOMIAL_CHREC)
...@@ -955,7 +965,53 @@ loop_versioning::analyze_term_using_scevs (address_info &address, ...@@ -955,7 +965,53 @@ loop_versioning::analyze_term_using_scevs (address_info &address,
} }
analyze_stride (address, term, stride, get_chrec_loop (chrec)); 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 /* Try to identify loop strides in ADDRESS and try to choose realistic
...@@ -1038,8 +1094,10 @@ loop_versioning::analyze_address_fragment (address_info &address) ...@@ -1038,8 +1094,10 @@ loop_versioning::analyze_address_fragment (address_info &address)
find_per_loop_multiplication and analyze_term_using_scevs can handle, find_per_loop_multiplication and analyze_term_using_scevs can handle,
but the former is much cheaper than SCEV analysis, so try it first. */ but the former is much cheaper than SCEV analysis, so try it first. */
for (unsigned int i = 0; i < address.terms.length (); ++i) for (unsigned int i = 0; i < address.terms.length (); ++i)
if (!find_per_loop_multiplication (address, address.terms[i])) if (!find_per_loop_multiplication (address, address.terms[i])
analyze_term_using_scevs (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. /* Check for strides that are likely to be for the innermost dimension.
......
2019-01-19 Richard Sandiford <richard.sandiford@arm.com>
* 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 <jakub@redhat.com> 2019-01-19 Jakub Jelinek <jakub@redhat.com>
PR fortran/88902 PR fortran/88902
......
...@@ -23,6 +23,6 @@ subroutine f3(x, limit, step) ...@@ -23,6 +23,6 @@ subroutine f3(x, limit, step)
end do end do
end subroutine f3 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 {want to version containing loop} 3 "lversion" } }
! { dg-final { scan-tree-dump-times {versioned this loop} 3 "lversion" } } ! { dg-final { scan-tree-dump-times {versioned this loop} 3 "lversion" } }
! { 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" } }
! { 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" } }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment