re PR fortran/45648 (Unnecessary temporary for transpose calls as actual argument.)
2010-09-21 Mikael Morin <mikael@gcc.gnu.org> PR fortran/45648 * trans-array.c (gfc_conv_expr_descriptor): Calculate dim out of n and info->dim. PR fortran/45648 * trans-array.c (gfc_conv_expr_descriptor): Unset full if we are accessing dimensions in reversed order. PR fortran/45648 * trans-array.c (gfc_conv_expr_descriptor): Special case noncopying intrinsic function call. * trans-array.c (gfc_conv_expr_descriptor): Remove ss lookup. Update asserts accordingly. PR fortran/45648 * trans.h (gfc_se): New field force_tmp. * trans-expr.c (gfc_conv_procedure_call): Check for argument alias and set parmse.force_tmp if some alias is found. * trans-array.c (gfc_conv_expr_descriptor): Force a temporary creation if se->force_tmp is set. 2010-09-21 Mikael Morin <mikael@gcc.gnu.org> PR fortran/45648 * gfortran.dg/inline_transpose_1.f90: Update temporary's locations and counts. Add non-elemental function call check. PR fortran/45648 * gfortran.dg/inline_transpose_1.f90: Add function calls with aliasing arguments checks. Update temporary counts. * gfortran.dg/transpose_optimization_1.f90: New. From-SVN: r164494
This commit is contained in:
parent
5e68c77aff
commit
0b4f2770ff
@ -1,3 +1,27 @@
|
|||||||
|
2010-09-21 Mikael Morin <mikael@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR fortran/45648
|
||||||
|
* trans-array.c (gfc_conv_expr_descriptor): Calculate dim out of n and
|
||||||
|
info->dim.
|
||||||
|
|
||||||
|
PR fortran/45648
|
||||||
|
* trans-array.c (gfc_conv_expr_descriptor): Unset full if we are
|
||||||
|
accessing dimensions in reversed order.
|
||||||
|
|
||||||
|
PR fortran/45648
|
||||||
|
* trans-array.c (gfc_conv_expr_descriptor): Special case noncopying
|
||||||
|
intrinsic function call.
|
||||||
|
|
||||||
|
* trans-array.c (gfc_conv_expr_descriptor): Remove ss lookup.
|
||||||
|
Update asserts accordingly.
|
||||||
|
|
||||||
|
PR fortran/45648
|
||||||
|
* trans.h (gfc_se): New field force_tmp.
|
||||||
|
* trans-expr.c (gfc_conv_procedure_call): Check for argument alias
|
||||||
|
and set parmse.force_tmp if some alias is found.
|
||||||
|
* trans-array.c (gfc_conv_expr_descriptor): Force a temporary creation
|
||||||
|
if se->force_tmp is set.
|
||||||
|
|
||||||
2010-09-20 Janus Weil <janus@gcc.gnu.org>
|
2010-09-20 Janus Weil <janus@gcc.gnu.org>
|
||||||
|
|
||||||
PR fortran/45438
|
PR fortran/45438
|
||||||
|
@ -5136,7 +5136,6 @@ get_array_charlen (gfc_expr *expr, gfc_se *se)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Convert an array for passing as an actual argument. Expressions and
|
/* Convert an array for passing as an actual argument. Expressions and
|
||||||
vector subscripts are evaluated and stored in a temporary, which is then
|
vector subscripts are evaluated and stored in a temporary, which is then
|
||||||
passed. For whole arrays the descriptor is passed. For array sections
|
passed. For whole arrays the descriptor is passed. For array sections
|
||||||
@ -5158,13 +5157,18 @@ get_array_charlen (gfc_expr *expr, gfc_se *se)
|
|||||||
EXPR is the right-hand side of a pointer assignment and
|
EXPR is the right-hand side of a pointer assignment and
|
||||||
se->expr is the descriptor for the previously-evaluated
|
se->expr is the descriptor for the previously-evaluated
|
||||||
left-hand side. The function creates an assignment from
|
left-hand side. The function creates an assignment from
|
||||||
EXPR to se->expr. */
|
EXPR to se->expr.
|
||||||
|
|
||||||
|
|
||||||
|
The se->force_tmp flag disables the non-copying descriptor optimization
|
||||||
|
that is used for transpose. It may be used in cases where there is an
|
||||||
|
alias between the transpose argument and another argument in the same
|
||||||
|
function call. */
|
||||||
|
|
||||||
void
|
void
|
||||||
gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
||||||
{
|
{
|
||||||
gfc_loopinfo loop;
|
gfc_loopinfo loop;
|
||||||
gfc_ss *secss;
|
|
||||||
gfc_ss_info *info;
|
gfc_ss_info *info;
|
||||||
int need_tmp;
|
int need_tmp;
|
||||||
int n;
|
int n;
|
||||||
@ -5175,7 +5179,9 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
|||||||
tree offset;
|
tree offset;
|
||||||
int full;
|
int full;
|
||||||
bool subref_array_target = false;
|
bool subref_array_target = false;
|
||||||
|
gfc_expr *arg;
|
||||||
|
|
||||||
|
gcc_assert (ss != NULL);
|
||||||
gcc_assert (ss != gfc_ss_terminator);
|
gcc_assert (ss != gfc_ss_terminator);
|
||||||
|
|
||||||
/* Special case things we know we can pass easily. */
|
/* Special case things we know we can pass easily. */
|
||||||
@ -5185,22 +5191,21 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
|||||||
/* If we have a linear array section, we can pass it directly.
|
/* If we have a linear array section, we can pass it directly.
|
||||||
Otherwise we need to copy it into a temporary. */
|
Otherwise we need to copy it into a temporary. */
|
||||||
|
|
||||||
/* Find the SS for the array section. */
|
gcc_assert (ss->type == GFC_SS_SECTION);
|
||||||
secss = ss;
|
gcc_assert (ss->expr == expr);
|
||||||
while (secss != gfc_ss_terminator && secss->type != GFC_SS_SECTION)
|
info = &ss->data.info;
|
||||||
secss = secss->next;
|
|
||||||
|
|
||||||
gcc_assert (secss != gfc_ss_terminator);
|
|
||||||
info = &secss->data.info;
|
|
||||||
|
|
||||||
/* Get the descriptor for the array. */
|
/* Get the descriptor for the array. */
|
||||||
gfc_conv_ss_descriptor (&se->pre, secss, 0);
|
gfc_conv_ss_descriptor (&se->pre, ss, 0);
|
||||||
desc = info->descriptor;
|
desc = info->descriptor;
|
||||||
|
|
||||||
subref_array_target = se->direct_byref && is_subref_array (expr);
|
subref_array_target = se->direct_byref && is_subref_array (expr);
|
||||||
need_tmp = gfc_ref_needs_temporary_p (expr->ref)
|
need_tmp = gfc_ref_needs_temporary_p (expr->ref)
|
||||||
&& !subref_array_target;
|
&& !subref_array_target;
|
||||||
|
|
||||||
|
if (se->force_tmp)
|
||||||
|
need_tmp = 1;
|
||||||
|
|
||||||
if (need_tmp)
|
if (need_tmp)
|
||||||
full = 0;
|
full = 0;
|
||||||
else if (GFC_ARRAY_TYPE_P (TREE_TYPE (desc)))
|
else if (GFC_ARRAY_TYPE_P (TREE_TYPE (desc)))
|
||||||
@ -5215,6 +5220,14 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
|||||||
else
|
else
|
||||||
full = gfc_full_array_ref_p (info->ref, NULL);
|
full = gfc_full_array_ref_p (info->ref, NULL);
|
||||||
|
|
||||||
|
if (full)
|
||||||
|
for (n = 0; n < info->dimen; n++)
|
||||||
|
if (info->dim[n] != n)
|
||||||
|
{
|
||||||
|
full = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (full)
|
if (full)
|
||||||
{
|
{
|
||||||
if (se->direct_byref && !se->byref_noassign)
|
if (se->direct_byref && !se->byref_noassign)
|
||||||
@ -5245,30 +5258,45 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EXPR_FUNCTION:
|
case EXPR_FUNCTION:
|
||||||
|
|
||||||
|
/* We don't need to copy data in some cases. */
|
||||||
|
arg = gfc_get_noncopying_intrinsic_argument (expr);
|
||||||
|
if (arg)
|
||||||
|
{
|
||||||
|
/* This is a call to transpose... */
|
||||||
|
gcc_assert (expr->value.function.isym->id == GFC_ISYM_TRANSPOSE);
|
||||||
|
/* ... which has already been handled by the scalarizer, so
|
||||||
|
that we just need to get its argument's descriptor. */
|
||||||
|
gfc_conv_expr_descriptor (se, expr->value.function.actual->expr, ss);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* A transformational function return value will be a temporary
|
/* A transformational function return value will be a temporary
|
||||||
array descriptor. We still need to go through the scalarizer
|
array descriptor. We still need to go through the scalarizer
|
||||||
to create the descriptor. Elemental functions ar handled as
|
to create the descriptor. Elemental functions ar handled as
|
||||||
arbitrary expressions, i.e. copy to a temporary. */
|
arbitrary expressions, i.e. copy to a temporary. */
|
||||||
secss = ss;
|
|
||||||
/* Look for the SS for this function. */
|
|
||||||
while (secss != gfc_ss_terminator
|
|
||||||
&& (secss->type != GFC_SS_FUNCTION || secss->expr != expr))
|
|
||||||
secss = secss->next;
|
|
||||||
|
|
||||||
if (se->direct_byref)
|
if (se->direct_byref)
|
||||||
{
|
{
|
||||||
gcc_assert (secss != gfc_ss_terminator);
|
gcc_assert (ss->type == GFC_SS_FUNCTION && ss->expr == expr);
|
||||||
|
|
||||||
/* For pointer assignments pass the descriptor directly. */
|
/* For pointer assignments pass the descriptor directly. */
|
||||||
se->ss = secss;
|
if (se->ss == NULL)
|
||||||
|
se->ss = ss;
|
||||||
|
else
|
||||||
|
gcc_assert (se->ss == ss);
|
||||||
se->expr = gfc_build_addr_expr (NULL_TREE, se->expr);
|
se->expr = gfc_build_addr_expr (NULL_TREE, se->expr);
|
||||||
gfc_conv_expr (se, expr);
|
gfc_conv_expr (se, expr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (secss == gfc_ss_terminator)
|
if (ss->expr != expr)
|
||||||
{
|
{
|
||||||
/* Elemental function. */
|
/* Elemental function. */
|
||||||
|
gcc_assert ((expr->value.function.esym != NULL
|
||||||
|
&& expr->value.function.esym->attr.elemental)
|
||||||
|
|| (expr->value.function.isym != NULL
|
||||||
|
&& expr->value.function.isym->elemental));
|
||||||
need_tmp = 1;
|
need_tmp = 1;
|
||||||
if (expr->ts.type == BT_CHARACTER
|
if (expr->ts.type == BT_CHARACTER
|
||||||
&& expr->ts.u.cl->length->expr_type != EXPR_CONSTANT)
|
&& expr->ts.u.cl->length->expr_type != EXPR_CONSTANT)
|
||||||
@ -5279,7 +5307,7 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Transformational function. */
|
/* Transformational function. */
|
||||||
info = &secss->data.info;
|
info = &ss->data.info;
|
||||||
need_tmp = 0;
|
need_tmp = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -5292,12 +5320,10 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
|||||||
{
|
{
|
||||||
need_tmp = 0;
|
need_tmp = 0;
|
||||||
info = &ss->data.info;
|
info = &ss->data.info;
|
||||||
secss = ss;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
need_tmp = 1;
|
need_tmp = 1;
|
||||||
secss = NULL;
|
|
||||||
info = NULL;
|
info = NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -5305,11 +5331,15 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
|||||||
default:
|
default:
|
||||||
/* Something complicated. Copy it into a temporary. */
|
/* Something complicated. Copy it into a temporary. */
|
||||||
need_tmp = 1;
|
need_tmp = 1;
|
||||||
secss = NULL;
|
|
||||||
info = NULL;
|
info = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we are creating a temporary, we don't need to bother about aliases
|
||||||
|
anymore. */
|
||||||
|
if (need_tmp)
|
||||||
|
se->force_tmp = 0;
|
||||||
|
|
||||||
gfc_init_loopinfo (&loop);
|
gfc_init_loopinfo (&loop);
|
||||||
|
|
||||||
/* Associate the SS with the loop. */
|
/* Associate the SS with the loop. */
|
||||||
@ -5421,7 +5451,6 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
|||||||
se->string_length = gfc_get_expr_charlen (expr);
|
se->string_length = gfc_get_expr_charlen (expr);
|
||||||
|
|
||||||
desc = info->descriptor;
|
desc = info->descriptor;
|
||||||
gcc_assert (secss && secss != gfc_ss_terminator);
|
|
||||||
if (se->direct_byref && !se->byref_noassign)
|
if (se->direct_byref && !se->byref_noassign)
|
||||||
{
|
{
|
||||||
/* For pointer assignments we fill in the destination. */
|
/* For pointer assignments we fill in the destination. */
|
||||||
@ -5439,12 +5468,11 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
|||||||
}
|
}
|
||||||
|
|
||||||
offset = gfc_index_zero_node;
|
offset = gfc_index_zero_node;
|
||||||
dim = 0;
|
|
||||||
|
|
||||||
/* The following can be somewhat confusing. We have two
|
/* The following can be somewhat confusing. We have two
|
||||||
descriptors, a new one and the original array.
|
descriptors, a new one and the original array.
|
||||||
{parm, parmtype, dim} refer to the new one.
|
{parm, parmtype, dim} refer to the new one.
|
||||||
{desc, type, n, secss, loop} refer to the original, which maybe
|
{desc, type, n, loop} refer to the original, which maybe
|
||||||
a descriptorless array.
|
a descriptorless array.
|
||||||
The bounds of the scalarization are the bounds of the section.
|
The bounds of the scalarization are the bounds of the section.
|
||||||
We don't have to worry about numeric overflows when calculating
|
We don't have to worry about numeric overflows when calculating
|
||||||
@ -5479,9 +5507,6 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Check we haven't somehow got out of sync. */
|
|
||||||
gcc_assert (info->dim[dim] == n);
|
|
||||||
|
|
||||||
/* Evaluate and remember the start of the section. */
|
/* Evaluate and remember the start of the section. */
|
||||||
start = info->start[n];
|
start = info->start[n];
|
||||||
stride = gfc_evaluate_now (stride, &loop.pre);
|
stride = gfc_evaluate_now (stride, &loop.pre);
|
||||||
@ -5505,6 +5530,14 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
|||||||
/* Vector subscripts need copying and are handled elsewhere. */
|
/* Vector subscripts need copying and are handled elsewhere. */
|
||||||
if (info->ref)
|
if (info->ref)
|
||||||
gcc_assert (info->ref->u.ar.dimen_type[n] == DIMEN_RANGE);
|
gcc_assert (info->ref->u.ar.dimen_type[n] == DIMEN_RANGE);
|
||||||
|
|
||||||
|
/* look for the corresponding scalarizer dimension: dim. */
|
||||||
|
for (dim = 0; dim < ndim; dim++)
|
||||||
|
if (info->dim[dim] == n)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* loop exited early: the DIM being looked for has been found. */
|
||||||
|
gcc_assert (dim < ndim);
|
||||||
|
|
||||||
/* Set the new lower bound. */
|
/* Set the new lower bound. */
|
||||||
from = loop.from[dim];
|
from = loop.from[dim];
|
||||||
@ -5559,8 +5592,6 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
|
|||||||
/* Store the new stride. */
|
/* Store the new stride. */
|
||||||
gfc_conv_descriptor_stride_set (&loop.pre, parm,
|
gfc_conv_descriptor_stride_set (&loop.pre, parm,
|
||||||
gfc_rank_cst[dim], stride);
|
gfc_rank_cst[dim], stride);
|
||||||
|
|
||||||
dim++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (se->data_not_needed)
|
if (se->data_not_needed)
|
||||||
|
@ -2770,7 +2770,7 @@ conv_isocbinding_procedure (gfc_se * se, gfc_symbol * sym,
|
|||||||
|
|
||||||
int
|
int
|
||||||
gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
||||||
gfc_actual_arglist * arg, gfc_expr * expr,
|
gfc_actual_arglist * args, gfc_expr * expr,
|
||||||
VEC(tree,gc) *append_args)
|
VEC(tree,gc) *append_args)
|
||||||
{
|
{
|
||||||
gfc_interface_mapping mapping;
|
gfc_interface_mapping mapping;
|
||||||
@ -2789,6 +2789,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
|||||||
VEC(tree,gc) *stringargs;
|
VEC(tree,gc) *stringargs;
|
||||||
tree result = NULL;
|
tree result = NULL;
|
||||||
gfc_formal_arglist *formal;
|
gfc_formal_arglist *formal;
|
||||||
|
gfc_actual_arglist *arg;
|
||||||
int has_alternate_specifier = 0;
|
int has_alternate_specifier = 0;
|
||||||
bool need_interface_mapping;
|
bool need_interface_mapping;
|
||||||
bool callee_alloc;
|
bool callee_alloc;
|
||||||
@ -2809,7 +2810,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
|||||||
gfc_clear_ts (&ts);
|
gfc_clear_ts (&ts);
|
||||||
|
|
||||||
if (sym->from_intmod == INTMOD_ISO_C_BINDING
|
if (sym->from_intmod == INTMOD_ISO_C_BINDING
|
||||||
&& conv_isocbinding_procedure (se, sym, arg))
|
&& conv_isocbinding_procedure (se, sym, args))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
gfc_is_proc_ptr_comp (expr, &comp);
|
gfc_is_proc_ptr_comp (expr, &comp);
|
||||||
@ -2859,7 +2860,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Evaluate the arguments. */
|
/* Evaluate the arguments. */
|
||||||
for (; arg != NULL; arg = arg->next, formal = formal ? formal->next : NULL)
|
for (arg = args; arg != NULL;
|
||||||
|
arg = arg->next, formal = formal ? formal->next : NULL)
|
||||||
{
|
{
|
||||||
e = arg->expr;
|
e = arg->expr;
|
||||||
fsym = formal ? formal->sym : NULL;
|
fsym = formal ? formal->sym : NULL;
|
||||||
@ -3040,6 +3042,24 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
|||||||
else
|
else
|
||||||
f = f || !sym->attr.always_explicit;
|
f = f || !sym->attr.always_explicit;
|
||||||
|
|
||||||
|
/* If the argument is a function call that may not create
|
||||||
|
a temporary for the result, we have to check that we
|
||||||
|
can do it, i.e. that there is no alias between this
|
||||||
|
argument and another one. */
|
||||||
|
if (gfc_get_noncopying_intrinsic_argument (e) != NULL)
|
||||||
|
{
|
||||||
|
sym_intent intent;
|
||||||
|
|
||||||
|
if (fsym != NULL)
|
||||||
|
intent = fsym->attr.intent;
|
||||||
|
else
|
||||||
|
intent = INTENT_UNKNOWN;
|
||||||
|
|
||||||
|
if (gfc_check_fncall_dependency (e, intent, sym, args,
|
||||||
|
NOT_ELEMENTAL))
|
||||||
|
parmse.force_tmp = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (e->expr_type == EXPR_VARIABLE
|
if (e->expr_type == EXPR_VARIABLE
|
||||||
&& is_subref_array (e))
|
&& is_subref_array (e))
|
||||||
/* The actual argument is a component reference to an
|
/* The actual argument is a component reference to an
|
||||||
|
@ -81,6 +81,11 @@ typedef struct gfc_se
|
|||||||
/* If set, gfc_conv_procedure_call does not put byref calls into se->pre. */
|
/* If set, gfc_conv_procedure_call does not put byref calls into se->pre. */
|
||||||
unsigned no_function_call:1;
|
unsigned no_function_call:1;
|
||||||
|
|
||||||
|
/* If set, we will force the creation of a temporary. Useful to disable
|
||||||
|
non-copying procedure argument passing optimizations, when some function
|
||||||
|
args alias. */
|
||||||
|
unsigned force_tmp:1;
|
||||||
|
|
||||||
/* Scalarization parameters. */
|
/* Scalarization parameters. */
|
||||||
struct gfc_se *parent;
|
struct gfc_se *parent;
|
||||||
struct gfc_ss *ss;
|
struct gfc_ss *ss;
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
|
2010-09-21 Mikael Morin <mikael@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR fortran/45648
|
||||||
|
* gfortran.dg/inline_transpose_1.f90: Update temporary's locations
|
||||||
|
and counts. Add non-elemental function call check.
|
||||||
|
|
||||||
|
PR fortran/45648
|
||||||
|
* gfortran.dg/inline_transpose_1.f90: Add function calls with aliasing
|
||||||
|
arguments checks. Update temporary counts.
|
||||||
|
* gfortran.dg/transpose_optimization_1.f90: New.
|
||||||
|
|
||||||
2010-09-21 Nicola Pero <nicola.pero@meta-innovation.com>
|
2010-09-21 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||||
|
|
||||||
Merge from 'apple/trunk' branch on FSF servers.
|
Merge from 'apple/trunk' branch on FSF servers.
|
||||||
|
@ -61,10 +61,10 @@
|
|||||||
if (u /= v) call abort
|
if (u /= v) call abort
|
||||||
|
|
||||||
|
|
||||||
a = foo(transpose(c)) ! Unnecessary { dg-warning "Creating array temporary" }
|
a = foo(transpose(c))
|
||||||
if (any(a /= p+1)) call abort
|
if (any(a /= p+1)) call abort
|
||||||
|
|
||||||
write(u,*) foo(transpose(c)) ! 2 temps, should be 1 { dg-warning "Creating array temporary" }
|
write(u,*) foo(transpose(c)) ! { dg-warning "Creating array temporary" }
|
||||||
write(v,*) p+1
|
write(v,*) p+1
|
||||||
if (u /= v) call abort
|
if (u /= v) call abort
|
||||||
|
|
||||||
@ -77,10 +77,10 @@
|
|||||||
if (u /= v) call abort
|
if (u /= v) call abort
|
||||||
|
|
||||||
|
|
||||||
e = foo(transpose(e)) ! 2 temps, should be 1 { dg-warning "Creating array temporary" }
|
e = foo(transpose(e)) ! { dg-warning "Creating array temporary" }
|
||||||
if (any(e /= 2*s+1)) call abort
|
if (any(e /= 2*s+1)) call abort
|
||||||
|
|
||||||
write(u,*) transpose(foo(transpose(e))-1) ! 2 temps, should be 1 { dg-warning "Creating array temporary" }
|
write(u,*) transpose(foo(transpose(e))-1) ! { dg-warning "Creating array temporary" }
|
||||||
write(v,*) 2*s+1
|
write(v,*) 2*s+1
|
||||||
if (u /= v) call abort
|
if (u /= v) call abort
|
||||||
|
|
||||||
@ -141,28 +141,46 @@
|
|||||||
if (u /= v) call abort
|
if (u /= v) call abort
|
||||||
|
|
||||||
|
|
||||||
if (any(transpose(matmul(a,c)) /= matmul(transpose(c), transpose(a)))) call abort ! 4 temps, should be 2 { dg-warning "Creating array temporary" }
|
if (any(transpose(matmul(a,c)) /= matmul(transpose(c), transpose(a)))) call abort ! 2 temps { dg-warning "Creating array temporary" }
|
||||||
|
|
||||||
write(u,*) transpose(matmul(a,c)) ! { dg-warning "Creating array temporary" }
|
write(u,*) transpose(matmul(a,c)) ! { dg-warning "Creating array temporary" }
|
||||||
write(v,*) matmul(transpose(c), transpose(a)) ! 3 temps, should be 1 { dg-warning "Creating array temporary" }
|
write(v,*) matmul(transpose(c), transpose(a)) ! { dg-warning "Creating array temporary" }
|
||||||
if (u /= v) call abort
|
if (u /= v) call abort
|
||||||
|
|
||||||
|
|
||||||
if (any(transpose(matmul(e,a)) /= matmul(transpose(a), transpose(e)))) call abort ! 4 temps, should be 2 { dg-warning "Creating array temporary" }
|
if (any(transpose(matmul(e,a)) /= matmul(transpose(a), transpose(e)))) call abort ! 2 temps { dg-warning "Creating array temporary" }
|
||||||
|
|
||||||
write(u,*) transpose(matmul(e,a)) ! { dg-warning "Creating array temporary" }
|
write(u,*) transpose(matmul(e,a)) ! { dg-warning "Creating array temporary" }
|
||||||
write(v,*) matmul(transpose(a), transpose(e)) ! 3 temps, should be 1 { dg-warning "Creating array temporary" }
|
write(v,*) matmul(transpose(a), transpose(e)) ! { dg-warning "Creating array temporary" }
|
||||||
if (u /= v) call abort
|
if (u /= v) call abort
|
||||||
|
|
||||||
|
|
||||||
call baz (transpose(a)) ! Unnecessary { dg-warning "Creating array temporary" }
|
call baz (transpose(a))
|
||||||
|
|
||||||
call toto (f, transpose (e))
|
|
||||||
if (any (f /= 4 * s + 12)) call abort
|
|
||||||
|
|
||||||
call toto (f, transpose (f)) ! { dg-warning "Creating array temporary" }
|
call toto1 (a, transpose (c))
|
||||||
if (any (f /= 8 * r + 24)) call abort
|
if (any (a /= 2 * p + 12)) call abort
|
||||||
|
|
||||||
|
call toto1 (e, transpose (e)) ! { dg-warning "Creating array temporary" }
|
||||||
|
if (any (e /= 4 * s + 12)) call abort
|
||||||
|
|
||||||
|
|
||||||
|
call toto2 (c, transpose (a))
|
||||||
|
if (any (c /= 2 * q + 13)) call abort
|
||||||
|
|
||||||
|
call toto2 (e, transpose(e)) ! { dg-warning "Creating array temporary" }
|
||||||
|
if (any (e /= 4 * r + 13)) call abort
|
||||||
|
|
||||||
|
call toto2 (e, transpose(transpose(e))) ! { dg-warning "Creating array temporary" }
|
||||||
|
if (any (e /= 4 * r + 14)) call abort
|
||||||
|
|
||||||
|
|
||||||
|
call toto3 (e, transpose(e))
|
||||||
|
if (any (e /= 4 * r + 14)) call abort
|
||||||
|
|
||||||
|
|
||||||
|
call titi (nx, e, transpose(e)) ! { dg-warning "Creating array temporary" }
|
||||||
|
if (any (e /= 4 * s + 17)) call abort
|
||||||
|
|
||||||
contains
|
contains
|
||||||
|
|
||||||
@ -182,22 +200,38 @@
|
|||||||
integer, intent(in) :: x(:,:)
|
integer, intent(in) :: x(:,:)
|
||||||
end subroutine baz
|
end subroutine baz
|
||||||
|
|
||||||
elemental subroutine toto (x, y)
|
elemental subroutine toto1 (x, y)
|
||||||
integer, intent(out) :: x
|
integer, intent(out) :: x
|
||||||
integer, intent(in) :: y
|
integer, intent(in) :: y
|
||||||
x = y + y
|
x = y + y
|
||||||
end subroutine toto
|
end subroutine toto1
|
||||||
|
|
||||||
|
subroutine toto2 (x, y)
|
||||||
|
integer, dimension(:,:), intent(out) :: x
|
||||||
|
integer, dimension(:,:), intent(in) :: y
|
||||||
|
x = y + 1
|
||||||
|
end subroutine toto2
|
||||||
|
|
||||||
|
subroutine toto3 (x, y)
|
||||||
|
integer, dimension(:,:), intent(in) :: x, y
|
||||||
|
end subroutine toto3
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
subroutine titi (n, x, y)
|
||||||
|
integer :: n, x(n,n), y(n,n)
|
||||||
|
x = y + 3
|
||||||
|
end subroutine titi
|
||||||
|
|
||||||
! No call to transpose
|
! No call to transpose
|
||||||
! { dg-final { scan-tree-dump-times "_gfortran_transpose" 0 "original" } }
|
! { dg-final { scan-tree-dump-times "_gfortran_transpose" 0 "original" } }
|
||||||
!
|
!
|
||||||
! 34 temporaries
|
! 24 temporaries
|
||||||
! { dg-final { scan-tree-dump-times "struct\[^\\n\]*atmp" 34 "original" } }
|
! { dg-final { scan-tree-dump-times "struct\[^\\n\]*atmp" 24 "original" } }
|
||||||
!
|
!
|
||||||
! 2 tests optimized out
|
! 2 tests optimized out
|
||||||
! { dg-final { scan-tree-dump-times "_gfortran_abort" 34 "original" } }
|
! { dg-final { scan-tree-dump-times "_gfortran_abort" 39 "original" } }
|
||||||
! { # Commented out as failing at -O0: dg-final { scan-tree-dump-times "_gfortran_abort" 32 "optimized" } }
|
! { # Commented out as failing at -O0: dg-final { scan-tree-dump-times "_gfortran_abort" 37 "optimized" } }
|
||||||
!
|
!
|
||||||
! cleanup
|
! cleanup
|
||||||
! { dg-final { cleanup-tree-dump "original" } }
|
! { dg-final { cleanup-tree-dump "original" } }
|
||||||
|
106
gcc/testsuite/gfortran.dg/transpose_optimization_1.f90
Normal file
106
gcc/testsuite/gfortran.dg/transpose_optimization_1.f90
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
! { dg-do compile }
|
||||||
|
! { dg-options "-Warray-temporaries -fdump-tree-original" }
|
||||||
|
!
|
||||||
|
! PR fortran/45648
|
||||||
|
! Non-copying descriptor transpose optimization (for function call args).
|
||||||
|
!
|
||||||
|
! Contributed by Richard Sandiford <richard@codesourcery.com>
|
||||||
|
|
||||||
|
module foo
|
||||||
|
interface
|
||||||
|
subroutine ext1 (a, b)
|
||||||
|
real, intent (in), dimension (:, :) :: a, b
|
||||||
|
end subroutine ext1
|
||||||
|
subroutine ext2 (a, b)
|
||||||
|
real, intent (in), dimension (:, :) :: a
|
||||||
|
real, intent (out), dimension (:, :) :: b
|
||||||
|
end subroutine ext2
|
||||||
|
subroutine ext3 (a, b)
|
||||||
|
real, dimension (:, :) :: a, b
|
||||||
|
end subroutine ext3
|
||||||
|
end interface
|
||||||
|
contains
|
||||||
|
! No temporary needed here.
|
||||||
|
subroutine test1 (n, a, b, c)
|
||||||
|
integer :: n
|
||||||
|
real, dimension (n, n) :: a, b, c
|
||||||
|
a = matmul (transpose (b), c)
|
||||||
|
end subroutine test1
|
||||||
|
|
||||||
|
! No temporary either, as we know the arguments to matmul are intent(in)
|
||||||
|
subroutine test2 (n, a, b)
|
||||||
|
integer :: n
|
||||||
|
real, dimension (n, n) :: a, b
|
||||||
|
a = matmul (transpose (b), b)
|
||||||
|
end subroutine test2
|
||||||
|
|
||||||
|
! No temporary needed.
|
||||||
|
subroutine test3 (n, a, b, c)
|
||||||
|
integer :: n
|
||||||
|
real, dimension (n, n) :: a, c
|
||||||
|
real, dimension (n+4, n+4) :: b
|
||||||
|
a = matmul (transpose (b (2:n+1, 3:n+2)), c)
|
||||||
|
end subroutine test3
|
||||||
|
|
||||||
|
! A temporary is needed for the result of either the transpose or matmul.
|
||||||
|
subroutine test4 (n, a, b)
|
||||||
|
integer :: n
|
||||||
|
real, dimension (n, n) :: a, b
|
||||||
|
a = matmul (transpose (a), b) ! { dg-warning "Creating array temporary" }
|
||||||
|
end subroutine test4
|
||||||
|
|
||||||
|
! The temporary is needed here since the second argument to imp1
|
||||||
|
! has unknown intent.
|
||||||
|
subroutine test5 (n, a)
|
||||||
|
integer :: n
|
||||||
|
real, dimension (n, n) :: a
|
||||||
|
call imp1 (transpose (a), a) ! { dg-warning "Creating array temporary" }
|
||||||
|
end subroutine test5
|
||||||
|
|
||||||
|
! No temporaries are needed here; imp1 can't modify either argument.
|
||||||
|
! We have to pack the arguments, however.
|
||||||
|
subroutine test6 (n, a, b)
|
||||||
|
integer :: n
|
||||||
|
real, dimension (n, n) :: a, b
|
||||||
|
call imp1 (transpose (a), transpose (b)) ! { dg-warning "Creating array temporary" }
|
||||||
|
end subroutine test6
|
||||||
|
|
||||||
|
! No temporaries are needed here; imp1 can't modify either argument.
|
||||||
|
! We don't have to pack the arguments.
|
||||||
|
subroutine test6_bis (n, a, b)
|
||||||
|
integer :: n
|
||||||
|
real, dimension (n, n) :: a, b
|
||||||
|
call ext3 (transpose (a), transpose (b))
|
||||||
|
end subroutine test6_bis
|
||||||
|
|
||||||
|
! No temporary is neede here; the second argument is intent(in).
|
||||||
|
subroutine test7 (n, a)
|
||||||
|
integer :: n
|
||||||
|
real, dimension (n, n) :: a
|
||||||
|
call ext1 (transpose (a), a)
|
||||||
|
end subroutine test7
|
||||||
|
|
||||||
|
! The temporary is needed here though.
|
||||||
|
subroutine test8 (n, a)
|
||||||
|
integer :: n
|
||||||
|
real, dimension (n, n) :: a
|
||||||
|
call ext2 (transpose (a), a) ! { dg-warning "Creating array temporary" }
|
||||||
|
end subroutine test8
|
||||||
|
|
||||||
|
! Silly, but we don't need any temporaries here.
|
||||||
|
subroutine test9 (n, a)
|
||||||
|
integer :: n
|
||||||
|
real, dimension (n, n) :: a
|
||||||
|
call ext1 (transpose (transpose (a)), a)
|
||||||
|
end subroutine test9
|
||||||
|
|
||||||
|
! The outer transpose needs a temporary; the inner one doesn't.
|
||||||
|
subroutine test10 (n, a)
|
||||||
|
integer :: n
|
||||||
|
real, dimension (n, n) :: a
|
||||||
|
call ext2 (transpose (transpose (a)), a) ! { dg-warning "Creating array temporary" }
|
||||||
|
end subroutine test10
|
||||||
|
end module foo
|
||||||
|
|
||||||
|
! { dg-final { scan-tree-dump-times "struct\[^\\n\]*atmp" 4 "original" } }
|
||||||
|
! { dg-final { cleanup-tree-dump "original" } }
|
Loading…
Reference in New Issue
Block a user