Re: Complex arithmetic in Fortran

2024-11-13 Thread Thomas Koenig

Am 13.11.24 um 15:55 schrieb Toon Moene:


Since the Fortran 95 Standard it does (in the current Standard: 7.4.3.2 
Real type):


The real type includes a zero value. Processors that distinguish between 
positive and negative zeros shall treat them as mathematically equivalent

• in all intrinsic relational operations, and
• as actual arguments to intrinsic procedures other than those for which
   it is explicitly specified that negative zero is distinguished.

[Note that "processor" in Fortran standardese means everything 
(combined) from the compiler down to the actual hardware].


So we have to comb through the Standard to see where bullet 2 applies ...


I looked through the current standard, and the only mention of positive
and negative zero I could find were in the IEEE intrinsics.

So, I think we could ignore signed zeros (from the Fortran standard
perspective)

- for complex arithmetic, always
- for real arithmetic, if none of the IEEE modules is USEd

Best regards

Thomas



Re: Complex arithmetic in Fortran

2024-11-13 Thread FX Coudert
> So, I think we could ignore signed zeros (from the Fortran standard
> perspective)
> 
> - for complex arithmetic, always
> - for real arithmetic, if none of the IEEE modules is USEd

That seems like a very backward-incompatible change to introduce :(
I might break a lot of existing codes.

FX


Re: Complex arithmetic in Fortran

2024-11-13 Thread Steve Kargl
On Wed, Nov 13, 2024 at 05:33:20PM +0100, Thomas Koenig wrote:
> Am 13.11.24 um 15:55 schrieb Toon Moene:
> > 
> > Since the Fortran 95 Standard it does (in the current Standard: 7.4.3.2
> > Real type):
> > 
> > The real type includes a zero value. Processors that distinguish between
> > positive and negative zeros shall treat them as mathematically
> > equivalent
> > • in all intrinsic relational operations, and
> > • as actual arguments to intrinsic procedures other than those for which
> >    it is explicitly specified that negative zero is distinguished.
> > 
> > [Note that "processor" in Fortran standardese means everything
> > (combined) from the compiler down to the actual hardware].
> > 
> > So we have to comb through the Standard to see where bullet 2 applies ...
> 
> I looked through the current standard, and the only mention of positive
> and negative zero I could find were in the IEEE intrinsics.
> 
> So, I think we could ignore signed zeros (from the Fortran standard
> perspective)
> 
> - for complex arithmetic, always
> - for real arithmetic, if none of the IEEE modules is USEd
> 

Possibly ending up on the wrong Riemann sheet seems like
a good idea to me.

If you're going to revisit complex multication and division,
then I believe the -fcx-fortran-rules option should be removed.
It states 

Complex multiplication and division follow Fortran rules.

There are no special rules for Fortran.  The rules for Fortran
are


   (24-007r1.pdf, p162)
   The two operands of numeric intrinsic binary operations may be of
   different numeric types or different kind type parameters.  Except
   for a value of type real or complex raised to an integer power, if
   the operands have different types or kind type parameters, the effect
   is as if each operand that differs in type or kind type parameter from
   those of the result is converted to the type and kind type parameter
   of the result before the operation is performed.

So,

(1) r*z = (r+I0)*(x+Iy),

which is gfortran's current behavior.


   Once the interpretation of a numeric intrinsic operation is established,
   the processor may evaluate any mathematically equivalent expression,
   provided that the integrity of parentheses is not violated.

(There are implicit parentheses above, but let's let that go.)

(2) r*z = r*x + Ir*y

This appears to be mathematically equivalent, except they are not.
+-0 and +-inf are fundamental to the foundations of calculus and
branch cuts in complex plane.  gfortran does (1) by default.  Users
can get (2) if they use -ffast-math, -Ofast or -fno-cx-fortran-rules.

J3 threw a red herring and cop out into the interpretation by
making a statement that IEEE754 does consider complex number.
Of course, it would not!  IEEE754 deals with mapping real numbers
to a finite set of floating point numbers.  J3 should have considered 
Annex G, "IEC 60559-compatible complex arithmetic" from C23; specially,
G.5.1 "Multiplicative operators".

-- 
Steve


Complex arithmetic in Fortran

2024-11-13 Thread Thomas Koenig

Hello world,

J3, the US Fortran standards committee, has passed
https://j3-fortran.org/doc/year/24/24-179.txt
which states (with a bit of an overabundance of
clarity) that, in Fortran, it is possible special-case
complex multiplication when one of the numbers is known
to have a zero component, for example when promoting
a real to complex for complex multiplication.  For
example, multiplying a complex variable b with a real
variable a can be done with c%re = b%re * a, c%im = b%im * a,
without considering NaNs and infinities. Apparently, other
Fortran compilers do this.

They also stated that ISO/IEC 60559:2020 (aka IEEE 754) does
not specify complex arithmetic (I wouldn't know, because it is a
paywalled standard).

How do we want to deal with this? Do we want to implement this
(it's an obvious speed advantage)?  Should it be the default?
Do we want to include this in -fcx-fortran-rules?

Best regards

Thomas




Re: Complex arithmetic in Fortran

2024-11-13 Thread Toon Moene

On 11/13/24 15:12, Richard Biener wrote:


On Wed, Nov 13, 2024 at 3:05 PM Thomas Koenig  wrote:


Hello world,

J3, the US Fortran standards committee, has passed
https://j3-fortran.org/doc/year/24/24-179.txt
which states (with a bit of an overabundance of
clarity) that, in Fortran, it is possible special-case
complex multiplication when one of the numbers is known
to have a zero component, for example when promoting
a real to complex for complex multiplication.  For
example, multiplying a complex variable b with a real
variable a can be done with c%re = b%re * a, c%im = b%im * a,
without considering NaNs and infinities. Apparently, other
Fortran compilers do this.

They also stated that ISO/IEC 60559:2020 (aka IEEE 754) does
not specify complex arithmetic (I wouldn't know, because it is a
paywalled standard).

How do we want to deal with this? Do we want to implement this
(it's an obvious speed advantage)?  Should it be the default?
Do we want to include this in -fcx-fortran-rules?


The middle-end complex lowering pass does this already, irrespective
of NaNs, same for some degenerate cases with division.


Are you sure ?

For this code:

$ cat complex.f90
complex function p(c, r)
complex, intent(in) :: c
real, intent(in):: r
p = c * r
end

I definitely see a difference between

$ gfortran -O2 -S complex.f90

and

$ gfortran -O2 -ffast-math -S complex.f90

--
Toon Moene - e-mail: t...@moene.org - phone: +31 346 214290
Saturnushof 14, 3738 XG  Maartensdijk, The Netherlands


Re: Complex arithmetic in Fortran

2024-11-13 Thread Richard Biener
On Wed, Nov 13, 2024 at 3:21 PM Toon Moene  wrote:
>
> On 11/13/24 15:12, Richard Biener wrote:
>
> > On Wed, Nov 13, 2024 at 3:05 PM Thomas Koenig  wrote:
> >>
> >> Hello world,
> >>
> >> J3, the US Fortran standards committee, has passed
> >> https://j3-fortran.org/doc/year/24/24-179.txt
> >> which states (with a bit of an overabundance of
> >> clarity) that, in Fortran, it is possible special-case
> >> complex multiplication when one of the numbers is known
> >> to have a zero component, for example when promoting
> >> a real to complex for complex multiplication.  For
> >> example, multiplying a complex variable b with a real
> >> variable a can be done with c%re = b%re * a, c%im = b%im * a,
> >> without considering NaNs and infinities. Apparently, other
> >> Fortran compilers do this.
> >>
> >> They also stated that ISO/IEC 60559:2020 (aka IEEE 754) does
> >> not specify complex arithmetic (I wouldn't know, because it is a
> >> paywalled standard).
> >>
> >> How do we want to deal with this? Do we want to implement this
> >> (it's an obvious speed advantage)?  Should it be the default?
> >> Do we want to include this in -fcx-fortran-rules?
> >
> > The middle-end complex lowering pass does this already, irrespective
> > of NaNs, same for some degenerate cases with division.
>
> Are you sure ?
>
> For this code:
>
> $ cat complex.f90
> complex function p(c, r)
> complex, intent(in) :: c
> real, intent(in):: r
> p = c * r
> end
>
> I definitely see a difference between
>
> $ gfortran -O2 -S complex.f90
>
> and
>
> $ gfortran -O2 -ffast-math -S complex.f90

Ah.  This is because of

static int
some_nonzerop (tree t)
{
  int zerop = false;

  /* Operations with real or imaginary part of a complex number zero
 cannot be treated the same as operations with a real or imaginary
 operand if we care about the signs of zeros in the result.  */
  if (TREE_CODE (t) == REAL_CST && !flag_signed_zeros)
zerop = real_identical (&TREE_REAL_CST (t), &dconst0);

so the -ffast-math result can be obtained with just -fno-signed-zeros (I assumed
fortran doesn't have signed zeros?)

Richard.

> --
> Toon Moene - e-mail: t...@moene.org - phone: +31 346 214290
> Saturnushof 14, 3738 XG  Maartensdijk, The Netherlands


Re: Complex arithmetic in Fortran

2024-11-13 Thread Toon Moene

On 11/13/24 15:40, Richard Biener wrote:

On Wed, Nov 13, 2024 at 3:21 PM Toon Moene  wrote:


On 11/13/24 15:12, Richard Biener wrote:


On Wed, Nov 13, 2024 at 3:05 PM Thomas Koenig  wrote:


Hello world,

J3, the US Fortran standards committee, has passed
https://j3-fortran.org/doc/year/24/24-179.txt
which states (with a bit of an overabundance of
clarity) that, in Fortran, it is possible special-case
complex multiplication when one of the numbers is known
to have a zero component, for example when promoting
a real to complex for complex multiplication.  For
example, multiplying a complex variable b with a real
variable a can be done with c%re = b%re * a, c%im = b%im * a,
without considering NaNs and infinities. Apparently, other
Fortran compilers do this.

They also stated that ISO/IEC 60559:2020 (aka IEEE 754) does
not specify complex arithmetic (I wouldn't know, because it is a
paywalled standard).

How do we want to deal with this? Do we want to implement this
(it's an obvious speed advantage)?  Should it be the default?
Do we want to include this in -fcx-fortran-rules?


The middle-end complex lowering pass does this already, irrespective
of NaNs, same for some degenerate cases with division.


Are you sure ?

For this code:

$ cat complex.f90
complex function p(c, r)
complex, intent(in) :: c
real, intent(in):: r
p = c * r
end

I definitely see a difference between

$ gfortran -O2 -S complex.f90

and

$ gfortran -O2 -ffast-math -S complex.f90


Ah.  This is because of

static int
some_nonzerop (tree t)
{
   int zerop = false;

   /* Operations with real or imaginary part of a complex number zero
  cannot be treated the same as operations with a real or imaginary
  operand if we care about the signs of zeros in the result.  */
   if (TREE_CODE (t) == REAL_CST && !flag_signed_zeros)
 zerop = real_identical (&TREE_REAL_CST (t), &dconst0);

so the -ffast-math result can be obtained with just -fno-signed-zeros (I assumed
fortran doesn't have signed zeros?)


Since the Fortran 95 Standard it does (in the current Standard: 7.4.3.2 
Real type):


The real type includes a zero value. Processors that distinguish between 
positive and negative zeros shall treat them as mathematically equivalent

• in all intrinsic relational operations, and
• as actual arguments to intrinsic procedures other than those for which
  it is explicitly specified that negative zero is distinguished.

[Note that "processor" in Fortran standardese means everything 
(combined) from the compiler down to the actual hardware].


So we have to comb through the Standard to see where bullet 2 applies ...

Kind regards,

--
Toon Moene - e-mail: t...@moene.org - phone: +31 346 214290
Saturnushof 14, 3738 XG  Maartensdijk, The Netherlands


Re: Complex arithmetic in Fortran

2024-11-13 Thread Richard Biener
On Wed, Nov 13, 2024 at 3:05 PM Thomas Koenig  wrote:
>
> Hello world,
>
> J3, the US Fortran standards committee, has passed
> https://j3-fortran.org/doc/year/24/24-179.txt
> which states (with a bit of an overabundance of
> clarity) that, in Fortran, it is possible special-case
> complex multiplication when one of the numbers is known
> to have a zero component, for example when promoting
> a real to complex for complex multiplication.  For
> example, multiplying a complex variable b with a real
> variable a can be done with c%re = b%re * a, c%im = b%im * a,
> without considering NaNs and infinities. Apparently, other
> Fortran compilers do this.
>
> They also stated that ISO/IEC 60559:2020 (aka IEEE 754) does
> not specify complex arithmetic (I wouldn't know, because it is a
> paywalled standard).
>
> How do we want to deal with this? Do we want to implement this
> (it's an obvious speed advantage)?  Should it be the default?
> Do we want to include this in -fcx-fortran-rules?

The middle-end complex lowering pass does this already, irrespective
of NaNs, same for some degenerate cases with division.

Richard.

> Best regards
>
> Thomas
>
>


Re: [PATCH] Fortran: fix passing of NULL() actual argument to character dummy [PR104819]

2024-11-13 Thread Jerry D

On 11/13/24 2:26 PM, Harald Anlauf wrote:

Dear all,

the attached patch is the third part of a series to fix the handling of
NULL() passed to pointer dummy arguments.  This one addresses character
dummy arguments (scalar, assumed-shape, assumed-rank) for various
uses in the caller.

The patch is a little larger than I expected, due to corner cases
(MOLD present or not, assumed-rank or other).  If someone finds a
more clever version, I would be happy to learn about it.
Especially the treatment of assumed-rank dummy could certainly
be done differently.

Regtested on x86_64-pc-linux-gnu.  OK for mainline?

As this fixes wrong code on the one hand, and is very localized,
I would like to backport this to 14-branch after some waiting.
Is this ok?

Thanks,
Harald



OK for mainline and backport.

Food for thought at another time:

gfc_conv_procedure_call contains about 2100 lines of code. One can read 
through this fairly directly and the comments are very helpful. It begs 
for some refactoring into a set of smaller functions.


Kind and Type regards,

Jerry


[PATCH] Fortran: fix passing of NULL() actual argument to character dummy [PR104819]

2024-11-13 Thread Harald Anlauf
Dear all,

the attached patch is the third part of a series to fix the handling of
NULL() passed to pointer dummy arguments.  This one addresses character
dummy arguments (scalar, assumed-shape, assumed-rank) for various
uses in the caller.

The patch is a little larger than I expected, due to corner cases
(MOLD present or not, assumed-rank or other).  If someone finds a
more clever version, I would be happy to learn about it.
Especially the treatment of assumed-rank dummy could certainly
be done differently.

Regtested on x86_64-pc-linux-gnu.  OK for mainline?

As this fixes wrong code on the one hand, and is very localized,
I would like to backport this to 14-branch after some waiting.
Is this ok?

Thanks,
Harald

From 3c7877fd4a20b6681dab6737f5d5be0d77241709 Mon Sep 17 00:00:00 2001
From: Harald Anlauf 
Date: Wed, 13 Nov 2024 23:03:47 +0100
Subject: [PATCH] Fortran: fix passing of NULL() actual argument to character
 dummy [PR104819]

Ensure that character length is set and passed by the call to a procedure
when its dummy argument is NULL() with MOLD argument present, or set length
to either 0 or the callee's expected character length.  For assumed-rank
dummies, use the rank of the MOLD argument.  Generate temporaries for
passed arguments when needed.

	PR fortran/104819

gcc/fortran/ChangeLog:

	* trans-expr.cc (gfc_conv_procedure_call): Handle passing of NULL()
	to non-optional dummy arguments of non-bind(c) procedures.

gcc/testsuite/ChangeLog:

	* gfortran.dg/null_actual_6.f90: New test.
---
 gcc/fortran/trans-expr.cc   |  69 ++
 gcc/testsuite/gfortran.dg/null_actual_6.f90 | 221 
 2 files changed, 290 insertions(+)
 create mode 100644 gcc/testsuite/gfortran.dg/null_actual_6.f90

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index ddbb5ecf068..f9a6f8fb16f 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -7542,6 +7542,75 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 	  gfc_conv_const_charlen (e->symtree->n.sym->ts.u.cl);
 	  parmse.string_length = e->symtree->n.sym->ts.u.cl->backend_decl;
 	}
+
+	  /* Obtain the character length for a NULL() actual with a character
+	 MOLD argument.  Otherwise substitute a suitable dummy length.
+	 Here we handle non-optional dummies of non-bind(c) procedures.  */
+	  if (e->expr_type == EXPR_NULL
+	  && fsym->ts.type == BT_CHARACTER
+	  && !fsym->attr.optional
+	  && !(sym->attr.is_bind_c && is_CFI_desc (fsym, NULL)))
+	{
+	  if (e->ts.type == BT_CHARACTER
+		  && e->symtree->n.sym->ts.type == BT_CHARACTER)
+		{
+		  /* MOLD is present.  Substitute a temporary character NULL
+		 pointer.  For assumed-rank dummy we need a descriptor that
+		 passes the correct rank.  */
+		  if (fsym->as && fsym->as->type == AS_ASSUMED_RANK)
+		{
+		  tree rank;
+		  tree tmp = parmse.expr;
+		  tmp = gfc_conv_scalar_to_descriptor (&parmse, tmp,
+			   fsym->attr);
+		  rank = gfc_conv_descriptor_rank (tmp);
+		  gfc_add_modify (&parmse.pre, rank,
+  build_int_cst (TREE_TYPE (rank),
+		 e->rank));
+		  parmse.expr = gfc_build_addr_expr (NULL_TREE, tmp);
+		}
+		  else
+		{
+		  tree tmp = gfc_create_var (TREE_TYPE (parmse.expr),
+		 "null");
+		  gfc_add_modify (&se->pre, tmp,
+  build_zero_cst (TREE_TYPE (tmp)));
+		  parmse.expr = gfc_build_addr_expr (NULL_TREE, tmp);
+		}
+
+		  /* Ensure that a usable length is available.  */
+		  if (parmse.string_length == NULL_TREE)
+		{
+		  gfc_typespec *ts = &e->symtree->n.sym->ts;
+
+		  if (ts->u.cl->length != NULL
+			  && ts->u.cl->length->expr_type == EXPR_CONSTANT)
+			gfc_conv_const_charlen (ts->u.cl);
+
+		  if (ts->u.cl->backend_decl)
+			parmse.string_length = ts->u.cl->backend_decl;
+		}
+		}
+	  else if (e->ts.type == BT_UNKNOWN
+		   && parmse.string_length == NULL_TREE)
+		{
+		  /* MOLD is not present.  Pass length of associated dummy
+		 character argument if constant, or zero.  */
+		  if (fsym->ts.u.cl->length != NULL
+		  && fsym->ts.u.cl->length->expr_type == EXPR_CONSTANT)
+		{
+		  gfc_conv_const_charlen (fsym->ts.u.cl);
+		  parmse.string_length = fsym->ts.u.cl->backend_decl;
+		}
+		  else
+		{
+		  parmse.string_length
+			= gfc_create_var (gfc_charlen_type_node, "slen");
+		  gfc_add_modify (&se->pre, parmse.string_length,
+  build_zero_cst (gfc_charlen_type_node));
+		}
+		}
+	}
 	}

   /* If any actual argument of the procedure is allocatable and passed
diff --git a/gcc/testsuite/gfortran.dg/null_actual_6.f90 b/gcc/testsuite/gfortran.dg/null_actual_6.f90
new file mode 100644
index 000..e6745311bee
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/null_actual_6.f90
@@ -0,0 +1,221 @@
+! { dg-do run }
+! { dg-additional-options "-fcheck=bounds" }
+!
+! PR fortran/104819 - passing of NULL() actual argume