aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Koenig <tkoenig@gcc.gnu.org>2024-08-08 20:10:33 +0200
committerThomas Koenig <tkoenig@gcc.gnu.org>2024-08-08 20:10:33 +0200
commit8366ec0e2fbf52cdf209272826b64d4e049743de (patch)
tree7cb3dd3d648af470e0e398c0e213d20d4d543f64
parentd5c05281bacf79bca1c10c34135aa61e14be8acb (diff)
downloadgcc-devel/fortran_unsigned.zip
gcc-devel/fortran_unsigned.tar.gz
gcc-devel/fortran_unsigned.tar.bz2
Add merge_bits.devel/fortran_unsigned
-rw-r--r--gcc/fortran/check.cc50
-rw-r--r--gcc/fortran/iresolve.cc4
-rw-r--r--gcc/fortran/simplify.cc2
-rw-r--r--gcc/testsuite/gfortran.dg/unsigned_14.f9018
4 files changed, 64 insertions, 10 deletions
diff --git a/gcc/fortran/check.cc b/gcc/fortran/check.cc
index 108e05d..ae1ca6e 100644
--- a/gcc/fortran/check.cc
+++ b/gcc/fortran/check.cc
@@ -4443,20 +4443,54 @@ gfc_check_merge_bits (gfc_expr *i, gfc_expr *j, gfc_expr *mask)
&& !gfc_boz2int (j, i->ts.kind))
return false;
- if (!type_check (i, 0, BT_INTEGER))
- return false;
+ if (flag_unsigned)
+ {
+ /* 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))
- return false;
+ /* 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_boz2int (j, i->ts.kind))
+ 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 (!same_type_check (i, 0, j, 1))
return false;
- if (mask->ts.type == BT_BOZ && !gfc_boz2int(mask, i->ts.kind))
- return false;
+ if (mask->ts.type == BT_BOZ)
+ {
+ if (i->ts.type == BT_INTEGER && !gfc_boz2int (mask, i->ts.kind))
+ return false;
+ if (i->ts.type == BT_UNSIGNED && !gfc_boz2uint (mask, i->ts.kind))
+ return false;
+ }
- if (!type_check (mask, 2, BT_INTEGER))
- return false;
+ if (flag_unsigned)
+ {
+ if (!type_check2 (mask, 2, BT_INTEGER, BT_UNSIGNED))
+ return false;
+ }
+ else
+ {
+ if (!type_check (mask, 2, BT_INTEGER))
+ return false;
+ }
if (!same_type_check (i, 0, mask, 2))
return false;
diff --git a/gcc/fortran/iresolve.cc b/gcc/fortran/iresolve.cc
index 8e2ad87..a43c07c 100644
--- a/gcc/fortran/iresolve.cc
+++ b/gcc/fortran/iresolve.cc
@@ -2000,7 +2000,9 @@ gfc_resolve_merge_bits (gfc_expr *f, gfc_expr *i,
gfc_expr *mask ATTRIBUTE_UNUSED)
{
f->ts = i->ts;
- f->value.function.name = gfc_get_string ("__merge_bits_i%d", i->ts.kind);
+ const char *name = i->ts.kind == BT_UNSIGNED ? "__merge_bits_u%d" :
+ "__merge_bits_i%d";
+ f->value.function.name = gfc_get_string (name, i->ts.kind);
}
diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc
index 0539603..da3c3cf 100644
--- a/gcc/fortran/simplify.cc
+++ b/gcc/fortran/simplify.cc
@@ -5221,7 +5221,7 @@ gfc_simplify_merge_bits (gfc_expr *i, gfc_expr *j, gfc_expr *mask_expr)
|| mask_expr->expr_type != EXPR_CONSTANT)
return NULL;
- result = gfc_get_constant_expr (BT_INTEGER, i->ts.kind, &i->where);
+ result = gfc_get_constant_expr (i->ts.type, i->ts.kind, &i->where);
/* Convert all argument to unsigned. */
mpz_init_set (arg1, i->value.integer);
diff --git a/gcc/testsuite/gfortran.dg/unsigned_14.f90 b/gcc/testsuite/gfortran.dg/unsigned_14.f90
new file mode 100644
index 0000000..3ccce68
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/unsigned_14.f90
@@ -0,0 +1,18 @@
+! { dg-do run }
+! { dg-options "-funsigned" }
+! Test basic functionality of merge_bits.
+program main
+ unsigned(kind=4) :: a, b, c
+ if (merge_bits(15u,51u,85u) /= 39u) stop 1
+ a = 15u
+ b = 51u
+ c = 85u
+ if (merge_bits(a,b,c) /= 39u) stop 2
+
+ if (merge_bits(4026531840u,3422552064u,2852126720u) /= 3825205248u) stop 3
+
+ a = 4026531840u_4
+ b = 3422552064u_4
+ c = 2852126720u_4
+ if (merge_bits(a,b,c) /= 3825205248u) stop 4
+end program