This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [Patch, fortran] PR64952 - Missing temporary in assignment from elemental function
- From: Mikael Morin <mikael dot morin at sfr dot fr>
- To: Paul Richard Thomas <paul dot richard dot thomas at gmail dot com>, "fortran at gcc dot gnu dot org" <fortran at gcc dot gnu dot org>, gcc-patches <gcc-patches at gcc dot gnu dot org>, Tobias Burnus <burnus at net-b dot de>, Dominique Dhumieres <dominiq at lps dot ens dot fr>
- Date: Sun, 08 Feb 2015 18:27:12 +0100
- Subject: Re: [Patch, fortran] PR64952 - Missing temporary in assignment from elemental function
- Authentication-results: sourceware.org; auth=none
- Authentication-results: sfrmc.priv.atos.fr; dkim=none (no signature); dkim-adsp=none (no policy) header dot from=mikael dot morin at sfr dot fr
- References: <CAGkQGiLg9VKL2BOGmW0GKC3viE9hDoEJG1FLzFbce-QT12cO4w at mail dot gmail dot com> <CAGkQGiL2g=jxdr5vGtshfqHjpCf+SeQL0OyMYjpeXsmf1UeuEQ at mail dot gmail dot com>
Hello Paul,
comments below
Le 08/02/2015 16:24, Paul Richard Thomas a écrit :
>
> Index: gcc/fortran/gfortran.h
> ===================================================================
> *** gcc/fortran/gfortran.h (revision 220482)
> --- gcc/fortran/gfortran.h (working copy)
> *************** typedef struct
> *** 789,794 ****
> --- 789,798 ----
> cannot alias. Note that this is zero for PURE procedures. */
> unsigned implicit_pure:1;
>
> + /* This set for an elemental function that contains expressions for
> + arrays coming from outside its namespace. */
> + unsigned potentially_aliased:1;
> +
aliased is more something about pointers, so how about naming it
something like array_outer_dependency? Anyway, that's minor.
I wonder whether we should negate the meaning, that is set the flag if
there is no external dependency.
If we can get the conditions to set it exhaustively right, both are
equivalent. Otherwise... maybe not.
> /* This is set if the subroutine doesn't return. Currently, this
> is only possible for intrinsic subroutines. */
> unsigned noreturn:1;
> Index: gcc/fortran/trans.h
> ===================================================================
> *** gcc/fortran/trans.h (revision 220481)
> --- gcc/fortran/trans.h (working copy)
> *************** typedef struct gfc_ss_info
> *** 226,231 ****
> --- 226,235 ----
> /* Suppresses precalculation of scalars in WHERE assignments. */
> unsigned where:1;
>
> + /* Signals that an array argument of an elemental function might be aliased,
> + thereby generating a temporary in assignments. */
> + unsigned potentially_aliased:1;
> +
> /* Tells whether the SS is for an actual argument which can be a NULL
> reference. In other words, the associated dummy argument is OPTIONAL.
> Used to handle elemental procedures. */
> Index: gcc/fortran/resolve.c
> ===================================================================
> *** gcc/fortran/resolve.c (revision 220481)
> --- gcc/fortran/resolve.c (working copy)
> *************** resolve_variable (gfc_expr *e)
> *** 5054,5059 ****
> --- 5054,5067 ----
> && gfc_current_ns->parent->parent == sym->ns)))
> sym->attr.host_assoc = 1;
>
> + if (sym->attr.dimension
> + && (sym->ns != gfc_current_ns
> + || sym->attr.use_assoc
> + || sym->attr.in_common)
> + && gfc_elemental (NULL)
> + && gfc_current_ns->proc_name->attr.function)
> + gfc_current_ns->proc_name->attr.potentially_aliased = 1;
I would expect the flag to also be copied between procedures in some
cases; namely if A calls B, and B has the flag, then A has the flag.
There is also the case of external procedures (for which the flag is not
known -> assume the worst)
> +
> resolve_procedure:
> if (t && !resolve_procedure_expression (e))
> t = false;
> Index: gcc/fortran/trans-array.c
> ===================================================================
> *** gcc/fortran/trans-array.c (revision 220482)
> --- gcc/fortran/trans-array.c (working copy)
> *************** gfc_conv_resolve_dependencies (gfc_loopi
> *** 4391,4396 ****
> --- 4391,4402 ----
> {
> ss_expr = ss->info->expr;
>
> + if (ss->info->potentially_aliased)
> + {
> + nDepend = 1;
> + break;
> + }
> +
> if (ss->info->type != GFC_SS_SECTION)
> {
> if (flag_realloc_lhs
> *************** gfc_walk_function_expr (gfc_ss * ss, gfc
> *** 9096,9104 ****
> /* Walk the parameters of an elemental function. For now we always pass
> by reference. */
> if (sym->attr.elemental || (comp && comp->attr.elemental))
> ! return gfc_walk_elemental_function_args (ss, expr->value.function.actual,
> gfc_get_proc_ifc_for_expr (expr),
> GFC_SS_REFERENCE);
>
> /* Scalar functions are OK as these are evaluated outside the scalarization
> loop. Pass back and let the caller deal with it. */
> --- 9102,9114 ----
> /* Walk the parameters of an elemental function. For now we always pass
> by reference. */
> if (sym->attr.elemental || (comp && comp->attr.elemental))
> ! {
> ! ss = gfc_walk_elemental_function_args (ss, expr->value.function.actual,
> gfc_get_proc_ifc_for_expr (expr),
> GFC_SS_REFERENCE);
> + if (sym->attr.potentially_aliased)
> + ss->info->potentially_aliased = 1;
> + }
This is somewhat hackish, potentially_aliased is a global thing, not
specific to SS, and this may end up marking gfc_ss_terminator as
potentiallly_aliased for example, but I don't see any other obvious way
to do it, so it's OK I guess.
Anyway, the comp && comp->attr.elemental part of the if should be
handled too (always set the flag in that case?). I actually wonder why
it works without.
I attach a few variants of the testcase, which don't work yet.
Mikael
MODULE M
INTEGER, PRIVATE :: i
REAL :: array(5) = (/ (i+0.0, i = 1,5) /)
CONTAINS
ELEMENTAL FUNCTION Fred (n, x)
REAL :: Fred
INTEGER, INTENT(IN) :: n
REAL, INTENT(IN) :: x
! In general, this would be in an external procedure
Fred = x+SUM(array(:n-1))+SUM(array(n+1:))
END FUNCTION Fred
END MODULE M
PROGRAM Main
USE M
INTEGER :: i, index(5) = (/ (i, i = 1,5) /)
array = Fred(index,array)
PRINT *, array
END PROGRAM Main
MODULE M
INTEGER, PRIVATE :: i
TYPE, ABSTRACT :: t
REAL :: f
! PROCEDURE(Fred), POINTER :: p => NULL()
CONTAINS
PROCEDURE(Fred_ifc), DEFERRED, PASS :: tbp
END TYPE t
TYPE, EXTENDS(t) :: t2
CONTAINS
PROCEDURE :: tbp => Fred
END TYPE t2
TYPE(t2) :: array(5) = (/ (t2(i+0.0), i = 1,5) /)
INTERFACE
ELEMENTAL FUNCTION Fred_ifc (x, n)
IMPORT
REAL :: Fred
CLASS(T), INTENT(IN) :: x
INTEGER, INTENT(IN) :: n
END FUNCTION Fred_ifc
END INTERFACE
CONTAINS
ELEMENTAL FUNCTION Fred (x, n)
REAL :: Fred
CLASS(T2), INTENT(IN) :: x
INTEGER, INTENT(IN) :: n
! In general, this would be in an external procedure
Fred = x%f+SUM(array(:n-1)%f)+SUM(array(n+1:)%f)
END FUNCTION Fred
END MODULE M
PROGRAM Main
USE M
INTEGER :: i, index(5) = (/ (i, i = 1,5) /)
array%f = array%tbp(index)
PRINT *, array%f
END PROGRAM Main
PROGRAM Main
INTEGER :: i, index(5) = (/ (i, i = 1,5) /)
REAL :: array(5) = (/ (i+0.0, i = 1,5) /)
array = Fred(index)
PRINT *, array
CONTAINS
ELEMENTAL FUNCTION Fred (n)
REAL :: Fred
INTEGER, INTENT(IN) :: n
! In general, this would be in an external procedure
Fred = Fred2(n)
END FUNCTION Fred
ELEMENTAL FUNCTION Fred2 (n)
REAL :: Fred2
INTEGER, INTENT(IN) :: n
! In general, this would be in an external procedure
Fred2 = n + SUM(array(:n-1))+SUM(array(n+1:))
END FUNCTION Fred2
END PROGRAM Main