https://gcc.gnu.org/g:f70cf64690ab718b40763be506ec47e135e666f3

commit f70cf64690ab718b40763be506ec47e135e666f3
Author: Thomas Koenig <tkoe...@gcc.gnu.org>
Date:   Wed Jul 24 22:35:49 2024 +0200

    Got some basic arithmetic working, test case now run-time.

Diff:
---
 gcc/fortran/arith.cc                     | 13 +++++++++-
 gcc/fortran/check.cc                     |  9 +++++++
 gcc/fortran/expr.cc                      |  3 ++-
 gcc/fortran/gfortran.h                   |  2 ++
 gcc/fortran/primary.cc                   | 42 ++++++++++++++++++++++----------
 gcc/fortran/resolve.cc                   | 27 +++++++++++++++++++-
 gcc/fortran/simplify.cc                  | 18 +++++++-------
 gcc/testsuite/gfortran.dg/unsigned_1.f90 | 13 ++++++----
 8 files changed, 97 insertions(+), 30 deletions(-)

diff --git a/gcc/fortran/arith.cc b/gcc/fortran/arith.cc
index b373c25e5e12..a7b8af7779d1 100644
--- a/gcc/fortran/arith.cc
+++ b/gcc/fortran/arith.cc
@@ -1719,14 +1719,25 @@ eval_intrinsic (gfc_intrinsic_op op,
 
     gcc_fallthrough ();
     /* Numeric binary  */
+    case INTRINSIC_POWER:
+      if (flag_unsigned)
+       {
+         if (op1->ts.type == BT_UNSIGNED || op2->ts.type == BT_UNSIGNED)
+           goto runtime;
+       }
+
+      gcc_fallthrough();
+
     case INTRINSIC_PLUS:
     case INTRINSIC_MINUS:
     case INTRINSIC_TIMES:
     case INTRINSIC_DIVIDE:
-    case INTRINSIC_POWER:
       if (!gfc_numeric_ts (&op1->ts) || !gfc_numeric_ts (&op2->ts))
        goto runtime;
 
+      if (flag_unsigned && gfc_invalid_unsigned_ops (op1, op2))
+       goto runtime;
+
       /* Do not perform conversions if operands are not conformable as
         required for the binary intrinsic operators (F2018:10.1.5).
         Defer to a possibly overloading user-defined operator.  */
diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc
index 2f50d84b876f..e90a99df1e2b 100644
--- a/gcc/fortran/check.cc
+++ b/gcc/fortran/check.cc
@@ -7637,3 +7637,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;
+}
diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index 2c1f965c73a2..545a64dba239 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -903,7 +903,8 @@ gfc_kind_max (gfc_expr *e1, gfc_expr *e2)
 static bool
 numeric_type (bt type)
 {
-  return type == BT_COMPLEX || type == BT_REAL || type == BT_INTEGER;
+  return type == BT_COMPLEX || type == BT_REAL || type == BT_INTEGER
+    || type == BT_UNSIGNED;
 }
 
 
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index d51960ff0d31..3e20821cceae 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -4021,6 +4021,7 @@ bool gfc_boz2real (gfc_expr *, int);
 bool gfc_invalid_boz (const char *, locus *);
 bool gfc_invalid_null_arg (gfc_expr *);
 
+bool gfc_invalid_unsigned_ops (gfc_expr *, gfc_expr *);
 
 /* class.cc */
 void gfc_fix_class_refs (gfc_expr *e);
@@ -4103,6 +4104,7 @@ void gfc_convert_mpz_to_signed (mpz_t, int);
 gfc_expr *gfc_simplify_ieee_functions (gfc_expr *);
 bool gfc_is_constant_array_expr (gfc_expr *);
 bool gfc_is_size_zero_array (gfc_expr *);
+void gfc_convert_mpz_to_unsigned (mpz_t, int);
 
 /* trans-array.cc  */
 
diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
index d2a6e69fa428..c1aa0bc77c91 100644
--- a/gcc/fortran/primary.cc
+++ b/gcc/fortran/primary.cc
@@ -210,20 +210,27 @@ 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.  */
+   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;
-  mpz_t tmp;
-  mpz_init_set_ui (tmp, 1);
-  /* XXX  Change this later.  */
-  mpz_mul_2exp (tmp, tmp, kind * 8);
-  mpz_sub_ui (tmp, tmp, 1);
+  const char *t;
+  int k;
+
   e = gfc_get_constant_expr (BT_UNSIGNED, kind, where);
-  mpz_set_str (e->value.integer, buffer, radix);
-  mpz_and (e->value.integer, e->value.integer, tmp);
-  mpz_clear (tmp);
+  /* 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);
+  gfc_convert_mpz_to_unsigned (e->value.integer, 
gfc_unsigned_kinds[k].bit_size);
+
   return e;
 }
 
@@ -333,9 +340,15 @@ match_unsigned_constant (gfc_expr **result)
   gfc_gobble_whitespace ();
 
   length = match_digits (/* signflag = */ false, 10, NULL);
-  gfc_current_locus = old_loc;
+
   if (length == -1)
-    return MATCH_NO;
+    goto fail;
+
+  m = gfc_match_char ('u');
+  if (m == MATCH_NO)
+    goto fail;
+
+  gfc_current_locus = old_loc;
 
   buffer = (char *) alloca (length + 1);
   memset (buffer, '\0', length + 1);
@@ -343,9 +356,10 @@ match_unsigned_constant (gfc_expr **result)
   gfc_gobble_whitespace ();
 
   match_digits (false, 10, buffer);
+
   m = gfc_match_char ('u');
   if (m == MATCH_NO)
-    return m;
+    goto fail;
 
   kind = get_kind (&is_iso_c);
   if (kind == -2)
@@ -368,6 +382,9 @@ match_unsigned_constant (gfc_expr **result)
   *result = e;
   return MATCH_YES;
 
+ fail:
+  gfc_current_locus = old_loc;
+  return MATCH_NO;
 }
 
 /* Match a Hollerith constant.  */
@@ -4419,4 +4436,3 @@ gfc_match_equiv_variable (gfc_expr **result)
 {
   return match_variable (result, 1, 0);
 }
-
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 503029364c14..98ad7aef42b4 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -4232,11 +4232,36 @@ resolve_operator (gfc_expr *e)
                gfc_op2string (e->value.op.op), gfc_typename (e));
       goto bad_op;
 
+    case INTRINSIC_POWER:
+
+      if (flag_unsigned)
+       {
+         if (op1->ts.type == BT_UNSIGNED || op2->ts.type == BT_UNSIGNED)
+           {
+             snprintf (msg, sizeof(msg),
+                       _("Exponentiation not valid at %%L for %s and %s"),
+                       gfc_typename (op1), gfc_typename (op2));
+             goto bad_op;
+           }
+       }
+      gcc_fallthrough();
+
     case INTRINSIC_PLUS:
     case INTRINSIC_MINUS:
     case INTRINSIC_TIMES:
     case INTRINSIC_DIVIDE:
-    case INTRINSIC_POWER:
+
+      /* UNSIGNED cannot appear in a mixed expression without explicit
+            conversion.  */
+      if (flag_unsigned &&  gfc_invalid_unsigned_ops (op1, op2))
+       {
+         snprintf (msg, sizeof(msg),
+                   _("Operands of binary numeric operator %%<%s%%> at %%L are 
%s/%s"),
+                   gfc_op2string (e->value.op.op), gfc_typename (op1),
+                   gfc_typename (op2));
+         goto bad_op;
+       }
+
       if (gfc_numeric_ts (&op1->ts) && gfc_numeric_ts (&op2->ts))
        {
          /* Do not perform conversions if operands are not conformable as
diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc
index 8ddd491de113..18c9088ef667 100644
--- a/gcc/fortran/simplify.cc
+++ b/gcc/fortran/simplify.cc
@@ -147,8 +147,8 @@ get_kind (bt type, gfc_expr *k, const char *name, int 
default_kind)
    The conversion is a no-op unless x is negative; otherwise, it can
    be accomplished by masking out the high bits.  */
 
-static void
-convert_mpz_to_unsigned (mpz_t x, int bitsize)
+void
+gfc_convert_mpz_to_unsigned (mpz_t x, int bitsize)
 {
   mpz_t mask;
 
@@ -1693,11 +1693,11 @@ compare_bitwise (gfc_expr *i, gfc_expr *j)
 
   mpz_init_set (x, i->value.integer);
   k = gfc_validate_kind (i->ts.type, i->ts.kind, false);
-  convert_mpz_to_unsigned (x, gfc_integer_kinds[k].bit_size);
+  gfc_convert_mpz_to_unsigned (x, gfc_integer_kinds[k].bit_size);
 
   mpz_init_set (y, j->value.integer);
   k = gfc_validate_kind (j->ts.type, j->ts.kind, false);
-  convert_mpz_to_unsigned (y, gfc_integer_kinds[k].bit_size);
+  gfc_convert_mpz_to_unsigned (y, gfc_integer_kinds[k].bit_size);
 
   res = mpz_cmp (x, y);
   mpz_clear (x);
@@ -3403,7 +3403,7 @@ gfc_simplify_ibclr (gfc_expr *x, gfc_expr *y)
       result->representation.string = NULL;
     }
 
-  convert_mpz_to_unsigned (result->value.integer,
+  gfc_convert_mpz_to_unsigned (result->value.integer,
                           gfc_integer_kinds[k].bit_size);
 
   mpz_clrbit (result->value.integer, pos);
@@ -3446,7 +3446,7 @@ gfc_simplify_ibits (gfc_expr *x, gfc_expr *y, gfc_expr *z)
     }
 
   result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where);
-  convert_mpz_to_unsigned (result->value.integer,
+  gfc_convert_mpz_to_unsigned (result->value.integer,
                           gfc_integer_kinds[k].bit_size);
 
   bits = XCNEWVEC (int, bitsize);
@@ -3501,7 +3501,7 @@ gfc_simplify_ibset (gfc_expr *x, gfc_expr *y)
       result->representation.string = NULL;
     }
 
-  convert_mpz_to_unsigned (result->value.integer,
+  gfc_convert_mpz_to_unsigned (result->value.integer,
                           gfc_integer_kinds[k].bit_size);
 
   mpz_setbit (result->value.integer, pos);
@@ -4000,7 +4000,7 @@ gfc_simplify_ishftc (gfc_expr *e, gfc_expr *s, gfc_expr 
*sz)
   if (shift == 0)
     return result;
 
-  convert_mpz_to_unsigned (result->value.integer, isize);
+  gfc_convert_mpz_to_unsigned (result->value.integer, isize);
 
   bits = XCNEWVEC (int, ssize);
 
@@ -6648,7 +6648,7 @@ gfc_simplify_popcnt (gfc_expr *e)
 
   /* Convert argument to unsigned, then count the '1' bits.  */
   mpz_init_set (x, e->value.integer);
-  convert_mpz_to_unsigned (x, gfc_integer_kinds[k].bit_size);
+  gfc_convert_mpz_to_unsigned (x, gfc_integer_kinds[k].bit_size);
   res = mpz_popcount (x);
   mpz_clear (x);
 
diff --git a/gcc/testsuite/gfortran.dg/unsigned_1.f90 
b/gcc/testsuite/gfortran.dg/unsigned_1.f90
index e8caadca9d98..a5f110aa0ab5 100644
--- a/gcc/testsuite/gfortran.dg/unsigned_1.f90
+++ b/gcc/testsuite/gfortran.dg/unsigned_1.f90
@@ -1,8 +1,11 @@
-! { dg-do compile }
+! { dg-do run }
 ! { dg-options "-funsigned" }
-! A first, very simple program, that should compile.
+! Test basic assignment, arithmetic and a condition.
 program memain
-  unsigned :: u
-  u = 1U
-  u = 2u
+  unsigned :: u, v
+  u = 1u
+  v = 42u
+  if (u + v /= 43u) then
+     stop 1
+  end if
 end program memain

Reply via email to