Hi Thomas,

may I ask you to run contrib/check_GNU_style.py on your patch? At least on my
system more than lines 50 are reported. I am drawn to this style issues and find
it hard to digest the beef of the patch. That's my personal OCD unfortunately.

Furthermore (Sorry, I inserted your w/o cite and noted that after it was too
late. I have prefixed my remarks/questions with AV: to make them easier to
find. I hope this helps):

diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc
index 2f50d84b876..1020ba5342f 100644
--- a/gcc/fortran/check.cc
+++ b/gcc/fortran/check.cc
@@ -7637,3 +7960,12 @@ gfc_check_storage_size (gfc_expr *a, gfc_expr *kind)

   return true;
 }
+
+/* Check two operands that either both or none of them can
+   be UNSIGNED.  */
+
+bool
+gfc_invalid_unsigned_ops (gfc_expr * op1, gfc_expr * op2)
+{
+  return (op1->ts.type == BT_UNSIGNED) + (op2->ts.type == BT_UNSIGNED) == 1;

AV: That's an interesting way to model an xor. Why not `op1.. ^ op2..`? Yes,
it's bitwise, but on bools.

+}
diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi
index 7e8783a3690..9043fa321dc 100644
--- a/gcc/fortran/gfortran.texi
+++ b/gcc/fortran/gfortran.texi
@@ -2701,7 +2702,90 @@ descriptor occurred, use @code{INQUIRE} to get the file
position, count the characters up to the next @code{NEW_LINE} and then start
 reading from the position marked previously.

+@node Experimental features for Fortran 202Y
+@section Experimental features for Fortran 202Y
+@cindex Fortran 202Y

+GNU Fortran supports some experimental features which have been
+proposed and accepted by the J3 standards committee.  These
+exist to give users a chance to try them out, and to provide
+a reference implementation.
+
+As these features have not been finalized, there is a chance that the
+version in the upcoming standard will differ from what GNU Fortran
+currently implements.  Stability of these implementations is therefore
+not guaranteed.
+
+@menu
+* Unsigned integers::
+@end menu
+
+@node Unsigned integers
+@subsection Unsigned integers
+@cindex Unsigned integers
+GNU Fortran supports unsigned integers according to
+@uref{https://j3-fortran.org/doc/year/24/24-116.txt, J3/24-116}.  The
+data type is called @code{UNSIGNED}.  For an unsigned type with $n$ bits,
+it implements integer arithmetic modulo @code{2**n}, comparable to the
+@code{unsigned} data type in C.
+
+The data type has @code{KIND} numbers comparable to other Fortran data
+types, which can be selected via the @code{SELECTED_UNSIGNED_KIND}
+function.
+
+Mixed arithmetic, comparisoins and assignment between @code{UNSIGNED}

AV: ... comparisons ...

+and other types are only possible via explicit conversion.  Conversion
+from @code{UNSIGNED} to other types is done via type conversion
+functions like @code{INT} or @code{REAL}. Conversion from other types
+to @code{UNSIGNED} is done via @code{UINT}. Unsigned variables cannot be
+used as index variables in @code{DO} loops or as array indices.
+
+Unsigned numbers have a trailing @code{u} as suffix, optionally followed
+by a @code{KIND} number separated by an underscore.
+
+Input and output can be done using the @code{I}, @code{B}, @code{O}
+and @code{Z} descriptors, plus unformatted I/O.
+
+Here is a small, somewhat contrived example of their use:
+@smallexample
+program main
+  unsigned(kind=8) :: v
+  v = huge(v) - 32u_8
+  print *,v
+end program main
+@end smallexample
+which will output the number 18446744073709551583.
+
+Arithmetic operations work on unsigned integers, except for exponentiation,
+which is prohibited.  Unary minus is not permitted when @code{-predantic}

AV: ... @code{-pedantic}

+is in force; this prohibition is part of J3/24-116.txt.
+
+Generally, unsigned integers are only permitted as data in intrinsics.
+
+Unsigned numbers can be read and written using list-directed,
+formatted and unformatted I/O.  For formatted I/O, the @code{B},
+@code{I}, @code{O} and @code{Z} descriptors are valid.  Negative
+values and values which would overflow are rejected with
+@code{-pedantic}.
+
+As of now, the following intrinsics take unsigned arguments:
+@itemize @bullet
+@item @code{BLT}, @code{BLE}, @code{BGE} and @code{BGT}. These intrinsics
+      are actually redundant because comparison operators could be used
+      directly.
+@item @code{IAND}, @code{IOR}, @code{IEOR} and @code{NOT}
+@item @code{BIT_SIZE}, @code{DIGITS} and @code{HUGE}
+@item @code{DSHIFTL} and @code{DSHIFTR}
+@item @code{IBCLR}, @code{IBITS} and @code{IBITS}

AV: IBITS and IBITS ???

+@item @code{MIN} and @code{MAX}
+@item @code{ISHFT}, @code{ISHFTC}, @code{SHIFTL}, @code{SHIFTR} and
@code{SHIFTA}. +@item @code{MERGE_BITS}
+@item @code{MOD} and @code{MODULO}
+@item @code{MVBITS}
+@item @code{RANGE}
+@item @code{TRANSFER}
+@end itemize
+This list will grow in the near future.
 @c ---------------------------------------------------------------------
 @c ---------------------------------------------------------------------
 @c Mixed-Language Programming
diff --git a/gcc/fortran/intrinsic.cc b/gcc/fortran/intrinsic.cc
index 40f4c4f4b0b..926ac44dfd4 100644
--- a/gcc/fortran/intrinsic.cc
+++ b/gcc/fortran/intrinsic.cc
@@ -5316,7 +5347,8 @@ gfc_convert_type_warn (gfc_expr *expr, gfc_typespec *ts,
int eflag, int wflag, else if (from_ts.type == ts->type
               || (from_ts.type == BT_INTEGER && ts->type == BT_REAL)
               || (from_ts.type == BT_INTEGER && ts->type == BT_COMPLEX)
-              || (from_ts.type == BT_REAL && ts->type == BT_COMPLEX))
+              || (from_ts.type == BT_REAL && ts->type == BT_COMPLEX)
+              || (from_ts.type == BT_UNSIGNED && ts->type == BT_UNSIGNED))

AV: I don't get why converting from unsigned to unsigned is an issue here?

        {
          /* Larger kinds can hold values of smaller kinds without problems.
             Hence, only warn if target kind is smaller than the source
diff --git a/gcc/fortran/iresolve.cc b/gcc/fortran/iresolve.cc
index c63a4a8d38c..f466a473f15 100644
--- a/gcc/fortran/iresolve.cc
+++ b/gcc/fortran/iresolve.cc
@@ -895,11 +895,13 @@ void
 gfc_resolve_dshift (gfc_expr *f, gfc_expr *i, gfc_expr *j ATTRIBUTE_UNUSED,
                    gfc_expr *shift ATTRIBUTE_UNUSED)
 {
+  char c = i->ts.type == BT_INTEGER ? 'i' : 'u';
+
   f->ts = i->ts;
   if (f->value.function.isym->id == GFC_ISYM_DSHIFTL)
-    f->value.function.name = gfc_get_string ("dshiftl_i%d", f->ts.kind);
+    f->value.function.name = gfc_get_string ("dshiftl_%c%d", c, f->ts.kind);
   else if (f->value.function.isym->id == GFC_ISYM_DSHIFTR)
-    f->value.function.name = gfc_get_string ("dshiftr_i%d", f->ts.kind);
+    f->value.function.name = gfc_get_string ("dshiftr_%c%d", c, f->ts.kind);
   else
     gcc_unreachable ();
 }
@@ -1182,6 +1184,7 @@ gfc_resolve_iand (gfc_expr *f, gfc_expr *i, gfc_expr *j)
   /* If the kind of i and j are different, then g77 cross-promoted the
      kinds to the largest value.  The Fortran 95 standard requires the
      kinds to match.  */
+
   if (i->ts.kind != j->ts.kind)
     {
       if (i->ts.kind == gfc_kind_max (i, j))
@@ -1191,7 +1194,8 @@ gfc_resolve_iand (gfc_expr *f, gfc_expr *i, gfc_expr *j)
     }

   f->ts = i->ts;
-  f->value.function.name = gfc_get_string ("__iand_%d", i->ts.kind);
+  const char *name = i->ts.kind == BT_UNSIGNED ? "__iand_m_%d" : "__iand_%d";

AV: Why not using _(u|i)%d here, too, like above with dshift?

+  f->value.function.name = gfc_get_string (name, i->ts.kind);
 }



@@ -2213,7 +2239,8 @@ void
 gfc_resolve_not (gfc_expr *f, gfc_expr *i)
 {
   f->ts = i->ts;
-  f->value.function.name = gfc_get_string ("__not_%d", i->ts.kind);
+  const char *name = i->ts.kind == BT_UNSIGNED ? "__not_u_%d" : "__not_%d";

AV: And here another "style". Wouldn't a consistent one be more understandable
or did these function pre-exist and now are only reused? (Sorry, for my
ignorance).

+  f->value.function.name = gfc_get_string (name, i->ts.kind);
 }


diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
index 76f6bcb8a78..80cbf39a752 100644
--- a/gcc/fortran/primary.cc
+++ b/gcc/fortran/primary.cc
@@ -209,6 +209,44 @@ convert_integer (const char *buffer, int kind, int radix,
locus *where) }


+/* Convert an unsigned string to an expression node.  XXX:
+   This needs a calculation modulo 2^n.  TODO: Implement restriction
+   that no unary minus is permitted.  */
+static gfc_expr *
+convert_unsigned (const char *buffer, int kind, int radix, locus *where)
+{
+  gfc_expr *e;
+  const char *t;
+  int k;
+  arith rc;
+
+  e = gfc_get_constant_expr (BT_UNSIGNED, kind, where);
+  /* A leading plus is allowed, but not by mpz_set_str.  */
+  if (buffer[0] == '+')
+    t = buffer + 1;
+  else
+    t = buffer;
+
+  mpz_set_str (e->value.integer, t, radix);
+
+  k = gfc_validate_kind (BT_UNSIGNED, kind, false);
+
+  /* XXX Maybe move this somewhere else.  */

AV: How about replacing XXX by TODO and above? No one searches for XXX and TODOs
are quite good support by most recent IDEs.

+  rc = gfc_range_check (e);
+  if (rc != ARITH_OK)
+    {
+    if (pedantic)
+      gfc_error_now (gfc_arith_error (rc), &e->where);
+    else
+      gfc_warning (0, gfc_arith_error (rc), &e->where);
+    }
+
+  gfc_convert_mpz_to_unsigned (e->value.integer,
gfc_unsigned_kinds[k].bit_size,
+                              false);
+
+  return e;
+}
+
 /* Convert a real string to an expression node.  */

 static gfc_expr *
@@ -296,6 +334,71 @@ match_integer_constant (gfc_expr **result, int signflag)
   return MATCH_YES;
 }

+/* Match an unsigned constant (an integer with suffixed u).  No sign

AV: ... with suffix u)...

+   is currently accepted, in accordance with 24-116.txt, but that
+   could be changed later.  This is very much like the integer
+   constant matching above, but with enough differences to put it into
+   its own function.  */
+

diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc
index 8ddd491de11..e339f7ebc06 100644
--- a/gcc/fortran/simplify.cc
+++ b/gcc/fortran/simplify.cc
@@ -3738,16 +3814,48 @@ gfc_simplify_idint (gfc_expr *e)
   return range_check (result, "IDINT");
 }

+gfc_expr *
+gfc_simplify_uint (gfc_expr *e, gfc_expr *k)
+{
+  gfc_expr *result = NULL;
+  int kind;
+
+  kind = get_kind (BT_INTEGER, k, "INT", gfc_default_integer_kind);

AV: May I ask you to add a comment, why the above is correct?

AV: I have skipped reviewing all testcases.

AV: Nothing to comment in the library part.

I have to admit, that I am only familiar to a small part of the code.
Therefore I hope that my initial comments will make it easier for a second
reviewer to comment on the Fortran-specific problems?!

Thanks for the patch and the big effort. I hope my comments help at least a bit.

Regards,
        Andre

On Mon, 12 Aug 2024 21:40:07 +0200
Thomas Koenig <tkoe...@netcologne.de> wrote:

> Hello world,
>
> the attached patch and ChangeLog show the current state of the UNSIGNED
> implementation for gfortran.  This pretty much follows J3/24-116.txt
> and implements the basic functionality, plus the non-array intrinsics.
> Some basic functionality is tested (see the attached test cases),
> but there are, with a very high probability, still quite a few bugs.
>
> However, given my problems with git and the branch, maybe the
> best strategy is to push this to master as soon as possible;
> I would then start working on the array intrinsics.
>
> Regarding where to put this:  Paul, you had the idea of making this
> dependent on a future standard plan.  I think we can do this, setting
> -funsigned when this is flag is set.
>
> Where to put the test cases: I currently have them in the main
> gfortran.dg directory.  A subdirectory might also be a good idea,
> but then somebody would have to help me withe DejaGnu code to
> put there.
>
> So... Comments? Suggestions? OK for master?
>
> Best regards
>
>       Thomas
>


--
Andre Vehreschild * Email: vehre ad gmx dot de

Reply via email to