aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran
diff options
context:
space:
mode:
authorTobias Burnus <burnus@net-b.de>2014-10-24 22:52:41 +0200
committerTobias Burnus <burnus@gcc.gnu.org>2014-10-24 22:52:41 +0200
commit229c59193afa304d5f3f214a691e355b3cd89d6d (patch)
tree18bad83bfccb41a662f817065b9b6a8b1752b346 /gcc/fortran
parent763206befb00fdcecfd8e54ccffd72d618077e92 (diff)
downloadgcc-229c59193afa304d5f3f214a691e355b3cd89d6d.zip
gcc-229c59193afa304d5f3f214a691e355b3cd89d6d.tar.gz
gcc-229c59193afa304d5f3f214a691e355b3cd89d6d.tar.bz2
check.c (check_co_collective): Reject coindexed A args.
2014-10-24 Tobias Burnus <burnus@net-b.de> gcc/fortran * check.c (check_co_collective): Reject coindexed A args. (gfc_check_co_reduce): Add OPERATOR checks. * gfortran.texi (_gfortran_caf_co_broadcast, * _gfortran_caf_co_max, _gfortran_caf_co_min, _gfortran_caf_co_sum, _gfortran_caf_co_reduce): Add ABI documentation. * intrinsic.texi (CO_REDUCE): Document intrinsic. (DPROD): Returns double not single precision. * trans-decl.c (gfor_fndecl_co_reduce): New global var. (gfc_build_builtin_function_decls): Init it. * trans.h (gfor_fndecl_co_reduce): Declare it. * trans-intrinsic.c (conv_co_collective, gfc_conv_intrinsic_subroutine): Handle CO_REDUCE. gcc/testsuite/ * gfortran.dg/coarray_collectives_9.f90: Remove dg-error. * gfortran.dg/coarray_collectives_13.f90: New. * gfortran.dg/coarray_collectives_14.f90: New. * gfortran.dg/coarray_collectives_15.f90: New. * gfortran.dg/coarray_collectives_16.f90: New. From-SVN: r216678
Diffstat (limited to 'gcc/fortran')
-rw-r--r--gcc/fortran/ChangeLog15
-rw-r--r--gcc/fortran/check.c173
-rw-r--r--gcc/fortran/gfortran.texi190
-rw-r--r--gcc/fortran/intrinsic.texi107
-rw-r--r--gcc/fortran/libgfortran.h8
-rw-r--r--gcc/fortran/trans-decl.c9
-rw-r--r--gcc/fortran/trans-intrinsic.c72
-rw-r--r--gcc/fortran/trans.h1
8 files changed, 532 insertions, 43 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 6f05ef9..6c84d61 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,18 @@
+2014-10-24 Tobias Burnus <burnus@net-b.de>
+
+ * check.c (check_co_collective): Reject coindexed A args.
+ (gfc_check_co_reduce): Add OPERATOR checks.
+ * gfortran.texi (_gfortran_caf_co_broadcast, _gfortran_caf_co_max,
+ _gfortran_caf_co_min, _gfortran_caf_co_sum,
+ _gfortran_caf_co_reduce): Add ABI documentation.
+ * intrinsic.texi (CO_REDUCE): Document intrinsic.
+ (DPROD): Returns double not single precision.
+ * trans-decl.c (gfor_fndecl_co_reduce): New global var.
+ (gfc_build_builtin_function_decls): Init it.
+ * trans.h (gfor_fndecl_co_reduce): Declare it.
+ * trans-intrinsic.c (conv_co_collective,
+ gfc_conv_intrinsic_subroutine): Handle CO_REDUCE.
+
2014-10-19 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
PR fortran/48979
diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c
index 0a08c73..6f1fe3f 100644
--- a/gcc/fortran/check.c
+++ b/gcc/fortran/check.c
@@ -1433,6 +1433,13 @@ check_co_collective (gfc_expr *a, gfc_expr *image_idx, gfc_expr *stat,
return false;
}
+ if (gfc_is_coindexed (a))
+ {
+ gfc_error ("The A argument at %L to the intrinsic %s shall not be "
+ "coindexed", &a->where, gfc_current_intrinsic);
+ return false;
+ }
+
if (image_idx != NULL)
{
if (!type_check (image_idx, co_reduce ? 2 : 1, BT_INTEGER))
@@ -1490,10 +1497,10 @@ gfc_check_co_broadcast (gfc_expr *a, gfc_expr *source_image, gfc_expr *stat,
{
if (a->ts.type == BT_CLASS || gfc_expr_attr (a).alloc_comp)
{
- gfc_error ("Support for the A argument at %L which is polymorphic A "
- "argument or has allocatable components is not yet "
- "implemented", &a->where);
- return false;
+ gfc_error ("Support for the A argument at %L which is polymorphic A "
+ "argument or has allocatable components is not yet "
+ "implemented", &a->where);
+ return false;
}
return check_co_collective (a, source_image, stat, errmsg, false);
}
@@ -1504,38 +1511,164 @@ gfc_check_co_reduce (gfc_expr *a, gfc_expr *op, gfc_expr *result_image,
gfc_expr *stat, gfc_expr *errmsg)
{
symbol_attribute attr;
+ gfc_formal_arglist *formal;
+ gfc_symbol *sym;
if (a->ts.type == BT_CLASS)
{
- gfc_error ("The A argument at %L of CO_REDUCE shall not be polymorphic",
- &a->where);
- return false;
+ gfc_error ("The A argument at %L of CO_REDUCE shall not be polymorphic",
+ &a->where);
+ return false;
}
if (gfc_expr_attr (a).alloc_comp)
{
- gfc_error ("Support for the A argument at %L with allocatable components"
- " is not yet implemented", &a->where);
- return false;
+ gfc_error ("Support for the A argument at %L with allocatable components"
+ " is not yet implemented", &a->where);
+ return false;
}
+ if (!check_co_collective (a, result_image, stat, errmsg, true))
+ return false;
+
+ if (!gfc_resolve_expr (op))
+ return false;
+
attr = gfc_expr_attr (op);
if (!attr.pure || !attr.function)
{
- gfc_error ("OPERATOR argument at %L must be a PURE function",
- &op->where);
- return false;
+ gfc_error ("OPERATOR argument at %L must be a PURE function",
+ &op->where);
+ return false;
}
- if (!check_co_collective (a, result_image, stat, errmsg, true))
- return false;
+ if (attr.intrinsic)
+ {
+ /* None of the intrinsics fulfills the criteria of taking two arguments,
+ returning the same type and kind as the arguments and being permitted
+ as actual argument. */
+ gfc_error ("Intrinsic function %s at %L is not permitted for CO_REDUCE",
+ op->symtree->n.sym->name, &op->where);
+ return false;
+ }
- /* FIXME: After J3/WG5 has decided what they actually exactly want, more
- checks such as same-argument checks have to be added, implemented and
- intrinsic.texi upated. */
+ if (gfc_is_proc_ptr_comp (op))
+ {
+ gfc_component *comp = gfc_get_proc_ptr_comp (op);
+ sym = comp->ts.interface;
+ }
+ else
+ sym = op->symtree->n.sym;
- gfc_error("CO_REDUCE at %L is not yet implemented", &a->where);
- return false;
+ formal = sym->formal;
+
+ if (!formal || !formal->next || formal->next->next)
+ {
+ gfc_error ("The function passed as OPERATOR at %L shall have two "
+ "arguments", &op->where);
+ return false;
+ }
+
+ if (sym->result->ts.type == BT_UNKNOWN)
+ gfc_set_default_type (sym->result, 0, NULL);
+
+ if (!gfc_compare_types (&a->ts, &sym->result->ts))
+ {
+ gfc_error ("A argument at %L has type %s but the function passed as "
+ "OPERATOR at %L returns %s",
+ &a->where, gfc_typename (&a->ts), &op->where,
+ gfc_typename (&sym->result->ts));
+ return false;
+ }
+ if (!gfc_compare_types (&a->ts, &formal->sym->ts)
+ || !gfc_compare_types (&a->ts, &formal->next->sym->ts))
+ {
+ gfc_error ("The function passed as OPERATOR at %L has arguments of type "
+ "%s and %s but shall have type %s", &op->where,
+ gfc_typename (&formal->sym->ts),
+ gfc_typename (&formal->next->sym->ts), gfc_typename (&a->ts));
+ return false;
+ }
+ if (op->rank || attr.allocatable || attr.pointer || formal->sym->as
+ || formal->next->sym->as || formal->sym->attr.allocatable
+ || formal->next->sym->attr.allocatable || formal->sym->attr.pointer
+ || formal->next->sym->attr.pointer)
+ {
+ gfc_error ("The function passed as OPERATOR at %L shall have scalar "
+ "nonallocatable nonpointer arguments and return a "
+ "nonallocatable nonpointer scalar", &op->where);
+ return false;
+ }
+
+ if (formal->sym->attr.value != formal->next->sym->attr.value)
+ {
+ gfc_error ("The function passed as OPERATOR at %L shall have the VALUE "
+ "attribute either for none or both arguments", &op->where);
+ return false;
+ }
+
+ if (formal->sym->attr.target != formal->next->sym->attr.target)
+ {
+ gfc_error ("The function passed as OPERATOR at %L shall have the TARGET "
+ "attribute either for none or both arguments", &op->where);
+ return false;
+ }
+
+ if (formal->sym->attr.asynchronous != formal->next->sym->attr.asynchronous)
+ {
+ gfc_error ("The function passed as OPERATOR at %L shall have the "
+ "ASYNCHRONOUS attribute either for none or both arguments",
+ &op->where);
+ return false;
+ }
+
+ if (formal->sym->attr.optional || formal->next->sym->attr.optional)
+ {
+ gfc_error ("The function passed as OPERATOR at %L shall not have the "
+ "OPTIONAL attribute for either of the arguments", &op->where);
+ return false;
+ }
+
+ if (a->ts.type == BT_CHARACTER)
+ {
+ gfc_charlen *cl;
+ unsigned long actual_size, formal_size1, formal_size2, result_size;
+
+ cl = a->ts.u.cl;
+ actual_size = cl && cl->length && cl->length->expr_type == EXPR_CONSTANT
+ ? mpz_get_ui (cl->length->value.integer) : 0;
+
+ cl = formal->sym->ts.u.cl;
+ formal_size1 = cl && cl->length && cl->length->expr_type == EXPR_CONSTANT
+ ? mpz_get_ui (cl->length->value.integer) : 0;
+
+ cl = formal->next->sym->ts.u.cl;
+ formal_size2 = cl && cl->length && cl->length->expr_type == EXPR_CONSTANT
+ ? mpz_get_ui (cl->length->value.integer) : 0;
+
+ cl = sym->ts.u.cl;
+ result_size = cl && cl->length && cl->length->expr_type == EXPR_CONSTANT
+ ? mpz_get_ui (cl->length->value.integer) : 0;
+
+ if (actual_size
+ && ((formal_size1 && actual_size != formal_size1)
+ || (formal_size2 && actual_size != formal_size2)))
+ {
+ gfc_error ("The character length of the A argument at %L and of the "
+ "arguments of the OPERATOR at %L shall be the same",
+ &a->where, &op->where);
+ return false;
+ }
+ if (actual_size && result_size && actual_size != result_size)
+ {
+ gfc_error ("The character length of the A argument at %L and of the "
+ "function result of the OPERATOR at %L shall be the same",
+ &a->where, &op->where);
+ return false;
+ }
+ }
+
+ return true;
}
diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi
index d02452c..41d6559 100644
--- a/gcc/fortran/gfortran.texi
+++ b/gcc/fortran/gfortran.texi
@@ -3238,6 +3238,11 @@ caf_register_t;
* _gfortran_caf_sendget:: Sending data between remote images
* _gfortran_caf_lock:: Locking a lock variable
* _gfortran_caf_unlock:: Unlocking a lock variable
+* _gfortran_caf_co_broadcast:: Sending data to all images
+* _gfortran_caf_co_max:: Collective maximum reduction
+* _gfortran_caf_co_min:: Collective minimum reduction
+* _gfortran_caf_co_sum:: Collective summing reduction
+* _gfortran_caf_co_reduce:: Generic collective reduction
@end menu
@@ -3680,6 +3685,191 @@ images for critical-block locking variables.
+@node _gfortran_caf_co_broadcast
+@subsection @code{_gfortran_caf_co_broadcast} --- Sending data to all images
+@cindex Coarray, _gfortran_caf_co_broadcast
+
+@table @asis
+@item @emph{Description}:
+Distribute a value from a given image to all other images in the team. Has to
+be called collectively.
+
+@item @emph{Syntax}:
+@code{void _gfortran_caf_co_broadcast (gfc_descriptor_t *a,
+int source_image, int *stat, char *errmsg, int errmsg_len)}
+
+@item @emph{Arguments}:
+@multitable @columnfractions .15 .70
+@item @var{a} @tab intent(inout) And array descriptor with the data to be
+breoadcasted (on @var{source_image}) or to be received (other images).
+@item @var{source_image} @tab The ID of the image from which the data should
+be taken.
+@item @var{stat} @tab intent(out) Stores the status STAT= and my may be NULL.
+@item @var{errmsg} @tab intent(out) When an error occurs, this will be set to
+an error message; may be NULL
+@item @var{errmsg_len} @tab the buffer size of errmsg.
+@end multitable
+@end table
+
+
+
+@node _gfortran_caf_co_max
+@subsection @code{_gfortran_caf_co_max} --- Collective maximum reduction
+@cindex Coarray, _gfortran_caf_co_max
+
+@table @asis
+@item @emph{Description}:
+Calculates the for the each array element of the variable @var{a} the maximum
+value for that element in the current team; if @var{result_image} has the
+value 0, the result shall be stored on all images, otherwise, only on the
+specified image. This function operates on numeric values and character
+strings.
+
+@item @emph{Syntax}:
+@code{void _gfortran_caf_co_max (gfc_descriptor_t *a, int result_image,
+int *stat, char *errmsg, int a_len, int errmsg_len)}
+
+@item @emph{Arguments}:
+@multitable @columnfractions .15 .70
+@item @var{a} @tab intent(inout) And array descriptor with the data to be
+breoadcasted (on @var{source_image}) or to be received (other images).
+@item @var{result_image} @tab The ID of the image to which the reduced
+value should be copied to; if zero, it has to be copied to all images.
+@item @var{stat} @tab intent(out) Stores the status STAT= and my may be NULL.
+@item @var{errmsg} @tab intent(out) When an error occurs, this will be set to
+an error message; may be NULL
+@item @var{a_len} @tab The string length of argument @var{a}.
+@item @var{errmsg_len} @tab the buffer size of errmsg.
+@end multitable
+
+@item @emph{NOTES}
+If @var{result_image} is nonzero, the value on all images except of the
+specified one become undefined; hence, the library may make use of this.
+@end table
+
+
+
+@node _gfortran_caf_co_min
+@subsection @code{_gfortran_caf_co_min} --- Collective minimum reduction
+@cindex Coarray, _gfortran_caf_co_min
+
+@table @asis
+@item @emph{Description}:
+Calculates the for the each array element of the variable @var{a} the minimum
+value for that element in the current team; if @var{result_image} has the
+value 0, the result shall be stored on all images, otherwise, only on the
+specified image. This function operates on numeric values and character
+strings.
+
+@item @emph{Syntax}:
+@code{void _gfortran_caf_co_min (gfc_descriptor_t *a, int result_image,
+int *stat, char *errmsg, int a_len, int errmsg_len)}
+
+@item @emph{Arguments}:
+@multitable @columnfractions .15 .70
+@item @var{a} @tab intent(inout) And array descriptor with the data to be
+breoadcasted (on @var{source_image}) or to be received (other images).
+@item @var{result_image} @tab The ID of the image to which the reduced
+value should be copied to; if zero, it has to be copied to all images.
+@item @var{stat} @tab intent(out) Stores the status STAT= and my may be NULL.
+@item @var{errmsg} @tab intent(out) When an error occurs, this will be set to
+an error message; may be NULL
+@item @var{a_len} @tab The string length of argument @var{a}.
+@item @var{errmsg_len} @tab the buffer size of errmsg.
+@end multitable
+
+@item @emph{NOTES}
+If @var{result_image} is nonzero, the value on all images except of the
+specified one become undefined; hence, the library may make use of this.
+@end table
+
+
+
+@node _gfortran_caf_co_sum
+@subsection @code{_gfortran_caf_co_sum} --- Collective summing reduction
+@cindex Coarray, _gfortran_caf_co_sum
+
+@table @asis
+@item @emph{Description}:
+Calculates the for the each array element of the variable @var{a} the sum
+value for that element in the current team; if @var{result_image} has the
+value 0, the result shall be stored on all images, otherwise, only on the
+specified image. This function operates on numeric values.
+
+@item @emph{Syntax}:
+@code{void _gfortran_caf_co_sum (gfc_descriptor_t *a, int result_image,
+int *stat, char *errmsg, int errmsg_len)}
+
+@item @emph{Arguments}:
+@multitable @columnfractions .15 .70
+@item @var{a} @tab intent(inout) And array descriptor with the data to be
+breoadcasted (on @var{source_image}) or to be received (other images).
+@item @var{result_image} @tab The ID of the image to which the reduced
+value should be copied to; if zero, it has to be copied to all images.
+@item @var{stat} @tab intent(out) Stores the status STAT= and my may be NULL.
+@item @var{errmsg} @tab intent(out) When an error occurs, this will be set to
+an error message; may be NULL
+@item @var{errmsg_len} @tab the buffer size of errmsg.
+@end multitable
+
+@item @emph{NOTES}
+If @var{result_image} is nonzero, the value on all images except of the
+specified one become undefined; hence, the library may make use of this.
+@end table
+
+
+
+@node _gfortran_caf_co_reduce
+@subsection @code{_gfortran_caf_co_reduce} --- Generic collective reduction
+@cindex Coarray, _gfortran_caf_co_reduce
+
+@table @asis
+@item @emph{Description}:
+Calculates the for the each array element of the variable @var{a} the reduction
+value for that element in the current team; if @var{result_image} has the
+value 0, the result shall be stored on all images, otherwise, only on the
+specified image. The @var{opr} is a pure function doing a mathematically
+commutative and associative operation.
+
+The @var{opr_flags} denote the following; the values are bitwise ored.
+@code{GFC_CAF_BYREF} (1) if the result should be returned
+by value; @code{GFC_CAF_HIDDENLEN} (2) whether the result and argument
+string lengths shall be specified as hidden argument;
+@code{GFC_CAF_ARG_VALUE} (4) whether the arguments shall be passed by value,
+@code{GFC_CAF_ARG_DESC} (8) whether the arguments shall be passed by descriptor.
+
+
+@item @emph{Syntax}:
+@code{void _gfortran_caf_co_reduce (gfc_descriptor_t *a,
+void * (*opr) (void *, void *), int opr_flags, int result_image,
+int *stat, char *errmsg, int a_len, int errmsg_len)}
+
+@item @emph{Arguments}:
+@multitable @columnfractions .15 .70
+@item @var{opr} @tab Function pointer to the reduction function.
+@item @var{opr_flags} @tab Flags regarding the reduction function
+@item @var{a} @tab intent(inout) And array descriptor with the data to be
+breoadcasted (on @var{source_image}) or to be received (other images).
+@item @var{result_image} @tab The ID of the image to which the reduced
+value should be copied to; if zero, it has to be copied to all images.
+@item @var{stat} @tab intent(out) Stores the status STAT= and my may be NULL.
+@item @var{errmsg} @tab intent(out) When an error occurs, this will be set to
+an error message; may be NULL
+@item @var{a_len} @tab The string length of argument @var{a}.
+@item @var{errmsg_len} @tab the buffer size of errmsg.
+@end multitable
+
+@item @emph{NOTES}
+If @var{result_image} is nonzero, the value on all images except of the
+specified one become undefined; hence, the library may make use of this.
+For character arguments, the result is passed as first argument, followed
+by the result string length, next come the two string arguments, followed
+by the two hidden arguments. With C binding, there are no hidden arguments
+and by-reference passing and either only a single character is passed or
+an array descriptor.
+@end table
+
+
@c Intrinsic Procedures
@c ---------------------------------------------------------------------
diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi
index 4d884d7..90c9a3a 100644
--- a/gcc/fortran/intrinsic.texi
+++ b/gcc/fortran/intrinsic.texi
@@ -98,6 +98,7 @@ Some basic guidelines for editing this document:
* @code{CO_BROADCAST}: CO_BROADCAST, Copy a value to all images the current set of images
* @code{CO_MAX}: CO_MAX, Maximal value on the current set of images
* @code{CO_MIN}: CO_MIN, Minimal value on the current set of images
+* @code{CO_REDUCE}: CO_REDUCE, Reduction of values on the current set of images
* @code{CO_SUM}: CO_SUM, Sum of values on the current set of images
* @code{COMMAND_ARGUMENT_COUNT}: COMMAND_ARGUMENT_COUNT, Get number of command line arguments
* @code{COMPILER_OPTIONS}: COMPILER_OPTIONS, Options passed to the compiler
@@ -3340,7 +3341,7 @@ end program test
@end smallexample
@item @emph{See also}:
-@ref{CO_MAX}, @ref{CO_MIN}, @ref{CO_SUM}
+@ref{CO_MAX}, @ref{CO_MIN}, @ref{CO_SUM}, @ref{CO_REDUCE}
@end table
@@ -3354,7 +3355,7 @@ end program test
@item @emph{Description}:
@code{CO_MAX} determines element-wise the maximal value of @var{A} on all
images of the current team. If @var{RESULT_IMAGE} is present, the maximum
-values are returned on in @var{A} on the specified image only and the value
+values are returned in @var{A} on the specified image only and the value
of @var{A} on the other images become undefined. If @var{RESULT_IMAGE} is
not present, the value is returned on all images. If the execution was
successful and @var{STAT} is present, it is assigned the value zero. If the
@@ -3394,7 +3395,7 @@ end program test
@end smallexample
@item @emph{See also}:
-@ref{CO_MIN}, @ref{CO_SUM}, @ref{CO_BROADCAST}
+@ref{CO_MIN}, @ref{CO_SUM}, @ref{CO_REDUCE}, @ref{CO_BROADCAST}
@end table
@@ -3408,7 +3409,7 @@ end program test
@item @emph{Description}:
@code{CO_MIN} determines element-wise the minimal value of @var{A} on all
images of the current team. If @var{RESULT_IMAGE} is present, the minimal
-values are returned on in @var{A} on the specified image only and the value
+values are returned in @var{A} on the specified image only and the value
of @var{A} on the other images become undefined. If @var{RESULT_IMAGE} is
not present, the value is returned on all images. If the execution was
successful and @var{STAT} is present, it is assigned the value zero. If the
@@ -3448,7 +3449,87 @@ end program test
@end smallexample
@item @emph{See also}:
-@ref{CO_MAX}, @ref{CO_SUM}, @ref{CO_BROADCAST}
+@ref{CO_MAX}, @ref{CO_SUM}, @ref{CO_REDUCE}, @ref{CO_BROADCAST}
+@end table
+
+
+
+@node CO_REDUCE
+@section @code{CO_REDUCE} --- Reduction of values on the current set of images
+@fnindex CO_REDUCE
+@cindex Collectives, generic reduction
+
+@table @asis
+@item @emph{Description}:
+@code{CO_REDUCE} determines element-wise the reduction of the value of @var{A}
+on all images of the current team. The pure function passed as @var{OPERATOR}
+is used to pairwise reduce the values of @var{A} by passing either the value
+of @var{A} of different images or the result values of such a reduction as
+argument. If @var{A} is an array, the deduction is done element wise. If
+@var{RESULT_IMAGE} is present, the result values are returned in @var{A} on
+the specified image only and the value of @var{A} on the other images become
+undefined. If @var{RESULT_IMAGE} is not present, the value is returned on all
+images. If the execution was successful and @var{STAT} is present, it is
+assigned the value zero. If the execution failed, @var{STAT} gets assigned
+a nonzero value and, if present, @var{ERRMSG} gets assigned a value describing
+the occurred error.
+
+@item @emph{Standard}:
+Technical Specification (TS) 18508 or later
+
+@item @emph{Class}:
+Collective subroutine
+
+@item @emph{Syntax}:
+@code{CALL CO_REDUCE(A, OPERATOR, [, RESULT_IMAGE, STAT, ERRMSG])}
+
+@item @emph{Arguments}:
+@multitable @columnfractions .15 .70
+@item @var{A} @tab is an @code{INTENT(INOUT)} argument and shall be
+nonpolymorphic. If it is allocatable, it shall be allocated; if it is a pointer,
+it shall be associated. @var{A} shall have the same type and type parameters on
+all images of the team; if it is an array, it shall have the same shape on all
+images.
+@item @var{OPERATOR} @tab pure function with two scalar nonallocatable
+arguments, which shall be nonpolymorphic and have the same type and type
+parameters as @var{A}. The function shall return a nonallocatable scalar of
+the same type and type parameters as @var{A}. The function shall be the same on
+all images and with regards to the arguments mathematically commutative and
+associative. Note that @var{OPERATOR} may not be an elemental function, unless
+it is an intrisic function.
+@item @var{RESULT_IMAGE} @tab (optional) a scalar integer expression; if
+present, it shall have the same the same value on all images and refer to an
+image of the current team.
+@item @var{STAT} @tab (optional) a scalar integer variable
+@item @var{ERRMSG} @tab (optional) a scalar character variable
+@end multitable
+
+@item @emph{Example}:
+@smallexample
+program test
+ integer :: val
+ val = this_image ()
+ call co_reduce (val, result_image=1, operator=myprod)
+ if (this_image() == 1) then
+ write(*,*) "Product value", val ! prints num_images() factorial
+ end if
+contains
+ pure function myprod(a, b)
+ integer, value :: a, b
+ integer :: myprod
+ myprod = a * b
+ end function myprod
+end program test
+@end smallexample
+
+@item @emph{Note}:
+While the rules permit in principle an intrinsic function, none of the
+intrinsics in the standard fulfill the criteria of having a specific
+function, which takes two arguments of the same type and returning that
+type as result.
+
+@item @emph{See also}:
+@ref{CO_MIN}, @ref{CO_MAX}, @ref{CO_SUM}, @ref{CO_BROADCAST}
@end table
@@ -3462,7 +3543,7 @@ end program test
@item @emph{Description}:
@code{CO_SUM} sums up the values of each element of @var{A} on all
images of the current team. If @var{RESULT_IMAGE} is present, the summed-up
-values are returned on in @var{A} on the specified image only and the value
+values are returned in @var{A} on the specified image only and the value
of @var{A} on the other images become undefined. If @var{RESULT_IMAGE} is
not present, the value is returned on all images. If the execution was
successful and @var{STAT} is present, it is assigned the value zero. If the
@@ -3502,7 +3583,7 @@ end program test
@end smallexample
@item @emph{See also}:
-@ref{CO_MAX}, @ref{CO_MIN}, @ref{CO_BROADCAST}
+@ref{CO_MAX}, @ref{CO_MIN}, @ref{CO_REDUCE}, @ref{CO_BROADCAST}
@end table
@@ -3671,7 +3752,7 @@ value is of default @code{COMPLEX} type.
If @var{X} and @var{Y} are of @code{REAL} type, or one is of @code{REAL}
type and one is of @code{INTEGER} type, then the return value is of
@code{COMPLEX} type with a kind equal to that of the @code{REAL}
-argument with the highest precision.
+argument with the highest precision.
@item @emph{Example}:
@smallexample
@@ -3689,7 +3770,7 @@ end program test_complex
@node CONJG
-@section @code{CONJG} --- Complex conjugate function
+@section @code{CONJG} --- Complex conjugate function
@fnindex CONJG
@fnindex DCONJG
@cindex complex conjugate
@@ -3739,7 +3820,7 @@ end program test_conjg
@node COS
-@section @code{COS} --- Cosine function
+@section @code{COS} --- Cosine function
@fnindex COS
@fnindex DCOS
@fnindex CCOS
@@ -3798,7 +3879,7 @@ Inverse function: @ref{ACOS}
@node COSH
-@section @code{COSH} --- Hyperbolic cosine function
+@section @code{COSH} --- Hyperbolic cosine function
@fnindex COSH
@fnindex DCOSH
@cindex hyperbolic cosine
@@ -4166,7 +4247,7 @@ end program test_time_and_date
@node DBLE
-@section @code{DBLE} --- Double conversion function
+@section @code{DBLE} --- Double conversion function
@fnindex DBLE
@cindex conversion, to real
@@ -4448,7 +4529,7 @@ end program test_dprod
@item @emph{Specific names}:
@multitable @columnfractions .20 .20 .20 .25
@item Name @tab Argument @tab Return type @tab Standard
-@item @code{DPROD(X,Y)} @tab @code{REAL(4) X, Y} @tab @code{REAL(4)} @tab Fortran 77 and later
+@item @code{DPROD(X,Y)} @tab @code{REAL(4) X, Y} @tab @code{REAL(8)} @tab Fortran 77 and later
@end multitable
@end table
diff --git a/gcc/fortran/libgfortran.h b/gcc/fortran/libgfortran.h
index b7e11cb..dda755b 100644
--- a/gcc/fortran/libgfortran.h
+++ b/gcc/fortran/libgfortran.h
@@ -130,6 +130,14 @@ typedef enum
GFC_CAF_ATOMIC_XOR
} libcaf_atomic_codes;
+
+/* For CO_REDUCE. */
+#define GFC_CAF_BYREF (1<<0)
+#define GFC_CAF_HIDDENLEN (1<<1)
+#define GFC_CAF_ARG_VALUE (1<<2)
+#define GFC_CAF_ARG_DESC (1<<3)
+
+
/* Default unit number for preconnected standard input and output. */
#define GFC_STDIN_UNIT_NUMBER 5
#define GFC_STDOUT_UNIT_NUMBER 6
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index 522c0f0..3fbc789 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -153,6 +153,7 @@ tree gfor_fndecl_caf_unlock;
tree gfor_fndecl_co_broadcast;
tree gfor_fndecl_co_max;
tree gfor_fndecl_co_min;
+tree gfor_fndecl_co_reduce;
tree gfor_fndecl_co_sum;
@@ -3445,6 +3446,14 @@ gfc_build_builtin_function_decls (void)
void_type_node, 6, pvoid_type_node, integer_type_node,
pint_type, pchar_type_node, integer_type_node, integer_type_node);
+ gfor_fndecl_co_reduce = gfc_build_library_function_decl_with_spec (
+ get_identifier (PREFIX("caf_co_reduce")), "W.R.WW",
+ void_type_node, 8, pvoid_type_node,
+ build_pointer_type (build_varargs_function_type_list (void_type_node,
+ NULL_TREE)),
+ integer_type_node, integer_type_node, pint_type, pchar_type_node,
+ integer_type_node, integer_type_node);
+
gfor_fndecl_co_sum = gfc_build_library_function_decl_with_spec (
get_identifier (PREFIX("caf_co_sum")), "W.WW",
void_type_node, 5, pvoid_type_node, integer_type_node,
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c
index 1815903..932bf79 100644
--- a/gcc/fortran/trans-intrinsic.c
+++ b/gcc/fortran/trans-intrinsic.c
@@ -8563,15 +8563,31 @@ conv_co_collective (gfc_code *code)
gfc_se argse;
stmtblock_t block, post_block;
tree fndecl, array, strlen, image_index, stat, errmsg, errmsg_len;
+ gfc_expr *image_idx_expr, *stat_expr, *errmsg_expr, *opr_expr;
gfc_start_block (&block);
gfc_init_block (&post_block);
+ if (code->resolved_isym->id == GFC_ISYM_CO_REDUCE)
+ {
+ opr_expr = code->ext.actual->next->expr;
+ image_idx_expr = code->ext.actual->next->next->expr;
+ stat_expr = code->ext.actual->next->next->next->expr;
+ errmsg_expr = code->ext.actual->next->next->next->next->expr;
+ }
+ else
+ {
+ opr_expr = NULL;
+ image_idx_expr = code->ext.actual->next->expr;
+ stat_expr = code->ext.actual->next->next->expr;
+ errmsg_expr = code->ext.actual->next->next->next->expr;
+ }
+
/* stat. */
- if (code->ext.actual->next->next->expr)
+ if (stat_expr)
{
gfc_init_se (&argse, NULL);
- gfc_conv_expr (&argse, code->ext.actual->next->next->expr);
+ gfc_conv_expr (&argse, stat_expr);
gfc_add_block_to_block (&block, &argse.pre);
gfc_add_block_to_block (&post_block, &argse.post);
stat = argse.expr;
@@ -8620,10 +8636,10 @@ conv_co_collective (gfc_code *code)
strlen = integer_zero_node;
/* image_index. */
- if (code->ext.actual->next->expr)
+ if (image_idx_expr)
{
gfc_init_se (&argse, NULL);
- gfc_conv_expr (&argse, code->ext.actual->next->expr);
+ gfc_conv_expr (&argse, image_idx_expr);
gfc_add_block_to_block (&block, &argse.pre);
gfc_add_block_to_block (&post_block, &argse.post);
image_index = fold_convert (integer_type_node, argse.expr);
@@ -8632,10 +8648,10 @@ conv_co_collective (gfc_code *code)
image_index = integer_zero_node;
/* errmsg. */
- if (code->ext.actual->next->next->next->expr)
+ if (errmsg_expr)
{
gfc_init_se (&argse, NULL);
- gfc_conv_expr (&argse, code->ext.actual->next->next->next->expr);
+ gfc_conv_expr (&argse, errmsg_expr);
gfc_add_block_to_block (&block, &argse.pre);
gfc_add_block_to_block (&post_block, &argse.post);
errmsg = argse.expr;
@@ -8659,6 +8675,9 @@ conv_co_collective (gfc_code *code)
case GFC_ISYM_CO_MIN:
fndecl = gfor_fndecl_co_min;
break;
+ case GFC_ISYM_CO_REDUCE:
+ fndecl = gfor_fndecl_co_reduce;
+ break;
case GFC_ISYM_CO_SUM:
fndecl = gfor_fndecl_co_sum;
break;
@@ -8670,9 +8689,44 @@ conv_co_collective (gfc_code *code)
|| code->resolved_isym->id == GFC_ISYM_CO_BROADCAST)
fndecl = build_call_expr_loc (input_location, fndecl, 5, array,
image_index, stat, errmsg, errmsg_len);
- else
+ else if (code->resolved_isym->id != GFC_ISYM_CO_REDUCE)
fndecl = build_call_expr_loc (input_location, fndecl, 6, array, image_index,
stat, errmsg, strlen, errmsg_len);
+ else
+ {
+ tree opr, opr_flags;
+
+ // FIXME: Handle TS29113's bind(C) strings with descriptor.
+ int opr_flag_int;
+ if (gfc_is_proc_ptr_comp (opr_expr))
+ {
+ gfc_symbol *sym = gfc_get_proc_ptr_comp (opr_expr)->ts.interface;
+ opr_flag_int = sym->attr.dimension
+ || (sym->ts.type == BT_CHARACTER
+ && !sym->attr.is_bind_c)
+ ? GFC_CAF_BYREF : 0;
+ opr_flag_int |= opr_expr->ts.type == BT_CHARACTER
+ && !sym->attr.is_bind_c
+ ? GFC_CAF_HIDDENLEN : 0;
+ opr_flag_int |= sym->formal->sym->attr.value ? GFC_CAF_ARG_VALUE : 0;
+ }
+ else
+ {
+ opr_flag_int = gfc_return_by_reference (opr_expr->symtree->n.sym)
+ ? GFC_CAF_BYREF : 0;
+ opr_flag_int |= opr_expr->ts.type == BT_CHARACTER
+ && !opr_expr->symtree->n.sym->attr.is_bind_c
+ ? GFC_CAF_HIDDENLEN : 0;
+ opr_flag_int |= opr_expr->symtree->n.sym->formal->sym->attr.value
+ ? GFC_CAF_ARG_VALUE : 0;
+ }
+ opr_flags = build_int_cst (integer_type_node, opr_flag_int);
+ gfc_conv_expr (&argse, opr_expr);
+ opr = gfc_build_addr_expr (NULL_TREE, argse.expr);
+ fndecl = build_call_expr_loc (input_location, fndecl, 8, array, opr, opr_flags,
+ image_index, stat, errmsg, strlen, errmsg_len);
+ }
+
gfc_add_expr_to_block (&block, fndecl);
gfc_add_block_to_block (&block, &post_block);
@@ -9386,12 +9440,10 @@ gfc_conv_intrinsic_subroutine (gfc_code *code)
res = conv_caf_send (code);
break;
- case GFC_ISYM_CO_REDUCE:
- gcc_unreachable ();
- break;
case GFC_ISYM_CO_BROADCAST:
case GFC_ISYM_CO_MIN:
case GFC_ISYM_CO_MAX:
+ case GFC_ISYM_CO_REDUCE:
case GFC_ISYM_CO_SUM:
res = conv_co_collective (code);
break;
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 465661c..51ad910 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -742,6 +742,7 @@ extern GTY(()) tree gfor_fndecl_caf_unlock;
extern GTY(()) tree gfor_fndecl_co_broadcast;
extern GTY(()) tree gfor_fndecl_co_max;
extern GTY(()) tree gfor_fndecl_co_min;
+extern GTY(()) tree gfor_fndecl_co_reduce;
extern GTY(()) tree gfor_fndecl_co_sum;