Hi Paul,
what do want us to do with it?
Let me give an early review:
In gfc_resolve_reduce, I think you duplicate the test for the function having
optional formal arguments. Ones in this block:
+ if (formal->sym->attr.allocatable || formal->sym->attr.allocatable
+ || formal->sym->attr.pointer || formal->sym->attr.pointer
+ || formal->sym->attr.optional || formal->sym->attr.optional
+ || formal->sym->ts.type == BT_CLASS || formal->sym->ts.type == BT_CLASS)
+ {
+ gfc_error ("Each argument of OPERATION at %L shall be a scalar, "
+ "non-allocatable, non-pointer, non-polymorphic and "
+ "nonoptional", &operation->where);
+ return false;
+ }
and then again (in the third next if) in:
+ if (formal->sym->attr.optional || formal->next->sym->attr.optional)
+ {
+ gfc_error ("The function passed as OPERATION at %L shall not have the "
+ "OPTIONAL attribute for either of the arguments",
+ &operation->where);
+ return false;
+ }
Testing ones should be enough, right?
I don't like the code repetition in
+ if (array->ts.type == BT_CHARACTER)
+ {
+ gfc_charlen *cl;
+ unsigned long actual_size, formal_size1, formal_size2, result_size;
+
+ cl = array->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;
+
either use function for evaluating the constant cl or how about this modern C++:
+ if (array->ts.type == BT_CHARACTER)
+ {
+ unsigned long actual_size, formal_size1, formal_size2, result_size;
+ auto get_cst_cl = [](const gfc_charlen *cl) -> unsigned log {
+ return cl && cl->length && cl->length->expr_type == EXPR_CONSTANT
+ ? mpz_get_ui (cl->length->value.integer) : 0;
+ };
+
+ actual_size = get_cst_cl (array->ts.u.cl);
+
+ formal_size1 = get_cst_cl (formal->sym->ts.u.cl);
+
+ formal_size2 = get_cst_cl (formal->next->sym->ts.u.cl);
+
+ result_size = get_cst_cl (sym->ts.u.cl);
I think the above is easier to maintain and read. Whether you use the lambda or
a dedicated function I leave to your liking.
In
+static gfc_symtree *
+generate_reduce_op_wrapper (gfc_expr *op)
+{
+ gfc_symbol *operation = op->symtree->n.sym;
+ gfc_symbol *wrapper, *a, *b, *c;
+ gfc_symtree *st;
+ char tname[GFC_MAX_SYMBOL_LEN+1];
+ char *name;
+ gfc_namespace *ns;
+// gfc_gsymbol *gsym = NULL;
^^^ Is this needed?
@@ -8785,6 +8801,12 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
gfc_add_expr_to_block (&se->pre, tmp);
}
}
+ else if (scalar_reduce)
+ {
+ gfc_add_expr_to_block (&se->pre, se->expr);
+ se->expr = result;
+// gfc_add_block_to_block (&se->post, &post);
^^^ I'd rather uncomment it to be safe in the future, if something is in post.
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -4250,6 +4250,20 @@ gfc_get_symbol_for_expr (gfc_expr * expr, bool
ignore_optional) sym->attr.proc = PROC_INTRINSIC;
sym->attr.flavor = FL_PROCEDURE;
sym->result = sym;
+#if 0
+ if (expr->value.function.isym
+ && expr->value.function.isym->id == GFC_ISYM_REDUCE)
+ {
+ if (expr->value.function.actual
+ && expr->value.function.actual->next
+ && expr->value.function.actual->next->next
+ && expr->value.function.actual->next->next->expr == NULL)
+ expr->rank = 0;
+ else if (expr->value.function.actual
+ && expr->value.function.actual->expr)
+ expr->rank = expr->value.function.actual->expr->rank - 1;
+ }
+#endif
Er?
Typo in Change.Logs
s/discription/description/
That Changelog looks non-standard.
Ok, I hope this first feedback is valuable to you.
One other question: How does REDUCE() relate to CO_REDUCE()?
Regards,
Andre
On Sun, 2 Mar 2025 20:41:55 +0000
Paul Richard Thomas <[email protected]> wrote:
> Hi All,
>
> This is very much an early version of the F2018 REDUCE intrinsic. I am
> posting it now because I have totally forgotten how to include new
> functions in libgfortran.so. -static-libfortran works fine and the results
> are the same as the other brands.
>
> At present, it produces several of link warnings.
> test_reduce.f90:23:2: warning: type of ‘_gfortran_reduce_scalar’ does not
> match original declaration [-Wlto-type-mismatch]
> 23 | pure function add(i,j) result(sum_ij)
> | ^
> test_reduce.f90:23:2: note: return value type mismatch
> test_reduce.f90:23:2: note: type ‘struct s’ should match type ‘int’
> test_reduce.f90:23:2: note: ‘_gfortran_reduce_scalar’ was previously
> declared here
> test_reduce.f90:23:2: note: code may be misoptimized unless
> ‘-fno-strict-aliasing’ is used
> /usr/bin/ld: warning: /tmp/ccfEUYXA.ltrans0.ltrans.o: requires executable
> stack (because the .note.GNU-stack section is executable)
>
> The last one is unavoidable because of the use of the wrapper for
> 'operation' that allows type agnostic use of pointer arithmetic in the
> library functions. I am working on the type mismatch, which occurs when
> different wrapper types appear in the same namespace.
>
> Clearly there is a fair amount to do: clear the commented out
> sections/lines, testcases and documentation.
>
> Paul
--
Andre Vehreschild * Email: vehre ad gmx dot de