https://gcc.gnu.org/g:22300a5b248c1888fd70477286c8602d5a632b20

commit 22300a5b248c1888fd70477286c8602d5a632b20
Author: Thomas Koenig <tkoe...@gcc.gnu.org>
Date:   Sun Aug 4 17:50:56 2024 +0200

    Bit functions, HUGE and DIGITS.

Diff:
---
 gcc/fortran/arith.cc                     | 42 +++++++++------
 gcc/fortran/check.cc                     | 90 ++++++++++++++++++++++++++++++--
 gcc/fortran/gfortran.h                   |  1 +
 gcc/fortran/intrinsic.cc                 |  2 +-
 gcc/fortran/intrinsic.h                  |  1 +
 gcc/fortran/resolve.cc                   |  9 ++++
 gcc/fortran/simplify.cc                  | 22 ++++++--
 gcc/testsuite/gfortran.dg/unsigned_7.f90 | 26 +++++++++
 8 files changed, 167 insertions(+), 26 deletions(-)

diff --git a/gcc/fortran/arith.cc b/gcc/fortran/arith.cc
index b270ae8741ff..93641d91926f 100644
--- a/gcc/fortran/arith.cc
+++ b/gcc/fortran/arith.cc
@@ -58,7 +58,16 @@ gfc_mpfr_to_mpz (mpz_t z, mpfr_t x, locus *where)
     mpz_tdiv_q_2exp (z, z, -e);
 }
 
+/* Reduce an unsigned number to within its range.  */
 
+void
+gfc_reduce_unsigned (gfc_expr *e)
+{
+  int k;
+  gcc_checking_assert (e->expr_type == EXPR_CONSTANT && e->ts.type == 
BT_UNSIGNED);
+  k = gfc_validate_kind (BT_UNSIGNED, e->ts.kind, false);
+  mpz_and (e->value.integer, e->value.integer, gfc_unsigned_kinds[k].huge);
+}
 /* Set the model number precision by the requested KIND.  */
 
 void
@@ -688,7 +697,6 @@ gfc_arith_uminus (gfc_expr *op1, gfc_expr **resultp)
 {
   gfc_expr *result;
   arith rc;
-  int k;
 
   result = gfc_get_constant_expr (op1->ts.type, op1->ts.kind, &op1->where);
 
@@ -702,13 +710,11 @@ gfc_arith_uminus (gfc_expr *op1, gfc_expr **resultp)
       {
        arith neg_rc;
        mpz_neg (result->value.integer, op1->value.integer);
-       k = gfc_validate_kind (BT_UNSIGNED, op1->ts.kind, false);
        neg_rc = gfc_range_check (result);
        if (neg_rc != ARITH_OK)
          gfc_warning (0, gfc_arith_error (neg_rc), &result->where);
 
-       mpz_and (result->value.integer, result->value.integer,
-                gfc_unsigned_kinds[k].huge);
+       gfc_reduce_unsigned (result);
        if (pedantic)
          rc = neg_rc;
       }
@@ -749,6 +755,11 @@ gfc_arith_plus (gfc_expr *op1, gfc_expr *op2, gfc_expr 
**resultp)
       mpz_add (result->value.integer, op1->value.integer, op2->value.integer);
       break;
 
+    case BT_UNSIGNED:
+      mpz_add (result->value.integer, op1->value.integer, op2->value.integer);
+      gfc_reduce_unsigned (result);
+      break;
+
     case BT_REAL:
       mpfr_add (result->value.real, op1->value.real, op2->value.real,
               GFC_RND_MODE);
@@ -783,6 +794,7 @@ gfc_arith_minus (gfc_expr *op1, gfc_expr *op2, gfc_expr 
**resultp)
   switch (op1->ts.type)
     {
     case BT_INTEGER:
+    case BT_UNSIGNED:
       mpz_sub (result->value.integer, op1->value.integer, op2->value.integer);
       break;
 
@@ -823,6 +835,11 @@ gfc_arith_times (gfc_expr *op1, gfc_expr *op2, gfc_expr 
**resultp)
       mpz_mul (result->value.integer, op1->value.integer, op2->value.integer);
       break;
 
+    case BT_UNSIGNED:
+      mpz_mul (result->value.integer, op1->value.integer, op2->value.integer);
+      gfc_reduce_unsigned (result);
+      break;
+
     case BT_REAL:
       mpfr_mul (result->value.real, op1->value.real, op2->value.real,
               GFC_RND_MODE);
@@ -860,6 +877,7 @@ gfc_arith_divide (gfc_expr *op1, gfc_expr *op2, gfc_expr 
**resultp)
   switch (op1->ts.type)
     {
     case BT_INTEGER:
+    case BT_UNSIGNED:
       if (mpz_sgn (op2->value.integer) == 0)
        {
          rc = ARITH_DIV0;
@@ -2384,7 +2402,6 @@ gfc_uint2uint (gfc_expr *src, int kind)
 {
   gfc_expr *result;
   arith rc;
-  int k;
 
   if (src->ts.type != BT_UNSIGNED && src->ts.type != BT_INTEGER)
     return NULL;
@@ -2396,10 +2413,7 @@ gfc_uint2uint (gfc_expr *src, int kind)
   if (rc != ARITH_OK)
     gfc_warning (0, gfc_arith_error (rc), &result->where);
 
-  k = gfc_validate_kind (BT_UNSIGNED, kind, false);
-  mpz_and (result->value.integer, result->value.integer,
-          gfc_unsigned_kinds[k].huge);
-
+  gfc_reduce_unsigned (result);
   return result;
 }
 
@@ -2540,7 +2554,6 @@ gfc_real2uint (gfc_expr *src, int kind)
   gfc_expr *result;
   arith rc;
   bool did_warn = false;
-  int k;
 
   if (src->ts.type != BT_REAL)
     return NULL;
@@ -2555,9 +2568,7 @@ gfc_real2uint (gfc_expr *src, int kind)
       return NULL;
     }
 
-  k = gfc_validate_kind (BT_UNSIGNED, kind, false);
-  mpz_and (result->value.integer, result->value.integer,
-          gfc_unsigned_kinds[k].huge);
+  gfc_reduce_unsigned (result);
 
   /* If there was a fractional part, warn about this.  */
 
@@ -2774,7 +2785,6 @@ gfc_complex2uint (gfc_expr *src, int kind)
   gfc_expr *result;
   arith rc;
   bool did_warn = false;
-  int k;
 
   if (src->ts.type != BT_COMPLEX)
     return NULL;
@@ -2791,9 +2801,7 @@ gfc_complex2uint (gfc_expr *src, int kind)
       return NULL;
     }
 
-  k = gfc_validate_kind (BT_UNSIGNED, kind, false);
-  mpz_and (result->value.integer, result->value.integer,
-          gfc_unsigned_kinds[k].huge);
+  gfc_reduce_unsigned (result);
 
   if (warn_conversion || warn_conversion_extra)
     {
diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc
index 360d06f2532c..5cfae6182c3b 100644
--- a/gcc/fortran/check.cc
+++ b/gcc/fortran/check.cc
@@ -524,6 +524,20 @@ type_check (gfc_expr *e, int n, bt type)
   return false;
 }
 
+/* Check the type of an expression which can be one of two.  */
+
+static bool
+type_check2 (gfc_expr *e, int n, bt type1, bt type2)
+{
+  if (e->ts.type == type1 || e->ts.type == type2)
+    return true;
+
+  gfc_error ("%qs argument of %qs intrinsic at %L must be %s or %s",
+            gfc_current_intrinsic_arg[n]->name, gfc_current_intrinsic,
+            &e->where, gfc_basic_typename (type1), gfc_basic_typename (type2));
+
+  return false;
+}
 
 /* Check that the expression is a numeric type.  */
 
@@ -575,6 +589,23 @@ int_or_real_check (gfc_expr *e, int n)
   return true;
 }
 
+/* Check that an expression is integer or real... or unsigned.  */
+
+static bool
+int_or_real_or_unsigned_check (gfc_expr *e, int n)
+{
+  if (e->ts.type != BT_INTEGER && e->ts.type != BT_REAL
+      && e->ts.type != BT_UNSIGNED)
+    {
+      gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER, "
+                "REAL or UNSIGNED", gfc_current_intrinsic_arg[n]->name,
+                gfc_current_intrinsic, &e->where);
+      return false;
+    }
+
+  return true;
+}
+
 /* Check that an expression is integer or real; allow character for
    F2003 or later.  */
 
@@ -2669,7 +2700,13 @@ gfc_check_dble (gfc_expr *x)
 bool
 gfc_check_digits (gfc_expr *x)
 {
-  if (!int_or_real_check (x, 0))
+
+  if (flag_unsigned)
+    {
+      if (!int_or_real_or_unsigned_check (x, 0))
+       return false;
+    }
+  else if (!int_or_real_check (x, 0))
     return false;
 
   return true;
@@ -3049,7 +3086,12 @@ gfc_check_fnum (gfc_expr *unit)
 bool
 gfc_check_huge (gfc_expr *x)
 {
-  if (!int_or_real_check (x, 0))
+  if (flag_unsigned)
+    {
+      if (!int_or_real_or_unsigned_check (x, 0))
+       return false;
+    }
+  else if (!int_or_real_check (x, 0))
     return false;
 
   return true;
@@ -3079,6 +3121,21 @@ gfc_check_i (gfc_expr *i)
   return true;
 }
 
+/* Check that the single argument is an integer or an UNSIGNED.  */
+
+bool
+gfc_check_iu (gfc_expr *i)
+{
+  if (flag_unsigned)
+    {
+      if (!type_check2 (i, 0, BT_INTEGER, BT_UNSIGNED))
+       return false;
+    }
+  else if (!type_check (i, 0, BT_INTEGER))
+    return false;
+
+  return true;
+}
 
 bool
 gfc_check_iand_ieor_ior (gfc_expr *i, gfc_expr *j)
@@ -3097,12 +3154,37 @@ gfc_check_iand_ieor_ior (gfc_expr *i, gfc_expr *j)
       && !gfc_boz2int (j, i->ts.kind))
     return false;
 
-  if (!type_check (i, 0, BT_INTEGER))
+  /* If i is BOZ and j is UNSIGNED, convert i to type of j.  */
+  if (i->ts.type == BT_BOZ && j->ts.type == BT_UNSIGNED
+      && !gfc_boz2uint (i, j->ts.kind))
     return false;
 
-  if (!type_check (j, 1, BT_INTEGER))
+  /* If j is BOZ and i is UNSIGNED, convert j to type of i.  */
+  if (j->ts.type == BT_BOZ && i->ts.type == BT_UNSIGNED
+      && !gfc_boz2uint (j, i->ts.kind))
     return false;
 
+  if (flag_unsigned)
+    {
+      if (gfc_invalid_unsigned_ops (i,j))
+       return false;
+
+      if (!type_check2 (i, 0, BT_INTEGER, BT_UNSIGNED))
+       return false;
+
+      if (!type_check2 (j, 1, BT_INTEGER, BT_UNSIGNED))
+       return false;
+    }
+  else
+    {
+
+      if (!type_check (i, 0, BT_INTEGER))
+       return false;
+
+      if (!type_check (j, 1, BT_INTEGER))
+       return false;
+    }
+
   if (i->ts.kind != j->ts.kind)
     {
       gfc_error ("Arguments of %qs have different kind type parameters "
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index e3567cd0d18f..5f8dd1300a50 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -3474,6 +3474,7 @@ arith gfc_check_integer_range (mpz_t p, int kind);
 arith gfc_check_unsigned_range (mpz_t p, int kind);
 bool gfc_check_character_range (gfc_char_t, int);
 const char *gfc_arith_error (arith);
+void gfc_reduce_unigned (gfc_expr *e);
 
 extern bool gfc_seen_div0;
 
diff --git a/gcc/fortran/intrinsic.cc b/gcc/fortran/intrinsic.cc
index 86f5ce9f1e32..8dcdff9540a5 100644
--- a/gcc/fortran/intrinsic.cc
+++ b/gcc/fortran/intrinsic.cc
@@ -2747,7 +2747,7 @@ add_functions (void)
   make_generic ("nint", GFC_ISYM_NINT, GFC_STD_F77);
 
   add_sym_1 ("not", GFC_ISYM_NOT, CLASS_ELEMENTAL, ACTUAL_NO, BT_INTEGER, di, 
GFC_STD_F95,
-            gfc_check_i, gfc_simplify_not, gfc_resolve_not,
+            gfc_check_iu, gfc_simplify_not, gfc_resolve_not,
             i, BT_INTEGER, di, REQUIRED);
 
   if (flag_dec_intrinsic_ints)
diff --git a/gcc/fortran/intrinsic.h b/gcc/fortran/intrinsic.h
index fcb2733ddec8..653a17fd9b9f 100644
--- a/gcc/fortran/intrinsic.h
+++ b/gcc/fortran/intrinsic.h
@@ -89,6 +89,7 @@ bool gfc_check_hostnm (gfc_expr *);
 bool gfc_check_huge (gfc_expr *);
 bool gfc_check_hypot (gfc_expr *, gfc_expr *);
 bool gfc_check_i (gfc_expr *);
+bool gfc_check_iu (gfc_expr *);
 bool gfc_check_iand_ieor_ior (gfc_expr *, gfc_expr *);
 bool gfc_check_and (gfc_expr *, gfc_expr *);
 bool gfc_check_ibits (gfc_expr *, gfc_expr *, gfc_expr *);
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 8f70acf84ca0..dca383ebd19f 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -4458,6 +4458,15 @@ resolve_operator (gfc_expr *e)
              goto bad_op;
            }
 
+         if (flag_unsigned  && gfc_invalid_unsigned_ops (op1, op2))
+           {
+             dual_locus_error = true;
+             snprintf (msg, sizeof (msg),
+                       _("Inconsistent types for operator at %%L and %%L: "
+                         "%s and %s"), gfc_typename (op1), gfc_typename (op2));
+             goto bad_op;
+           }
+
          gfc_type_convert_binary (e, 1);
 
          e->ts.type = BT_LOGICAL;
diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc
index 5bedab3f3f4d..e00ebb6e4d19 100644
--- a/gcc/fortran/simplify.cc
+++ b/gcc/fortran/simplify.cc
@@ -2356,6 +2356,10 @@ gfc_simplify_digits (gfc_expr *x)
        digits = gfc_integer_kinds[i].digits;
        break;
 
+      case BT_UNSIGNED:
+       digits = gfc_unsigned_kinds[i].digits;
+       break;
+
       case BT_REAL:
       case BT_COMPLEX:
        digits = gfc_real_kinds[i].digits;
@@ -3265,7 +3269,11 @@ gfc_simplify_huge (gfc_expr *e)
        mpz_set (result->value.integer, gfc_integer_kinds[i].huge);
        break;
 
-      case BT_REAL:
+      case BT_UNSIGNED:
+       mpz_set (result->value.integer, gfc_unsigned_kinds[i].huge);
+       break;
+
+    case BT_REAL:
        mpfr_set (result->value.real, gfc_real_kinds[i].huge, GFC_RND_MODE);
        break;
 
@@ -3369,11 +3377,13 @@ gfc_expr *
 gfc_simplify_iand (gfc_expr *x, gfc_expr *y)
 {
   gfc_expr *result;
+  bt type;
 
   if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT)
     return NULL;
 
-  result = gfc_get_constant_expr (BT_INTEGER, x->ts.kind, &x->where);
+  type = x->ts.type == BT_UNSIGNED ? BT_UNSIGNED : BT_INTEGER;
+  result = gfc_get_constant_expr (type, x->ts.kind, &x->where);
   mpz_and (result->value.integer, x->value.integer, y->value.integer);
 
   return range_check (result, "IAND");
@@ -3547,11 +3557,13 @@ gfc_expr *
 gfc_simplify_ieor (gfc_expr *x, gfc_expr *y)
 {
   gfc_expr *result;
+  bt type;
 
   if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT)
     return NULL;
 
-  result = gfc_get_constant_expr (BT_INTEGER, x->ts.kind, &x->where);
+  type = x->ts.type == BT_UNSIGNED ? BT_UNSIGNED : BT_INTEGER;
+  result = gfc_get_constant_expr (type, x->ts.kind, &x->where);
   mpz_xor (result->value.integer, x->value.integer, y->value.integer);
 
   return range_check (result, "IEOR");
@@ -3774,11 +3786,13 @@ gfc_expr *
 gfc_simplify_ior (gfc_expr *x, gfc_expr *y)
 {
   gfc_expr *result;
+  bt type;
 
   if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT)
     return NULL;
 
-  result = gfc_get_constant_expr (BT_INTEGER, x->ts.kind, &x->where);
+  type = x->ts.type == BT_UNSIGNED ? BT_UNSIGNED : BT_INTEGER;
+  result = gfc_get_constant_expr (type, x->ts.kind, &x->where);
   mpz_ior (result->value.integer, x->value.integer, y->value.integer);
 
   return range_check (result, "IOR");
diff --git a/gcc/testsuite/gfortran.dg/unsigned_7.f90 
b/gcc/testsuite/gfortran.dg/unsigned_7.f90
new file mode 100644
index 000000000000..703c8abcbf79
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/unsigned_7.f90
@@ -0,0 +1,26 @@
+! { dg-do run }
+! { dg-options "-funsigned" }
+! Test bit functions, huge and digits.
+  unsigned :: u1, u2, u3
+  u1 = 32u
+  u2 = 64u
+  if (ior (u1,u2) /= u1 + u2) error stop 1
+  if (ior (32u,64u) /= 32u + 64u) error stop 2
+  u1 = 234u
+  u2 = 221u
+  if (iand (u1,u2) /= 200u) error stop 3
+  if (iand (234u,221u) /= 200u) error stop 4
+  if (ieor (u1,u2) /= 55u) error stop 5
+  if (ieor (234u,221u) /= 55u) error stop 6
+  u1 = huge(u1)
+  if (u1 /= 4294967295u) error stop 7
+  u2 = not(0u)
+  u3 = u2 - u1
+  if (u3 /= 0u) error stop 8
+  u2 = not(255u);
+  if (u2 /= huge(u2) - 255u) error stop 9
+  u1 = 255u
+  u2 = not(u1)
+  if (u2 /= huge(u2) - 255u) error stop 9
+  if (digits(u1) /= 32) error stop 10
+end

Reply via email to