diff options
author | Mikael Morin <mikael@gcc.gnu.org> | 2010-09-21 19:04:09 +0000 |
---|---|---|
committer | Mikael Morin <mikael@gcc.gnu.org> | 2010-09-21 19:04:09 +0000 |
commit | 0b4f2770ff14ee139b9f5d0aa16c1507eb60cb55 (patch) | |
tree | aa4f4a282ac80b91b29b28096d4af2a6ad0d5e3f | |
parent | 5e68c77aff8d9c984668f8932e54b28d02456bba (diff) | |
download | gcc-0b4f2770ff14ee139b9f5d0aa16c1507eb60cb55.zip gcc-0b4f2770ff14ee139b9f5d0aa16c1507eb60cb55.tar.gz gcc-0b4f2770ff14ee139b9f5d0aa16c1507eb60cb55.tar.bz2 |
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
-rw-r--r-- | gcc/fortran/ChangeLog | 24 | ||||
-rw-r--r-- | gcc/fortran/trans-array.c | 93 | ||||
-rw-r--r-- | gcc/fortran/trans-expr.c | 26 | ||||
-rw-r--r-- | gcc/fortran/trans.h | 5 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/testsuite/gfortran.dg/inline_transpose_1.f90 | 72 | ||||
-rw-r--r-- | gcc/testsuite/gfortran.dg/transpose_optimization_1.f90 | 106 |
7 files changed, 284 insertions, 53 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index d9777bf..33eb639 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -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> PR fortran/45438 diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 7bce2ef..310a42b 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -5136,7 +5136,6 @@ get_array_charlen (gfc_expr *expr, gfc_se *se) } - /* Convert an array for passing as an actual argument. Expressions and vector subscripts are evaluated and stored in a temporary, which is then 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 se->expr is the descriptor for the previously-evaluated 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 gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss) { gfc_loopinfo loop; - gfc_ss *secss; gfc_ss_info *info; int need_tmp; int n; @@ -5175,7 +5179,9 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss) tree offset; int full; bool subref_array_target = false; + gfc_expr *arg; + gcc_assert (ss != NULL); gcc_assert (ss != gfc_ss_terminator); /* 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. Otherwise we need to copy it into a temporary. */ - /* Find the SS for the array section. */ - secss = ss; - while (secss != gfc_ss_terminator && secss->type != GFC_SS_SECTION) - secss = secss->next; - - gcc_assert (secss != gfc_ss_terminator); - info = &secss->data.info; + gcc_assert (ss->type == GFC_SS_SECTION); + gcc_assert (ss->expr == expr); + info = &ss->data.info; /* 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; subref_array_target = se->direct_byref && is_subref_array (expr); need_tmp = gfc_ref_needs_temporary_p (expr->ref) && !subref_array_target; + if (se->force_tmp) + need_tmp = 1; + if (need_tmp) full = 0; else if (GFC_ARRAY_TYPE_P (TREE_TYPE (desc))) @@ -5216,6 +5221,14 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss) 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 (se->direct_byref && !se->byref_noassign) { @@ -5245,30 +5258,45 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss) break; 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 array descriptor. We still need to go through the scalarizer to create the descriptor. Elemental functions ar handled as 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) { - gcc_assert (secss != gfc_ss_terminator); + gcc_assert (ss->type == GFC_SS_FUNCTION && ss->expr == expr); /* 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); gfc_conv_expr (se, expr); return; } - if (secss == gfc_ss_terminator) + if (ss->expr != expr) { /* 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; if (expr->ts.type == BT_CHARACTER && 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 { /* Transformational function. */ - info = &secss->data.info; + info = &ss->data.info; need_tmp = 0; } break; @@ -5292,12 +5320,10 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss) { need_tmp = 0; info = &ss->data.info; - secss = ss; } else { need_tmp = 1; - secss = NULL; info = NULL; } break; @@ -5305,11 +5331,15 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss) default: /* Something complicated. Copy it into a temporary. */ need_tmp = 1; - secss = NULL; info = NULL; 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); /* 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); desc = info->descriptor; - gcc_assert (secss && secss != gfc_ss_terminator); if (se->direct_byref && !se->byref_noassign) { /* 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; - dim = 0; /* The following can be somewhat confusing. We have two descriptors, a new one and the original array. {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. The bounds of the scalarization are the bounds of the section. 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 { - /* Check we haven't somehow got out of sync. */ - gcc_assert (info->dim[dim] == n); - /* Evaluate and remember the start of the section. */ start = info->start[n]; 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. */ if (info->ref) 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. */ 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. */ gfc_conv_descriptor_stride_set (&loop.pre, parm, gfc_rank_cst[dim], stride); - - dim++; } if (se->data_not_needed) diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 9b24cad..a6837c9 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -2770,7 +2770,7 @@ conv_isocbinding_procedure (gfc_se * se, gfc_symbol * sym, int 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) { gfc_interface_mapping mapping; @@ -2789,6 +2789,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, VEC(tree,gc) *stringargs; tree result = NULL; gfc_formal_arglist *formal; + gfc_actual_arglist *arg; int has_alternate_specifier = 0; bool need_interface_mapping; bool callee_alloc; @@ -2809,7 +2810,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, gfc_clear_ts (&ts); if (sym->from_intmod == INTMOD_ISO_C_BINDING - && conv_isocbinding_procedure (se, sym, arg)) + && conv_isocbinding_procedure (se, sym, args)) return 0; gfc_is_proc_ptr_comp (expr, &comp); @@ -2859,7 +2860,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, } /* 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; fsym = formal ? formal->sym : NULL; @@ -3040,6 +3042,24 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, else 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 && is_subref_array (e)) /* The actual argument is a component reference to an diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index acdd3e3..a883cf5 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -81,6 +81,11 @@ typedef struct gfc_se /* If set, gfc_conv_procedure_call does not put byref calls into se->pre. */ 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. */ struct gfc_se *parent; struct gfc_ss *ss; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b9ca99d..a1d8eb0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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> Merge from 'apple/trunk' branch on FSF servers. diff --git a/gcc/testsuite/gfortran.dg/inline_transpose_1.f90 b/gcc/testsuite/gfortran.dg/inline_transpose_1.f90 index 4995c49..a364842 100644 --- a/gcc/testsuite/gfortran.dg/inline_transpose_1.f90 +++ b/gcc/testsuite/gfortran.dg/inline_transpose_1.f90 @@ -61,10 +61,10 @@ 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 - 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 if (u /= v) call abort @@ -77,10 +77,10 @@ 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 - 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 if (u /= v) call abort @@ -141,28 +141,46 @@ 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(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 (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(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 - 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" } - if (any (f /= 8 * r + 24)) call abort + call toto1 (a, transpose (c)) + 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 @@ -182,22 +200,38 @@ integer, intent(in) :: x(:,:) end subroutine baz - elemental subroutine toto (x, y) + elemental subroutine toto1 (x, y) integer, intent(out) :: x integer, intent(in) :: 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 + +subroutine titi (n, x, y) + integer :: n, x(n,n), y(n,n) + x = y + 3 +end subroutine titi + ! No call to transpose ! { dg-final { scan-tree-dump-times "_gfortran_transpose" 0 "original" } } ! -! 34 temporaries -! { dg-final { scan-tree-dump-times "struct\[^\\n\]*atmp" 34 "original" } } +! 24 temporaries +! { dg-final { scan-tree-dump-times "struct\[^\\n\]*atmp" 24 "original" } } ! ! 2 tests optimized out -! { dg-final { scan-tree-dump-times "_gfortran_abort" 34 "original" } } -! { # Commented out as failing at -O0: dg-final { scan-tree-dump-times "_gfortran_abort" 32 "optimized" } } +! { dg-final { scan-tree-dump-times "_gfortran_abort" 39 "original" } } +! { # Commented out as failing at -O0: dg-final { scan-tree-dump-times "_gfortran_abort" 37 "optimized" } } ! ! cleanup ! { dg-final { cleanup-tree-dump "original" } } diff --git a/gcc/testsuite/gfortran.dg/transpose_optimization_1.f90 b/gcc/testsuite/gfortran.dg/transpose_optimization_1.f90 new file mode 100644 index 0000000..885ff7c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/transpose_optimization_1.f90 @@ -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" } } |