Re: Complex arithmetic in Fortran
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
> 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
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
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
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
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
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
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]
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]
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