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 <paul.richard.tho...@gmail.com> 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 

Reply via email to